-- This testbench is intended to help you test your VGA code and find timing -- errors. It prints out the various timing intervals (front porch, vsync -- pulse, etc) so that you can check them against the specified values. -- It has not been tested extensively and may not catch all bugs, but hopefully -- it catches some! -- -- Tufts ES 4 (http://www.ece.tufts.edu/es/4/) -- Steven Bell library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; entity vga_test is -- testbench end; architecture sim of vga_test is component vga is port ( clk : in std_logic; hsync : out std_logic; vsync : out std_logic; row : out unsigned (9 downto 0); -- includes vsync rows col : out unsigned (9 downto 0); -- includes hsync rows valid : out std_logic ); end component; signal clk : std_logic; signal hsync : std_logic; signal vsync : std_logic; signal row : unsigned (9 downto 0); signal col : unsigned (9 downto 0); signal valid : std_logic; constant CLOCK_PERIOD : time := 39.722 ns; -- 25.175 MHz pixel clock constant ROW_TIME : time := CLOCK_PERIOD * 800; -- Time elapsed for a whole horizontal scanline begin vga_dut : vga port map(clk => clk, hsync => hsync, vsync => vsync, row => row, col => col, valid => valid); process begin clk <= '0'; wait for CLOCK_PERIOD / 2; clk <= '1'; wait for CLOCK_PERIOD / 2; end process; process variable front_porch_start : time; variable sync_start : time; variable back_porch_start : time; variable visible_start : time; variable dt : time; variable last_valid_high : time; -- Last time valid was high, for finding vertical front porch begin -- Check the following horizontal intervals -- * Front porch (valid low, but HSYNC still high) -- * hsync pulse (HSYNC low) -- * Back porch (valid low, but HSYNC high again) -- * visible area (valid high) wait until valid = '1'; wait until falling_edge(valid); assert hsync = '1' report "HSYNC was " & to_string(hsync) & " at start of front porch"; front_porch_start := now; wait until falling_edge(hsync); sync_start := now; dt := sync_start - front_porch_start; report "front porch is " & to_string(dt, UNIT=>us) & " (" & to_string(dt / CLOCK_PERIOD) & " cycles)"; wait until rising_edge(hsync); back_porch_start := now; dt := back_porch_start - sync_start; report "sync pulse is " & to_string(dt, UNIT=>us) & " (" & to_string(dt / CLOCK_PERIOD) & " cycles)"; wait until rising_edge(valid); visible_start := now; dt := visible_start - back_porch_start; report "back porch is " & to_string(dt, UNIT=>us) & " (" & to_string(dt / CLOCK_PERIOD) & " cycles)"; wait until falling_edge(valid); front_porch_start := now; dt := front_porch_start - visible_start; report "horizontal visible period is " & to_string(dt, UNIT=>us) & " (" & to_string(dt / CLOCK_PERIOD) & " cycles)"; -- Check the following vertical intervals -- * Front porch (valid low, but VSYNC still high) -- * hsync pulse (VSYNC low) -- * Back porch (valid low, but VSYNC high again) -- Look for a falling edge while keeping track of the last time valid was high -- This will tell us the vertical front porch while vsync = '1' loop wait on valid, vsync; -- Wait for valid or vsync to change (either rising or falling edge) if falling_edge(valid) then last_valid_high := now; end if; end loop; -- The loop will exit as soon as vsync goes low, which is the start of the sync pulse sync_start := now; dt := sync_start - last_valid_high; report "vertical front porch is " & to_string(dt, UNIT=>ms) & " (" & to_string(dt / ROW_TIME) & " rows)"; wait until rising_edge(vsync); back_porch_start := now; dt := back_porch_start - sync_start; report "vsync pulse is " & to_string(dt, UNIT=>ms) & " (" & to_string(dt / ROW_TIME) & " rows)"; wait until rising_edge(valid); visible_start := now; dt := visible_start - back_porch_start; report "vertical back porch is " & to_string(dt, UNIT=>ms) & " (" & to_string(dt / ROW_TIME) & " rows)"; -- End the simulation here std.env.finish; end process; end;