diff --git a/src/controller/control_unit.vhd b/src/controller/control_unit.vhd index c013767..00a4f5d 100644 --- a/src/controller/control_unit.vhd +++ b/src/controller/control_unit.vhd @@ -19,10 +19,10 @@ end entity control_unit; architecture behave of control_unit is type state_t is record address: std_logic_vector(address_width - 1 downto 0); - seq_mem_access_count: std_logic_vector(seq_vector_length - 1 downto 0); + seq_mem_access_count: integer; curr_driver: std_logic_vector(number_of_drivers - 1 downto 0); --one-hot encoded, 0 means disabled ready: std_logic; - instruction: std_logic_vector(inst_word_width - 1 downto 0); + instruction: instruction_command_t; end record state_t; signal state: state_t; @@ -49,17 +49,20 @@ begin if rising_edge(clk) then if rst = '1' then state <= ((others => '0'), - (others => '0'), + 0, (others => '0'), '1', - x"00"); + NO_OP); else state.ready <= not ored; if ored = '0' then state.address <= ext_control_in.address; state.seq_mem_access_count <= ext_control_in.seq_mem_access_count; state.curr_driver <= ext_control_in.driver_id; - state.instruction <= ext_control_in.instruction; + with ext_control_in.cmd select + state.instruction <= WRITE when "01", + READ when "10", + NO_OP when others; end if; end if; end if; diff --git a/src/controller/control_unit_tb.vhd b/src/controller/control_unit_tb.vhd index db8b317..3fb4e22 100644 --- a/src/controller/control_unit_tb.vhd +++ b/src/controller/control_unit_tb.vhd @@ -17,8 +17,8 @@ architecture tb of control_unit_tb is signal ext_control_input: ext_control_unit_in_t := ( (others => '0'), (others => '0'), - (others => '0'), - x"00"); + 0, + "00"); signal int_control_input: int_control_unit_in_t := (active_driver => (others => '0')); signal ext_control_output: ext_control_unit_out_t; signal int_control_output: int_control_unit_out_t; @@ -53,8 +53,8 @@ begin ext_control_input.driver_id <= "010"; int_control_input.active_driver <= "000"; ext_control_input.address <= x"F0F0F0F0"; - ext_control_input.seq_mem_access_count <= "00000011"; - ext_control_input.instruction <= x"81"; + ext_control_input.seq_mem_access_count <= 3; + ext_control_input.cmd <= "01"; word_counter := 3; wait for cycle; current_driver <= "010"; @@ -78,7 +78,7 @@ begin wait for cycle; assert int_control_output.driver_id = "010" report "Incorrect driver_id from control_unit" severity error; assert int_control_output.address = x"F0F0F0F0" report "Incorrect address from control_unit" severity error; - assert int_control_output.instruction = x"81" report "Incorrect memory op from control_unit" severity error; + assert int_control_output.instruction = WRITE report "Incorrect memory op from control_unit" severity error; wait for 5 * cycle; reset <= '1'; diff --git a/src/ganimede/control_socbridge_tb.vhd b/src/ganimede/control_socbridge_tb.vhd index e961672..3eed3a4 100644 --- a/src/ganimede/control_socbridge_tb.vhd +++ b/src/ganimede/control_socbridge_tb.vhd @@ -1,8 +1,8 @@ library IEEE; use IEEE.std_logic_1164.all; use IEEE.NUMERIC_STD.all; -library work; -use work.io_types.all; +library ganimede; +use ganimede.io_types.all; library socbridge; use socbridge.socbridge_driver_tb_pkg.all; library controller; @@ -22,8 +22,8 @@ architecture tb of control_socbridge_tb is control => (others => '0') ); signal ext_socbridge_out : ext_socbridge_out_t; - signal int_socbridge_in : int_socbridge_in_t; - signal int_socbridge_out : int_socbridge_out_t := ( + signal int_socbridge_out : int_socbridge_out_t; + signal int_socbridge_in : int_socbridge_in_t := ( payload => (others => '0'), write_enable_out => '0', is_full_in => '0' @@ -31,26 +31,26 @@ architecture tb of control_socbridge_tb is signal ext_control_input: ext_control_unit_in_t := ( driver_id => (others => '0'), address => (others => '0'), - seq_mem_access_count => (others => '0'), - instruction => x"00" + seq_mem_access_count => 0, + cmd => x"00" ); signal int_control_input: int_control_unit_in_t := (active_driver => (others => '0')); signal ext_control_output: ext_control_unit_out_t; signal int_control_output: int_control_unit_out_t; -begin - + signal driver_to_control: driver_to_control_t; + signal control_to_driver: control_to_driver_t; +begin socbridge_inst: entity socbridge.socbridge_driver port map( clk => clk, rst => rst, - cmd => cu_to_sb_cmd, - address => cu_to_sb_address, - cmd_size => cmd_size, - ext_in => ext_socbridge_in, + ctrl_in => control_to_driver, + ctrl_out => driver_to_control, + ext_in => ext_socbridge_in, ext_out => ext_socbridge_out, - int_in => int_socbridge_in, + int_in => int_socbridge_in, int_out => int_socbridge_out ); @@ -63,6 +63,13 @@ begin int_control_in => int_control_input, int_control_out => int_control_output ); + + control_to_driver.address <= int_control_output.address; + control_to_driver.request <= int_control_output.driver_id(0); + control_to_driver.instruction <= int_control_output.instruction; + control_to_driver.seq_mem_access_count <= int_control_output.seq_mem_access_count; + + int_control_input.active_driver(0) <= driver_to_control.is_active; clock_proc: process begin diff --git a/src/ganimede/io_type_pkg.vhd b/src/ganimede/io_type_pkg.vhd index 32e351d..a20221b 100644 --- a/src/ganimede/io_type_pkg.vhd +++ b/src/ganimede/io_type_pkg.vhd @@ -5,12 +5,14 @@ use IEEE.MATH_REAL.all; package io_types is --- CONSTANTS --- - constant number_of_drivers: natural := 3; + constant number_of_drivers: natural := 1; constant address_width: natural := 32; constant seq_vector_length: natural := 8; - constant inst_word_width: natural := 8; + constant inst_word_width: natural := 2; --- STANDARD TYPES --- + type instruction_command_t is (NO_OP, READ, WRITE); + type ext_protocol_def_t is record name: string (1 to 20); payload_width: natural; @@ -25,8 +27,8 @@ package io_types is type ext_control_unit_in_t is record driver_id: std_logic_vector(number_of_drivers - 1 downto 0); address: std_logic_vector(address_width - 1 downto 0); - seq_mem_access_count: std_logic_vector(seq_vector_length - 1 downto 0); - instruction: std_logic_vector(inst_word_width - 1 downto 0); + seq_mem_access_count: integer; + cmd: std_logic_vector(inst_word_width - 1 downto 0); end record ext_control_unit_in_t; type ext_control_unit_out_t is record @@ -36,14 +38,25 @@ package io_types is type int_control_unit_out_t is record driver_id: std_logic_vector(number_of_drivers - 1 downto 0); address: std_logic_vector(address_width - 1 downto 0); - seq_mem_access_count: std_logic_vector(seq_vector_length - 1 downto 0); - instruction: std_logic_vector(inst_word_width - 1 downto 0); + seq_mem_access_count: integer; + instruction: instruction_command_t; end record int_control_unit_out_t; type int_control_unit_in_t is record active_driver: std_logic_vector(number_of_drivers - 1 downto 0); end record int_control_unit_in_t; + type driver_to_control_t is record + is_active : std_logic; + end record driver_to_control_t; + + type control_to_driver_t is record + request: std_logic; + address: std_logic_vector(address_width - 1 downto 0); + seq_mem_access_count: integer; + instruction: instruction_command_t; + end record control_to_driver_t; + --- PROTOCOL INFORMATION --- constant interface_inst : interface_inst_t := ( socbridge => ("SoCBridge ", 8, 2, 2) @@ -60,16 +73,16 @@ package io_types is control : STD_LOGIC_VECTOR(interface_inst.socbridge.control_width_in - 1 downto 0); end record ext_socbridge_out_t; - type int_socbridge_in_t is record - payload : STD_LOGIC_VECTOR(interface_inst.socbridge.payload_width - 1 downto 0); - write_enable_in, is_full_out : std_logic; - end record int_socbridge_in_t; - type int_socbridge_out_t is record payload : STD_LOGIC_VECTOR(interface_inst.socbridge.payload_width - 1 downto 0); - write_enable_out, is_full_in : std_logic; + write_enable_in, is_full_out : std_logic; end record int_socbridge_out_t; + type int_socbridge_in_t is record + payload : STD_LOGIC_VECTOR(interface_inst.socbridge.payload_width - 1 downto 0); + write_enable_out, is_full_in : std_logic; + end record int_socbridge_in_t; + type ext_interface_in_t is record socbridge : ext_socbridge_in_t; end record ext_interface_in_t; @@ -78,12 +91,12 @@ package io_types is socbridge : ext_socbridge_out_t; end record ext_interface_out_t; - type int_interface_in_t is record - socbridge : int_socbridge_in_t; - end record int_interface_in_t; - type int_interface_out_t is record socbridge : int_socbridge_out_t; end record int_interface_out_t; + type int_interface_in_t is record + socbridge : int_socbridge_in_t; + end record int_interface_in_t; + end package io_types; diff --git a/src/socbridge/socbridge_driver.vhd b/src/socbridge/socbridge_driver.vhd index c2c393f..fb5bf3c 100644 --- a/src/socbridge/socbridge_driver.vhd +++ b/src/socbridge/socbridge_driver.vhd @@ -1,23 +1,25 @@ library IEEE; use IEEE.std_logic_1164.all; use IEEE.NUMERIC_STD.all; -library work; -use work.socbridge_driver_tb_pkg.all; library ganimede; use ganimede.io_types.all; +library socbridge; +use socbridge.socbridge_driver_tb_pkg.all; entity socbridge_driver is port( clk : in std_logic; rst : in std_logic; - cmd : in command_t; - address : in std_logic_vector(31 downto 0); - cmd_size: in positive; + ctrl_in : in control_to_driver_t; + ctrl_out: out driver_to_control_t; + -- cmd : in command_t; + -- address : in std_logic_vector(31 downto 0); + -- cmd_size: in positive; ext_in : in ext_socbridge_in_t; ext_out : out ext_socbridge_out_t; - int_in : out int_socbridge_in_t; - int_out : in int_socbridge_out_t + int_out : out int_socbridge_out_t; + int_in : in int_socbridge_in_t ); end entity socbridge_driver; @@ -27,11 +29,16 @@ architecture rtl of socbridge_driver is signal ext_in_rec : ext_protocol_t; shared variable ext_out_data_cmd : std_logic_vector(interface_inst.socbridge.payload_width - 1 downto 0); signal test : std_logic_vector(interface_inst.socbridge.payload_width - 1 downto 0); + signal next_cmd : command_t; + signal next_cmd_size : integer; signal next_state : state_t; signal curr_cmd_bits : std_logic_vector(4 downto 0); signal curr_response : response_t; signal curr_response_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; begin --- DEBUG GLOBAL BINDINGS --- -- synthesis translate_off @@ -72,11 +79,13 @@ begin READ_RESPONSE when "01000", READ_RESPONSE when "01100", NO_OP when others; - comb_proc: process(ext_in, int_out, curr_response, st, cmd) + comb_proc: process(ext_in, int_in, curr_response, st, ctrl_in, trans_st) begin -- Outputs ext_out <= create_io_type_out_from_ext_protocol(st.ext_out_reg); - + with trans_st.curr_state select + ctrl_out.is_active <= '0' when IDLE, + '1' when others; --- State Transition Diagram --- -- @@ -119,9 +128,9 @@ begin --- Next State Assignment --- case st.curr_state is when IDLE => - if cmd = WRITE or cmd = WRITE_ADD then + if st.curr_cmd = WRITE or st.curr_cmd = WRITE_ADD then next_state <= TX_HEADER; - elsif cmd = READ or cmd = READ_ADD then + elsif st.curr_cmd = READ or st.curr_cmd = READ_ADD then next_state <= RX_HEADER; else next_state <= IDLE; @@ -129,7 +138,7 @@ begin when TX_HEADER => -- The header only takes one word (cycle) to transmit. -- Continue to body or address directly afterwards. - if st.cmd_reg = WRITE_ADD then + if st.curr_cmd = WRITE_ADD then next_state <= ADDR1; else next_state <= TX_BODY; @@ -151,7 +160,7 @@ begin when RX_HEADER => -- The header only takes one word (cycle) to transmit. -- Continue to awaiting response directly afterwards. - if st.cmd_reg = READ_ADD then + if st.curr_cmd = READ_ADD then next_state <= ADDR1; else next_state <= RX_RESPONSE; @@ -180,7 +189,7 @@ begin when ADDR3 => next_state <= ADDR4; when ADDR4 => - if st.cmd_reg = WRITE or st.cmd_reg = WRITE_ADD then + if st.curr_cmd = WRITE or st.curr_cmd = WRITE_ADD then next_state <= TX_BODY; else next_state <= RX_RESPONSE; @@ -189,50 +198,51 @@ begin --- Combinatorial output based on current state --- ext_out_data_cmd := (others => '0'); - int_in.is_full_out <= '1'; - int_in.write_enable_in <= '0'; - int_in.payload <= (others => '0'); + int_out.is_full_out <= '1'; + int_out.write_enable_in <= '0'; + int_out.payload <= (others => '0'); case st.curr_state is when IDLE => - if cmd = WRITE or cmd = WRITE_ADD then - ext_out_data_cmd := get_cmd_bits(cmd) & get_size_bits(cmd_size); - elsif cmd = READ or cmd = READ_ADD then - ext_out_data_cmd := get_cmd_bits(cmd) & get_size_bits(cmd_size); + if st.curr_cmd = WRITE or st.curr_cmd = WRITE_ADD then + ext_out_data_cmd := get_cmd_bits(st.curr_cmd) & get_size_bits(st.curr_cmd_size); + elsif st.curr_cmd = READ or st.curr_cmd = READ_ADD then + ext_out_data_cmd := get_cmd_bits(st.curr_cmd) & get_size_bits(st.curr_cmd_size); + else end if; when TX_HEADER => - if st.cmd_reg = WRITE_ADD then - ext_out_data_cmd := st.addr_reg(7 downto 0); + if st.curr_cmd = WRITE_ADD then + ext_out_data_cmd := st.curr_addr(7 downto 0); else - ext_out_data_cmd := int_out.payload; - int_in.is_full_out <= '0'; + ext_out_data_cmd := int_in.payload; + int_out.is_full_out <= '0'; end if; when TX_BODY => if st.write_stage > 0 then - int_in.is_full_out <= '0'; - ext_out_data_cmd := int_out.payload; + int_out.is_full_out <= '0'; + ext_out_data_cmd := int_in.payload; else ext_out_data_cmd := (others => '0'); end if; when TX_ACK => when RX_HEADER => - if st.cmd_reg = READ_ADD then - ext_out_data_cmd := st.addr_reg(7 downto 0); + if st.curr_cmd = READ_ADD then + ext_out_data_cmd := st.curr_addr(7 downto 0); end if; when RX_RESPONSE => when RX_BODY_NO_OUT => when RX_BODY => - int_in.payload <= st.ext_in_reg.data; - int_in.write_enable_in <= '1'; + int_out.payload <= st.ext_in_reg.data; + int_out.write_enable_in <= '1'; when ADDR1 => - ext_out_data_cmd := st.addr_reg(15 downto 8); + ext_out_data_cmd := st.curr_addr(15 downto 8); when ADDR2 => - ext_out_data_cmd := st.addr_reg(23 downto 16); + ext_out_data_cmd := st.curr_addr(23 downto 16); when ADDR3 => - ext_out_data_cmd := st.addr_reg(31 downto 24); + ext_out_data_cmd := st.curr_addr(31 downto 24); when ADDR4 => - if st.cmd_reg = WRITE_ADD then - int_in.is_full_out <= '0'; - ext_out_data_cmd := int_out.payload; + if st.curr_cmd = WRITE_ADD then + int_out.is_full_out <= '0'; + ext_out_data_cmd := int_in.payload; end if; end case; next_parity_out <= calc_parity(ext_out_data_cmd); @@ -240,9 +250,65 @@ begin -- synthesis translate_off test <= ext_out_data_cmd; -- synthesis translate_on + --- 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_state /= IDLE then + trans_next_state <= AWAIT; + else + trans_next_state <= SEND; + end if; + -- Wait for driver to finish current instruction, then reenter SEND + when AWAIT => + if trans_st.curr_inst.seq_mem_access_count <= 0 then + trans_next_state <= IDLE; + elsif st.curr_state = IDLE then + trans_next_state <= SEND; + else + trans_next_state <= AWAIT; + end if; + end case; + + --- Combinatorial output based on state + next_cmd <= NO_OP; + next_cmd_size <= 0; + 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_cmd <= READ_ADD; + elsif trans_st.curr_inst.instruction = WRITE then + next_cmd <= WRITE_ADD; + end if; + else + if trans_st.curr_inst.instruction = READ then + next_cmd <= READ; + elsif trans_st.curr_inst.instruction = WRITE then + next_cmd <= WRITE; + end if; + end if; + + if trans_st.curr_inst.seq_mem_access_count > 256 then + next_cmd_size <= 256; + else + next_cmd_size <= trans_st.curr_inst.seq_mem_access_count; + end if; + when AWAIT => + end case; + end process comb_proc; -- Process updating internal registers based on primary clock - seq_proc: process(ext_in_rec.clk, rst) + seq_proc: process(ext_in_rec.clk, rst, clk) begin if(rst = '1') then st.ext_in_reg.data <= (others => '0'); @@ -252,8 +318,9 @@ begin st.curr_state <= IDLE; st.write_stage <= 0; st.read_stage <= 0; - st.cmd_reg <= NO_OP; - st.addr_reg <= (others => '0'); + st.curr_cmd <= NO_OP; + st.curr_cmd_size <= 0; + st.curr_addr <= (others => '0'); elsif(rising_edge(ext_in_rec.clk)) then st.ext_in_reg.data <= ext_in_rec.data; @@ -265,19 +332,17 @@ begin st.curr_state <= next_state; case st.curr_state is when IDLE => - if cmd = WRITE or cmd = WRITE_ADD or - cmd = READ or cmd = READ_ADD then - st.addr_reg <= address; - st.cmd_reg <= cmd; - end if; + st.curr_cmd <= next_cmd; + st.curr_cmd_size <= next_cmd_size; + st.curr_addr <= trans_st.curr_inst.address; when TX_HEADER => - st.write_stage <= 2**(cmd_size - 1) - 1; + st.write_stage <= 2**(st.curr_cmd_size - 1) - 1; when TX_BODY => if st.write_stage > 0 then st.write_stage <= st.write_stage - 1; end if; when RX_HEADER => - st.read_stage <= 2**(cmd_size - 1) - 1; + st.read_stage <= 2**(st.curr_cmd_size - 1) - 1; when RX_BODY => if st.read_stage > 0 then st.read_stage <= st.read_stage - 1; @@ -286,6 +351,29 @@ begin 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 ctrl_in.request = '1' then + trans_st.curr_inst <= ctrl_in; + end if; + when SEND => + trans_st.curr_inst.seq_mem_access_count <= trans_st.curr_inst.seq_mem_access_count - 256; + when AWAIT => + trans_st.is_first_word <= '0'; + when others => + end case; + end if; end process seq_proc; diff --git a/src/socbridge/socbridge_driver_tb.vhd b/src/socbridge/socbridge_driver_tb.vhd index 057b57a..25a67fc 100644 --- a/src/socbridge/socbridge_driver_tb.vhd +++ b/src/socbridge/socbridge_driver_tb.vhd @@ -75,7 +75,7 @@ architecture tb of socbridge_driver_tb is -- end component socbridge_driver; begin - socbridge_driver_inst: entity work.socbridge_driver + socbridge_driver_inst: entity socbridge.socbridge_driver port map( clk => clk, rst => rst, diff --git a/src/socbridge/socbridge_driver_tb_pkg.vhd b/src/socbridge/socbridge_driver_tb_pkg.vhd index 14b5d11..060d8e8 100644 --- a/src/socbridge/socbridge_driver_tb_pkg.vhd +++ b/src/socbridge/socbridge_driver_tb_pkg.vhd @@ -20,6 +20,15 @@ package socbridge_driver_tb_pkg is TX_HEADER, TX_BODY, TX_ACK, RX_HEADER, RX_RESPONSE, RX_BODY_NO_OUT, RX_BODY); + --- TRANSLATOR --- + type translator_state_t is (IDLE, SEND, AWAIT); + + type translator_state_rec_t is record + curr_inst : control_to_driver_t; + curr_state : translator_state_t; + is_first_word : std_logic; + end record translator_state_rec_t; + type ext_protocol_t is record data : std_logic_vector(interface_inst.socbridge.payload_width - 1 downto 0); clk : std_logic; @@ -30,8 +39,9 @@ package socbridge_driver_tb_pkg is curr_state: state_t; ext_in_reg, ext_out_reg : ext_protocol_t; write_stage, read_stage : NATURAL; - cmd_reg : command_t; - addr_reg : std_logic_vector(31 downto 0); + curr_cmd : command_t; + curr_cmd_size: integer; + curr_addr : std_logic_vector(31 downto 0); end record state_rec_t; impure function calc_parity( d : STD_LOGIC_VECTOR(interface_inst.socbridge.payload_width - 1 downto 0) diff --git a/src/vhdl_ls.toml b/src/vhdl_ls.toml index b7085cb..3a01a68 100644 --- a/src/vhdl_ls.toml +++ b/src/vhdl_ls.toml @@ -3,7 +3,7 @@ standard = "1993" # File names are either absolute or relative to the parent folder of the vhdl_ls.toml file [libraries] ganimede.files = [ - 'ganimede/*.vhd' + 'ganimede/io_type_pkg.vhd' ] socbridge.files = [ 'socbridge/*.vhd'