diff --git a/src/socbridge/socbridge_driver.vhd b/src/socbridge/socbridge_driver.vhd index 4db0a4b..f6ab3f6 100644 --- a/src/socbridge/socbridge_driver.vhd +++ b/src/socbridge/socbridge_driver.vhd @@ -13,7 +13,7 @@ use grlib.stdlib.all; entity socbridge_driver is generic( - MAX_PKT_SIZE : integer range 1 to 128 := 32 + MAX_PKT_SIZE : integer range 1 to 128 := 8 ); port( clk : in std_logic; @@ -55,7 +55,7 @@ begin ext_to_socbridge_driver_rec.parity <= ext_to_socbridge_driver.control(0); socbridge_clk <= ext_to_socbridge_driver_rec.clk; socbridge_driver_to_ip.used_slots <= 0; - + comb_proc: process(ext_to_socbridge_driver, ip_to_socbridge_driver, st, controller_to_socbridge_driver, trans_st, tx_sent_response, rx_received_response, @@ -105,7 +105,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; @@ -117,7 +121,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; @@ -138,7 +142,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 @@ -146,7 +150,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; @@ -181,12 +185,18 @@ begin -- Responses elsif st.curr_rx_transaction = READ_RESPONSE then next_rx_state <= RX_R_BODY; - else + elsif local_next_rx_transaction /= NO_OP then + next_rx_state <= RX_HEADER; + else next_rx_state <= IDLE; 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; @@ -312,12 +322,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 @@ -349,11 +359,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; @@ -370,7 +380,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 @@ -424,6 +435,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 @@ -438,8 +452,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; @@ -448,6 +476,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; @@ -469,12 +509,41 @@ 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; + if next_rx_transaction /= NO_OP 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; + 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; @@ -541,7 +610,8 @@ begin trans_st.write.curr_state <= trans_write_next_state; case trans_st.write.curr_state is when IDLE => - if controller_to_socbridge_driver.request = '1' and controller_to_socbridge_driver.instruction = WRITE then + if controller_to_socbridge_driver.request = '1' and controller_to_socbridge_driver.instruction = WRITE + and trans_st.write.curr_inst.request = '0' then trans_st.write.curr_inst <= controller_to_socbridge_driver; else end if; @@ -561,7 +631,8 @@ begin end if; if trans_st.write.curr_inst.seq_mem_access_count mod 256 = 0 then trans_st.write.is_first_word <= '1'; - elsif trans_st.read.curr_inst.instruction /= NO_OP then + elsif st.last_sent_transaction = READ or st.last_sent_transaction = READ_ADD + or next_tx_transaction = READ or next_tx_transaction = READ_ADD then trans_st.write.is_first_word <= '1'; else trans_st.write.is_first_word <= '0'; @@ -576,6 +647,14 @@ begin end if; trans_st.read.is_first_word <= '1'; when SEND => + if trans_st.read.curr_inst.seq_mem_access_count mod 256 = 0 then + trans_st.read.is_first_word <= '1'; + elsif st.last_sent_transaction = WRITE or st.last_sent_transaction = WRITE_ADD + or next_tx_transaction = WRITE or next_tx_transaction = WRITE_ADD then + trans_st.read.is_first_word <= '1'; + else + trans_st.read.is_first_word <= '0'; + end if; when SEND_ACCEPTED => trans_st.read.curr_inst.seq_mem_access_count <= trans_st.read.curr_inst.seq_mem_access_count - MAX_PKT_SIZE; trans_st.read.curr_inst.address <= std_logic_vector(unsigned(trans_st.read.curr_inst.address) + MAX_PKT_SIZE); @@ -588,7 +667,8 @@ begin end if; if trans_st.read.curr_inst.seq_mem_access_count mod 256 = 0 then trans_st.read.is_first_word <= '1'; - elsif trans_st.write.curr_inst.instruction /= NO_OP then + elsif st.last_sent_transaction = WRITE or st.last_sent_transaction = WRITE_ADD + or next_tx_transaction = WRITE or next_tx_transaction = WRITE_ADD then trans_st.read.is_first_word <= '1'; else trans_st.read.is_first_word <= '0'; 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)