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 : std_logic;
signal sda_override : std_logic := '0';
signal sda_enable, 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 err_noack : std_logic;
signal validate_sda_stable_when_scl_high : std_logic := '0';
signal check_noerr : std_logic := '0';
signal zero : std_logic := '0';
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;
constant trigger_ack : in std_logic;
signal sda_override : inout 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_enable, not 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
-- ack
if trigger_ack = '1' then
sda_override <= '1';
end if;
trigger_scl_pulse(scl, scl_rising_pulse, scl_falling_pulse);
if trigger_ack = '1' then
sda_override <= '0';
end if;
end procedure check_received_data;
begin -- architecture a1
uut : entity i2c.tx
port map (
clk_i => clk,
rst_in => rst_n,
start_write_i => start_write,
ss_condition_i => '0',
expect_ack_i => '1',
err_noack_o => err_noack,
scl_stretch_o => scl_stretch,
scl_rising_pulse_i => scl_rising_pulse,
scl_falling_delayed_i => scl_falling_pulse,
sda_enable_o => sda_enable,
sda_i => 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;
sda <= '0' when sda_override = '1' else
not sda_enable;
main: process is
begin -- process
scl <= '1';
wait until rst_n = '1';
wait until falling_edge(clk);
check_noerr <= '1';
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', '1', sda_override, scl, scl_rising_pulse, scl_falling_pulse);
check_equal(sda_enable, '0');
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', '1', sda_override, scl, scl_rising_pulse, scl_falling_pulse);
wait until falling_edge(clk);
check_received_data("00101011", '1', '1', sda_override, scl, scl_rising_pulse, scl_falling_pulse);
check_equal(sda_enable, '0');
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', '1', sda_override, 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', '1', sda_override, scl, scl_rising_pulse, scl_falling_pulse);
check_received_data("00001111", '1', '1', sda_override, scl, scl_rising_pulse, scl_falling_pulse);
check_equal(sda_enable, '0');
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', '1', sda_override, scl, scl_rising_pulse, scl_falling_pulse);
elsif run("no_ack") then
valid <= '1';
write_data <= "11010100";
check_equal(ready, '1');
start_write <= '1';
wait until falling_edge(clk);
valid <= '0';
check_noerr <= '0'; -- disable no err check
check_received_data("11010100", '1', '0', sda_override, scl, scl_rising_pulse, scl_falling_pulse);
check_equal(err_noack, '1');
check_equal(sda_enable, '0');
end if;
end loop;
test_runner_cleanup(runner);
end process;
no_err: check_stable(clk, check_noerr, check_noerr, zero, err_noack);
stability_check: check_stable(clk, validate_sda_stable_when_scl_high, scl_rising_pulse, scl_falling_pulse, sda_enable);
end architecture a1;