From eb2258a9ca00b9da79a50c8e678b6842a64cbe5f Mon Sep 17 00:00:00 2001 From: Rutherther Date: Fri, 29 Dec 2023 20:50:43 +0100 Subject: [PATCH] tests: add tx testbench --- tb/i2c/tx_tb.vhd | 205 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 tb/i2c/tx_tb.vhd diff --git a/tb/i2c/tx_tb.vhd b/tb/i2c/tx_tb.vhd new file mode 100644 index 0000000..5eb1656 --- /dev/null +++ b/tb/i2c/tx_tb.vhd @@ -0,0 +1,205 @@ +library ieee; +use ieee.std_logic_1164.all; + +library i2c; + +library vunit_lib; +context vunit_lib.vunit_context; + +entity tx_tb is + + generic ( + runner_cfg : string); + +end entity tx_tb; + +architecture a1 of tx_tb is + signal clk : std_logic := '0'; + constant CLK_PERIOD : time := 10 ns; + + signal rst_n : std_logic := '0'; + + signal sda, scl : std_logic := '0'; + signal scl_rising_pulse, scl_falling_pulse : std_logic := '0'; + + signal start_write : std_logic := '0'; + signal valid, ready : std_logic := '0'; + signal write_data : std_logic_vector(7 downto 0); + signal scl_stretch : std_logic; + + signal validate_sda_stable_when_scl_high : std_logic := '0'; + + -- validate sda stable when scl = '1' + + procedure trigger_scl_pulse( + signal scl : inout std_logic; + signal scl_rising_pulse : inout std_logic; + signal scl_falling_pulse : inout std_logic) is + begin -- procedure trigger_scl_pulse + scl_falling_pulse <= scl; + scl_rising_pulse <= '0'; + scl <= '0'; + wait until falling_edge(clk); + scl <= '1'; + scl_falling_pulse <= '0'; + scl_rising_pulse <= '1'; + wait until falling_edge(clk); + scl_rising_pulse <= '0'; + wait until falling_edge(clk); + scl <= '0'; + scl_falling_pulse <= '1'; + wait until falling_edge(clk); + scl_rising_pulse <= '0'; + scl_falling_pulse <= '0'; + wait until falling_edge(clk); + wait until falling_edge(clk); + wait until falling_edge(clk); + end procedure trigger_scl_pulse; + + procedure trigger_scl_rise( + signal scl : inout std_logic; + signal scl_rising_pulse : inout std_logic; + signal scl_falling_pulse : inout std_logic) is + begin -- procedure trigger_scl_pulse + check_equal(scl, '0'); + wait until falling_edge(clk); + scl <= '1'; + scl_rising_pulse <= '1'; + scl_falling_pulse <= '0'; + wait until falling_edge(clk); + scl_rising_pulse <= '0'; + scl_falling_pulse <= '0'; + end procedure trigger_scl_rise; + + procedure check_received_data ( + constant data : in std_logic_vector(7 downto 0); + constant check_ready : in std_logic; + signal scl : inout std_logic; + signal scl_rising_pulse : inout std_logic; + signal scl_falling_pulse : inout std_logic) is + begin + check(scl_stretch = '0', "Cannot send when stretch is active", failure); + wait until falling_edge(clk); + + if scl = '1' then + scl <= '0'; + scl_falling_pulse <= '1'; + scl_rising_pulse <= '0'; + wait until falling_edge(clk); + scl_falling_pulse <= '0'; + scl_rising_pulse <= '0'; + end if; + + for i in 7 downto 0 loop + check_equal(sda, data(i)); + + if check_ready /= 'Z' then + check_equal(ready, check_ready); + end if; + + check(scl_stretch = '0', "Cannot send when stretch is active", failure); + + trigger_scl_pulse(scl, scl_rising_pulse, scl_falling_pulse); + end loop; -- i + end procedure check_received_data; + +begin -- architecture a1 + uut : entity i2c.tx + generic map ( + DELAY_SDA_FOR => 1) + port map ( + clk_i => clk, + rst_in => rst_n, + start_write_i => start_write, + ss_condition_i => '0', + scl_stretch_o => scl_stretch, + scl_rising_pulse_i => scl_rising_pulse, + scl_falling_pulse_i => scl_falling_pulse, + sda_o => sda, + ready_o => ready, + valid_i => valid, + write_data_i => write_data); + + clk <= not clk after CLK_PERIOD / 2; + rst_n <= '1' after 2 * CLK_PERIOD; + + main: process is + begin -- process + scl <= '1'; + wait until rst_n = '1'; + wait until falling_edge(clk); + test_runner_setup(runner, runner_cfg); + set_stop_level(failure); + + + while test_suite loop + if run("simple") then + valid <= '1'; + write_data <= "11010100"; + check_equal(ready, '1'); + start_write <= '1'; + wait until falling_edge(clk); + valid <= '0'; + check_received_data("11010100", '1', scl, scl_rising_pulse, scl_falling_pulse); + check_equal(sda, '1'); + elsif run("twice") then + valid <= '1'; + write_data <= "11010100"; + check_equal(ready, '1'); + start_write <= '1'; + wait until falling_edge(clk); + write_data <= "00101011"; + check_equal(ready, '1'); + wait until falling_edge(clk); + valid <= '0'; + check_equal(ready, '0'); + + check_received_data("11010100", '0', scl, scl_rising_pulse, scl_falling_pulse); + wait until falling_edge(clk); + check_received_data("00101011", '1', scl, scl_rising_pulse, scl_falling_pulse); + check_equal(sda, '1'); + elsif run("three") then + valid <= '1'; + write_data <= "11010100"; + check_equal(ready, '1'); + start_write <= '1'; + wait until falling_edge(clk); + write_data <= "00101011"; + check_equal(ready, '1'); + wait until falling_edge(clk); + valid <= '0'; + check_equal(ready, '0'); + + check_received_data("11010100", '0', scl, scl_rising_pulse, scl_falling_pulse); + wait until falling_edge(clk); + check_equal(ready, '1'); + write_data <= "00001111"; + valid <= '1'; + wait until falling_edge(clk); + valid <= '0'; + check_received_data("00101011", '0', scl, scl_rising_pulse, scl_falling_pulse); + check_received_data("00001111", '1', scl, scl_rising_pulse, scl_falling_pulse); + check_equal(sda, '1'); + elsif run("stretching") then + start_write <= '1'; + check_equal(scl_stretch, '0'); + wait until falling_edge(clk); + for i in 0 to 5 loop + check_equal(scl_stretch, '1'); + wait until falling_edge(clk); + end loop; -- i + + valid <= '1'; + write_data <= "11001100"; + wait until falling_edge(clk); + valid <= '0'; + check_equal(scl_stretch, '0'); + check_received_data("11001100", '1', scl, scl_rising_pulse, scl_falling_pulse); + end if; + end loop; + + test_runner_cleanup(runner); + end process; + + stability_check: check_stable(clk, validate_sda_stable_when_scl_high, scl_rising_pulse, scl_falling_pulse, sda); +end architecture a1; -- 2.49.0