From 36d2d454fdda3a5c9ff10a8397de135f767cb027 Mon Sep 17 00:00:00 2001 From: Rutherther Date: Thu, 4 Jan 2024 22:46:54 +0100 Subject: [PATCH] tests: add basic master testbench --- tb/i2c/master_tb.vhd | 176 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 tb/i2c/master_tb.vhd diff --git a/tb/i2c/master_tb.vhd b/tb/i2c/master_tb.vhd new file mode 100644 index 0000000..a85be3a --- /dev/null +++ b/tb/i2c/master_tb.vhd @@ -0,0 +1,176 @@ +library ieee; +use ieee.std_logic_1164.all; + +library vunit_lib; +context vunit_lib.vunit_context; + +library i2c; + +use work.tb_pkg.all; +use work.tb_i2c_pkg.all; +use work.tb_i2c_master_pkg.all; +use work.tb_i2c_slave_pkg.all; + +entity master_tb is + + generic ( + runner_cfg : string); + +end entity master_tb; + +architecture tb of master_tb is + constant CLK_PERIOD : time := 10 ns; + signal rst_n : std_logic := '0'; + + signal master_sda_enable : std_logic; + signal master_sda : std_logic; + + signal slave_address : std_logic_vector(6 downto 0); + + signal master_scl_enable : std_logic; + signal master_scl : std_logic; + + signal dev_busy, bus_busy : std_logic; + signal err_noack_address, err_noack_data, err_arbitration, err_general : std_logic; + signal rw : std_logic; + + signal master_stop, master_start, master_run : std_logic := '0'; + signal waiting : std_logic; + + signal rx_confirm : std_logic := '0'; + + signal tx_valid : std_logic := '0'; + signal tx_data : std_logic_vector(7 downto 0) := (others => '0'); + + signal one : std_logic := '1'; + signal zero : std_logic := '0'; + + constant SCL_MIN_STABLE_CYCLES : natural := 5; + constant TIMEOUT : time := SCL_MIN_STABLE_CYCLES * CLK_PERIOD * 2; +begin -- architecture tb + + clk <= not clk after CLK_PERIOD / 2; + rst_n <= '1' after 2 * CLK_PERIOD; + + sda <= 'H'; + scl <= 'H'; + + sda <= '0' when master_sda_enable = '1' else 'Z'; + scl <= '0' when master_scl_enable = '1' else 'Z'; + + master_sda <= '1' when sda = 'H' else sda; + master_scl <= '1' when scl = 'H' else scl; + + uut : entity i2c.master + generic map ( + SCL_FALLING_DELAY => 1, + SCL_MIN_STABLE_CYCLES => SCL_MIN_STABLE_CYCLES) + port map ( + clk_i => clk, + rst_in => rst_n, +-- + slave_address_i => slave_address, +-- + generate_ack_i => '1', + expect_ack_i => '1', +-- + rx_valid_o => rx_valid, + rx_data_o => rx_data, + rx_confirm_i => rx_confirm, +-- + tx_ready_o => tx_ready, + tx_valid_i => tx_valid, + tx_data_i => tx_data, + tx_clear_buffer_i => '0', +-- + err_noack_data_o => err_noack_data, + err_noack_address_o => err_noack_address, + err_arbitration_o => err_arbitration, + err_general_o => err_general, +-- + stop_i => master_stop, + start_i => master_start, + run_i => master_run, + rw_i => rw, +-- + dev_busy_o => dev_busy, + bus_busy_o => bus_busy, + waiting_o => waiting, +-- + sda_i => master_sda, + scl_i => master_scl, + sda_enable_o => master_sda_enable, + scl_enable_o => master_scl_enable); + + -- stable sda_enable when scl high + -- TODO ensure active only when no start/stop + -- conditions should be generated... + -- sda_stability_check: check_stable(clk, one, scl, not_scl, master_sda_enable); + + main: process is + procedure request_start( + constant address : in std_logic_vector(6 downto 0); + constant rw_i : in std_logic; + constant stop : in std_logic := '0') is + begin -- procedure request_start + slave_address <= address; + rw <= rw_i; + + master_start <= '1'; + master_stop <= stop; + master_run <= '1'; + wait until falling_edge(clk); + master_start <= '0'; + master_stop <= '0'; + end procedure request_start; + + procedure request_stop is + begin -- procedure request_stop + master_start <= '0'; + master_stop <= '1'; + master_run <= '0'; + wait until falling_edge(clk); + master_stop <= '0'; + end procedure request_stop; + + procedure check_errors ( + constant exp_noack_address : in std_logic := '0'; + constant exp_noack_data : in std_logic := '0'; + constant exp_arbitration : in std_logic := '0'; + constant exp_general : in std_logic := '0') is + begin -- procedure check_errors + check_equal(err_noack_address, exp_noack_address, "Noack address error not as expected."); + check_equal(err_noack_data, exp_noack_data, "Noack data error not as expected."); + check_equal(err_arbitration, exp_arbitration, "Arbitration error not as expected."); + check_equal(err_general, exp_general, "Gneral error not as expected."); + end procedure check_errors; + begin -- process main + 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_read") then + request_start("1110101", '1', stop => '1'); + i2c_slave_check_start("1110101", '1', TIMEOUT, scl, sda); + i2c_slave_transmit("11101010", TIMEOUT, scl => scl, sda => sda); + rx_read_data("11101010", rx_confirm); + check_errors; + i2c_slave_check_stop(TIMEOUT, scl, sda); + check_errors; + elsif run("simple_write") then + request_start("1110101", '0', stop => '1'); + tx_write_data("11101010", tx_data, tx_valid); + i2c_slave_check_start("1110101", '0', TIMEOUT, scl, sda); + i2c_slave_receive("11101010", TIMEOUT, scl, sda); + check_errors; + i2c_slave_check_stop(TIMEOUT, scl, sda); + check_errors; + end if; + end loop; + + test_runner_cleanup(runner); + end process main; +end architecture tb; -- 2.49.0