§ Верхний уровень
Полный код для DE0.Для использования видеоадаптера также требуются модули памяти 8К:
Карта памяти:
0000 - 0FFF Память знакогенератора
1000 - 1FFF Видеопамять 80x25
wire [12:0] cga_address; wire [ 7:0] cga_data; cga CGA ( .clock_25 (clock_25), // Интерфейс .R (VGA_R), .HS (VGA_HS), .G (VGA_G), .VS (VGA_VS), .B (VGA_B), // Память .address (cga_address), .data (cga_data), ); cga8k CGASTORE ( .clock (clock_100), .address_a (cga_address), .q_a (cga_data), );
§ Код видеоадаптера
module cga ( // Опорная частота input wire clock_25, // Выходные данные output reg [3:0] R, // 4 бит на красный output reg [3:0] G, // 4 бит на зеленый output reg [3:0] B, // 4 бит на синий output wire HS, // горизонтальная развертка output wire VS, // вертикальная развертка // Доступ к памяти output reg [12:0] address, // 4k Шрифты 8x16 [0000-0FFF] | 4k Видеоданные [1000..1FFF] input wire [ 7:0] data, // data = videoram[ address ] // Внешний интерфейс input wire [10:0] cursor // Положение курсора от 0 до 2047 ); // --------------------------------------------------------------------- // Тайминги для горизонтальной|вертикальной развертки (640x400) // --------------------------------------------------------------------- parameter hz_visible = 640, vt_visible = 400, hz_front = 16, vt_front = 12, hz_sync = 96, vt_sync = 2, hz_back = 48, vt_back = 35, hz_whole = 800, vt_whole = 449; assign HS = x < (hz_back + hz_visible + hz_front); // NEG. assign VS = y >= (vt_back + vt_visible + vt_front); // POS. // --------------------------------------------------------------------- wire xmax = (x == hz_whole - 1); wire ymax = (y == vt_whole - 1); reg [10:0] x = 0; reg [10:0] y = 0; wire [10:0] X = x - hz_back + 8; // X=[0..639] wire [ 9:0] Y = y - vt_back; // Y=[0..399] // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Текстовый видеоадаптер // --------------------------------------------------------------------- reg [ 7:0] char; reg [7:0] tchar; // Битовая маска reg [ 7:0] attr; reg [7:0] tattr; // Атрибут reg [23:0] timer; // Мерцание курсора reg flash; // --------------------------------------------------------------------- // Текущая позиция курсора wire [10:0] id = X[9:3] + (Y[8:4] * 80); // Если появляется курсор [1..4000], то он использует нижние 2 строки у линии wire maskbit = (char[ 3'h7 ^ X[2:0] ]) | (flash && (id == cursor+1) && Y[3:0] >= 14); // Разбираем цветовую компоненту (нижние 4 бита отвечают за цвет символа) wire [15:0] frcolor = attr[3:0] == 4'h0 ? 12'h111 : // 0 Черный (почти) attr[3:0] == 4'h1 ? 12'h008 : // 1 Синий (темный) attr[3:0] == 4'h2 ? 12'h080 : // 2 Зеленый (темный) attr[3:0] == 4'h3 ? 12'h088 : // 3 Бирюзовый (темный) attr[3:0] == 4'h4 ? 12'h800 : // 4 Красный (темный) attr[3:0] == 4'h5 ? 12'h808 : // 5 Фиолетовый (темный) attr[3:0] == 4'h6 ? 12'h880 : // 6 Коричневый attr[3:0] == 4'h7 ? 12'hccc : // 7 Серый -- тут что-то не то attr[3:0] == 4'h8 ? 12'h888 : // 8 Темно-серый attr[3:0] == 4'h9 ? 12'h00f : // 9 Синий (темный) attr[3:0] == 4'hA ? 12'h0f0 : // 10 Зеленый attr[3:0] == 4'hB ? 12'h0ff : // 11 Бирюзовый attr[3:0] == 4'hC ? 12'hf00 : // 12 Красный attr[3:0] == 4'hD ? 12'hf0f : // 13 Фиолетовый attr[3:0] == 4'hE ? 12'hff0 : // 14 Желтый 12'hfff; // 15 Белый // Цветовая компонента фона (только 8 цветов) wire [15:0] bgcolor = attr[6:4] == 3'd0 ? 12'h111 : // 0 Черный (почти) attr[6:4] == 3'd1 ? 12'h008 : // 1 Синий (темный) attr[6:4] == 3'd2 ? 12'h080 : // 2 Зеленый (темный) attr[6:4] == 3'd3 ? 12'h088 : // 3 Бирюзовый (темный) attr[6:4] == 3'd4 ? 12'h800 : // 4 Красный (темный) attr[6:4] == 3'd5 ? 12'h808 : // 5 Фиолетовый (темный) attr[6:4] == 3'd6 ? 12'h880 : // 6 Коричневый 12'hccc; // 7 Серый // Вывод видеосигнала always @(posedge clock_25) begin // Кадровая развертка x <= xmax ? 0 : x + 1; y <= xmax ? (ymax ? 0 : y + 1) : y; // Вывод окна видеоадаптера if (x >= hz_back && x < hz_visible + hz_back && y >= vt_back && y < vt_visible + vt_back) begin {R, G, B} <= maskbit ? (attr[7] & flash ? bgcolor : frcolor) : bgcolor; end else {R, G, B} <= 12'h000; end // Извлечение битовой маски и атрибутов для генерации шрифта always @(posedge clock_25) begin case (X[2:0]) // Запрос на ASCII-символ 0: begin address <= {1'b1, id[10:0], 1'b0}; end // Сохранить ASCII -> tchar, запрос на атрибут 1: begin tchar <= data; address[0] <= 1'b1; end // Сохранить атрибут, запрос на знакогенератор 2: begin tattr <= data; address <= {1'b0, tchar[7:0], Y[3:0]}; end // Сохранить значение битовой маски 3: begin tchar <= data; end // Обновить данные для рисования символа 7: begin attr <= tattr; char <= tchar; end endcase end // Каждые 0,5 секунды перебрасывается регистр flash always @(posedge clock_25) begin if (timer == 12500000) begin flash <= ~flash; timer <= 0; end else timer <= timer + 1; end endmodule