diff --git a/src/socbridge_driver.vhd b/src/socbridge_driver.vhd new file mode 100644 index 0000000..9261c85 --- /dev/null +++ b/src/socbridge_driver.vhd @@ -0,0 +1,292 @@ +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/socbridge_driver_tb.gtkw b/src/socbridge_driver_tb.gtkw new file mode 100644 index 0000000..4b32853 --- /dev/null +++ b/src/socbridge_driver_tb.gtkw @@ -0,0 +1,77 @@ +[*] +[*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI +[*] Thu Feb 27 10:27:13 2025 +[*] +[dumpfile] "/home/thesis1/repos/exjobb-public/src/wave/socbridge_driver_tb-tb.ghw" +[dumpfile_mtime] "Thu Feb 27 10:26:19 2025" +[dumpfile_size] 2417 +[savefile] "/home/thesis1/repos/exjobb-public/src/socbridge_driver_tb.gtkw" +[timestart] 21800000 +[size] 956 1033 +[pos] -1 -1 +*-24.456779 22000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[treeopen] top. +[treeopen] top.socbridge_driver_tb. +[treeopen] top.socbridge_driver_tb_pkg. +[treeopen] top.socbridge_driver_tb_pkg.g_st. +[sst_width] 273 +[signals_width] 214 +[sst_expanded] 1 +[sst_vpaned_height] 324 +@800200 +-Outwards +-Internal +@28 +top.socbridge_driver_tb.int_out.is_full_in +@22 +#{top.socbridge_driver_tb.int_out.payload[7:0]} top.socbridge_driver_tb.int_out.payload[7] top.socbridge_driver_tb.int_out.payload[6] top.socbridge_driver_tb.int_out.payload[5] top.socbridge_driver_tb.int_out.payload[4] top.socbridge_driver_tb.int_out.payload[3] top.socbridge_driver_tb.int_out.payload[2] top.socbridge_driver_tb.int_out.payload[1] top.socbridge_driver_tb.int_out.payload[0] +@28 +top.socbridge_driver_tb.int_out.write_enable_out +@1000200 +-Internal +@800200 +-External +@28 ++{clk} top.socbridge_driver_tb.ext_out.control[1] ++{parity} top.socbridge_driver_tb.ext_out.control[0] ++{next_parity} top.socbridge_driver_tb_pkg.g_next_parity_out +@22 +#{top.socbridge_driver_tb.ext_out.payload[7:0]} top.socbridge_driver_tb.ext_out.payload[7] top.socbridge_driver_tb.ext_out.payload[6] top.socbridge_driver_tb.ext_out.payload[5] top.socbridge_driver_tb.ext_out.payload[4] top.socbridge_driver_tb.ext_out.payload[3] top.socbridge_driver_tb.ext_out.payload[2] top.socbridge_driver_tb.ext_out.payload[1] top.socbridge_driver_tb.ext_out.payload[0] ++{next_payload[7:0]} #{top.socbridge_driver_tb_pkg.g_ext_out_data_cmd[7:0]} top.socbridge_driver_tb_pkg.g_ext_out_data_cmd[7] top.socbridge_driver_tb_pkg.g_ext_out_data_cmd[6] top.socbridge_driver_tb_pkg.g_ext_out_data_cmd[5] top.socbridge_driver_tb_pkg.g_ext_out_data_cmd[4] top.socbridge_driver_tb_pkg.g_ext_out_data_cmd[3] top.socbridge_driver_tb_pkg.g_ext_out_data_cmd[2] top.socbridge_driver_tb_pkg.g_ext_out_data_cmd[1] top.socbridge_driver_tb_pkg.g_ext_out_data_cmd[0] +@1000200 +-External +-Outwards +@800200 +-Inwards +-Internal +@28 +top.socbridge_driver_tb.int_in.is_full_out +@22 +#{top.socbridge_driver_tb.int_in.payload[7:0]} top.socbridge_driver_tb.int_in.payload[7] top.socbridge_driver_tb.int_in.payload[6] top.socbridge_driver_tb.int_in.payload[5] top.socbridge_driver_tb.int_in.payload[4] top.socbridge_driver_tb.int_in.payload[3] top.socbridge_driver_tb.int_in.payload[2] top.socbridge_driver_tb.int_in.payload[1] top.socbridge_driver_tb.int_in.payload[0] +@28 +top.socbridge_driver_tb.int_in.write_enable_in +@1000200 +-Internal +@800200 +-External +@28 ++{clk} top.socbridge_driver_tb.ext_in.control[1] ++{parity} top.socbridge_driver_tb.ext_in.control[0] +@22 +#{top.socbridge_driver_tb.ext_in.payload[7:0]} top.socbridge_driver_tb.ext_in.payload[7] top.socbridge_driver_tb.ext_in.payload[6] top.socbridge_driver_tb.ext_in.payload[5] top.socbridge_driver_tb.ext_in.payload[4] top.socbridge_driver_tb.ext_in.payload[3] top.socbridge_driver_tb.ext_in.payload[2] top.socbridge_driver_tb.ext_in.payload[1] top.socbridge_driver_tb.ext_in.payload[0] +@1000200 +-External +-Inwards +@800200 +-Internal Signals +@420 +top.socbridge_driver_tb_pkg.g_st.curr_state ++{next_state} top.socbridge_driver_tb_pkg.g_next_state +top.socbridge_driver_tb_pkg.g_curr_command +top.socbridge_driver_tb_pkg.g_curr_respoonse +@1000200 +-Internal Signals +@420 +top.socbridge_driver_tb.cmd +[pattern_trace] 1 +[pattern_trace] 0 diff --git a/src/socbridge_driver_tb.vhd b/src/socbridge_driver_tb.vhd new file mode 100644 index 0000000..ae74ab4 --- /dev/null +++ b/src/socbridge_driver_tb.vhd @@ -0,0 +1,337 @@ +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; + + +entity socbridge_driver_tb is +end entity socbridge_driver_tb; + +architecture tb of socbridge_driver_tb is + signal clk : std_logic := '0'; + signal rst : std_logic; + 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); + + constant CLK_PERIOD : TIME := 10 ns; + constant SIMULATION_CYCLE_COUNT : INTEGER := 100; + + 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(ext_out.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) + & " 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 + 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)) + & " 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; + +begin + socbridge_driver_inst: entity work.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 + ); + + ext_in.control(1) <= clk; + real_clk_proc: process + begin + for x in 0 to SIMULATION_CYCLE_COUNT*2 loop + clk <= not clk; + wait for CLK_PERIOD / 2; + end loop; + wait; + end process real_clk_proc; + + verify_clk: process + variable last_clk : std_logic; + begin + wait for CLK_PERIOD / 2; + for x in 0 to SIMULATION_CYCLE_COUNT loop + if last_clk = ext_out.control(1) then + report "Secondary side clk not correct." severity error; + end if; + last_clk := ext_out.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 + check_data_out(expected_out); + check_parity(expected_out); + wait for CLK_PERIOD; + end loop; + wait; + end process verify_out_signals; + + verify_signals : process + variable nsv: boolean; + begin + expected_out <= "00000000"; + wait for 3 * CLK_PERIOD; + wait for CLK_PERIOD / 3; + expected_out <= "00000000"; + check_next_state(IDLE); + wait for CLK_PERIOD /4; + check_next_state(TX_HEADER); + wait for CLK_PERIOD * 3 / 4; + expected_out <= get_cmd_bits(WRITE) & get_size_bits_sim(2); + check_next_state(TX_BODY); + wait for CLK_PERIOD; + expected_out <= "00000001"; + check_next_state(TX_BODY); + wait for CLK_PERIOD; + expected_out <= "00000010"; + check_next_state(TX_ACK); + wait for CLK_PERIOD; + expected_out <= "00000000"; + check_next_state(TX_ACK); + wait for CLK_PERIOD; + check_next_state(IDLE); + wait for CLK_PERIOD * 6; + expected_out <= "00000000"; + check_next_state(IDLE); + wait for CLK_PERIOD /4; + check_next_state(TX_HEADER); + wait for CLK_PERIOD * 3 / 4; + expected_out <= get_cmd_bits(WRITE_ADD) & get_size_bits(2); + check_next_state(ADDR1); + wait for CLK_PERIOD; + expected_out <= x"FA"; + check_next_state(ADDR2); + wait for CLK_PERIOD; + expected_out <= x"A0"; + check_next_state(ADDR3); + wait for CLK_PERIOD; + expected_out <= x"0F"; + check_next_state(ADDR4); + wait for CLK_PERIOD; + expected_out <= x"FA"; + check_next_state(TX_BODY); + wait for CLK_PERIOD; + expected_out <= "00000100"; + check_next_state(TX_BODY); + wait for CLK_PERIOD; + expected_out <= "00001000"; + check_next_state(TX_ACK); + wait for CLK_PERIOD; + expected_out <= "00000000"; + check_next_state(TX_ACK); + wait for CLK_PERIOD; + expected_out <= "00000000"; + check_next_state(IDLE); + wait for CLK_PERIOD * 2; + wait for CLK_PERIOD /4; + check_next_state(RX_HEADER); + wait for CLK_PERIOD * 3 / 4; + expected_out <= get_cmd_bits(READ) & get_size_bits(2); + check_next_state(RX_RESPONSE); + wait for CLK_PERIOD; + 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); + wait for CLK_PERIOD; + check_next_state(IDLE); + wait for CLK_PERIOD * 5; + wait for CLK_PERIOD /4; + check_next_state(RX_HEADER); + wait for CLK_PERIOD * 3 / 4; + expected_out <= get_cmd_bits(READ_ADD) & get_size_bits(2); + check_next_state(ADDR1); + wait for CLK_PERIOD; + expected_out <= x"FA"; + check_next_state(ADDR2); + wait for CLK_PERIOD; + expected_out <= x"A0"; + check_next_state(ADDR3); + wait for CLK_PERIOD; + expected_out <= x"0F"; + check_next_state(ADDR4); + wait for CLK_PERIOD; + expected_out <= x"FA"; + check_next_state(RX_RESPONSE); + wait for CLK_PERIOD; + 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); + wait for CLK_PERIOD; + check_next_state(IDLE); + wait; + end process verify_signals; + + command_stimulus: process + begin + cmd <= NO_OP; + cmd_size <= 2; + wait for 3*CLK_PERIOD; + wait for CLK_PERIOD / 2; + cmd <= WRITE; + wait for CLK_PERIOD; + cmd <= NO_OP; + wait for CLK_PERIOD * 10; + cmd <= WRITE_ADD; + address <= x"FA0FA0FA"; + wait for CLK_PERIOD; + cmd <= NO_OP; + address <= (others => '0'); + wait for CLK_PERIOD * 10; + cmd <= READ; + wait for CLK_PERIOD; + cmd <= NO_OP; + wait for CLK_PERIOD * 10; + cmd <= READ_ADD; + address <= x"FA0FA0FA"; + wait for CLK_PERIOD; + cmd <= NO_OP; + address <= (others => '0'); + wait; + end process command_stimulus; + + external_stimulus_signal: process(curr_word) + begin + ext_in.payload <= curr_word; + ext_in.control(0) <= calc_parity(curr_word); + end process external_stimulus_signal; + + external_stimulus: process + begin + rst <= '0'; + wait for CLK_PERIOD / 1000; + rst <= '1'; + curr_word <= "00000000"; + wait for 999 * CLK_PERIOD / 1000; + wait for 2 * CLK_PERIOD; + rst <= '0'; + wait for CLK_PERIOD / 2; + wait for 4* CLK_PERIOD; + curr_word <= "00001001"; + wait for CLK_PERIOD; + curr_word <= "00000000"; + wait for CLK_PERIOD * 14; + curr_word <= "00101001"; + wait for CLK_PERIOD; + curr_word <= "00000000"; + wait for CLK_PERIOD*5; + curr_word <= "01000001"; + wait for CLK_PERIOD; + curr_word <= "10000000"; + wait for CLK_PERIOD; + curr_word <= "01000000"; + wait for CLK_PERIOD; + curr_word <= "00000000"; + wait for CLK_PERIOD*12; + curr_word <= "01100001"; + wait for CLK_PERIOD; + curr_word <= "00100000"; + wait for CLK_PERIOD; + curr_word <= "00010000"; + wait for CLK_PERIOD; + curr_word <= "00000000"; + + + wait; + end process external_stimulus; + + internal_stimulus: process + begin + int_out.is_full_in <= '0'; + int_out.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'; + wait until falling_edge(clk); + int_out.payload <= "00000010"; + wait until rising_edge(clk) and int_in.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'; + wait until falling_edge(clk); + int_out.payload <= "00001000"; + wait until rising_edge(clk) and int_in.is_full_out = '0'; + wait until falling_edge(clk); + int_out.payload <= "00010000"; + wait until int_in.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'; + wait for CLK_PERIOD/2; + wait until rising_edge(clk); + wait until rising_edge(clk); --- ??? Why all these rising_edge checks? + wait; + end process internal_stimulus; + +end architecture tb ; diff --git a/src/socbridge_driver_tb_pkg.vhd b/src/socbridge_driver_tb_pkg.vhd new file mode 100644 index 0000000..11acdf6 --- /dev/null +++ b/src/socbridge_driver_tb_pkg.vhd @@ -0,0 +1,127 @@ +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; + + +package socbridge_driver_tb_pkg is + subtype command_size_t is integer range 1 to 128; + + type command_t is + (NO_OP, WRITE_ADD, WRITE, READ_ADD, READ, P_ERR); + + type response_t is + (NO_OP, WRITE_ACK, READ_RESPONSE); + + 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); + + type ext_protocol_t is record + data : std_logic_vector(interface_inst.socbridge.payload_width - 1 downto 0); + clk : std_logic; + parity : std_logic; + end record ext_protocol_t; + + type state_rec_t is record + 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); + 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; + 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; + pure function get_size_bits_sim(size : command_size_t) return std_logic_vector; + --- 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_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; + -- synthesis translate_on + +end package socbridge_driver_tb_pkg; + +package body socbridge_driver_tb_pkg is + function to_string ( a: std_logic_vector) return string is + variable b : string (1 to a'length) := (others => NUL); + variable stri : integer := 1; + begin + for i in a'range loop + b(stri) := std_logic'image(a((i)))(2); + stri := stri+1; + end loop; + return b; + end function; + + impure function calc_parity( + d : STD_LOGIC_VECTOR(interface_inst.socbridge.payload_width - 1 downto 0) + ) return std_logic is + variable parity : std_logic; + begin + parity := d(0); + for x in integer'(1) to d'length - 1 loop + parity := parity xor d(x); + 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; + begin + val.payload:= input.data; + val.control(1) := input.clk; + val.control(0) := input.parity; + return val; + end function; + pure function get_cmd_bits(command : command_t) + return std_logic_vector is + variable val : std_logic_vector(4 downto 0); + begin + with command select + val := "00000" when NO_OP, + "10000" when WRITE_ADD, + "10100" when WRITE, + "11000" when READ_ADD, + "11100" when READ, + "01001" when P_ERR, + "11111" when others; + return val; + end function; + + + pure function get_size_bits(size: command_size_t) + return std_logic_vector is + variable val : std_logic_vector(2 downto 0); + begin + val := std_logic_vector(TO_UNSIGNED(size - 1, 3)); + return val; + end function; + pure function get_size_bits_sim(size: command_size_t) + return std_logic_vector is + variable pow : integer; + variable val : std_logic_vector(2 downto 0); + begin + pow := integer(CEIL(sqrt(Real(size)))); + val := std_logic_vector(TO_UNSIGNED(size - 1, 3)); + return val; + end function; +end package body socbridge_driver_tb_pkg;