From 34326b4c5626ea36e550505f258a455a75c75982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Thu, 20 Feb 2025 14:24:58 +0100 Subject: [PATCH 01/13] added initial driver file --- src/socbridge_driver.vhd | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/socbridge_driver.vhd diff --git a/src/socbridge_driver.vhd b/src/socbridge_driver.vhd new file mode 100644 index 0000000..160db9e --- /dev/null +++ b/src/socbridge_driver.vhd @@ -0,0 +1,24 @@ +library IEEE; +use IEEE.std_logic_1164.all; +library work; +use work.io_types.all; + + +entity socbridge_driver 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 + ); +end entity socbridge_driver; + +architecture rtl of socbridge_driver is + + +begin + ext_out <= (payload => (others => '0'), control => (others => '0')); + int_in <= (payload => (others => '0'), write_enable_in => '0', is_full_out =>'0'); +end architecture rtl; -- 2.43.0 From bd75d79bb35420bb4ec7c24ba08d4909e8b08c3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Thu, 20 Feb 2025 16:23:00 +0100 Subject: [PATCH 02/13] inital work on the example socbridge driver --- src/socbridge_driver.vhd | 57 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/src/socbridge_driver.vhd b/src/socbridge_driver.vhd index 160db9e..2334bb3 100644 --- a/src/socbridge_driver.vhd +++ b/src/socbridge_driver.vhd @@ -7,7 +7,7 @@ use work.io_types.all; entity socbridge_driver is port( clk : in std_logic; - reset : 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; @@ -17,8 +17,59 @@ end entity socbridge_driver; architecture rtl of socbridge_driver is + 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; + + + type command_t is + (IDLE, WRITE_ADD, WRITE, READ_ADD, READ, P_ERR); + + type response_t is + (WRITE_ACK, READ_RESPONSE, UNKNOWN); + + type state_t is + (RESET, IDLE, TX_HEADER, TX_BODY, TX_ACK, RX_HEADER, RX_RESPONSE, RX_BODY); + + signal curr_state, next_state : state_t; + signal curr_command : command_t; + signal curr_command_bits : std_logic_vector(4 downto 0); + signal curr_respoonse : response_t; begin - ext_out <= (payload => (others => '0'), control => (others => '0')); - int_in <= (payload => (others => '0'), write_enable_in => '0', is_full_out =>'0'); + 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); + + -- 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; + + + -- Process updating internal registers based on primary clock + reg_proc: process(ext_clk_in, rst) + begin + if(rst = '1') then + ext_clk_out <= '0'; + ext_d_in_reg <= (others => '0'); + + elsif(rising_edge(ext_clk_in)) then + ext_clk_out <= not ext_clk_out; + ext_d_in_reg <= ext_d_in; + end if; + end process reg_proc; + + + end architecture rtl; -- 2.43.0 From 9d56b875fd60d2ae586c365f69adab8ab32015a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Mon, 24 Feb 2025 17:11:25 +0100 Subject: [PATCH 03/13] made socbridge driver testbench and continued development on the driver --- src/socbridge_driver.vhd | 94 ++++++++++++++++++------- src/socbridge_driver_tb.vhd | 137 ++++++++++++++++++++++++++++++++++++ 2 files changed, 204 insertions(+), 27 deletions(-) create mode 100644 src/socbridge_driver_tb.vhd 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 ; -- 2.43.0 From e2035f9daf0cf9793f2140a5af72d24253aa038a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Tue, 25 Feb 2025 14:26:11 +0100 Subject: [PATCH 04/13] added next_state concurrent assignment --- src/socbridge_driver.vhd | 50 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/socbridge_driver.vhd b/src/socbridge_driver.vhd index b4888fa..e9fcb6a 100644 --- a/src/socbridge_driver.vhd +++ b/src/socbridge_driver.vhd @@ -72,6 +72,31 @@ begin READ_RESPONSE when "01100", NO_OP when others; + --- State Transition Diagram --- +-- +-- +-----+ +-- \|/ | +-- RESET --+ +-- | +-- | +-- IDLE<-------------------+ +-- / \ | +-- / \ | +-- / \ | +-- \|/ \|/ | +-- TX_HEADER RX_HEADER | +-- | | | +-- | | ----+ | +-- \|/ \|/ \|/ | | +-- TX_BODY RX_RESPONSE---+ | +-- | | | +-- | +--+ | | +-- \|/\|/ | \|/ | +-- TX_ACK--+ RX_BODY | +-- | | | +-- | | | +-- +-----------+--------------+ +-- case curr_state is when IDLE => if curr_command = WRITE or curr_command = WRITE_ADD then @@ -82,12 +107,37 @@ begin next_state <= IDLE; end if; when RESET => + next_state <= IDLE; when TX_HEADER => + -- The header only takes one word (cycle) to transmit. + -- Continue to body directly afterwards. + next_state <= TX_BODY; when TX_BODY => + -- Here we want to stay in TX_BODY for the duration of a packet. + -- Right now, we transfer one single word at a time for simplicity + next_state <= TX_ACK; when TX_ACK => + -- Wait for write acknowledgement. + if curr_respoonse = 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. + next_state <= RX_RESPONSE; when RX_RESPONSE => + -- Wait for read response. + if curr_respoonse = 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. + -- Right now, we receive only one single word at a time for simplicity + next_state <= IDLE; end case; end process comb_proc; -- 2.43.0 From 63166587b679aeee1b499f13ec2b9f1d0f2a77e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Tue, 25 Feb 2025 16:17:34 +0100 Subject: [PATCH 05/13] cleaned up the code in accordance with the two process method --- src/socbridge_driver.vhd | 101 ++++++++++++++++++++++++++------------- 1 file changed, 69 insertions(+), 32 deletions(-) diff --git a/src/socbridge_driver.vhd b/src/socbridge_driver.vhd index e9fcb6a..c92981c 100644 --- a/src/socbridge_driver.vhd +++ b/src/socbridge_driver.vhd @@ -16,6 +16,26 @@ entity socbridge_driver is end entity socbridge_driver; architecture rtl of socbridge_driver is + 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 + (RESET, IDLE, TX_HEADER, TX_BODY, TX_ACK, RX_HEADER, RX_RESPONSE, 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; + end record state_rec_t; + pure function calc_parity( d : STD_LOGIC_VECTOR(interface_inst.socbridge.payload_width - 1 downto 0) ) return std_logic is @@ -28,34 +48,48 @@ architecture rtl of socbridge_driver is 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, ext_next_parity_out : std_logic; + pure function create_ext_protocol_from_io_type_in( + input : ext_socbridge_in_t + ) return ext_protocol_t is + variable val : ext_protocol_t; + begin + val.data := input.payload; + val.clk := input.control(1); + val.parity := input.control(0); + return val; + 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; + + signal next_parity_out : std_logic; - 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 - (RESET, IDLE, TX_HEADER, TX_BODY, TX_ACK, RX_HEADER, RX_RESPONSE, RX_BODY); - - signal curr_state, next_state : state_t; + signal ext_in_rec : ext_protocol_t; + signal ext_out_rec : ext_protocol_t; + signal next_state : state_t; 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); + signal st : state_rec_t; begin - comb_proc: process(ext_in, int_out, ext_d_out_reg, ext_clk_out, ext_parity_out, curr_state) + comb_proc: process(ext_in, int_out, st) 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); + ext_in_rec <= create_ext_protocol_from_io_type_in(ext_in); + ext_out <= create_io_type_out_from_ext_protocol(ext_out_rec); + next_parity_out <= calc_parity(int_out.payload); + ext_out.payload <= st.ext_out_reg.data; + ext_out.control <= st.ext_out_reg.clk & st.ext_out_reg.parity; + curr_response_bits <= ext_in_rec.data(7 downto 3); -- Create combinational bindings for command/response types with curr_command select curr_command_bits <= "00000" when NO_OP, @@ -97,7 +131,8 @@ begin -- | | | -- +-----------+--------------+ -- - case curr_state is +--- Next State Assignment --- + case st.curr_state is when IDLE => if curr_command = WRITE or curr_command = WRITE_ADD then next_state <= TX_HEADER; @@ -142,21 +177,23 @@ begin end process comb_proc; -- Process updating internal registers based on primary clock - seq_proc: process(ext_clk_in, rst) + seq_proc: process(ext_in_rec.clk, rst) begin if(rst = '1') then - ext_d_in_reg <= (others => '0'); - ext_d_out_reg <= (others => '0'); - ext_clk_out <= '0'; - ext_parity_out <= '1'; - curr_state <= IDLE; + 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; - 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; + 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 <= int_out.payload; + st.ext_out_reg.clk <= not st.ext_out_reg.clk; + st.ext_out_reg.parity <= next_parity_out; + st.curr_state <= next_state; end if; end process seq_proc; -- 2.43.0 From 8f72602cc27fe076db664ec117c8bc443e1cba7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Tue, 25 Feb 2025 17:08:20 +0100 Subject: [PATCH 06/13] begun work on output logic based on state --- src/socbridge_driver.vhd | 38 +++++++++++++++++++++++++++++-------- src/socbridge_driver_tb.vhd | 38 +++++++++++++++++++------------------ 2 files changed, 50 insertions(+), 26 deletions(-) diff --git a/src/socbridge_driver.vhd b/src/socbridge_driver.vhd index c92981c..f0b9b77 100644 --- a/src/socbridge_driver.vhd +++ b/src/socbridge_driver.vhd @@ -74,7 +74,7 @@ architecture rtl of socbridge_driver is signal ext_in_rec : ext_protocol_t; - signal ext_out_rec : ext_protocol_t; + signal ext_out_data_cmd : std_logic_vector(interface_inst.socbridge.payload_width - 1 downto 0); signal next_state : state_t; signal curr_command : command_t; signal curr_command_bits : std_logic_vector(4 downto 0); @@ -84,13 +84,14 @@ architecture rtl of socbridge_driver is begin comb_proc: process(ext_in, int_out, st) begin + -- Outputs + ext_out <= create_io_type_out_from_ext_protocol(st.ext_out_reg); + int_in.payload <= st.ext_in_reg.data; + + -- Helpful Bindings -- ext_in_rec <= create_ext_protocol_from_io_type_in(ext_in); - ext_out <= create_io_type_out_from_ext_protocol(ext_out_rec); - next_parity_out <= calc_parity(int_out.payload); - ext_out.payload <= st.ext_out_reg.data; - ext_out.control <= st.ext_out_reg.clk & st.ext_out_reg.parity; curr_response_bits <= ext_in_rec.data(7 downto 3); - -- Create combinational bindings for command/response types + next_parity_out <= calc_parity(ext_out_data_cmd); with curr_command select curr_command_bits <= "00000" when NO_OP, "10000" when WRITE_ADD, @@ -131,7 +132,7 @@ begin -- | | | -- +-----------+--------------+ -- ---- Next State Assignment --- + --- Next State Assignment --- case st.curr_state is when IDLE => if curr_command = WRITE or curr_command = WRITE_ADD then @@ -174,7 +175,28 @@ begin -- Right now, we receive only one single word at a time for simplicity next_state <= IDLE; 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'; + case st.curr_state is + when IDLE => + when RESET => + when TX_HEADER => + curr_command <= WRITE; + ext_out_data_cmd <= curr_command_bits & "001"; + when TX_BODY => + ext_out_data_cmd <= int_out.payload; + int_in.is_full_out <= '0'; + when TX_ACK => + when RX_HEADER => + curr_command <= READ; + ext_out_data_cmd <= curr_command_bits & "001"; + when RX_RESPONSE => + when RX_BODY => + end case; + end process comb_proc; -- Process updating internal registers based on primary clock seq_proc: process(ext_in_rec.clk, rst) diff --git a/src/socbridge_driver_tb.vhd b/src/socbridge_driver_tb.vhd index 239400d..17dc5d1 100644 --- a/src/socbridge_driver_tb.vhd +++ b/src/socbridge_driver_tb.vhd @@ -33,7 +33,7 @@ architecture tb of socbridge_driver_tb is ); end component socbridge_driver; signal clk : std_logic := '0'; - signal rst : std_logic := '0'; + signal rst : std_logic; signal ext_in : ext_socbridge_in_t; signal ext_out : ext_socbridge_out_t; signal int_in : int_socbridge_in_t; @@ -57,12 +57,11 @@ begin int_out => int_out ); + ext_in.control(1) <= clk; 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; @@ -105,9 +104,11 @@ begin external_stimulus: process begin rst <= '1'; + curr_word <= "00000000"; wait for 3 * CLK_PERIOD; rst <= '0'; - curr_word <= "00000000"; + wait for CLK_PERIOD / 2; + -- stimulus goes here wait for CLK_PERIOD*10; wait; end process external_stimulus; @@ -115,22 +116,23 @@ begin internal_stimulus: process begin + int_out.is_full_in <= '0'; + int_out.write_enable_out <= '0'; wait for 3 * CLK_PERIOD; - wait for CLK_PERIOD / 2; + -- stimulus goes here + int_out.write_enable_out <= '1'; 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 until int_in.is_full_out = '0'; + int_out.payload <= "00000010"; + wait until int_in.is_full_out = '0'; + int_out.payload <= "00000100"; + wait until int_in.is_full_out = '0'; + int_out.payload <= "00001000"; + wait until int_in.is_full_out = '0'; + int_out.payload <= "00010000"; + wait until int_in.is_full_out = '0'; + int_out.payload <= "00100000"; + wait until int_in.is_full_out = '0'; wait; end process internal_stimulus; -- 2.43.0 From 2d63f99f7fb1e5dd59e2903f62e30cf1be543623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Wed, 26 Feb 2025 17:57:03 +0100 Subject: [PATCH 07/13] At least i know what the problem is... --- src/socbridge_driver.vhd | 100 +++++++++------------------- src/socbridge_driver_tb.vhd | 90 +++++++++++++++++++------ src/socbridge_driver_tb_pkg.vhd | 112 ++++++++++++++++++++++++++++++++ 3 files changed, 212 insertions(+), 90 deletions(-) create mode 100644 src/socbridge_driver_tb_pkg.vhd diff --git a/src/socbridge_driver.vhd b/src/socbridge_driver.vhd index f0b9b77..3102ecf 100644 --- a/src/socbridge_driver.vhd +++ b/src/socbridge_driver.vhd @@ -1,13 +1,16 @@ 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; + rst : in std_logic; + cmd : in command_t; ext_in : in ext_socbridge_in_t; ext_out : out ext_socbridge_out_t; int_in : out int_socbridge_in_t; @@ -16,63 +19,8 @@ entity socbridge_driver is end entity socbridge_driver; architecture rtl of socbridge_driver is - 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 - (RESET, IDLE, TX_HEADER, TX_BODY, TX_ACK, RX_HEADER, RX_RESPONSE, 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; - end record state_rec_t; - - 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; - - pure function create_ext_protocol_from_io_type_in( - input : ext_socbridge_in_t - ) return ext_protocol_t is - variable val : ext_protocol_t; - begin - val.data := input.payload; - val.clk := input.control(1); - val.parity := input.control(0); - return val; - 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; signal next_parity_out : std_logic; - - - signal ext_in_rec : ext_protocol_t; signal ext_out_data_cmd : std_logic_vector(interface_inst.socbridge.payload_width - 1 downto 0); signal next_state : state_t; @@ -82,6 +30,22 @@ architecture rtl of socbridge_driver is signal curr_response_bits : std_logic_vector(4 downto 0); signal st : state_rec_t; begin + next_parity_out <= calc_parity(ext_out_data_cmd); + --- DEBUG GLOBAL BINDINGS --- + -- synthesis translate_off + G_next_parity_out <= next_parity_out; + G_ext_in_rec <= ext_in_rec; + G_ext_out_data_cmd <= ext_out_data_cmd; + G_next_state <= next_state; + G_curr_command <= curr_command; + G_curr_command_bits <= curr_command_bits; + G_curr_respoonse <= curr_respoonse; + G_curr_response_bits <= curr_response_bits; + G_st <= st; + -- synthesis translate_on + + + comb_proc: process(ext_in, int_out, st) begin -- Outputs @@ -91,15 +55,6 @@ begin -- Helpful Bindings -- ext_in_rec <= create_ext_protocol_from_io_type_in(ext_in); curr_response_bits <= ext_in_rec.data(7 downto 3); - next_parity_out <= calc_parity(ext_out_data_cmd); - 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", @@ -135,9 +90,9 @@ begin --- Next State Assignment --- case st.curr_state is when IDLE => - if curr_command = WRITE or curr_command = WRITE_ADD then + if cmd = WRITE or cmd = WRITE_ADD then next_state <= TX_HEADER; - elsif curr_command = READ or curr_command = READ_ADD then + elsif cmd = READ or cmd = READ_ADD then next_state <= RX_HEADER; else next_state <= IDLE; @@ -185,7 +140,7 @@ begin when RESET => when TX_HEADER => curr_command <= WRITE; - ext_out_data_cmd <= curr_command_bits & "001"; + ext_out_data_cmd <= get_command_bits(WRITE) & "001"; when TX_BODY => ext_out_data_cmd <= int_out.payload; int_in.is_full_out <= '0'; @@ -196,7 +151,8 @@ begin when RX_RESPONSE => when RX_BODY => end case; - + report "Running comb part with ext_out_data_cmd = " & to_string(ext_out_data_cmd) severity note; + report "Running comb part with next_parity_out = " & std_logic'image(next_parity_out) severity note; end process comb_proc; -- Process updating internal registers based on primary clock seq_proc: process(ext_in_rec.clk, rst) @@ -209,12 +165,14 @@ begin st.curr_state <= IDLE; elsif(rising_edge(ext_in_rec.clk)) then + report "Running seq part with ext_out_data_cmd = " & to_string(ext_out_data_cmd) severity note; + report "Running seq part with next_parity_out = " & std_logic'image(next_parity_out) severity note; + st.ext_out_reg.parity <= next_parity_out; 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 <= int_out.payload; + 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; end if; end process seq_proc; diff --git a/src/socbridge_driver_tb.vhd b/src/socbridge_driver_tb.vhd index 17dc5d1..9b009e1 100644 --- a/src/socbridge_driver_tb.vhd +++ b/src/socbridge_driver_tb.vhd @@ -3,29 +3,31 @@ 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 - pure function calc_parity( - d : STD_LOGIC_VECTOR(interface_inst.socbridge.payload_width - 1 downto 0) - ) return std_logic is - variable parity : std_logic; + impure function check_next_state(correct_state: state_t) return boolean is begin - parity := d(0); - for x in 1 to d'length - 1 loop - parity := parity xor d(x); - end loop; - return not parity; + 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; + return FALSE; + end if; + return TRUE; end function; + + component socbridge_driver is port( clk : in std_logic; - rst : in std_logic; + rst : in std_logic; + cmd : in command_t; ext_in : in ext_socbridge_in_t; ext_out : out ext_socbridge_out_t; int_in : out int_socbridge_in_t; @@ -34,6 +36,7 @@ architecture tb of socbridge_driver_tb is end component socbridge_driver; signal clk : std_logic := '0'; signal rst : std_logic; + signal cmd : command_t; signal ext_in : ext_socbridge_in_t; signal ext_out : ext_socbridge_out_t; signal int_in : int_socbridge_in_t; @@ -45,12 +48,11 @@ architecture tb of socbridge_driver_tb is constant SIMULATION_CYCLE_COUNT : INTEGER := 100; begin - - socbridge_driver_inst: entity work.socbridge_driver port map( clk => clk, rst => rst, + cmd => cmd, ext_in => ext_in, ext_out => ext_out, int_in => int_in, @@ -74,7 +76,7 @@ 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; + report "Secondary side clk not correct." severity error; end if; last_clk := ext_out.control(1); wait for CLK_PERIOD; @@ -85,16 +87,61 @@ begin verify_parity: process variable curr_parity : std_logic; begin - for x in 0 to SIMULATION_CYCLE_COUNT * 2 loop + for x in 0 to SIMULATION_CYCLE_COUNT * 10 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; + report "Secondary side parity not correct" severity error; + wait for CLK_PERIOD; + report "Ending Simulation... " severity FAILURE; end if; - wait for CLK_PERIOD / 2; + wait for CLK_PERIOD / 10; end loop; wait; end process verify_parity; + verify_next_state : process + variable nsv: boolean; + begin + wait for 3 * CLK_PERIOD; + wait for CLK_PERIOD / 2; + nsv := check_next_state(IDLE); + wait for CLK_PERIOD; + nsv := check_next_state(TX_HEADER); + wait for CLK_PERIOD; + nsv := check_next_state(TX_BODY); + wait for CLK_PERIOD; + nsv := check_next_state(TX_ACK); + wait for CLK_PERIOD; + nsv := check_next_state(TX_ACK); + wait for CLK_PERIOD; + nsv := check_next_state(IDLE); + wait for CLK_PERIOD; + nsv := check_next_state(IDLE); + wait for CLK_PERIOD; + nsv := check_next_state(IDLE); + wait for CLK_PERIOD; + nsv := check_next_state(IDLE); + wait for CLK_PERIOD; + nsv := check_next_state(IDLE); + wait for CLK_PERIOD; + nsv := check_next_state(IDLE); + wait for CLK_PERIOD; + nsv := check_next_state(IDLE); + wait for CLK_PERIOD; + wait; + end process verify_next_state; + + command_stimulus: process + begin + cmd <= NO_OP; + wait for 3*CLK_PERIOD; + wait for CLK_PERIOD / 2; + cmd <= WRITE; + wait for CLK_PERIOD; + cmd <= NO_OP; + wait; + end process command_stimulus; + external_stimulus_signal: process(curr_word) begin ext_in.payload <= curr_word; @@ -108,12 +155,11 @@ begin wait for 3 * CLK_PERIOD; rst <= '0'; wait for CLK_PERIOD / 2; - -- stimulus goes here - wait for CLK_PERIOD*10; + wait for 3* CLK_PERIOD; + curr_word <= "00001001"; wait; end process external_stimulus; - internal_stimulus: process begin int_out.is_full_in <= '0'; @@ -123,16 +169,22 @@ begin int_out.write_enable_out <= '1'; int_out.payload <= "00000000"; wait until int_in.is_full_out = '0'; + wait until rising_edge(clk); int_out.payload <= "00000010"; wait until int_in.is_full_out = '0'; + wait until rising_edge(clk); int_out.payload <= "00000100"; wait until int_in.is_full_out = '0'; + wait until rising_edge(clk); int_out.payload <= "00001000"; wait until int_in.is_full_out = '0'; + wait until rising_edge(clk); int_out.payload <= "00010000"; wait until int_in.is_full_out = '0'; + wait until rising_edge(clk); int_out.payload <= "00100000"; wait until int_in.is_full_out = '0'; + wait until rising_edge(clk); wait; end process internal_stimulus; diff --git a/src/socbridge_driver_tb_pkg.vhd b/src/socbridge_driver_tb_pkg.vhd new file mode 100644 index 0000000..676b6ef --- /dev/null +++ b/src/socbridge_driver_tb_pkg.vhd @@ -0,0 +1,112 @@ +library IEEE; +use IEEE.std_logic_1164.all; +library work; +use work.io_types.all; + + +package socbridge_driver_tb_pkg is + 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 + (RESET, IDLE, TX_HEADER, TX_BODY, TX_ACK, RX_HEADER, RX_RESPONSE, 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; + 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_ext_protocol_from_io_type_in ( + input : ext_socbridge_in_t + ) return ext_protocol_t; + 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_command_bits(command : command_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_respoonse : 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_ext_protocol_from_io_type_in( + input : ext_socbridge_in_t + ) return ext_protocol_t is + variable val : ext_protocol_t; + begin + val.data := input.payload; + val.clk := input.control(1); + val.parity := input.control(0); + return val; + 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_command_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; + +end package body socbridge_driver_tb_pkg; -- 2.43.0 From a88dd13fafabd8a24c61b1a68c4ae384dc5c04e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Thu, 27 Feb 2025 10:55:09 +0100 Subject: [PATCH 08/13] added socbrdige driver tb gtkwave config --- src/socbridge_driver_tb.gtkw | 79 ++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/socbridge_driver_tb.gtkw diff --git a/src/socbridge_driver_tb.gtkw b/src/socbridge_driver_tb.gtkw new file mode 100644 index 0000000..3290cb7 --- /dev/null +++ b/src/socbridge_driver_tb.gtkw @@ -0,0 +1,79 @@ +[*] +[*] GTKWave Analyzer v3.3.120 (w)1999-2024 BSI +[*] Wed Feb 26 15:43:46 2025 +[*] +[dumpfile] "/home/kryddan/repos/exjobb-public/src/wave/socbridge_driver_tb-tb.ghw" +[dumpfile_mtime] "Wed Feb 26 15:43:13 2025" +[dumpfile_size] 2378 +[savefile] "/home/kryddan/repos/exjobb-public/src/wave/socbridge_driver_tb.gtkw" +[timestart] 0 +[size] 1920 1080 +[pos] -966 -6 +*-23.724968 40550000 -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] +@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 +@23 +#{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] +@420 +top.socbridge_driver_tb_pkg.g_curr_respoonse +@1000200 +-Internal Signals +@420 +top.socbridge_driver_tb.cmd +[pattern_trace] 1 +[pattern_trace] 0 -- 2.43.0 From d9b0725b7e7669b13300414105f561770b3c5502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Thu, 27 Feb 2025 13:48:17 +0100 Subject: [PATCH 09/13] improved testbench and removed unnecessary delay caused by 2PM --- src/socbridge_driver.vhd | 73 ++++++++++++----- src/socbridge_driver_tb.gtkw | 24 +++--- src/socbridge_driver_tb.vhd | 140 +++++++++++++++++++++----------- src/socbridge_driver_tb_pkg.vhd | 15 +--- 4 files changed, 156 insertions(+), 96 deletions(-) diff --git a/src/socbridge_driver.vhd b/src/socbridge_driver.vhd index 3102ecf..d0abb8f 100644 --- a/src/socbridge_driver.vhd +++ b/src/socbridge_driver.vhd @@ -22,29 +22,30 @@ architecture rtl of socbridge_driver is signal next_parity_out : std_logic; signal ext_in_rec : ext_protocol_t; - signal ext_out_data_cmd : std_logic_vector(interface_inst.socbridge.payload_width - 1 downto 0); + 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_command : command_t; signal curr_command_bits : std_logic_vector(4 downto 0); - signal curr_respoonse : response_t; + signal curr_response : response_t; signal curr_response_bits : std_logic_vector(4 downto 0); signal st : state_rec_t; begin - next_parity_out <= calc_parity(ext_out_data_cmd); --- DEBUG GLOBAL BINDINGS --- -- synthesis translate_off G_next_parity_out <= next_parity_out; G_ext_in_rec <= ext_in_rec; - G_ext_out_data_cmd <= ext_out_data_cmd; G_next_state <= next_state; + G_ext_out_data_cmd <=test; G_curr_command <= curr_command; G_curr_command_bits <= curr_command_bits; - G_curr_respoonse <= curr_respoonse; + 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); comb_proc: process(ext_in, int_out, st) begin @@ -53,10 +54,25 @@ begin int_in.payload <= st.ext_in_reg.data; -- Helpful Bindings -- - ext_in_rec <= create_ext_protocol_from_io_type_in(ext_in); - curr_response_bits <= ext_in_rec.data(7 downto 3); + 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_respoonse <= WRITE_ACK when "00001", + curr_response <= WRITE_ACK when "00001", WRITE_ACK when "00101", READ_RESPONSE when "01000", READ_RESPONSE when "01100", @@ -109,7 +125,7 @@ begin next_state <= TX_ACK; when TX_ACK => -- Wait for write acknowledgement. - if curr_respoonse = WRITE_ACK then + if curr_response = WRITE_ACK then next_state <= IDLE; else next_state <= TX_ACK; @@ -120,7 +136,7 @@ begin next_state <= RX_RESPONSE; when RX_RESPONSE => -- Wait for read response. - if curr_respoonse = READ_RESPONSE then + if curr_response = READ_RESPONSE then next_state <= RX_BODY; else next_state <= RX_RESPONSE; @@ -132,27 +148,42 @@ begin end case; --- Combinatorial output based on current state --- - ext_out_data_cmd <= (others => '0'); + ext_out_data_cmd := (others => '0'); int_in.is_full_out <= '1'; int_in.write_enable_in <= '0'; case st.curr_state is when IDLE => + if cmd = WRITE or cmd = WRITE_ADD then + ext_out_data_cmd := get_command_bits(WRITE) & "001"; + elsif cmd = READ or cmd = READ_ADD then + ext_out_data_cmd := get_command_bits(READ) & "001"; + end if; when RESET => when TX_HEADER => curr_command <= WRITE; - ext_out_data_cmd <= get_command_bits(WRITE) & "001"; - when TX_BODY => - ext_out_data_cmd <= int_out.payload; + ext_out_data_cmd := int_out.payload; int_in.is_full_out <= '0'; + when TX_BODY => + -- here more logic is needed for mulit word transmission (and address setting) + if cmd = WRITE_ADD then + ext_out_data_cmd := int_out.payload; + int_in.is_full_out <= '0'; + end if; when TX_ACK => when RX_HEADER => curr_command <= READ; - ext_out_data_cmd <= curr_command_bits & "001"; + ext_out_data_cmd := curr_command_bits & "001"; when RX_RESPONSE => when RX_BODY => end case; - report "Running comb part with ext_out_data_cmd = " & to_string(ext_out_data_cmd) severity note; - report "Running comb part with next_parity_out = " & std_logic'image(next_parity_out) severity note; + next_parity_out <= calc_parity(ext_out_data_cmd); + --- DEBUG GLOBAL BINDINGS --- + -- synthesis translate_off + test <= ext_out_data_cmd; + report to_string(ext_out_data_cmd); + report to_string(test); + report to_string(G_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) @@ -165,14 +196,12 @@ begin st.curr_state <= IDLE; elsif(rising_edge(ext_in_rec.clk)) then - report "Running seq part with ext_out_data_cmd = " & to_string(ext_out_data_cmd) severity note; - report "Running seq part with next_parity_out = " & std_logic'image(next_parity_out) severity note; - st.ext_out_reg.parity <= next_parity_out; 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; end if; end process seq_proc; diff --git a/src/socbridge_driver_tb.gtkw b/src/socbridge_driver_tb.gtkw index 3290cb7..4b32853 100644 --- a/src/socbridge_driver_tb.gtkw +++ b/src/socbridge_driver_tb.gtkw @@ -1,15 +1,15 @@ [*] -[*] GTKWave Analyzer v3.3.120 (w)1999-2024 BSI -[*] Wed Feb 26 15:43:46 2025 +[*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI +[*] Thu Feb 27 10:27:13 2025 [*] -[dumpfile] "/home/kryddan/repos/exjobb-public/src/wave/socbridge_driver_tb-tb.ghw" -[dumpfile_mtime] "Wed Feb 26 15:43:13 2025" -[dumpfile_size] 2378 -[savefile] "/home/kryddan/repos/exjobb-public/src/wave/socbridge_driver_tb.gtkw" -[timestart] 0 -[size] 1920 1080 -[pos] -966 -6 -*-23.724968 40550000 -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 +[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. @@ -37,6 +37,7 @@ top.socbridge_driver_tb.int_out.write_enable_out +{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 @@ -67,9 +68,6 @@ top.socbridge_driver_tb.int_in.write_enable_in 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 -@23 -#{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] -@420 top.socbridge_driver_tb_pkg.g_curr_respoonse @1000200 -Internal Signals diff --git a/src/socbridge_driver_tb.vhd b/src/socbridge_driver_tb.vhd index 9b009e1..88d4137 100644 --- a/src/socbridge_driver_tb.vhd +++ b/src/socbridge_driver_tb.vhd @@ -10,18 +10,51 @@ entity socbridge_driver_tb is end entity socbridge_driver_tb; architecture tb of socbridge_driver_tb is - impure function check_next_state(correct_state: state_t) return boolean is + signal clk : std_logic := '0'; + signal rst : std_logic; + signal cmd : command_t; + 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; - return FALSE; + fail("Next State"); end if; - return TRUE; - end function; - - + 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( @@ -34,18 +67,6 @@ architecture tb of socbridge_driver_tb is int_out : in int_socbridge_out_t ); end component socbridge_driver; - signal clk : std_logic := '0'; - signal rst : std_logic; - signal cmd : command_t; - 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 @@ -68,7 +89,6 @@ begin end loop; wait; end process real_clk_proc; - verify_clk: process variable last_clk : std_logic; @@ -84,52 +104,64 @@ begin wait; end process verify_clk; - verify_parity: process + verify_out_signals: process variable curr_parity : std_logic; begin - for x in 0 to SIMULATION_CYCLE_COUNT * 10 loop - curr_parity := calc_parity(ext_out.payload); - if not (curr_parity = ext_out.control(0)) then - report "Secondary side parity not correct" severity error; - wait for CLK_PERIOD; - report "Ending Simulation... " severity FAILURE; - end if; - wait for CLK_PERIOD / 10; + 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_parity; + end process verify_out_signals; - verify_next_state : process + verify_signals : process variable nsv: boolean; begin + expected_out <= "00000000"; wait for 3 * CLK_PERIOD; - wait for CLK_PERIOD / 2; - nsv := check_next_state(IDLE); + 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_command_bits(WRITE) & "001"; + check_next_state(TX_BODY); wait for CLK_PERIOD; - nsv := check_next_state(TX_HEADER); + expected_out <= "00000001"; + check_next_state(TX_ACK); wait for CLK_PERIOD; - nsv := check_next_state(TX_BODY); + expected_out <= "00000000"; + check_next_state(TX_ACK); wait for CLK_PERIOD; - nsv := check_next_state(TX_ACK); + expected_out <= "00000000"; + check_next_state(IDLE); wait for CLK_PERIOD; - nsv := check_next_state(TX_ACK); + expected_out <= "00000000"; + check_next_state(IDLE); wait for CLK_PERIOD; - nsv := check_next_state(IDLE); + expected_out <= "00000000"; + check_next_state(IDLE); wait for CLK_PERIOD; - nsv := check_next_state(IDLE); + expected_out <= "00000000"; + check_next_state(IDLE); wait for CLK_PERIOD; - nsv := check_next_state(IDLE); + expected_out <= "00000000"; + check_next_state(IDLE); wait for CLK_PERIOD; - nsv := check_next_state(IDLE); + expected_out <= "00000000"; + check_next_state(IDLE); wait for CLK_PERIOD; - nsv := check_next_state(IDLE); + expected_out <= "00000000"; + check_next_state(IDLE); wait for CLK_PERIOD; - nsv := check_next_state(IDLE); - wait for CLK_PERIOD; - nsv := check_next_state(IDLE); + expected_out <= "00000000"; + check_next_state(IDLE); wait for CLK_PERIOD; wait; - end process verify_next_state; + end process verify_signals; command_stimulus: process begin @@ -150,9 +182,12 @@ begin external_stimulus: process begin + rst <= '0'; + wait for CLK_PERIOD / 1000; rst <= '1'; curr_word <= "00000000"; - wait for 3 * CLK_PERIOD; + wait for 999 * CLK_PERIOD / 1000; + wait for 2 * CLK_PERIOD; rst <= '0'; wait for CLK_PERIOD / 2; wait for 3* CLK_PERIOD; @@ -167,24 +202,35 @@ begin wait for 3 * CLK_PERIOD; -- stimulus goes here int_out.write_enable_out <= '1'; - int_out.payload <= "00000000"; + int_out.payload <= "00000001"; wait until int_in.is_full_out = '0'; wait until rising_edge(clk); + wait until rising_edge(clk); int_out.payload <= "00000010"; 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 <= "00000100"; 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 <= "00001000"; 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 <= "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; diff --git a/src/socbridge_driver_tb_pkg.vhd b/src/socbridge_driver_tb_pkg.vhd index 676b6ef..10dad39 100644 --- a/src/socbridge_driver_tb_pkg.vhd +++ b/src/socbridge_driver_tb_pkg.vhd @@ -27,9 +27,6 @@ package socbridge_driver_tb_pkg is impure function calc_parity( d : STD_LOGIC_VECTOR(interface_inst.socbridge.payload_width - 1 downto 0) ) return std_logic; - pure function create_ext_protocol_from_io_type_in ( - input : ext_socbridge_in_t - ) return ext_protocol_t; pure function create_io_type_out_from_ext_protocol( input: ext_protocol_t ) return ext_socbridge_out_t; @@ -43,7 +40,7 @@ package socbridge_driver_tb_pkg is 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_respoonse : response_t; + 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 @@ -74,16 +71,6 @@ package body socbridge_driver_tb_pkg is return not parity; end function; - pure function create_ext_protocol_from_io_type_in( - input : ext_socbridge_in_t - ) return ext_protocol_t is - variable val : ext_protocol_t; - begin - val.data := input.payload; - val.clk := input.control(1); - val.parity := input.control(0); - return val; - end function; pure function create_io_type_out_from_ext_protocol( input : ext_protocol_t ) return ext_socbridge_out_t is -- 2.43.0 From d5ad4da4f5d4be627cc26ce17e7bdfc9c151965e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Thu, 27 Feb 2025 16:11:16 +0100 Subject: [PATCH 10/13] added support for multi word writes --- src/socbridge_driver.vhd | 108 +++++++++++++++++++++----------- src/socbridge_driver_tb.vhd | 33 +++++----- src/socbridge_driver_tb_pkg.vhd | 24 +++++++ 3 files changed, 110 insertions(+), 55 deletions(-) diff --git a/src/socbridge_driver.vhd b/src/socbridge_driver.vhd index d0abb8f..19c0834 100644 --- a/src/socbridge_driver.vhd +++ b/src/socbridge_driver.vhd @@ -11,6 +11,7 @@ entity socbridge_driver is clk : in std_logic; rst : in std_logic; cmd : in command_t; + 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; @@ -47,36 +48,36 @@ begin ext_in_rec.clk <= ext_in.control(1); ext_in_rec.parity <= ext_in.control(0); - comb_proc: process(ext_in, int_out, st) + -- 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) begin -- Outputs ext_out <= create_io_type_out_from_ext_protocol(st.ext_out_reg); int_in.payload <= st.ext_in_reg.data; - -- 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; --- State Transition Diagram --- -- @@ -122,7 +123,11 @@ begin when TX_BODY => -- Here we want to stay in TX_BODY for the duration of a packet. -- Right now, we transfer one single word at a time for simplicity - next_state <= TX_ACK; + 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 @@ -154,25 +159,31 @@ begin case st.curr_state is when IDLE => if cmd = WRITE or cmd = WRITE_ADD then - ext_out_data_cmd := get_command_bits(WRITE) & "001"; + curr_command <= cmd; + ext_out_data_cmd := get_command_bits(cmd) & get_size_bits(cmd_size); elsif cmd = READ or cmd = READ_ADD then - ext_out_data_cmd := get_command_bits(READ) & "001"; + curr_command <= cmd; + ext_out_data_cmd := get_command_bits(cmd) & get_size_bits(cmd_size); end if; when RESET => when TX_HEADER => - curr_command <= WRITE; - ext_out_data_cmd := int_out.payload; + if cmd = WRITE_ADD then + --ext_out_data_cmd := address; + else + ext_out_data_cmd := int_out.payload; + end if; int_in.is_full_out <= '0'; when TX_BODY => - -- here more logic is needed for mulit word transmission (and address setting) - if cmd = WRITE_ADD then + if curr_response = WRITE_ACK then + ext_out_data_cmd := "00000000"; + else ext_out_data_cmd := int_out.payload; int_in.is_full_out <= '0'; end if; when TX_ACK => when RX_HEADER => curr_command <= READ; - ext_out_data_cmd := curr_command_bits & "001"; + ext_out_data_cmd := curr_command_bits & get_size_bits(cmd_size); when RX_RESPONSE => when RX_BODY => end case; @@ -180,9 +191,6 @@ begin --- DEBUG GLOBAL BINDINGS --- -- synthesis translate_off test <= ext_out_data_cmd; - report to_string(ext_out_data_cmd); - report to_string(test); - report to_string(G_ext_out_data_cmd); -- synthesis translate_on end process comb_proc; -- Process updating internal registers based on primary clock @@ -194,6 +202,8 @@ begin st.ext_out_reg.clk <= '0'; st.ext_out_reg.parity <= '1'; st.curr_state <= IDLE; + st.write_stage <= 0; + st.read_stage <= 0; elsif(rising_edge(ext_in_rec.clk)) then st.ext_in_reg.data <= ext_in_rec.data; @@ -203,7 +213,31 @@ begin st.ext_out_reg.clk <= not st.ext_out_reg.clk; st.ext_out_reg.parity <= next_parity_out; st.curr_state <= next_state; - end if; + case st.curr_state is + when TX_HEADER => + if curr_command = WRITE then + st.write_stage <= 2**(cmd_size - 1) - 1; + elsif curr_command = WRITE_ADD then + st.write_stage <= 2**(cmd_size - 1); + end if; + when TX_BODY => + if st.write_stage > 0 then + st.write_stage <= st.write_stage - 1; + end if; + when RX_HEADER => + if curr_command = READ then + st.read_stage <= 2**(cmd_size - 1) - 1; + elsif curr_command = WRITE_ADD then + st.read_stage <= 2**(cmd_size - 1); + end if; + 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; diff --git a/src/socbridge_driver_tb.vhd b/src/socbridge_driver_tb.vhd index 88d4137..65f196d 100644 --- a/src/socbridge_driver_tb.vhd +++ b/src/socbridge_driver_tb.vhd @@ -13,6 +13,7 @@ architecture tb of socbridge_driver_tb is signal clk : std_logic := '0'; signal rst : std_logic; signal cmd : command_t; + 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; @@ -61,6 +62,7 @@ architecture tb of socbridge_driver_tb is clk : in std_logic; rst : in std_logic; cmd : in command_t; + 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; @@ -74,6 +76,7 @@ begin clk => clk, rst => rst, cmd => cmd, + cmd_size => cmd_size, ext_in => ext_in, ext_out => ext_out, int_in => int_in, @@ -127,13 +130,13 @@ begin wait for CLK_PERIOD /4; check_next_state(TX_HEADER); wait for CLK_PERIOD * 3 / 4; - expected_out <= get_command_bits(WRITE) & "001"; + expected_out <= get_command_bits(WRITE) & get_size_bits_sim(2); check_next_state(TX_BODY); wait for CLK_PERIOD; expected_out <= "00000001"; - check_next_state(TX_ACK); + check_next_state(TX_BODY); wait for CLK_PERIOD; - expected_out <= "00000000"; + expected_out <= "00000010"; check_next_state(TX_ACK); wait for CLK_PERIOD; expected_out <= "00000000"; @@ -166,6 +169,7 @@ begin command_stimulus: process begin cmd <= NO_OP; + cmd_size <= 2; wait for 3*CLK_PERIOD; wait for CLK_PERIOD / 2; cmd <= WRITE; @@ -203,24 +207,17 @@ begin -- stimulus goes here int_out.write_enable_out <= '1'; int_out.payload <= "00000001"; - wait until int_in.is_full_out = '0'; - wait until rising_edge(clk); - wait until rising_edge(clk); + wait until rising_edge(clk) and int_in.is_full_out = '0'; + wait until falling_edge(clk); int_out.payload <= "00000010"; - wait until int_in.is_full_out = '0'; - wait for CLK_PERIOD/2; - wait until rising_edge(clk); - wait until rising_edge(clk); + wait until rising_edge(clk) and int_in.is_full_out = '0'; + wait until falling_edge(clk); int_out.payload <= "00000100"; - wait until int_in.is_full_out = '0'; - wait for CLK_PERIOD/2; - wait until rising_edge(clk); - wait until rising_edge(clk); + wait until rising_edge(clk) and int_in.is_full_out = '0'; + wait until falling_edge(clk); int_out.payload <= "00001000"; - wait until int_in.is_full_out = '0'; - wait for CLK_PERIOD/2; - wait until rising_edge(clk); - wait until rising_edge(clk); + 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; diff --git a/src/socbridge_driver_tb_pkg.vhd b/src/socbridge_driver_tb_pkg.vhd index 10dad39..6723108 100644 --- a/src/socbridge_driver_tb_pkg.vhd +++ b/src/socbridge_driver_tb_pkg.vhd @@ -1,10 +1,14 @@ 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); @@ -23,6 +27,7 @@ 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; + write_stage, read_stage : NATURAL; end record state_rec_t; impure function calc_parity( d : STD_LOGIC_VECTOR(interface_inst.socbridge.payload_width - 1 downto 0) @@ -32,6 +37,8 @@ package socbridge_driver_tb_pkg is ) return ext_socbridge_out_t; function to_string ( a: std_logic_vector) return string; pure function get_command_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; @@ -96,4 +103,21 @@ package body socbridge_driver_tb_pkg is 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; -- 2.43.0 From 6451f77dce1bdbd2dfd1c19f8178ccc85db0bfbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Mon, 3 Mar 2025 17:13:16 +0100 Subject: [PATCH 11/13] in progress of adding addressing for write command --- src/socbridge_driver.vhd | 97 ++++++++++++++++++++------------- src/socbridge_driver_tb.vhd | 2 +- src/socbridge_driver_tb_pkg.vhd | 10 +++- 3 files changed, 67 insertions(+), 42 deletions(-) diff --git a/src/socbridge_driver.vhd b/src/socbridge_driver.vhd index 19c0834..3b6336e 100644 --- a/src/socbridge_driver.vhd +++ b/src/socbridge_driver.vhd @@ -11,6 +11,7 @@ entity socbridge_driver is 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; @@ -26,8 +27,7 @@ architecture rtl of socbridge_driver is 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_command : command_t; - signal curr_command_bits : std_logic_vector(4 downto 0); + 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; @@ -38,8 +38,7 @@ begin G_ext_in_rec <= ext_in_rec; G_next_state <= next_state; G_ext_out_data_cmd <=test; - G_curr_command <= curr_command; - G_curr_command_bits <= curr_command_bits; + G_curr_command_bits <= curr_cmd_bits; G_curr_response <= curr_response; G_curr_response_bits <= curr_response_bits; G_st <= st; @@ -81,19 +80,32 @@ begin --- State Transition Diagram --- -- --- +-----+ --- \|/ | --- RESET --+ --- | --- | +-- +-- +-- +-----+ +-- | | +-- \|/ /--+ -- IDLE<-------------------+ -- / \ | -- / \ | -- / \ | -- \|/ \|/ | -- TX_HEADER RX_HEADER | --- | | | --- | | ----+ | +-- |\ / | | +-- | \ / | | +-- | ADDR1 | | +-- | | | | +-- | \|/ | | +-- | ADDR2 | | +-- | | | | +-- | \|/ | | +-- | ADDR3 | | +-- | | | | +-- | \|/ | | +-- | ADDR4 | | +-- | /\ | | +-- | / \ | | +-- |-+ +----| +---+ | -- \|/ \|/ \|/ | | -- TX_BODY RX_RESPONSE---+ | -- | | | @@ -114,8 +126,6 @@ begin else next_state <= IDLE; end if; - when RESET => - next_state <= IDLE; when TX_HEADER => -- The header only takes one word (cycle) to transmit. -- Continue to body directly afterwards. @@ -150,6 +160,16 @@ begin -- Here we want to stay in RX_BODY for the duration of a packet. -- Right now, we receive only one single word at a time for simplicity next_state <= IDLE; + when ADDR1 => + next_state <= ADDR2; + when ADDR2 => + next_state <= ADDR3; + when ADDR3 => + if st.cmd_reg = WRITE or st.cmd_reg = WRITE_ADD then + next_state <= TX_BODY; + else + next_state <= RX_BODY; + end if; end case; --- Combinatorial output based on current state --- @@ -158,34 +178,27 @@ begin int_in.write_enable_in <= '0'; case st.curr_state is when IDLE => - if cmd = WRITE or cmd = WRITE_ADD then - curr_command <= cmd; - ext_out_data_cmd := get_command_bits(cmd) & get_size_bits(cmd_size); - elsif cmd = READ or cmd = READ_ADD then - curr_command <= cmd; - ext_out_data_cmd := get_command_bits(cmd) & get_size_bits(cmd_size); - end if; - when RESET => when TX_HEADER => - if cmd = WRITE_ADD then - --ext_out_data_cmd := address; - else - ext_out_data_cmd := int_out.payload; - end if; - int_in.is_full_out <= '0'; - when TX_BODY => - if curr_response = WRITE_ACK then - ext_out_data_cmd := "00000000"; + 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 => + ext_out_data_cmd := int_out.payload; + int_in.is_full_out <= '0'; when TX_ACK => when RX_HEADER => - curr_command <= READ; - ext_out_data_cmd := curr_command_bits & get_size_bits(cmd_size); + ext_out_data_cmd := get_cmd_bits(st.cmd_reg) & get_size_bits(cmd_size); when RX_RESPONSE => when RX_BODY => + 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); end case; next_parity_out <= calc_parity(ext_out_data_cmd); --- DEBUG GLOBAL BINDINGS --- @@ -204,6 +217,8 @@ begin 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; @@ -214,21 +229,27 @@ begin 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 => - if curr_command = WRITE then + if st.cmd_reg = WRITE then st.write_stage <= 2**(cmd_size - 1) - 1; - elsif curr_command = WRITE_ADD then - st.write_stage <= 2**(cmd_size - 1); + elsif st.cmd_reg = WRITE_ADD then + st.write_stage <= 2**(cmd_size - 1) + 3; end if; when TX_BODY => if st.write_stage > 0 then st.write_stage <= st.write_stage - 1; end if; when RX_HEADER => - if curr_command = READ then + if st.cmd_reg = READ then st.read_stage <= 2**(cmd_size - 1) - 1; - elsif curr_command = WRITE_ADD then - st.read_stage <= 2**(cmd_size - 1); + elsif st.cmd_reg = READ_ADD then + st.read_stage <= 2**(cmd_size - 1) + 3; end if; when RX_BODY => if st.read_stage > 0 then diff --git a/src/socbridge_driver_tb.vhd b/src/socbridge_driver_tb.vhd index 65f196d..2bcf280 100644 --- a/src/socbridge_driver_tb.vhd +++ b/src/socbridge_driver_tb.vhd @@ -130,7 +130,7 @@ begin wait for CLK_PERIOD /4; check_next_state(TX_HEADER); wait for CLK_PERIOD * 3 / 4; - expected_out <= get_command_bits(WRITE) & get_size_bits_sim(2); + expected_out <= get_cmd_bits(WRITE) & get_size_bits_sim(2); check_next_state(TX_BODY); wait for CLK_PERIOD; expected_out <= "00000001"; diff --git a/src/socbridge_driver_tb_pkg.vhd b/src/socbridge_driver_tb_pkg.vhd index 6723108..d174742 100644 --- a/src/socbridge_driver_tb_pkg.vhd +++ b/src/socbridge_driver_tb_pkg.vhd @@ -16,7 +16,9 @@ package socbridge_driver_tb_pkg is (NO_OP, WRITE_ACK, READ_RESPONSE); type state_t is - (RESET, IDLE, TX_HEADER, TX_BODY, TX_ACK, RX_HEADER, RX_RESPONSE, RX_BODY); + (IDLE, ADDR1, ADDR2, ADDR3, + TX_HEADER, TX_BODY, TX_ACK, + RX_HEADER, RX_RESPONSE, RX_BODY); type ext_protocol_t is record data : std_logic_vector(interface_inst.socbridge.payload_width - 1 downto 0); @@ -28,6 +30,8 @@ package socbridge_driver_tb_pkg is curr_state: state_t; ext_in_reg, ext_out_reg : ext_protocol_t; write_stage, read_stage : NATURAL; + cmd_reg : command_t; + addr_reg : std_logic_vector(31 downto 0); end record state_rec_t; impure function calc_parity( d : STD_LOGIC_VECTOR(interface_inst.socbridge.payload_width - 1 downto 0) @@ -36,7 +40,7 @@ package socbridge_driver_tb_pkg is input: ext_protocol_t ) return ext_socbridge_out_t; function to_string ( a: std_logic_vector) return string; - pure function get_command_bits(command : command_t) return std_logic_vector; + 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 --- @@ -88,7 +92,7 @@ package body socbridge_driver_tb_pkg is val.control(0) := input.parity; return val; end function; - pure function get_command_bits(command : command_t) + pure function get_cmd_bits(command : command_t) return std_logic_vector is variable val : std_logic_vector(4 downto 0); begin -- 2.43.0 From 78a830b82edbb7fb4a75c1eb0e4d01b709c0a898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Tue, 4 Mar 2025 16:06:30 +0100 Subject: [PATCH 12/13] added support for multi word addressable writes --- src/socbridge_driver.vhd | 47 ++++++++++++++++++++++++--------- src/socbridge_driver_tb.vhd | 41 ++++++++++++++++++++++++++-- src/socbridge_driver_tb_pkg.vhd | 2 +- 3 files changed, 75 insertions(+), 15 deletions(-) diff --git a/src/socbridge_driver.vhd b/src/socbridge_driver.vhd index 3b6336e..c6f2cbb 100644 --- a/src/socbridge_driver.vhd +++ b/src/socbridge_driver.vhd @@ -71,7 +71,7 @@ begin READ_RESPONSE when "01000", READ_RESPONSE when "01100", NO_OP when others; - comb_proc: process(ext_in, int_out, curr_response, st) + 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); @@ -128,8 +128,12 @@ begin end if; when TX_HEADER => -- The header only takes one word (cycle) to transmit. - -- Continue to body directly afterwards. - next_state <= TX_BODY; + -- 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. -- Right now, we transfer one single word at a time for simplicity @@ -148,7 +152,11 @@ begin when RX_HEADER => -- The header only takes one word (cycle) to transmit. -- Continue to awaiting response directly afterwards. - next_state <= RX_RESPONSE; + if st.cmd_reg = WRITE_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 @@ -165,6 +173,8 @@ begin 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 @@ -178,6 +188,11 @@ begin int_in.write_enable_in <= '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); @@ -186,8 +201,13 @@ begin int_in.is_full_out <= '0'; end if; when TX_BODY => - ext_out_data_cmd := int_out.payload; - int_in.is_full_out <= '0'; + 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 => ext_out_data_cmd := get_cmd_bits(st.cmd_reg) & get_size_bits(cmd_size); @@ -199,6 +219,9 @@ begin ext_out_data_cmd := st.addr_reg(23 downto 16); when ADDR3 => ext_out_data_cmd := st.addr_reg(31 downto 24); + when ADDR4 => + int_in.is_full_out <= '0'; + ext_out_data_cmd := int_out.payload; end case; next_parity_out <= calc_parity(ext_out_data_cmd); --- DEBUG GLOBAL BINDINGS --- @@ -236,20 +259,20 @@ begin st.cmd_reg <= cmd; end if; when TX_HEADER => - if st.cmd_reg = WRITE then + if st.cmd_reg = WRITE_ADD then + st.write_stage <= 2**(cmd_size - 1) - 1; + else st.write_stage <= 2**(cmd_size - 1) - 1; - elsif st.cmd_reg = WRITE_ADD then - st.write_stage <= 2**(cmd_size - 1) + 3; end if; when TX_BODY => if st.write_stage > 0 then st.write_stage <= st.write_stage - 1; end if; when RX_HEADER => - if st.cmd_reg = READ then + if st.cmd_reg = READ_ADD then + st.read_stage <= 2**(cmd_size - 1); + else st.read_stage <= 2**(cmd_size - 1) - 1; - elsif st.cmd_reg = READ_ADD then - st.read_stage <= 2**(cmd_size - 1) + 3; end if; when RX_BODY => if st.read_stage > 0 then diff --git a/src/socbridge_driver_tb.vhd b/src/socbridge_driver_tb.vhd index 2bcf280..e99093b 100644 --- a/src/socbridge_driver_tb.vhd +++ b/src/socbridge_driver_tb.vhd @@ -13,6 +13,7 @@ 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; @@ -62,6 +63,7 @@ architecture tb of socbridge_driver_tb is 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; @@ -76,6 +78,7 @@ begin clk => clk, rst => rst, cmd => cmd, + address => address, cmd_size => cmd_size, ext_in => ext_in, ext_out => ext_out, @@ -140,7 +143,7 @@ begin check_next_state(TX_ACK); wait for CLK_PERIOD; expected_out <= "00000000"; - check_next_state(IDLE); + check_next_state(TX_ACK); wait for CLK_PERIOD; expected_out <= "00000000"; check_next_state(IDLE); @@ -162,7 +165,30 @@ begin wait for CLK_PERIOD; 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"; + wait for CLK_PERIOD; + expected_out <= "00000000"; wait; end process verify_signals; @@ -175,6 +201,12 @@ begin 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; end process command_stimulus; @@ -194,8 +226,13 @@ begin wait for 2 * CLK_PERIOD; rst <= '0'; wait for CLK_PERIOD / 2; - wait for 3* CLK_PERIOD; + wait for 4* CLK_PERIOD; curr_word <= "00001001"; + wait for CLK_PERIOD; + curr_word <= "00000000"; + wait for CLK_PERIOD * 10; + curr_word <= "00101001"; + wait; end process external_stimulus; diff --git a/src/socbridge_driver_tb_pkg.vhd b/src/socbridge_driver_tb_pkg.vhd index d174742..19b7b7a 100644 --- a/src/socbridge_driver_tb_pkg.vhd +++ b/src/socbridge_driver_tb_pkg.vhd @@ -16,7 +16,7 @@ package socbridge_driver_tb_pkg is (NO_OP, WRITE_ACK, READ_RESPONSE); type state_t is - (IDLE, ADDR1, ADDR2, ADDR3, + (IDLE, ADDR1, ADDR2, ADDR3, ADDR4, TX_HEADER, TX_BODY, TX_ACK, RX_HEADER, RX_RESPONSE, RX_BODY); -- 2.43.0 From 883bf6ea0c6069c8dccb49d0e126ef9f718fb3e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Tue, 4 Mar 2025 17:10:48 +0100 Subject: [PATCH 13/13] added support for reads with and without addresses --- src/socbridge_driver.vhd | 45 +++++++------- src/socbridge_driver_tb.vhd | 102 ++++++++++++++++++++++++++------ src/socbridge_driver_tb_pkg.vhd | 4 +- 3 files changed, 110 insertions(+), 41 deletions(-) diff --git a/src/socbridge_driver.vhd b/src/socbridge_driver.vhd index c6f2cbb..9261c85 100644 --- a/src/socbridge_driver.vhd +++ b/src/socbridge_driver.vhd @@ -75,7 +75,6 @@ begin begin -- Outputs ext_out <= create_io_type_out_from_ext_protocol(st.ext_out_reg); - int_in.payload <= st.ext_in_reg.data; --- State Transition Diagram --- @@ -136,7 +135,6 @@ begin end if; when TX_BODY => -- Here we want to stay in TX_BODY for the duration of a packet. - -- Right now, we transfer one single word at a time for simplicity if st.write_stage = 0 then next_state <= TX_ACK; else @@ -152,7 +150,7 @@ begin when RX_HEADER => -- The header only takes one word (cycle) to transmit. -- Continue to awaiting response directly afterwards. - if st.cmd_reg = WRITE_ADD then + if st.cmd_reg = READ_ADD then next_state <= ADDR1; else next_state <= RX_RESPONSE; @@ -160,15 +158,21 @@ begin when RX_RESPONSE => -- Wait for read response. if curr_response = READ_RESPONSE then - next_state <= RX_BODY; + 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. - -- Right now, we receive only one single word at a time for simplicity - next_state <= IDLE; + 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; @@ -178,7 +182,7 @@ begin if st.cmd_reg = WRITE or st.cmd_reg = WRITE_ADD then next_state <= TX_BODY; else - next_state <= RX_BODY; + next_state <= RX_RESPONSE; end if; end case; @@ -186,6 +190,7 @@ begin 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 @@ -207,12 +212,16 @@ begin else ext_out_data_cmd := (others => '0'); end if; - when TX_ACK => when RX_HEADER => - ext_out_data_cmd := get_cmd_bits(st.cmd_reg) & get_size_bits(cmd_size); + 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 => @@ -220,8 +229,10 @@ begin when ADDR3 => ext_out_data_cmd := st.addr_reg(31 downto 24); when ADDR4 => - int_in.is_full_out <= '0'; - ext_out_data_cmd := int_out.payload; + 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 --- @@ -259,21 +270,13 @@ begin st.cmd_reg <= cmd; end if; when TX_HEADER => - if st.cmd_reg = WRITE_ADD then - st.write_stage <= 2**(cmd_size - 1) - 1; - else - st.write_stage <= 2**(cmd_size - 1) - 1; - end if; + 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 => - if st.cmd_reg = READ_ADD then - st.read_stage <= 2**(cmd_size - 1); - else - st.read_stage <= 2**(cmd_size - 1) - 1; - end if; + st.read_stage <= 2**(cmd_size - 1) - 1; when RX_BODY => if st.read_stage > 0 then st.read_stage <= st.read_stage - 1; diff --git a/src/socbridge_driver_tb.vhd b/src/socbridge_driver_tb.vhd index e99093b..ae74ab4 100644 --- a/src/socbridge_driver_tb.vhd +++ b/src/socbridge_driver_tb.vhd @@ -145,24 +145,8 @@ begin expected_out <= "00000000"; check_next_state(TX_ACK); wait for CLK_PERIOD; - expected_out <= "00000000"; check_next_state(IDLE); - wait for CLK_PERIOD; - expected_out <= "00000000"; - check_next_state(IDLE); - wait for CLK_PERIOD; - expected_out <= "00000000"; - check_next_state(IDLE); - wait for CLK_PERIOD; - expected_out <= "00000000"; - check_next_state(IDLE); - wait for CLK_PERIOD; - expected_out <= "00000000"; - check_next_state(IDLE); - wait for CLK_PERIOD; - expected_out <= "00000000"; - check_next_state(IDLE); - wait for CLK_PERIOD; + wait for CLK_PERIOD * 6; expected_out <= "00000000"; check_next_state(IDLE); wait for CLK_PERIOD /4; @@ -187,8 +171,61 @@ begin 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; @@ -207,6 +244,16 @@ begin 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; @@ -230,8 +277,27 @@ begin curr_word <= "00001001"; wait for CLK_PERIOD; curr_word <= "00000000"; - wait for CLK_PERIOD * 10; + 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; diff --git a/src/socbridge_driver_tb_pkg.vhd b/src/socbridge_driver_tb_pkg.vhd index 19b7b7a..11acdf6 100644 --- a/src/socbridge_driver_tb_pkg.vhd +++ b/src/socbridge_driver_tb_pkg.vhd @@ -16,9 +16,9 @@ package socbridge_driver_tb_pkg is (NO_OP, WRITE_ACK, READ_RESPONSE); type state_t is - (IDLE, ADDR1, ADDR2, ADDR3, ADDR4, + (IDLE, ADDR1, ADDR2, ADDR3, ADDR4, TX_HEADER, TX_BODY, TX_ACK, - RX_HEADER, RX_RESPONSE, RX_BODY); + 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); -- 2.43.0