March 31st, 2021

QuatCore

Подправляем видеопроцессор QuatCore

Я его "собрал" в конце июля 2020 года, и с тех пор толком не трогал. Ну, размер входного и выходного буфера увеличил (циферку поменял), чуть изменил логику ожидания синхроимпульсов, вот не так давно заставил его не пропускать пикселей на стыках отрезков.

Пора внести чуть более серьёзное изменение. Как выяснилось, удаление результатов обработки по предыдущей строке после синхроимпульса сыграло с нами злую шутку. Вместо него добавим "чётность строки" и её проверку. Для этого залезем в модуль QuatCoreFullGPUout:

//буфер FIFO, через который результаты работы видеопроцессора поступают в QuatCore. Также здесь логика общения по шине
//резервируем аж 4 команды:
//GPUL (luminance):   	1000_100x
//GPUH (horiz. coord):	1000_101x
//GPUPL (Product Low):	1000_110x
//GPUPH (Product High): 1000_111x
//т.е на каждую из них выделено по 2 адреса, чтобы поменьше декодировать
//GPUL остановится, если данные ещё не поступили, равно как и GPUH 
//между тем, GPUL не трогает буфер (только читает из него),
//а GPUH выталкивает последние значения из него

//GPUPL и GPUPH также останавливаются, но не выталкивают, считываем их пораньше

module QuatCoreFullGPUout(input clk, input [PixSumWidth-1:0] D, input [PixMulWidth-1:0] Prod, input wrreq, input sclr, input [7:0] SrcAddr, input SrcStall, output DestStallReq, output [15:0] Q, output OFLO);

	parameter PixSumWidth = 22;	//сколько отводится на совместное хранение координаты и яркости или на хранение суммы всех яркостей на отрезке
	parameter PixWidth = 12;	//разрядность АЦП по сути
	parameter XregWidth = 10;	//сколько бит на координату. Теоретически могли бы сократить до 8, но довольно муторно, пока не жадничаем...
	parameter PixMulWidth = 26;	//сколько бит на "вторую сумму"
	parameter ElemCount = 4;
	parameter LongClr = 1'b1;	//1: сигнал sclr достаточно долгий, чтобы тупо "вытолкнуть" элементы по одному, или считаем что по одному лишнему оттуда выпихивать вполне хватит
								//0: обнуление за один такт

	wire IsOurAddr = (~SrcStall)&(SrcAddr[7:3] == 5'b1000_1); 	//используем при формировании Stall
	
	wire i_sclr = (~LongClr) & sclr;	//наша жадность не знает границ!
	wire L_sclr = LongClr & sclr;		//"длинный" сброс
	
	wire rdreq = (IsOurAddr & (~SrcAddr[2]) & SrcAddr[1]) | L_sclr;			//выталкиваем только по GPUH
	
	
	wire empty;							//нужен для формирования stall
	wire [PixWidth-1:0] LumOut;			//"широкий" выход буфера
	wire [XregWidth-1:0] HorOut;
	wire [15:0] ProdOutL;				//предполагаем, что 16 бит нужно как минимум
	wire [PixMulWidth-17:0] ProdOutH;	//всё, что осталось

	FIFO_on_LE buff (.clk(clk),
			.D({Prod, D}),
			.rdreq(rdreq),
			.wrreq(wrreq & (~L_sclr)),
			.sclr(i_sclr),
			.empty(empty),
			.nfull(),
			.Q({ProdOutH, ProdOutL, HorOut, LumOut}),
			.wr_stall(OFLO),	//для начала "защёлкнем" и выведем на светодиод, чтобы посмотреть, не возникает ли переполнения
			.rd_stall()		//у нас логика чуть сложнее, сами сделаем на основе empty
			 );
	defparam
		buff.DataWidth = PixSumWidth+PixMulWidth,
		buff.ElemCount = ElemCount;				//пока не можем сообразить, сколько их надо
	
	wire [1:0] cmd = SrcAddr[2:1];
	assign Q = 	(cmd == 2'b11)?	ProdOutH:
			(cmd == 2'b10)? ProdOutL:
			(cmd == 2'b01)? HorOut	: LumOut;
	
	assign DestStallReq = empty & IsOurAddr;	//т.е когда запрашиваем любую из частей, а выдать нечего
	
endmodule


Осталось вспомнить, что здесь вообще творится, и ничего не сломать, скорее починить...

Collapse )

Один модуль, QuatCoreFullGPUout, мы переделали. Но теперь нужно ещё переделать QuatCoreFullGPUinput, об этом в следующий раз.
QuatCore

Подправляем видеопроцессор QuatCore (2)

Мы уже переделали выходной модуль, но теперь нужно, чтобы он получал на вход бит чётности строки, а также разобраться, что будет происходить по заданиям HSync и VSync - раньше они "сами себя затирали", но сейчас этого механизма больше нет.
Collapse )

Вот так в итоге выглядит видеопроцессор "в сборе":


Он синтезируется в 602 ЛЭ, из которых львиная доля используется в буферах FIFO. Сам по себе он показывает предельную частоту 35 МГц, нормально.

Тестовая "схема", включающая в себя дурацкий распаковщик ч/б картинки, ядро QuatCore и видеопроцессор успешно отсинтезировалась в 1200 ЛЭ:



Тайминги соблюдены, аж 25,07 МГц :) Осталось посмотреть, оно вообще фурычит?
QuatCore

Доработка видеопроцессора (3)

Ну и теперь нужно компилятор привести в соответствие с "железом".




Collapse )

Ну и поглядим таблицу команд процессора, часть SrcAddr:
Адрес +0 +1 +2 +3 +4 +5 +6 +7
00 IMM0 IMM1 IMM2 IMM3 IMM4 IMM5 IMM6 IMM7
08 IMM8 IMM9 IMM10 IMM11 IMM12 IMM13 IMM14 IMM15
10 IMM16 IMM17 IMM18 IMM19 IMM20 IMM21 IMM22 IMM23
18 IMM24 IMM25 IMM26 IMM27 IMM28 IMM29 IMM30 IMM31
20 IMM32 IMM33 IMM34 IMM35 IMM36 IMM37 IMM38 IMM39
28 IMM40 IMM41 IMM42 IMM43 IMM44 IMM45 IMM46 IMM47
30 IMM48 IMM49 IMM50 IMM51 IMM52 IMM53 IMM54 IMM55
38 IMM56 IMM57 IMM58 IMM59 IMM60 IMM61 IMM62 IMM63
40 IMM-64 IMM-63 IMM-62 IMM-61 IMM-60 IMM-59 IMM-58 IMM-57
48 IMM-56 IMM-55 IMM-54 IMM-53 IMM-52 IMM-51 IMM-50 IMM-49
50 IMM-48 IMM-47 IMM-46 IMM-45 IMM-44 IMM-43 IMM-42 IMM-41
58 IMM-40 IMM-39 IMM-38 IMM-37 IMM-36 IMM-35 IMM-34 IMM-33
60 IMM-32 IMM-31 IMM-30 IMM-29 IMM-28 IMM-27 IMM-26 IMM-25
68 IMM-24 IMM-23 IMM-22 IMM-21 IMM-20 IMM-19 IMM-18 IMM-17
70 IMM-16 IMM-15 IMM-14 IMM-13 IMM-12 IMM-11 IMM-10 IMM-9
78 IMM-8 IMM-7 IMM-6 IMM-5 IMM-4 IMM-3 IMM-2 IMM-1
80 Acc Acc UAC C Acc Acc UAC C
88 GPUL BGPUL GPUH BGPUH GPUPL BGPUPL GPUPH BGPUPH
90 IN IN IN IN IN IN IN IN
98 [ER++] [ER++] [ER++] [ER++] [ER++] [ER++] [ER++] [ER++]
A0 i j k Inv ijk ijk ijk ijk
A8 i j k Inv ijk ijk ijk ijk
B0 CALL0 CALL1 CALL2 CALL3 CALL4 CALL5 CALL6 CALL7
B8 CALL8 CALL9 CALLA CALLB CALLC CALLD CALLE CALLF
C0 [X+1] [X+2i+1] [X+2j+1] [X+4j+1] [X+i] [X+3i] [X+2j+i] [X+4j+i]
C8 [X+k] [X+2i+k] [X+2j+k] [X+4j+k] [X+i^j] X [X+2j+i^j] [X+4j+i^j]
D0 [Y+1] [Y+2i+1] [Y+2j+1] [Y+Treug[j]+1] [Y+i] [Y+3i] [Y+2j+i] [Y+Treug[j]+i]
D8 [Y+k] [Y+2i+k] [Y+2j+k] [Y+Treug[j]+k] [Y+i^j] Y [Y+2j+i^j] [Y+Treug[j]+i^j]
E0 [Z+1] [Z+2i+1] [Z+2j+1] [Z+4j+1] [Z+i] [Z+3i] [Z+2j+i] [Z+4j+i]
E8 [Z+k] [Z+2i+k] [Z+2j+k] [Z+4j+k] [Z+i^j] Z [Z+2j+i^j] [Z+4j+i^j]
F0 [SP+1] [SP+2i+1] [SP+2j+1] [SP++] [SP+i] [SP+3i] [SP+2j+i] [i-1+SP++]
F8 [SP+k] [SP+2i+k] [SP+2j+k] [--SP+k] [SP] SP [SP+2j] [--SP]


Серые ячейки - там где не происходит полного декодирования, поэтому несколько адресов принадлежат одной и той же команде. Как видно, таких становится всё меньше и меньше, не знаю, хорошо это или плохо.

И на сегодня пока всё. Завтра испробуем. Всяко посмеёмся.