library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_unsigned.all; entity vgacore is port ( reset: in std_logic; -- reset clock: in std_logic; -- VGA dot clock hsyncb: buffer std_logic; -- horizontal (line) sync vsyncb: out std_logic; -- vertical (frame) sync rgb: out std_logic_vector(5 downto 0); -- red,green,blue colors addr: out std_logic_vector(14 downto 0); -- address into video RAM data: in std_logic_vector(7 downto 0); -- data from video RAM csb: out std_logic; -- video RAM chip enable oeb: out std_logic; -- video RAM output enable web: out std_logic -- video RAM write enable ); end vgacore; architecture vgacore_arch of vgacore is signal hcnt: std_logic_vector(8 downto 0); -- horizontal pixel counter signal vcnt: std_logic_vector(9 downto 0); -- vertical line counter signal pixrg: std_logic_vector(7 downto 0); -- byte-wide register for 4 pixels signal blank: std_logic; -- video blanking signal signal pblank: std_logic; -- pipelined video blanking signal begin A: process(clock,reset) begin -- reset asynchronously clears pixel counter if reset='1' then hcnt <= "000000000"; -- horiz. pixel counter increments on rising edge of dot clock elsif (clock'event and clock='1') then -- horiz. pixel counter rolls-over after 381 pixels if hcnt<380 then hcnt <= hcnt + 1; else hcnt <= "000000000"; end if; end if; end process; B: process(hsyncb,reset) begin -- reset asynchronously clears line counter if reset='1' then vcnt <= "0000000000"; -- vert. line counter increments after every horiz. line elsif (hsyncb'event and hsyncb='1') then -- vert. line counter rolls-over after 528 lines if vcnt<527 then vcnt <= vcnt + 1; else vcnt <= "0000000000"; end if; end if; end process; C: process(clock,reset) begin -- reset asynchronously sets horizontal sync to inactive if reset='1' then hsyncb <= '1'; -- horizontal sync is recomputed on the rising edge of every dot clock elsif (clock'event and clock='1') then -- horiz. sync is low in this interval to signal start of a new line if (hcnt>=291 and hcnt<337) then hsyncb <= '0'; else hsyncb <= '1'; end if; end if; end process; D: process(hsyncb,reset) begin -- reset asynchronously sets vertical sync to inactive if reset='1' then vsyncb <= '1'; -- vertical sync is recomputed at the end of every line of pixels elsif (hsyncb'event and hsyncb='1') then -- vert. sync is low in this interval to signal start of a new frame if (vcnt>=490 and vcnt<492) then vsyncb <= '0'; else vsyncb <= '1'; end if; end if; end process; -- blank video outside of visible region: (0,0) -> (255,479) E: blank <= '1' when (hcnt>=256 or vcnt>=480) else '0'; -- store the blanking signal for use in the next pipeline stage F: process(clock,reset) begin if reset='1' then pblank <= '0'; elsif (clock'event and clock='1') then pblank <= blank; end if; end process; -- video RAM control signals G: csb <= '0'; -- enable the RAM web <= '1'; -- disable writing to the RAM oeb <= blank; -- enable the RAM outputs when video is not blanked -- The video RAM address is built from the lower 9 bits of the vertical -- line counter and bits 7-2 of the horizontal pixel counter. -- Each byte of the RAM contains four 2-bit pixels. As an example, -- the byte at address ^h1234=^b0001,0010,0011,0100 contains the pixels -- at (row,col) of (^h048,^hD0),(^h048,^hD1),(^h048,^hD2),(^h048,^hD3). H: addr <= vcnt(8 downto 0) & hcnt(7 downto 2); I: process(clock,reset) begin -- clear the pixel register on reset if reset='1' then pixrg <= "00000000"; -- pixel clock controls changes in pixel register elsif (clock'event and clock='1') then -- the pixel register is loaded with the contents of the video -- RAM location when the lower two bits of the horiz. counter -- are both zero. The active pixel is in the lower two bits -- of the pixel register. For the next 3 clocks, the pixel -- register is right-shifted by two bits to bring the other -- pixels in the register into the active position. if hcnt(1 downto 0)="00" then pixrg <= data; -- load 4 pixels from RAM else pixrg <= "00" & pixrg(7 downto 2); -- right-shift pixel register end if; end if; end process; -- the color mapper translates each 2-bit pixel into a 6-bit -- color value. When the video signal is blanked, the color -- is forced to zero (black). J: process(clock,reset) begin -- blank the video on reset if reset='1' then rgb <= "000000"; -- update the color outputs on every dot clock elsif (clock'event and clock='1') then -- map the pixel to a color if the video is not blanked if pblank='0' then case pixrg(1 downto 0) is when "00" => rgb <= "110000"; -- red when "01" => rgb <= "001100"; -- green when "10" => rgb <= "000011"; -- blue when others => rgb <= "111111"; -- white end case; -- otherwise, output black if the video is blanked else rgb <= "000000"; -- black end if; end if; end process; end vgacore_arch;