@@ 0,0 1,232 @@
+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,
+ 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;