From d2d01a3c5b4e59284c32b402a7c1c288853c767d Mon Sep 17 00:00:00 2001 From: Rutherther Date: Sat, 30 Dec 2023 11:40:53 +0100 Subject: [PATCH] feat: handle ack in rx, tx --- src/i2c/rx.vhd | 81 ++++++++++++++++++--------------- src/i2c/sdascl_enabler.vhd | 91 -------------------------------------- src/i2c/slave_state.vhd | 32 +------------- src/i2c/tx.vhd | 63 +++++++++++++++----------- tb/i2c/rx_tb.vhd | 40 ++++++++++++----- tb/i2c/tx_tb.vhd | 89 ++++++++++++++++++++++++++----------- 6 files changed, 176 insertions(+), 220 deletions(-) delete mode 100644 src/i2c/sdascl_enabler.vhd diff --git a/src/i2c/rx.vhd b/src/i2c/rx.vhd index d08ae4d..ffef596 100644 --- a/src/i2c/rx.vhd +++ b/src/i2c/rx.vhd @@ -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; diff --git a/src/i2c/sdascl_enabler.vhd b/src/i2c/sdascl_enabler.vhd deleted file mode 100644 index 14f1a54..0000000 --- a/src/i2c/sdascl_enabler.vhd +++ /dev/null @@ -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; diff --git a/src/i2c/slave_state.vhd b/src/i2c/slave_state.vhd index 0355f82..aaa300f 100644 --- a/src/i2c/slave_state.vhd +++ b/src/i2c/slave_state.vhd @@ -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; diff --git a/src/i2c/tx.vhd b/src/i2c/tx.vhd index 476d3ca..d6708ad 100644 --- a/src/i2c/tx.vhd +++ b/src/i2c/tx.vhd @@ -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; diff --git a/tb/i2c/rx_tb.vhd b/tb/i2c/rx_tb.vhd index 4e0863d..18046f3 100644 --- a/tb/i2c/rx_tb.vhd +++ b/tb/i2c/rx_tb.vhd @@ -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; diff --git a/tb/i2c/tx_tb.vhd b/tb/i2c/tx_tb.vhd index 992a1a5..10f67e6 100644 --- a/tb/i2c/tx_tb.vhd +++ b/tb/i2c/tx_tb.vhd @@ -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; -- 2.48.1