From 2149c1ec685611da035efa1669ce228a57b7059d 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] 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;