diff --git a/src/socbridge/socbridge_driver.vhd b/src/socbridge/socbridge_driver.vhd index 7dc34fd..fc2a2a7 100644 --- a/src/socbridge/socbridge_driver.vhd +++ b/src/socbridge/socbridge_driver.vhd @@ -104,7 +104,11 @@ begin --- ### TX NEXT STATE ASSIGNMENTS ### --- case st.curr_tx_state is when IDLE => - if local_next_tx_transaction /= NO_OP then + if (local_next_tx_transaction = WRITE or local_next_tx_transaction = WRITE_ADD) and not st.write_in_flight then + next_tx_state <= TX_HEADER; + elsif (local_next_tx_transaction = READ or local_next_tx_transaction = READ_ADD) and not st.read_in_flight then + next_tx_state <= TX_HEADER; + elsif local_next_tx_transaction = READ_RESPONSE or local_next_tx_transaction = WRITE_ACK then next_tx_state <= TX_HEADER; else next_tx_state <= IDLE; @@ -116,7 +120,7 @@ begin elsif st.curr_tx_transaction = WRITE then next_tx_state <= TX_W_BODY; elsif st.curr_tx_transaction = READ then - next_tx_state <= TX_AWAIT; + next_tx_state <= IDLE; -- Responses elsif st.curr_tx_transaction = READ_RESPONSE then next_tx_state <= TX_R_BODY; @@ -137,7 +141,7 @@ begin next_tx_state <= ADDR4; when ADDR4 => if st.curr_tx_transaction = READ_ADD then - next_tx_state <= TX_AWAIT; + next_tx_state <= IDLE; elsif st.curr_tx_transaction = WRITE_ADD then next_tx_state <= TX_W_BODY; else @@ -145,7 +149,7 @@ begin end if; when TX_W_BODY => if st.tx_stage <= 1 then - next_tx_state <= TX_AWAIT; + next_tx_state <= IDLE; else next_tx_state <= TX_W_BODY; end if; @@ -185,7 +189,11 @@ begin end if; when RX_R_BODY => if st.rx_stage <= 1 then - next_rx_state <= IDLE; + if local_next_rx_transaction /= NO_OP then + next_rx_state <= RX_HEADER; + else + next_rx_state <= IDLE; + end if; else next_rx_state <= RX_R_BODY; end if; @@ -311,12 +319,12 @@ begin trans_write_next_state <= AWAIT; -- Wait for driver to finish current instruction, then reenter SEND when AWAIT => - if trans_st.write.curr_inst.seq_mem_access_count <= MAX_PKT_SIZE and st.curr_tx_state = IDLE then + if trans_st.write.curr_inst.seq_mem_access_count <= MAX_PKT_SIZE and not st.write_in_flight then trans_write_next_state <= IDLE; elsif ip_to_socbridge_driver.fifo.used_slots = 0 and ip_to_socbridge_driver.flush = '1' - and st.curr_tx_state = IDLE then + and not st.write_in_flight then trans_write_next_state <= IDLE; - elsif st.curr_tx_state = IDLE and (ip_to_socbridge_driver.fifo.used_slots >= MAX_PKT_SIZE + elsif not st.write_in_flight and (ip_to_socbridge_driver.fifo.used_slots >= MAX_PKT_SIZE or ip_to_socbridge_driver.flush = '1') then trans_write_next_state <= SEND; else @@ -348,11 +356,11 @@ begin trans_read_next_state <= AWAIT; -- Wait for driver to finish current instruction, then reenter SEND when AWAIT => - if trans_st.read.curr_inst.seq_mem_access_count <= MAX_PKT_SIZE and st.curr_tx_state = IDLE then + if trans_st.read.curr_inst.seq_mem_access_count <= MAX_PKT_SIZE and not st.read_in_flight then trans_read_next_state <= IDLE; - elsif ip_to_socbridge_driver.flush = '1'and st.curr_tx_state = IDLE then + elsif ip_to_socbridge_driver.flush = '1'and not st.read_in_flight then trans_read_next_state <= IDLE; - elsif st.curr_tx_state = IDLE then + elsif not st.read_in_flight then trans_read_next_state <= SEND; else trans_read_next_state <= AWAIT; @@ -369,7 +377,8 @@ begin next_tx_data_size <= st.rx_data_size; local_next_tx_transaction := READ_RESPONSE; end if; - elsif trans_st.read.curr_state = SEND then + elsif trans_st.read.curr_state = SEND + and not ((st.last_sent_transaction = READ or st.last_sent_transaction = READ_ADD) and trans_st.write.curr_state = SEND) then if trans_st.read.is_first_word = '1' then local_next_tx_transaction := READ_ADD; else @@ -423,6 +432,9 @@ begin st.curr_write_data <= (others => '0'); st.curr_read_data <= (others => '0'); socbridge_driver_to_ip.data <= (others => '0'); + st.read_in_flight <= false; + st.write_in_flight <= false; + st.last_sent_transaction <= NO_OP; valid_out <= '0'; elsif(rising_edge(ext_to_socbridge_driver_rec.clk)) then @@ -437,8 +449,22 @@ begin valid_out <= '0'; case st.curr_tx_state is when IDLE => - st.curr_tx_transaction <= next_tx_transaction; - st.tx_data_size <= next_tx_data_size; + if ip_to_socbridge_driver.flush = '1' then + st.last_sent_transaction <= NO_OP; + end if; + if (next_tx_transaction = WRITE or next_tx_transaction = WRITE_ADD + or next_tx_transaction = READ or next_tx_transaction = READ_ADD) then + if not st.read_in_flight or not st.write_in_flight then + st.curr_tx_transaction <= next_tx_transaction; + st.tx_data_size <= next_tx_data_size; + else + st.curr_tx_transaction <= NO_OP; + st.tx_data_size <= 0; + end if; + else + st.curr_tx_transaction <= next_tx_transaction; + st.tx_data_size <= next_tx_data_size; + end if; if next_tx_transaction = WRITE_ADD or next_tx_transaction = WRITE or next_tx_transaction = READ_RESPONSE then st.curr_tx_addr <= trans_st.write.curr_inst.address; @@ -447,6 +473,18 @@ begin st.curr_tx_addr <= trans_st.read.curr_inst.address; st.tx_stage <= 0; end if; + when TX_HEADER => + if st.curr_tx_transaction = WRITE or st.curr_tx_transaction = WRITE_ADD then + st.last_sent_transaction <= st.curr_tx_transaction; + if not (st.curr_rx_state = RX_HEADER and st.curr_rx_transaction = WRITE_ACK) then + st.write_in_flight <= true; + end if; + elsif st.curr_tx_transaction = READ or st.curr_tx_transaction = READ_ADD then + st.last_sent_transaction <= st.curr_tx_transaction; + if not (st.curr_rx_state = RX_HEADER and st.curr_rx_transaction = READ_RESPONSE) then + st.read_in_flight <= true; + end if; + end if; when TX_W_BODY => if st.tx_stage > 0 then st.tx_stage <= st.tx_stage - 1; @@ -468,12 +506,31 @@ begin st.rx_stage <= 0; end if; when RX_HEADER => + if st.curr_rx_transaction = WRITE_ACK then + if not (st.curr_tx_state = TX_HEADER and (st.curr_tx_transaction = WRITE or st.curr_tx_transaction = WRITE_ADD)) then + st.write_in_flight <= false; + end if; + elsif st.curr_rx_transaction = READ_RESPONSE then + if not (st.curr_tx_state = TX_HEADER and (st.curr_tx_transaction = READ or st.curr_tx_transaction = READ_ADD)) then + st.read_in_flight <= false; + end if; + end if; when RX_R_BODY => valid_out <= '1'; socbridge_driver_to_ip.data <= st.ext_to_socbridge_driver_reg.data; if st.rx_stage > 0 then st.rx_stage <= st.rx_stage - 1; end if; + if next_rx_transaction /= NO_OP and st.rx_stage <= 1 then + st.curr_rx_transaction <= next_rx_transaction; + st.rx_data_size <= next_rx_data_size; + if next_rx_transaction = WRITE_ADD or next_rx_transaction = WRITE + or next_rx_transaction = READ_RESPONSE then + st.rx_stage <= next_rx_data_size; + else + st.rx_stage <= 0; + end if; + end if; when RX_W_BODY => if st.rx_stage > 0 then st.rx_stage <= st.rx_stage - 1; diff --git a/src/socbridge/socbridge_driver_pkg.vhd b/src/socbridge/socbridge_driver_pkg.vhd index 85385a0..2026aba 100644 --- a/src/socbridge/socbridge_driver_pkg.vhd +++ b/src/socbridge/socbridge_driver_pkg.vhd @@ -8,6 +8,7 @@ use gan_ganimede.io_types.all; package socbridge_driver_pkg is subtype command_size_t is integer range 0 to 128; + constant MAX_IN_FLIGHT : integer := 1; type transaction_t is (NO_OP, WRITE_ADD, WRITE, READ_ADD, READ, P_ERR, WRITE_ACK, READ_RESPONSE); @@ -52,6 +53,9 @@ package socbridge_driver_pkg is curr_tx_addr : std_logic_vector(31 downto 0); curr_rx_read_addr : std_logic_vector(31 downto 0); curr_rx_write_addr : std_logic_vector(31 downto 0); + read_in_flight : boolean; + write_in_flight : boolean; + last_sent_transaction : transaction_t; end record state_rec_t; impure function calc_parity( d : STD_LOGIC_VECTOR(interface_inst.socbridge.payload_width - 1 downto 0)