-- Description: Simple testbench for VGA controller --Input/Output map description --HS corresponds to honizonal sync --VS corresponds to vertical sync --pixel_x corresponds to horizonal count --pixel_y corresponds to vertical count --last column corresponds to the last columm for a particular row, -- (indicates that the current pixel corresponds to the last visible column --last row corresponds to the last row in the pixel range, -- (indicates that the last visible line is being displayed) --blank corresonds to the vga outputting black because it is not in the valid -- pixel write zones -- (Indicates that the current pixel is part of a horizontal or vertical -- retrace and that the output color must be blanked. The VGA pixel must -- be set to "black" during blanking.) library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; library std; use std.textio.all; entity tb_vga_timing is end tb_vga_timing; architecture testbench of tb_vga_timing is component vga_timing port( clk : in std_logic; rst : in std_logic; HS : out std_logic; VS : out std_logic; pixel_x : out std_logic_vector(9 downto 0); pixel_y : out std_logic_vector(9 downto 0); last_column : out std_logic; last_row : out std_logic; blank : out std_logic ); end component; signal t_clk, t_rst, t_pixel_en : std_logic; signal t_HS, t_VS, t_blank : std_logic; signal t_pixel_x : std_logic_vector(9 downto 0); signal t_pixel_y : std_logic_vector(9 downto 0); signal t_column : unsigned(9 downto 0); signal t_row : unsigned(9 downto 0); signal t_last_column, t_last_row : std_logic; signal clk50MHz : std_logic := '0'; constant UNINIT_STARTUP_TIME : time := 200 ns; constant CLOCK_PERIOD : time := 20 ns; constant HALF_CLOCK_PERIOD : time := CLOCK_PERIOD / 2; constant UNINITIALIZED_TIME : time := 500 ns; constant CLOCK_INIT_TIME : time := 500 ns; constant RESET_RELEASE_TIME : time := CLOCK_INIT_TIME + 500 ns; constant POST_RESET_TEST_TIME : time := 45 ms; -- 96 pixel clocks (3840 ns) constant HS_LOW_TIME : time := 3840 ns; -- 800-96=704 pixel clocks (28160 ns) constant HS_HIGH_TIME : time := 28160 ns; -- 2 lines = 2x800 = 1600 clocks (64,000 ns) --constant VS_LOW_TIME : time := 30080 ns; constant VS_LOW_TIME : time := 64_000 ns; -- 521-2 lines = 519x800 = 415200 clocks (1660800) -- 0-479: display -- 480-489: front porch -- 490-491: pulse --constant VS_HIGH_TIME : time := 16353920 ns; constant VS_HIGH_TIME : time := 16_608_000 ns; type CLOCK_STATE_TYPE is (uninitialized, zero, running); signal clock_state : CLOCK_STATE_TYPE; begin -- testbench -------------------------------------------------- -- Main testbench process: -------------------------------------------------- process begin report "--- Begin with input signals uninitialized ---"; clock_State <= uninitialized; t_rst <= 'U'; wait for UNINITIALIZED_TIME; report "--- Start Clock Without Reset ---"; clock_State <= zero; wait for CLOCK_INIT_TIME; clock_state <= running; wait for CLOCK_INIT_TIME; report "--- Issue Reset ---"; t_rst <= '1'; wait for RESET_RELEASE_TIME; report "--- Release Reset ---"; t_rst <= '0'; -- The initialization is over. Let the timing generator -- run for a while wait for POST_RESET_TEST_TIME; report "--- Done ---"; wait; end process; ---------------------------------------------------------------------- -- Design under test ---------------------------------------------------------------------- uut: vga_timing port map ( clk => t_clk, rst => t_rst, HS => t_HS, VS => t_VS, pixel_x => t_pixel_x, pixel_y => t_pixel_y, last_column => t_last_column, last_row => t_last_row, blank => t_blank); t_column <= unsigned(t_pixel_x); t_row <= unsigned(t_pixel_y); -- Check the last_column signal process(t_last_column,t_column,t_last_row,t_row) begin assert ((t_last_column = '1' and t_column = 639) or t_last_column /= '1') or not t_last_column'stable report "Incorrect last_column signal"; -- Check last row signal assert ((t_last_row = '1' and t_row = 479) or t_last_row /= '1') or not t_last_row'stable report "Incorrect last_row signal"; end process; -- Response: Check the blank signal process(t_blank, t_column, t_row) begin if(t_blank'stable and t_column'stable and t_row'stable)then assert (t_blank = '1' and (t_column > 639 or t_row > 479)) or t_blank /= '1' report "Incorrect blank signal timing: Blank should be high"; assert (t_blank = '0' and t_column <= 639 and t_row <= 479) or t_blank /= '0' report "Incorrect blank signal timing: Blank should be low"; end if; end process; --------------------------------------------------------------- -- Check the HS signal. Measure both the high and low time --------------------------------------------------------------- process variable hs_falling_edge_time, hs_rising_edge_time, hs_low_time_measured, hs_high_time_measured : time; variable L : LINE; begin -- Wait until a falling edge on HS wait until t_hs'event and t_hs = '0'; hs_falling_edge_time := NOW; -- Wait until a rising edge on HS wait until t_hs'event and t_hs = '1'; hs_rising_edge_time := NOW; hs_low_time_measured := hs_rising_edge_time - hs_falling_edge_time; if (hs_low_time_measured /= HS_LOW_TIME) then report "Incorrect HS Timing" severity error; write(L, string'("Incorrect HS low time. HS low measured at ")); write(L, hs_low_time_measured); write(L, string'(" but expecting ")); write(L, HS_LOW_TIME); writeline(output, L); end if; -- Wait until a falling edge on HS wait until t_hs'event and t_hs = '0'; hs_falling_edge_time := NOW; hs_high_time_measured := hs_falling_edge_time - hs_rising_edge_time; if (hs_high_time_measured /= HS_HIGH_TIME) then report "Incorrect HS Timing" severity error; write(L, string'("Incorrect HS high time. HS high measured at ")); write(L, hs_high_time_measured); write(L, string'(" but expecting ")); write(L, HS_HIGH_TIME); writeline(output, L); end if; end process; --------------------------------------------------------------- -- Response: check the VS signal --------------------------------------------------------------- process variable vs_falling_edge_time, vs_rising_edge_time, vs_low_time_measured, vs_high_time_measured : time; variable L : LINE; begin -- Wait until a falling edge on VS wait until t_vs'event and t_vs = '0'; vs_falling_edge_time := NOW; wait until t_vs'event and t_vs = '1'; vs_rising_edge_time := NOW; vs_low_time_measured := vs_rising_edge_time - vs_falling_edge_time; if (vs_low_time_measured /= VS_LOW_TIME) then report "Incorrect VS Timing" severity error; write(L, string'("Incorrect VS low time. VS low measured at ")); write(L, vs_low_time_measured); write(L, string'(" but expecting ")); write(L, VS_LOW_TIME); writeline(output, L); end if; wait until t_vs'event and t_vs = '0'; vs_falling_edge_time := NOW; vs_high_time_measured := vs_falling_edge_time - vs_rising_edge_time; if (vs_high_time_measured /= VS_HIGH_TIME) then report "Incorrect VS Timing" severity error; write(L, string'("Incorrect VS high time. VS high measured at ")); write(L, vs_high_time_measured); write(L, string'(" but expecting ")); write(L, VS_HIGH_TIME); writeline(output, L); end if; end process; -------------------------------------------------- -- Clock generation statement -------------------------------------------------- with clock_state select t_clk <= 'U' when uninitialized, '0' when zero, clk50MHz when others; clk50MHz <= not clk50MHz after HALF_CLOCK_PERIOD; end testbench;