~ruther/vhdl-i2c

a41330924e3b5a48d4590ac912ea56b094bcd423 — Rutherther 1 year, 5 months ago d664c04
feat: prepare i2c slave tb model
3 files changed, 196 insertions(+), 2 deletions(-)

M tb/i2c/scl_generator_tb.vhd
M tb/i2c/tb_i2c_pkg.vhd
A tb/i2c/tb_i2c_slave_pkg.vhd
M tb/i2c/scl_generator_tb.vhd => tb/i2c/scl_generator_tb.vhd +2 -2
@@ 161,7 161,7 @@ begin  -- architecture tb

          stable_cannot_comply <= '0';
          wait_delay(1);
          check_equal(cannot_comply, '1');
          check_equal(cannot_comply, '1', "Wrong cannot comply");
        elsif run("falling_rising_scl_low") then
          req_falling;
          wait_delay(DELAY);


@@ 170,7 170,7 @@ begin  -- architecture tb

          stable_cannot_comply <= '0';
          wait_delay(DELAY);
          check_equal(cannot_comply, '1');
          check_equal(cannot_comply, '1', "Wrong cannot comply");
          check_equal(scl_enable, '0');
          wait_delay(DELAY);
          check_equal(scl_enable, '0');

M tb/i2c/tb_i2c_pkg.vhd => tb/i2c/tb_i2c_pkg.vhd +56 -0
@@ 41,6 41,24 @@ package tb_i2c_pkg is
    constant exp_data : in std_logic_vector(7 downto 0);
    signal rx_confirm_read : inout std_logic);

  procedure wait_for_start_condition (
    constant timeout : in time;
    signal scl       : in std_logic;
    signal sda       : in std_logic);

  procedure wait_for_stop_condition (
    constant timeout : in time;
    signal scl       : in std_logic;
    signal sda       : in std_logic);

  procedure wait_for_scl_rise (
    constant timeout : in time;
    signal scl       : in std_logic);

  procedure wait_for_scl_fall (
    constant timeout : in time;
    signal scl       : in std_logic);

end package tb_i2c_pkg;

package body tb_i2c_pkg is


@@ 128,4 146,42 @@ package body tb_i2c_pkg is
    rx_confirm_read <= '0';
  end procedure rx_read_data;

  procedure wait_for_start_condition (
    constant timeout : in time;
    signal scl       : in std_logic;
    signal sda       : in std_logic) is
  begin
    wait until falling_edge(sda) and scl = 'H' for timeout;
    check(sda = '0' and scl = 'H', "Did not get start condition in time.");
  end procedure wait_for_start_condition;

  procedure wait_for_stop_condition (
    constant timeout : in time;
    signal scl       : in std_logic;
    signal sda       : in std_logic) is
  begin
    wait until rising_edge(sda) and scl = 'H' for timeout;
    check(sda = '1' and scl = 'H', "Did not get stop condition in time.");
  end procedure wait_for_stop_condition;

  procedure wait_for_scl_rise (
    constant timeout : in time;
    signal scl       : in std_logic) is
  begin
    wait until scl = 'H' for timeout;
    check_equal(scl, 'H', "Did not get rising scl in time.");
    wait until falling_edge(clk);
  end procedure wait_for_scl_rise;


  procedure wait_for_scl_fall (
    constant timeout : in time;
    signal scl       : in std_logic) is
  begin
    wait until scl = '0' for timeout;
    check_equal(scl, '0', "Did not get falling scl in time.");
    wait until falling_edge(clk);
  end procedure wait_for_scl_fall;


end package body tb_i2c_pkg;

A tb/i2c/tb_i2c_slave_pkg.vhd => tb/i2c/tb_i2c_slave_pkg.vhd +138 -0
@@ 0,0 1,138 @@
library ieee;
use ieee.std_logic_1164.all;

library vunit_lib;
-- use vunit_lib.check_pkg.all;
context vunit_lib.vunit_context;

use work.tb_pkg.all;
use work.tb_i2c_pkg.all;

package tb_i2c_slave_pkg is

  procedure i2c_slave_check_start (
    constant address : in std_logic_vector(6 downto 0);
    constant rw : in std_logic;
    constant timeout : in time;
    signal scl : inout std_logic;
    signal sda : inout std_logic;
    constant ack : in std_logic := '1');

  procedure i2c_slave_check_stop (
    constant timeout : in time;
    signal scl : inout std_logic;
    signal sda : inout std_logic);

  procedure i2c_slave_transmit (
    constant data        : in    std_logic_vector(7 downto 0);
    constant scl_timeout : in    time;
    signal scl           : inout std_logic;
    signal sda           : inout std_logic;
    constant exp_ack     : in    std_logic := '1');

  procedure i2c_slave_receive (
    constant exp_data       : in    std_logic_vector(7 downto 0);
    constant scl_timeout    : in    time;
    signal scl              : inout std_logic;
    signal sda              : inout std_logic;
    constant ack            : in    std_logic := '1');

end package tb_i2c_slave_pkg;

package body tb_i2c_slave_pkg is

  procedure i2c_slave_check_start (
    constant address : in std_logic_vector(6 downto 0);
    constant rw : in std_logic;
    constant timeout : in time;
    signal scl : inout std_logic;
    signal sda : inout std_logic;
    constant ack : in std_logic := '1') is
    begin
      wait_for_start_condition(timeout, scl, sda);
      i2c_slave_receive(address & rw, timeout, scl, sda, ack);
    end procedure i2c_slave_check_start;

  procedure i2c_slave_check_stop (
    constant timeout : in time;
    signal scl : inout std_logic;
    signal sda : inout std_logic) is
  begin
    wait_for_stop_condition(timeout, scl, sda);
  end procedure i2c_slave_check_stop;

  procedure i2c_slave_transmit (
    constant data        : in    std_logic_vector(7 downto 0);
    constant scl_timeout : in    time;
    signal scl           : inout std_logic;
    signal sda           : inout std_logic;
    constant exp_ack     : in    std_logic := '1') is

  begin  -- procedure transmit
    report "Start slave transmit";
    if scl = 'H' then
        wait_for_scl_fall(scl_timeout, scl);
    end if;

    -- data
    for i in 7 downto 0 loop
    report "Data " & integer'image(i) & " scl is: " & std_logic'image(scl);
      wait until falling_edge(clk);
      sda <= '0' when data(i) = '0' else 'Z';
      wait_for_scl_rise(scl_timeout, scl);
      wait_for_scl_fall(scl_timeout, scl);
    end loop;  -- i

    wait until falling_edge(clk);
    sda <= 'Z';
    wait_for_scl_rise(scl_timeout, scl);

    report "Ack slave transmit";
    if exp_ack = '1' then
      check_equal(sda, '0', "No acknowledge");
    elsif exp_ack = '0' then
      check_equal(sda, 'H', "There was acknowledge even though there shouldn't have been");
    end if;

    -- TODO consider removing this?
    wait_for_scl_fall(scl_timeout, scl);
    wait until falling_edge(clk);
    sda <= 'Z';
  end procedure i2c_slave_transmit;

  procedure i2c_slave_receive (
    constant exp_data       : in    std_logic_vector(7 downto 0);
    constant scl_timeout    : in    time;
    signal scl              : inout std_logic;
    signal sda              : inout std_logic;
    constant ack            : in    std_logic := '1') is

  begin  -- procedure transmit
    if scl = 'H' then
      wait_for_scl_fall(scl_timeout, scl);
    end if;

    sda <= 'Z';

    -- data
    for i in 7 downto 0 loop
      wait_for_scl_rise(scl_timeout, scl);
      if exp_data(i) = '1' then
        check(sda = '1' or sda = 'H', result("Received data (sda) not as expected."));
      else
        check(sda = '0' or sda = 'L', result("Received data (sda) not as expected."));
      end if;
      wait_for_scl_fall(scl_timeout, scl);
    end loop;  -- i

    if ack = '1' then
      sda <= '0';
    end if;

    wait_for_scl_rise(scl_timeout, scl);
    wait_for_scl_fall(scl_timeout, scl);

    sda <= 'Z';
  end procedure i2c_slave_receive;

end package body tb_i2c_slave_pkg;

Do not follow this link