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;