§ Небольшое описание
Этот видеоадаптер, это вывод символов на экран 80 на 25, для OMDAZZ CYCLONE IV. Так как на этой отладочной плате установлено только 3 бита для цвета (R,G,B), то он может выводить только 8 цветов, к сожалению. А внешний переходник мне подключать что-то лень.Сначала надо определиться с тем, что подключать. Для вывода символов 8x16 нам потребуется хранить знакоместа для них, и так как символов 256, и на каждый символ тратится по 16 строк (по 8 бит одна строка), то необходимо 4096 байт для хранения знакомест. Аналогично, для хранения номеров знакомест потребуется 80 на 25 = 2000 байт, и напротив каждого существует атрибут, что дает по итогу 4000 байт (без 96 байт в конце).
Как объявить блоки памяти в TOP модуле, всем понятно. Просто и легко.
» Diяect download шаблон of проект
wire [11:0] ram_a, rom_a; wire [ 7:0] ram_i, rom_i; wire [10:0] cursor; video U1 ( .clock (clock_25), // Физический интерфейс .r (VGA_R), .g (VGA_G), .b (VGA_B), .hs (VGA_HS), .vs (VGA_VS), // Подключение к видеопамяти и шрифтам .ram_a (ram_a), .rom_a (rom_a), .ram_i (ram_i), .rom_i (rom_i), .cursor (cursor) ); vram U2 ( .clock (~clock_25), .a (ram_a), .q (ram_i) ); vrom U3 ( .clock (~clock_25), .a (rom_a), .q (rom_i) );
§ Сам модуль
Теперь приведу код самого модуля, который выводит на экран необходимые символы. Он, как и все остальное с видеоадаптерами, крайне прост и тратит всего лишь 3 такта (из 8 тактов на 1 символ), чтобы извлечь.- Номер знакоместа
- Атрибут
- Значение знакоместа
module video ( input clock, output reg r, output reg g, output reg b, output hs, output vs, // --- output reg [11:0] ram_a, output reg [11:0] rom_a, input [ 7:0] ram_i, input [ 7:0] rom_i, input [10:0] cursor ); // --------------------------------------------------------------------- // Тайминги для горизонтальной и вертикальной развертки parameter // Visible Back Sync Front Whole hzv = 640, hzb = 48, hzs = 96, hzf = 16, hzw = 800, vtv = 400, vtb = 35, vts = 2, vtf = 12, vtw = 449; // --------------------------------------------------------------------- assign hs = x < (hzb + hzv + hzf); assign vs = y < (vtb + vtv + vtf); // --------------------------------------------------------------------- reg [ 9:0] x = 0; reg [ 9:0] y = 0; wire [ 9:0] rx = x - hzb + 8; wire [ 9:0] ry = y - vtb; // --------------------------------------------------------------------- wire xmax = (x == hzw - 1); wire ymax = (y == vtw - 1); wire show = (x >= hzb && x < hzb + hzv) && (y >= vtb && y < vtb + vtv); // --------------------------------------------------------------------- reg flash; reg [ 7:0] mask, attr; reg [22:0] incr; wire [10:0] curr = rx[9:3] + ry[9:4]*80; wire cbit = mask[ ~rx[2:0] ]; wire cur = flash && (curr == cursor+1 && ry[3:0] >= 14); wire blink = (flash & attr[7]) || (attr[7] == 1'b0); always @(posedge clock) begin // Черный цвет по краям {r, b, g} <= 3'b000; // Кадровая развертка x <= xmax ? 0 : x + 1; y <= xmax ? (ymax ? 0 : y + 1) : y; // Чтение следующего символа case (rx[2:0]) 5: begin ram_a <= 2*curr; end 6: begin rom_a <= {ram_i, ry[3:0]}; ram_a <= ram_a + 1; end 7: begin {mask, attr} <= {rom_i, ram_i}; end endcase // Вывод окна видеоадаптера if (show) begin {r,g,b} <= ((cbit && blink) || cur ? attr[2:0] : attr[6:4]); end // Мерцающий курсор incr <= (incr == 6250000) ? 0 : incr+1; flash <= !incr ? ~flash : flash; end endmodule