Category: здоровье

Category was added automatically. Read all entries about "здоровье".

QuatCore

QuatCoreImmTable здорового человека без вредных привычек

Извините, если кого испугал названием предыдущей записи (QuatCoreImmTable короновирусного больного). Нужна была ещё одна градация после здорового человека и курильщика. Та ужасающая таблица, которая при длине в 24 записи занимала 56 ЛЭ (и задержку распространения 30 нс), уступила своё место усовершенствованной, которая занимает 27 ЛЭ.

Сейчас вооружился четвёртым томом Кнута и заставил свой компилятор для QuatCore генерировать такой вот модуль:

//таблица непосредственных значений, сгенерированная под конкретный исполняемый код
module QuatCoreImmTable (input [7:0] SrcAddr, output [15:0] Q);
	wire[6:0] adr = SrcAddr[6:0];
	assign Q[0]=adr[6];
	assign Q[1]=adr[5];
	assign Q[2]=adr[4];
	assign Q[3]=adr[3];
	assign Q[4]=adr[2];
	assign Q[8]=adr[5];
	assign Q[10]=adr[5];
	assign Q[11]=adr[5];
	assign Q[12]=1'b0;
	assign Q[13]=1'b0;
	assign Q[14]=adr[1];
	wire [3:0] adr15={adr[6],adr[2],adr[1],adr[0]};
	assign Q[15]=
		(adr15==4'b0000)?	1'b0:
		(adr15==4'b1100)?	1'b0:
		(adr15==4'b0001)?	1'b1:
		(adr15==4'b1001)?	1'b0:
		(adr15==4'b0101)?	1'b0:
		(adr15==4'b1101)?	1'b0:
		(adr15==4'b0011)?	1'b0:
			1'bx;
	wire [2:0] adr9={adr[3],adr[2],adr[0]};
	assign Q[9]=
		(adr9==3'b000)?	1'b0:
		(adr9==3'b110)?	1'b1:
		(adr9==3'b001)?	1'b0:
		(adr9==3'b011)?	1'b1:
			1'b0;
	wire [2:0] adr7={adr[4],adr[2],adr[1]};
	assign Q[7]=
		(adr7==3'b000)?	1'b0:
		(adr7==3'b010)?	1'b1:
		(adr7==3'b110)?	1'b1:
		(adr7==3'b001)?	1'b0:
		(adr7==3'b101)?	1'b0:
		(adr7==3'b011)?	1'b0:
			1'b1;
	wire [3:0] adr6={adr[6],adr[3],adr[2],adr[1]};
	assign Q[6]=
		(adr6==4'b0000)?	1'b0:
		(adr6==4'b1000)?	1'b0:
		(adr6==4'b0100)?	1'b1:
		(adr6==4'b0010)?	1'b1:
		(adr6==4'b1110)?	1'b1:
		(adr6==4'b0001)?	1'b0:
		(adr6==4'b1001)?	1'b0:
		(adr6==4'b0101)?	1'b0:
		(adr6==4'b1101)?	1'b0:
		(adr6==4'b0011)?	1'b0:
		(adr6==4'b1011)?	1'b0:
		(adr6==4'b0111)?	1'b0:
			1'b1;
	wire [4:0] adr5={adr[6],adr[5],adr[4],adr[3],adr[1]};
	assign Q[5]=
		(adr5==5'b00000)?	1'b0:
		(adr5==5'b10000)?	1'b0:
		(adr5==5'b01100)?	1'b1:
		(adr5==5'b01110)?	1'b0:
		(adr5==5'b11110)?	1'b1:
		(adr5==5'b00001)?	1'b0:
		(adr5==5'b10001)?	1'b0:
		(adr5==5'b01001)?	1'b1:
		(adr5==5'b11001)?	1'b0:
		(adr5==5'b10101)?	1'b1:
		(adr5==5'b01101)?	1'b1:
		(adr5==5'b11101)?	1'b0:
		(adr5==5'b10011)?	1'b1:
		(adr5==5'b11011)?	1'b0:
		(adr5==5'b00111)?	1'b1:
		(adr5==5'b10111)?	1'b1:
		(adr5==5'b01111)?	1'b0:
			1'b0;
//Непосредственные значения и их адреса:
// Значение (dec) Значение (hex) Маска Адрес Где используется                                                    
// 181            00B5           00FF  0057  SP Stack/NOP 0/NOP 0                                                
// 1              0001           FFFF  0041  j 1/i 1/JGE ProcessFrame::@NotSoBright/SUB 1/JL AcqQueue::@queue    
// 32768          8000           C3FF  0001  ACQ VSync                                                           
// 10             000A           001F  002B  k 10                                                                
// 15             000F           00FF  007B  Z D1                                                                
// 16384          4000           C3FF  0003  ACQ HSync/ACQ HSync                                                 
// 125            007D           007F  005F  kLOOP ProcessFrame::@topRows/iLOOP AcqQueue::@updCycle              
// 720            02D0           FFFF  0005  [SP+2j] ImgHeight                                                   
// 54             0036           007F  0037  JMP ProcessFrame::@FinalRange                                       
// 16             0010           00FF  0007  X ActivePoints                                                      
// 3583           0DFF           FFFF  007D  Acc Threshold                                                       
// 17             0011           00FF  0047  JL ProcessFrame::@MidCycle/X AllPoints                              
// 7              0007           007F  0073  JL ProcessFrame::@DoMerge                                           
// 118            0076           007F  0035  iLOOP ProcessFrame::@checkCycle                                     
// 19             0013           00FF  0067  Y Heap                                                              
// 34             0022           007F  0023  JMP ProcessFrame::@MidCycle/i 2                                     
// 0              0000           FFFF  0000  Acc 0/SUB 0                                                         
// 14             000E           007F  003B  JGE ProcessFrame::@FinalRange                                       
// 11             000B           007F  006B  JMP ProcessFrame::@ActPointsStart/JMP ProcessFrame::@ActPointsStart 
// 121            0079           007F  004F  JL ProcessFrame::@QueueAnyway                                       
// 1023           03FF           C3FF  007C  ACQ WholeRow                                                        
// 78             004E           007F  0039  JGE ProcessFrame::@newRow                                           
// 60             003C           007F  001F  JMP main::@endless                                                  
// 3              0003           007F  0063  JL ListOp::@OutOfMem                                                
endmodule


Он занимает всего 7 ЛЭ, а задержка распространения (tpd) составляет 16 нс.

Collapse )

Увы, когда я попробовал синтезировать всю схему в сборе (процессор + видеопроцессор в тесной связке), тайминги опять были завалены. Ну не хватает у фиттера усидчивости нормально всё расставить и соединить, хоть ты тресни! Ну хоть размер схемы снизился: вместо 991 ЛЭ получили 950 ЛЭ.

В работе фиттера хватает случайности: чуть-чуть где-то что-то поменял - и он совсем по-другому всё соединяет. Одно только избавление от выходных пинов очень сильно влияет на результаты его работы. Наверное, надо смириться пока с заваленными таймингами - и посмотреть работу всего этого дела на симуляции со сниженной тактовой частотой. А там, когда вместо вытаскивания "внутренностей" процессора наружу (как-то SrcAddr, DestAddr, DataBus) туда пойдёт UART и SPI, тайминги внезапно придут в норму. А если нет - у меня есть ещё пара тузов в рукаве...
QuatCore

QuatCoreImmTable коронавирусного больного:

//таблица непосредственных значений, сгенерированная под конкретный исполняемый код
module QuatCoreImmTable (input [7:0] SrcAddr, output [15:0] Q);
	wire[5:0] adr = SrcAddr[5:0];
	assign Q = 
		(adr==5'h00)?	16'h00B5:
		(adr==5'h01)?	16'h0001:
		(adr==5'h02)?	16'h8000:
		(adr==5'h03)?	16'h000A:
		(adr==5'h04)?	16'h000F:
		(adr==5'h05)?	16'h4000:
		(adr==5'h06)?	16'h007D:
		(adr==5'h07)?	16'h02D0:
		(adr==5'h08)?	16'h0036:
		(adr==5'h09)?	16'h0010:
		(adr==5'h0A)?	16'h0DFF:
		(adr==5'h0B)?	16'h0011:
		(adr==5'h0C)?	16'h0007:
		(adr==5'h0D)?	16'h0076:
		(adr==5'h0E)?	16'h0013:
		(adr==5'h0F)?	16'h0022:
		(adr==5'h10)?	16'h0000:
		(adr==5'h11)?	16'h000E:
		(adr==5'h12)?	16'h000B:
		(adr==5'h13)?	16'h0079:
		(adr==5'h14)?	16'h03FF:
		(adr==5'h15)?	16'h004E:
		(adr==5'h16)?	16'h003C:
				16'h0003;
endmodule

Выглядит не так уж плохо, но синтезируется в 56 ЛЭ (а это по 3,5 ЛЭ на каждый бит), да ещё и с задержкой распространения 30 нс (при периоде тактовой частоты 40 нс), поэтому при синтезе всей штуковины в сборе (ядро QuatCore плюс видеообработчик, соединённые между собой через FIFO) у меня заваливаются тайминги. Совсем чуть-чуть: предельная частота 24,96 МГц, но нехорошо это...

После двух дней возни я научился автоматически генерировать QuatCoreImmTable здорового курильщика:
Collapse )
QuatCore

Транслятор QuatCore: первый успех по Hazard'ам

Промучался ещё немного. Что-то я поначалу думал сделать обнаружение Hazard'ов отдельным этапом, и уже почти что написал, как стало ясно - тогда и адресация вся слетает нахрен! Когда мы всё перекодировали в машинный код, нам будет очень сложно все переходы, условные и безусловные, подправить.

Так что на самом деле нужно их ловить "на лету" - только декодировал очередную команду в исходном .asm-файле - и прежде чем сразу её добавить "на выход", нужно проверить, мешает ли она предыдущей, и если да - принять карантинные меры, обеспечить между ними дистанцию, а уже потом добавить эту команду. Вот тогда красота. Ну, не самый красивый код, но всё же весьма компактный:

    if CodeRamIndex > 0 then begin
      prevSrc := SrcByAdr[CodeSeg[CodeRamIndex-1].comand.src];
      prevDest := DestByAdr[CodeSeg[CodeRamIndex-1].comand.dest];
      v := SrcByAdr[com.src];
      if (prevDest.Resources * v.Resources <> []) and not (prevSrc.CreatesBubble) then begin
        //Вот он HAZARD, великий и ужасный
        log(Format('Конфликт (Hazard) между командами %s и %s, процедура %s, строки:',[prevDest.Key, v.Key, curProc]));
        log(DebugCodeLines[DebugCodeLines.Count-1]);
        log(origLine);
        log('Вставляем NOP');
        log('');
        DebugCodeLines.Add('    NOP  0 ;AUTOMATICALLY INSERTED BY TRANSLATOR TO PREVENT HAZARD');
        StoreToCode(CodeRamIndex,NOP);
        inc(CodeRamIndex);
        if LabelIndex > 0 then
          Labels.Objects[LabelIndex] := TObject(CodeRamIndex); //чтобы не прыгать на NOP
      end;
    end;


А разговоров-то было! (раз, два, три, четыре)

Проверим это дело на программе нахождения наиболее удалённой точки из четырёх, ту, которую мы "ручками" отладили, но это было тяжело (раз, два, три, четыре, пять.

Collapse )