-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathvga_controller.vhd
347 lines (304 loc) · 9.98 KB
/
vga_controller.vhd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
-------------------------------------------------------------------------------
--
-- A VGA line-doubler for an Apple ][
--
-- Stephen A. Edwards, sedwards.cs.columbia.edu
--
-- The Apple ][ uses a 14.31818 MHz master clock. It outputs a new
-- horizontal line every 65 * 14 + 2 = 912 14M cycles. The extra two
-- are from the "extended cycle" used to keep the 3.579545 MHz
-- colorburst signal in sync. Of these, 40 * 14 = 560 are active video.
--
-- In graphics mode, the Apple effectively generates 140 four-bit pixels
-- output serially (i.e., with 3.579545 MHz pixel clock). In text mode,
-- it generates 280 one-bit pixels (i.e., with a 7.15909 MHz pixel clock).
--
-- We capture 140 four-bit nibbles for each line and interpret them in
-- one of the two modes. In graphics mode, each is displayed as a
-- single pixel of one of 16 colors. In text mode, each is displayed
-- as two black or white pixels.
--
-- The VGA display is nominally 640 X 480, but we use a 14.31818 MHz
-- dot clock. To stay in sync with the Apple, we generate a new line
-- every 912 / 2 = 456 14M cycles= 31.8 us, a 31.4 kHz horizontal
-- refresh rate. Of these, 280 will be active video.
--
-- One set of suggested VGA timings:
--
-- ______________________ ________
-- ________| VIDEO |________| VIDEO
-- |-C-|----------D-----------|-E-|
-- __ ______________________________ ___________
-- |_| |_|
-- |B|
-- |---------------A----------------|
--
-- A = 31.77 us Scanline time
-- B = 3.77 us Horizontal sync time
-- C = 1.89 us Back porch
-- D = 25.17 us Active video
-- E = 0.94 us Front porch
--
-- We use A = 456 / 14.31818 MHz = 31.84 us
-- B = 54 / 14.31818 MHz = 3.77 us
-- C = 106 / 14.31818 MHz = 7.40 us
-- D = 280 / 14.31818 MHz = 19.56 us
-- E = 16 / 14.31818 MHz = 1.12 us
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity vga_controller is
port (
CLK_14M : in std_logic; -- 14.31818 MHz master clock
nVIDEO : in std_logic;
COLOR_LINE : in std_logic;
CBL : in std_logic;
SRAM_nWE : out std_logic;
SRAM_nOE : out std_logic;
SRAM_nCE : out std_logic;
SRAM_addr : out unsigned(8 downto 0);
SRAM_data : inout unsigned(3 downto 0);
VGA_HS : out std_logic; -- Active low
VGA_VS : out std_logic; -- Active low
VGA_R : out std_logic_vector(1 downto 0);
VGA_G : out std_logic_vector(1 downto 0);
VGA_B : out std_logic_vector(1 downto 0);
MODE : in std_logic
);
end vga_controller;
architecture rtl of vga_controller is
--GE
signal HBL : std_logic := '0';
signal VBL : std_logic := '0';
signal SRAM_rd_data : unsigned(5 downto 0);
signal SRAM_wr_data : unsigned(3 downto 0);
signal SRAM_nWEi : std_logic;
signal SRAM_nOEi : std_logic;
signal SRAM_nCEi : std_logic;
signal RCOL : std_logic_vector(1 downto 0) := "00";
signal GCOL : std_logic_vector(1 downto 0) := "00";
signal BCOL : std_logic_vector(1 downto 0) := "00";
signal R : std_logic_vector(1 downto 0);
signal G : std_logic_vector(1 downto 0);
signal B : std_logic_vector(1 downto 0);
signal PIXPAT : unsigned(3 downto 0);
signal RAMPIXPAT : unsigned(5 downto 0);
signal COLPAT : unsigned(3 downto 0);
signal TEXT : std_logic;
signal ram_write_addr : unsigned(8 downto 0);
signal ram_we : std_logic;
signal ram_read_addr : unsigned(8 downto 0);
signal hcount : unsigned(9 downto 0);
signal hcount2 : unsigned(9 downto 0);
--GE signal vcount : unsigned(5 downto 0);
signal vcount : unsigned(6 downto 0);
signal even_line : std_logic := '0';
signal hactive : std_logic;
constant VGA_SCANLINE : integer := 456; -- Must be 456 (set by the Apple)
constant VGA_HSYNC : integer := 54;
constant VGA_BACK_PORCH : integer := 66;
constant VGA_ACTIVE : integer := 282; -- Must be 280 (set by the Apple)
constant VGA_FRONT_PORCH : integer := 54;
-- VGA_HSYNC + VGA_BACK_PORCH + VGA_ACTIVE + VGA_FRONT_PORCH = VGA_SCANLINE
--GE (org) constant VBL_TO_VSYNC : integer := 33;
--GE constant VBL_TO_VSYNC : integer := 80;
constant VBL_TO_VSYNC : integer := 55;
constant VGA_VSYNC_LINES : integer := 3;
signal VGA_VS_I, VGA_HS_I : std_logic;
signal video_active : std_logic;
signal vbl_delayed : std_logic;
signal color_line_delayed_1, color_line_delayed_2 : std_logic;
--GE 10/02/2009
signal cbl_last : std_logic;
signal cbl_count : unsigned(9 downto 0);
begin
--GE 10/02/2009
blank_sep2 : process(CLK_14M, CBL, cbl_last, cbl_count)
begin
if falling_edge(CLK_14M) then
cbl_count <= cbl_count + 1;
cbl_last <= CBL;
if (cbl_last = '0' and CBL = '1') then
cbl_count <= "1000100101"; -- 549
end if;
if (cbl_count = 911) then
cbl_count <= (others => '0');
VBL <= CBL;
color_line_delayed_2 <= color_line_delayed_1;
color_line_delayed_1 <= COLOR_LINE;
vbl_delayed <= VBL;
if VBL = '1' then
even_line <= '0';
vcount <= vcount + 1;
else
vcount <= (others => '0');
even_line <= not even_line;
end if;
end if;
if (cbl_count >= 549) and (cbl_count <= 899) then
HBL <= '1';
else
HBL <= '0';
end if;
end if;
end process;
hcount <= cbl_count;
hsync_gen : process (CLK_14M)
begin
if falling_edge(CLK_14M) then
if hcount = VGA_ACTIVE + VGA_FRONT_PORCH or
hcount = VGA_SCANLINE + VGA_ACTIVE + VGA_FRONT_PORCH then
VGA_HS_I <= '0';
elsif hcount = VGA_ACTIVE + VGA_FRONT_PORCH + VGA_HSYNC or
hcount = VGA_SCANLINE + VGA_ACTIVE + VGA_FRONT_PORCH + VGA_HSYNC then
VGA_HS_I <= '1';
end if;
if hcount = VGA_SCANLINE - 1 or
hcount = VGA_SCANLINE + VGA_SCANLINE - 1 then
hactive <= '1';
elsif hcount = VGA_ACTIVE or
hcount = VGA_ACTIVE + VGA_SCANLINE then
hactive <= '0';
end if;
end if;
end process hsync_gen;
VGA_HS <= VGA_HS_I;
vsync_gen : process (CLK_14M)
begin
if falling_edge(CLK_14M) then
if vcount = VBL_TO_VSYNC then
VGA_VS_I <= '0';
elsif vcount = VBL_TO_VSYNC + VGA_VSYNC_LINES then
VGA_VS_I <= '1';
end if;
end if;
end process vsync_gen;
VGA_VS <= VGA_VS_I;
-- Shift in the incoming bits to reconstruct four-bit groups
input_shift_register : process (CLK_14M)
begin
if falling_edge(CLK_14M) then
PIXPAT <= PIXPAT(2 downto 0) & nVIDEO;
end if;
end process input_shift_register;
hcount2 <= hcount - VGA_SCANLINE;
ram_read_addr <=
even_line & hcount(8 downto 1) when hcount < VGA_SCANLINE else
even_line & hcount2(8 downto 1);
ram_write_addr <= (not even_line) & hcount(9 downto 2);
ram_we <= '1' when hcount(1 downto 0) = "00" else '0';
video_active <= hactive and not vbl_delayed;
-- RGB values from Linards Ticmanis,
-- http://newsgroups.derkeiler.com/Archive/Comp/comp.sys.apple2/2005-09/msg00534.html
colorgen: process(COLPAT)
begin
case COLPAT is
when "1110" => -- 1 - 0x90 17 40
RCOL <= "10";
GCOL <= "00";
BCOL <= "01";
when "0111" => -- 2 - 0x40 2c a5
RCOL <= "01";
GCOL <= "00";
BCOL <= "10";
when "0110" => -- 3 - 0xd0 43 e5
RCOL <= "11";
GCOL <= "01";
BCOL <= "11";
when "1011" => -- 4 - 0x00 69 40
RCOL <= "00";
GCOL <= "01";
BCOL <= "01";
when "1010" => -- 5 - 0x80 80 80
RCOL <= "10";
GCOL <= "10";
BCOL <= "10";
when "0011" => -- 6 - 0x2f 95 e5
RCOL <= "00";
GCOL <= "10";
BCOL <= "11";
when "0010" => -- 7 - 0xbf ab ff
RCOL <= "11";
GCOL <= "10";
BCOL <= "11";
when "1101" => -- 8 - 0x40 54 00
RCOL <= "01";
GCOL <= "01";
BCOL <= "00";
when "1100" => -- 9 - 0xd0 6a 1a
RCOL <= "11";
GCOL <= "01";
BCOL <= "00";
when "0101" => -- 10 - 0x80 80 80
RCOL <= "01";
GCOL <= "01";
BCOL <= "01";
when "0100" => -- 11 - 0xff 96 bf
RCOL <= "11";
GCOL <= "10";
BCOL <= "11";
when "1001" => -- 12 - 0x2f bc 1a
RCOL <= "00";
GCOL <= "11";
BCOL <= "00";
when "1000" => -- 13 - 0xbf d3 5a
RCOL <= "11";
GCOL <= "11";
BCOL <= "01";
when "0001" => -- 14 - 0x6f e8 bf
RCOL <= "01";
GCOL <= "11";
BCOL <= "11";
when "0000" => -- 15 - 0xff ff ff
RCOL <= "11";
GCOL <= "11";
BCOL <= "11";
when others => -- 0 - 0x00 00 00
RCOL <= "00";
GCOL <= "00";
BCOL <= "00";
end case;
end process;
TEXT <= '1' when hcount(0) = '0' and CLK_14M = '0' and RAMPIXPAT(3) = '0'
else '1' when hcount(0) = '0' and CLK_14M = '1' and RAMPIXPAT(2) = '0'
else '1' when hcount(0) = '1' and CLK_14M = '0' and RAMPIXPAT(1) = '0'
else '1' when hcount(0) = '1' and CLK_14M = '1' and RAMPIXPAT(0) = '0'
else '0';
COLPAT <= RAMPIXPAT(3 downto 0) when hcount(0) = '1'
else RAMPIXPAT(3 downto 2) & RAMPIXPAT(5 downto 4);
--GE
SRAM_addr <= ram_read_addr when hcount(0) = '1' else ram_write_addr;
SRAM_nWEi <= not ram_we;
SRAM_nOEi <= '0' when hcount(0) = '1' else '1';
SRAM_nCEi <= CLK_14M;
process(CLK_14M)
begin
if rising_edge(CLK_14M) and SRAM_nOEi = '0' then
SRAM_rd_data <= SRAM_rd_data(1 downto 0) & SRAM_data;
end if;
end process;
process(CLK_14M)
begin
if falling_edge(CLK_14M) then
RAMPIXPAT <= SRAM_rd_data;
end if;
end process;
SRAM_wr_data <= PIXPAT;
SRAM_data <= SRAM_wr_data when SRAM_nCEi = '0' and SRAM_nWEi = '0' else "ZZZZ";
SRAM_nCE <= SRAM_nCEi;
SRAM_nOE <= SRAM_nOEi;
SRAM_nWE <= SRAM_nWEi;
R <= RCOL when video_active = '1' and color_line_delayed_2 = '1'
else TEXT & TEXT when video_active = '1' and color_line_delayed_2 = '0'
else "00";
G <= GCOL when video_active = '1' and color_line_delayed_2 = '1'
else TEXT & TEXT when video_active = '1' and color_line_delayed_2 = '0'
else "00";
B <= BCOL when video_active = '1' and color_line_delayed_2 = '1'
else TEXT & TEXT when video_active = '1' and color_line_delayed_2 = '0'
else "00";
VGA_R <= R when MODE = '1' else "00";
VGA_G <= G when MODE = '1' else TEXT & TEXT when video_active = '1' else "00";
VGA_B <= B when MODE = '1' else "00";
end rtl;