------------------------------------------------------- -- Project : TKT-1212 Digitaalijärjestelmien toteutus -- Author : Petteri Aimonen, student number 205441, group 50 -- Date : 2009-02-23 -- File : audio_ctrl.vhd -- Design: Course exercise 12: I2C configuration block test bench ------------------------------------------------------ -- Description : Verifies i2c_config ------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity tb_i2c_config is generic ( -- Configuration data for testing n_params_g : integer := 8; -- Simulated clock frequency (Hz) -- Uses 1MHz for faster simulation ref_clk_freq_g : integer := 1000000; -- Maximum frequency of the i2c bus i2c_freq_g : integer := 20000; -- Count of simulated configuration rounds -- The deny pattern will be different every time test_count_g : integer := 5; -- 7 bit register address, 9 bit data -- NOTE: the vector uses ascending range, so the parameters are in logical -- order but the bits are not. -- NOTE2: the test bench assumes that these are in order by register address param_values_g : std_logic_vector := "0000000" & "100000000" & "0000001" & "010000000" & "0000010" & "001000000" & "0000011" & "000100000" & "0000100" & "000010000" & "0000101" & "000001000" & "0000110" & "000000100" & "0000111" & "000000010" ); end entity; architecture testbench of tb_i2c_config is component i2c_receiver_model is generic ( n_params_g : integer; address_byte_g : std_logic_vector := "00110100" ); port ( rst_n : in std_logic; clk : in std_logic; sdat_inout : inout std_logic; sclk_in : in std_logic; deny_ack_in : in std_logic; registers_out : out std_logic_vector(n_params_g * 9 - 1 downto 0) ); end component; component i2c_config is generic ( ref_clk_freq_g : integer := 50000000; i2c_freq_g : integer := 20000; n_params_g : integer := 10; addr_byte_g : std_logic_vector := "00110100"; param_values_g : std_logic_vector ); port( clk : in std_logic; rst_n : in std_logic; sdat_inout : inout std_logic; sclk_out : out std_logic; param_status_out : out std_logic_vector(n_params_g - 1 downto 0); finished_out : out std_logic ); end component; component i2c_timing_checker is generic ( sclk_low_period_g : time := 4.7 us; sclk_high_period_g : time := 4.0 us; start_hold_time_g : time := 4.0 us; repeated_start_setup_g : time := 4.7 us; data_setup_time_g : time := 250 ns; stop_setup_time_g : time := 4.0 us; bus_free_time_g : time := 4.7 us ); port ( clk : in std_logic; rst_n : in std_logic; sdat_in : in std_logic; sclk_in : in std_logic ); end component; constant clk_period_c : time := (1 sec) / ref_clk_freq_g / 2; -- Simulated I2C bus signal i2c_sdat : std_logic; signal i2c_sclk : std_logic; -- Tell receiver not to acknowledge bytes signal deny_ack : std_logic; -- Map of register values received signal received_regs : std_logic_vector(n_params_g * 9 - 1 downto 0); -- Status of the i2c config block signal param_status : std_logic_vector(n_params_g - 1 downto 0); signal finished : std_logic; -- Clock and reset signals to devices signal clk_to_dut : std_logic; signal rst_to_dut : std_logic; -- Deny the ack randomly signal ack_deny_counter : integer; begin assert param_values_g'high = 16 * n_params_g - 1 report "Array param_values_g has wrong size" severity ERROR; i_i2c_model: i2c_receiver_model generic map (n_params_g => n_params_g) port map ( rst_n => rst_to_dut, clk => clk_to_dut, sdat_inout => i2c_sdat, sclk_in => i2c_sclk, deny_ack_in => deny_ack, registers_out => received_regs ); i_i2c_config: i2c_config generic map ( ref_clk_freq_g => ref_clk_freq_g, i2c_freq_g => i2c_freq_g, n_params_g => n_params_g, param_values_g => param_values_g ) port map ( clk => clk_to_dut, rst_n => rst_to_dut, sdat_inout => i2c_sdat, sclk_out => i2c_sclk, param_status_out => param_status, finished_out => finished ); i_i2c_timing_checker: i2c_timing_checker port map ( clk => clk_to_dut, rst_n => rst_to_dut, sdat_in => i2c_sdat, sclk_in => i2c_sclk ); -- Simulate the pull-up resistor on i2c bus i2c_sdat <= 'H'; clk_gen_proc: process variable received_value_v : std_logic_vector(8 downto 0); variable correct_value_v : std_logic_vector(8 downto 0); begin for test_round in 1 to test_count_g loop -- Reset devices clk_to_dut <= '0'; rst_to_dut <= '0'; deny_ack <= '0'; wait for clk_period_c * 10; rst_to_dut <= '1'; while finished /= '1' loop clk_to_dut <= '1'; wait for clk_period_c; clk_to_dut <= '0'; wait for clk_period_c; ack_deny_counter <= ack_deny_counter + 1; -- Randomly instruct the receiver to skip the acknowledge bit if (ack_deny_counter mod 735) = 0 or (ack_deny_counter mod 533) = 0 then deny_ack <= not deny_ack; end if; end loop; for i in 0 to 1000 loop clk_to_dut <= '1'; wait for clk_period_c; clk_to_dut <= '0'; wait for clk_period_c; assert i2c_sclk = '1' and To_X01(i2c_sdat) = '1' report "I2C did not stay in idle state" severity FAILURE; end loop; -- Check that received values are correct for i in 0 to n_params_g - 1 loop -- The parameter MSB is at i * 16 -- The config byte MSB is 7 bits after that correct_value_v := param_values_g(i * 16 + 7 to i * 16 + 15); received_value_v := received_regs(i * 9 + 8 downto i * 9); assert received_value_v = correct_value_v report "Register " & integer'image(i) & " value received wrong: " & integer'image(to_integer(unsigned(received_value_v))) & " instead of " & integer'image(to_integer(unsigned(correct_value_v))) severity FAILURE; end loop; report "Simulation round " & integer'image(test_round) & " done" severity NOTE; end loop; report "Simulation completed" severity NOTE; wait; end process clk_gen_proc; end architecture;