§ Верхний уровень

Полный код для 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