library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; -- During vblank, we transfer image to SRAM using DMA and Avalon Flow Control -- During vactive, display whatever is in SRAM to VGA screen entity vgafb is port ( reset_n : in std_logic; clk : in std_logic; -- 50 Mhz; we downscale to 25 MHz ourselves -- Avalon Bus signals signal chipselect : in std_logic; signal write, read : in std_logic; signal address : in std_logic_vector(17 downto 0); signal readdata : out std_logic_vector(15 downto 0); signal writedata : in std_logic_vector(15 downto 0); signal byteenable : in std_logic_vector(1 downto 0); signal readyfordata : out std_logic; -- VGA Output signals VGA_CLK, -- Clock VGA_HS, -- H_SYNC VGA_VS, -- V_SYNC VGA_BLANK, -- BLANK VGA_SYNC : out std_logic; -- SYNC VGA_R, -- Red[9:0] VGA_G, -- Green[9:0] VGA_B : out unsigned(9 downto 0) -- Blue[9:0] ); end vgafb; architecture dp of vgafb is -- Video parameters constant HRES : integer := 320; constant VRES : integer := 200; constant HTOTAL : integer := 800; constant HSYNC : integer := 96; constant HBACK_PORCH : integer := 48; constant HACTIVE : integer := 640; constant HFRONT_PORCH : integer := 16; constant VTOTAL : integer := 525; constant VSYNC : integer := 2; constant VBACK_PORCH : integer := 33; constant VACTIVE : integer := 480; constant VFRONT_PORCH : integer := 10; constant FB_MIN_ROW : integer := 0; constant FB_MAX_ROW : integer := VRES - 1; constant FB_MIN_COL : integer := 0; constant FB_MAX_COL : integer := HRES - 1; -- Signals for the video controller signal Hcount : unsigned(9 downto 0); -- Horizontal position (0-800) signal Vcount : unsigned(9 downto 0); -- Vertical position (0-524) signal EndOfLine, EndOfField : std_logic; -- Sync. signals signal vga_hblank, vga_hsync, vga_vblank, vga_vsync : std_logic; -- 25 MHz clock for all video signal control signal video_clk : std_logic; signal reset : std_logic; signal row, col : unsigned(17 downto 0); signal FB_Addr : unsigned (17 downto 0); signal flowready : std_logic := '0'; begin reset <= not reset_n; -- Get address of SRAM for current pixel FB_Addr <= to_unsigned( ((to_integer(ROW) * HRES) + to_integer(COL)) , 18); -- downscale 50 MHz clock to 25 MHz video clock VideoClock: process (clk) begin if rising_edge(clk) then video_clk <= not video_clk; end if; end process VideoClock; -- AvalonValid lets avalon know when we are ready for data transfer AvalonValid : process (clk) begin if rising_edge(clk) then if Vcount = VSYNC + VBACK_PORCH + VACTIVE - 1 then flowready <= '1'; readyfordata <= '1'; elsif Vcount = VSYNC + VBACK_PORCH - 1 then flowready <= '0'; readyfordata <= '0'; end if; end if; end process AvalonValid; -- Horizontal and vertical counters HCounter : process (video_clk) variable c : integer; begin if rising_edge(video_clk) then if reset = '1' then Hcount <= (others => '0'); COL <= (others => '0'); elsif EndOfLine = '1' then Hcount <= (others => '0'); else Hcount <= Hcount + 1; end if; c := (to_integer(Hcount) - (HSYNC + HBACK_PORCH)) / 2; if c > FB_MAX_COL then c := FB_MAX_COL; elsif c < FB_MIN_COL then c := FB_MIN_COL; end if; COL <= to_unsigned(c, 18); end if; end process HCounter; EndOfLine <= '1' when Hcount = HTOTAL - 1 else '0'; VCounter: process (video_clk) variable r : integer; begin if rising_edge(video_clk) then if reset = '1' then Vcount <= (others => '0'); ROW <= (others => '0'); elsif EndOfLine = '1' then if EndOfField = '1' then Vcount <= (others => '0'); else Vcount <= Vcount + 1; end if; r := ((to_integer(Vcount) - (VSYNC + VBACK_PORCH) - (VACTIVE/2 - VRES)) / 2); if r > FB_MAX_ROW then r := FB_MAX_ROW; elsif r < FB_MIN_ROW then r := FB_MIN_ROW; end if; ROW <= to_unsigned(r, 18); end if; end if; end process VCounter; EndOfField <= '1' when Vcount = VTOTAL - 1 else '0'; -- State machines to generate HSYNC, VSYNC, HBLANK, and VBLANK HSyncGen : process (video_clk) begin if rising_edge(video_clk) then if reset = '1' or EndOfLine = '1' then vga_hsync <= '1'; elsif Hcount = HSYNC - 1 then vga_hsync <= '0'; end if; end if; end process HSyncGen; HBlankGen : process (video_clk) begin if rising_edge(video_clk) then if reset = '1' then vga_hblank <= '1'; elsif Hcount = HSYNC + HBACK_PORCH then vga_hblank <= '0'; elsif Hcount = HSYNC + HBACK_PORCH + HACTIVE then vga_hblank <= '1'; end if; end if; end process HBlankGen; VSyncGen : process (video_clk) begin if rising_edge(video_clk) then if reset = '1' then vga_vsync <= '1'; elsif EndOfLine ='1' then if EndOfField = '1' then vga_vsync <= '1'; elsif Vcount = VSYNC - 1 then vga_vsync <= '0'; end if; end if; end if; end process VSyncGen; VBlankGen : process (video_clk) begin if rising_edge(video_clk) then if reset = '1' then vga_vblank <= '1'; elsif EndOfLine = '1' then if Vcount = VSYNC + VBACK_PORCH - 1 then vga_vblank <= '0'; elsif Vcount = VSYNC + VBACK_PORCH + VACTIVE - 1 then vga_vblank <= '1'; end if; end if; end if; end process VBlankGen; -- Registered video signals going to the video DAC VideoOut: process (video_clk, reset) variable r, b : std_logic_vector(4 downto 0); variable g : std_logic_vector(5 downto 0); begin if reset = '1' then VGA_R <= "0000000000"; VGA_G <= "0000000000"; VGA_B <= "0000000000"; elsif video_clk'event and video_clk = '1' then if vga_hblank = '0' and vga_vblank ='0' then if vcount > vsync + vback_porch + ((vactive/2) - vres) and vcount < vsync + vback_porch + ((vactive/2) - vres) + (vres * 2) - 1 then VGA_R(9 downto 5) <= unsigned(r); VGA_G(9 downto 4) <= unsigned(g); VGA_B(9 downto 5) <= unsigned(b); VGA_R(4 downto 0) <= "00000"; VGA_G(3 downto 0) <= "0000"; VGA_B(4 downto 0) <= "00000"; else VGA_R <= "0000000000"; VGA_G <= "0000000000"; VGA_B <= "0000000000"; end if; else VGA_R <= "0000000000"; VGA_G <= "0000000000"; VGA_B <= "0000000000"; end if; end if; end process VideoOut; VGA_CLK <= video_clk; VGA_HS <= not vga_hsync; VGA_VS <= not vga_vsync; VGA_SYNC <= '0'; VGA_BLANK <= not (vga_hsync or vga_vsync); end dp;