library ieee;
use ieee.std_logic_1164.all;
library i2c;
library vunit_lib;
context vunit_lib.vunit_context;
entity address_generator_tb is
generic (
runner_cfg : string);
end entity address_generator_tb;
architecture tb of address_generator_tb is
signal clk : std_logic := '0';
constant CLK_PERIOD : time := 10 ns;
signal rst_n : std_logic := '0';
signal sda : std_logic := 'H';
signal slave_sda : std_logic := 'H';
signal sda_enable : std_logic;
signal scl : std_logic := 'H';
signal not_scl : std_logic;
signal scl_rising : std_logic := '0';
signal scl_falling : std_logic := '0';
signal scl_falling_delayed : std_logic := '0';
signal start : std_logic := '0';
signal done : std_logic;
signal unexpected_sda, noack : std_logic;
signal rw : std_logic := '0';
signal address : std_logic_vector(6 downto 0);
signal one : std_logic := '1';
signal zero : std_logic := '0';
begin -- architecture tb
clk <= not clk after CLK_PERIOD/2;
rst_n <= '1' after 2*CLK_PERIOD;
sda <= 'H';
sda <= '0' when sda_enable = '1' else 'Z';
slave_sda <= '1' when sda = 'H' else sda;
not_scl <= not scl;
scl <= 'H';
uut : entity i2c.address_generator
port map (
clk_i => clk,
rst_in => rst_n,
start_i => start,
store_address_rw_i => '1',
address_i => address,
rw_i => rw,
sda_i => slave_sda,
sda_enable_o => sda_enable,
scl_rising_i => scl_rising,
scl_falling_delayed_i => scl_falling_delayed,
unexpected_sda_o => unexpected_sda,
noack_o => noack,
done_o => done);
sda_stability_check: check_stable(clk, one, scl, not_scl, sda);
main: process is
procedure request_address_gen (
constant address_i : in std_logic_vector(6 downto 0);
constant rw_i : in std_logic) is
begin
rw <= rw_i;
address <= address_i;
start <= '1';
wait until falling_edge(clk);
start <= '0';
end procedure request_address_gen;
procedure scl_fall is
begin -- procedure scl_fall
wait until falling_edge(clk);
wait until falling_edge(clk);
wait until falling_edge(clk);
wait until falling_edge(clk);
scl <= '0';
wait until falling_edge(clk);
wait until falling_edge(clk);
wait until falling_edge(clk);
wait until falling_edge(clk);
end procedure scl_fall;
procedure scl_rise is
begin -- procedure scl_fall
scl <= 'Z';
wait until falling_edge(clk);
end procedure scl_rise;
procedure scl_pulse is
begin -- procedure scl_pulse
scl_rise;
scl_fall;
end procedure scl_pulse;
procedure validate_address_gen (
constant address : in std_logic_vector(6 downto 0);
constant rw : in std_logic;
constant ack : in std_logic := '1';
constant exp_noack : in std_logic := '0';
constant exp_unexpected_sda : in std_logic_vector(7 downto 0) := (others => '0')) is
begin -- procedure validate_address_gen
check_equal(done, '0', "Wrong done before validation!");
scl_fall;
for i in 0 to 6 loop
if address(6 - i) = '1' then
check_equal(sda, 'H', "Sda should be high for index " & integer'image(i));
else
check_equal(sda, '0', "Sda should be low for index " & integer'image(i));
end if;
wait for 0 ns;
if exp_unexpected_sda(7 - i) = '1' then
sda <= '0';
end if;
scl_rise;
check_equal(unexpected_sda, exp_unexpected_sda(7 - i));
scl_fall;
if exp_unexpected_sda(7 - i) = '1' then
sda <= 'Z';
end if;
wait for 0 ns;
end loop; -- i
if rw = '1' then
check_equal(sda, 'H', "Sda should be high for rw");
else
check_equal(sda, '0', "Sda should be low for rw");
end if;
scl_rise;
check_equal(unexpected_sda, exp_unexpected_sda(0));
scl_fall;
if ack = '1' then
sda <= '0';
wait until falling_edge(clk);
end if;
scl <= 'Z';
wait for CLK_PERIOD/4;
check_equal(noack, exp_noack, "Unexpected noack.");
wait until falling_edge(clk);
scl_fall;
sda <= 'Z';
check_equal(done, '1', "Not reporting done");
end procedure validate_address_gen;
begin -- process main
wait until rst_n = '1';
wait until falling_edge(clk);
check_equal(scl, 'H', "begin SCL not high");
test_runner_setup(runner, runner_cfg);
while test_suite loop
if run("simple_read") then
request_address_gen("1110101", '1');
validate_address_gen("1110101", '1');
elsif run("simple_write") then
request_address_gen("0001010", '0');
validate_address_gen("0001010", '0');
elsif run("write_read") then
request_address_gen("0001010", '0');
validate_address_gen("0001010", '0');
request_address_gen("1111010", '1');
validate_address_gen("1111010", '1');
elsif run("noack") then
request_address_gen("0001010", '0');
validate_address_gen("0001010", '0', ack => '0', exp_noack => '1');
elsif run("sda_wrong") then
request_address_gen("1111111", '0');
validate_address_gen("1111111", '0', exp_unexpected_sda => "10101010");
end if;
end loop;
test_runner_cleanup(runner);
end process main;
set_scl_rising: process is
begin -- process scl_rising
wait until rising_edge(scl);
scl_rising <= '1';
wait until falling_edge(clk);
wait until rising_edge(clk);
scl_rising <= '0';
end process set_scl_rising;
set_scl_falling: process is
begin -- process scl_rising
wait until falling_edge(scl);
scl_falling <= '1';
wait until rising_edge(clk);
wait until falling_edge(clk);
scl_falling <= '0';
end process set_scl_falling;
set_delayed_scl_falling: process is
begin -- process scl_rising
wait until falling_edge(scl);
wait until falling_edge(clk);
scl_falling_delayed <= '1';
wait until rising_edge(clk);
wait until falling_edge(clk);
scl_falling_delayed <= '0';
end process set_delayed_scl_falling;
end architecture tb;