1 | library IEEE;
|
2 | use IEEE.std_logic_1164.all;
|
3 | use IEEE.std_logic_unsigned.all;
|
4 |
|
5 | entity vgacore is
|
6 | port
|
7 | (
|
8 | rgb: out std_logic_vector(5 downto 0); -- red,green,blue colors
|
9 | addr: out std_logic_vector(14 downto 0); -- address into video RAM
|
10 | data: in std_logic_vector(7 downto 0); -- data from video RAM
|
11 | csb: out std_logic; -- video RAM chip enable
|
12 | oeb: out std_logic; -- video RAM output enable
|
13 | web: out std_logic -- video RAM write enable
|
14 | );
|
15 | end vgacore;
|
16 |
|
17 | architecture vgacore_arch of vgacore is
|
18 | signal vsyncb: std_logic:= '0';
|
19 | signal hsyncb:std_logic:= '0';
|
20 | signal clock: std_logic:= '0';
|
21 | signal reset:std_logic:= '0';
|
22 | signal hcnt: std_logic_vector(8 downto 0); -- horizontal pixel counter
|
23 | signal vcnt: std_logic_vector(9 downto 0); -- vertical line counter
|
24 | signal pixrg: std_logic_vector(7 downto 0); -- byte-wide register for 4 pixels
|
25 | signal blank: std_logic; -- video blanking signal
|
26 | signal pblank: std_logic; -- pipelined video blanking signal
|
27 | begin
|
28 |
|
29 | A: process(clock,reset)
|
30 | begin
|
31 | -- reset asynchronously clears pixel counter
|
32 | if reset='1' then
|
33 | hcnt <= "000000000";
|
34 | -- horiz. pixel counter increments on rising edge of dot clock
|
35 | elsif (clock'event and clock='1') then
|
36 | -- horiz. pixel counter rolls-over after 381 pixels
|
37 | if hcnt<380 then
|
38 | hcnt <= hcnt + 1;
|
39 | else
|
40 | hcnt <= "000000000";
|
41 | end if;
|
42 | end if;
|
43 | end process;
|
44 |
|
45 | B: process(hsyncb,reset)
|
46 | begin
|
47 | -- reset asynchronously clears line counter
|
48 | if reset='1' then
|
49 | vcnt <= "0000000000";
|
50 | -- vert. line counter increments after every horiz. line
|
51 | elsif (hsyncb'event and hsyncb='1') then
|
52 | -- vert. line counter rolls-over after 528 lines
|
53 | if vcnt<527 then
|
54 | vcnt <= vcnt + 1;
|
55 | else
|
56 | vcnt <= "0000000000";
|
57 | end if;
|
58 | end if;
|
59 | end process;
|
60 |
|
61 | C: process(clock,reset)
|
62 | begin
|
63 | -- reset asynchronously sets horizontal sync to inactive
|
64 | if reset='1' then
|
65 | hsyncb <= '1';
|
66 | -- horizontal sync is recomputed on the rising edge of every dot clock
|
67 | elsif (clock'event and clock='1') then
|
68 | -- horiz. sync is low in this interval to signal start of a new line
|
69 | if (hcnt>=291 and hcnt<337) then
|
70 | hsyncb <= '0';
|
71 | else
|
72 | hsyncb <= '1';
|
73 | end if;
|
74 | end if;
|
75 | end process;
|
76 |
|
77 | D: process(hsyncb,reset)
|
78 | begin
|
79 | -- reset asynchronously sets vertical sync to inactive
|
80 | if reset='1' then
|
81 | vsyncb <= '1';
|
82 | -- vertical sync is recomputed at the end of every line of pixels
|
83 | elsif (hsyncb'event and hsyncb='1') then
|
84 | -- vert. sync is low in this interval to signal start of a new frame
|
85 | if (vcnt>=490 and vcnt<492) then
|
86 | vsyncb <= '0';
|
87 | else
|
88 | vsyncb <= '1';
|
89 | end if;
|
90 | end if;
|
91 | end process;
|
92 |
|
93 | -- blank video outside of visible region: (0,0) -> (255,479)
|
94 | E: blank <= '1' when (hcnt>=256 or vcnt>=480) else '0';
|
95 | -- store the blanking signal for use in the next pipeline stage
|
96 | F: process(clock,reset)
|
97 | begin
|
98 | if reset='1' then
|
99 | pblank <= '0';
|
100 | elsif (clock'event and clock='1') then
|
101 | pblank <= blank;
|
102 | end if;
|
103 | end process;
|
104 |
|
105 | -- video RAM control signals
|
106 | G:
|
107 | csb <= '0'; -- enable the RAM
|
108 | web <= '1'; -- disable writing to the RAM
|
109 | oeb <= blank; -- enable the RAM outputs when video is not blanked
|
110 |
|
111 | -- The video RAM address is built from the lower 9 bits of the vertical
|
112 | -- line counter and bits 7-2 of the horizontal pixel counter.
|
113 | -- Each byte of the RAM contains four 2-bit pixels. As an example,
|
114 | -- the byte at address ^h1234=^b0001,0010,0011,0100 contains the pixels
|
115 | -- at (row,col) of (^h048,^hD0),(^h048,^hD1),(^h048,^hD2),(^h048,^hD3).
|
116 | H: addr <= vcnt(8 downto 0) & hcnt(7 downto 2);
|
117 |
|
118 | I: process(clock,reset)
|
119 | begin
|
120 | -- clear the pixel register on reset
|
121 | if reset='1' then
|
122 | pixrg <= "00000000";
|
123 | -- pixel clock controls changes in pixel register
|
124 | elsif (clock'event and clock='1') then
|
125 | -- the pixel register is loaded with the contents of the video
|
126 | -- RAM location when the lower two bits of the horiz. counter
|
127 | -- are both zero. The active pixel is in the lower two bits
|
128 | -- of the pixel register. For the next 3 clocks, the pixel
|
129 | -- register is right-shifted by two bits to bring the other
|
130 | -- pixels in the register into the active position.
|
131 | if hcnt(1 downto 0)="00" then
|
132 | pixrg <= data; -- load 4 pixels from RAM
|
133 | else
|
134 | pixrg <= "00" & pixrg(7 downto 2); -- right-shift pixel register
|
135 | end if;
|
136 | end if;
|
137 | end process;
|
138 |
|
139 | -- the color mapper translates each 2-bit pixel into a 6-bit
|
140 | -- color value. When the video signal is blanked, the color
|
141 | -- is forced to zero (black).
|
142 | J: process(clock,reset)
|
143 | begin
|
144 | -- blank the video on reset
|
145 | if reset='1' then
|
146 | rgb <= "000000";
|
147 | -- update the color outputs on every dot clock
|
148 | elsif (clock'event and clock='1') then
|
149 | -- map the pixel to a color if the video is not blanked
|
150 | if pblank='0' then
|
151 | case pixrg(1 downto 0) is
|
152 | when "00" => rgb <= "110000"; -- red
|
153 | when "01" => rgb <= "001100"; -- green
|
154 | when "10" => rgb <= "000011"; -- blue
|
155 | when others => rgb <= "111111"; -- white
|
156 | end case;
|
157 | -- otherwise, output black if the video is blanked
|
158 | else
|
159 | rgb <= "000000"; -- black
|
160 | end if;
|
161 | end if;
|
162 | end process;
|
163 |
|
164 | end vgacore_arch;
|