library ieee; use ieee.std_logic_1164.all; library vunit_lib; -- use vunit_lib.check_pkg.all; context vunit_lib.vunit_context; use work.tb_pkg.all; use work.tb_i2c_pkg.all; package tb_i2c_slave_pkg is procedure i2c_slave_check_start ( constant address : in std_logic_vector(6 downto 0); constant rw : in std_logic; constant timeout : in time; signal scl : inout std_logic; signal sda : inout std_logic; constant ack : in std_logic := '1'); procedure i2c_slave_check_stop ( constant timeout : in time; signal scl : inout std_logic; signal sda : inout std_logic); procedure i2c_slave_transmit ( constant data : in std_logic_vector(7 downto 0); constant scl_timeout : in time; signal scl : inout std_logic; signal sda : inout std_logic; constant exp_ack : in std_logic := '1'); procedure i2c_slave_receive ( constant exp_data : in std_logic_vector(7 downto 0); constant scl_timeout : in time; signal scl : inout std_logic; signal sda : inout std_logic; constant ack : in std_logic := '1'); end package tb_i2c_slave_pkg; package body tb_i2c_slave_pkg is procedure i2c_slave_check_start ( constant address : in std_logic_vector(6 downto 0); constant rw : in std_logic; constant timeout : in time; signal scl : inout std_logic; signal sda : inout std_logic; constant ack : in std_logic := '1') is begin wait_for_start_condition(timeout, scl, sda); i2c_slave_receive(address & rw, timeout, scl, sda, ack); end procedure i2c_slave_check_start; procedure i2c_slave_check_stop ( constant timeout : in time; signal scl : inout std_logic; signal sda : inout std_logic) is begin wait_for_stop_condition(timeout, scl, sda); end procedure i2c_slave_check_stop; procedure i2c_slave_transmit ( constant data : in std_logic_vector(7 downto 0); constant scl_timeout : in time; signal scl : inout std_logic; signal sda : inout std_logic; constant exp_ack : in std_logic := '1') is begin -- procedure transmit if scl = 'H' then wait_for_scl_fall(scl_timeout, scl); end if; -- data for i in 7 downto 0 loop wait until falling_edge(clk); sda <= '0' when data(i) = '0' else 'Z'; wait_for_scl_rise(scl_timeout, scl); wait_for_scl_fall(scl_timeout, scl); end loop; -- i wait until falling_edge(clk); sda <= 'Z'; wait_for_scl_rise(scl_timeout, scl); if exp_ack = '1' then check_equal(sda, '0', "No acknowledge"); elsif exp_ack = '0' then check_equal(sda, 'H', "There was acknowledge even though there shouldn't have been"); end if; -- TODO consider removing this? wait_for_scl_fall(scl_timeout, scl); wait until falling_edge(clk); sda <= 'Z'; end procedure i2c_slave_transmit; procedure i2c_slave_receive ( constant exp_data : in std_logic_vector(7 downto 0); constant scl_timeout : in time; signal scl : inout std_logic; signal sda : inout std_logic; constant ack : in std_logic := '1') is begin -- procedure transmit if scl = 'H' then wait_for_scl_fall(scl_timeout, scl); end if; sda <= 'Z'; -- data for i in 7 downto 0 loop wait_for_scl_rise(scl_timeout, scl); if exp_data(i) = '1' then check(sda = '1' or sda = 'H', result("Received data (sda) not as expected.")); elsif exp_data(i) = '0' then check(sda = '0' or sda = 'L', result("Received data (sda) not as expected.")); end if; wait_for_scl_fall(scl_timeout, scl); end loop; -- i if ack = '1' then sda <= '0'; end if; wait_for_scl_rise(scl_timeout, scl); wait_for_scl_fall(scl_timeout, scl); sda <= 'Z'; end procedure i2c_slave_receive; end package body tb_i2c_slave_pkg;