diff --git a/hdl/ip/vhd/i2c/sims/i2c_peripheral.vhd b/hdl/ip/vhd/i2c/sims/i2c_peripheral.vhd index b76c7340..58c456df 100644 --- a/hdl/ip/vhd/i2c/sims/i2c_peripheral.vhd +++ b/hdl/ip/vhd/i2c/sims/i2c_peripheral.vhd @@ -48,16 +48,18 @@ architecture model of i2c_peripheral is signal sda_last : std_logic := '1'; signal rx_data : std_logic_vector(7 downto 0) := (others => '0'); signal rx_bit_count : unsigned(3 downto 0) := (others => '0'); - signal rx_done : std_logic := '0'; + signal rx_done : boolean := FALSE; signal rx_ackd : boolean := FALSE; + signal tx_data : std_logic_vector(7 downto 0) := (others => '0'); signal tx_bit_count : unsigned(3 downto 0) := (others => '0'); - signal tx_done : std_logic := '0'; + signal tx_done : boolean := FALSE; signal scl_oe : std_logic := '0'; signal sda_oe : std_logic := '0'; signal reg_addr : unsigned(7 downto 0) := (others => '0'); - signal is_addr_set : boolean := FALSE; + signal addr_set : boolean := FALSE; + signal addr_incr : boolean := FALSE; begin -- I2C interface is open-drain scl_if.o <= '0'; @@ -109,11 +111,11 @@ begin end if; -- SEND_ACK/NACK: acknowledge the START byte - wait on tx_done; wait until falling_edge(scl_if.i); if state = SEND_ACK then if is_read then state <= SEND_BYTE; + wait for 1 ns; else state <= GET_BYTE; end if; @@ -121,14 +123,13 @@ begin -- NACK'd state <= GET_STOP; end if; - -- wait until rising_edge(scl_if.i); if is_read then -- loop to respond to a controller read request while state /= GET_STOP loop -- SEND_BYTE: send the byte and then wait for an acknowledge wait on tx_done; - wait until rising_edge(scl_if.i); + wait until falling_edge(scl_if.i); state <= GET_ACK; -- GET_ACK: see if the controller wants to continue reading or is finished @@ -147,7 +148,7 @@ begin end if; -- GET_BYTE: get the byte and then send an acknowledge - wait on rx_done; + wait until rx_done or stop_condition; state <= GET_STOP when stop_condition else SEND_ACK; -- the loop condition needs this to realize when state gets set to GET_STOP wait for 1 ns; @@ -157,13 +158,15 @@ begin wait until falling_edge(scl_if.i); state <= GET_BYTE; - if is_addr_set then + if addr_set then write_word(memory(i2c_peripheral_vc), to_integer(reg_addr), rx_data); event_msg := new_msg(got_byte); send(net, i2c_peripheral_vc.p_actor, event_msg); - reg_addr <= reg_addr + 1; + if addr_incr then + reg_addr <= reg_addr + 1; + end if; else - is_addr_set <= TRUE; + addr_set <= TRUE; reg_addr <= unsigned(rx_data); end if; else @@ -174,73 +177,67 @@ begin -- GET_STOP: wait for a STOP wait until (stop_condition or stop_during_write); - event_msg := new_msg(got_stop); + event_msg := new_msg(got_stop); send(net, i2c_peripheral_vc.p_actor, event_msg); - state <= IDLE; + state <= IDLE; stop_during_write := FALSE; end process; - rx_done <= '1' when (state = GET_BYTE and rx_bit_count = 8) or - (state = GET_ACK and rx_bit_count = 1) or - stop_condition - else '0'; - receive_sm: process - variable data_next : std_logic_vector(7 downto 0) := (others => '0'); begin wait until rising_edge(scl_if.i); - + rx_done <= FALSE; if state = GET_ACK then -- '0' = ACK, '1' = NACK rx_ackd <= TRUE when sda_if.i = '0' else FALSE; + rx_bit_count <= to_unsigned(1, rx_bit_count'length); elsif state = GET_BYTE then - data_next := sda_if.i & rx_data(7 downto 1); + rx_data <= sda_if.i & rx_data(7 downto 1); + rx_bit_count <= rx_bit_count + 1; end if; - rx_data <= data_next; - - wait until falling_edge(scl_if.i); + wait until falling_edge(scl_if.i) or stop_condition; + if stop_condition then + rx_bit_count <= (others => '0'); + wait until falling_edge(scl_if.i); + end if; - if state = GET_ACK then - rx_bit_count <= to_unsigned(1, rx_bit_count'length); - elsif state = GET_BYTE then - rx_bit_count <= rx_bit_count + 1; - else + if (state = GET_BYTE and rx_bit_count = 8) or (state = GET_ACK and rx_bit_count = 1) then + rx_done <= TRUE; rx_bit_count <= (others => '0'); end if; end process; - tx_done <= '1' when ((state = SEND_ACK or state = SEND_ACK) and tx_bit_count = 1) or - (state = SEND_BYTE and tx_bit_count = 8) - else '0'; - transmit_sm: process - variable data_v : std_logic_vector(7 downto 0) := X"CC"; + variable txd : std_logic_vector(7 downto 0) := (others => '0'); begin wait until falling_edge(scl_if.i); + tx_done <= FALSE; -- delay the SDA transition to a bit after SCL falls to allow the controller to release SDA wait for 100 ns; if state = SEND_ACK or state = SEND_NACK then sda_oe <= '1' when state = SEND_ACK else '0'; + tx_bit_count <= to_unsigned(1, tx_bit_count'length); elsif state = SEND_BYTE then if tx_bit_count = 0 then - data_v := read_word(i2c_peripheral_vc.p_buffer.p_memory_ref, natural(to_integer(reg_addr)), 1); + txd := read_word(i2c_peripheral_vc.p_buffer.p_memory_ref, natural(to_integer(reg_addr)), 1); + else + txd := '1' & tx_data(7 downto 1); end if; - sda_oe <= not data_v(to_integer(tx_bit_count)); + sda_oe <= not txd(0); + tx_bit_count <= tx_bit_count + 1; else -- release the bus sda_oe <= '0'; end if; + tx_data <= txd; wait until rising_edge(scl_if.i); - -- update counter once bit has been sampled - if state = SEND_ACK or state = SEND_NACK then - tx_bit_count <= to_unsigned(1, tx_bit_count'length); - elsif state = SEND_BYTE then - tx_bit_count <= tx_bit_count + 1; - else + if ((state = SEND_ACK or state = SEND_ACK) and tx_bit_count = 1) or + (state = SEND_BYTE and tx_bit_count = 8) then + tx_done <= TRUE; tx_bit_count <= (others => '0'); end if; diff --git a/hdl/ip/vhd/i2c/sims/i2c_tb.vhd b/hdl/ip/vhd/i2c/sims/i2c_tb.vhd index d364d55d..c99187f9 100644 --- a/hdl/ip/vhd/i2c/sims/i2c_tb.vhd +++ b/hdl/ip/vhd/i2c/sims/i2c_tb.vhd @@ -67,26 +67,7 @@ begin check_false(ack, "Peripheral did not NACK incorrect address"); -- transaction is over, receive STOP event wait for 10 us; - elsif run("write_one_byte") then - expected_addr := X"9E"; -- arbitrary for the test - expected_data := X"A5"; - - command := ( - op => WRITE, - addr => address(I2C_PERIPHERAL_VC), - reg => std_logic_vector(expected_addr), - len => to_unsigned(1, command.len'length) - ); - push_i2c_cmd(net, I2C_CMD_VC, command); - - start_byte_ack(net, I2C_PERIPHERAL_VC, ack); - check_true(ack, "Peripheral did not ACK correct address"); - - push_basic_stream(net, TX_DATA_SOURCE_VC, expected_data); - check_written_byte(net, I2C_PERIPHERAL_VC, expected_data, expected_addr); - - expect_stop(net, I2C_PERIPHERAL_VC); - elsif run("read_one_byte") then + elsif run("write_and_read_one_byte") then -- write some data in expected_addr := X"9E"; -- arbitrary for the test expected_data := X"A5"; @@ -123,6 +104,9 @@ begin check_equal(data, expected_data, "Expected read data to match"); expect_stop(net, I2C_PERIPHERAL_VC); + elsif run("write_and_read_many_bytes") then + + end if; end if; end loop; diff --git a/hdl/ip/vhd/i2c/sims/tb_i2c.gtkw b/hdl/ip/vhd/i2c/sims/tb_i2c.gtkw index 74937788..96c763df 100644 --- a/hdl/ip/vhd/i2c/sims/tb_i2c.gtkw +++ b/hdl/ip/vhd/i2c/sims/tb_i2c.gtkw @@ -1,15 +1,15 @@ [*] [*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI -[*] Thu Nov 21 22:01:19 2024 +[*] Fri Nov 22 17:02:19 2024 [*] -[dumpfile] "/home/aaron/Oxide/git/quartz/vunit_out/test_output/lib.i2c_tb.write_one_byte_45371635dc90e325712a46a4289140589cf4a62c/nvc/i2c_tb.fst" -[dumpfile_mtime] "Thu Nov 21 21:54:59 2024" -[dumpfile_size] 3991 +[dumpfile] "/home/aaron/Oxide/git/quartz/vunit_out/test_output/lib.i2c_tb.read_one_byte_f5003d4ca7a772188d7e5908ca58541f5b186a63/nvc/i2c_tb.fst" +[dumpfile_mtime] "Fri Nov 22 16:55:54 2024" +[dumpfile_size] 4917 [savefile] "/home/aaron/Oxide/git/quartz/hdl/ip/vhd/i2c/sims/tb_i2c.gtkw" -[timestart] 64455600000 +[timestart] 122700000000 [size] 2688 1283 -[pos] -1 -1 -*-25.367004 64660000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[pos] 1183 23 +*-32.015984 138388000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 [treeopen] i2c_tb. [treeopen] i2c_tb.th. [treeopen] i2c_tb.th.dut.i2c_link_layer_inst. @@ -69,7 +69,7 @@ i2c_tb.th.dut.i2c_link_layer_inst.scl_fedge i2c_tb.th.dut.i2c_link_layer_inst.transition_sda @200 -Transmit Stream -@29 +@28 i2c_tb.th.dut.i2c_link_layer_inst.tx_data_valid @22 i2c_tb.th.dut.i2c_link_layer_inst.tx_data[7:0] @@ -130,7 +130,6 @@ i2c_tb.th.peripheral.sda_if.oe i2c_tb.th.peripheral.state i2c_tb.th.peripheral.start_condition i2c_tb.th.peripheral.stop_condition -i2c_tb.th.peripheral.is_addr_set @22 i2c_tb.th.peripheral.reg_addr[7:0] @28 @@ -140,6 +139,19 @@ i2c_tb.th.peripheral.rx_data[7:0] i2c_tb.th.peripheral.rx_bit_count[3:0] @28 i2c_tb.th.peripheral.tx_done +@800023 +i2c_tb.th.peripheral.tx_data[7:0] +@29 +(0)i2c_tb.th.peripheral.tx_data[7:0] +(1)i2c_tb.th.peripheral.tx_data[7:0] +(2)i2c_tb.th.peripheral.tx_data[7:0] +(3)i2c_tb.th.peripheral.tx_data[7:0] +(4)i2c_tb.th.peripheral.tx_data[7:0] +(5)i2c_tb.th.peripheral.tx_data[7:0] +(6)i2c_tb.th.peripheral.tx_data[7:0] +(7)i2c_tb.th.peripheral.tx_data[7:0] +@1001201 +-group_end @22 i2c_tb.th.peripheral.tx_bit_count[3:0] [pattern_trace] 1