1 |
130 |
dilbert57 |
--===========================================================================--
|
2 |
|
|
-- --
|
3 |
|
|
-- S Y N T H E S I Z A B L E CRTC6845 C O R E --
|
4 |
|
|
-- --
|
5 |
|
|
-- www.opencores.org - January 2000 --
|
6 |
|
|
-- This IP core adheres to the GNU public license. --
|
7 |
|
|
-- --
|
8 |
|
|
-- VHDL model of MC6845 compatible CRTC --
|
9 |
|
|
-- --
|
10 |
|
|
-- This model doesn't implement interlace mode. Everything else is --
|
11 |
|
|
-- (probably) according to original MC6845 data sheet (except VTOTADJ). --
|
12 |
|
|
-- --
|
13 |
|
|
-- Implementation in Xilinx Virtex XCV50-6 runs at 50 MHz (character clock).--
|
14 |
|
|
-- With external pixel generator this CRTC could handle 450MHz pixel rate --
|
15 |
|
|
-- (see MC6845 data-sheet for typical application). --
|
16 |
|
|
-- --
|
17 |
|
|
-- Author: Damjan Lampret, lampret@opencores.org --
|
18 |
|
|
-- Reworked: John Kent, dilbert57@opencores.org --
|
19 |
|
|
-- --
|
20 |
|
|
-- TO DO: --
|
21 |
|
|
-- --
|
22 |
|
|
-- - testbench --
|
23 |
|
|
-- --
|
24 |
|
|
-- - interlace mode support, extend VSYNC for V.Total Adjust value (R5) --
|
25 |
|
|
-- --
|
26 |
|
|
-- - verification in a real application --
|
27 |
|
|
-- --
|
28 |
|
|
--===========================================================================--
|
29 |
|
|
--
|
30 |
|
|
-- Revision History
|
31 |
|
|
--
|
32 |
|
|
-- Version Date Author Modification
|
33 |
|
|
-- 1.0 2000-01-?? Damjan Lampret Original Version
|
34 |
|
|
-- 2.0 2012-04-07 John Kent Substantial rework for System09
|
35 |
|
|
-- Added vertical synch width to hsw_reg
|
36 |
|
|
-- Made light pen strobe positive going
|
37 |
|
|
--
|
38 |
|
|
library IEEE;
|
39 |
|
|
use ieee.std_logic_1164.all;
|
40 |
|
|
use IEEE.STD_LOGIC_ARITH.ALL;
|
41 |
|
|
use IEEE.STD_LOGIC_UNSIGNED.ALL;
|
42 |
|
|
use ieee.numeric_std.all;
|
43 |
|
|
|
44 |
|
|
entity crtc6845 is
|
45 |
|
|
generic (
|
46 |
|
|
DB_WIDTH : integer := 8;
|
47 |
|
|
MA_WIDTH : integer := 14;
|
48 |
|
|
RA_WIDTH : integer := 5
|
49 |
|
|
);
|
50 |
|
|
port (
|
51 |
|
|
clk : in STD_LOGIC; -- cpu clock (falling edge)
|
52 |
|
|
rst : in STD_LOGIC; -- reset (active high)
|
53 |
|
|
cs : in STD_LOGIC; -- register chip select
|
54 |
|
|
addr : in STD_LOGIC; -- register select
|
55 |
|
|
rw : in STD_LOGIC; -- register read write
|
56 |
|
|
data_in : in STD_LOGIC_VECTOR(DB_WIDTH-1 downto 0); -- register data bus in
|
57 |
|
|
data_out : out STD_LOGIC_VECTOR(DB_WIDTH-1 downto 0); -- register data bus out
|
58 |
|
|
|
59 |
|
|
chr_clk : in STD_LOGIC; -- character clock input (rising edge)
|
60 |
|
|
MA : out STD_LOGIC_VECTOR(MA_WIDTH-1 downto 0); -- memory address (characters)
|
61 |
|
|
RA : out STD_LOGIC_VECTOR(RA_WIDTH-1 downto 0); -- row address (character generator lines)
|
62 |
|
|
HSYNC : out STD_LOGIC; -- Horizontal synch
|
63 |
|
|
VSYNC : out STD_LOGIC; -- Vertical synch
|
64 |
|
|
dsp_ena : out STD_LOGIC; -- Display enable
|
65 |
|
|
cur_ena : out STD_LOGIC; -- Cursor enable
|
66 |
|
|
lpn_stb : in STD_LOGIC -- light pen strobe input (active high)
|
67 |
|
|
);
|
68 |
|
|
end crtc6845;
|
69 |
|
|
|
70 |
|
|
architecture rtl of crtc6845 is
|
71 |
|
|
|
72 |
|
|
constant AR_WIDTH : integer := 5;
|
73 |
|
|
|
74 |
|
|
--
|
75 |
|
|
-- 6845 Register Index Numbers
|
76 |
|
|
--
|
77 |
|
|
constant hto_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "00000"; -- Horizontal Total (Characters) WO
|
78 |
|
|
constant hds_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "00001"; -- Horizontal Displayed (Characters) WO
|
79 |
|
|
constant hsp_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "00010"; -- Horizontal Synch position (Characters) WO
|
80 |
|
|
constant hsw_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "00011"; -- Sync Width (Ver & Hor) (SL / Chars) WO
|
81 |
|
|
constant vto_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "00100"; -- Vertical Total (Char Rows) WO
|
82 |
|
|
constant adj_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "00101"; -- Vertical Total Adjust (Scan Lines) WO
|
83 |
|
|
constant vds_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "00110"; -- Vertical Displayed (Char Rows) WO
|
84 |
|
|
constant vsp_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "00111"; -- Vertical Synch position (Char Rows) WO
|
85 |
|
|
constant imd_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "01000"; -- Interlace Mode & Skew WO
|
86 |
|
|
constant sln_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "01001"; -- Maximum Scan Line Address (Scan Lines) WO
|
87 |
|
|
constant cur_s_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "01010"; -- Cursor Start (Scan Lines) WO Bit 5 BP, Bit 6 BE
|
88 |
|
|
constant cur_e_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "01011"; -- Cursor End (Scan Lines) WO
|
89 |
|
|
constant sta_h_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "01100"; -- Start Address High RW
|
90 |
|
|
constant sta_l_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "01101"; -- Start Address Low RW
|
91 |
|
|
constant cur_h_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "01110"; -- Cursor Position High RW
|
92 |
|
|
constant cur_l_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "01111"; -- Cusror Position Low RW
|
93 |
|
|
constant lpn_h_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "10000"; -- Light Pen Position High RO
|
94 |
|
|
constant lpn_l_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "10001"; -- Light Pen Position Low RO
|
95 |
|
|
|
96 |
|
|
--
|
97 |
|
|
-- I/O address register
|
98 |
|
|
--
|
99 |
|
|
signal ind_reg : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0);
|
100 |
|
|
|
101 |
|
|
--
|
102 |
|
|
-- 6845 Registers R0-R17
|
103 |
|
|
--
|
104 |
|
|
signal hto_reg : STD_LOGIC_VECTOR(7 downto 0); -- Horizontal Total (Chars) WO
|
105 |
|
|
signal hds_reg : STD_LOGIC_VECTOR(7 downto 0); -- Horizontal Display (Chars) WO
|
106 |
|
|
signal hsp_reg : STD_LOGIC_VECTOR(7 downto 0); -- Horizontal Synch Position (Chars) WO
|
107 |
|
|
signal hsw_reg : STD_LOGIC_VECTOR(7 downto 0); -- Horizontal Synch Width (Chars) WO
|
108 |
|
|
signal vto_reg : STD_LOGIC_VECTOR(6 downto 0); -- Vertical Total (Rows) WO
|
109 |
|
|
signal adj_reg : STD_LOGIC_VECTOR(4 downto 0); -- Vertical Total Adjust (Lines) WO
|
110 |
|
|
signal vds_reg : STD_LOGIC_VECTOR(6 downto 0); -- Vertcal Display (Rows) WO
|
111 |
|
|
signal vsp_reg : STD_LOGIC_VECTOR(6 downto 0); -- Vertical Synch Position (Rows) WO
|
112 |
|
|
signal imd_reg : STD_LOGIC_VECTOR(1 downto 0); -- Interlace Mode & Skew WO
|
113 |
|
|
signal sln_reg : STD_LOGIC_VECTOR(4 downto 0); -- Maximum Scan Line Address (Lines) WO
|
114 |
|
|
signal cur_s_reg : STD_LOGIC_VECTOR(6 downto 0); -- Cursor Start (Lines) WO
|
115 |
|
|
signal cur_e_reg : STD_LOGIC_VECTOR(4 downto 0); -- Cursor End (Lines) WO
|
116 |
|
|
signal sta_h_reg : STD_LOGIC_VECTOR(5 downto 0); -- Start Address High RW
|
117 |
|
|
signal sta_l_reg : STD_LOGIC_VECTOR(7 downto 0); -- Start Address Low RW
|
118 |
|
|
signal cur_h_reg : STD_LOGIC_VECTOR(5 downto 0); -- Cursor Position High RW
|
119 |
|
|
signal cur_l_reg : STD_LOGIC_VECTOR(7 downto 0); -- Cursor Position Low RW
|
120 |
|
|
signal lpn_h_reg : STD_LOGIC_VECTOR(5 downto 0); -- Light Pen Address High RO
|
121 |
|
|
signal lpn_l_reg : STD_LOGIC_VECTOR(7 downto 0); -- Light Pen Address Low RO
|
122 |
|
|
|
123 |
|
|
--
|
124 |
|
|
-- Counters
|
125 |
|
|
--
|
126 |
|
|
signal hor_ctr : STD_LOGIC_VECTOR( 7 downto 0); -- Horizontal Counter (Chars)
|
127 |
|
|
signal hsw_ctr : STD_LOGIC_VECTOR( 3 downto 0); -- Horizontal Synch Width Counter (Chars)
|
128 |
|
|
signal sln_ctr : STD_LOGIC_VECTOR( 4 downto 0); -- Scan Line Counter (Lines)
|
129 |
|
|
signal ver_ctr : STD_LOGIC_VECTOR( 6 downto 0); -- Vertical Counter (Rows)
|
130 |
|
|
signal vsw_ctr : STD_LOGIC_VECTOR( 3 downto 0); -- Vertical Synch widtrh Counter (Lines)
|
131 |
|
|
signal row_ctr : STD_LOGIC_VECTOR(13 downto 0); -- Vertical Row counter
|
132 |
|
|
signal lag_ctr : STD_LOGIC_VECTOR(13 downto 0); -- Linear Address Generator Counter
|
133 |
|
|
signal bnk_ctr : STD_LOGIC_VECTOR( 4 downto 0); -- Blink Counter
|
134 |
|
|
|
135 |
|
|
--
|
136 |
|
|
-- Interconnect signals
|
137 |
|
|
--
|
138 |
|
|
signal hor_end : STD_LOGIC; -- Horizontal display end
|
139 |
|
|
signal ver_end : STD_LOGIC; -- Vertical display end
|
140 |
|
|
signal hor_syn : STD_LOGIC; -- Horizontal Synch
|
141 |
|
|
signal ver_syn : STD_LOGIC; -- Vertical Synch
|
142 |
|
|
signal hor_dsp : STD_LOGIC; -- Horizontal Display Enable
|
143 |
|
|
signal ver_dsp : STD_LOGIC; -- Vertical Display Enable
|
144 |
|
|
signal hor_rst : STD_LOGIC; -- Horizontal Reset (End of Line)
|
145 |
|
|
signal ver_rst : STD_LOGIC; -- Vertical Reset (End of Frame)
|
146 |
|
|
signal sln_rst : STD_LOGIC; -- Scan Line Reset (End of Row)
|
147 |
|
|
signal sln_adj : STD_LOGIC; -- Scan Line Adjust (End of Frame)
|
148 |
|
|
signal cur_act : STD_LOGIC; -- Cursor active
|
149 |
|
|
|
150 |
|
|
begin
|
151 |
|
|
|
152 |
|
|
--
|
153 |
|
|
-- Read CRTC6845 registers
|
154 |
|
|
--
|
155 |
|
|
crtc_read: process(addr, ind_reg, sta_h_reg, sta_l_reg, cur_h_reg, cur_l_reg, lpn_h_reg, lpn_l_reg )
|
156 |
|
|
begin
|
157 |
|
|
if addr = '0' then
|
158 |
|
|
--
|
159 |
|
|
-- Read register address
|
160 |
|
|
--
|
161 |
|
|
data_out(AR_WIDTH-1 downto 0) <= ind_reg;
|
162 |
|
|
data_out(7 downto AR_WIDTH) <= (others=>'0');
|
163 |
|
|
else
|
164 |
|
|
--
|
165 |
|
|
-- Read register value
|
166 |
|
|
--
|
167 |
|
|
case ind_reg is
|
168 |
|
|
when sta_h_ind =>
|
169 |
|
|
data_out <= "00" & sta_h_reg;
|
170 |
|
|
when sta_l_ind =>
|
171 |
|
|
data_out <= sta_l_reg;
|
172 |
|
|
when cur_h_ind =>
|
173 |
|
|
data_out <= "00" & cur_h_reg;
|
174 |
|
|
when cur_l_ind =>
|
175 |
|
|
data_out <= cur_l_reg;
|
176 |
|
|
when lpn_h_ind =>
|
177 |
|
|
data_out <= "00" & lpn_h_reg;
|
178 |
|
|
when lpn_l_ind =>
|
179 |
|
|
data_out <= lpn_l_reg;
|
180 |
|
|
when others =>
|
181 |
|
|
data_out <= (others => '0');
|
182 |
|
|
end case;
|
183 |
|
|
end if;
|
184 |
|
|
end process;
|
185 |
|
|
|
186 |
|
|
--
|
187 |
|
|
-- Write CRTC registers
|
188 |
|
|
--
|
189 |
|
|
crtc_write: process(clk, rst, cs, rw, addr, data_in)
|
190 |
|
|
begin
|
191 |
|
|
if falling_edge(clk) then
|
192 |
|
|
if rst = '1' then
|
193 |
|
|
ind_reg <= b"0" & x"0";
|
194 |
|
|
hto_reg <= x"65";
|
195 |
|
|
hds_reg <= x"50";
|
196 |
|
|
hsp_reg <= x"56";
|
197 |
|
|
hsw_reg <= x"F9";
|
198 |
|
|
sln_reg <= '0' & x"b";
|
199 |
|
|
vto_reg <= b"001" & x"8"; --18
|
200 |
|
|
adj_reg <= b"0" & x"a";
|
201 |
|
|
vds_reg <= b"001" & x"8"; --18
|
202 |
|
|
vsp_reg <= b"001" & x"8"; --18
|
203 |
|
|
imd_reg <= b"00";
|
204 |
|
|
cur_s_reg <= b"000" & x"0";
|
205 |
|
|
cur_e_reg <= b"0" & x"B";
|
206 |
|
|
sta_h_reg <= b"00" & x"0";
|
207 |
|
|
sta_l_reg <= x"80";
|
208 |
|
|
cur_h_reg <= b"00" & x"0";
|
209 |
|
|
cur_l_reg <= x"80";
|
210 |
|
|
|
211 |
|
|
elsif cs = '1' and rw = '0' then
|
212 |
|
|
if addr = '0' then
|
213 |
|
|
ind_reg <= data_in(AR_WIDTH-1 downto 0);
|
214 |
|
|
else
|
215 |
|
|
case ind_reg is
|
216 |
|
|
when hto_ind =>
|
217 |
|
|
hto_reg <= data_in;
|
218 |
|
|
when hds_ind =>
|
219 |
|
|
hds_reg <= data_in;
|
220 |
|
|
when hsp_ind =>
|
221 |
|
|
hsp_reg <= data_in;
|
222 |
|
|
when hsw_ind =>
|
223 |
|
|
hsw_reg <= data_in;
|
224 |
|
|
when sln_ind =>
|
225 |
|
|
sln_reg <= data_in(4 downto 0);
|
226 |
|
|
when vto_ind =>
|
227 |
|
|
vto_reg <= data_in(6 downto 0);
|
228 |
|
|
when adj_ind =>
|
229 |
|
|
adj_reg <= data_in(4 downto 0);
|
230 |
|
|
when vds_ind =>
|
231 |
|
|
vds_reg <= data_in(6 downto 0);
|
232 |
|
|
when vsp_ind =>
|
233 |
|
|
vsp_reg <= data_in(6 downto 0);
|
234 |
|
|
when imd_ind =>
|
235 |
|
|
imd_reg <= data_in(1 downto 0);
|
236 |
|
|
when cur_s_ind =>
|
237 |
|
|
cur_s_reg <= data_in(6 downto 0);
|
238 |
|
|
when cur_e_ind =>
|
239 |
|
|
cur_e_reg <= data_in(4 downto 0);
|
240 |
|
|
when sta_h_ind =>
|
241 |
|
|
sta_h_reg <= data_in(5 downto 0);
|
242 |
|
|
when sta_l_ind =>
|
243 |
|
|
sta_l_reg <= data_in;
|
244 |
|
|
when cur_h_ind =>
|
245 |
|
|
cur_h_reg <= data_in(5 downto 0);
|
246 |
|
|
when cur_l_ind =>
|
247 |
|
|
cur_l_reg <= data_in;
|
248 |
|
|
when others =>
|
249 |
|
|
null;
|
250 |
|
|
end case;
|
251 |
|
|
end if; -- addr
|
252 |
|
|
end if; -- cs
|
253 |
|
|
end if; -- E
|
254 |
|
|
|
255 |
|
|
end process;
|
256 |
|
|
|
257 |
|
|
--------------------------------------------
|
258 |
|
|
-- Horizontal Counter --
|
259 |
|
|
--------------------------------------------
|
260 |
|
|
--
|
261 |
|
|
-- hor_ctr (horizontal counter) increments
|
262 |
|
|
-- until it reaches the horizontal total
|
263 |
|
|
-- then resets to zero
|
264 |
|
|
--
|
265 |
|
|
crtc_hor_ctr_p : process(chr_clk, rst, hor_rst, hor_ctr)
|
266 |
|
|
begin
|
267 |
|
|
if rising_edge(chr_clk) then
|
268 |
|
|
if rst = '1' then
|
269 |
|
|
hor_ctr <= (others => '0');
|
270 |
|
|
else
|
271 |
|
|
if hor_rst = '1' then
|
272 |
|
|
hor_ctr <= (others => '0');
|
273 |
|
|
else
|
274 |
|
|
hor_ctr <= hor_ctr + 1;
|
275 |
|
|
end if;
|
276 |
|
|
end if;
|
277 |
|
|
end if;
|
278 |
|
|
end process;
|
279 |
|
|
|
280 |
|
|
--------------------------------------------
|
281 |
|
|
-- Horizontal Reset --
|
282 |
|
|
--------------------------------------------
|
283 |
|
|
--
|
284 |
|
|
-- hor_rst (horizontal reset) goes high
|
285 |
|
|
-- for one horizontal character cycle
|
286 |
|
|
-- when the horizontal counte reaches
|
287 |
|
|
-- the horizontal total, then it goes low
|
288 |
|
|
--
|
289 |
|
|
crtc_hor_rst_p : process(hor_ctr, hto_reg)
|
290 |
|
|
begin
|
291 |
|
|
if hor_ctr = hto_reg then
|
292 |
|
|
hor_rst <= '1';
|
293 |
|
|
else
|
294 |
|
|
hor_rst <= '0';
|
295 |
|
|
end if;
|
296 |
|
|
end process;
|
297 |
|
|
|
298 |
|
|
--------------------------------------------
|
299 |
|
|
-- Horizontal Display End --
|
300 |
|
|
--------------------------------------------
|
301 |
|
|
--
|
302 |
|
|
-- hor_end (horizontal end) goes high
|
303 |
|
|
-- for one horizontal character clock cycles
|
304 |
|
|
-- when the horizontal counter reaches
|
305 |
|
|
-- the horizontal display count
|
306 |
|
|
--
|
307 |
|
|
crtc_hor_end_p: process(hor_ctr, hds_reg)
|
308 |
|
|
begin
|
309 |
|
|
if hor_ctr = hds_reg then
|
310 |
|
|
hor_end <= '1';
|
311 |
|
|
else
|
312 |
|
|
hor_end <= '0';
|
313 |
|
|
end if;
|
314 |
|
|
end process;
|
315 |
|
|
|
316 |
|
|
--------------------------------------------
|
317 |
|
|
-- Horizontal Display Enable --
|
318 |
|
|
--------------------------------------------
|
319 |
|
|
--
|
320 |
|
|
-- Horizontal display goes high on a
|
321 |
|
|
-- horizontal reset and goes low at
|
322 |
|
|
-- horizontal end.
|
323 |
|
|
--
|
324 |
|
|
crtc_hor_dsp_p: process(chr_clk, rst, hor_rst, hor_end )
|
325 |
|
|
begin
|
326 |
|
|
|
327 |
|
|
if rising_edge( chr_clk ) then
|
328 |
|
|
if rst = '1' then
|
329 |
|
|
hor_dsp <= '0';
|
330 |
|
|
elsif hor_rst = '1' and hor_end = '0' then
|
331 |
|
|
hor_dsp <= '1';
|
332 |
|
|
elsif hor_rst = '0' and hor_end = '1' then
|
333 |
|
|
hor_dsp <= '0';
|
334 |
|
|
end if;
|
335 |
|
|
end if;
|
336 |
|
|
end process;
|
337 |
|
|
|
338 |
|
|
--------------------------------------------
|
339 |
|
|
-- Horizontal Horizontal Synch --
|
340 |
|
|
--------------------------------------------
|
341 |
|
|
--
|
342 |
|
|
-- hor_syn (horizontal synch) goes high
|
343 |
|
|
-- when the horizontal counter reaches
|
344 |
|
|
-- the the value in the horizontal synch position
|
345 |
|
|
-- register. It is reset when the horizontal
|
346 |
|
|
-- synch width counter reaches the value
|
347 |
|
|
-- in the horizontal synch width register
|
348 |
|
|
--
|
349 |
|
|
crtc_hor_syn_p: process(chr_clk, rst, hor_ctr, hsp_reg, hsw_reg, hor_syn)
|
350 |
|
|
begin
|
351 |
|
|
if rising_edge(chr_clk) then
|
352 |
|
|
if rst = '1' then
|
353 |
|
|
hor_syn <= '0';
|
354 |
|
|
elsif hor_ctr = hsp_reg then
|
355 |
|
|
hor_syn <= '1';
|
356 |
|
|
elsif hsw_ctr = hsw_reg(3 downto 0) then
|
357 |
|
|
hor_syn <= '0';
|
358 |
|
|
end if;
|
359 |
|
|
end if;
|
360 |
|
|
HSYNC <= hor_syn;
|
361 |
|
|
|
362 |
|
|
end process;
|
363 |
|
|
|
364 |
|
|
--------------------------------------------
|
365 |
|
|
-- Horizontal Synch Width Counter --
|
366 |
|
|
--------------------------------------------
|
367 |
|
|
--
|
368 |
|
|
-- The horizaontal synch width counter
|
369 |
|
|
-- increments each character clock cycle
|
370 |
|
|
-- while the horizontal synch pulse is high
|
371 |
|
|
-- It is reset when horizontal synch goes low
|
372 |
|
|
--
|
373 |
|
|
crtc_hsw_ctr_p: process(chr_clk, rst, hor_syn, hsw_ctr)
|
374 |
|
|
begin
|
375 |
|
|
if rising_edge(chr_clk) then
|
376 |
|
|
if rst = '1' then
|
377 |
|
|
hsw_ctr <= (others => '0');
|
378 |
|
|
else
|
379 |
|
|
if hor_syn = '1' then
|
380 |
|
|
hsw_ctr <= hsw_ctr + 1;
|
381 |
|
|
else
|
382 |
|
|
hsw_ctr <= (others => '0');
|
383 |
|
|
end if;
|
384 |
|
|
end if;
|
385 |
|
|
end if;
|
386 |
|
|
end process;
|
387 |
|
|
|
388 |
|
|
--------------------------------------------
|
389 |
|
|
-- Scan Line Counter --
|
390 |
|
|
--------------------------------------------
|
391 |
|
|
--
|
392 |
|
|
-- The Scan line counter increments
|
393 |
|
|
-- when horizontal reset goes high.
|
394 |
|
|
-- It is reset when the scan line counter
|
395 |
|
|
-- reaches the value in the scan line register
|
396 |
|
|
-- The Scan line counter is used to generate
|
397 |
|
|
-- the row address of the character generator
|
398 |
|
|
--
|
399 |
|
|
crtc_sln_ctr_p: process(chr_clk, rst, hor_rst, sln_rst, sln_ctr )
|
400 |
|
|
begin
|
401 |
|
|
if rising_edge(chr_clk) then
|
402 |
|
|
if rst = '1' then
|
403 |
|
|
sln_ctr <= (others => '0');
|
404 |
|
|
elsif sln_rst = '1' then
|
405 |
|
|
sln_ctr <= (others => '0');
|
406 |
|
|
elsif hor_rst = '1' then
|
407 |
|
|
sln_ctr <= sln_ctr + 1;
|
408 |
|
|
end if;
|
409 |
|
|
end if;
|
410 |
|
|
RA <= sln_ctr;
|
411 |
|
|
end process;
|
412 |
|
|
|
413 |
|
|
--------------------------------------------
|
414 |
|
|
-- Scan Line Reset --
|
415 |
|
|
--------------------------------------------
|
416 |
|
|
--
|
417 |
|
|
-- Scan line reset is goes high when the
|
418 |
|
|
-- scan line counter reaches the value in
|
419 |
|
|
-- the scan line register and is zero otherwise
|
420 |
|
|
--
|
421 |
|
|
crtc_sln_rst_p: process(sln_reg, sln_ctr)
|
422 |
|
|
begin
|
423 |
|
|
if sln_ctr = sln_reg then
|
424 |
|
|
sln_rst <= '1';
|
425 |
|
|
else
|
426 |
|
|
sln_rst <= '0';
|
427 |
|
|
end if;
|
428 |
|
|
end process;
|
429 |
|
|
|
430 |
|
|
--------------------------------------------
|
431 |
|
|
-- Scan Line Adjust --
|
432 |
|
|
--------------------------------------------
|
433 |
|
|
--
|
434 |
|
|
-- Scan line Adjust goes high when the
|
435 |
|
|
-- scan line counter reaches the value
|
436 |
|
|
-- in the scan line adjust register.
|
437 |
|
|
-- It is use to reset the vertical counter
|
438 |
|
|
-- when it reaches the vertical total
|
439 |
|
|
--
|
440 |
|
|
crtc_sln_adj_p: process(sln_ctr, adj_reg)
|
441 |
|
|
begin
|
442 |
|
|
if sln_ctr = adj_reg then
|
443 |
|
|
sln_adj <= '1';
|
444 |
|
|
else
|
445 |
|
|
sln_adj <= '0';
|
446 |
|
|
end if;
|
447 |
|
|
end process;
|
448 |
|
|
|
449 |
|
|
--------------------------------------------
|
450 |
|
|
-- Vertical Row Counter --
|
451 |
|
|
--------------------------------------------
|
452 |
|
|
--
|
453 |
|
|
-- The Vertical Row counter is incremenented
|
454 |
|
|
-- when there is a scan line reset and there
|
455 |
|
|
-- is a horizontal reset.
|
456 |
|
|
-- The vertical row counter is reset when
|
457 |
|
|
-- there is a vertical reset due to the
|
458 |
|
|
-- vertical counter reaching the value in
|
459 |
|
|
-- the vertical total register and a
|
460 |
|
|
-- scan line adjust signal is generated
|
461 |
|
|
--
|
462 |
|
|
ctrc_ver_ctr_p: process(chr_clk, rst, sln_rst)
|
463 |
|
|
begin
|
464 |
|
|
if rising_edge(chr_clk) then
|
465 |
|
|
if rst = '1' then
|
466 |
|
|
ver_ctr <= (others => '0');
|
467 |
|
|
elsif ver_rst = '1' then
|
468 |
|
|
ver_ctr <= (others => '0');
|
469 |
|
|
elsif sln_rst = '1' and hor_rst = '1' then
|
470 |
|
|
ver_ctr <= ver_ctr + 1;
|
471 |
|
|
end if;
|
472 |
|
|
end if;
|
473 |
|
|
end process;
|
474 |
|
|
|
475 |
|
|
--------------------------------------------
|
476 |
|
|
-- Vertical Reset --
|
477 |
|
|
--------------------------------------------
|
478 |
|
|
--
|
479 |
|
|
-- Vertical reset is generated when the
|
480 |
|
|
-- vertical counter reaches the value in
|
481 |
|
|
-- the vertical total register and the
|
482 |
|
|
-- scan line counter reaches the scan
|
483 |
|
|
-- line adjust register value
|
484 |
|
|
--
|
485 |
|
|
ctrc_ver_rst_p: process(ver_ctr, vto_reg, sln_adj )
|
486 |
|
|
begin
|
487 |
|
|
|
488 |
|
|
if ver_ctr = vto_reg and sln_adj = '1' then
|
489 |
|
|
ver_rst <= '1';
|
490 |
|
|
else
|
491 |
|
|
ver_rst <= '0';
|
492 |
|
|
end if;
|
493 |
|
|
|
494 |
|
|
end process;
|
495 |
|
|
|
496 |
|
|
--------------------------------------------
|
497 |
|
|
-- Vertical Display End Process --
|
498 |
|
|
--------------------------------------------
|
499 |
|
|
--
|
500 |
|
|
-- Vertical end is generated when the
|
501 |
|
|
-- vertical counter reaches the value in
|
502 |
|
|
-- the display end register
|
503 |
|
|
--
|
504 |
|
|
crtc_ver_end_p: process(ver_ctr, vds_reg)
|
505 |
|
|
begin
|
506 |
|
|
if ver_ctr = vds_reg then
|
507 |
|
|
ver_end <= '1';
|
508 |
|
|
else
|
509 |
|
|
ver_end <= '0';
|
510 |
|
|
end if;
|
511 |
|
|
end process;
|
512 |
|
|
|
513 |
|
|
--------------------------------------------
|
514 |
|
|
-- Vertical Display Enable --
|
515 |
|
|
--------------------------------------------
|
516 |
|
|
|
517 |
|
|
crtc_ver_dsp_p: process(chr_clk, rst, ver_rst, ver_end )
|
518 |
|
|
begin
|
519 |
|
|
|
520 |
|
|
if rising_edge( chr_clk ) then
|
521 |
|
|
if rst = '1' then
|
522 |
|
|
ver_dsp <= '0';
|
523 |
|
|
elsif ver_rst = '1' and ver_end = '0' then
|
524 |
|
|
ver_dsp <= '1';
|
525 |
|
|
elsif ver_rst = '0' and ver_end = '1' then
|
526 |
|
|
ver_dsp <= '0';
|
527 |
|
|
end if;
|
528 |
|
|
end if;
|
529 |
|
|
|
530 |
|
|
end process;
|
531 |
|
|
|
532 |
|
|
--------------------------------------------
|
533 |
|
|
-- Vertical Synch Width Counter --
|
534 |
|
|
--------------------------------------------
|
535 |
|
|
--
|
536 |
|
|
-- The Vertical Synch Width Counter
|
537 |
|
|
-- is incremented when vertical synch goes high
|
538 |
|
|
-- as a result of the Vertical Counter reaching
|
539 |
|
|
-- the Vertical Synch Width Position and horizontal
|
540 |
|
|
-- reset goes high.
|
541 |
|
|
-- The Vertical synch width counter is reset
|
542 |
|
|
-- when Vertical synch goes low.
|
543 |
|
|
--
|
544 |
|
|
crtc_vsw_ctr_p: process(chr_clk, rst, hor_rst, ver_ctr, vsp_reg, vsw_ctr)
|
545 |
|
|
begin
|
546 |
|
|
if rising_edge(chr_clk) then
|
547 |
|
|
if rst = '1' then
|
548 |
|
|
vsw_ctr <= (others => '0');
|
549 |
|
|
elsif ver_syn = '0' then
|
550 |
|
|
vsw_ctr <= (others => '0');
|
551 |
|
|
elsif ver_syn = '1' and hor_rst = '1' then
|
552 |
|
|
vsw_ctr <= vsw_ctr + 1;
|
553 |
|
|
end if;
|
554 |
|
|
end if;
|
555 |
|
|
end process;
|
556 |
|
|
|
557 |
|
|
--------------------------------------------
|
558 |
|
|
-- Vertical Synch --
|
559 |
|
|
--------------------------------------------
|
560 |
|
|
--
|
561 |
|
|
-- The Vertical Synch goes high when the
|
562 |
|
|
-- vertical counter reaches the value in the
|
563 |
|
|
-- vertical synch position register.
|
564 |
|
|
-- It is reset when the vertical synch width
|
565 |
|
|
-- counter reaches 16.
|
566 |
|
|
--
|
567 |
|
|
crtc_ver_syn_p: process(chr_clk, rst, ver_ctr, vsp_reg, vsw_ctr, hsw_reg, ver_syn)
|
568 |
|
|
begin
|
569 |
|
|
if rising_edge(chr_clk) then
|
570 |
|
|
if rst = '1' then
|
571 |
|
|
ver_syn <= '0';
|
572 |
|
|
elsif ver_ctr = vsp_reg then
|
573 |
|
|
ver_syn <= '1';
|
574 |
|
|
elsif vsw_ctr = hsw_reg(7 downto 4) then
|
575 |
|
|
ver_syn <= '0';
|
576 |
|
|
end if;
|
577 |
|
|
end if;
|
578 |
|
|
VSYNC <= ver_syn;
|
579 |
|
|
end process;
|
580 |
|
|
|
581 |
|
|
--------------------------------------------
|
582 |
|
|
-- Vertical Row Counter --
|
583 |
|
|
--------------------------------------------
|
584 |
|
|
--
|
585 |
|
|
-- The character row counter is incremented
|
586 |
|
|
-- by the horizontal display count
|
587 |
|
|
-- on a scan line reset and a horizontal reset.
|
588 |
|
|
-- It is reset to the start address on a vertical reset
|
589 |
|
|
--
|
590 |
|
|
crtc_row_ctr_p: process(chr_clk, rst, sln_rst, ver_rst, hor_rst, sta_h_reg, sta_l_reg)
|
591 |
|
|
begin
|
592 |
|
|
if rising_edge(chr_clk) then
|
593 |
|
|
if rst = '1' then
|
594 |
|
|
row_ctr <= sta_h_reg & sta_l_reg;
|
595 |
|
|
elsif sln_rst = '1' and hor_rst = '1' then
|
596 |
|
|
row_ctr <= row_ctr + hds_reg;
|
597 |
|
|
if ver_rst = '1' then
|
598 |
|
|
row_ctr <= sta_h_reg & sta_l_reg;
|
599 |
|
|
end if;
|
600 |
|
|
end if;
|
601 |
|
|
end if;
|
602 |
|
|
end process;
|
603 |
|
|
|
604 |
|
|
--------------------------------------------
|
605 |
|
|
-- Display Enable --
|
606 |
|
|
--------------------------------------------
|
607 |
|
|
--
|
608 |
|
|
-- Display enable is active when both
|
609 |
|
|
-- horizantal display and vertical displays
|
610 |
|
|
-- are active
|
611 |
|
|
--
|
612 |
|
|
crtc_dsp_ena_p: process(hor_dsp, ver_dsp)
|
613 |
|
|
begin
|
614 |
|
|
|
615 |
|
|
dsp_ena <= hor_dsp and ver_dsp;
|
616 |
|
|
|
617 |
|
|
end process;
|
618 |
|
|
|
619 |
|
|
|
620 |
|
|
--------------------------------------------
|
621 |
|
|
-- Linear Address Generator --
|
622 |
|
|
--------------------------------------------
|
623 |
|
|
|
624 |
|
|
crtc_lag_p: process(chr_clk, rst, hor_rst, sta_h_reg, sta_l_reg, lag_ctr)
|
625 |
|
|
begin
|
626 |
|
|
if rising_edge(chr_clk) then
|
627 |
|
|
if rst = '1' then
|
628 |
|
|
lag_ctr <= sta_h_reg & sta_l_reg;
|
629 |
|
|
else
|
630 |
|
|
if hor_rst = '1' then
|
631 |
|
|
lag_ctr <= row_ctr;
|
632 |
|
|
end if;
|
633 |
|
|
lag_ctr <= lag_ctr + 1;
|
634 |
|
|
end if;
|
635 |
|
|
end if;
|
636 |
|
|
MA <= lag_ctr;
|
637 |
|
|
end process;
|
638 |
|
|
|
639 |
|
|
--------------------------------------------
|
640 |
|
|
-- Cursor Control Unit Instantiation --
|
641 |
|
|
--------------------------------------------
|
642 |
|
|
--
|
643 |
|
|
-- Cursor active when the Linear Address Generator
|
644 |
|
|
-- reaches the value in the Cursor position register
|
645 |
|
|
--
|
646 |
|
|
crtc_cur_act_p: process(lag_ctr, cur_h_reg, cur_l_reg)
|
647 |
|
|
begin
|
648 |
|
|
if lag_ctr = (cur_h_reg & cur_l_reg) then
|
649 |
|
|
cur_act <= '1';
|
650 |
|
|
else
|
651 |
|
|
cur_act <= '0';
|
652 |
|
|
end if;
|
653 |
|
|
end process;
|
654 |
|
|
|
655 |
|
|
--------------------------------------------
|
656 |
|
|
-- Cursor Blink Counter --
|
657 |
|
|
--------------------------------------------
|
658 |
|
|
--
|
659 |
|
|
-- The Cursor Blink Counter increments
|
660 |
|
|
-- every frame
|
661 |
|
|
--
|
662 |
|
|
crtc_blink_ctr_p: process (chr_clk, rst, hor_rst, ver_rst)
|
663 |
|
|
begin
|
664 |
|
|
if rising_edge(chr_clk) then
|
665 |
|
|
if rst = '1' then
|
666 |
|
|
bnk_ctr <= (others => '0');
|
667 |
|
|
elsif hor_rst = '1' and ver_rst = '1' then
|
668 |
|
|
bnk_ctr <= bnk_ctr + 1;
|
669 |
|
|
end if;
|
670 |
|
|
end if;
|
671 |
|
|
end process;
|
672 |
|
|
|
673 |
|
|
--------------------------------------------
|
674 |
|
|
-- Cursor Enable --
|
675 |
|
|
--------------------------------------------
|
676 |
|
|
--
|
677 |
|
|
-- The Cursor is enabled when the Scan line
|
678 |
|
|
-- counter is great or equal to the Cursor Start Line
|
679 |
|
|
-- and the scan line counter is less than or equal
|
680 |
|
|
-- to the Cursor End line and the Cusor is active
|
681 |
|
|
--
|
682 |
|
|
crtc_cur_ena_p: process (sln_ctr, cur_s_reg, cur_e_reg, cur_act, bnk_ctr)
|
683 |
|
|
begin
|
684 |
|
|
if sln_ctr >= cur_s_reg(4 downto 0) and sln_ctr <= cur_e_reg and cur_act = '1' then
|
685 |
|
|
case cur_s_reg(6 downto 5) is
|
686 |
|
|
when "00" =>
|
687 |
|
|
cur_ena <= '1';
|
688 |
|
|
when "10" =>
|
689 |
|
|
cur_ena <= bnk_ctr(3);
|
690 |
|
|
when "11" =>
|
691 |
|
|
cur_ena <= bnk_ctr(4);
|
692 |
|
|
when others =>
|
693 |
|
|
cur_ena <= '0';
|
694 |
|
|
end case;
|
695 |
|
|
else
|
696 |
|
|
cur_ena <= '0';
|
697 |
|
|
end if;
|
698 |
|
|
end process;
|
699 |
|
|
|
700 |
|
|
--------------------------------------------
|
701 |
|
|
-- Light Pen Capture --
|
702 |
|
|
--------------------------------------------
|
703 |
|
|
--
|
704 |
|
|
-- The light pen resister is loaded
|
705 |
|
|
-- when ther is a high on the light
|
706 |
|
|
-- pen strobe input
|
707 |
|
|
--
|
708 |
|
|
ctrc_lpn_stb_p: process(chr_clk, rst, lpn_stb)
|
709 |
|
|
begin
|
710 |
|
|
if rising_edge(chr_clk) then
|
711 |
|
|
if rst = '1' then
|
712 |
|
|
lpn_h_reg <= (others => '0');
|
713 |
|
|
lpn_l_reg <= (others => '0');
|
714 |
|
|
elsif lpn_stb = '1' then
|
715 |
|
|
lpn_h_reg <= lag_ctr(13 downto 8);
|
716 |
|
|
lpn_l_reg <= lag_ctr(7 downto 0);
|
717 |
|
|
end if;
|
718 |
|
|
end if;
|
719 |
|
|
end process;
|
720 |
|
|
|
721 |
|
|
end rtl;
|
722 |
|
|
|