12:06
Модуль Видака 2 — Лисья нора
§ Модуль на верилоге
Версия 2.16.2025/* verilator lint_off WIDTHTRUNC */ /* verilator lint_off WIDTHEXPAND */ /* * 256 x 192 ZX SPECTRUM RESOLUTION * 16 цветов на 1 пиксель (24Kb) */ module vidac ( input clock, input reset_n, // Интерфейс взаимодействия и конфигурации input cmd, input page, output reg bsy, // Подключение к разделяемой видеопамяти различных модулей 256K output reg [17:0] a, input [ 7:0] i, output reg [ 7:0] o, output reg w, // Координаты и отладка output reg [15:0] x, output reg [15:0] y, output reg [15:0] x1, output reg [15:0] y1, output reg [15:0] x2, output reg [15:0] y2, output reg [15:0] x3, output reg [15:0] y3, output reg [15:0] dx, output reg [15:0] dy, output reg [ 7:0] t, output [15:0] dxs, output [15:0] dys, // Запрос текстуры 256x256x1 == 64Kb output reg [ 7:0] tx, output reg [ 7:0] ty, input [ 7:0] td ); // 00000 - 0FFFF | 64K | Видеостраница 1 // 10000 - 1FFFF | 64K | Видеостраница 2 // 20000 - 3FFFF | 128K | Буфер // Старт командного буфера `define ACMD 18'h20000 localparam LINE = 1, BLOCK = 2, BLOCK_FILL = 3, POLY = 4, CIRCLE = 5, // CIRCLE (word:x,word:y), word:r, byte:c CIRCLE_FILL = 6, // CIRCLE (word:x,word:y), word:r, byte:c BLOCK_TEX = 7; // BITBLT (x:byte,y:byte,w:byte,h:byte)-(x1:word,y1:word,w:word,h:word) localparam WIDTH = 256, HEIGHT = 192; // --------------------------------------------------------------------- reg [ 7:0] tn, comm; reg [ 3:0] b; reg [17:0] u; reg [15:0] err; // Знаковое сравнение чисел wire [15:0] sub_x = x2 - x1; wire [15:0] sub_y = y2 - y1; wire [15:0] abs_x = xlt ? -sub_x : sub_x; // (A ^ B) & (A ^ C) ^ C :: Если OF != SF wire xlt = (x2[15] ^ x1[15]) & (x2[15] ^ sub_x[15]) ^ sub_x[15]; wire ylt = (y2[15] ^ y1[15]) & (y2[15] ^ sub_y[15]) ^ sub_y[15]; wire [15:0] e1 = {err, 1'b0} + dy; wire [15:0] e2 = {err, 1'b0} - dx; // AX = WIDTH*Y + X wire [16:0] ax = x + y*WIDTH + {page, 16'h0000}; wire wx = x < WIDTH && y < HEIGHT; wire yof = (y >= HEIGHT && y[15] == 0); wire [15:0] cirx = dx + 4*x2 + 6; wire [15:0] dxi = dx + y3[ 7:0]; // + Texture.Width wire [15:0] dyi = dy + y3[15:8]; // + Texture.Height assign dxs = dxi - x2; assign dys = dyi - y2; // --------------------------------------------------------------------- // Блок распределения команд и наблюдение за их исполнением // --------------------------------------------------------------------- always @(posedge clock) if (reset_n == 0) begin bsy <= 0; // Получена команда от процессора end else if ({bsy, cmd} == 2'b01) begin bsy <= 1; t <= 0; u <= `ACMD; w <= 0; // Ждать завершения исполнения команды end else begin w <= 0; case (t) // Считывание кода команды 0: begin t <= 1; a <= u; end // Прочесть очередной код команды 1: begin case (i) // LINE [x1:word,y1:word]-[x2:word,y2:word],c:byte LINE: begin t <= 2; tn <= 3; b <= 9; end // BLOCK [x1,y1]-[x2,y2],c :: 2-не закрашенный, 3-закрашенный BLOCK, BLOCK_FILL: begin t <= 2; tn <= 6; b <= 9; end // LINE -[x2:word,y2:word],c:byte Дорисовать линию POLY: begin t <= 8; b <= 5; end // 5=CIRCLE (word:x, word:y), word:r, byte:c; 6=CIRCLEFILL CIRCLE, CIRCLE_FILL: begin t <= 9; b <= 7; end // 7=BITBLT(...) // Координаты текстуры x:byte,y:byte,w:byte,h:byte; // Координаты прямугольника x1:word,y1:word,w:word,h:word BLOCK_TEX: begin t <= 13; b <= 13; end // Любой не объявленный код команды сбрасывает в BSY=0 default: begin t <= 0; bsy <= 0; end endcase a <= a + 1; comm <= i; end // --------------------------------------------------------------------- // Рисование линии // --------------------------------------------------------------------- // Считывание данных для обработки (LINE, BLOCK) 2: if (b) begin a <= a + 1; b <= b - 1; {o,y2,x2,y1,x1} <= {i,o,y2,x2,y1,x1[15:8]}; end else t <= tn; // Подготовка данных к рендерингу 3: begin t <= 4; u <= a; // Сохранить значение точки для линии-полигона {x3, y3} <= {x2, y2}; // Поменять точки местами, если Y2 > Y1 if (ylt) begin {x1, y1, x2, y2} <= {x2, y2, x1, y1}; end end // Расчет параметров 4: begin t <= 5; dx <= abs_x; // dx=|X2-X1| dy <= sub_y; // dy=|Y2-Y1| err <= abs_x - sub_y; // error = dx - dy x <= x1; y <= y1; end // Рисование точек линии 5: begin a <= ax; w <= wx; x <= x + (e1[15] ? 0 : (xlt ? -1 : 1)); y <= y + (e2[15] ? 1 : 0); err <= err + (e1[15] ? 0 : -dy) + (e2[15] ? dx : 0); // Условие выхода из цикла if ((x == x2 && y == y2) || yof || (x >= WIDTH && xlt)) t <= 0; end // --------------------------------------------------------------------- // Рисование блока // --------------------------------------------------------------------- // Коррекция 6: begin t <= 7; u <= a; {x, x1, x2} <= xlt ? {x2, x2, x1} : {x1, x1, x2}; {y, y1, y2} <= ylt ? {y2, x2, y1} : {y1, y1, y2}; end // Если не закрашенный, то рисуется полностью верхний и нижний, // Слева и справа только по одной точке 7: begin a <= ax; w <= wx; x <= x == x2 ? x1 : (comm == 3 || y == y1 || y == y2 ? x + 1 : (x == x1 ? x2 : x1)); y <= x == x2 ? (y == y2 ? y : y + 1) : y; if (x == x2 && y == y2 || yof) t <= 0; end // ------------------------------------------------------------- // LINE -[x2,y2],c // Дорисовать линию через задание новых x2,y2,cl // ------------------------------------------------------------- 8: if (b) begin a <= a + 1; b <= b - 1; {o,y2,x2} <= {i,o,y2,x2[15:8]}; end else begin t <= 3; {x1,y1} <= {x3,y3}; end // ------------------------------------------------------------- // CIRCLE (x,y),r,c // ------------------------------------------------------------- 9: if (b) begin a <= a + 1; b <= b - 1; {o,y2,y1,x1} <= {i,o,y2,y1,x1[15:8]}; end else begin t <= 10; u <= a; tn <= 0; dx <= 3 - 2*y2; x2 <= 0; end // Рисование точек на круге 10: begin t <= 11; if (comm == CIRCLE_FILL) begin case (tn) 0: begin tn <= 1; x <= x1 - x2; x3 <= x1 + x2; y <= y1 + y2; end 1: begin tn <= 2; x <= x1 - x2; x3 <= x1 + x2; y <= y1 - y2; end 2: begin tn <= 3; x <= x1 - y2; x3 <= x1 + y2; y <= y1 + x2; end 3: begin tn <= 0; x <= x1 - y2; x3 <= x1 + y2; y <= y1 - x2; end endcase end else begin case (tn) 0: begin tn <= 1; x <= x1 - x2; y <= y1 + y2; end 1: begin tn <= 2; x <= x1 + x2; y <= y1 + y2; end 2: begin tn <= 3; x <= x1 - x2; y <= y1 - y2; end 3: begin tn <= 4; x <= x1 + x2; y <= y1 - y2; end 4: begin tn <= 5; x <= x1 - y2; y <= y1 + x2; end 5: begin tn <= 6; x <= x1 + y2; y <= y1 + x2; end 6: begin tn <= 7; x <= x1 - y2; y <= y1 - x2; end 7: begin tn <= 0; x <= x1 + y2; y <= y1 - x2; end endcase end end // Установка точки 11: begin a <= ax; w <= wx; t <= comm == CIRCLE ? (tn ? 10 : 12) : (x < x3 ? 11 : (tn ? 10 : 12)); x <= x + 1; end // Следующая итерация 12: if (x2 <= y2) begin t <= 10; tn <= (comm == CIRCLE_FILL && cirx[15] ? 2 : 0); dx <= cirx[15] ? cirx : (cirx + 4*(1 - y2)); x2 <= x2 + 1; y2 <= y2 - !cirx[15]; end else t <= 0; // ------------------------------------------------------------- // BITBLT (x1=x,y1=y,x2=w,y2=h)-(x1,y1,w,h) // Рисование текстуры на видеостранице // x3[ 7:0] = x :: Точка X начальная текстуры // x3[15:8] = y :: Точка Y начальная текстуры // y3[ 7:0] = w :: Ширина текстуры // y3[15:8] = h :: Высота // ------------------------------------------------------------- // Считывание данных из памяти 13: if (b) begin a <= a + 1; b <= b - 1; {o,y2,x2,y1,x1,y3,x3} <= {i,o,y2,x2,y1,x1,y3,x3[15:8]}; end else begin t <= 14; u <= a; dx <= 0; dy <= 0; x <= x1; y <= y1; x2 <= x2 - 1; // Ширина блока y2 <= y2 - 1; tx <= x3[ 7:0]; // Старт текстуры X ty <= x3[15:8]; // Старт текстуры Y end // Рисование пикселей в блоке 14: begin a <= ax; w <= wx; o <= td; x <= x + 1; // Переход на новую линию if (x == x1 + x2) begin dx <= 0; x <= x1; y <= y + 1; tx <= x3[7:0]; ty <= !dys[15] + ty; dy <= dys[15] ? dyi : dys; // Если после вычитания DY >= Y2, то уменьшать if (!dys[15] && dys >= y2) t <= 16; // Отменить переход на 16, если был, при достижении конца картинки if (y == y1 + y2) t <= 0; end else begin tx <= !dxs[15] + tx; dx <= dxs[15] ? dxi : dxs; // Если после вычитания DX >= X2, то уменьшать if (!dxs[15] && dxs >= x2) t <= 15; end end // Сжимание текстуры по X/Y 15: begin tx <= tx + 1; if (dx < x2*2) t <= 14; dx <= dx - x2; end 16: begin ty <= ty + 1; if (dy < y2*2) t <= 14; dy <= dy - y2; end endcase end endmodule