diff --git a/src/socbridge_driver.vhd b/src/socbridge_driver.vhd index 2334bb3..b4888fa 100644 --- a/src/socbridge_driver.vhd +++ b/src/socbridge_driver.vhd @@ -16,16 +16,27 @@ entity socbridge_driver is end entity socbridge_driver; architecture rtl of socbridge_driver is + pure 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 1 to d'length - 1 loop + parity := parity xor d(x); + end loop; + return not parity; + end function; signal ext_d_in, ext_d_out,ext_d_in_reg, ext_d_out_reg : std_logic_vector(interface_inst.socbridge.payload_width - 1 downto 0); - signal ext_clk_in, ext_clk_out, ext_parity_in, ext_parity_out : std_logic; + signal ext_clk_in, ext_clk_out, ext_parity_in, ext_parity_out, ext_next_parity_out : std_logic; type command_t is - (IDLE, WRITE_ADD, WRITE, READ_ADD, READ, P_ERR); + (NO_OP, WRITE_ADD, WRITE, READ_ADD, READ, P_ERR); type response_t is - (WRITE_ACK, READ_RESPONSE, UNKNOWN); + (NO_OP, WRITE_ACK, READ_RESPONSE); type state_t is (RESET, IDLE, TX_HEADER, TX_BODY, TX_ACK, RX_HEADER, RX_RESPONSE, RX_BODY); @@ -34,41 +45,70 @@ architecture rtl of socbridge_driver is signal curr_command : command_t; signal curr_command_bits : std_logic_vector(4 downto 0); signal curr_respoonse : response_t; - + signal curr_response_bits : std_logic_vector(4 downto 0); begin - ext_out.payload <= ext_d_out_reg; - ext_out.control <= ext_clk_out & ext_parity_out; - ext_d_in <= ext_in.payload; - ext_parity_in <= ext_out.control(0); - ext_clk_in <= ext_out.control(1); + comb_proc: process(ext_in, int_out, ext_d_out_reg, ext_clk_out, ext_parity_out, curr_state) + begin + ext_next_parity_out <= calc_parity(int_out.payload); + ext_out.payload <= ext_d_out_reg; + ext_out.control <= ext_clk_out & ext_parity_out; + ext_d_in <= ext_in.payload; + ext_parity_in <= ext_in.control(0); + ext_clk_in <= ext_in.control(1); + curr_response_bits <= ext_d_in(7 downto 3); + -- Create combinational bindings for command/response types + with curr_command select + curr_command_bits <= "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; + with curr_response_bits select + curr_respoonse <= WRITE_ACK when "00001", + WRITE_ACK when "00101", + READ_RESPONSE when "01000", + READ_RESPONSE when "01100", + NO_OP when others; + + case curr_state is + when IDLE => + if curr_command = WRITE or curr_command = WRITE_ADD then + next_state <= TX_HEADER; + elsif curr_command = READ or curr_command = READ_ADD then + next_state <= RX_HEADER; + else + next_state <= IDLE; + end if; + when RESET => + when TX_HEADER => + when TX_BODY => + when TX_ACK => + when RX_HEADER => + when RX_RESPONSE => + when RX_BODY => + end case; - -- Create combinational bindings for command/response types - with curr_command select - curr_command_bits <= "00000" when IDLE, - "10000" when WRITE_ADD, - "10100" when WRITE, - "11000" when READ_ADD, - "11100" when READ, - "01001" when P_ERR, - "11111" when others; - with ext_d_in(7 downto 3) select - curr_respoonse <= WRITE_ACK when "00001" or "00101", - READ_RESPONSE when "01000" or "01100", - UNKNOWN when others; - - + end process comb_proc; -- Process updating internal registers based on primary clock - reg_proc: process(ext_clk_in, rst) + seq_proc: process(ext_clk_in, rst) begin if(rst = '1') then - ext_clk_out <= '0'; ext_d_in_reg <= (others => '0'); + ext_d_out_reg <= (others => '0'); + ext_clk_out <= '0'; + ext_parity_out <= '1'; + curr_state <= IDLE; elsif(rising_edge(ext_clk_in)) then ext_clk_out <= not ext_clk_out; ext_d_in_reg <= ext_d_in; + ext_d_out_reg <= int_out.payload; + ext_parity_out <= ext_next_parity_out; + curr_state <= next_state; end if; - end process reg_proc; + end process seq_proc; diff --git a/src/socbridge_driver_tb.vhd b/src/socbridge_driver_tb.vhd new file mode 100644 index 0000000..239400d --- /dev/null +++ b/src/socbridge_driver_tb.vhd @@ -0,0 +1,137 @@ +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.MATH_REAL.all; +library work; +use work.io_types.all; + + +entity socbridge_driver_tb is +end entity socbridge_driver_tb; + +architecture tb of socbridge_driver_tb is + pure 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 1 to d'length - 1 loop + parity := parity xor d(x); + end loop; + return not parity; + end function; + + + component socbridge_driver is + port( + clk : in std_logic; + rst : 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 + ); + end component socbridge_driver; + signal clk : std_logic := '0'; + signal rst : std_logic := '0'; + 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); + + constant CLK_PERIOD : TIME := 10 ns; + constant SIMULATION_CYCLE_COUNT : INTEGER := 100; + +begin + + + socbridge_driver_inst: entity work.socbridge_driver + port map( + clk => clk, + rst => rst, + ext_in => ext_in, + ext_out => ext_out, + int_in => int_in, + int_out => int_out + ); + + real_clk_proc: process + begin + clk <= '0'; + for x in 0 to SIMULATION_CYCLE_COUNT*2 loop + clk <= not clk; + ext_in.control(1) <= 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 warning; + end if; + last_clk := ext_out.control(1); + wait for CLK_PERIOD; + end loop; + wait; + end process verify_clk; + + verify_parity: process + variable curr_parity : std_logic; + begin + for x in 0 to SIMULATION_CYCLE_COUNT * 2 loop + curr_parity := calc_parity(ext_out.payload); + if not (curr_parity = ext_out.control(0)) then + report "Secondary side parity not correct" severity warning; + end if; + wait for CLK_PERIOD / 2; + end loop; + wait; + end process verify_parity; + + 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 <= '1'; + wait for 3 * CLK_PERIOD; + rst <= '0'; + curr_word <= "00000000"; + wait for CLK_PERIOD*10; + wait; + end process external_stimulus; + + + internal_stimulus: process + begin + wait for 3 * CLK_PERIOD; + wait for CLK_PERIOD / 2; + int_out.payload <= "00000000"; + wait for CLK_PERIOD; + int_out.payload <= "00000001"; + wait for CLK_PERIOD; + int_out.payload <= "00000011"; + wait for CLK_PERIOD; + int_out.payload <= "00000111"; + wait for CLK_PERIOD; + int_out.payload <= "00001111"; + wait for CLK_PERIOD; + int_out.payload <= "00011111"; + wait for CLK_PERIOD; + int_out.payload <= "00111111"; + wait for CLK_PERIOD; + wait; + end process internal_stimulus; + +end architecture tb ;