M tb/i2c/scl_generator_tb.vhd => tb/i2c/scl_generator_tb.vhd +2 -2
@@ 161,7 161,7 @@ begin -- architecture tb
stable_cannot_comply <= '0';
wait_delay(1);
- check_equal(cannot_comply, '1');
+ check_equal(cannot_comply, '1', "Wrong cannot comply");
elsif run("falling_rising_scl_low") then
req_falling;
wait_delay(DELAY);
@@ 170,7 170,7 @@ begin -- architecture tb
stable_cannot_comply <= '0';
wait_delay(DELAY);
- check_equal(cannot_comply, '1');
+ check_equal(cannot_comply, '1', "Wrong cannot comply");
check_equal(scl_enable, '0');
wait_delay(DELAY);
check_equal(scl_enable, '0');
M tb/i2c/tb_i2c_pkg.vhd => tb/i2c/tb_i2c_pkg.vhd +56 -0
@@ 41,6 41,24 @@ package tb_i2c_pkg is
constant exp_data : in std_logic_vector(7 downto 0);
signal rx_confirm_read : inout std_logic);
+ procedure wait_for_start_condition (
+ constant timeout : in time;
+ signal scl : in std_logic;
+ signal sda : in std_logic);
+
+ procedure wait_for_stop_condition (
+ constant timeout : in time;
+ signal scl : in std_logic;
+ signal sda : in std_logic);
+
+ procedure wait_for_scl_rise (
+ constant timeout : in time;
+ signal scl : in std_logic);
+
+ procedure wait_for_scl_fall (
+ constant timeout : in time;
+ signal scl : in std_logic);
+
end package tb_i2c_pkg;
package body tb_i2c_pkg is
@@ 128,4 146,42 @@ package body tb_i2c_pkg is
rx_confirm_read <= '0';
end procedure rx_read_data;
+ procedure wait_for_start_condition (
+ constant timeout : in time;
+ signal scl : in std_logic;
+ signal sda : in std_logic) is
+ begin
+ wait until falling_edge(sda) and scl = 'H' for timeout;
+ check(sda = '0' and scl = 'H', "Did not get start condition in time.");
+ end procedure wait_for_start_condition;
+
+ procedure wait_for_stop_condition (
+ constant timeout : in time;
+ signal scl : in std_logic;
+ signal sda : in std_logic) is
+ begin
+ wait until rising_edge(sda) and scl = 'H' for timeout;
+ check(sda = '1' and scl = 'H', "Did not get stop condition in time.");
+ end procedure wait_for_stop_condition;
+
+ procedure wait_for_scl_rise (
+ constant timeout : in time;
+ signal scl : in std_logic) is
+ begin
+ wait until scl = 'H' for timeout;
+ check_equal(scl, 'H', "Did not get rising scl in time.");
+ wait until falling_edge(clk);
+ end procedure wait_for_scl_rise;
+
+
+ procedure wait_for_scl_fall (
+ constant timeout : in time;
+ signal scl : in std_logic) is
+ begin
+ wait until scl = '0' for timeout;
+ check_equal(scl, '0', "Did not get falling scl in time.");
+ wait until falling_edge(clk);
+ end procedure wait_for_scl_fall;
+
+
end package body tb_i2c_pkg;
A tb/i2c/tb_i2c_slave_pkg.vhd => tb/i2c/tb_i2c_slave_pkg.vhd +138 -0
@@ 0,0 1,138 @@
+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
+ report "Start slave transmit";
+ if scl = 'H' then
+ wait_for_scl_fall(scl_timeout, scl);
+ end if;
+
+ -- data
+ for i in 7 downto 0 loop
+ report "Data " & integer'image(i) & " scl is: " & std_logic'image(scl);
+ 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);
+
+ report "Ack slave transmit";
+ 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."));
+ else
+ 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;