diff --git a/.gitignore b/.gitignore index 0be0f35..aaae97c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -*/wave -*/work +**/wave +**/work diff --git a/scripts/build_env.py b/scripts/build_env.py index b6fceff..d9ff493 100644 --- a/scripts/build_env.py +++ b/scripts/build_env.py @@ -43,20 +43,16 @@ def addAllVHDLFiles(std: str, lib: str, init=False): return -1 vhdlFiles = [] currentlyAdded = [] - absWorkDir = os.path.join(os.getcwd(), "work") cfFileId = getCfFileId(std) ## Find already present files if not init: - cfFileName = list(filter(lambda x: ".cf" in x and lib in x and cfFileId in x, os.listdir(absWorkDir)))[0] - cfFilePath = os.path.join(absWorkDir,cfFileName) + cfFileName = list(filter(lambda x: ".cf" in x and lib in x and cfFileId in x, os.listdir("work")))[0] + cfFilePath = os.path.join("work",cfFileName) currentlyAdded = getCurrentlyAddedFiles(cfFilePath) - print(currentlyAdded) ## Add files not added for file in os.listdir(): - print(file) - print(currentlyAdded, file, file not in currentlyAdded) if ".vhd" in file and file not in currentlyAdded: - vhdlFiles.append(os.path.join(os.getcwd(), file)) + vhdlFiles.append(file) if len(vhdlFiles) > 0: print(f"Detected new files. Adding {vhdlFiles}") command = ["ghdl", "-i", "--workdir=work", f"--work={lib}", f"--std={std}"] + vhdlFiles @@ -68,5 +64,5 @@ def getCurrentlyAddedFiles(cfFilePath:str): lines = f.readlines() f.close() fileLines = filter(lambda x: "file" in x, lines) - files = map(lambda x: split("\"",x)[1], fileLines) + files = map(lambda x: split("\" \"",x)[1], fileLines) return list(files) diff --git a/scripts/elab.py b/scripts/elab.py index 1d5a040..7cf0edc 100644 --- a/scripts/elab.py +++ b/scripts/elab.py @@ -7,7 +7,7 @@ from typing import List def generateIncludesForGHDL(includes: List[str]): cmd = [] for inc in includes: - cmd.append(f"-P{os.path.join(os.getcwd(), f"{inc}/work")}") + cmd.append(f"-P{inc}/work") return cmd def elabDesign(topDef: str, arch: str, lib: str, std: str, includes: List[str]): @@ -26,7 +26,7 @@ def runDesign(topDef: str, arch: str, lib: str, std: str, includes): print("Elaboration failed...") return -1 os.makedirs("wave",exist_ok=True) - wavePath = os.path.join(os.getcwd(), "wave") + wavePath = "wave" incs = generateIncludesForGHDL(includes) command = [ ## may add -v for verbose "ghdl", "--elab-run", f"--workdir=work", f"--work={lib}", f"--std={std}"] + incs + ["-o", f"work/{topDef}-{arch}", f"{topDef}", f"{arch}", diff --git a/src/control_socbridge_merge/control_socbridge_tb.vhd b/src/control_socbridge_merge/control_socbridge_tb.vhd new file mode 100644 index 0000000..dc15769 --- /dev/null +++ b/src/control_socbridge_merge/control_socbridge_tb.vhd @@ -0,0 +1,218 @@ +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.NUMERIC_STD.all; +library ganimede; +use ganimede.io_types.all; +library socbridge; +use socbridge.socbridge_driver_tb_pkg.all; +library controller; + +entity control_socbridge_tb is +end entity control_socbridge_tb; + +architecture tb of control_socbridge_tb is + + constant CLK_PERIOD : Time := 10 ns; + constant SIMULATION_CYCLE_COUNT : integer := 2000; + signal clk, rst : std_logic := '0'; + signal controller_to_socbridge_driver_cmd : command_t; + signal controller_to_socbridge_driver_address : std_logic_vector(31 downto 0); + signal cmd_size : positive; + signal ext_to_socbridge_driver : ext_to_socbridge_driver_t := ( + payload => (others => '0'), + control => (others => '0') + ); + signal socbridge_driver_to_ext : socbridge_driver_to_ext_t; + signal socbridge_driver_to_buffer : socbridge_driver_to_buffer_t; + signal buffer_to_socbridge_driver : buffer_to_socbridge_driver_t := ( + payload => (others => '0'), + write_enable_out => '0', + is_full_in => '0' + ); + signal cpu_to_controller: cpu_to_controller_t := ( + driver_id => (others => '0'), + address => (others => '0'), + seq_mem_access_count => 0, + cmd => "00" + ); + signal socbridge_driver_to_controller: socbridge_driver_to_controller_t := (is_active => '0'); + signal controller_to_cpu: controller_to_cpu_t; + signal controller_to_socbridge_driver: controller_to_socbridge_driver_t; + + signal curr_word : std_logic_vector(ext_to_socbridge_driver.payload'length - 1 downto 0); + signal expected_out : std_logic_vector(socbridge_driver_to_ext.payload'length - 1 downto 0); + + procedure fail(error_msg : string) is + begin + wait for CLK_PERIOD; + report "Simulation ending due to: " & error_msg & ". Shutting down..." severity FAILURE; + end procedure; + + procedure check_next_state(correct_state: state_t) is + begin + if(not (correct_state = G_next_state)) then + report "Next State is not what was expected, found " & state_t'image(G_next_state) + & " but expected " & state_t'image(correct_state) severity error; + fail("Next State"); + end if; + end procedure; + + procedure check_data_out(correct_data: std_logic_vector(socbridge_driver_to_ext.payload'length - 1 downto 0)) is + begin + if(not (correct_data = socbridge_driver_to_ext.payload)) then + report "Data out is not what was expected, found " & to_string(socbridge_driver_to_ext.payload) + & " but expected " & to_string(correct_data) severity error; + fail("Data out"); + end if; + end procedure; + + procedure check_parity(correct_data: std_logic_vector(socbridge_driver_to_ext.payload'length - 1 downto 0)) is + begin + if(not (calc_parity(correct_data) = calc_parity(socbridge_driver_to_ext.payload))) then + report "Parity out is not what was expected, found " & std_logic'image(calc_parity(socbridge_driver_to_ext.payload)) + & " but expected " & std_logic'image(calc_parity(correct_data)) severity error; + fail("Parity out"); + end if; + end procedure; + +begin + socbridge_inst: entity socbridge.socbridge_driver + port map( + clk => clk, + rst => rst, + controller_to_socbridge_driver => controller_to_socbridge_driver, + socbridge_driver_to_controller => socbridge_driver_to_controller, + ext_to_socbridge_driver => ext_to_socbridge_driver, + socbridge_driver_to_ext => socbridge_driver_to_ext, + buffer_to_socbridge_driver => buffer_to_socbridge_driver, + socbridge_driver_to_buffer => socbridge_driver_to_buffer + ); + + controller_unit_inst: entity controller.control_unit + port map( + clk => clk, + rst => rst, + cpu_to_controller => cpu_to_controller, + controller_to_cpu => controller_to_cpu, + socbridge_driver_to_controller => socbridge_driver_to_controller, + controller_to_socbridge_driver => controller_to_socbridge_driver + ); + + ext_to_socbridge_driver.control(1) <= clk; + controller_clock_proc: process + begin + for i in 0 to SIMULATION_CYCLE_COUNT - 1 loop + wait for CLK_PERIOD / 2; + clk <= not clk; + end loop; + wait; + end process controller_clock_proc; + + stimulus_proc: process + begin + report "Starting Simulation Stimulus!"; + rst <= '1'; + cpu_to_controller.address <= (others => '0'); + cpu_to_controller.cmd <= "00"; + cpu_to_controller.driver_id <= "1"; + cpu_to_controller.seq_mem_access_count <= 256; + wait for 3 * CLK_PERIOD; + report "Reset grace period ended, starting stimulus..."; + rst <= '0'; + cpu_to_controller.address <= x"FA0FA0FA"; + cpu_to_controller.cmd <= "01"; + wait until socbridge_driver_to_controller.is_active = '1'; + report "Task received in driver, awaiting completion..."; + cpu_to_controller.address <= (others => '0'); + cpu_to_controller.cmd <= "00"; + wait until socbridge_driver_to_controller.is_active = '0'; + wait for CLK_PERIOD; + report "Task completed in driver, sending next task..."; + cpu_to_controller.address <= x"FA0FA0FA"; + cpu_to_controller.cmd <= "10"; + wait for CLK_PERIOD; + wait until socbridge_driver_to_controller.is_active = '1'; + report "Task received in driver, awaiting completion..."; + cpu_to_controller.address <= (others => '0'); + cpu_to_controller.cmd <= "00"; + wait until socbridge_driver_to_controller.is_active = '0'; + wait for CLK_PERIOD; + report "Task completed in driver, ending simulation stimulus"; + cpu_to_controller.address <= (others => '0'); + cpu_to_controller.cmd <= "00"; + cpu_to_controller.driver_id <= "0"; + cpu_to_controller.seq_mem_access_count <= 0; + + wait; + end process stimulus_proc; + + external_stimulus_signal: process(curr_word) + begin + ext_to_socbridge_driver.payload <= curr_word; + ext_to_socbridge_driver.control(0) <= calc_parity(curr_word); + end process external_stimulus_signal; + + external_stimulus: process + variable input : positive := 1; + begin + wait for CLK_PERIOD / 1000; + curr_word <= "00000000"; + wait for 999 * CLK_PERIOD / 1000; + wait for 2 * CLK_PERIOD; + wait for CLK_PERIOD / 2; + wait for 10* CLK_PERIOD; + curr_word <= "00001001"; + wait for CLK_PERIOD; + curr_word <= "00000000"; + wait for CLK_PERIOD * 140; + curr_word <= "00101001"; + wait for CLK_PERIOD; + curr_word <= "00000000"; + wait for CLK_PERIOD * 140; + curr_word <= "00101001"; + wait for CLK_PERIOD; + curr_word <= "00000000"; + wait for CLK_PERIOD * 20; + curr_word <= "01100111"; + wait for CLK_PERIOD; + for x in 0 to 127 loop + curr_word <= std_logic_vector(to_unsigned(input, 8)); + input := input + 1 mod 256; + wait for CLK_PERIOD; + end loop; + curr_word <= "00000000"; + wait for CLK_PERIOD * 140; + wait for CLK_PERIOD * 20; + curr_word <= "01100111"; + wait for CLK_PERIOD; + for x in 0 to 127 loop + curr_word <= std_logic_vector(to_unsigned(input, 8)); + input := input + 1 mod 256; + wait for CLK_PERIOD; + end loop; + + wait; + end process external_stimulus; + + internal_stimulus: process + variable input : positive := 1; + begin + buffer_to_socbridge_driver.is_full_in <= '0'; + buffer_to_socbridge_driver.write_enable_out <= '0'; + wait for 3 * CLK_PERIOD; + -- stimulus goes here + buffer_to_socbridge_driver.write_enable_out <= '1'; + buffer_to_socbridge_driver.payload <= std_logic_vector(to_unsigned(input, buffer_to_socbridge_driver.payload'length)); + input := input + 1 mod 256; + wait until rising_edge(clk) and socbridge_driver_to_buffer.is_full_out = '0'; + wait until falling_edge(clk); + for x in 0 to 1000 loop + buffer_to_socbridge_driver.payload <= std_logic_vector(to_unsigned(input, buffer_to_socbridge_driver.payload'length)); + input := input + 1 mod 256; + wait until rising_edge(clk) and socbridge_driver_to_buffer.is_full_out = '0'; + wait until falling_edge(clk); + end loop; + wait; + end process internal_stimulus; + +end architecture tb; diff --git a/src/control_unit.vhd b/src/control_unit.vhd deleted file mode 100644 index 7c4095b..0000000 --- a/src/control_unit.vhd +++ /dev/null @@ -1,66 +0,0 @@ -library IEEE; -use IEEE.std_logic_1164.all; -use IEEE.MATH_REAL.all; -library work; -use work.io_types.all; - -entity control_unit is - - port ( - clk, rst: in std_logic; - control_in: in control_unit_in_t; - control_out: out control_unit_out_t - ); - -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); - 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); - end record state_t; - - signal state: state_t; - shared variable ored: std_logic; - - -begin - - comb_proc: process(control_in, state) - begin - ored := '0'; - ready_reduction: for i in 0 to number_of_drivers - 1 loop - ored := ored or control_in.active_driver(i); - end loop ready_reduction; - control_out.driver_id <= state.curr_driver; - control_out.address <= state.address; - control_out.seq_mem_access_count <= state.seq_mem_access_count; - control_out.ready <= state.ready; - control_out.instruction <= state.instruction; - end process comb_proc; - - sync_proc: process(clk, state) - begin - if rising_edge(clk) then - if rst = '1' then - state <= ((others => '0'), - (others => '0'), - (others => '0'), - '1', - x"00"); - else - state.ready <= not ored; - if ored = '0' then - state.address <= control_in.address; - state.seq_mem_access_count <= control_in.seq_mem_access_count; - state.curr_driver <= control_in.driver_id; - state.instruction <= control_in.instruction; - end if; - end if; - end if; - end process sync_proc; - -end architecture behave; diff --git a/src/control_unit_tb.vhd b/src/control_unit_tb.vhd deleted file mode 100644 index 62eefd8..0000000 --- a/src/control_unit_tb.vhd +++ /dev/null @@ -1,91 +0,0 @@ -library IEEE; -use IEEE.std_logic_1164.all; -use IEEE.MATH_REAL.all; -use ieee.numeric_std.all; -library work; -use work.io_types.all; - -entity control_unit_tb is -end entity control_unit_tb; - -architecture tb of control_unit_tb is - - constant cycle: Time := 10 ns; - signal clock: std_logic := '0'; - signal reset: std_logic := '0'; - signal control_input: control_unit_in_t := ( - (others => '0'), - (others => '0'), - (others => '0'), - (others => '0'), - x"00"); - signal control_output: control_unit_out_t := ( - (others => '0'), - (others => '0'), - (others => '1'), - '1', - x"00"); - signal current_driver : std_logic_vector(2 downto 0) := "000"; - shared variable word_counter: natural := 0; - -begin - - clock_proc: process - begin - for i in 0 to 50 loop - wait for cycle / 2; - clock <= not clock; - end loop; - wait; - end process clock_proc; - - control_unit_inst: entity work.control_unit - port map( - clk => clock, - rst => reset, - control_in => control_input, - control_out => control_output - ); - -stimulus_proc: process -begin - wait for cycle; - - control_input.driver_id <= "010"; - control_input.active_driver <= "000"; - control_input.address <= x"F0F0F0F0"; - control_input.seq_mem_access_count <= "00000011"; - control_input.instruction <= x"81"; - word_counter := 3; - wait for cycle; - current_driver <= "010"; - - report "entering loop with word_counter" & integer'image(word_counter); - for_loop: for i in word_counter - 1 downto 0 loop - wait for cycle; - report "words remaining are " & integer'image(i); - end loop for_loop; - - control_input.active_driver <= "000"; - report "Stim process done"; - wait; -end process stimulus_proc; - -monitor_proc: process -begin - - wait for cycle; - - wait for cycle; - assert control_output.driver_id = "010" report "Incorrect driver_id from control_unit" severity error; - assert control_output.address = x"F0F0F0F0" report "Incorrect address from control_unit" severity error; - assert control_output.instruction = x"81" report "Incorrect memory op from control_unit" severity error; - - wait for 5 * cycle; - reset <= '1'; - - report "Monitor process done"; - wait; -end process monitor_proc; - -end architecture tb; diff --git a/src/controller/control_unit.vhd b/src/controller/control_unit.vhd new file mode 100644 index 0000000..66f4870 --- /dev/null +++ b/src/controller/control_unit.vhd @@ -0,0 +1,77 @@ +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.MATH_REAL.all; +library ganimede; +use ganimede.io_types.all; + +entity control_unit is + + port ( + clk, rst : in std_logic; + cpu_to_controller : in cpu_to_controller_t; + controller_to_cpu : out controller_to_cpu_t; + socbridge_driver_to_controller : in socbridge_driver_to_controller_t; + controller_to_socbridge_driver : out controller_to_socbridge_driver_t + ); + +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: integer; + curr_driver: std_logic; + ready: std_logic; + instruction: instruction_command_t; + end record state_t; + + signal state: state_t; + shared variable ored: std_logic; + + +begin + + comb_proc: process(cpu_to_controller, socbridge_driver_to_controller, state) + begin + ored := '0'; + ready_reduction: for i in 0 to number_of_drivers - 1 loop + ored := ored or socbridge_driver_to_controller.is_active; + end loop ready_reduction; + controller_to_socbridge_driver.request <= state.curr_driver; + controller_to_socbridge_driver.address <= state.address; + controller_to_socbridge_driver.seq_mem_access_count <= state.seq_mem_access_count; + controller_to_cpu.ready <= state.ready; + controller_to_socbridge_driver.instruction <= state.instruction; + end process comb_proc; + + sync_proc: process(clk, state) + begin + if rising_edge(clk) then + if rst = '1' then + state <= ((others => '0'), + 0, + '0', + '1', + NO_OP); + else + state.ready <= not ored; + if ored = '0' then + state.address <= cpu_to_controller.address; + state.seq_mem_access_count <= cpu_to_controller.seq_mem_access_count; + state.curr_driver <= cpu_to_controller.driver_id(0); + with cpu_to_controller.cmd select + state.instruction <= WRITE when "01", + READ when "10", + NO_OP when others; + else + state <= ((others => '0'), + 0, + '0', + '1', + NO_OP); + end if; + end if; + end if; + end process sync_proc; + +end architecture behave; diff --git a/src/controller/control_unit_tb.vhd b/src/controller/control_unit_tb.vhd new file mode 100644 index 0000000..905166d --- /dev/null +++ b/src/controller/control_unit_tb.vhd @@ -0,0 +1,90 @@ +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.MATH_REAL.all; +use IEEE.numeric_std.all; +library ganimede; +use ganimede.io_types.all; +library controller; + +entity control_unit_tb is +end entity control_unit_tb; + +architecture tb of control_unit_tb is + + constant cycle: Time := 10 ns; + signal clock: std_logic := '0'; + signal reset: std_logic := '0'; + signal cpu_to_controller: cpu_to_controller_t := ( + (others => '0'), + (others => '0'), + 0, + "00"); + signal socbridge_driver_to_controller: socbridge_driver_to_controller_t := (is_active => '0'); + signal controller_to_cpu: controller_to_cpu_t; + signal controller_to_socbridge_driver: controller_to_socbridge_driver_t; + signal current_driver : std_logic_vector(0 downto 0) := "0"; + shared variable word_counter: natural := 0; + +begin + + clock_proc: process + begin + for i in 0 to 50 loop + wait for cycle / 2; + clock <= not clock; + end loop; + wait; + end process clock_proc; + + control_unit_inst: entity controller.control_unit + port map( + clk => clock, + rst => reset, + cpu_to_controller => cpu_to_controller, + controller_to_cpu => controller_to_cpu, + socbridge_driver_to_controller => socbridge_driver_to_controller, + controller_to_socbridge_driver => controller_to_socbridge_driver + ); + +stimulus_proc: process +begin + wait for cycle; + + cpu_to_controller.driver_id <= "1"; + socbridge_driver_to_controller.is_active <= '0'; + cpu_to_controller.address <= x"F0F0F0F0"; + cpu_to_controller.seq_mem_access_count <= 3; + cpu_to_controller.cmd <= "01"; + word_counter := 3; + wait for cycle; + current_driver <= "1"; + + report "entering loop with word_counter" & integer'image(word_counter); + for_loop: for i in word_counter - 1 downto 0 loop + wait for cycle; + report "words remaining are " & integer'image(i); + end loop for_loop; + + socbridge_driver_to_controller.is_active <= '0'; + report "Stim process done"; + wait; +end process stimulus_proc; + +monitor_proc: process +begin + + wait for cycle; + + wait for cycle; + assert controller_to_socbridge_driver.request = '1' report "Incorrect driver_id from control_unit" severity error; + assert controller_to_socbridge_driver.address = x"F0F0F0F0" report "Incorrect address from control_unit" severity error; + assert controller_to_socbridge_driver.instruction = WRITE report "Incorrect memory op from control_unit" severity error; + + wait for 5 * cycle; + reset <= '1'; + + report "Monitor process done"; + wait; +end process monitor_proc; + +end architecture tb; diff --git a/src/ganimede.vhd b/src/ganimede/ganimede.vhd similarity index 91% rename from src/ganimede.vhd rename to src/ganimede/ganimede.vhd index e95d003..7bcb720 100644 --- a/src/ganimede.vhd +++ b/src/ganimede/ganimede.vhd @@ -43,10 +43,10 @@ architecture rtl of ganimede is port( clk : in std_logic; reset : in std_logic; - 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 + ext_in : in ext_to_socbridge_driver_t; + ext_out : out socbridge_driver_to_ext_t; + int_in : out buffer_to_socbridge_driver_t; + int_out : in socbridge_driver_to_buffer_t ); end component; diff --git a/src/ganimede/io_type_pkg.vhd b/src/ganimede/io_type_pkg.vhd new file mode 100644 index 0000000..ed67ad3 --- /dev/null +++ b/src/ganimede/io_type_pkg.vhd @@ -0,0 +1,102 @@ +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.MATH_REAL.all; + +package io_types is + + --- CONSTANTS --- + constant number_of_drivers: natural := 1; + constant address_width: natural := 32; + constant seq_vector_length: 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; + control_width_in, control_width_out: natural; + end record ext_protocol_def_t; + + type interface_inst_t is record + socbridge: ext_protocol_def_t; + end record interface_inst_t; + + --- CONTROL UNIT --- + type cpu_to_controller_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: integer; + cmd: std_logic_vector(1 downto 0); + end record cpu_to_controller_t; + + type controller_to_cpu_t is record + ready: std_logic; + end record controller_to_cpu_t; + + --type controller_to_socbridge_driver_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: integer; + -- instruction: instruction_command_t; + --end record controller_to_socbridge_driver_t; + + --type socbridge_driver_to_controller_t is record + -- active_driver: std_logic_vector(number_of_drivers - 1 downto 0); + --end record socbridge_driver_to_controller_t; + + type socbridge_driver_to_controller_t is record + is_active : std_logic; + end record socbridge_driver_to_controller_t; + + type controller_to_socbridge_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 controller_to_socbridge_driver_t; + + --- PROTOCOL INFORMATION --- + constant interface_inst : interface_inst_t := ( + socbridge => ("SoCBridge ", 8, 2, 2) + ); + + --- AUTOGENERATED TYPES --- + type ext_to_socbridge_driver_t is record + payload : STD_LOGIC_VECTOR(interface_inst.socbridge.payload_width - 1 downto 0); + control : STD_LOGIC_VECTOR(interface_inst.socbridge.control_width_in - 1 downto 0); + end record ext_to_socbridge_driver_t; + + type socbridge_driver_to_ext_t is record + payload : STD_LOGIC_VECTOR(interface_inst.socbridge.payload_width - 1 downto 0); + control : STD_LOGIC_VECTOR(interface_inst.socbridge.control_width_in - 1 downto 0); + end record socbridge_driver_to_ext_t; + + type socbridge_driver_to_buffer_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 socbridge_driver_to_buffer_t; + + type buffer_to_socbridge_driver_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 buffer_to_socbridge_driver_t; + + type ext_interface_in_t is record + socbridge : ext_to_socbridge_driver_t; + end record ext_interface_in_t; + + type ext_interface_out_t is record + socbridge : socbridge_driver_to_ext_t; + end record ext_interface_out_t; + + type int_interface_out_t is record + socbridge : socbridge_driver_to_buffer_t; + end record int_interface_out_t; + + type int_interface_in_t is record + socbridge : buffer_to_socbridge_driver_t; + end record int_interface_in_t; + +end package io_types; diff --git a/src/io_type_pkg.vhd b/src/io_type_pkg.vhd deleted file mode 100644 index 6238419..0000000 --- a/src/io_type_pkg.vhd +++ /dev/null @@ -1,79 +0,0 @@ -library IEEE; -use IEEE.std_logic_1164.all; -use IEEE.MATH_REAL.all; - -package io_types is - - --- STANDARD TYPES --- - type ext_protocol_def_t is record - name: string (1 to 20); - payload_width: natural; - control_width_in, control_width_out: natural; - end record ext_protocol_def_t; - - type interface_inst_t is record - socbridge: ext_protocol_def_t; - end record interface_inst_t; - - constant number_of_drivers: natural := 3; - constant address_width: natural := 32; - constant seq_vector_length: natural := 8; - constant inst_word_width: natural := 8; - - type 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); - ready: std_logic; - instruction: std_logic_vector(inst_word_width - 1 downto 0); - end record control_unit_out_t; - - type control_unit_in_t is record - driver_id, active_driver: 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); - end record control_unit_in_t; - --- PROTOCOL INFORMATION --- - constant interface_inst : interface_inst_t := ( - socbridge => ("SoCBridge ", 8, 2, 2) - ); - - --- AUTOGENERATED TYPES --- - type ext_socbridge_in_t is record - payload : STD_LOGIC_VECTOR(interface_inst.socbridge.payload_width - 1 downto 0); - control : STD_LOGIC_VECTOR(interface_inst.socbridge.control_width_in - 1 downto 0); - end record ext_socbridge_in_t; - - type ext_socbridge_out_t is record - payload : STD_LOGIC_VECTOR(interface_inst.socbridge.payload_width - 1 downto 0); - 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; - end record int_socbridge_out_t; - - type ext_interface_in_t is record - socbridge : ext_socbridge_in_t; - end record ext_interface_in_t; - - type ext_interface_out_t is record - 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; - -end package io_types; diff --git a/src/socbridge/socbridge_driver.vhd b/src/socbridge/socbridge_driver.vhd new file mode 100644 index 0000000..449a32e --- /dev/null +++ b/src/socbridge/socbridge_driver.vhd @@ -0,0 +1,398 @@ +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.NUMERIC_STD.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; + 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; + socbridge_driver_to_buffer : out socbridge_driver_to_buffer_t; + buffer_to_socbridge_driver : in buffer_to_socbridge_driver_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); + 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 + G_next_parity_out <= next_parity_out; + G_ext_to_socbridge_driver_rec <= ext_to_socbridge_driver_rec; + G_next_state <= next_state; + G_socbridge_driver_to_ext_data_cmd <=test; + G_curr_command_bits <= curr_cmd_bits; + G_curr_response <= curr_response; + G_curr_response_bits <= curr_response_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); + + -- Helpful Bindings -- + curr_response_bits <= ext_to_socbridge_driver.payload(7 downto 3); -- CANT USE ext_to_socbridge_driver_REC here for some reason, the assignment becomes stasteful + -- Not sure that the two process method is helping here: if this was a normal + -- signal assignment there would be no confusion. + -- in the case ... <= ext_to_socbridge_driver_rec we get + -- curr_resp | ext_to_socbridge_driver_rec | ext_to_socbridge_driver + -- 00000 | 00000000 | 00001001 + -- 00000 | 00001001 | 00001001 + -- 00001 | 00001001 | 00001001 + -- 00001 | 00001001 | 00001001 + -- + -- but in the case ... <= ext_to_socbridge_driver we get + -- curr_resp | ext_to_socbridge_driver_rec | ext_to_socbridge_driver + -- 00000 | 00000000 | 00001001 + -- 00001 | 00001001 | 00001001 + -- 00001 | 00001001 | 00001001 + -- 00001 | 00001001 | 00001001 + + with curr_response_bits select + curr_response <= WRITE_ACK when "00001", + WRITE_ACK when "00101", + READ_RESPONSE when "01000", + READ_RESPONSE when "01100", + NO_OP when others; + comb_proc: process(ext_to_socbridge_driver, buffer_to_socbridge_driver, curr_response, st, controller_to_socbridge_driver, trans_st) + begin + -- Outputs + socbridge_driver_to_ext <= create_io_type_out_from_ext_protocol(st.socbridge_driver_to_ext_reg); + with trans_st.curr_state select + socbridge_driver_to_controller.is_active <= '0' when IDLE, + '1' when others; + + --- State Transition Diagram --- +-- +-- +-- +-- +-----+ +-- | | +-- \|/ /--+ +-- IDLE<-------------------+ +-- / \ | +-- / \ | +-- / \ | +-- \|/ \|/ | +-- TX_HEADER RX_HEADER | +-- |\ / | | +-- | \ / | | +-- | ADDR1 | | +-- | | | | +-- | \|/ | | +-- | ADDR2 | | +-- | | | | +-- | \|/ | | +-- | ADDR3 | | +-- | | | | +-- | \|/ | | +-- | ADDR4 | | +-- | /\ | | +-- | / \ | | +-- |-+ +----| +---+ | +-- \|/ \|/ \|/ | | +-- TX_BODY RX_RESPONSE---+ | +-- | | | +-- | +--+ | | +-- \|/\|/ | \|/ | +-- TX_ACK--+ RX_BODY | +-- | | | +-- | | | +-- +-----------+--------------+ +-- + --- Next State Assignment --- + case st.curr_state is + when IDLE => + if st.curr_cmd = WRITE or st.curr_cmd = WRITE_ADD then + next_state <= TX_HEADER; + elsif st.curr_cmd = READ or st.curr_cmd = READ_ADD then + next_state <= RX_HEADER; + else + next_state <= IDLE; + end if; + when TX_HEADER => + -- The header only takes one word (cycle) to transmit. + -- Continue to body or address directly afterwards. + if st.curr_cmd = WRITE_ADD then + next_state <= ADDR1; + else + next_state <= TX_BODY; + end if; + when TX_BODY => + -- Here we want to stay in TX_BODY for the duration of a packet. + if st.write_stage = 0 then + next_state <= TX_ACK; + else + next_state <= TX_BODY; + end if; + when TX_ACK => + -- Wait for write acknowledgement. + if curr_response = WRITE_ACK then + next_state <= IDLE; + else + next_state <= TX_ACK; + end if; + when RX_HEADER => + -- The header only takes one word (cycle) to transmit. + -- Continue to awaiting response directly afterwards. + if st.curr_cmd = READ_ADD then + next_state <= ADDR1; + else + next_state <= RX_RESPONSE; + end if; + when RX_RESPONSE => + -- Wait for read response. + if curr_response = READ_RESPONSE then + next_state <= RX_BODY; + else + next_state <= RX_RESPONSE; + end if; + when RX_BODY => + -- Here we want to stay in RX_BODY for the duration of a packet. + if st.read_stage = 0 then + next_state <= IDLE; + else + next_state <= RX_BODY; + end if; + when ADDR1 => + -- Transmits the entire address and returns to the appropriate + next_state <= ADDR2; + when ADDR2 => + next_state <= ADDR3; + when ADDR3 => + next_state <= ADDR4; + when ADDR4 => + if st.curr_cmd = WRITE or st.curr_cmd = WRITE_ADD then + next_state <= TX_BODY; + else + next_state <= RX_RESPONSE; + end if; + end case; + + --- Combinatorial output based on current state --- + socbridge_driver_to_ext_data_cmd := (others => '0'); + socbridge_driver_to_buffer.is_full_out <= '1'; + socbridge_driver_to_buffer.write_enable_in <= '0'; + socbridge_driver_to_buffer.payload <= (others => '0'); + case st.curr_state is + when IDLE => + if st.curr_cmd = WRITE or st.curr_cmd = WRITE_ADD then + socbridge_driver_to_ext_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 + socbridge_driver_to_ext_data_cmd := get_cmd_bits(st.curr_cmd) & get_size_bits(st.curr_cmd_size); + else + end if; + when TX_HEADER => + if st.curr_cmd = WRITE_ADD then + socbridge_driver_to_ext_data_cmd := st.curr_addr(7 downto 0); + else + socbridge_driver_to_ext_data_cmd := buffer_to_socbridge_driver.payload; + socbridge_driver_to_buffer.is_full_out <= '0'; + end if; + when TX_BODY => + if st.write_stage > 0 then + socbridge_driver_to_buffer.is_full_out <= '0'; + socbridge_driver_to_ext_data_cmd := buffer_to_socbridge_driver.payload; + else + socbridge_driver_to_ext_data_cmd := (others => '0'); + end if; + when TX_ACK => + when RX_HEADER => + if st.curr_cmd = READ_ADD then + socbridge_driver_to_ext_data_cmd := st.curr_addr(7 downto 0); + end if; + when RX_RESPONSE => + when RX_BODY => + socbridge_driver_to_buffer.payload <= st.ext_to_socbridge_driver_reg.data; + socbridge_driver_to_buffer.write_enable_in <= '1'; + when ADDR1 => + socbridge_driver_to_ext_data_cmd := st.curr_addr(15 downto 8); + when ADDR2 => + socbridge_driver_to_ext_data_cmd := st.curr_addr(23 downto 16); + when ADDR3 => + socbridge_driver_to_ext_data_cmd := st.curr_addr(31 downto 24); + when ADDR4 => + if st.curr_cmd = WRITE_ADD then + socbridge_driver_to_buffer.is_full_out <= '0'; + socbridge_driver_to_ext_data_cmd := buffer_to_socbridge_driver.payload; + report integer'image(to_integer(signed(socbridge_driver_to_ext_data_cmd))) & " "& integer'image(to_integer(signed(buffer_to_socbridge_driver.payload))); + end if; + end case; + next_parity_out <= calc_parity(socbridge_driver_to_ext_data_cmd); + --- DEBUG GLOBAL BINDINGS --- + -- synthesis translate_off + test <= socbridge_driver_to_ext_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 <= 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_state = IDLE 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 > 128 then + next_cmd_size <= 128; + elsif trans_st.curr_inst.seq_mem_access_count > 0 then + next_cmd_size <= trans_st.curr_inst.seq_mem_access_count; + else + next_cmd_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_state <= IDLE; + st.write_stage <= 0; + st.read_stage <= 0; + st.curr_cmd <= NO_OP; + st.curr_cmd_size <= 0; + st.curr_addr <= (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_state <= next_state; + case st.curr_state is + when IDLE => + st.curr_cmd <= next_cmd; + st.curr_cmd_size <= next_cmd_size; + st.curr_addr <= trans_st.curr_inst.address; + if next_cmd_size > 0 then + st.write_stage <= next_cmd_size - 1; + st.read_stage <= next_cmd_size - 1; + end if; + when TX_HEADER => + when TX_BODY => + if st.write_stage > 0 then + st.write_stage <= st.write_stage - 1; + end if; + when TX_ACK => + st.curr_cmd <= NO_OP; + st.curr_cmd_size <= 0; + when RX_HEADER => + when RX_BODY => + if st.read_stage > 0 then + st.read_stage <= st.read_stage - 1; + else + st.curr_cmd <= NO_OP; + st.curr_cmd_size <= 0; + end if; + + 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 - 128; + when AWAIT => + if trans_st.curr_inst.seq_mem_access_count <= 0 and st.curr_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; diff --git a/src/socbridge_driver_tb.gtkw b/src/socbridge/socbridge_driver_tb.gtkw similarity index 100% rename from src/socbridge_driver_tb.gtkw rename to src/socbridge/socbridge_driver_tb.gtkw diff --git a/src/socbridge_driver_tb.vhd b/src/socbridge/socbridge_driver_tb.vhd similarity index 68% rename from src/socbridge_driver_tb.vhd rename to src/socbridge/socbridge_driver_tb.vhd index ae74ab4..0471486 100644 --- a/src/socbridge_driver_tb.vhd +++ b/src/socbridge/socbridge_driver_tb.vhd @@ -2,8 +2,10 @@ library IEEE; use IEEE.std_logic_1164.all; use IEEE.MATH_REAL.all; library work; -use work.io_types.all; use work.socbridge_driver_tb_pkg.all; +library ganimede; +use ganimede.io_types.all; +library socbridge; entity socbridge_driver_tb is @@ -15,12 +17,14 @@ architecture tb of socbridge_driver_tb is signal cmd : command_t; signal address : std_logic_vector(31 downto 0); signal cmd_size : positive; - signal ext_in : ext_socbridge_in_t; - signal ext_out : ext_socbridge_out_t; - signal int_in : int_socbridge_in_t; - signal int_out : int_socbridge_out_t; - signal curr_word : std_logic_vector(ext_in.payload'length - 1 downto 0); - signal expected_out : std_logic_vector(ext_out.payload'length - 1 downto 0); + signal ext_to_socbridge_driver : ext_to_socbridge_driver_t; + signal socbridge_driver_to_ext : socbridge_driver_to_ext_t; + signal buffer_to_socbridge_driver : buffer_to_socbridge_driver_t; + signal socbridge_driver_to_buffer : socbridge_driver_to_buffer_t; + signal controller_to_socbridge_driver : controller_to_socbridge_driver_t; + signal socbridge_driver_controller : socbridge_driver_to_controller_t; + signal curr_word : std_logic_vector(ext_to_socbridge_driver.payload'length - 1 downto 0); + signal expected_out : std_logic_vector(socbridge_driver_to_ext.payload'length - 1 downto 0); constant CLK_PERIOD : TIME := 10 ns; constant SIMULATION_CYCLE_COUNT : INTEGER := 100; @@ -40,53 +44,52 @@ architecture tb of socbridge_driver_tb is end if; end procedure; - procedure check_data_out(correct_data: std_logic_vector(ext_out.payload'length - 1 downto 0)) is + procedure check_data_out(correct_data: std_logic_vector(socbridge_driver_to_ext.payload'length - 1 downto 0)) is begin - if(not (correct_data = ext_out.payload)) then - report "Data out is not what was expected, found " & to_string(ext_out.payload) + if(not (correct_data = socbridge_driver_to_ext.payload)) then + report "Data out is not what was expected, found " & to_string(socbridge_driver_to_ext.payload) & " but expected " & to_string(correct_data) severity error; fail("Data out"); end if; end procedure; - procedure check_parity(correct_data: std_logic_vector(ext_out.payload'length - 1 downto 0)) is + procedure check_parity(correct_data: std_logic_vector(socbridge_driver_to_ext.payload'length - 1 downto 0)) is begin - if(not (calc_parity(correct_data) = calc_parity(ext_out.payload))) then - report "Parity out is not what was expected, found " & std_logic'image(calc_parity(ext_out.payload)) + if(not (calc_parity(correct_data) = calc_parity(socbridge_driver_to_ext.payload))) then + report "Parity out is not what was expected, found " & std_logic'image(calc_parity(socbridge_driver_to_ext.payload)) & " but expected " & std_logic'image(calc_parity(correct_data)) severity error; fail("Parity out"); end if; end procedure; - component 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; - 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 - ); - end component socbridge_driver; +-- component 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; +-- ext_to_socbridge_driver : in ext_to_socbridge_driver_t; +-- socbridge_driver_to_ext : out socbridge_driver_to_ext_t; +-- buffer_to_socbridge_driver : out buffer_to_socbridge_driver_t; +-- socbridge_driver_to_buffer : in socbridge_driver_to_buffer_t +-- ); +-- 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, - cmd => cmd, - address => address, - cmd_size => cmd_size, - ext_in => ext_in, - ext_out => ext_out, - int_in => int_in, - int_out => int_out + controller_to_socbridge_driver => controller_to_socbridge_driver, + socbridge_driver_to_controller => socbridge_driver_controller, + ext_to_socbridge_driver => ext_to_socbridge_driver, + socbridge_driver_to_ext => socbridge_driver_to_ext, + buffer_to_socbridge_driver => buffer_to_socbridge_driver, + socbridge_driver_to_buffer => socbridge_driver_to_buffer ); - ext_in.control(1) <= clk; + ext_to_socbridge_driver.control(1) <= clk; real_clk_proc: process begin for x in 0 to SIMULATION_CYCLE_COUNT*2 loop @@ -101,17 +104,16 @@ begin begin wait for CLK_PERIOD / 2; for x in 0 to SIMULATION_CYCLE_COUNT loop - if last_clk = ext_out.control(1) then + if last_clk = socbridge_driver_to_ext.control(1) then report "Secondary side clk not correct." severity error; end if; - last_clk := ext_out.control(1); + last_clk := socbridge_driver_to_ext.control(1); wait for CLK_PERIOD; end loop; wait; end process verify_clk; verify_out_signals: process - variable curr_parity : std_logic; begin wait for CLK_PERIOD / 2; for x in 0 to SIMULATION_CYCLE_COUNT loop @@ -123,7 +125,6 @@ begin end process verify_out_signals; verify_signals : process - variable nsv: boolean; begin expected_out <= "00000000"; wait for 3 * CLK_PERIOD; @@ -188,9 +189,6 @@ begin expected_out <= "00000000"; check_next_state(RX_RESPONSE); wait for CLK_PERIOD; - wait for CLK_PERIOD / 4; - check_next_state(RX_BODY_NO_OUT); - wait for CLK_PERIOD * 3 /4; check_next_state(RX_BODY); wait for CLK_PERIOD; check_next_state(RX_BODY); @@ -218,9 +216,6 @@ begin expected_out <= "00000000"; check_next_state(RX_RESPONSE); wait for CLK_PERIOD; - wait for CLK_PERIOD / 4; - check_next_state(RX_BODY_NO_OUT); - wait for CLK_PERIOD * 3 /4; check_next_state(RX_BODY); wait for CLK_PERIOD; check_next_state(RX_BODY); @@ -259,8 +254,8 @@ begin external_stimulus_signal: process(curr_word) begin - ext_in.payload <= curr_word; - ext_in.control(0) <= calc_parity(curr_word); + ext_to_socbridge_driver.payload <= curr_word; + ext_to_socbridge_driver.control(0) <= calc_parity(curr_word); end process external_stimulus_signal; external_stimulus: process @@ -304,30 +299,30 @@ begin internal_stimulus: process begin - int_out.is_full_in <= '0'; - int_out.write_enable_out <= '0'; + buffer_to_socbridge_driver.is_full_in <= '0'; + buffer_to_socbridge_driver.write_enable_out <= '0'; wait for 3 * CLK_PERIOD; -- stimulus goes here - int_out.write_enable_out <= '1'; - int_out.payload <= "00000001"; - wait until rising_edge(clk) and int_in.is_full_out = '0'; + buffer_to_socbridge_driver.write_enable_out <= '1'; + buffer_to_socbridge_driver.payload <= "00000001"; + wait until rising_edge(clk) and socbridge_driver_to_buffer.is_full_out = '0'; wait until falling_edge(clk); - int_out.payload <= "00000010"; - wait until rising_edge(clk) and int_in.is_full_out = '0'; + buffer_to_socbridge_driver.payload <= "00000010"; + wait until rising_edge(clk) and socbridge_driver_to_buffer.is_full_out = '0'; wait until falling_edge(clk); - int_out.payload <= "00000100"; - wait until rising_edge(clk) and int_in.is_full_out = '0'; + buffer_to_socbridge_driver.payload <= "00000100"; + wait until rising_edge(clk) and socbridge_driver_to_buffer.is_full_out = '0'; wait until falling_edge(clk); - int_out.payload <= "00001000"; - wait until rising_edge(clk) and int_in.is_full_out = '0'; + buffer_to_socbridge_driver.payload <= "00001000"; + wait until rising_edge(clk) and socbridge_driver_to_buffer.is_full_out = '0'; wait until falling_edge(clk); - int_out.payload <= "00010000"; - wait until int_in.is_full_out = '0'; + buffer_to_socbridge_driver.payload <= "00010000"; + wait until socbridge_driver_to_buffer.is_full_out = '0'; wait for CLK_PERIOD/2; wait until rising_edge(clk); wait until rising_edge(clk); - int_out.payload <= "00100000"; - wait until int_in.is_full_out = '0'; + buffer_to_socbridge_driver.payload <= "00100000"; + wait until socbridge_driver_to_buffer.is_full_out = '0'; wait for CLK_PERIOD/2; wait until rising_edge(clk); wait until rising_edge(clk); --- ??? Why all these rising_edge checks? diff --git a/src/socbridge_driver_tb_pkg.vhd b/src/socbridge/socbridge_driver_tb_pkg.vhd similarity index 72% rename from src/socbridge_driver_tb_pkg.vhd rename to src/socbridge/socbridge_driver_tb_pkg.vhd index 11acdf6..fc8e8cd 100644 --- a/src/socbridge_driver_tb_pkg.vhd +++ b/src/socbridge/socbridge_driver_tb_pkg.vhd @@ -2,12 +2,12 @@ library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; use IEEE.MATH_REAL.all; -library work; -use work.io_types.all; +library ganimede; +use ganimede.io_types.all; package socbridge_driver_tb_pkg is - subtype command_size_t is integer range 1 to 128; + subtype command_size_t is integer range 0 to 128; type command_t is (NO_OP, WRITE_ADD, WRITE, READ_ADD, READ, P_ERR); @@ -18,7 +18,16 @@ package socbridge_driver_tb_pkg is type state_t is (IDLE, ADDR1, ADDR2, ADDR3, ADDR4, TX_HEADER, TX_BODY, TX_ACK, - RX_HEADER, RX_RESPONSE, RX_BODY_NO_OUT, RX_BODY); + RX_HEADER, RX_RESPONSE, RX_BODY); + + --- TRANSLATOR --- + type translator_state_t is (IDLE, SEND, SEND_ACCEPTED, AWAIT); + + type translator_state_rec_t is record + curr_inst : controller_to_socbridge_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); @@ -28,17 +37,18 @@ package socbridge_driver_tb_pkg is type state_rec_t is record curr_state: state_t; - ext_in_reg, ext_out_reg : ext_protocol_t; + ext_to_socbridge_driver_reg, socbridge_driver_to_ext_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) ) return std_logic; pure function create_io_type_out_from_ext_protocol( input: ext_protocol_t - ) return ext_socbridge_out_t; + ) return socbridge_driver_to_ext_t; function to_string ( a: std_logic_vector) return string; pure function get_cmd_bits(command : command_t) return std_logic_vector; pure function get_size_bits(size : command_size_t) return std_logic_vector; @@ -46,14 +56,15 @@ package socbridge_driver_tb_pkg is --- DEBUG GLOBAL SIGNALS --- -- synthesis translate_off signal G_next_parity_out : std_logic; - signal G_ext_in_rec : ext_protocol_t; - signal G_ext_out_data_cmd : std_logic_vector(interface_inst.socbridge.payload_width - 1 downto 0); + signal G_ext_to_socbridge_driver_rec : ext_protocol_t; + signal G_socbridge_driver_to_ext_data_cmd : std_logic_vector(interface_inst.socbridge.payload_width - 1 downto 0); signal G_next_state : state_t; signal G_curr_command : command_t; signal G_curr_command_bits : std_logic_vector(4 downto 0); signal G_curr_response : response_t; signal G_curr_response_bits : std_logic_vector(4 downto 0); signal G_st : state_rec_t; + signal G_trans_st : translator_state_rec_t; -- synthesis translate_on end package socbridge_driver_tb_pkg; @@ -81,11 +92,13 @@ package body socbridge_driver_tb_pkg is end loop; return not parity; end function; + + pure function create_io_type_out_from_ext_protocol( input : ext_protocol_t - ) return ext_socbridge_out_t is - variable val : ext_socbridge_out_t; + ) return socbridge_driver_to_ext_t is + variable val : socbridge_driver_to_ext_t; begin val.payload:= input.data; val.control(1) := input.clk; @@ -112,7 +125,23 @@ package body socbridge_driver_tb_pkg is return std_logic_vector is variable val : std_logic_vector(2 downto 0); begin - val := std_logic_vector(TO_UNSIGNED(size - 1, 3)); + if size > 2**6 then + val := "111"; + elsif size > 2**5 then + val := "110"; + elsif size > 2**4 then + val := "101"; + elsif size > 2**3 then + val := "100"; + elsif size > 2**2 then + val := "011"; + elsif size > 2**1 then + val := "010"; + elsif size > 2**0 then + val := "001"; + elsif size >= 0 then + val := "000"; + end if; return val; end function; pure function get_size_bits_sim(size: command_size_t) diff --git a/src/socbridge_driver.vhd b/src/socbridge_driver.vhd deleted file mode 100644 index 9261c85..0000000 --- a/src/socbridge_driver.vhd +++ /dev/null @@ -1,292 +0,0 @@ -library IEEE; -use IEEE.std_logic_1164.all; -use IEEE.NUMERIC_STD.all; -library work; -use work.io_types.all; -use work.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; - 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 - ); -end entity socbridge_driver; - -architecture rtl of socbridge_driver is - - signal next_parity_out : std_logic; - 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_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; -begin - --- DEBUG GLOBAL BINDINGS --- - -- synthesis translate_off - G_next_parity_out <= next_parity_out; - G_ext_in_rec <= ext_in_rec; - G_next_state <= next_state; - G_ext_out_data_cmd <=test; - G_curr_command_bits <= curr_cmd_bits; - G_curr_response <= curr_response; - G_curr_response_bits <= curr_response_bits; - G_st <= st; - -- synthesis translate_on - ext_in_rec.data <= ext_in.payload; - ext_in_rec.clk <= ext_in.control(1); - ext_in_rec.parity <= ext_in.control(0); - - -- Helpful Bindings -- - curr_response_bits <= ext_in.payload(7 downto 3); -- CANT USE EXT_IN_REC here for some reason, the assignment becomes stasteful - -- Not sure that the two process method is helping here: if this was a normal - -- signal assignment there would be no confusion. - -- in the case ... <= ext_in_rec we get - -- curr_resp | ext_in_rec | ext_in - -- 00000 | 00000000 | 00001001 - -- 00000 | 00001001 | 00001001 - -- 00001 | 00001001 | 00001001 - -- 00001 | 00001001 | 00001001 - -- - -- but in the case ... <= ext_in we get - -- curr_resp | ext_in_rec | ext_in - -- 00000 | 00000000 | 00001001 - -- 00001 | 00001001 | 00001001 - -- 00001 | 00001001 | 00001001 - -- 00001 | 00001001 | 00001001 - - with curr_response_bits select - curr_response <= WRITE_ACK when "00001", - WRITE_ACK when "00101", - READ_RESPONSE when "01000", - READ_RESPONSE when "01100", - NO_OP when others; - comb_proc: process(ext_in, int_out, curr_response, st, cmd) - begin - -- Outputs - ext_out <= create_io_type_out_from_ext_protocol(st.ext_out_reg); - - - --- State Transition Diagram --- --- --- --- --- +-----+ --- | | --- \|/ /--+ --- IDLE<-------------------+ --- / \ | --- / \ | --- / \ | --- \|/ \|/ | --- TX_HEADER RX_HEADER | --- |\ / | | --- | \ / | | --- | ADDR1 | | --- | | | | --- | \|/ | | --- | ADDR2 | | --- | | | | --- | \|/ | | --- | ADDR3 | | --- | | | | --- | \|/ | | --- | ADDR4 | | --- | /\ | | --- | / \ | | --- |-+ +----| +---+ | --- \|/ \|/ \|/ | | --- TX_BODY RX_RESPONSE---+ | --- | | | --- | +--+ | | --- \|/\|/ | \|/ | --- TX_ACK--+ RX_BODY | --- | | | --- | | | --- +-----------+--------------+ --- - --- Next State Assignment --- - case st.curr_state is - when IDLE => - if cmd = WRITE or cmd = WRITE_ADD then - next_state <= TX_HEADER; - elsif cmd = READ or cmd = READ_ADD then - next_state <= RX_HEADER; - else - next_state <= IDLE; - end if; - 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 - next_state <= ADDR1; - else - next_state <= TX_BODY; - end if; - when TX_BODY => - -- Here we want to stay in TX_BODY for the duration of a packet. - if st.write_stage = 0 then - next_state <= TX_ACK; - else - next_state <= TX_BODY; - end if; - when TX_ACK => - -- Wait for write acknowledgement. - if curr_response = WRITE_ACK then - next_state <= IDLE; - else - next_state <= TX_ACK; - end if; - 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 - next_state <= ADDR1; - else - next_state <= RX_RESPONSE; - end if; - when RX_RESPONSE => - -- Wait for read response. - if curr_response = READ_RESPONSE then - next_state <= RX_BODY_NO_OUT; - else - next_state <= RX_RESPONSE; - end if; - when RX_BODY_NO_OUT => - next_state <= RX_BODY; - when RX_BODY => - -- Here we want to stay in RX_BODY for the duration of a packet. - if st.read_stage = 0 then - next_state <= IDLE; - else - next_state <= RX_BODY; - end if; - when ADDR1 => - -- Transmits the entire address and returns to the appropriate - next_state <= ADDR2; - when ADDR2 => - next_state <= ADDR3; - when ADDR3 => - next_state <= ADDR4; - when ADDR4 => - if st.cmd_reg = WRITE or st.cmd_reg = WRITE_ADD then - next_state <= TX_BODY; - else - next_state <= RX_RESPONSE; - end if; - end case; - - --- 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'); - 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); - end if; - when TX_HEADER => - if st.cmd_reg = WRITE_ADD then - ext_out_data_cmd := st.addr_reg(7 downto 0); - else - ext_out_data_cmd := int_out.payload; - int_in.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; - 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); - 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'; - when ADDR1 => - ext_out_data_cmd := st.addr_reg(15 downto 8); - when ADDR2 => - ext_out_data_cmd := st.addr_reg(23 downto 16); - when ADDR3 => - ext_out_data_cmd := st.addr_reg(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; - end if; - end case; - next_parity_out <= calc_parity(ext_out_data_cmd); - --- DEBUG GLOBAL BINDINGS --- - -- synthesis translate_off - test <= ext_out_data_cmd; - -- synthesis translate_on - end process comb_proc; - -- Process updating internal registers based on primary clock - seq_proc: process(ext_in_rec.clk, rst) - begin - if(rst = '1') then - st.ext_in_reg.data <= (others => '0'); - st.ext_out_reg.data <= (others => '0'); - st.ext_out_reg.clk <= '0'; - st.ext_out_reg.parity <= '1'; - st.curr_state <= IDLE; - st.write_stage <= 0; - st.read_stage <= 0; - st.cmd_reg <= NO_OP; - st.addr_reg <= (others => '0'); - - elsif(rising_edge(ext_in_rec.clk)) then - st.ext_in_reg.data <= ext_in_rec.data; - st.ext_in_reg.clk <= ext_in_rec.clk; - st.ext_in_reg.parity <= ext_in_rec.parity; - st.ext_out_reg.data <= ext_out_data_cmd; - st.ext_out_reg.clk <= not st.ext_out_reg.clk; - st.ext_out_reg.parity <= next_parity_out; - 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; - when TX_HEADER => - st.write_stage <= 2**(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; - when RX_BODY => - if st.read_stage > 0 then - st.read_stage <= st.read_stage - 1; - end if; - when others => - end case; - end if; - - end process seq_proc; - - - -end architecture rtl; diff --git a/src/test.vhd b/src/test.vhd deleted file mode 100644 index 5a27d24..0000000 --- a/src/test.vhd +++ /dev/null @@ -1,27 +0,0 @@ -library IEEE; -library work; -use work.io_types.all; - -entity test is - port ( - ext_interface_in : in ext_interface_in_t; - ext_interface_out : out ext_interface_out_t - ); -end entity test; - -architecture rtl of test is - signal int_interface_in : int_interface_in_t; - signal int_interface_out : int_interface_out_t; -begin - - proc_name: process - begin - - report "Hello"; - report integer'image(ext_interface_in.socbridge.payload'length); - report integer'image(ext_interface_in.spi.payload'length); - wait; - end process proc_name; - - -end architecture rtl; diff --git a/src/vhdl_ls.toml b/src/vhdl_ls.toml new file mode 100644 index 0000000..3a01a68 --- /dev/null +++ b/src/vhdl_ls.toml @@ -0,0 +1,18 @@ +# What standard to use. This is optional and defaults to VHDL2008. +standard = "1993" +# File names are either absolute or relative to the parent folder of the vhdl_ls.toml file +[libraries] +ganimede.files = [ + 'ganimede/io_type_pkg.vhd' +] +socbridge.files = [ + 'socbridge/*.vhd' +] + +controller.files = [ + 'controller/*.vhd', +] + +[lint] +unused = 'error' # Upgrade the 'unused' diagnostic to the 'error' severity +unnecessary_work_library = false # Disable linting for the 'library work;' statement