diff --git a/src/controller/control_unit.vhd b/src/controller/control_unit.vhd index aaa7f82..88f5730 100644 --- a/src/controller/control_unit.vhd +++ b/src/controller/control_unit.vhd @@ -26,17 +26,24 @@ architecture behave of control_unit is end record state_t; signal state: state_t; - shared variable ored: std_logic; + signal ored_reading: std_logic; + signal ored_writing: std_logic; begin comb_proc: process(manager_to_controller, drivers_to_controller, state) + variable local_ored_reading : std_logic; + variable local_ored_writing : std_logic; begin - ored := '0'; + local_ored_reading := '0'; + local_ored_writing := '0'; ready_reduction: for i in 0 to number_of_drivers - 1 loop - ored := ored or drivers_to_controller.socbridge.is_active; + local_ored_reading := local_ored_reading or drivers_to_controller.socbridge.is_reading; + local_ored_writing := local_ored_writing or drivers_to_controller.socbridge.is_writing; end loop ready_reduction; + ored_reading <= local_ored_reading; + ored_writing <= local_ored_writing; controller_to_drivers.socbridge.request <= state.curr_driver; controller_to_drivers.socbridge.address <= state.address; controller_to_drivers.socbridge.seq_mem_access_count <= state.seq_mem_access_count; @@ -48,20 +55,20 @@ begin begin if rising_edge(clk) then if rst = '1' then - state <= ((others => '0'), - 0, - '0', - '1', - NO_OP); + state.address <= (others => '0'); + state.seq_mem_access_count <= 0; + state.curr_driver <= '0'; + state.ready <= '1'; + state.instruction <= NO_OP; else -- Make sure to tell the management unit instruction is done - if ored = '0' and state.ready = '0' then - controller_to_manager.done <= '1'; + if (ored_writing = '0' and ored_reading = '0') and state.ready = '0' then state.ready <= '1'; else - controller_to_manager.done <= '0'; end if; - if ored = '0' then + controller_to_manager.done_reading <= ored_reading; + controller_to_manager.done_writing <= ored_writing; + if ored_reading = '0' or ored_writing = '0' then state.address <= manager_to_controller.address; state.seq_mem_access_count <= manager_to_controller.seq_mem_access_count; state.curr_driver <= manager_to_controller.driver_id(0); @@ -73,11 +80,11 @@ begin state.instruction <= NO_OP; end if; else - state <= ((others => '0'), - 0, - '0', - '1', - NO_OP); + state.address <= (others => '0'); + state.seq_mem_access_count <= 0; + state.curr_driver <= '0'; + state.ready <= '1'; + state.instruction <= NO_OP; end if; end if; end if; diff --git a/src/ganimede/ganimede.vhd b/src/ganimede/ganimede.vhd index 816ba67..24d38d1 100644 --- a/src/ganimede/ganimede.vhd +++ b/src/ganimede/ganimede.vhd @@ -7,7 +7,6 @@ use gan_socbridge.socbridge_driver_pkg.all; library gan_controller; library gan_manager; use gan_manager.management_types.all; -library gan_buffer; entity ganimede_toplevel is port ( diff --git a/src/ganimede/io_type_pkg.vhd b/src/ganimede/io_type_pkg.vhd index 4cf73ff..dd8271b 100644 --- a/src/ganimede/io_type_pkg.vhd +++ b/src/ganimede/io_type_pkg.vhd @@ -37,7 +37,7 @@ package io_types is end record manager_to_controller_t; type controller_to_manager_t is record - ready, done : std_logic; + ready, done_reading, done_writing : std_logic; end record controller_to_manager_t; --- PROTOCOL INFORMATION --- @@ -47,7 +47,8 @@ package io_types is --- AUTOGENERATED TYPES --- type socbridge_driver_to_controller_t is record - is_active : std_logic; + is_reading : std_logic; + is_writing : std_logic; end record socbridge_driver_to_controller_t; type controller_to_socbridge_driver_t is record diff --git a/src/manager/management_unit.vhd b/src/manager/management_unit.vhd index 26b51f6..caed8da 100644 --- a/src/manager/management_unit.vhd +++ b/src/manager/management_unit.vhd @@ -75,24 +75,20 @@ begin or socbridge_driver_to_manager.address = write_address_index then -- CLEAR BUFFER TO IP CORE end if; - end if; - -- Is the controller done executing an instruction - if controller_to_manager.done = '1' then - if cmd = "10" then - manager_state.memory(0) <= manager_word_reset_val; - elsif cmd = "01" then - manager_state.memory(1) <= manager_word_reset_val; - end if; + elsif controller_to_manager.done_reading = '1' then + manager_state.memory(0) <= manager_word_reset_val; + elsif controller_to_manager.done_writing = '1' then + manager_state.memory(1) <= manager_word_reset_val; end if; -- Is there a read instruction in memory - if pack(read_address) /= empty_word and controller_to_manager.ready = '1' then + if pack(read_address) /= empty_word and controller_to_manager.ready = '1' and controller_to_manager.done_reading = '0' then manager_to_controller.address <= read_address.address & "0000000000"; manager_to_controller.driver_id <= "1"; -- Only supprts one driver at present manager_to_controller.seq_mem_access_count <= 2**to_integer(unsigned(read_address.size)) * 2**10; cmd <= "10"; -- Is there a write instruction in memory - elsif pack(write_address) /= empty_word and controller_to_manager.ready = '1' then + elsif pack(write_address) /= empty_word and controller_to_manager.ready = '1' and controller_to_manager.done_writing = '0'then manager_to_controller.address <= write_address.address & "0000000000"; manager_to_controller.driver_id <= "1"; -- Only supports one driver at present manager_to_controller.seq_mem_access_count <= 2**to_integer(unsigned(read_address.size)) * 2**10; diff --git a/src/socbridge/socbridge_driver.vhd b/src/socbridge/socbridge_driver.vhd index 1bbb5c8..6238120 100644 --- a/src/socbridge/socbridge_driver.vhd +++ b/src/socbridge/socbridge_driver.vhd @@ -7,6 +7,8 @@ library gan_socbridge; use gan_socbridge.socbridge_driver_pkg.all; library gan_manager; use gan_manager.management_types.all; +library grlib; +use grlib.stdlib.all; entity socbridge_driver is @@ -41,8 +43,9 @@ architecture rtl of socbridge_driver is signal st : state_rec_t; signal valid_out : std_logic; --- TRANSLATOR --- - signal trans_st : translator_state_rec_t; - signal trans_next_state : translator_state_t; + signal trans_st : translator_state_t; + signal trans_read_next_state : ctrl_inst_state_t; + signal trans_write_next_state : ctrl_inst_state_t; --- FSM COMMUNICATION --- signal tx_sent_response, rx_received_response : std_logic; --- MANAGEMENT COMMUNICATION --- @@ -59,6 +62,7 @@ begin variable local_next_rx_transaction : transaction_t; variable local_next_tx_transaction : transaction_t; variable local_next_data_out : std_logic_vector(interface_inst.socbridge.payload_width - 1 downto 0); + variable curr_tx_addr : std_logic_vector(31 downto 0); begin -- Helpful Bindings -- next_rx_data_size <= 2 ** to_integer(unsigned(ext_to_socbridge_driver.payload(2 downto 0))); @@ -79,15 +83,26 @@ begin local_next_rx_transaction := WRITE_ACK; elsif curr_response_bits = "01100" or curr_response_bits = "01000" then local_next_rx_transaction := READ_RESPONSE; + end if; + -- determine address to ouput if address is needed + if st.curr_tx_transaction = READ or st.curr_tx_transaction = READ_ADD then + curr_tx_addr := trans_st.read.curr_inst.address; + elsif st.curr_tx_transaction = WRITE or st.curr_tx_transaction = WRITE_ADD then + curr_tx_addr := trans_st.write.curr_inst.address; end if; -- Outputs -- socbridge_driver_to_ext.payload <= st.socbridge_driver_to_ext_reg.data; socbridge_driver_to_ext.control(0) <= st.socbridge_driver_to_ext_reg.parity; socbridge_driver_to_ext.control(1) <= st.socbridge_driver_to_ext_reg.clk; - if trans_st.curr_state = IDLE then - socbridge_driver_to_controller.is_active <= '0'; + if trans_st.read.curr_state = IDLE then + socbridge_driver_to_controller.is_reading <= '0'; else - socbridge_driver_to_controller.is_active <= '1'; + socbridge_driver_to_controller.is_reading <= '1'; + end if; + if trans_st.write.curr_state = IDLE then + socbridge_driver_to_controller.is_writing <= '0'; + else + socbridge_driver_to_controller.is_writing <= '1'; end if; --- Next State Assignments --- @@ -145,7 +160,7 @@ begin and st.curr_rx_transaction = WRITE_ACK then next_tx_state <= IDLE; elsif (st.curr_tx_transaction = READ_ADD or st.curr_tx_transaction = READ) - and st.curr_rx_transaction = READ_RESPONSE and st.rx_stage = 1 then + and st.curr_rx_transaction = READ_RESPONSE and (st.rx_stage = 1 or next_tx_transaction = WRITE or next_tx_transaction = WRITE_ADD) then next_tx_state <= IDLE; else next_tx_state <= TX_AWAIT; @@ -236,13 +251,13 @@ begin end if; when TX_AWAIT => when ADDR1 => - local_next_data_out := st.curr_tx_addr(31 downto 24); + local_next_data_out := curr_tx_addr(31 downto 24); when ADDR2 => - local_next_data_out := st.curr_tx_addr(23 downto 16); + local_next_data_out := curr_tx_addr(23 downto 16); when ADDR3 => - local_next_data_out := st.curr_tx_addr(15 downto 8); + local_next_data_out := curr_tx_addr(15 downto 8); when ADDR4 => - local_next_data_out := st.curr_tx_addr(7 downto 0); + local_next_data_out := curr_tx_addr(7 downto 0); end case; --- ### RX_STATE BASED OUTPUT ### --- socbridge_driver_to_manager.valid <= '0'; @@ -252,6 +267,11 @@ begin when IDLE => when RX_HEADER => when RX_W_BODY => + if st.rx_stage mod 4 = 0 and st.rx_stage /= st.rx_data_size then + socbridge_driver_to_manager.data <= st.curr_write_data; + socbridge_driver_to_manager.address <= st.curr_rx_write_addr; + socbridge_driver_to_manager.valid <= '1'; + end if; when RX_R_BODY => when RX_AWAIT => if st.curr_rx_transaction = WRITE or st.curr_rx_transaction = WRITE_ADD then @@ -269,74 +289,103 @@ begin next_parity_out <= calc_parity(local_next_data_out); --- TRANSLATOR --- --- Next state assignment - case trans_st.curr_state is + case trans_st.write.curr_state is when IDLE => if st.curr_rx_transaction = READ or st.curr_rx_transaction = READ_ADD or st.curr_rx_transaction = WRITE or st.curr_rx_transaction = WRITE_ADD then - trans_next_state <= IDLE; - elsif trans_st.curr_inst.request = '1' then - trans_next_state <= SEND; + trans_write_next_state <= IDLE; + elsif trans_st.write.curr_inst.request = '1' then + trans_write_next_state <= SEND; else - trans_next_state <= IDLE; + trans_write_next_state <= IDLE; end if; -- Wait for driver to go idle and send next instruction. Then enter AWAIT when SEND => - if st.curr_tx_state /= IDLE then - trans_next_state <= SEND_ACCEPTED; + if st.curr_tx_transaction = WRITE or st.curr_tx_transaction = WRITE_ADD then + trans_write_next_state <= SEND_ACCEPTED; else - trans_next_state <= SEND; + trans_write_next_state <= SEND; end if; -- Transisitonal state to decrement counter in transition between SEND and AWAIT. when SEND_ACCEPTED => - trans_next_state <= AWAIT; + trans_write_next_state <= AWAIT; -- Wait for driver to finish current instruction, then reenter SEND when AWAIT => - if trans_st.curr_inst.seq_mem_access_count <= 0 and st.curr_tx_state = IDLE then - trans_next_state <= IDLE; + if trans_st.write.curr_inst.seq_mem_access_count <= 0 and st.curr_tx_state = IDLE then + trans_write_next_state <= IDLE; elsif st.curr_tx_state = IDLE then - trans_next_state <= SEND; + trans_write_next_state <= SEND; else - trans_next_state <= AWAIT; + trans_write_next_state <= AWAIT; + end if; + end case; + case trans_st.read.curr_state is + when IDLE => + if st.curr_rx_transaction = READ or st.curr_rx_transaction = READ_ADD + or st.curr_rx_transaction = WRITE or st.curr_rx_transaction = WRITE_ADD then + trans_read_next_state <= IDLE; + elsif trans_st.read.curr_inst.request = '1' then + trans_read_next_state <= SEND; + else + trans_read_next_state <= IDLE; + end if; + -- Wait for driver to go idle and send next instruction. Then enter AWAIT + when SEND => + if st.curr_tx_transaction = READ or st.curr_tx_transaction = READ_ADD then + trans_read_next_state <= SEND_ACCEPTED; + else + trans_read_next_state <= SEND; + end if; + -- Transisitonal state to decrement counter in transition between SEND and AWAIT. + when SEND_ACCEPTED => + 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 <= 0 and st.curr_tx_state = IDLE then + trans_read_next_state <= IDLE; + elsif st.curr_tx_state = IDLE then + trans_read_next_state <= SEND; + else + trans_read_next_state <= AWAIT; end if; end case; --- NEXT TX TRANSACTION --- local_next_tx_transaction := NO_OP; next_tx_data_size <= 0; - if trans_st.curr_state = IDLE and st.curr_rx_state = RX_AWAIT then + if trans_st.read.curr_state = IDLE and trans_st.write.curr_state = IDLE and st.curr_rx_state = RX_AWAIT then if (st.curr_rx_transaction = WRITE or st.curr_rx_transaction = WRITE_ADD) and manager_to_socbridge_driver.ready = '1' then local_next_tx_transaction := WRITE_ACK; elsif (st.curr_rx_transaction = READ or st.curr_rx_transaction = READ_ADD) and manager_to_socbridge_driver.valid = '1' then next_tx_data_size <= st.rx_data_size; local_next_tx_transaction := READ_RESPONSE; end if; - else - case trans_st.curr_state is - when IDLE => - when SEND => - if trans_st.is_first_word = '1' then - if trans_st.curr_inst.instruction = READ then - local_next_tx_transaction := READ_ADD; - elsif trans_st.curr_inst.instruction = WRITE then - local_next_tx_transaction := WRITE_ADD; - end if; - else - if trans_st.curr_inst.instruction = READ then - local_next_tx_transaction := READ; - elsif trans_st.curr_inst.instruction = WRITE then - local_next_tx_transaction := WRITE; - end if; - end if; - - if trans_st.curr_inst.seq_mem_access_count > MAX_PKT_SIZE then - next_tx_data_size <= MAX_PKT_SIZE; - elsif trans_st.curr_inst.seq_mem_access_count > 0 then - next_tx_data_size <= trans_st.curr_inst.seq_mem_access_count; - else - next_tx_data_size <= 0; - end if; - when others => - end case; + elsif trans_st.read.curr_state = SEND then + if trans_st.read.is_first_word = '1' then + local_next_tx_transaction := READ_ADD; + else + local_next_tx_transaction := READ; + end if; + if trans_st.read.curr_inst.seq_mem_access_count > MAX_PKT_SIZE then + next_tx_data_size <= MAX_PKT_SIZE; + elsif trans_st.read.curr_inst.seq_mem_access_count > 0 then + next_tx_data_size <= trans_st.read.curr_inst.seq_mem_access_count; + else + next_tx_data_size <= 0; + end if; + elsif trans_st.write.curr_state = SEND then + if trans_st.write.is_first_word = '1' then + local_next_tx_transaction := WRITE_ADD; + else + local_next_tx_transaction := WRITE; + end if; + if trans_st.write.curr_inst.seq_mem_access_count > MAX_PKT_SIZE then + next_tx_data_size <= MAX_PKT_SIZE; + elsif trans_st.write.curr_inst.seq_mem_access_count > 0 then + next_tx_data_size <= trans_st.write.curr_inst.seq_mem_access_count; + else + next_tx_data_size <= 0; + end if; end if; next_tx_transaction <= local_next_tx_transaction; @@ -360,7 +409,6 @@ begin st.curr_rx_transaction <= NO_OP; st.tx_data_size <= 0; st.rx_data_size <= 0; - st.curr_tx_addr <= (others => '0'); st.curr_rx_read_addr <= (others => '0'); st.curr_rx_write_addr <= (others => '0'); st.curr_write_data <= (others => '0'); @@ -381,7 +429,6 @@ begin when IDLE => st.curr_tx_transaction <= next_tx_transaction; st.tx_data_size <= next_tx_data_size; - st.curr_tx_addr <= trans_st.curr_inst.address; if next_tx_transaction = WRITE_ADD or next_tx_transaction = WRITE or next_tx_transaction = READ_RESPONSE then st.tx_stage <= next_tx_data_size; @@ -420,6 +467,9 @@ begin st.rx_stage <= st.rx_stage - 1; st.curr_write_data((((st.rx_stage - 1) mod 4) + 1) * 8 - 1 downto ((((st.rx_stage - 1) mod 4) + 1) - 1) * 8) <= st.ext_to_socbridge_driver_reg.data; end if; + if (st.rx_stage - 2) mod 4 = 0 and st.rx_data_size - st.rx_stage > 4 then + st.curr_rx_write_addr <= std_logic_vector(to_unsigned(to_integer(unsigned(st.curr_rx_write_addr) + 4), 32)); + end if; when RX_AWAIT => st.curr_read_data <= manager_to_socbridge_driver.data; -- THIS DOESN'T WORK FOR LARGER THAN 4 BYTE ACCESSES, SHOULD BE FIXED BUT NOT NEEDED IF ONLY 4 BYTE ACCESSES ARRIVE @@ -461,32 +511,65 @@ begin --- TRANSLATOR --- if(rst = '1') then - trans_st.curr_state <= IDLE; - trans_st.curr_inst.request <= '0'; - trans_st.curr_inst.address <= (others => '0'); - trans_st.curr_inst.seq_mem_access_count <= 0; - trans_st.curr_inst.instruction <= NO_OP; - trans_st.is_first_word <= '1'; - elsif(rising_edge(clk)) then - trans_st.curr_state <= trans_next_state; - case trans_st.curr_state is + trans_st.read.curr_state <= IDLE; + trans_st.read.curr_inst.request <= '0'; + trans_st.read.curr_inst.address <= (others => '0'); + trans_st.read.curr_inst.seq_mem_access_count <= 0; + trans_st.read.curr_inst.instruction <= NO_OP; + trans_st.read.is_first_word <= '1'; + trans_st.write.curr_state <= IDLE; + trans_st.write.curr_inst.request <= '0'; + trans_st.write.curr_inst.address <= (others => '0'); + trans_st.write.curr_inst.seq_mem_access_count <= 0; + trans_st.write.curr_inst.instruction <= NO_OP; + trans_st.write.is_first_word <= '1'; + elsif(rising_edge(ext_to_socbridge_driver_rec.clk)) then + trans_st.read.curr_state <= trans_read_next_state; + 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' then - trans_st.curr_inst <= controller_to_socbridge_driver; + if controller_to_socbridge_driver.request = '1' and controller_to_socbridge_driver.instruction = WRITE then + trans_st.write.curr_inst <= controller_to_socbridge_driver; else end if; - trans_st.is_first_word <= '1'; + trans_st.write.is_first_word <= '1'; when SEND => when SEND_ACCEPTED => - trans_st.curr_inst.seq_mem_access_count <= trans_st.curr_inst.seq_mem_access_count - MAX_PKT_SIZE; + trans_st.write.curr_inst.seq_mem_access_count <= trans_st.write.curr_inst.seq_mem_access_count - MAX_PKT_SIZE; when AWAIT => - if trans_st.curr_inst.seq_mem_access_count <= 0 and st.curr_tx_state = IDLE then - trans_st.curr_inst.request <= '0'; - trans_st.curr_inst.address <= (others => '0'); - trans_st.curr_inst.seq_mem_access_count <= 0; - trans_st.curr_inst.instruction <= NO_OP; + if trans_st.write.curr_inst.seq_mem_access_count <= 0 and st.curr_tx_state = IDLE then + trans_st.write.curr_inst.request <= '0'; + trans_st.write.curr_inst.address <= (others => '0'); + trans_st.write.curr_inst.seq_mem_access_count <= 0; + trans_st.write.curr_inst.instruction <= NO_OP; + end if; + trans_st.write.is_first_word <= '0'; + when others => + end case; + case trans_st.read.curr_state is + when IDLE => + if controller_to_socbridge_driver.request = '1' and controller_to_socbridge_driver.instruction = READ then + trans_st.read.curr_inst <= controller_to_socbridge_driver; + else + end if; + trans_st.read.is_first_word <= '1'; + when SEND => + 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); + when AWAIT => + if trans_st.read.curr_inst.seq_mem_access_count <= 0 and st.curr_tx_state = IDLE then + trans_st.read.curr_inst.request <= '0'; + trans_st.read.curr_inst.address <= (others => '0'); + trans_st.read.curr_inst.seq_mem_access_count <= 0; + trans_st.read.curr_inst.instruction <= NO_OP; + end if; + if trans_st.read.curr_inst.seq_mem_access_count mod 256 = 0 then + trans_st.read.is_first_word <= '0'; + report tost(trans_st.read.curr_inst.address) & " -> " & tost(trans_st.read.curr_inst.address + 256); + else + trans_st.read.is_first_word <= '0'; end if; - trans_st.is_first_word <= '0'; when others => end case; end if; diff --git a/src/socbridge/socbridge_driver_pkg.vhd b/src/socbridge/socbridge_driver_pkg.vhd index deb3b06..67986df 100644 --- a/src/socbridge/socbridge_driver_pkg.vhd +++ b/src/socbridge/socbridge_driver_pkg.vhd @@ -20,13 +20,18 @@ package socbridge_driver_pkg is (IDLE, ADDR1, ADDR2, ADDR3, ADDR4, TX_AWAIT, TX_HEADER, TX_W_BODY, TX_R_BODY); --- TRANSLATOR --- - type translator_state_t is (IDLE, SEND, SEND_ACCEPTED, AWAIT); + type ctrl_inst_state_t is (IDLE, SEND, SEND_ACCEPTED, AWAIT); - type translator_state_rec_t is record + type ctrl_inst_state_rec_t is record curr_inst : controller_to_socbridge_driver_t; - curr_state : translator_state_t; + curr_state : ctrl_inst_state_t; is_first_word : std_logic; - end record translator_state_rec_t; + end record ctrl_inst_state_rec_t; + + type translator_state_t is record + read: ctrl_inst_state_rec_t; + write: ctrl_inst_state_rec_t; + end record translator_state_t; type ext_protocol_t is record data : std_logic_vector(interface_inst.socbridge.payload_width - 1 downto 0); @@ -44,7 +49,6 @@ package socbridge_driver_pkg is tx_data_size, rx_data_size : integer; curr_write_data : std_logic_vector(31 downto 0); curr_read_data : std_logic_vector(31 downto 0); - 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); end record state_rec_t;