nabbla (nabbla1) wrote,
nabbla
nabbla1

Categories:

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 здорового курильщика:

//таблица непосредственных значений, сгенерированная под конкретный исполняемый код
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];
	assign Q[5]=
		(adr == 7'h57)? 1'b1:
		(adr == 7'h41)? 1'b0:
		(adr == 7'h1)? 1'b0:
		(adr == 7'h2B)? 1'b0:
		(adr == 7'h7B)? 1'b0:
		(adr == 7'h3)? 1'b0:
		(adr == 7'h5F)? 1'b1:
		(adr == 7'h5)? 1'b0:
		(adr == 7'h37)? 1'b1:
		(adr == 7'h7)? 1'b0:
		(adr == 7'h7D)? 1'b1:
		(adr == 7'h47)? 1'b0:
		(adr == 7'h73)? 1'b0:
		(adr == 7'h35)? 1'b1:
		(adr == 7'h67)? 1'b0:
		(adr == 7'h23)? 1'b1:
		(adr == 7'h0)? 1'b0:
		(adr == 7'h3B)? 1'b0:
		(adr == 7'h6B)? 1'b0:
		(adr == 7'h4F)? 1'b1:
		(adr == 7'h7C)? 1'b1:
		(adr == 7'h39)? 1'b0:
		(adr == 7'h1F)? 1'b1:
				1'b0;
	assign Q[6]=
		(adr == 7'h57)? 1'b0:
		(adr == 7'h41)? 1'b0:
		(adr == 7'h1)? 1'b0:
		(adr == 7'h2B)? 1'b0:
		(adr == 7'h7B)? 1'b0:
		(adr == 7'h3)? 1'b0:
		(adr == 7'h5F)? 1'b1:
		(adr == 7'h5)? 1'b1:
		(adr == 7'h37)? 1'b0:
		(adr == 7'h7)? 1'b0:
		(adr == 7'h7D)? 1'b1:
		(adr == 7'h47)? 1'b0:
		(adr == 7'h73)? 1'b0:
		(adr == 7'h35)? 1'b1:
		(adr == 7'h67)? 1'b0:
		(adr == 7'h23)? 1'b0:
		(adr == 7'h0)? 1'b0:
		(adr == 7'h3B)? 1'b0:
		(adr == 7'h6B)? 1'b0:
		(adr == 7'h4F)? 1'b1:
		(adr == 7'h7C)? 1'b1:
		(adr == 7'h39)? 1'b1:
		(adr == 7'h1F)? 1'b0:
				1'b0;
	assign Q[7]=
		(adr == 7'h57)? 1'b1:
		(adr == 7'h41)? 1'b0:
		(adr == 7'h1)? 1'b0:
		(adr == 7'h2B)? 1'b0:
		(adr == 7'h7B)? 1'b0:
		(adr == 7'h3)? 1'b0:
		(adr == 7'h5F)? 1'b0:
		(adr == 7'h5)? 1'b1:
		(adr == 7'h37)? 1'b0:
		(adr == 7'h7)? 1'b0:
		(adr == 7'h7D)? 1'b1:
		(adr == 7'h47)? 1'b0:
		(adr == 7'h73)? 1'b0:
		(adr == 7'h35)? 1'b0:
		(adr == 7'h67)? 1'b0:
		(adr == 7'h23)? 1'b0:
		(adr == 7'h0)? 1'b0:
		(adr == 7'h3B)? 1'b0:
		(adr == 7'h6B)? 1'b0:
		(adr == 7'h4F)? 1'b0:
		(adr == 7'h7C)? 1'b1:
		(adr == 7'h39)? 1'b0:
		(adr == 7'h1F)? 1'b0:
				1'b0;
	assign Q[9]=
		(adr == 7'h57)? 1'b0:
		(adr == 7'h41)? 1'b0:
		(adr == 7'h1)? 1'b0:
		(adr == 7'h2B)? 1'b0:
		(adr == 7'h7B)? 1'b0:
		(adr == 7'h3)? 1'b0:
		(adr == 7'h5F)? 1'b0:
		(adr == 7'h5)? 1'b1:
		(adr == 7'h37)? 1'b0:
		(adr == 7'h7)? 1'b0:
		(adr == 7'h7D)? 1'b0:
		(adr == 7'h47)? 1'b0:
		(adr == 7'h73)? 1'b0:
		(adr == 7'h35)? 1'b0:
		(adr == 7'h67)? 1'b0:
		(adr == 7'h23)? 1'b0:
		(adr == 7'h0)? 1'b0:
		(adr == 7'h3B)? 1'b0:
		(adr == 7'h6B)? 1'b0:
		(adr == 7'h4F)? 1'b0:
		(adr == 7'h7C)? 1'b1:
		(adr == 7'h39)? 1'b0:
		(adr == 7'h1F)? 1'b0:
				1'b0;
	assign Q[15]=
		(adr == 7'h57)? 1'b0:
		(adr == 7'h41)? 1'b0:
		(adr == 7'h1)? 1'b1:
		(adr == 7'h2B)? 1'b0:
		(adr == 7'h7B)? 1'b0:
		(adr == 7'h3)? 1'b0:
		(adr == 7'h5F)? 1'b0:
		(adr == 7'h5)? 1'b0:
		(adr == 7'h37)? 1'b0:
		(adr == 7'h7)? 1'b0:
		(adr == 7'h7D)? 1'b0:
		(adr == 7'h47)? 1'b0:
		(adr == 7'h73)? 1'b0:
		(adr == 7'h35)? 1'b0:
		(adr == 7'h67)? 1'b0:
		(adr == 7'h23)? 1'b0:
		(adr == 7'h0)? 1'b0:
		(adr == 7'h3B)? 1'b0:
		(adr == 7'h6B)? 1'b0:
		(adr == 7'h4F)? 1'b0:
		(adr == 7'h7C)? 1'b0:
		(adr == 7'h39)? 1'b0:
		(adr == 7'h1F)? 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


Начало очень многообещающее: должным образом выбрав, какой из 128 адресов SrcAddr[] какому непосредственному значению соответствует, 11 выходных бит удалось выразить вообще без логических элементов, скоммутировав их либо на биты адреса, либо на нолик или единичку.

Осталось лишь 5 бит, которые выражаются через комбинаторную логику, и пока я лишь указал, какое значение они должны принимать в какой ситуации, причём вариант Don't care (x) квартус (как выяснилось опытным путём) не понимает.

В результате, такая штуковина отсинтезировалась в 27 ЛЭ - улучшение в 2 раза в сравнении с предыдущим вариантом. Увы, это также означает, что на каждый из 5 битов, которые не получилось выразить напрямую, приходится свыше 5 ЛЭ! И действительно, при синтезе всей моей конструкции тайминги завалились ещё сильнее, с предельной тактовой частотой всего 22,32 МГц.

Но, по крайней мере, такой код работает корректно:

NewImmTableTestbench.png

Две верхние строчки я пока что "вбил" вручную в Vector Waveform File. Это те самые 24 непосредственных значения, которые использует программа обнаружения точек на изображении, и маски для них.

Две нижние строки - результат симуляции. RawOut - это по сути выход Q. Как можно видеть, его значения не всегда совпадают с заданными. Но если его прогнать через побитовое "И" с маской - получим ровно то, что ожидали.

Ещё поглядим на начало листинга программы:

    main proc
00  FD57          SP      Stack   ;инициализация стека.
        ProcessFrame proc
01  A141                          j       1   ;отныне и во веки веков!    
02  2001                          ACQ     VSync       ;"застревает" до тех пор, пока кадровый импульс не придёт
03  A22B                          k       10
04  ED7B                          Z       D1                                              
05  2003              @@topRows:      ACQ     HSync
06  AA5F                          kLOOP       @@topRows
07  8AE8                          C       [Z+k]           ;ожидаемый диаметр точки, всё-таки штука весьма нужная, лучше держать локальной перем.                                              
08  FE05                          [SP+2j] ImgHeight       ;в [SP+2] храним номер строки, начинать надо с 720, ибо сразу же единичку вычитаем
09  B037                          JMP     @@FinalRange    ;чтобы СНАЧАЛА отправить запрос, а потом уже смотреть результат, так почему-то удобнее                  
0A  CD07              @@newRow:       X       ActivePoints    ;начинаем цикл по всем активным точкам
0B  F288              @@ActPointsStart:   [SP+2j+1]   GPUL            ;яркость самой яркой точки на отрезке
0C  F08A                          [SP+1]  GPUH            ;соотв. координата
0D  807D                          Acc     Threshold       ;поставили задом наперёд, чтобы избежать Hazard'а   
0E  83F2                          SUB     [SP+2j+1]       ;вычитаем порог, положит. значение свидетельствует о новом найденном "пятне"                        
0F  B847                          JL      @@MidCycle      ;пятна нет, не торопимся заказывать отрезок
10  EDCD                          Z       X       ;Чтобы в Merge всегда использовать Z, независимо от того, левая или правая точка оказались
11  A041                          i       1


Полужирным я выделил значения, на которые надо обратить внимания. Это то, во что непосредственно в коде превращаются непосредственные значения. Как видно, это ровно то, что надо - пройдя через QuatCoreImmTable, мы получаем нужные 16-битные значения.

Это уже радостно. Осталось "бросить курить", то бишь заставить компилятор отыскать то минимальное количество входных бит, от которых должны зависеть выходные биты. Вроде бы понимание, как это сделать, есть, но штука обещает быть муторной...
Tags: ПЛИС, программки, работа, странные девайсы
Subscribe

Recent Posts from This Journal

  • Нахождение двух самых отдалённых точек

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

  • Слишком общительный счётчик

    Вчера я чуть поторопился отсинтезировать проект,параметры не поменял: RomWidth = 8 вместо 7, RamWidth = 9 вместо 8, и ещё EnableByteAccess=1, чтобы…

  • Балансируем конвейер QuatCore

    В пятницу у нас всё замечательно сработало на симуляции, первые 16 миллисекунд полёт нормальный. А вот прошить весь проект на ПЛИС и попробовать "в…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 8 comments