library IEEE; use IEEE.std_logic_1164.all; use IEEE.NUMERIC_STD.all; library ganimede; use ganimede.io_types.all; library gan_socbridge; use gan_socbridge.socbridge_driver_tb_pkg.all; entity socbridge_driver is generic( MAX_PKT_SIZE : integer range 1 to 128 := 32 ); port( clk : in std_logic; rst : in std_logic; controller_to_socbridge_driver : in controller_to_socbridge_driver_t; socbridge_driver_to_controller : out socbridge_driver_to_controller_t; ext_to_socbridge_driver : in ext_to_socbridge_driver_t; socbridge_driver_to_ext : out socbridge_driver_to_ext_t; ip_to_socbridge_driver : in ip_to_socbridge_driver_t; socbridge_driver_to_ip : out socbridge_driver_to_ip_t ); end entity socbridge_driver; architecture rtl of socbridge_driver is signal next_parity_out : std_logic; signal ext_to_socbridge_driver_rec : ext_protocol_t; shared variable socbridge_driver_to_ext_data_cmd : std_logic_vector(interface_inst.socbridge.payload_width - 1 downto 0); shared variable next_rx_transaction : transaction_t; shared variable next_tx_transaction : transaction_t; signal test : std_logic_vector(interface_inst.socbridge.payload_width - 1 downto 0); signal next_tx_data_size, next_rx_data_size : integer; signal next_rx_state : rx_state_t; signal next_tx_state : tx_state_t; signal curr_cmd_bits : std_logic_vector(4 downto 0); signal st : state_rec_t; --- TRANSLATOR --- signal trans_st : translator_state_rec_t; signal trans_next_state : translator_state_t; --- FSM COMMUNICATION --- signal tx_sent_response, rx_received_response : std_logic; --- MANAGEMENT COMMUNICATION --- signal mgnt_valid_in, mgnt_valid_out, mgnt_ready_out : std_logic; begin --- DEBUG GLOBAL BINDINGS --- -- synthesis translate_off G_next_parity_out <= next_parity_out; G_ext_to_socbridge_driver_rec <= ext_to_socbridge_driver_rec; G_socbridge_driver_to_ext_data_cmd <=test; G_curr_command_bits <= curr_cmd_bits; G_st <= st; G_trans_st <= trans_st; -- synthesis translate_on ext_to_socbridge_driver_rec.data <= ext_to_socbridge_driver.payload; ext_to_socbridge_driver_rec.clk <= ext_to_socbridge_driver.control(1); ext_to_socbridge_driver_rec.parity <= ext_to_socbridge_driver.control(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) variable curr_response_bits : std_logic_vector(4 downto 0); begin -- Helpful Bindings -- next_rx_data_size <= 2 ** to_integer(unsigned(ext_to_socbridge_driver.payload(2 downto 0))); curr_response_bits := ext_to_socbridge_driver.payload(7 downto 3); -- Set helper var to current transaction seen at the input. next_rx_transaction := NO_OP; if curr_response_bits = "10000" then next_rx_transaction := WRITE_ADD; elsif curr_response_bits = "10100" then next_rx_transaction := WRITE; elsif curr_response_bits = "11000" then next_rx_transaction := READ_ADD; elsif curr_response_bits = "11100" then next_rx_transaction := READ; elsif curr_response_bits = "01001" then next_rx_transaction := P_ERR; elsif curr_response_bits = "00101" or curr_response_bits = "00001" then next_rx_transaction := WRITE_ACK; elsif curr_response_bits = "01100" or curr_response_bits = "01000" then next_rx_transaction := READ_RESPONSE; end if; -- Outputs -- socbridge_driver_to_ext <= create_io_type_out_from_ext_protocol(st.socbridge_driver_to_ext_reg); if trans_st.curr_state = IDLE then socbridge_driver_to_controller.is_active <= '0'; else socbridge_driver_to_controller.is_active <= '1'; end if; --- Next State Assignments --- --- ### TX NEXT STATE ASSIGNMENTS ### --- case st.curr_tx_state is when IDLE => if next_tx_transaction /= NO_OP then next_tx_state <= TX_HEADER; else next_tx_state <= IDLE; end if; when TX_HEADER => -- Commands if st.curr_tx_transaction = WRITE_ADD or st.curr_tx_transaction = READ_ADD then next_tx_state <= ADDR1; 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; -- Responses elsif st.curr_tx_transaction = READ_RESPONSE then next_tx_state <= TX_R_BODY; else next_tx_state <= IDLE; end if; when TX_R_BODY => if st.tx_stage = 0 then next_tx_state <= IDLE; else next_tx_state <= TX_R_BODY; end if; when ADDR1 => next_tx_state <= ADDR2; when ADDR2 => next_tx_state <= ADDR3; when ADDR3 => next_tx_state <= ADDR4; when ADDR4 => if st.curr_tx_transaction = READ_ADD then next_tx_state <= TX_AWAIT; elsif st.curr_tx_transaction = WRITE_ADD then next_tx_state <= TX_W_BODY; else next_tx_state <= IDLE; end if; when TX_W_BODY => if st.tx_stage = 0 then next_tx_state <= TX_AWAIT; else next_tx_state <= TX_W_BODY; end if; when TX_AWAIT => -- Wait for RX FSM to get a response if (st.curr_tx_transaction = WRITE_ADD or st.curr_tx_transaction = WRITE) 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 = 0 then next_tx_state <= IDLE; else next_tx_state <= TX_AWAIT; end if; end case; --- Next State Assignment Of RX FSM --- case st.curr_rx_state is when IDLE => if next_rx_transaction /= NO_OP then next_rx_state <= RX_HEADER; else next_rx_state <= IDLE; end if; when RX_HEADER => -- Commands if st.curr_rx_transaction = WRITE_ADD or st.curr_rx_transaction = READ_ADD then next_rx_state <= ADDR1; elsif st.curr_rx_transaction = WRITE then next_rx_state <= RX_W_BODY; elsif st.curr_rx_transaction = READ then next_rx_state <= RX_AWAIT; -- Responses elsif st.curr_rx_transaction = READ_RESPONSE then next_rx_state <= RX_R_BODY; else next_rx_state <= IDLE; end if; when RX_R_BODY => if st.rx_stage = 0 then next_rx_state <= IDLE; else next_rx_state <= RX_R_BODY; end if; when ADDR1 => next_rx_state <= ADDR2; when ADDR2 => next_rx_state <= ADDR3; when ADDR3 => next_rx_state <= ADDR4; when ADDR4 => if st.curr_rx_transaction = READ_ADD then next_rx_state <= RX_AWAIT; elsif st.curr_rx_transaction = WRITE_ADD then next_rx_state <= RX_W_BODY; else next_rx_state <= IDLE; -- Potentially superfluous safety end if; when RX_W_BODY => if st.rx_stage = 0 then next_rx_state <= RX_AWAIT; else next_rx_state <= RX_W_BODY; end if; when RX_AWAIT => -- Wait for TX FSM to send a response if (st.curr_rx_transaction = WRITE_ADD or st.curr_rx_transaction = WRITE) and st.curr_tx_transaction = WRITE_ACK then next_rx_state <= IDLE; elsif (st.curr_rx_transaction = READ_ADD or st.curr_rx_transaction = READ) and st.curr_tx_transaction = READ_RESPONSE and st.tx_stage = 0 then next_rx_state <= IDLE; else next_rx_state <= RX_AWAIT; end if; end case; --- Combinatorial output based on current state --- socbridge_driver_to_ext_data_cmd := (others => '0'); socbridge_driver_to_ip.is_full_out <= '1'; socbridge_driver_to_ip.write_enable_in <= '0'; socbridge_driver_to_ip.payload <= (others => '0'); --- ### TX_STATE BASED OUTPUT ### --- case st.curr_tx_state is when IDLE => when TX_HEADER => socbridge_driver_to_ext_data_cmd := get_header_bits(st.curr_tx_transaction, st.curr_rx_transaction) & get_size_bits(st.tx_data_size); when TX_W_BODY => if st.tx_stage > 0 then socbridge_driver_to_ip.is_full_out <= '0'; socbridge_driver_to_ext_data_cmd := ip_to_socbridge_driver.payload; end if; when TX_R_BODY => if st.tx_stage > 0 then socbridge_driver_to_ip.is_full_out <= '0'; socbridge_driver_to_ext_data_cmd := ip_to_socbridge_driver.payload; end if; when TX_AWAIT => when ADDR1 => socbridge_driver_to_ext_data_cmd := st.curr_tx_addr(31 downto 24); when ADDR2 => socbridge_driver_to_ext_data_cmd := st.curr_tx_addr(23 downto 16); when ADDR3 => socbridge_driver_to_ext_data_cmd := st.curr_tx_addr(15 downto 8); when ADDR4 => socbridge_driver_to_ext_data_cmd := st.curr_tx_addr(7 downto 0); end case; --- ### RX_STATE BASED OUTPUT ### --- mgnt_valid_in <= '0'; mgnt_valid_out <= '0'; mgnt_ready_out <= '0'; case st.curr_rx_state is when IDLE => when RX_HEADER => when RX_W_BODY => -- TODO Add output signals to management unit later -- TODO REPLACE TWO BELOW socbridge_driver_to_ip.payload <= st.ext_to_socbridge_driver_reg.data; socbridge_driver_to_ip.write_enable_in <= '1'; when RX_R_BODY => socbridge_driver_to_ip.payload <= st.ext_to_socbridge_driver_reg.data; socbridge_driver_to_ip.write_enable_in <= '1'; when RX_AWAIT => if st.curr_rx_transaction = WRITE or st.curr_rx_transaction = WRITE_ADD then mgnt_valid_in <= '1'; end if; when ADDR1 => when ADDR2 => when ADDR3 => when ADDR4 => end case; next_parity_out <= calc_parity(socbridge_driver_to_ext_data_cmd); --- TRANSLATOR --- --- Next state assignment case trans_st.curr_state is when IDLE => if trans_st.curr_inst.request = '1' then trans_next_state <= SEND; else trans_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; else trans_next_state <= SEND; end if; -- Transisitonal state to decrement counter in transition between SEND and AWAIT. when SEND_ACCEPTED => trans_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; elsif st.curr_tx_state = IDLE then trans_next_state <= SEND; else trans_next_state <= AWAIT; end if; end case; --- NEXT TX TRANSACTION --- 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 st.curr_rx_transaction = WRITE or st.curr_rx_transaction = WRITE_ADD then next_tx_transaction := WRITE_ACK; elsif st.curr_rx_transaction = READ or st.curr_rx_transaction = READ_ADD then next_tx_transaction := READ_RESPONSE; end if; end if; 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 next_tx_transaction := READ_ADD; elsif trans_st.curr_inst.instruction = WRITE then next_tx_transaction := WRITE_ADD; end if; else if trans_st.curr_inst.instruction = READ then next_tx_transaction := READ; elsif trans_st.curr_inst.instruction = WRITE then 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; end process comb_proc; -- Process updating internal registers based on primary clock seq_proc: process(ext_to_socbridge_driver_rec.clk, rst, clk) begin if(rst = '1') then st.ext_to_socbridge_driver_reg.data <= (others => '0'); st.socbridge_driver_to_ext_reg.data <= (others => '0'); st.socbridge_driver_to_ext_reg.clk <= '0'; st.socbridge_driver_to_ext_reg.parity <= '1'; st.curr_tx_state <= IDLE; st.curr_rx_state <= IDLE; st.tx_stage <= 0; st.rx_stage <= 0; st.curr_tx_transaction <= NO_OP; st.curr_rx_transaction <= NO_OP; st.tx_data_size <= 0; st.curr_tx_addr <= (others => '0'); st.curr_rx_addr <= (others => '0'); st.curr_write_data <= (others => '0'); st.curr_read_data <= (others => '0'); elsif(rising_edge(ext_to_socbridge_driver_rec.clk)) then st.ext_to_socbridge_driver_reg.data <= ext_to_socbridge_driver_rec.data; st.ext_to_socbridge_driver_reg.clk <= ext_to_socbridge_driver_rec.clk; st.ext_to_socbridge_driver_reg.parity <= ext_to_socbridge_driver_rec.parity; st.socbridge_driver_to_ext_reg.data <= socbridge_driver_to_ext_data_cmd; st.socbridge_driver_to_ext_reg.clk <= not st.socbridge_driver_to_ext_reg.clk; st.socbridge_driver_to_ext_reg.parity <= next_parity_out; st.curr_tx_state <= next_tx_state; st.curr_rx_state <= next_rx_state; case st.curr_tx_state is 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; else st.tx_stage <= 0; end if; when TX_W_BODY => if st.tx_stage > 0 then st.tx_stage <= st.tx_stage - 1; end if; when TX_R_BODY => if st.tx_stage > 0 then st.tx_stage <= st.tx_stage - 1; end if; when others => end case; case st.curr_rx_state is when IDLE => st.curr_rx_transaction <= next_rx_transaction; 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; when RX_HEADER => if st.curr_rx_transaction = READ then st.curr_rx_addr <= std_logic_vector(to_unsigned(to_integer(unsigned(st.curr_rx_addr) + 4), 32)); end if; when RX_R_BODY => if st.rx_stage > 0 then st.rx_stage <= st.rx_stage - 1; end if; when RX_W_BODY => if st.rx_stage > 0 then st.rx_stage <= st.rx_stage - 1; st.curr_write_data((st.rx_stage) * 8 - 1 downto (st.rx_stage - 1) * 8) <= st.ext_to_socbridge_driver_reg.data; end if; when ADDR1 => st.curr_rx_addr(31 downto 24) <= st.ext_to_socbridge_driver_reg.data; when ADDR2 => st.curr_rx_addr(23 downto 16) <= st.ext_to_socbridge_driver_reg.data; when ADDR3 => st.curr_rx_addr(15 downto 8) <= st.ext_to_socbridge_driver_reg.data; when ADDR4 => st.curr_rx_addr(7 downto 0) <= st.ext_to_socbridge_driver_reg.data; when others => end case; end if; --- 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 when IDLE => if controller_to_socbridge_driver.request = '1' then trans_st.curr_inst <= controller_to_socbridge_driver; else end if; trans_st.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; 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; end if; trans_st.is_first_word <= '0'; when others => end case; end if; end process seq_proc; end architecture rtl;