§ Верхний уровень
Полный код для DE0.Для использования видеоадаптера также требуются модули памяти 8К:
Карта памяти:
0000 - 0FFF Память знакогенератора
1000 - 1FFF Видеопамять 80x25
1wire [12:0] cga_address; 2wire [ 7:0] cga_data; 3 4cga CGA 5( 6 .clock_25 (clock_25), 7 8 // Интерфейс 9 .R (VGA_R), .HS (VGA_HS), 10 .G (VGA_G), .VS (VGA_VS), 11 .B (VGA_B), 12 13 // Память 14 .address (cga_address), 15 .data (cga_data), 16); 17 18cga8k CGASTORE 19( 20 .clock (clock_100), 21 .address_a (cga_address), 22 .q_a (cga_data), 23);
§ Код видеоадаптера
1module cga 2( 3 // Опорная частота 4 input wire clock_25, 5 6 // Выходные данные 7 output reg [3:0] R, // 4 бит на красный 8 output reg [3:0] G, // 4 бит на зеленый 9 output reg [3:0] B, // 4 бит на синий 10 output wire HS, // горизонтальная развертка 11 output wire VS, // вертикальная развертка 12 13 // Доступ к памяти 14 output reg [12:0] address, // 4k Шрифты 8x16 [0000-0FFF] | 4k Видеоданные [1000..1FFF] 15 input wire [ 7:0] data, // data = videoram[ address ] 16 17 // Внешний интерфейс 18 input wire [10:0] cursor // Положение курсора от 0 до 2047 19); 20 21// --------------------------------------------------------------------- 22// Тайминги для горизонтальной|вертикальной развертки (640x400) 23// --------------------------------------------------------------------- 24 25parameter 26 hz_visible = 640, vt_visible = 400, 27 hz_front = 16, vt_front = 12, 28 hz_sync = 96, vt_sync = 2, 29 hz_back = 48, vt_back = 35, 30 hz_whole = 800, vt_whole = 449; 31 32assign HS = x < (hz_back + hz_visible + hz_front); // NEG. 33assign VS = y >= (vt_back + vt_visible + vt_front); // POS. 34// --------------------------------------------------------------------- 35wire xmax = (x == hz_whole - 1); 36wire ymax = (y == vt_whole - 1); 37reg [10:0] x = 0; 38reg [10:0] y = 0; 39wire [10:0] X = x - hz_back + 8; // X=[0..639] 40wire [ 9:0] Y = y - vt_back; // Y=[0..399] 41// --------------------------------------------------------------------- 42 43// --------------------------------------------------------------------- 44// Текстовый видеоадаптер 45// --------------------------------------------------------------------- 46reg [ 7:0] char; reg [7:0] tchar; // Битовая маска 47reg [ 7:0] attr; reg [7:0] tattr; // Атрибут 48reg [23:0] timer; // Мерцание курсора 49reg flash; 50// --------------------------------------------------------------------- 51 52// Текущая позиция курсора 53wire [10:0] id = X[9:3] + (Y[8:4] * 80); 54 55// Если появляется курсор [1..4000], то он использует нижние 2 строки у линии 56wire maskbit = (char[ 3'h7 ^ X[2:0] ]) | (flash && (id == cursor+1) && Y[3:0] >= 14); 57 58// Разбираем цветовую компоненту (нижние 4 бита отвечают за цвет символа) 59wire [15:0] frcolor = 60 61 attr[3:0] == 4'h0 ? 12'h111 : // 0 Черный (почти) 62 attr[3:0] == 4'h1 ? 12'h008 : // 1 Синий (темный) 63 attr[3:0] == 4'h2 ? 12'h080 : // 2 Зеленый (темный) 64 attr[3:0] == 4'h3 ? 12'h088 : // 3 Бирюзовый (темный) 65 attr[3:0] == 4'h4 ? 12'h800 : // 4 Красный (темный) 66 attr[3:0] == 4'h5 ? 12'h808 : // 5 Фиолетовый (темный) 67 attr[3:0] == 4'h6 ? 12'h880 : // 6 Коричневый 68 attr[3:0] == 4'h7 ? 12'hccc : // 7 Серый -- тут что-то не то 69 attr[3:0] == 4'h8 ? 12'h888 : // 8 Темно-серый 70 attr[3:0] == 4'h9 ? 12'h00f : // 9 Синий (темный) 71 attr[3:0] == 4'hA ? 12'h0f0 : // 10 Зеленый 72 attr[3:0] == 4'hB ? 12'h0ff : // 11 Бирюзовый 73 attr[3:0] == 4'hC ? 12'hf00 : // 12 Красный 74 attr[3:0] == 4'hD ? 12'hf0f : // 13 Фиолетовый 75 attr[3:0] == 4'hE ? 12'hff0 : // 14 Желтый 76 12'hfff; // 15 Белый 77 78// Цветовая компонента фона (только 8 цветов) 79wire [15:0] bgcolor = 80 81 attr[6:4] == 3'd0 ? 12'h111 : // 0 Черный (почти) 82 attr[6:4] == 3'd1 ? 12'h008 : // 1 Синий (темный) 83 attr[6:4] == 3'd2 ? 12'h080 : // 2 Зеленый (темный) 84 attr[6:4] == 3'd3 ? 12'h088 : // 3 Бирюзовый (темный) 85 attr[6:4] == 3'd4 ? 12'h800 : // 4 Красный (темный) 86 attr[6:4] == 3'd5 ? 12'h808 : // 5 Фиолетовый (темный) 87 attr[6:4] == 3'd6 ? 12'h880 : // 6 Коричневый 88 12'hccc; // 7 Серый 89 90// Вывод видеосигнала 91always @(posedge clock_25) begin 92 93 // Кадровая развертка 94 x <= xmax ? 0 : x + 1; 95 y <= xmax ? (ymax ? 0 : y + 1) : y; 96 97 // Вывод окна видеоадаптера 98 if (x >= hz_back && x < hz_visible + hz_back && 99 y >= vt_back && y < vt_visible + vt_back) 100 begin 101 {R, G, B} <= maskbit ? (attr[7] & flash ? bgcolor : frcolor) : bgcolor; 102 end 103 else {R, G, B} <= 12'h000; 104 105end 106 107// Извлечение битовой маски и атрибутов для генерации шрифта 108always @(posedge clock_25) begin 109 110 case (X[2:0]) 111 112 // Запрос на ASCII-символ 113 0: begin address <= {1'b1, id[10:0], 1'b0}; end 114 115 // Сохранить ASCII -> tchar, запрос на атрибут 116 1: begin tchar <= data; address[0] <= 1'b1; end 117 118 // Сохранить атрибут, запрос на знакогенератор 119 2: begin tattr <= data; address <= {1'b0, tchar[7:0], Y[3:0]}; end 120 121 // Сохранить значение битовой маски 122 3: begin tchar <= data; end 123 124 // Обновить данные для рисования символа 125 7: begin attr <= tattr; char <= tchar; end 126 127 endcase 128 129end 130 131 132// Каждые 0,5 секунды перебрасывается регистр flash 133always @(posedge clock_25) begin 134 135 if (timer == 12500000) begin 136 flash <= ~flash; 137 timer <= 0; 138 end else 139 timer <= timer + 1; 140end 141 142endmodule