~ruther/vhdl-i2c

eb2258a9ca00b9da79a50c8e678b6842a64cbe5f — Rutherther 1 year, 5 months ago 560ec12
tests: add tx testbench
1 files changed, 205 insertions(+), 0 deletions(-)

A tb/i2c/tx_tb.vhd
A tb/i2c/tx_tb.vhd => tb/i2c/tx_tb.vhd +205 -0
@@ 0,0 1,205 @@
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;

Do not follow this link