~ruther/vhdl-i2c

d2d01a3c5b4e59284c32b402a7c1c288853c767d — Rutherther 1 year, 3 months ago 2759cb2
feat: handle ack in rx, tx
6 files changed, 176 insertions(+), 220 deletions(-)

M src/i2c/rx.vhd
D src/i2c/sdascl_enabler.vhd
M src/i2c/slave_state.vhd
M src/i2c/tx.vhd
M tb/i2c/rx_tb.vhd
M tb/i2c/tx_tb.vhd
M src/i2c/rx.vhd => src/i2c/rx.vhd +46 -35
@@ 24,11 24,15 @@ entity rx is
    clk_i          : in  std_logic;     -- Clock
    rst_in         : in  std_logic;     -- Reset (asynchronous)
    start_read_i   : in  std_logic;     -- Start reading with next scl_pulse
    ss_condition_i : in std_logic;    -- Reset rx circuitry
    ss_condition_i : in  std_logic;     -- Reset rx circuitry

    scl_pulse_i    : in  std_logic;     -- SCL rising edge pulse
    scl_falling_delayed_i    : in  std_logic;     -- SCL rising edge pulse
    scl_stretch_o  : out std_logic;     -- Stretch SCL (keep SCL 0)
    sda_i          : in  std_logic;     -- SDA data line state
    sda_enable_o   : out std_logic;     -- SDA data line state

    generate_ack_i : in std_logic;

    read_valid_o   : out std_logic;     -- Are there any data on read_data_o?
    read_ready_o   : out std_logic;     -- Is it possible to read anymore, or


@@ 41,19 45,23 @@ end entity rx;
architecture a1 of rx is
  -- IDLE - not doing anythign
  -- RECEIVING - currently receiving data to the buffer
  -- SAVING - trying to save to the read data output, waiting for data being
  -- ACK - going to generate acknowledge
  -- ACK_ON - sda should be enabled, to signal ack
  -- STRETCHING -
  -- read if cannot save
  -- SAVING_STRETCHING - waiting for data being read, should
  -- be sending already, but cannot, since the data are not read,
  -- so stretching SCL
  type rx_state_t is (IDLE, RECEIVING, SAVING, SAVING_STRETCHING);
  type rx_state_t is (IDLE, RECEIVING, ACK, ACK_ON, STRETCHING);
  signal curr_state : rx_state_t;
  signal next_state : rx_state_t;

  -- Whether state = RECEIVING
  signal curr_receiving : std_logic;
  -- Whether state = SAVING or SAVING_STRETCHING

  -- Whether data are being saved (could be just one cycle if not filled, or
  -- more if filled)
  signal curr_saving : std_logic;
  signal next_saving : std_logic;

  -- Whether the read data output is filled
  -- already (it's a register)


@@ 67,65 75,66 @@ architecture a1 of rx is
  signal curr_read_data : std_logic_vector(7 downto 0);
  signal next_read_data : std_logic_vector(7 downto 0);
begin  -- architecture a1
  read_ready_o <= '1' when curr_state /= SAVING_STRETCHING and (curr_saving = '0' or curr_read_data_filled = '0') else '0';
  scl_stretch_o <= '1' when curr_state = SAVING_STRETCHING else '0';
  read_ready_o <= '1' when curr_saving = '0' or curr_read_data_filled = '0' or confirm_read_i = '1' else
                  '0';

  scl_stretch_o <= '1' when curr_state = STRETCHING else '0';

  read_data_o <= curr_read_data;

  -- IDLE -> RECEIVING on start_read,
  -- RECEIVING -> RECEIVING when not received full data
  -- RECEIVING -> SAVING when received all data
  -- SAVING -> SAVING_STRETCHING when cannot overrode data AND start_read
  -- SAVING -> RECEIVING when start_read AND overriding data now
  -- SAVING -> SAVING when cannot override data (data not read yet)
  -- SAVING -> IDLE when can override data
  -- SAVING_STRETCHING -> SAVING_STRETCHING when data not read yet
  -- SAVING_STRETCHING -> RECEIVING when data read
  sda_enable_o <= '1' when curr_state = ACK_ON and generate_ack_i = '1' else
                  '0';

  set_next_state: process(all) is
    variable start_receive : std_logic;
  begin  -- process set_next_state
    next_state <= curr_state;
    start_receive := '0';

    if curr_state = IDLE then
      if start_read_i = '1' then
        next_state <= RECEIVING;
        start_receive := '1';
      end if;
    elsif curr_state = RECEIVING then
      if curr_rx_buffer(7) = '1' and scl_pulse_i = '1' then
        next_state <= SAVING;
        next_state <= ACK;
      end if;
    elsif curr_state = SAVING then
      if curr_read_data_filled = '0' then
        if start_read_i = '1' then
          next_state <= RECEIVING;
        else
          next_state <= IDLE;
        end if;
      elsif confirm_read_i = '1' then
    elsif curr_state = ACK then
      if scl_falling_delayed_i = '1' then
        next_state <= ACK_ON;
      end if;
    elsif curr_state = ACK_ON then
      if scl_falling_delayed_i = '1' then
        if start_read_i = '1' then
          next_state <= RECEIVING; -- skip SAVING_STRETCHING
          start_receive := '1';
        else
          next_state <= IDLE;
        end if;
      elsif start_read_i = '1' then
        next_state <= SAVING_STRETCHING;
      end if;
    elsif curr_state = SAVING_STRETCHING then
    elsif curr_state = STRETCHING then
      if confirm_read_i = '1' then
        next_state <= RECEIVING;
      end if;
    end if;

    if ss_condition_i = '1' then
      if curr_saving = '1' and curr_read_data_filled = '1' then
        next_state <= SAVING;
    if start_receive = '1' then
      if curr_read_data_filled = '0' or confirm_read_i = '1' or curr_saving = '0' then
        next_state <= RECEIVING;
      else
        next_state <= IDLE;
        next_state <= STRETCHING;
      end if;
    end if;

    if ss_condition_i = '1' then
      next_state <= IDLE;
    end if;
  end process set_next_state;

  curr_receiving <= '1' when curr_state = RECEIVING else '0';
  curr_saving <= '1' when curr_state = SAVING or curr_state = SAVING_STRETCHING else '0';

  next_saving <= '1' when curr_rx_buffer(7) = '1' and scl_pulse_i = '1' and curr_state = RECEIVING else
                 '1' when curr_saving = '1' and curr_read_data_filled = '1' and confirm_read_i = '0' else
                 '0';

  read_valid_o <= curr_read_data_filled;



@@ 153,11 162,13 @@ begin  -- architecture a1
        curr_rx_buffer <= (others => '0');
        curr_read_data_filled <= '0';
        curr_state <= IDLE;
        curr_saving <= '0';
      else
        curr_read_data <= next_read_data;
        curr_rx_buffer <= next_rx_buffer;
        curr_read_data_filled <= next_read_data_filled;
        curr_state <= next_state;
        curr_saving <= next_saving;
      end if;
    end if;
  end process set_regs;

D src/i2c/sdascl_enabler.vhd => src/i2c/sdascl_enabler.vhd +0 -91
@@ 1,91 0,0 @@
library ieee;
use ieee.std_logic_1164.all;

library utils;

entity sdascl_enabler is
  generic (
    DELAY : natural);

  port (
    clk_i          : in  std_logic;
    rst_in         : in  std_logic;

    scl_i : in std_logic;
    sda_i : in std_logic;

    scl_falling_pulse_i : in std_logic;

    transmitting_i : in  std_logic;
    receiving_i    : in  std_logic;

    expects_ack_i  : in  std_logic;
    generate_ack_i : in  std_logic;

    tx_sda_i         : in std_logic;
    tx_scl_stretch_i : in std_logic;
    rx_scl_stretch_i : in std_logic;

    sda_enable_o   : out std_logic;
    scl_enable_o   : out std_logic);

end entity sdascl_enabler;

architecture a1 of sdascl_enabler is
  type state_t is (TRANSMITTING, RECEIVING, EXPECTS_ACK, GENERATE_ACK, NONE);
  signal curr_state : state_t;
  signal next_state : state_t;

  signal curr_scl_enable : std_logic := '0';
  signal next_scl_enable : std_logic;

  signal any_stretch : std_logic;
  signal should_start_stretch : std_logic;

  signal delayed_scl_pulse : std_logic;
begin  -- architecture a1
  scl_falling_delay: entity utils.delay
    generic map (
      DELAY => DELAY)
    port map (
      clk_i   => clk_i,
      rst_in  => rst_in,
      signal_i => scl_falling_pulse_i,
      signal_o => delayed_scl_pulse);

  scl_enable_o <= curr_scl_enable;
  sda_enable_o <= '0' when curr_state = EXPECTS_ACK else
                  '1' when curr_state = GENERATE_ACK else
                  not tx_sda_i when curr_state = TRANSMITTING else
                  '0';

  any_stretch <= '1' when
                    (tx_scl_stretch_i = '1' and transmitting_i = '1') or
                    (rx_scl_stretch_i = '1' and receiving_i = '1')
                 else '0';
  should_start_stretch <= '1' when any_stretch = '1' and scl_i = '0' else '0';

  next_scl_enable <= '1' when should_start_stretch = '1' else
                     '0' when any_stretch = '0' else
                     curr_scl_enable;

  next_state <= TRANSMITTING when transmitting_i = '1' and delayed_scl_pulse = '1' else
                RECEIVING when receiving_i = '1' and delayed_scl_pulse = '1'else
                EXPECTS_ACK when expects_ack_i = '1' and delayed_scl_pulse = '1'else
                GENERATE_ACK when generate_ack_i = '1' and delayed_scl_pulse = '1'else
                curr_state;

  set_regs: process (clk_i) is
  begin  -- process set_regs
    if rising_edge(clk_i) then          -- rising clock edge
      if rst_in = '0' then              -- synchronous reset (active low)
        curr_state <= NONE;
        curr_scl_enable <= '0';
      else
        curr_state <= next_state;
        curr_scl_enable <= next_scl_enable;
      end if;
    end if;
  end process set_regs;

end architecture a1;

M src/i2c/slave_state.vhd => src/i2c/slave_state.vhd +2 -30
@@ 6,10 6,6 @@ entity i2c_slave_state is
    clk_i                    : in  std_logic;
    rst_in                   : in  std_logic;

    sda_i                    : in  std_logic;
    scl_i                    : in  std_logic;
    scl_pulse_i              : in  std_logic;

    start_condition_i        : in  std_logic;
    stop_condition_i         : in  std_logic;



@@ 17,14 13,10 @@ entity i2c_slave_state is
    address_detect_success_i : in  std_logic;
    address_detect_fail_i    : in  std_logic;
    address_detect_start_o   : out std_logic;
    address_detect_active_o  : out std_logic;

    expects_ack_o            : out std_logic;
    generate_ack_o           : out std_logic;
    receive_o                : out std_logic;
    transmit_o               : out std_logic;
    start_receive_o          : out std_logic;
    start_transmit_o         : out std_logic
    bus_busy_o               : out std_logic
  );
end entity i2c_slave_state;



@@ 40,34 32,16 @@ architecture a1 of i2c_slave_state is
  signal curr_state : slave_state;
  signal next_state : slave_state;

  constant TRANSMIT_LEN : integer := 9;
  signal curr_data_position : integer range 0 to TRANSMIT_LEN-1;
  signal next_data_position : integer range 0 to TRANSMIT_LEN-1;

  signal communicating_with_master : std_logic;
begin  -- architecture a1

  communicating_with_master <= '1' when curr_state = BUS_ADDRESS or curr_state = RECEIVING or curr_state = TRANSMITTING else '0';

  next_data_position <= 0 when start_condition_i = '1' else
                        0 when stop_condition_i = '1' or curr_state = BUS_FREE else
                        (curr_data_position + 1) mod TRANSMIT_LEN when scl_pulse_i = '1' and communicating_with_master = '1' else
                        curr_data_position;

  generate_ack_o <= '1' when next_data_position = TRANSMIT_LEN - 1 and
                             (curr_state = BUS_ADDRESS or curr_state = RECEIVING)
                    else '0';
  expects_ack_o <= '1' when next_data_position = TRANSMIT_LEN - 1 and
                            (curr_state = TRANSMITTING)
                   else '0';

  address_detect_start_o <= '1' when start_condition_i = '1' else '0';

  receive_o <= '1' when curr_state = RECEIVING else '0';
  transmit_o <= '1' when curr_state = TRANSMITTING else '0';

  start_receive_o <= '1' when curr_data_position /= 0 and next_data_position = 0 and curr_state = RECEIVING else '0';
  start_transmit_o <= '1' when curr_data_position /= 0 and next_data_position = 0 and curr_state = TRANSMITTING else '0';
  bus_busy_o <= '1' when curr_state = BUS_BUSY else '0';

  next_state <= BUS_ADDRESS when start_condition_i = '1' else
                -- BUS_BUSY when curr_state = BUS_FREE and (sda_i = '0' or scl_i = '0') else --


@@ 83,10 57,8 @@ begin  -- architecture a1
    if rising_edge(clk_i) then          -- rising clock edge
      if rst_in = '0' then              -- synchronous reset (active low)
        curr_state <= BUS_FREE;
        curr_data_position <= 0;
      else
        curr_state <= next_state;
        curr_data_position <= next_data_position;
      end if;
    end if;
  end process set_regs;

M src/i2c/tx.vhd => src/i2c/tx.vhd +37 -26
@@ 20,20 20,21 @@ use ieee.std_logic_1164.all;
library utils;

entity tx is
  generic (
    DELAY_SDA_FOR : natural := 5);      -- How many cycles to delay setting SDA
                                        -- after falling edge of scl
  port (
    clk_i               : in  std_logic;
    rst_in              : in  std_logic;
    start_write_i       : in  std_logic;
    ss_condition_i      : in std_logic;    -- Reset rx circuitry

    expect_ack_i        : in std_logic;
    err_noack_o         : out std_logic;

    scl_rising_pulse_i  : in  std_logic;
    scl_falling_pulse_i : in  std_logic;
    scl_falling_delayed_i : in  std_logic;

    scl_stretch_o       : out std_logic;
    sda_o               : out std_logic;
    sda_i               : in  std_logic;
    sda_enable_o        : out std_logic;

    ready_o             : out std_logic;
    valid_i             : in  std_logic;


@@ 46,7 47,7 @@ architecture a1 of tx is
  -- SENDING - data are in the buffer, being sent
  -- WAITING_FOR_SEND there were data written to the buffer, but cannot send now
  -- WAITING_FOR_DATA should be sending, but there are no data - stretching
  type tx_state_t is (IDLE, WAITING_FOR_FALLING_EDGE, SENDING, WAITING_FOR_DATA);
  type tx_state_t is (IDLE, WAITING_FOR_FALLING_EDGE, SENDING, ACK, WAITING_FOR_DATA);
  signal curr_state : tx_state_t;
  signal next_state : tx_state_t;



@@ 67,39 68,38 @@ architecture a1 of tx is
  signal tx_buffer : std_logic_vector(8 downto 0);
  signal tx_buffer_filled : std_logic;

  signal scl_delayed_pulse : std_logic;
  signal curr_scl : std_logic;
  signal next_scl : std_logic;

  signal curr_err_noack : std_logic;
  signal next_err_noack : std_logic;

  signal ready : std_logic;
begin  -- architecture a1
  scl_falling_delay: entity utils.delay
    generic map (
      DELAY => DELAY_SDA_FOR)
    port map (
      clk_i   => clk_i,
      rst_in  => rst_in,
      signal_i => scl_falling_pulse_i,
      signal_o => scl_delayed_pulse);

  scl_stretch_o <= '1' when curr_state = WAITING_FOR_DATA else '0';
  ready_o <= ready;
  sda_o <= tx_buffer(8) when curr_state = SENDING else '1';
  ready_o <= ready and not curr_err_noack;
  sda_enable_o <= not tx_buffer(8) when curr_state = SENDING else '0';
  err_noack_o <= curr_err_noack;

  ready <= '0' when curr_tx_buffers_filled(curr_saving_buffer_index) = '1' else '1';
  ready <= '0' when curr_tx_buffers_filled(curr_saving_buffer_index) = '1' or curr_err_noack = '1' else '1';
  tx_buffer <= curr_tx_buffers(curr_tx_buffer_index);
  tx_buffer_filled <= curr_tx_buffers_filled(curr_tx_buffer_index);

  next_scl <= '1' when scl_rising_pulse_i = '1' else
              '0' when scl_falling_pulse_i = '1' else
              '0' when scl_falling_delayed_i = '1' else
              curr_scl;

  next_tx_buffer_index <= (curr_tx_buffer_index + 1) mod 2 when tx_buffer(7 downto 0) = "10000000" and scl_delayed_pulse = '1' else
  next_tx_buffer_index <= (curr_tx_buffer_index + 1) mod 2 when tx_buffer(7 downto 0) = "10000000" and scl_falling_delayed_i = '1' else
                          curr_tx_buffer_index;

  next_saving_buffer_index <= (curr_saving_buffer_index + 1) mod 2 when ready = '1' and valid_i = '1' else
                              curr_saving_buffer_index;

  next_err_noack <= '0' when expect_ack_i = '0' else
                    '1' when curr_err_noack = '1' else
                    '1' when curr_state = ACK and scl_rising_pulse_i = '1' and sda_i = '1' else
                    '0';

  set_next_tx_buffers: process(all) is
  begin  -- process set_next_tx_buffer
    next_tx_buffers <= curr_tx_buffers;


@@ 107,7 107,7 @@ begin  -- architecture a1
      next_tx_buffers(curr_saving_buffer_index) <= write_data_i & '1';
    end if;

    if curr_state = SENDING and scl_delayed_pulse = '1' then
    if curr_state = SENDING and scl_falling_delayed_i = '1' then
      next_tx_buffers(curr_tx_buffer_index) <= tx_buffer(7 downto 0) & '0';
    end if;
  end process set_next_tx_buffers;


@@ 115,7 115,7 @@ begin  -- architecture a1
  set_next_buffer_filled: process(all) is
  begin  -- process set_next_buffer_filled
    next_tx_buffers_filled <= curr_tx_buffers_filled;
    if tx_buffer(7 downto 0) = "10000000" and scl_delayed_pulse = '1' then
    if tx_buffer(7 downto 0) = "10000000" and scl_falling_delayed_i = '1' then
      next_tx_buffers_filled(curr_tx_buffer_index) <= '0';
    end if;



@@ 137,11 137,15 @@ begin  -- architecture a1
        start_sending := '1';
      end if;
    elsif curr_state = WAITING_FOR_FALLING_EDGE then
      if scl_delayed_pulse = '1' then
      if scl_falling_delayed_i = '1' then
        next_state <= SENDING;
      end if;
    elsif curr_state = SENDING then
      if tx_buffer(7 downto 0) = "10000000" and scl_delayed_pulse = '1' then
      if tx_buffer(7 downto 0) = "10000000" and scl_falling_delayed_i = '1' then
        next_state <= ACK;
      end if;
    elsif curr_state = ACK then
      if scl_rising_pulse_i = '1' then
        if start_write_i = '1' then
          override_tx_buffer_filled := curr_tx_buffers_filled(next_tx_buffer_index);
          start_sending := '1';


@@ 158,12 162,17 @@ begin  -- architecture a1
    if start_sending = '1' then
      if override_tx_buffer_filled = '0' and valid_i = '0' then
        next_state <= WAITING_FOR_DATA;
      elsif curr_scl = '0' then
      elsif curr_scl = '0' and scl_rising_pulse_i = '0' then
        next_state <= SENDING;
      else
        next_state <= WAITING_FOR_FALLING_EDGE;
      end if;
    end if;

    if curr_err_noack = '1' then
      next_state <= IDLE;               -- not doing anything after an error.
                                        -- Waiting for ss condition or reset
    end if;
  end process set_next_state;

  set_regs: process (clk_i) is


@@ 176,6 185,7 @@ begin  -- architecture a1
        curr_tx_buffers_filled <= "00";
        curr_saving_buffer_index <= 0;
        curr_scl <= '1';                -- assume 1 (the default, no one transmitting)
        curr_err_noack <= '0';
      else
        curr_state <= next_state;
        curr_tx_buffers <= next_tx_buffers;


@@ 183,6 193,7 @@ begin  -- architecture a1
        curr_tx_buffers_filled <= next_tx_buffers_filled;
        curr_saving_buffer_index <= next_saving_buffer_index;
        curr_scl <= next_scl;
        curr_err_noack <= next_err_noack;
      end if;
    end if;
  end process set_regs;

M tb/i2c/rx_tb.vhd => tb/i2c/rx_tb.vhd +29 -11
@@ 25,6 25,7 @@ architecture a1 of rx_tb is
  signal start_read : std_logic := '0';
  signal valid, ready : std_logic;
  signal scl_stretch : std_logic;
  signal sda_enable : std_logic;

  signal confirm_read : std_logic := '0';
  signal read_data : std_logic_vector(7 downto 0);


@@ 71,21 72,31 @@ architecture a1 of rx_tb is
      sda <= data(i);
      trigger_scl_pulse(scl_rising_pulse, scl_falling_pulse);
    end loop;  -- i

    -- ack
    check_equal(sda_enable, '1');

    trigger_scl_pulse(scl_rising_pulse, scl_falling_pulse);

    check_equal(sda_enable, '0');
  end procedure transmit;
begin  -- architecture a1
  uut : entity i2c.rx
    port map (
      clk_i          => clk,
      rst_in         => rst_n,
      ss_condition_i => '0',
      start_read_i   => start_read,
      scl_pulse_i    => scl_rising_pulse,
      sda_i          => sda,
      scl_stretch_o  => scl_stretch,
      read_valid_o   => valid,
      read_ready_o   => ready,
      read_data_o    => read_data,
      confirm_read_i => confirm_read);
      clk_i                 => clk,
      rst_in                => rst_n,
      ss_condition_i        => '0',
      generate_ack_i        => '1',
      start_read_i          => start_read,
      scl_pulse_i           => scl_rising_pulse,
      scl_falling_delayed_i => scl_falling_pulse,
      sda_i                 => sda,
      sda_enable_o          => sda_enable,
      scl_stretch_o         => scl_stretch,
      read_valid_o          => valid,
      read_ready_o          => ready,
      read_data_o           => read_data,
      confirm_read_i        => confirm_read);

  clk <= not clk after CLK_PERIOD / 2;
  rst_n <= '1' after 2 * CLK_PERIOD;


@@ 161,11 172,13 @@ begin  -- architecture a1

        confirm_read <= '1';
        wait until falling_edge(clk);
        confirm_read <= '1';
        check_equal(read_data, std_logic_vector'("10000001"));
        check_equal(valid, '1');
        check_equal(ready, '1');
        check_equal(scl_stretch, '0');
        wait until falling_edge(clk);
        confirm_read <= '0';
        check_equal(valid, '0');
        check_equal(ready, '1');
        check_equal(scl_stretch, '0');


@@ 175,6 188,11 @@ begin  -- architecture a1
        check_equal(valid, '1');
        check_equal(ready, '1');
        check_equal(scl_stretch, '0');
        confirm_read <= '1';
        wait until falling_edge(clk);
        check_equal(valid, '0');
        check_equal(ready, '1');
        check_equal(scl_stretch, '0');
      end if;
    end loop;


M tb/i2c/tx_tb.vhd => tb/i2c/tx_tb.vhd +62 -27
@@ 19,7 19,9 @@ architecture a1 of tx_tb is

  signal rst_n : std_logic := '0';

  signal sda, scl : std_logic := '0';
  signal sda : std_logic;
  signal sda_override : std_logic := '0';
  signal sda_enable, scl : std_logic := '0';
  signal scl_rising_pulse, scl_falling_pulse : std_logic := '0';

  signal start_write : std_logic := '0';


@@ 27,7 29,11 @@ architecture a1 of tx_tb is
  signal write_data : std_logic_vector(7 downto 0);
  signal scl_stretch : std_logic;

  signal err_noack : std_logic;

  signal validate_sda_stable_when_scl_high : std_logic := '0';
  signal check_noerr : std_logic := '0';
  signal zero : std_logic := '0';

  procedure trigger_scl_pulse(
    signal scl : inout std_logic;


@@ 72,6 78,8 @@ architecture a1 of tx_tb is
  procedure check_received_data (
    constant data : in std_logic_vector(7 downto 0);
    constant check_ready : in std_logic;
    constant trigger_ack : in std_logic;
    signal sda_override : inout std_logic;
    signal scl : inout std_logic;
    signal scl_rising_pulse : inout std_logic;
    signal scl_falling_pulse : inout std_logic) is


@@ 89,7 97,7 @@ architecture a1 of tx_tb is
    end if;

    for i in 7 downto 0 loop
      check_equal(sda, data(i));
      check_equal(sda_enable, not data(i));

      if check_ready /= 'Z' then
        check_equal(ready, check_ready);


@@ 99,37 107,52 @@ architecture a1 of tx_tb is

      trigger_scl_pulse(scl, scl_rising_pulse, scl_falling_pulse);
    end loop;  -- i

    -- ack
    if trigger_ack = '1' then
      sda_override <= '1';
    end if;

    trigger_scl_pulse(scl, scl_rising_pulse, scl_falling_pulse);

    if trigger_ack = '1' then
      sda_override <= '0';
    end if;
  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_i                 => clk,
      rst_in                => rst_n,
      start_write_i         => start_write,
      ss_condition_i        => '0',
      expect_ack_i          => '1',
      err_noack_o           => err_noack,
      scl_stretch_o         => scl_stretch,
      scl_rising_pulse_i    => scl_rising_pulse,
      scl_falling_delayed_i => scl_falling_pulse,
      sda_enable_o          => sda_enable,
      sda_i                 => 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;

  sda <= '0' when sda_override = '1' else
         not sda_enable;

  main: process is
  begin  -- process
    scl <= '1';
    wait until rst_n = '1';
    wait until falling_edge(clk);
    check_noerr <= '1';
    test_runner_setup(runner, runner_cfg);
    set_stop_level(failure);


    while test_suite loop
      if run("simple") then
        valid <= '1';


@@ 138,8 161,8 @@ begin  -- architecture a1
        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');
        check_received_data("11010100", '1', '1', sda_override, scl, scl_rising_pulse, scl_falling_pulse);
        check_equal(sda_enable, '0');
      elsif run("twice") then
        valid <= '1';
        write_data <= "11010100";


@@ 152,10 175,10 @@ begin  -- architecture a1
        valid <= '0';
        check_equal(ready, '0');

        check_received_data("11010100", '0', scl, scl_rising_pulse, scl_falling_pulse);
        check_received_data("11010100", '0', '1', sda_override, 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');
        check_received_data("00101011", '1', '1', sda_override, scl, scl_rising_pulse, scl_falling_pulse);
        check_equal(sda_enable, '0');
      elsif run("three") then
        valid <= '1';
        write_data <= "11010100";


@@ 168,16 191,16 @@ begin  -- architecture a1
        valid <= '0';
        check_equal(ready, '0');

        check_received_data("11010100", '0', scl, scl_rising_pulse, scl_falling_pulse);
        check_received_data("11010100", '0', '1', sda_override,  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');
        check_received_data("00101011", '0', '1', sda_override,  scl, scl_rising_pulse, scl_falling_pulse);
        check_received_data("00001111", '1', '1', sda_override,  scl, scl_rising_pulse, scl_falling_pulse);
        check_equal(sda_enable, '0');
      elsif run("stretching") then
        start_write <= '1';
        check_equal(scl_stretch, '0');


@@ 192,12 215,24 @@ begin  -- architecture a1
        wait until falling_edge(clk);
        valid <= '0';
        check_equal(scl_stretch, '0');
        check_received_data("11001100", '1', scl, scl_rising_pulse, scl_falling_pulse);
        check_received_data("11001100", '1', '1', sda_override,  scl, scl_rising_pulse, scl_falling_pulse);
      elsif run("no_ack") then
        valid <= '1';
        write_data <= "11010100";
        check_equal(ready, '1');
        start_write <= '1';
        wait until falling_edge(clk);
        valid <= '0';
        check_noerr <= '0'; -- disable no err check
        check_received_data("11010100", '1', '0', sda_override, scl, scl_rising_pulse, scl_falling_pulse);
        check_equal(err_noack, '1');
        check_equal(sda_enable, '0');
      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);
  no_err: check_stable(clk, check_noerr, check_noerr, zero, err_noack);
  stability_check: check_stable(clk, validate_sda_stable_when_scl_high, scl_rising_pulse, scl_falling_pulse, sda_enable);
end architecture a1;

Do not follow this link