diff --git a/libraries/base/axi4/hdllib.cfg b/libraries/base/axi4/hdllib.cfg index 0442544293e42ee951e51c3ca99afec5a46b4fe0..de3bb46728c4e63e9006c041dc27488eb626778a 100644 --- a/libraries/base/axi4/hdllib.cfg +++ b/libraries/base/axi4/hdllib.cfg @@ -9,12 +9,10 @@ synth_files = src/vhdl/axi4_stream_pkg.vhd src/vhdl/axi4_stream_dp_bridge.vhd src/vhdl/axi4_lite_mm_bridge.vhd - src/vhdl/mem_to_axi4_lite.vhd test_bench_files = tb/vhdl/tb_axi4_stream_dp_bridge.vhd tb/vhdl/tb_tb_axi4_stream_dp_bridge.vhd - tb/vhdl/tb_axi4_lite_ram.vhd regression_test_vhdl = tb/vhdl/tb_tb_axi4_stream_dp_bridge.vhd diff --git a/libraries/base/axi4/src/vhdl/axi4_lite_pkg.vhd b/libraries/base/axi4/src/vhdl/axi4_lite_pkg.vhd index 4244b7262e211540fc2b99b821a4826dc09faeff..67581a53840baeb58ff8734b0aae5e75eff79358 100644 --- a/libraries/base/axi4/src/vhdl/axi4_lite_pkg.vhd +++ b/libraries/base/axi4/src/vhdl/axi4_lite_pkg.vhd @@ -83,16 +83,6 @@ PACKAGE axi4_lite_pkg IS rvalid : std_logic; -- read valid END RECORD; - TYPE t_register_address IS RECORD - base_address : NATURAL; - address : NATURAL; - offset : NATURAL; - width : NATURAL; - name : STRING(1 TO c_max_string); - END RECORD; - - TYPE t_register_address_array IS ARRAY (INTEGER RANGE <>) OF t_register_address; - CONSTANT c_axi4_lite_copi_rst : t_axi4_lite_copi := ((OTHERS=>'0'), (OTHERS=>'0'), '0', (OTHERS=>'0'), (OTHERS=>'0'), '0', '0', (OTHERS=>'0'), (OTHERS=>'0'), '0', '0'); CONSTANT c_axi4_lite_cipo_rst : t_axi4_lite_cipo := ('0', '0', (OTHERS=>'0'), '0', '0', (OTHERS=>'0'), (OTHERS=>'0'), '0'); @@ -105,635 +95,8 @@ PACKAGE axi4_lite_pkg IS CONSTANT c_axi4_lite_resp_slverr : STD_LOGIC_VECTOR(c_axi4_lite_resp_w-1 DOWNTO 0) := "10"; -- peripheral error CONSTANT c_axi4_lite_resp_decerr : STD_LOGIC_VECTOR(c_axi4_lite_resp_w-1 DOWNTO 0) := "11"; -- decode error - - -- Resize functions to fit an integer or an SLV in the corresponding t_axi4_lite_cipo or t_axi4_lite_copi field width - FUNCTION TO_AXI4_LITE_ADDRESS(n : INTEGER) RETURN STD_LOGIC_VECTOR; -- unsigned, use integer to support 32 bit range - FUNCTION TO_AXI4_LITE_DATA( n : INTEGER) RETURN STD_LOGIC_VECTOR; -- unsigned, alias of TO_AXI4_LITE_DATA() - FUNCTION TO_AXI4_LITE_UDATA( n : INTEGER) RETURN STD_LOGIC_VECTOR; -- unsigned, use integer to support 32 bit range - FUNCTION TO_AXI4_LITE_SDATA( n : INTEGER) RETURN STD_LOGIC_VECTOR; -- sign extended - FUNCTION RESIZE_AXI4_LITE_ADDRESS(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; -- unsigned - FUNCTION RESIZE_AXI4_LITE_DATA( vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; -- unsigned, alias of RESIZE_AXI4_LITE_UDATA - FUNCTION RESIZE_AXI4_LITE_UDATA( vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; -- unsigned - FUNCTION RESIZE_AXI4_LITE_SDATA( vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; -- sign extended - FUNCTION RESIZE_AXI4_LITE_XDATA( vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; -- set unused MSBits to 'X' - - - CONSTANT c_axi4_lite_reg_rd_latency : NATURAL := 0; - CONSTANT c_axi4_lite_reg : t_c_mem := (latency => c_axi4_lite_reg_rd_latency, - adr_w => 1, - dat_w => 32, - nof_dat => 1, - init_sl => 'X'); - - CONSTANT c_axi4_lite_reg_init_w : NATURAL := 1*256*32; -- >= largest expected value of dat_w*nof_dat (256 * 32 bit = 1k byte) - - CONSTANT c_mask_ones : t_slv_32_arr(0 TO 0) := (OTHERS => (OTHERS => '1')); - CONSTANT c_mask_zeros : t_slv_32_arr(0 TO 0) := (OTHERS => (OTHERS => '0')); - - FUNCTION pad(str: STRING; width: NATURAL; pad_char: CHARACTER) RETURN STRING; - FUNCTION pad(str: STRING) RETURN STRING; - FUNCTION strip(str: STRING) RETURN STRING; - - --PROCEDURE axi_lite_blockwrite (SIGNAL mm_clk : IN STD_LOGIC; - -- SIGNAL axi_cipo : IN t_axi4_lite_cipo; - -- SIGNAL axi_copi : OUT t_axi4_lite_copi; - -- register_addr : NATURAL; - -- dataFileName : STRING; - -- name : STRING := pad(""); - -- expected_fail : BOOLEAN := false; - -- fail_on_error : BOOLEAN := false); - - -- Multiple variants of the same function - PROCEDURE axi_lite_transaction (SIGNAL mm_clk : IN STD_LOGIC; SIGNAL axi_cipo : IN t_axi4_lite_cipo; SIGNAL axi_copi : OUT t_axi4_lite_copi; register_addr : NATURAL; write_reg : BOOLEAN; data : t_slv_32_arr; validate : boolean := false; mask : t_slv_32_arr := c_mask_zeros; expected_fail : BOOLEAN := false; fail_on_error : BOOLEAN := false); - - PROCEDURE axi_lite_transaction (SIGNAL mm_clk : IN STD_LOGIC; SIGNAL axi_cipo : IN t_axi4_lite_cipo; SIGNAL axi_copi : OUT t_axi4_lite_copi; register_addr : t_register_address; write_reg : BOOLEAN; data : t_slv_32_arr; validate : boolean := false; mask : t_slv_32_arr := c_mask_zeros; expected_fail : BOOLEAN := false; fail_on_error : BOOLEAN := false); - PROCEDURE axi_lite_transaction (SIGNAL mm_clk : IN STD_LOGIC; SIGNAL axi_cipo : IN t_axi4_lite_cipo; SIGNAL axi_copi : OUT t_axi4_lite_copi; register_addr : t_register_address; write_reg : BOOLEAN; data : STD_LOGIC_VECTOR(c_axi4_lite_data_w-1 DOWNTO 0); validate : boolean := false; mask : STD_LOGIC_VECTOR(c_axi4_lite_data_w-1 DOWNTO 0) := (OTHERS => '0'); expected_fail : BOOLEAN := false; fail_on_error : BOOLEAN := false); - - -- Base function - PROCEDURE axi_lite_transaction (SIGNAL mm_clk : IN STD_LOGIC; - SIGNAL axi_cipo : IN t_axi4_lite_cipo; - SIGNAL axi_copi : OUT t_axi4_lite_copi; - register_addr : NATURAL; - write_reg : BOOLEAN; - data : STD_LOGIC_VECTOR(c_axi4_lite_data_w-1 DOWNTO 0); - validate : boolean := false; - mask : STD_LOGIC_VECTOR(c_axi4_lite_data_w-1 DOWNTO 0) := (OTHERS => '0'); - offset : NATURAL := 0; - width : NATURAL := 32; - name : STRING := pad(""); - expected_fail : BOOLEAN := false; - fail_on_error : BOOLEAN := false); - - PROCEDURE axi_lite_init (SIGNAL mm_rst : IN STD_LOGIC; SIGNAL mm_clk : IN STD_LOGIC; SIGNAL axi_cipo : IN t_axi4_lite_cipo; SIGNAL axi_copi : OUT t_axi4_lite_copi); - --PROCEDURE axi_lite_wait (SIGNAL mm_clk : IN STD_LOGIC; SIGNAL axi_cipo : IN t_axi4_lite_cipo; SIGNAL axi_copi : OUT t_axi4_lite_copi; register_addr : t_register_address; data : STD_LOGIC_VECTOR(c_axi4_lite_data_w-1 DOWNTO 0); fail_on_error : BOOLEAN := TRUE); - - END axi4_lite_pkg; PACKAGE BODY axi4_lite_pkg IS - FUNCTION pad(str: STRING; width: NATURAL; pad_char: CHARACTER) RETURN STRING IS - VARIABLE v_str : STRING(1 TO width) := (OTHERS => pad_char); - BEGIN - v_str(width-str'LENGTH+1 TO width) := str; - RETURN v_str; - END; - - FUNCTION pad(str: STRING) RETURN STRING IS - VARIABLE v_str : STRING(1 TO c_max_string) := (OTHERS => ' '); - BEGIN - v_str(1 TO str'LENGTH) := str; - RETURN v_str; - END; - - FUNCTION strip(str: STRING) RETURN STRING IS - BEGIN - FOR i IN str'REVERSE_RANGE LOOP - IF str(i) /= ' ' THEN - RETURN str(1 TO i); - END IF; - END LOOP; - RETURN str; - END; - - -- Resize functions to fit an integer or an SLV in the corresponding t_axi4_lite_cipo or t_axi4_lite_copi field width - FUNCTION TO_AXI4_LITE_ADDRESS(n : INTEGER) RETURN STD_LOGIC_VECTOR IS - BEGIN - RETURN RESIZE_UVEC(TO_SVEC(n, 32), c_axi4_lite_address_w); - END TO_AXI4_LITE_ADDRESS; - - FUNCTION TO_AXI4_LITE_DATA(n : INTEGER) RETURN STD_LOGIC_VECTOR IS - BEGIN - RETURN TO_AXI4_LITE_UDATA(n); - END TO_AXI4_LITE_DATA; - - FUNCTION TO_AXI4_LITE_UDATA(n : INTEGER) RETURN STD_LOGIC_VECTOR IS - BEGIN - RETURN RESIZE_UVEC(TO_SVEC(n, 32), c_axi4_lite_data_w); - END TO_AXI4_LITE_UDATA; - - FUNCTION TO_AXI4_LITE_SDATA(n : INTEGER) RETURN STD_LOGIC_VECTOR IS - BEGIN - RETURN RESIZE_SVEC(TO_SVEC(n, 32), c_axi4_lite_data_w); - END TO_AXI4_LITE_SDATA; - - FUNCTION RESIZE_AXI4_LITE_ADDRESS(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS - BEGIN - RETURN RESIZE_UVEC(vec, c_axi4_lite_address_w); - END RESIZE_AXI4_LITE_ADDRESS; - - FUNCTION RESIZE_AXI4_LITE_DATA(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS - BEGIN - RETURN RESIZE_AXI4_LITE_UDATA(vec); - END RESIZE_AXI4_LITE_DATA; - - FUNCTION RESIZE_AXI4_LITE_UDATA(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS - BEGIN - RETURN RESIZE_UVEC(vec, c_axi4_lite_data_w); - END RESIZE_AXI4_LITE_UDATA; - - FUNCTION RESIZE_AXI4_LITE_SDATA(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS - BEGIN - RETURN RESIZE_SVEC(vec, c_axi4_lite_data_w); - END RESIZE_AXI4_LITE_SDATA; - - FUNCTION RESIZE_AXI4_LITE_XDATA(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS - VARIABLE v_vec : STD_LOGIC_VECTOR(c_axi4_lite_data_w-1 DOWNTO 0) := (OTHERS=>'X'); - BEGIN - v_vec(vec'LENGTH-1 DOWNTO 0) := vec; - RETURN v_vec; - END RESIZE_AXI4_LITE_XDATA; - - - ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ - PROCEDURE axi_lite_init (SIGNAL mm_rst : IN STD_LOGIC; - SIGNAL mm_clk : IN STD_LOGIC; - SIGNAL axi_cipo : IN t_axi4_lite_cipo; - SIGNAL axi_copi : OUT t_axi4_lite_copi) is - - BEGIN - - axi_copi <= c_axi4_lite_copi_rst; - - -- wait for reset to be released - WAIT UNTIL to_x01(mm_rst) = '0'; - WAIT UNTIL rising_edge(mm_clk); - WAIT UNTIL rising_edge(mm_clk); - - END PROCEDURE; - - - - ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ - PROCEDURE axi_lite_transaction (SIGNAL mm_clk : IN STD_LOGIC; - SIGNAL axi_cipo : IN t_axi4_lite_cipo; - SIGNAL axi_copi : OUT t_axi4_lite_copi; - register_addr : NATURAL; - write_reg : BOOLEAN; - data : t_slv_32_arr; - validate : BOOLEAN := false; - mask : t_slv_32_arr := c_mask_zeros; - expected_fail : BOOLEAN := false; - fail_on_error : BOOLEAN := false) is - - VARIABLE mask_unit : STD_LOGIC_VECTOR(31 DOWNTO 0); - BEGIN - data_write_loop: FOR i IN data'RANGE LOOP - - IF mask'LENGTH = data'LENGTH THEN - mask_unit := mask(i); - ELSE - mask_unit := mask(0); - END IF; - - axi_lite_transaction(mm_clk, axi_cipo, axi_copi, register_addr+i, write_reg, data(i), validate, mask_unit, 0, 32, pad(""), expected_fail, fail_on_error); - END LOOP; - END PROCEDURE; - - ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ - PROCEDURE axi_lite_transaction (SIGNAL mm_clk : IN STD_LOGIC; - SIGNAL axi_cipo : IN t_axi4_lite_cipo; - SIGNAL axi_copi : OUT t_axi4_lite_copi; - register_addr : t_register_address; - write_reg : BOOLEAN; - data : t_slv_32_arr; - validate : BOOLEAN := false; - mask : t_slv_32_arr := c_mask_zeros; - expected_fail : BOOLEAN := false; - fail_on_error : BOOLEAN := false) is - - VARIABLE mask_unit : STD_LOGIC_VECTOR(31 DOWNTO 0); - BEGIN - data_write_loop: FOR i IN data'RANGE LOOP - - IF mask'LENGTH = data'LENGTH THEN - mask_unit := mask(i); - ELSE - mask_unit := mask(0); - END IF; - - axi_lite_transaction(mm_clk, axi_cipo, axi_copi, register_addr.base_address+register_addr.address+i, write_reg, data(i), validate, mask_unit, register_addr.offset, register_addr.width, register_addr.name, expected_fail, fail_on_error); - END LOOP; - END PROCEDURE; - - ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ - PROCEDURE axi_lite_transaction (SIGNAL mm_clk : IN STD_LOGIC; - SIGNAL axi_cipo : IN t_axi4_lite_cipo; - SIGNAL axi_copi : OUT t_axi4_lite_copi; - register_addr : t_register_address; - write_reg : BOOLEAN; - data : STD_LOGIC_VECTOR(c_axi4_lite_data_w-1 DOWNTO 0); - validate : BOOLEAN := false; - mask : STD_LOGIC_VECTOR(c_axi4_lite_data_w-1 DOWNTO 0) := (OTHERS => '0'); - expected_fail : BOOLEAN := false; - fail_on_error : BOOLEAN := false) is - - BEGIN - axi_lite_transaction(mm_clk, axi_cipo, axi_copi, register_addr.base_address+register_addr.address, write_reg, data, validate, mask, register_addr.offset, register_addr.width, register_addr.name, expected_fail, fail_on_error); - END PROCEDURE; - - - - - ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ - PROCEDURE axi_lite_transaction (SIGNAL mm_clk : IN STD_LOGIC; - SIGNAL axi_cipo : IN t_axi4_lite_cipo; - SIGNAL axi_copi : OUT t_axi4_lite_copi; - register_addr : NATURAL; - write_reg : BOOLEAN; - data : STD_LOGIC_VECTOR(c_axi4_lite_data_w-1 DOWNTO 0); - validate : BOOLEAN := false; - mask : STD_LOGIC_VECTOR(c_axi4_lite_data_w-1 DOWNTO 0) := (OTHERS => '0'); - offset : NATURAL := 0; - width : NATURAL := 32; - name : STRING := pad(""); - expected_fail : BOOLEAN := false; - fail_on_error : BOOLEAN := false) is - - VARIABLE stdio : line; - VARIABLE result : STD_LOGIC_VECTOR(31 DOWNTO 0); - BEGIN - - -- Start transaction - WAIT UNTIL rising_edge(mm_clk); - - IF write_reg = false THEN - -- Setup read address - axi_copi.arvalid <= '1'; - axi_copi.araddr <= std_logic_vector(to_unsigned(register_addr*4, 32)); - axi_copi.rready <= '1'; - - read_address_wait: LOOP - WAIT UNTIL rising_edge(mm_clk); - IF axi_cipo.arready = '1' THEN - axi_copi.arvalid <= '0'; - axi_copi.araddr <= (OTHERS => '0'); - END IF; - - IF axi_cipo.rvalid = '1' THEN - EXIT; - END IF; - END LOOP; - - - write(stdio, string'("INFO: AXI Lite read of register ")); - IF name(1) /= ' ' THEN - write(stdio, strip(name)); - ELSE - write(stdio, (register_addr)); - END IF; - write(stdio, string'(" returned ")); - - -- Read response - IF axi_cipo.rresp = "00" THEN - write(stdio, string'("OK ")); - ELSIF axi_cipo.rresp = "01" THEN - write(stdio, string'("exclusive access error ")); - ELSIF axi_cipo.rresp = "10" THEN - write(stdio, string'("peripheral error ")); - ELSIF axi_cipo.rresp = "11" THEN - write(stdio, string'("address decode error ")); - END IF; - - write(stdio, string'("with data 0x")); - hwrite(stdio, axi_cipo.rdata(offset+width-1 DOWNTO offset)); - writeline(output, stdio); - - IF validate = TRUE THEN - IF (axi_cipo.rdata(offset+width-1 DOWNTO offset) AND mask(width-1 DOWNTO 0)) /= (data(width-1 DOWNTO 0) AND mask(width-1 DOWNTO 0) ) THEN - IF expected_fail THEN - write(stdio, string'("INFO (Expected Error)")); - ELSE - write(stdio, string'("ERROR")); - END IF; - write(stdio, string'(": Return data doesn't match mask")); - writeline(output, stdio); - ASSERT NOT(fail_on_error) REPORT "Return data doesn't match mask" SEVERITY ERROR; - END IF; - END IF; - - WAIT UNTIL rising_edge(mm_clk); - axi_copi.rready <= '0'; - ELSE - - -- Needs to actually do a read first to perform a RMW on the shared fields - axi_copi.arvalid <= '1'; - axi_copi.araddr <= std_logic_vector(to_unsigned(register_addr*4, 32)); - axi_copi.rready <= '1'; - - rmw_address_wait: LOOP - WAIT UNTIL rising_edge(mm_clk); - IF axi_cipo.arready = '1' THEN - axi_copi.arvalid <= '0'; - axi_copi.araddr <= (OTHERS => '0'); - EXIT; - END IF; - END LOOP; - - rmw_response_wait: WHILE axi_cipo.rvalid = '0' LOOP - WAIT UNTIL rising_edge(mm_clk); - END LOOP; - - result := axi_cipo.rdata; - - IF axi_cipo.rresp /= "00" THEN - IF expected_fail THEN - write(stdio, string'("INFO (Expected Error)")); - ELSE - write(stdio, string'("ERROR")); - END IF; - write(stdio, string'(": Failure to read during write of register ")); - IF name(1) /= ' ' THEN - write(stdio, strip(name)); - ELSE - write(stdio, (register_addr)); - END IF; - write(stdio, string'(" got ")); - write(stdio, to_integer(unsigned(axi_cipo.rresp))); - writeline(output, stdio); - ASSERT NOT(fail_on_error and not expected_fail) REPORT "Failure to read during write of register" SEVERITY ERROR; - END IF; - - WAIT UNTIL rising_edge(mm_clk); - axi_copi.rready <= '0'; - - -- Setup write address, data, & reponse ready - axi_copi.awvalid <= '1'; - axi_copi.awaddr <= std_logic_vector(to_unsigned(register_addr*4, 32)); - axi_copi.bready <= '1'; - axi_copi.wvalid <= '1'; - - FOR i IN 0 TO 31 LOOP - IF (i >= offset) and (i < (offset+width)) THEN - axi_copi.wdata(i) <= (result(i) AND mask(i-offset)) OR data(i-offset); - ELSE - axi_copi.wdata(i) <= result(i); - END IF; - END LOOP; - - axi_copi.wstrb <= X"f"; - - write_address_wait: LOOP - WAIT UNTIL rising_edge(mm_clk); - - IF axi_cipo.wready = '1' THEN - axi_copi.wvalid <= '0'; - END IF; - - IF axi_cipo.awready = '1' THEN - axi_copi.awvalid <= '0'; - axi_copi.awaddr <= (OTHERS => '0'); - END IF; - - IF axi_cipo.awready = '1' AND axi_cipo.wready = '1' THEN - EXIT; - END IF; - END LOOP; - - response_wait: WHILE axi_cipo.bvalid = '0' LOOP - WAIT UNTIL rising_edge(mm_clk); - END LOOP; - - IF axi_cipo.bresp = "00" THEN - write(stdio, string'("INFO")); - ELSE - IF expected_fail THEN - write(stdio, string'("INFO (Expected Error)")); - ELSE - write(stdio, string'("ERROR")); - END IF; - END IF; - - write(stdio, string'(": AXI Lite write of register ")); - IF name(1) /= ' ' THEN - write(stdio, strip(name)); - ELSE - write(stdio, (register_addr)); - END IF; - write(stdio, string'(" returned ")); - - -- Print response - IF axi_cipo.bresp = "00" THEN - write(stdio, string'("OK")); - ELSIF axi_cipo.bresp = "01" THEN - write(stdio, string'("exclusive access error ")); - ASSERT NOT(fail_on_error and not expected_fail) REPORT "AXI LIte error code exclusive access error" SEVERITY ERROR; - ELSIF axi_cipo.bresp = "10" THEN - write(stdio, string'("peripheral error ")); - ASSERT NOT(fail_on_error and not expected_fail) REPORT "AXI LIte error code peripheral error" SEVERITY ERROR; - ELSIF axi_cipo.bresp = "11" THEN - write(stdio, string'("address decode error ")); - ASSERT NOT(fail_on_error and not expected_fail) REPORT "AXI LIte error code address decode error" SEVERITY ERROR; - END IF; - - writeline(output, stdio); - - WAIT UNTIL rising_edge(mm_clk); - axi_copi.bready <= '0'; - END IF; - - END PROCEDURE; - - ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ - -- Write a block of values from a file starting at a given address. - PROCEDURE axi_lite_blockwrite (SIGNAL mm_clk : IN STD_LOGIC; - SIGNAL axi_cipo : IN t_axi4_lite_cipo; - SIGNAL axi_copi : OUT t_axi4_lite_copi; - register_addr : NATURAL; - dataFileName : STRING; - name : STRING := pad(""); - expected_fail : BOOLEAN := false; - fail_on_error : BOOLEAN := false) is - - VARIABLE stdio : line; - VARIABLE result : STD_LOGIC_VECTOR(31 DOWNTO 0); - variable wrData : std_logic_vector(31 downto 0); - variable wrCount : natural := 0; -- which word we are up to - file dataFile : TEXT; - variable lineIn : line; - variable good : boolean; - - BEGIN - - FILE_OPEN(dataFile,dataFileName,READ_MODE); - - while (not endfile(dataFile)) loop - - -- Get the data to write - readline(dataFile, lineIn); - - while (not endfile(dataFile)) and ((lineIn'length = 0) or (lineIn(lineIn'left) = '#')) loop - readline(dataFile, lineIn); -- skip empty lines or lines starting with a comment character ('#') - end loop; - if endfile(dataFile) and ((lineIn'length = 0) or (lineIn(lineIn'left) = '#')) then - exit; - end if; - hread(lineIn,wrData,good); - assert good - report "text IO Read error" severity ERROR; - - -- Start transaction - WAIT UNTIL rising_edge(mm_clk); - axi_copi.rready <= '0'; - - -- Setup write address, data, & response ready - axi_copi.awvalid <= '1'; - axi_copi.awaddr <= std_logic_vector(to_unsigned((register_addr + wrCount)*4, 32)); - axi_copi.bready <= '1'; - axi_copi.wvalid <= '1'; - axi_copi.wdata <= wrData; - axi_copi.wstrb <= X"f"; - - write_address_wait: LOOP - WAIT UNTIL rising_edge(mm_clk); - - IF axi_cipo.wready = '1' THEN - axi_copi.wvalid <= '0'; - END IF; - - IF axi_cipo.awready = '1' THEN - axi_copi.awvalid <= '0'; - axi_copi.awaddr <= (OTHERS => '0'); - END IF; - - IF axi_cipo.awready = '1' AND axi_cipo.wready = '1' THEN - EXIT; - END IF; - END LOOP; - - response_wait: WHILE axi_cipo.bvalid = '0' LOOP - WAIT UNTIL rising_edge(mm_clk); - END LOOP; - - IF axi_cipo.bresp /= "00" THEN - - IF expected_fail THEN - write(stdio, string'("INFO (Expected Error)")); - ELSE - write(stdio, string'("ERROR")); - END IF; - - write(stdio, string'(": AXI Lite write of register ")); - IF name(1) /= ' ' THEN - write(stdio, strip(name)); - ELSE - write(stdio, (register_addr)); - END IF; - write(stdio, string'(" returned ")); - - -- Print response - IF axi_cipo.bresp = "00" THEN - write(stdio, string'("OK")); - ELSIF axi_cipo.bresp = "01" THEN - write(stdio, string'("exclusive access error ")); - ASSERT NOT(fail_on_error and not expected_fail) REPORT "AXI LIte error code exclusive access error" SEVERITY ERROR; - ELSIF axi_cipo.bresp = "10" THEN - write(stdio, string'("peripheral error ")); - ASSERT NOT(fail_on_error and not expected_fail) REPORT "AXI LIte error code peripheral error" SEVERITY ERROR; - ELSIF axi_cipo.bresp = "11" THEN - write(stdio, string'("address decode error ")); - ASSERT NOT(fail_on_error and not expected_fail) REPORT "AXI LIte error code address decode error" SEVERITY ERROR; - END IF; - - writeline(output, stdio); - - end if; - - WAIT UNTIL rising_edge(mm_clk); - axi_copi.bready <= '0'; - - wrCount := wrCount + 1; - - end loop; - - END PROCEDURE; - - ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ - PROCEDURE axi_lite_wait (SIGNAL mm_clk : IN STD_LOGIC; - SIGNAL axi_cipo : IN t_axi4_lite_cipo; - SIGNAL axi_copi : OUT t_axi4_lite_copi; - register_addr : t_register_address; - data : STD_LOGIC_VECTOR(c_axi4_lite_data_w-1 DOWNTO 0); - fail_on_error : BOOLEAN := TRUE) is - - VARIABLE response : STD_LOGIC_VECTOR(1 DOWNTO 0); - VARIABLE stdio : LINE; - VARIABLE timeout : INTEGER := 100000; -- 100K iteration limit, about 50M clocks - BEGIN - - wait_loop: LOOP - -- Start transaction - WAIT UNTIL rising_edge(mm_clk); - - - -- Setup read address - axi_copi.arvalid <= '1'; - axi_copi.araddr <= std_logic_vector(to_unsigned((register_addr.base_address+register_addr.address)*4, 32)); - axi_copi.rready <= '1'; - - read_address_wait: LOOP - WAIT UNTIL rising_edge(mm_clk); - IF axi_cipo.arready = '1' THEN - axi_copi.arvalid <= '0'; - axi_copi.araddr <= (OTHERS => '0'); - END IF; - - IF axi_cipo.rvalid = '1' THEN - EXIT; - END IF; - END LOOP; - - response := axi_cipo.rresp; - - IF (axi_cipo.rdata(register_addr.offset+register_addr.width-1 DOWNTO register_addr.offset) = data(register_addr.width-1 DOWNTO 0)) OR response /= "00" THEN - EXIT; - END IF; - - WAIT UNTIL rising_edge(mm_clk); - axi_copi.rready <= '0'; - - delay_loop: FOR i IN 0 TO 500 LOOP - WAIT UNTIL rising_edge(mm_clk); - END LOOP; - timeout := timeout - 1; - IF timeout = 0 THEN - EXIT; - END IF; - END LOOP; - - IF timeout = 0 THEN - write(stdio, string'("ERROR: AXI Lite wait on register ")); - write(stdio, strip(register_addr.name)); - write(stdio, string'("failed")); - ASSERT not fail_on_error REPORT "AXI LIte wait timed out" SEVERITY ERROR; - ELSE - - write(stdio, string'("INFO: AXI Lite wait on register ")); - write(stdio, strip(register_addr.name)); - - write(stdio, string'(" completed with response ")); - - IF response = "00" THEN - write(stdio, string'("OK ")); - ELSIF response = "01" THEN - write(stdio, string'("exclusive access error ")); - ELSIF response = "10" THEN - write(stdio, string'("peripheral error ")); - ELSIF response = "11" THEN - write(stdio, string'("address decode error ")); - END IF; - END IF; - - - writeline(output, stdio); - END PROCEDURE; - - END axi4_lite_pkg; diff --git a/libraries/base/axi4/src/vhdl/mem_to_axi4_lite.vhd b/libraries/base/axi4/src/vhdl/mem_to_axi4_lite.vhd deleted file mode 100644 index 5cb460b2f77e7d4ac23295d093935ad74e057d28..0000000000000000000000000000000000000000 --- a/libraries/base/axi4/src/vhdl/mem_to_axi4_lite.vhd +++ /dev/null @@ -1,213 +0,0 @@ -------------------------------------------------------------------------------- --- --- Copyright 2023 --- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> --- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands --- --- Licensed under the Apache License, Version 2.0 (the "License"); --- you may not use this file except in compliance with the License. --- You may obtain a copy of the License at --- --- http://www.apache.org/licenses/LICENSE-2.0 --- --- Unless required by applicable law or agreed to in writing, software --- distributed under the License is distributed on an "AS IS" BASIS, --- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --- See the License for the specific language governing permissions and --- limitations under the License. --- -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- --- Author : R vd Walle --- Purpose: --- Translate AXI4-Lite to standard memory interface --- Description: --- Ported from: --- https://git.astron.nl/desp/gemini/-/blob/master/libraries/base/axi4/src/vhdl/mem_to_axi4_lite.vhd -------------------------------------------------------------------------------- - -LIBRARY IEEE, common_lib; -USE IEEE.STD_LOGIC_1164.ALL; -USE IEEE.NUMERIC_STD.ALL; -USE common_lib.common_pkg.ALL; -USE common_lib.common_mem_pkg.ALL; -USE work.axi4_lite_pkg.ALL; - -ENTITY mem_to_axi4_lite IS - GENERIC ( - g_adr_w : NATURAL := 8; - g_dat_w : NATURAL := 32; - g_timeout : NATURAL := 6); -- 2^clocks for transaction timeout. Needs to be longer than 3* slowest clock on AXI bus - - PORT ( - rst : IN STD_LOGIC; -- reset synchronous with mm_clk - clk : IN STD_LOGIC; -- memory-mapped bus clock - - -- Memory Mapped Peripheral in mm_clk domain - axi4_lite_in : IN t_axi4_lite_copi; - axi4_lite_out : OUT t_axi4_lite_cipo; - - wren : OUT STD_LOGIC; - rden : OUT STD_LOGIC; - - wr_adr : OUT STD_LOGIC_VECTOR(g_adr_w-1 DOWNTO 0); - wr_dat : OUT STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0); - rd_adr : OUT STD_LOGIC_VECTOR(g_adr_w-1 DOWNTO 0); - rd_dat : IN STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0); - rd_busy : IN STD_LOGIC; - rd_val : IN STD_LOGIC; - wr_busy : IN STD_LOGIC; - wr_val : IN STD_LOGIC); -END mem_to_axi4_lite; - - -ARCHITECTURE str OF mem_to_axi4_lite IS - - SIGNAL i_axi4_lite_out : t_axi4_lite_cipo; - - SIGNAL write_pending : STD_LOGIC := '0'; - SIGNAL write_counter : UNSIGNED(g_timeout-1 DOWNTO 0); - SIGNAL write_trans_valid : STD_LOGIC; - SIGNAL i_wren_d : STD_LOGIC; - SIGNAL i_wren : STD_LOGIC; - - SIGNAL read_pending : STD_LOGIC := '0'; - SIGNAL read_counter : UNSIGNED(g_timeout-1 DOWNTO 0); - SIGNAL read_trans_valid : STD_LOGIC; - SIGNAL i_rden : STD_LOGIC; - SIGNAL i_rden_d : STD_LOGIC; - - SIGNAL rresp : STD_LOGIC_VECTOR(1 DOWNTO 0); - SIGNAL rresp_r : STD_LOGIC_VECTOR(1 DOWNTO 0); - -BEGIN - - - axi4_lite_out <= i_axi4_lite_out; - - ---------------------------------------------------------------------------- --- Write Channel -- ---------------------------------------------------------------------------- - - - write_timeout: PROCESS(clk) - BEGIN - IF rising_edge(clk) THEN - i_wren_d <= i_wren; - - IF write_pending = '0' THEN - IF axi4_lite_in.awvalid = '1' AND wr_busy = '0' THEN - write_counter <= (OTHERS => '1'); - write_pending <= '1'; - END IF; - ELSE - -- Once the whole transaction is complete release pending and allow next - IF i_axi4_lite_out.bvalid = '1' AND axi4_lite_in.bready = '1' THEN - write_pending <= '0'; - ELSE - write_counter <= write_counter - 1; - END IF; - END IF; - END IF; - END PROCESS; - - write_trans_valid <= '1' WHEN write_pending = '1' AND (write_counter = 0 OR wr_val = '1') ELSE '0'; - - -- Assert ready after the transaction has been (or should have been) acknowledged - i_axi4_lite_out.wready <= write_trans_valid; - i_axi4_lite_out.awready <= write_trans_valid; - - -- Write when data path and address path are valid (make it a single clock for neatness) - i_wren <= axi4_lite_in.wvalid AND axi4_lite_in.awvalid AND NOT wr_busy; - wren <= i_wren AND NOT i_wren_d; - - wr_adr <= axi4_lite_in.awaddr(g_adr_w+1 DOWNTO 2); -- Correct for byte addressing, ARSG uses dword addressing - wr_dat <= axi4_lite_in.wdata(g_dat_w-1 DOWNTO 0); - - -- Need to latch response code in case ready is asserted on response bus - write_response_latch: PROCESS(CLK) - BEGIN - IF RISING_EDGE(CLK) THEN - IF RST = '1' THEN - i_axi4_lite_out.bvalid <= '0'; - ELSE - IF i_axi4_lite_out.bvalid = '1' THEN - IF axi4_lite_in.bready = '1' THEN - i_axi4_lite_out.bvalid <= '0'; - END IF; - ELSE - IF write_trans_valid = '1' THEN - i_axi4_lite_out.bvalid <= '1'; - IF wr_val = '1' THEN - i_axi4_lite_out.bresp <= c_axi4_lite_resp_okay; - ELSE - i_axi4_lite_out.bresp <= c_axi4_lite_resp_slverr; - END IF; - END IF; - END IF; - END IF; - END IF; - END PROCESS; - ---------------------------------------------------------------------------- --- Read Channel -- ---------------------------------------------------------------------------- - - read_timeout: PROCESS(clk) - BEGIN - IF RISING_EDGE(clk) THEN - i_rden_d <= i_rden; - - IF read_pending = '0' THEN - IF axi4_lite_in.arvalid = '1' AND rd_busy = '0' THEN - read_counter <= (OTHERS => '1'); - read_pending <= '1'; - END IF; - ELSE - IF read_trans_valid = '1' THEN - read_pending <= '0'; - ELSE - read_counter <= read_counter - 1; - END IF; - END IF; - END IF; - END PROCESS; - - read_trans_valid <= '1' WHEN read_pending = '1' and (read_counter = 0 or rd_val = '1') ELSE '0'; - - -- Acknowledge read when response is ready - i_axi4_lite_out.arready <= read_trans_valid; - - -- Map read address bus - rd_adr <= axi4_lite_in.araddr(g_adr_w+1 DOWNTO 2); - - -- Read Enable when address is valid - i_rden <= read_pending; - rden <= i_rden and not(i_rden_d); - - -- Assert data valid after the transaction has been (or should have been) acknowledged - i_axi4_lite_out.rvalid <= read_trans_valid; - i_axi4_lite_out.rdata(g_dat_w-1 DOWNTO 0) <= rd_dat; - - -- If the address was decoded return OK otherwise error. Need to latch status as AXI clock - -- crossing IP for AXI4Lite assumes values are static after the valid is deasserted - - rresp <= c_axi4_lite_resp_okay WHEN rd_val = '1' ELSE - c_axi4_lite_resp_slverr; - - u_pipe_rresp : ENTITY common_lib.common_pipeline - GENERIC MAP ( - g_pipeline => 1, - g_in_dat_w => 2, - g_out_dat_w => 2) - PORT MAP ( - clk => clk, - clken => read_trans_valid, - in_dat => rresp, - out_dat => rresp_r); - - i_axi4_lite_out.rresp <= rresp WHEN read_trans_valid = '1' ELSE rresp_r; - -END str; diff --git a/libraries/base/axi4/tb/vhdl/tb_axi4_lite_ram.vhd b/libraries/base/axi4/tb/vhdl/tb_axi4_lite_ram.vhd deleted file mode 100644 index 295b8d0fdcfff5abbd1b8be9cc75612e23cdc820..0000000000000000000000000000000000000000 --- a/libraries/base/axi4/tb/vhdl/tb_axi4_lite_ram.vhd +++ /dev/null @@ -1,184 +0,0 @@ -------------------------------------------------------------------------------- --- --- Copyright 2023 --- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> --- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands --- --- Licensed under the Apache License, Version 2.0 (the "License"); --- you may not use this file except in compliance with the License. --- You may obtain a copy of the License at --- --- http://www.apache.org/licenses/LICENSE-2.0 --- --- Unless required by applicable law or agreed to in writing, software --- distributed under the License is distributed on an "AS IS" BASIS, --- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --- See the License for the specific language governing permissions and --- limitations under the License. --- -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- --- Author : R vd Walle --- Purpose: --- TB for testing mem_to_axi4_lite using common_ram_crw_crw --- Description: --- Ported from: --- https://git.astron.nl/desp/gemini/-/blob/master/libraries/base/axi4/tb/vhdl/tb_axi4_lite_ram.vhd -------------------------------------------------------------------------------- - -LIBRARY IEEE, common_lib; -USE IEEE.std_logic_1164.ALL; -USE IEEE.numeric_std.ALL; -USE IEEE.std_logic_textio.ALL; -USE STD.textio.ALL; -USE common_lib.common_pkg.ALL; -USE common_lib.common_mem_pkg.ALL; -USE work.axi4_lite_pkg.ALL; - -ENTITY tb_axi4_lite_ram IS -END tb_axi4_lite_ram; - -ARCHITECTURE tb OF tb_axi4_lite_ram IS - - CONSTANT c_mm_clk_period : TIME := 40 ns; - CONSTANT c_usr_clk_period : TIME := 10 ns; - CONSTANT c_reset_len : NATURAL := 16; - - CONSTANT c_dat_w : INTEGER := 32; - CONSTANT c_adr_w : INTEGER := 8; - - CONSTANT c_mm_usr_ram : t_c_mem := (latency => 1, - c_adr_w => 5, - c_dat_w => 8, - nof_dat => 32, - init_sl => '0'); - - CONSTANT c_ram_addr_base : NATURAL := to_integer(shift_right(to_unsigned(0, 32), ceil_log2(c_mm_usr_ram.nof_dat))) ; - - SIGNAL mm_rst : STD_LOGIC; - SIGNAL mm_clk : STD_LOGIC := '0'; - SIGNAL usr_rst : STD_LOGIC; - SIGNAL usr_clk : STD_LOGIC := '0'; - SIGNAL sim_finished : STD_LOGIC := '0'; - SIGNAL tb_end : STD_LOGIC := '0'; - - SIGNAL rd_dat : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); - SIGNAL wr_dat : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); - SIGNAL wr_val : STD_LOGIC; - SIGNAL rd_val : STD_LOGIC; - SIGNAL reg_wren : STD_LOGIC; - SIGNAL reg_rden : STD_LOGIC; - SIGNAL wr_adr : STD_LOGIC_VECTOR(c_adr_w-1 DOWNTO 0); - SIGNAL rd_adr : STD_LOGIC_VECTOR(c_adr_w-1 DOWNTO 0); - - SIGNAL ram_wr_en : STD_LOGIC; - SIGNAL ram_rd_en : STD_LOGIC; - SIGNAL ram_adr : STD_LOGIC_VECTOR(c_mm_usr_ram.c_adr_w-1 DOWNTO 0); - SIGNAL ram_rd_dat : STD_LOGIC_VECTOR(c_mm_usr_ram.c_dat_w-1 DOWNTO 0); - - SIGNAL axi_copi : t_axi4_lite_copi; - SIGNAL axi_cipo : t_axi4_lite_cipo; - -BEGIN - - mm_clk <= NOT mm_clk OR sim_finished AFTER c_mm_clk_period/2; - mm_rst <= '1', '0' AFTER c_mm_clk_period*c_reset_len; - - usr_clk <= NOT usr_clk OR sim_finished AFTER c_usr_clk_period/2; - usr_rst <= '1', '0' AFTER c_usr_clk_period*c_reset_len; - - u_mem_to_axi4_lite : ENTITY work.mem_to_axi4_lite - GENERIC MAP ( - g_c_adr_w => c_adr_w, - g_c_dat_w => c_dat_w) - PORT MAP ( - rst => mm_rst, - clk => mm_clk, - axi4_lite_in => axi_copi, - axi4_lite_out => axi_cipo, - wren => reg_wren, - rden => reg_rden, - wr_adr => wr_adr, - wr_dat => wr_dat, - wr_val => wr_val, - wr_busy => '0', - rd_adr => rd_adr, - rd_dat => rd_dat, - rd_busy => '0', - rd_val => rd_val - ); - - ram_wr_en <= reg_wren AND is_true(c_ram_addr_base = UNSIGNED(wr_adr(wr_adr'LENGTH-1 DOWNTO c_mm_usr_ram.c_adr_w))); - ram_rd_en <= reg_rden AND is_true(c_ram_addr_base = UNSIGNED(rd_adr(rd_adr'LENGTH-1 DOWNTO c_mm_usr_ram.c_adr_w))); - - ram_adr <= wr_adr(c_mm_usr_ram.c_adr_w-1 DOWNTO 0) WHEN ram_wr_en = '1' ELSE rd_adr(c_mm_usr_ram.c_adr_w-1 DOWNTO 0); - - u_ram : ENTITY common_lib.common_ram_crw_crw - GENERIC MAP ( - g_ram => c_mm_usr_ram, - g_true_dual_port => TRUE) - PORT MAP ( - rst_a => mm_rst, - rst_b => usr_rst, - clk_a => mm_clk, - clk_b => usr_clk, - clken_a => '1', - clken_b => '1', - wr_en_a => ram_wr_en, - wr_dat_a => wr_dat(c_mm_usr_ram.c_dat_w-1 DOWNTO 0), - adr_a => ram_adr, - rd_en_a => ram_rd_en, - rd_dat_a => ram_rd_dat, - rd_val_a => rd_val, - wr_en_b => '0', - wr_dat_b => X"00", - adr_b => "00000", - rd_en_b => '0', - rd_dat_b => OPEN, - rd_val_b => OPEN - ); - - u_ram_wr_val : ENTITY common_lib.common_pipeline - GENERIC MAP ( - g_pipeline => c_mm_usr_ram.latency, - g_in_c_dat_w => 1, - g_out_c_dat_w => 1 - ) - PORT MAP ( - clk => mm_clk, - clken => '1', - in_dat(0) => ram_wr_en, - out_dat(0) => wr_val - ); - - rd_dat <= RESIZE_UVEC(ram_rd_dat, c_dat_w) WHEN rd_val = '1' ELSE (OTHERS => '0'); - - -- Testbench writes a number of words to memory and then reads them back trough the AXI interface. - -- It uses the axi_lite_transaction to write, read and verify the data. - tb : PROCESS - VARIABLE data_in : t_slv_32_arr(0 TO 10); - BEGIN - axi_lite_init (mm_rst, mm_clk, axi_cipo, axi_copi); - - -- Read and write a number of words to memory - FOR i IN 0 TO 10 LOOP - data_in(i) := std_logic_vector(to_unsigned(57+i, 32)); - END LOOP; - axi_lite_transaction (mm_clk, axi_cipo, axi_copi, 0, true, data_in, mask => c_mask_zeros); - - - FOR i IN 0 TO 10 LOOP - data_in(i) := std_logic_vector(to_unsigned(57+i, 32)); - END LOOP; - axi_lite_transaction (mm_clk, axi_cipo, axi_copi, 0, false, data_in, validate => true); - - - - sim_finished <= '1'; - tb_end <= '1'; - WAIT FOR 1 us; - REPORT "Finished Simulation" SEVERITY FAILURE; - WAIT; - END PROCESS tb; -END tb;