From 99b2e5e6da4e0ba6af6274534bb5ef395cdd2407 Mon Sep 17 00:00:00 2001 From: David Martin Date: Mon, 13 May 2024 14:57:57 +0200 Subject: [PATCH 01/24] Added axi master with equally powerful implementation as axi lite master has --- .../src/axi_master.vhd | 225 ++++++++ .../src/axi_master_pkg.vhd | 165 ++++++ .../test/tb_axi_master.vhd | 507 ++++++++++++++++++ 3 files changed, 897 insertions(+) create mode 100644 vunit/vhdl/verification_components/src/axi_master.vhd create mode 100644 vunit/vhdl/verification_components/src/axi_master_pkg.vhd create mode 100644 vunit/vhdl/verification_components/test/tb_axi_master.vhd diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd new file mode 100644 index 000000000..3bf91988d --- /dev/null +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -0,0 +1,225 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2024, Lars Asplund lars.anders.asplund@gmail.com + + +library ieee; +use ieee.std_logic_1164.all; + +use work.axi_master_pkg.all; +use work.axi_pkg.all; +use work.axi_slave_private_pkg.check_axi_resp; +use work.bus_master_pkg.address_length; +use work.bus_master_pkg.bus_master_t; +use work.bus_master_pkg.byte_enable_length; +use work.bus_master_pkg.data_length; +use work.com_pkg.net; +use work.com_pkg.receive; +use work.com_pkg.reply; +use work.com_types_pkg.all; +use work.log_levels_pkg.all; +use work.logger_pkg.all; +use work.queue_pkg.all; +use work.sync_pkg.all; + +entity axi_master is + generic ( + bus_handle : bus_master_t; + drive_invalid : boolean := true; + drive_invalid_val : std_logic := 'X' + ); + port ( + aclk : in std_logic; + + arvalid : out std_logic := '0'; + arready : in std_logic; + arid : out std_logic_vector; + araddr : out std_logic_vector(address_length(bus_handle) - 1 downto 0) := (others => '0'); + arlen : out std_logic_vector; + arsize : out std_logic_vector; + arburst : out axi_burst_type_t; + + rvalid : in std_logic; + rready : out std_logic := '0'; + rid : in std_logic_vector; + rdata : in std_logic_vector(data_length(bus_handle) - 1 downto 0); + rresp : in axi_resp_t; + rlast : in std_logic; + + awvalid : out std_logic := '0'; + awready : in std_logic := '0'; + awid : out std_logic_vector; + awaddr : out std_logic_vector(address_length(bus_handle) - 1 downto 0) := (others => '0'); + awlen : out std_logic_vector; + awsize : out std_logic_vector; + awburst : out axi_burst_type_t; + + wvalid : out std_logic; + wready : in std_logic := '0'; + wdata : out std_logic_vector(data_length(bus_handle) - 1 downto 0) := (others => '0'); + wstrb : out std_logic_vector(byte_enable_length(bus_handle) - 1 downto 0) := (others => '0'); + wlast : out std_logic; + + bvalid : in std_logic; + bready : out std_logic := '0'; + bid : in std_logic_vector; + bresp : in axi_resp_t := axi_resp_okay + ); +end entity; + +architecture a of axi_master is + constant reply_queue, message_queue : queue_t := new_queue; + signal idle : boolean := true; +begin + + main : process + variable request_msg : msg_t; + variable msg_type : msg_type_t; + begin + receive(net, bus_handle.p_actor, request_msg); + msg_type := message_type(request_msg); + + if is_read(msg_type) or is_write(msg_type) then + push(message_queue, request_msg); + elsif msg_type = wait_until_idle_msg then + if not idle or not is_empty(message_queue) then + wait until idle and is_empty(message_queue) and rising_edge(aclk); + end if; + handle_wait_until_idle(net, msg_type, request_msg); + else + unexpected_msg_type(msg_type); + end if; + end process; + + -- Use separate process to always align to rising edge of clock + bus_process : process + procedure drive_ar_invalid is + begin + if drive_invalid then + araddr <= (araddr'range => drive_invalid_val); + end if; + end procedure; + + procedure drive_aw_invalid is + begin + if drive_invalid then + awaddr <= (awaddr'range => drive_invalid_val); + end if; + end procedure; + + procedure drive_w_invalid is + begin + if drive_invalid then + wdata <= (wdata'range => drive_invalid_val); + wstrb <= (wstrb'range => drive_invalid_val); + end if; + end procedure; + + variable request_msg : msg_t; + variable msg_type : msg_type_t; + variable expected_resp : axi_resp_t; + variable w_done, aw_done : boolean; + + -- These variables are needed to keep the values for logging when transaction is fully done + variable addr_this_transaction : std_logic_vector(awaddr'range) := (others => '0'); + variable wdata_this_transaction : std_logic_vector(wdata'range) := (others => '0'); + begin + -- Initialization + drive_ar_invalid; + drive_aw_invalid; + drive_w_invalid; + + loop + wait until rising_edge(aclk) and not is_empty(message_queue); + idle <= false; + wait for 0 ps; + + request_msg := pop(message_queue); + msg_type := message_type(request_msg); + + if is_read(msg_type) then + addr_this_transaction := pop_std_ulogic_vector(request_msg); + expected_resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; + push(reply_queue, request_msg); + + arvalid <= '1'; + araddr <= addr_this_transaction; + wait until (arvalid and arready) = '1' and rising_edge(aclk); + arvalid <= '0'; + drive_ar_invalid; + + rready <= '1'; + wait until (rvalid and rready) = '1' and rising_edge(aclk); + rready <= '0'; + check_axi_resp(bus_handle, rresp, expected_resp, "rresp"); + + if is_visible(bus_handle.p_logger, debug) then + debug(bus_handle.p_logger, + "Read 0x" & to_hstring(rdata) & + " from address 0x" & to_hstring(addr_this_transaction)); + end if; + + elsif is_write(msg_type) then + addr_this_transaction := pop_std_ulogic_vector(request_msg); + wdata_this_transaction := pop_std_ulogic_vector(request_msg); + wstrb <= pop_std_ulogic_vector(request_msg); + expected_resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; + delete(request_msg); + + awaddr <= addr_this_transaction; + wdata <= wdata_this_transaction; + + wvalid <= '1'; + awvalid <= '1'; + + w_done := false; + aw_done := false; + while not (w_done and aw_done) loop + wait until ((awvalid and awready) = '1' or (wvalid and wready) = '1') and rising_edge(aclk); + + if (awvalid and awready) = '1' then + awvalid <= '0'; + drive_aw_invalid; + + aw_done := true; + end if; + + if (wvalid and wready) = '1' then + wvalid <= '0'; + drive_w_invalid; + + w_done := true; + end if; + end loop; + + bready <= '1'; + wait until (bvalid and bready) = '1' and rising_edge(aclk); + bready <= '0'; + check_axi_resp(bus_handle, bresp, expected_resp, "bresp"); + + if is_visible(bus_handle.p_logger, debug) then + debug(bus_handle.p_logger, + "Wrote 0x" & to_hstring(wdata_this_transaction) & + " to address 0x" & to_hstring(addr_this_transaction)); + end if; + end if; + + idle <= true; + end loop; + end process; + + -- Reply in separate process do not destroy alignment with the clock + read_reply : process + variable request_msg, reply_msg : msg_t; + begin + wait until (rvalid and rready) = '1' and rising_edge(aclk); + request_msg := pop(reply_queue); + reply_msg := new_msg; + push_std_ulogic_vector(reply_msg, rdata); + reply(net, request_msg, reply_msg); + delete(request_msg); + end process; + +end architecture; diff --git a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd new file mode 100644 index 000000000..bc46f32eb --- /dev/null +++ b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd @@ -0,0 +1,165 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2024, Lars Asplund lars.anders.asplund@gmail.com + + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.axi_pkg.all; +use work.bus_master_pkg.all; +use work.com_pkg.send; +use work.com_types_pkg.all; +use work.logger_pkg.all; + +package axi_master_pkg is + + constant axi_read_msg : msg_type_t := new_msg_type("read axi "); + constant axi_write_msg : msg_type_t := new_msg_type("write axi "); + + -- Blocking: Write the bus + procedure write_axi(signal net : inout network_t; + constant bus_handle : bus_master_t; + constant address : std_logic_vector; + constant data : std_logic_vector; + constant expected_bresp : axi_resp_t := axi_resp_okay; + -- default byte enable is all bytes + constant byte_enable : std_logic_vector := ""); + + -- Non blocking: Read the bus returning a reference to the future reply + procedure read_axi(signal net : inout network_t; + constant bus_handle : bus_master_t; + constant address : std_logic_vector; + constant expected_rresp : axi_resp_t := axi_resp_okay; + variable reference : inout bus_reference_t); + + -- Blocking: read bus with immediate reply + procedure read_axi(signal net : inout network_t; + constant bus_handle : bus_master_t; + constant address : std_logic_vector; + constant expected_rresp : axi_resp_t := axi_resp_okay; + variable data : inout std_logic_vector); + + -- Blocking: Read bus and check result against expected data + procedure check_axi(signal net : inout network_t; + constant bus_handle : bus_master_t; + constant address : std_logic_vector; + constant expected_rresp : axi_resp_t := axi_resp_okay; + constant expected : std_logic_vector; + constant msg : string := ""); + + function is_read(msg_type : msg_type_t) return boolean; + function is_write(msg_type : msg_type_t) return boolean; + function is_axi_msg(msg_type : msg_type_t) return boolean; + +end package; + +package body axi_master_pkg is + + procedure write_axi(signal net : inout network_t; + constant bus_handle : bus_master_t; + constant address : std_logic_vector; + constant data : std_logic_vector; + constant expected_bresp : axi_resp_t := axi_resp_okay; + -- default byte enable is all bytes + constant byte_enable : std_logic_vector := "") is + variable request_msg : msg_t := new_msg(axi_write_msg); + variable full_data : std_logic_vector(bus_handle.p_data_length - 1 downto 0) := (others => '0'); + variable full_address : std_logic_vector(bus_handle.p_address_length - 1 downto 0) := (others => '0'); + variable full_byte_enable : std_logic_vector(byte_enable_length(bus_handle) - 1 downto 0); + begin + full_address(address'length - 1 downto 0) := address; + push_std_ulogic_vector(request_msg, full_address); + + full_data(data'length - 1 downto 0) := data; + push_std_ulogic_vector(request_msg, full_data); + + if byte_enable = "" then + full_byte_enable := (others => '1'); + else + full_byte_enable(byte_enable'length - 1 downto 0) := byte_enable; + end if; + push_std_ulogic_vector(request_msg, full_byte_enable); + + push_std_ulogic_vector(request_msg, expected_bresp); + + send(net, bus_handle.p_actor, request_msg); + end procedure; + + procedure read_axi(signal net : inout network_t; + constant bus_handle : bus_master_t; + constant address : std_logic_vector; + constant expected_rresp : axi_resp_t := axi_resp_okay; + variable reference : inout bus_reference_t) is + variable full_address : std_logic_vector(bus_handle.p_address_length - 1 downto 0) := (others => '0'); + alias request_msg : msg_t is reference; + begin + request_msg := new_msg(axi_read_msg); + full_address(address'length - 1 downto 0) := address; + push_std_ulogic_vector(request_msg, full_address); + push_std_ulogic_vector(request_msg, expected_rresp); + send(net, bus_handle.p_actor, request_msg); + end procedure; + + procedure read_axi(signal net : inout network_t; + constant bus_handle : bus_master_t; + constant address : std_logic_vector; + constant expected_rresp : axi_resp_t := axi_resp_okay; + variable data : inout std_logic_vector) is + variable reference : bus_reference_t; + begin + read_axi(net, bus_handle, address, expected_rresp, reference); + await_read_bus_reply(net, reference, data); + end procedure; + + procedure check_axi(signal net : inout network_t; + constant bus_handle : bus_master_t; + constant address : std_logic_vector; + constant expected_rresp : axi_resp_t := axi_resp_okay; + constant expected : std_logic_vector; + constant msg : string := "") is + variable data : std_logic_vector(bus_handle.p_data_length - 1 downto 0); + variable edata : std_logic_vector(data'range) := (others => '0'); + + impure function error_prefix return string is + begin + if msg = "" then + return "check_bus(x""" & to_hstring(address) & """)"; + else + return msg; + end if; + end; + + impure function base_error return string is + begin + return error_prefix & " - Got x""" & to_hstring(data) & """ expected x""" & to_hstring(edata) & """"; + end; + begin + + edata(expected'length - 1 downto 0) := expected; + + read_axi(net, bus_handle, address, expected_rresp, data); + if not std_match(data, edata) then + failure(bus_handle.p_logger, base_error); + end if; + end procedure; + + function is_read(msg_type : msg_type_t) return boolean is + begin + return msg_type = bus_read_msg or msg_type = axi_read_msg; + end function; + + function is_write(msg_type : msg_type_t) return boolean is + begin + return msg_type = bus_write_msg or msg_type = axi_write_msg; + end function; + + function is_axi_msg(msg_type : msg_type_t) return boolean is + begin + return msg_type = axi_read_msg or msg_type = axi_write_msg; + end function; + +end package body; diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd new file mode 100644 index 000000000..2cd4a3f9d --- /dev/null +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -0,0 +1,507 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2024, Lars Asplund lars.anders.asplund@gmail.com + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library vunit_lib; +context vunit_lib.vunit_context; +context work.com_context; + +use work.axi_pkg.all; +use work.bus_master_pkg.all; +use work.axi_master_pkg.all; + +library osvvm; +use osvvm.RandomPkg.all; + +entity tb_axi_master is + generic (runner_cfg : string); +end entity; + +architecture a of tb_axi_master is + constant num_random_tests : integer := 128; + + signal clk : std_logic := '0'; + + signal arvalid : std_logic; + signal arready : std_logic := '0'; + signal arid : std_logic_vector(7 downto 0); --TBD + signal araddr : std_logic_vector(31 downto 0); + signal arlen : std_logic_vector(7 downto 0); --TBD + signal arsize : std_logic_vector(7 downto 0); --TBD + signal arburst : axi_burst_type_t; --TBD + + signal rvalid : std_logic; + signal rready : std_logic := '0'; + signal rid : std_logic_vector(7 downto 0); --TBD + signal rdata : std_logic_vector(15 downto 0); + signal rresp : std_logic_vector(1 downto 0); + signal rlast : std_logic; + + signal awvalid : std_logic; + signal awready : std_logic := '0'; + signal awid : std_logic_vector(7 downto 0); --TBD + signal awaddr : std_logic_vector(31 downto 0); + signal awlen : std_logic_vector(7 downto 0); --TBD + signal awsize : std_logic_vector(7 downto 0); --TBD + signal awburst : axi_burst_type_t; --TBD + + signal wvalid : std_logic; + signal wready : std_logic := '0'; + signal wdata : std_logic_vector(15 downto 0); + signal wstrb : std_logic_vector(1 downto 0); + signal wlast : std_logic; + + signal bvalid : std_logic := '0'; + signal bready : std_logic; + signal bid : std_logic_vector(7 downto 0); --TBD + signal bresp : std_logic_vector(1 downto 0); + + constant bus_handle : bus_master_t := new_bus(data_length => wdata'length, + address_length => awaddr'length); + + signal start, done : boolean := false; +begin + + main : process + variable tmp : std_logic_vector(rdata'range); + variable rnd : RandomPType; + variable timestamp : time; + begin + test_runner_setup(runner, runner_cfg); + rnd.InitSeed("common_seed"); + start <= true; + wait for 0 ns; + + if run("Test single write") then + mock(get_logger(bus_handle), debug); + write_bus(net, bus_handle, x"01234567", x"1122"); + wait_until_idle(net, bus_handle); + check_only_log(get_logger(bus_handle), "Wrote 0x1122 to address 0x01234567", debug); + unmock(get_logger(bus_handle)); + + elsif run("Test single write with byte enable") then + write_bus(net, bus_handle, x"01234567", x"1122", byte_enable => "10"); + + elsif run("Test write not okay") then + write_bus(net, bus_handle, x"01234567", x"1122"); + + elsif run("Test write with axi resp") then + write_axi(net, bus_handle, x"01234567", x"1122", axi_resp_slverr); + + elsif run("Test write with wrong axi resp") then + write_axi(net, bus_handle, x"01234567", x"1122", axi_resp_decerr); + + elsif run("Test single read") then + mock(get_logger(bus_handle), debug); + read_bus(net, bus_handle, x"01234567", tmp); + check_equal(tmp, std_logic_vector'(x"5566"), "read data"); + check_only_log(get_logger(bus_handle), "Read 0x5566 from address 0x01234567", debug); + unmock(get_logger(bus_handle)); + + elsif run("Test read not okay") then + read_bus(net, bus_handle, x"01234567", tmp); + + elsif run("Test read with axi resp") then + read_axi(net, bus_handle, x"01234567", axi_resp_slverr, tmp); + + elsif run("Test read with wrong axi resp") then + read_axi(net, bus_handle, x"01234567", axi_resp_exokay, tmp); + + elsif run("Test random") then + for i in 0 to num_random_tests-1 loop + if rnd.RandInt(0, 1) = 0 then + read_bus(net, bus_handle, rnd.RandSlv(araddr'length), tmp); + check_equal(tmp, rnd.RandSlv(rdata'length), "read data"); + else + write_bus(net, bus_handle, rnd.RandSlv(awaddr'length), rnd.RandSlv(wdata'length)); + end if; + end loop; + + elsif run("Test random axi resp") then + for i in 0 to num_random_tests-1 loop + if rnd.RandInt(0, 1) = 0 then + read_axi(net, bus_handle, rnd.RandSlv(araddr'length), rnd.RandSlv(axi_resp_t'length), tmp); + check_equal(tmp, rnd.RandSlv(rdata'length), "read data"); + else + write_axi(net, bus_handle, rnd.RandSlv(awaddr'length), rnd.RandSlv(wdata'length), + rnd.RandSlv(axi_resp_t'length)); + end if; + end loop; + + elsif run("Test idle when idle") then + wait until rising_edge(clk); + write_bus(net, bus_handle, x"01234567", x"1122"); + wait for 0 ps; + timestamp := now; + wait_until_idle(net, bus_handle); + check(now > timestamp, "Write: First wait did not have to wait"); + timestamp := now; + wait_until_idle(net, bus_handle); + check_equal(timestamp, now, "Write: Second wait had to wait"); + + wait until rising_edge(clk); + read_bus(net, bus_handle, x"01234567", tmp); + timestamp := now; + wait_until_idle(net, bus_handle); + check_equal(timestamp, now, "Read: Second wait had to wait"); + + end if; + + wait for 100 ns; + + if not done then + wait until done; + end if; + + test_runner_cleanup(runner); + end process; + test_runner_watchdog(runner, 100 us); + + + support : process + variable rnd : RandomPType; + begin + rnd.InitSeed("common_seed"); + + wait until start; + + if enabled("Test single write") then + awready <= '1'; + wait until (awready and awvalid) = '1' and rising_edge(clk); + awready <= '0'; + check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); + + wready <= '1'; + wait until (wready and wvalid) = '1' and rising_edge(clk); + wready <= '0'; + check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); + check_equal(wstrb, std_logic_vector'("11"), "wstrb"); + + bvalid <= '1'; + bresp <= axi_resp_okay; + wait until (bready and bvalid) = '1' and rising_edge(clk); + bvalid <= '0'; + + done <= true; + + elsif enabled("Test single write with byte enable") then + awready <= '1'; + wait until (awready and awvalid) = '1' and rising_edge(clk); + awready <= '0'; + check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); + + wready <= '1'; + wait until (wready and wvalid) = '1' and rising_edge(clk); + wready <= '0'; + check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); + check_equal(wstrb, std_logic_vector'("10"), "wstrb"); + + bvalid <= '1'; + bresp <= axi_resp_okay; + wait until (bready and bvalid) = '1' and rising_edge(clk); + bvalid <= '0'; + + done <= true; + + elsif enabled("Test write not okay") then + awready <= '1'; + wait until (awready and awvalid) = '1' and rising_edge(clk); + awready <= '0'; + + wready <= '1'; + wait until (wready and wvalid) = '1' and rising_edge(clk); + wready <= '0'; + + bvalid <= '1'; + bresp <= axi_resp_slverr; + mock(bus_logger, failure); + wait until (bready and bvalid) = '1' and rising_edge(clk); + bvalid <= '0'; + wait until mock_queue_length > 0 for 0 ns; + check_only_log(bus_logger, "bresp - Got AXI response SLVERR(10) expected OKAY(00)", failure); + unmock(bus_logger); + + done <= true; + + elsif enabled("Test write with axi resp") then + awready <= '1'; + wait until (awready and awvalid) = '1' and rising_edge(clk); + awready <= '0'; + check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); + + wready <= '1'; + wait until (wready and wvalid) = '1' and rising_edge(clk); + wready <= '0'; + check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); + check_equal(wstrb, std_logic_vector'("11"), "wstrb"); + + bvalid <= '1'; + bresp <= axi_resp_slverr; + wait until (bready and bvalid) = '1' and rising_edge(clk); + bvalid <= '0'; + + done <= true; + + elsif enabled("Test write with wrong axi resp") then + awready <= '1'; + wait until (awready and awvalid) = '1' and rising_edge(clk); + awready <= '0'; + check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); + + wready <= '1'; + wait until (wready and wvalid) = '1' and rising_edge(clk); + wready <= '0'; + check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); + check_equal(wstrb, std_logic_vector'("11"), "wstrb"); + + bvalid <= '1'; + bresp <= axi_resp_exokay; + mock(bus_logger, failure); + wait until (bready and bvalid) = '1' and rising_edge(clk); + bvalid <= '0'; + wait until mock_queue_length > 0 for 0 ns; + check_only_log(bus_logger, "bresp - Got AXI response EXOKAY(01) expected DECERR(11)", failure); + unmock(bus_logger); + + done <= true; + + elsif enabled("Test single read") then + arready <= '1'; + wait until (arready and arvalid) = '1' and rising_edge(clk); + arready <= '0'; + check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); + + rvalid <= '1'; + rresp <= axi_resp_okay; + rdata <= x"5566"; + wait until (rready and rvalid) = '1' and rising_edge(clk); + rvalid <= '0'; + + done <= true; + + elsif enabled("Test read not okay") then + arready <= '1'; + wait until (arready and arvalid) = '1' and rising_edge(clk); + arready <= '0'; + + rvalid <= '1'; + rresp <= axi_resp_decerr; + rdata <= x"5566"; + mock(bus_logger, failure); + wait until (rready and rvalid) = '1' and rising_edge(clk); + rvalid <= '0'; + wait until mock_queue_length > 0 for 0 ns; + check_only_log(bus_logger, "rresp - Got AXI response DECERR(11) expected OKAY(00)", failure); + unmock(bus_logger); + + done <= true; + + elsif enabled("Test read with axi resp") then + arready <= '1'; + wait until (arready and arvalid) = '1' and rising_edge(clk); + arready <= '0'; + check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); + + rvalid <= '1'; + rresp <= axi_resp_slverr; + rdata <= x"0000"; + wait until (rready and rvalid) = '1' and rising_edge(clk); + rvalid <= '0'; + + done <= true; + + elsif enabled("Test read with wrong axi resp") then + arready <= '1'; + wait until (arready and arvalid) = '1' and rising_edge(clk); + arready <= '0'; + check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); + + rvalid <= '1'; + rresp <= axi_resp_decerr; + rdata <= x"0000"; + mock(bus_logger, failure); + wait until (rready and rvalid) = '1' and rising_edge(clk); + rvalid <= '0'; + wait until mock_queue_length > 0 for 0 ns; + check_only_log(bus_logger, "rresp - Got AXI response DECERR(11) expected EXOKAY(01)", failure); + unmock(bus_logger); + + done <= true; + + elsif enabled("Test random") then + for i in 0 to num_random_tests-1 loop + if rnd.RandInt(0, 1) = 0 then + arready <= '1'; + wait until (arready and arvalid) = '1' and rising_edge(clk); + arready <= '0'; + check_equal(araddr, rnd.RandSlv(araddr'length), "araddr"); + + rvalid <= '1'; + rresp <= axi_resp_okay; + rdata <= rnd.RandSlv(rdata'length); + wait until (rready and rvalid) = '1' and rising_edge(clk); + rvalid <= '0'; + else + awready <= '1'; + wait until (awready and awvalid) = '1' and rising_edge(clk); + awready <= '0'; + check_equal(awaddr, rnd.RandSlv(awaddr'length), "awaddr"); + + wready <= '1'; + wait until (wready and wvalid) = '1' and rising_edge(clk); + wready <= '0'; + check_equal(wdata, rnd.RandSlv(wdata'length), "wdata"); + check_equal(wstrb, std_logic_vector'("11"), "wstrb"); + + bvalid <= '1'; + bresp <= axi_resp_okay; + wait until (bready and bvalid) = '1' and rising_edge(clk); + bvalid <= '0'; + end if; + end loop; + done <= true; + + elsif enabled("Test random axi resp") then + for i in 0 to num_random_tests-1 loop + if rnd.RandInt(0, 1) = 0 then + arready <= '1'; + wait until (arready and arvalid) = '1' and rising_edge(clk); + arready <= '0'; + check_equal(araddr, rnd.RandSlv(araddr'length), "araddr"); + + rvalid <= '1'; + rresp <= rnd.RandSlv(axi_resp_t'length); + rdata <= rnd.RandSlv(rdata'length); + wait until (rready and rvalid) = '1' and rising_edge(clk); + rvalid <= '0'; + else + awready <= '1'; + wait until (awready and awvalid) = '1' and rising_edge(clk); + awready <= '0'; + check_equal(awaddr, rnd.RandSlv(awaddr'length), "awaddr"); + + wready <= '1'; + wait until (wready and wvalid) = '1' and rising_edge(clk); + wready <= '0'; + check_equal(wdata, rnd.RandSlv(wdata'length), "wdata"); + check_equal(wstrb, std_logic_vector'("11"), "wstrb"); + + bvalid <= '1'; + bresp <= rnd.RandSlv(axi_resp_t'length); + wait until (bready and bvalid) = '1' and rising_edge(clk); + bvalid <= '0'; + end if; + end loop; + done <= true; + + elsif enabled("Test idle when idle") then + wait until rising_edge(clk); + awready <= '1'; + wait until (awready and awvalid) = '1' and rising_edge(clk); + awready <= '0'; + check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); + + wait until rising_edge(clk); + wready <= '1'; + wait until (wready and wvalid) = '1' and rising_edge(clk); + wready <= '0'; + check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); + check_equal(wstrb, std_logic_vector'("11"), "wstrb"); + + wait until rising_edge(clk); + bvalid <= '1'; + bresp <= axi_resp_okay; + wait until (bready and bvalid) = '1' and rising_edge(clk); + bvalid <= '0'; + + wait until rising_edge(clk); + arready <= '1'; + wait until (arready and arvalid) = '1' and rising_edge(clk); + arready <= '0'; + check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); + + wait until rising_edge(clk); + rvalid <= '1'; + rresp <= axi_resp_okay; + rdata <= x"5566"; + wait until (rready and rvalid) = '1' and rising_edge(clk); + rvalid <= '0'; + + done <= true; + + end if; + end process; + + check_not_valid : process + constant a_addr_invalid_value : std_logic_vector(araddr'range) := (others => 'X'); + constant wdata_invalid_value : std_logic_vector(wdata'range) := (others => 'X'); + constant wstrb_invalid_value : std_logic_vector(wstrb'range) := (others => 'X'); + begin + wait until rising_edge(clk); + + -- All signals should be driven with 'X' when the channel is not valid + -- (R and B channels have no outputs from the VC, except for handshake). + + if not arvalid then + check_equal(araddr, a_addr_invalid_value, "ARADDR not X when ARVALID low"); + end if; + + if not awvalid then + check_equal(awaddr, a_addr_invalid_value, "AWADDR not X when AWVALID low"); + end if; + + if not wvalid then + check_equal(wdata, wdata_invalid_value, "WDATA not X when WVALID low"); + check_equal(wstrb, wstrb_invalid_value, "WSTRB not X when WVALID low"); + end if; + end process; + + dut : entity work.axi_master + generic map ( + bus_handle => bus_handle) + port map ( + aclk => clk, + + arvalid => arvalid, + arready => arready, + arid => arid, + araddr => araddr, + arlen => arlen, + arsize => arsize, + arburst => arburst, + + rvalid => rvalid, + rready => rready, + rid => rid, + rdata => rdata, + rresp => rresp, + rlast => rlast, + + awvalid => awvalid, + awready => awready, + awid => awid, + awaddr => awaddr, + awlen => awlen, + awsize => awsize, + awburst => awburst, + + wvalid => wvalid, + wready => wready, + wdata => wdata, + wstrb => wstrb, + wlast => wlast, + + bvalid => bvalid, + bready => bready, + bid => bid, + bresp => bresp); + + clk <= not clk after 5 ns; + +end architecture; From f8ef5b6a33c7ab65ebe798409de03500f2cd9bb4 Mon Sep 17 00:00:00 2001 From: David Martin Date: Thu, 16 May 2024 13:11:19 +0200 Subject: [PATCH 02/24] add awid to axi master --- .../src/axi_master.vhd | 1 + .../src/axi_master_pkg.vhd | 4 ++++ .../test/tb_axi_master.vhd | 21 +++++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index 3bf91988d..7a1688395 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -165,6 +165,7 @@ begin addr_this_transaction := pop_std_ulogic_vector(request_msg); wdata_this_transaction := pop_std_ulogic_vector(request_msg); wstrb <= pop_std_ulogic_vector(request_msg); + awid <= pop_std_ulogic_vector(request_msg); expected_resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; delete(request_msg); diff --git a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd index bc46f32eb..3d4fb6d5d 100644 --- a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd @@ -25,6 +25,7 @@ package axi_master_pkg is constant bus_handle : bus_master_t; constant address : std_logic_vector; constant data : std_logic_vector; + constant id : std_logic_vector := ""; constant expected_bresp : axi_resp_t := axi_resp_okay; -- default byte enable is all bytes constant byte_enable : std_logic_vector := ""); @@ -63,6 +64,7 @@ package body axi_master_pkg is constant bus_handle : bus_master_t; constant address : std_logic_vector; constant data : std_logic_vector; + constant id : std_logic_vector := ""; constant expected_bresp : axi_resp_t := axi_resp_okay; -- default byte enable is all bytes constant byte_enable : std_logic_vector := "") is @@ -84,6 +86,8 @@ package body axi_master_pkg is end if; push_std_ulogic_vector(request_msg, full_byte_enable); + push_std_ulogic_vector(request_msg, id); + push_std_ulogic_vector(request_msg, expected_bresp); send(net, bus_handle.p_actor, request_msg); diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index 2cd4a3f9d..43c0cd0d6 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -151,6 +151,9 @@ begin wait_until_idle(net, bus_handle); check_equal(timestamp, now, "Read: Second wait had to wait"); + elsif run("Test single write with id") then + write_axi(net, bus_handle, x"01234567", x"1122", x"25"); + end if; wait for 100 ns; @@ -434,7 +437,25 @@ begin rvalid <= '0'; done <= true; + elsif enabled("Test single write with id") then + awready <= '1'; + wait until (awready and awvalid) = '1' and rising_edge(clk); + awready <= '0'; + check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); + check_equal(awid, std_logic_vector'(x"25"), "awid"); + + wready <= '1'; + wait until (wready and wvalid) = '1' and rising_edge(clk); + wready <= '0'; + check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); + check_equal(wstrb, std_logic_vector'("11"), "wstrb"); + + bvalid <= '1'; + bresp <= axi_resp_okay; + wait until (bready and bvalid) = '1' and rising_edge(clk); + bvalid <= '0'; + done <= true; end if; end process; From 3c10753cbbe10c03506bd005d1dcee4c20b22348 Mon Sep 17 00:00:00 2001 From: David Martin Date: Thu, 16 May 2024 13:11:19 +0200 Subject: [PATCH 03/24] Added awid to axi master --- .../src/axi_master.vhd | 1 + .../src/axi_master_pkg.vhd | 4 ++++ .../test/tb_axi_master.vhd | 21 +++++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index 3bf91988d..7a1688395 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -165,6 +165,7 @@ begin addr_this_transaction := pop_std_ulogic_vector(request_msg); wdata_this_transaction := pop_std_ulogic_vector(request_msg); wstrb <= pop_std_ulogic_vector(request_msg); + awid <= pop_std_ulogic_vector(request_msg); expected_resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; delete(request_msg); diff --git a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd index bc46f32eb..3d4fb6d5d 100644 --- a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd @@ -25,6 +25,7 @@ package axi_master_pkg is constant bus_handle : bus_master_t; constant address : std_logic_vector; constant data : std_logic_vector; + constant id : std_logic_vector := ""; constant expected_bresp : axi_resp_t := axi_resp_okay; -- default byte enable is all bytes constant byte_enable : std_logic_vector := ""); @@ -63,6 +64,7 @@ package body axi_master_pkg is constant bus_handle : bus_master_t; constant address : std_logic_vector; constant data : std_logic_vector; + constant id : std_logic_vector := ""; constant expected_bresp : axi_resp_t := axi_resp_okay; -- default byte enable is all bytes constant byte_enable : std_logic_vector := "") is @@ -84,6 +86,8 @@ package body axi_master_pkg is end if; push_std_ulogic_vector(request_msg, full_byte_enable); + push_std_ulogic_vector(request_msg, id); + push_std_ulogic_vector(request_msg, expected_bresp); send(net, bus_handle.p_actor, request_msg); diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index 2cd4a3f9d..43c0cd0d6 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -151,6 +151,9 @@ begin wait_until_idle(net, bus_handle); check_equal(timestamp, now, "Read: Second wait had to wait"); + elsif run("Test single write with id") then + write_axi(net, bus_handle, x"01234567", x"1122", x"25"); + end if; wait for 100 ns; @@ -434,7 +437,25 @@ begin rvalid <= '0'; done <= true; + elsif enabled("Test single write with id") then + awready <= '1'; + wait until (awready and awvalid) = '1' and rising_edge(clk); + awready <= '0'; + check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); + check_equal(awid, std_logic_vector'(x"25"), "awid"); + + wready <= '1'; + wait until (wready and wvalid) = '1' and rising_edge(clk); + wready <= '0'; + check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); + check_equal(wstrb, std_logic_vector'("11"), "wstrb"); + + bvalid <= '1'; + bresp <= axi_resp_okay; + wait until (bready and bvalid) = '1' and rising_edge(clk); + bvalid <= '0'; + done <= true; end if; end process; From 656437f73ca166d927314049a6f640c841334a1f Mon Sep 17 00:00:00 2001 From: David Martin Date: Thu, 16 May 2024 14:05:27 +0200 Subject: [PATCH 04/24] Addid arid to axi master --- .../src/axi_master.vhd | 3 ++ .../src/axi_master_pkg.vhd | 11 +++++-- .../test/tb_axi_master.vhd | 29 ++++++++++++++++--- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index 7a1688395..d36463625 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -99,6 +99,7 @@ begin begin if drive_invalid then araddr <= (araddr'range => drive_invalid_val); + arid <= (arid'range => drive_invalid_val); end if; end procedure; @@ -106,6 +107,7 @@ begin begin if drive_invalid then awaddr <= (awaddr'range => drive_invalid_val); + awid <= (arid'range => drive_invalid_val); end if; end procedure; @@ -141,6 +143,7 @@ begin if is_read(msg_type) then addr_this_transaction := pop_std_ulogic_vector(request_msg); + arid <= pop_std_ulogic_vector(request_msg); expected_resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; push(reply_queue, request_msg); diff --git a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd index 3d4fb6d5d..d05a4d7da 100644 --- a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd @@ -34,6 +34,7 @@ package axi_master_pkg is procedure read_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; + constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; variable reference : inout bus_reference_t); @@ -41,6 +42,7 @@ package axi_master_pkg is procedure read_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; + constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; variable data : inout std_logic_vector); @@ -48,6 +50,7 @@ package axi_master_pkg is procedure check_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; + constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; constant expected : std_logic_vector; constant msg : string := ""); @@ -96,6 +99,7 @@ package body axi_master_pkg is procedure read_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; + constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; variable reference : inout bus_reference_t) is variable full_address : std_logic_vector(bus_handle.p_address_length - 1 downto 0) := (others => '0'); @@ -104,6 +108,7 @@ package body axi_master_pkg is request_msg := new_msg(axi_read_msg); full_address(address'length - 1 downto 0) := address; push_std_ulogic_vector(request_msg, full_address); + push_std_ulogic_vector(request_msg, id); push_std_ulogic_vector(request_msg, expected_rresp); send(net, bus_handle.p_actor, request_msg); end procedure; @@ -111,17 +116,19 @@ package body axi_master_pkg is procedure read_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; + constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; variable data : inout std_logic_vector) is variable reference : bus_reference_t; begin - read_axi(net, bus_handle, address, expected_rresp, reference); + read_axi(net, bus_handle, address, id, expected_rresp, reference); await_read_bus_reply(net, reference, data); end procedure; procedure check_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; + constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; constant expected : std_logic_vector; constant msg : string := "") is @@ -145,7 +152,7 @@ package body axi_master_pkg is edata(expected'length - 1 downto 0) := expected; - read_axi(net, bus_handle, address, expected_rresp, data); + read_axi(net, bus_handle, address, id, expected_rresp, data); if not std_match(data, edata) then failure(bus_handle.p_logger, base_error); end if; diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index 43c0cd0d6..533a379c8 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -108,10 +108,10 @@ begin read_bus(net, bus_handle, x"01234567", tmp); elsif run("Test read with axi resp") then - read_axi(net, bus_handle, x"01234567", axi_resp_slverr, tmp); + read_axi(net, bus_handle, x"01234567", x"25", axi_resp_slverr, tmp); elsif run("Test read with wrong axi resp") then - read_axi(net, bus_handle, x"01234567", axi_resp_exokay, tmp); + read_axi(net, bus_handle, x"01234567", x"25", axi_resp_exokay, tmp); elsif run("Test random") then for i in 0 to num_random_tests-1 loop @@ -126,7 +126,7 @@ begin elsif run("Test random axi resp") then for i in 0 to num_random_tests-1 loop if rnd.RandInt(0, 1) = 0 then - read_axi(net, bus_handle, rnd.RandSlv(araddr'length), rnd.RandSlv(axi_resp_t'length), tmp); + read_axi(net, bus_handle, rnd.RandSlv(araddr'length), x"25", rnd.RandSlv(axi_resp_t'length), tmp); check_equal(tmp, rnd.RandSlv(rdata'length), "read data"); else write_axi(net, bus_handle, rnd.RandSlv(awaddr'length), rnd.RandSlv(wdata'length), @@ -153,6 +153,9 @@ begin elsif run("Test single write with id") then write_axi(net, bus_handle, x"01234567", x"1122", x"25"); + + elsif run("Test single read with id") then + read_axi(net, bus_handle, x"01234567", x"25", axi_resp_okay, tmp); end if; @@ -455,12 +458,28 @@ begin wait until (bready and bvalid) = '1' and rising_edge(clk); bvalid <= '0'; - done <= true; + done <= true; + + elsif enabled("Test single read with id") then + arready <= '1'; + wait until (arready and arvalid) = '1' and rising_edge(clk); + arready <= '0'; + check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); + check_equal(arid, std_logic_vector'(x"25"), "arid"); + + rvalid <= '1'; + rresp <= axi_resp_okay; + rdata <= x"5566"; + wait until (rready and rvalid) = '1' and rising_edge(clk); + rvalid <= '0'; + + done <= true; end if; end process; check_not_valid : process constant a_addr_invalid_value : std_logic_vector(araddr'range) := (others => 'X'); + constant a_id_invalid_value : std_logic_vector(arid'range) := (others => 'X'); constant wdata_invalid_value : std_logic_vector(wdata'range) := (others => 'X'); constant wstrb_invalid_value : std_logic_vector(wstrb'range) := (others => 'X'); begin @@ -471,10 +490,12 @@ begin if not arvalid then check_equal(araddr, a_addr_invalid_value, "ARADDR not X when ARVALID low"); + check_equal(arid, a_id_invalid_value, "ARID not X when ARVALID low"); end if; if not awvalid then check_equal(awaddr, a_addr_invalid_value, "AWADDR not X when AWVALID low"); + check_equal(awid, a_id_invalid_value, "AWID not X when ARVALID low"); end if; if not wvalid then From 7de251b22042001b38e21f4f3fc4d3b8655c15a9 Mon Sep 17 00:00:00 2001 From: David Martin Date: Thu, 16 May 2024 15:20:45 +0200 Subject: [PATCH 05/24] Added arlen to axi master --- .../src/axi_master.vhd | 2 ++ .../src/axi_master_pkg.vhd | 11 +++++-- .../test/tb_axi_master.vhd | 31 ++++++++++++++++--- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index d36463625..ca69dc116 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -99,6 +99,7 @@ begin begin if drive_invalid then araddr <= (araddr'range => drive_invalid_val); + arlen <= (arid'range => drive_invalid_val); arid <= (arid'range => drive_invalid_val); end if; end procedure; @@ -143,6 +144,7 @@ begin if is_read(msg_type) then addr_this_transaction := pop_std_ulogic_vector(request_msg); + arlen <= pop_std_ulogic_vector(request_msg); arid <= pop_std_ulogic_vector(request_msg); expected_resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; push(reply_queue, request_msg); diff --git a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd index d05a4d7da..026eb6cc5 100644 --- a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd @@ -34,6 +34,7 @@ package axi_master_pkg is procedure read_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; + constant len : std_logic_vector; constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; variable reference : inout bus_reference_t); @@ -42,6 +43,7 @@ package axi_master_pkg is procedure read_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; + constant len : std_logic_vector; constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; variable data : inout std_logic_vector); @@ -50,6 +52,7 @@ package axi_master_pkg is procedure check_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; + constant len : std_logic_vector; constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; constant expected : std_logic_vector; @@ -99,6 +102,7 @@ package body axi_master_pkg is procedure read_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; + constant len : std_logic_vector; constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; variable reference : inout bus_reference_t) is @@ -108,6 +112,7 @@ package body axi_master_pkg is request_msg := new_msg(axi_read_msg); full_address(address'length - 1 downto 0) := address; push_std_ulogic_vector(request_msg, full_address); + push_std_ulogic_vector(request_msg, len); push_std_ulogic_vector(request_msg, id); push_std_ulogic_vector(request_msg, expected_rresp); send(net, bus_handle.p_actor, request_msg); @@ -116,18 +121,20 @@ package body axi_master_pkg is procedure read_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; + constant len : std_logic_vector; constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; variable data : inout std_logic_vector) is variable reference : bus_reference_t; begin - read_axi(net, bus_handle, address, id, expected_rresp, reference); + read_axi(net, bus_handle, address, len, id, expected_rresp, reference); await_read_bus_reply(net, reference, data); end procedure; procedure check_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; + constant len : std_logic_vector; constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; constant expected : std_logic_vector; @@ -152,7 +159,7 @@ package body axi_master_pkg is edata(expected'length - 1 downto 0) := expected; - read_axi(net, bus_handle, address, id, expected_rresp, data); + read_axi(net, bus_handle, address, len, id, expected_rresp, data); if not std_match(data, edata) then failure(bus_handle.p_logger, base_error); end if; diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index 533a379c8..9ff514099 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -108,10 +108,10 @@ begin read_bus(net, bus_handle, x"01234567", tmp); elsif run("Test read with axi resp") then - read_axi(net, bus_handle, x"01234567", x"25", axi_resp_slverr, tmp); + read_axi(net, bus_handle, x"01234567", x"00", x"25", axi_resp_slverr, tmp); elsif run("Test read with wrong axi resp") then - read_axi(net, bus_handle, x"01234567", x"25", axi_resp_exokay, tmp); + read_axi(net, bus_handle, x"01234567", x"00", x"25", axi_resp_exokay, tmp); elsif run("Test random") then for i in 0 to num_random_tests-1 loop @@ -126,7 +126,7 @@ begin elsif run("Test random axi resp") then for i in 0 to num_random_tests-1 loop if rnd.RandInt(0, 1) = 0 then - read_axi(net, bus_handle, rnd.RandSlv(araddr'length), x"25", rnd.RandSlv(axi_resp_t'length), tmp); + read_axi(net, bus_handle, rnd.RandSlv(araddr'length), x"00", x"25", rnd.RandSlv(axi_resp_t'length), tmp); check_equal(tmp, rnd.RandSlv(rdata'length), "read data"); else write_axi(net, bus_handle, rnd.RandSlv(awaddr'length), rnd.RandSlv(wdata'length), @@ -155,8 +155,11 @@ begin write_axi(net, bus_handle, x"01234567", x"1122", x"25"); elsif run("Test single read with id") then - read_axi(net, bus_handle, x"01234567", x"25", axi_resp_okay, tmp); - + read_axi(net, bus_handle, x"01234567", x"00", x"25", axi_resp_okay, tmp); + + elsif run("Test single read with len") then + read_axi(net, bus_handle, x"01234567", x"12", x"25", axi_resp_okay, tmp); + end if; wait for 100 ns; @@ -474,11 +477,28 @@ begin rvalid <= '0'; done <= true; + + elsif enabled("Test single read with len") then + arready <= '1'; + wait until (arready and arvalid) = '1' and rising_edge(clk); + arready <= '0'; + check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); + check_equal(arlen, std_logic_vector'(x"12"), "arid"); + + rvalid <= '1'; + rresp <= axi_resp_okay; + rdata <= x"5566"; + wait until (rready and rvalid) = '1' and rising_edge(clk); + rvalid <= '0'; + + done <= true; + end if; end process; check_not_valid : process constant a_addr_invalid_value : std_logic_vector(araddr'range) := (others => 'X'); + constant a_len_invalid_value : std_logic_vector(arlen'range) := (others => 'X'); constant a_id_invalid_value : std_logic_vector(arid'range) := (others => 'X'); constant wdata_invalid_value : std_logic_vector(wdata'range) := (others => 'X'); constant wstrb_invalid_value : std_logic_vector(wstrb'range) := (others => 'X'); @@ -490,6 +510,7 @@ begin if not arvalid then check_equal(araddr, a_addr_invalid_value, "ARADDR not X when ARVALID low"); + check_equal(arlen, a_len_invalid_value, "ARLEN not X when ARVALID low"); check_equal(arid, a_id_invalid_value, "ARID not X when ARVALID low"); end if; From a17896630debac901ff74c267e6ece576c1a2ac0 Mon Sep 17 00:00:00 2001 From: David Martin Date: Fri, 17 May 2024 06:05:10 +0200 Subject: [PATCH 06/24] Added awlen to axi master --- .../src/axi_master.vhd | 1 + .../src/axi_master_pkg.vhd | 7 ++--- .../test/tb_axi_master.vhd | 27 +++++++++++++++++-- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index ca69dc116..8fdca82fb 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -170,6 +170,7 @@ begin addr_this_transaction := pop_std_ulogic_vector(request_msg); wdata_this_transaction := pop_std_ulogic_vector(request_msg); wstrb <= pop_std_ulogic_vector(request_msg); + awlen <= pop_std_ulogic_vector(request_msg); awid <= pop_std_ulogic_vector(request_msg); expected_resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; delete(request_msg); diff --git a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd index 026eb6cc5..18ca9058e 100644 --- a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd @@ -25,6 +25,7 @@ package axi_master_pkg is constant bus_handle : bus_master_t; constant address : std_logic_vector; constant data : std_logic_vector; + constant len : std_logic_vector; constant id : std_logic_vector := ""; constant expected_bresp : axi_resp_t := axi_resp_okay; -- default byte enable is all bytes @@ -70,6 +71,7 @@ package body axi_master_pkg is constant bus_handle : bus_master_t; constant address : std_logic_vector; constant data : std_logic_vector; + constant len : std_logic_vector; constant id : std_logic_vector := ""; constant expected_bresp : axi_resp_t := axi_resp_okay; -- default byte enable is all bytes @@ -90,12 +92,11 @@ package body axi_master_pkg is else full_byte_enable(byte_enable'length - 1 downto 0) := byte_enable; end if; - push_std_ulogic_vector(request_msg, full_byte_enable); + push_std_ulogic_vector(request_msg, full_byte_enable); + push_std_ulogic_vector(request_msg, len); push_std_ulogic_vector(request_msg, id); - push_std_ulogic_vector(request_msg, expected_bresp); - send(net, bus_handle.p_actor, request_msg); end procedure; diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index 9ff514099..8085de510 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -152,13 +152,16 @@ begin check_equal(timestamp, now, "Read: Second wait had to wait"); elsif run("Test single write with id") then - write_axi(net, bus_handle, x"01234567", x"1122", x"25"); + write_axi(net, bus_handle, x"01234567", x"1122", x"12", x"25"); elsif run("Test single read with id") then read_axi(net, bus_handle, x"01234567", x"00", x"25", axi_resp_okay, tmp); elsif run("Test single read with len") then - read_axi(net, bus_handle, x"01234567", x"12", x"25", axi_resp_okay, tmp); + read_axi(net, bus_handle, x"01234567", x"12", x"25", axi_resp_okay, tmp); + + elsif run("Test single write with len") then + write_axi(net, bus_handle, x"01234567", x"1122", x"12", x"25"); end if; @@ -493,6 +496,26 @@ begin done <= true; + elsif enabled("Test single write with len") then + awready <= '1'; + wait until (awready and awvalid) = '1' and rising_edge(clk); + awready <= '0'; + check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); + check_equal(awlen, std_logic_vector'(x"12"), "awlen"); + + wready <= '1'; + wait until (wready and wvalid) = '1' and rising_edge(clk); + wready <= '0'; + check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); + check_equal(wstrb, std_logic_vector'("11"), "wstrb"); + + bvalid <= '1'; + bresp <= axi_resp_okay; + wait until (bready and bvalid) = '1' and rising_edge(clk); + bvalid <= '0'; + + done <= true; + end if; end process; From a9707df91b9f5713033cb1a182c78bacaf6f794c Mon Sep 17 00:00:00 2001 From: David Martin Date: Fri, 17 May 2024 14:03:03 +0200 Subject: [PATCH 07/24] Added distinction between bus_msg and axi_msg --- .../src/axi_master.vhd | 18 +++++++-- .../src/axi_master_pkg.vhd | 38 +++++++++++++++++-- .../test/tb_axi_master.vhd | 6 +-- 3 files changed, 52 insertions(+), 10 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index 8fdca82fb..62e5513bd 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -128,6 +128,7 @@ begin -- These variables are needed to keep the values for logging when transaction is fully done variable addr_this_transaction : std_logic_vector(awaddr'range) := (others => '0'); variable wdata_this_transaction : std_logic_vector(wdata'range) := (others => '0'); + variable tmp : std_logic_vector(31 downto 0) := (others => '0'); begin -- Initialization drive_ar_invalid; @@ -144,8 +145,13 @@ begin if is_read(msg_type) then addr_this_transaction := pop_std_ulogic_vector(request_msg); - arlen <= pop_std_ulogic_vector(request_msg); - arid <= pop_std_ulogic_vector(request_msg); + + if(is_axi_msg(msg_type)) then + arlen <= pop_std_ulogic_vector(request_msg); + arid <= pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); + --tmp := pop_std_ulogic_vector(request_msg); + end if; + expected_resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; push(reply_queue, request_msg); @@ -170,8 +176,12 @@ begin addr_this_transaction := pop_std_ulogic_vector(request_msg); wdata_this_transaction := pop_std_ulogic_vector(request_msg); wstrb <= pop_std_ulogic_vector(request_msg); - awlen <= pop_std_ulogic_vector(request_msg); - awid <= pop_std_ulogic_vector(request_msg); + + if(is_axi_msg(msg_type)) then + awlen <= pop_std_ulogic_vector(request_msg); + awid <= pop_std_ulogic_vector(request_msg)(awid'length -1 downto 0); + end if; + expected_resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; delete(request_msg); diff --git a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd index 18ca9058e..9583a2e9c 100644 --- a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd @@ -63,6 +63,8 @@ package axi_master_pkg is function is_write(msg_type : msg_type_t) return boolean; function is_axi_msg(msg_type : msg_type_t) return boolean; + function len_length(bus_handle : bus_master_t) return natural; + function id_length(bus_handle : bus_master_t) return natural; end package; package body axi_master_pkg is @@ -80,6 +82,8 @@ package body axi_master_pkg is variable full_data : std_logic_vector(bus_handle.p_data_length - 1 downto 0) := (others => '0'); variable full_address : std_logic_vector(bus_handle.p_address_length - 1 downto 0) := (others => '0'); variable full_byte_enable : std_logic_vector(byte_enable_length(bus_handle) - 1 downto 0); + variable full_len : std_logic_vector(len_length(bus_handle) - 1 downto 0) := (others => '0'); + variable full_id : std_logic_vector(id_length(bus_handle) - 1 downto 0) := (others => '0'); begin full_address(address'length - 1 downto 0) := address; push_std_ulogic_vector(request_msg, full_address); @@ -92,10 +96,18 @@ package body axi_master_pkg is else full_byte_enable(byte_enable'length - 1 downto 0) := byte_enable; end if; - push_std_ulogic_vector(request_msg, full_byte_enable); + + full_len(len'length - 1 downto 0) := len; push_std_ulogic_vector(request_msg, len); - push_std_ulogic_vector(request_msg, id); + + if id = "" then + full_id := (others => '0'); + else + full_id(id'length - 1 downto 0) := id; + end if; + push_std_ulogic_vector(request_msg, full_id); + push_std_ulogic_vector(request_msg, expected_bresp); send(net, bus_handle.p_actor, request_msg); end procedure; @@ -108,13 +120,24 @@ package body axi_master_pkg is constant expected_rresp : axi_resp_t := axi_resp_okay; variable reference : inout bus_reference_t) is variable full_address : std_logic_vector(bus_handle.p_address_length - 1 downto 0) := (others => '0'); + variable full_len : std_logic_vector(len_length(bus_handle) - 1 downto 0) := (others => '0'); + variable full_id : std_logic_vector(id_length(bus_handle) - 1 downto 0) := (others => '0'); alias request_msg : msg_t is reference; begin request_msg := new_msg(axi_read_msg); full_address(address'length - 1 downto 0) := address; push_std_ulogic_vector(request_msg, full_address); + + full_len(len'length - 1 downto 0) := len; push_std_ulogic_vector(request_msg, len); - push_std_ulogic_vector(request_msg, id); + + if id = "" then + full_id := (others => '0'); + else + full_id(id'length - 1 downto 0) := id; + end if; + push_std_ulogic_vector(request_msg, full_id); + push_std_ulogic_vector(request_msg, expected_rresp); send(net, bus_handle.p_actor, request_msg); end procedure; @@ -181,4 +204,13 @@ package body axi_master_pkg is return msg_type = axi_read_msg or msg_type = axi_write_msg; end function; + function len_length(bus_handle : bus_master_t) return natural is + begin + return 8; + end; + + function id_length(bus_handle : bus_master_t) return natural is + begin + return 32; + end; end package body; diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index 8085de510..16112b868 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -92,10 +92,10 @@ begin write_bus(net, bus_handle, x"01234567", x"1122"); elsif run("Test write with axi resp") then - write_axi(net, bus_handle, x"01234567", x"1122", axi_resp_slverr); + write_axi(net, bus_handle, x"01234567", x"1122", x"12", x"25", axi_resp_slverr); elsif run("Test write with wrong axi resp") then - write_axi(net, bus_handle, x"01234567", x"1122", axi_resp_decerr); + write_axi(net, bus_handle, x"01234567", x"1122", x"12", x"25", axi_resp_decerr); elsif run("Test single read") then mock(get_logger(bus_handle), debug); @@ -130,7 +130,7 @@ begin check_equal(tmp, rnd.RandSlv(rdata'length), "read data"); else write_axi(net, bus_handle, rnd.RandSlv(awaddr'length), rnd.RandSlv(wdata'length), - rnd.RandSlv(axi_resp_t'length)); + x"12", x"25", rnd.RandSlv(axi_resp_t'length)); end if; end loop; From 82ccdbac477fe76ce11a90e45559de49a267dcc1 Mon Sep 17 00:00:00 2001 From: David Martin Date: Fri, 17 May 2024 14:17:05 +0200 Subject: [PATCH 08/24] Refactoring - remove comment --- vunit/vhdl/verification_components/src/axi_master.vhd | 1 - 1 file changed, 1 deletion(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index 62e5513bd..b1c240f8b 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -149,7 +149,6 @@ begin if(is_axi_msg(msg_type)) then arlen <= pop_std_ulogic_vector(request_msg); arid <= pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); - --tmp := pop_std_ulogic_vector(request_msg); end if; expected_resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; From 79dca3ff5535d7b7fa60607df1c003931dd5e7b3 Mon Sep 17 00:00:00 2001 From: David Martin Date: Tue, 21 May 2024 09:20:23 +0200 Subject: [PATCH 09/24] Added awsize and awburst to axi master --- .../src/axi_master.vhd | 7 +- .../src/axi_master_pkg.vhd | 24 +++- .../test/tb_axi_master.vhd | 131 ++++++++++++------ 3 files changed, 117 insertions(+), 45 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index b1c240f8b..6f7296817 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -99,7 +99,7 @@ begin begin if drive_invalid then araddr <= (araddr'range => drive_invalid_val); - arlen <= (arid'range => drive_invalid_val); + arlen <= (arlen'range => drive_invalid_val); arid <= (arid'range => drive_invalid_val); end if; end procedure; @@ -108,6 +108,9 @@ begin begin if drive_invalid then awaddr <= (awaddr'range => drive_invalid_val); + awlen <= (awlen'range => drive_invalid_val); + awsize <= (awsize'range => drive_invalid_val); + awburst <= (awburst'range => drive_invalid_val); awid <= (arid'range => drive_invalid_val); end if; end procedure; @@ -178,6 +181,8 @@ begin if(is_axi_msg(msg_type)) then awlen <= pop_std_ulogic_vector(request_msg); + awsize <= pop_std_ulogic_vector(request_msg); + awburst <= pop_std_ulogic_vector(request_msg); awid <= pop_std_ulogic_vector(request_msg)(awid'length -1 downto 0); end if; diff --git a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd index 9583a2e9c..2fd6df0a1 100644 --- a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd @@ -26,6 +26,8 @@ package axi_master_pkg is constant address : std_logic_vector; constant data : std_logic_vector; constant len : std_logic_vector; + constant size : std_logic_vector; + constant burst : axi_burst_type_t; constant id : std_logic_vector := ""; constant expected_bresp : axi_resp_t := axi_resp_okay; -- default byte enable is all bytes @@ -65,6 +67,7 @@ package axi_master_pkg is function len_length(bus_handle : bus_master_t) return natural; function id_length(bus_handle : bus_master_t) return natural; + function size_length(bus_handle : bus_master_t) return natural; end package; package body axi_master_pkg is @@ -74,6 +77,8 @@ package body axi_master_pkg is constant address : std_logic_vector; constant data : std_logic_vector; constant len : std_logic_vector; + constant size : std_logic_vector; + constant burst : axi_burst_type_t; constant id : std_logic_vector := ""; constant expected_bresp : axi_resp_t := axi_resp_okay; -- default byte enable is all bytes @@ -83,6 +88,7 @@ package body axi_master_pkg is variable full_address : std_logic_vector(bus_handle.p_address_length - 1 downto 0) := (others => '0'); variable full_byte_enable : std_logic_vector(byte_enable_length(bus_handle) - 1 downto 0); variable full_len : std_logic_vector(len_length(bus_handle) - 1 downto 0) := (others => '0'); + variable full_size : std_logic_vector(size_length(bus_handle) - 1 downto 0) := (others => '0'); variable full_id : std_logic_vector(id_length(bus_handle) - 1 downto 0) := (others => '0'); begin full_address(address'length - 1 downto 0) := address; @@ -99,7 +105,12 @@ package body axi_master_pkg is push_std_ulogic_vector(request_msg, full_byte_enable); full_len(len'length - 1 downto 0) := len; - push_std_ulogic_vector(request_msg, len); + push_std_ulogic_vector(request_msg, full_len); + + full_size(size'length - 1 downto 0) := size; + push_std_ulogic_vector(request_msg, full_size); + + push_std_ulogic_vector(request_msg, burst); if id = "" then full_id := (others => '0'); @@ -129,7 +140,7 @@ package body axi_master_pkg is push_std_ulogic_vector(request_msg, full_address); full_len(len'length - 1 downto 0) := len; - push_std_ulogic_vector(request_msg, len); + push_std_ulogic_vector(request_msg, full_len); if id = "" then full_id := (others => '0'); @@ -206,11 +217,16 @@ package body axi_master_pkg is function len_length(bus_handle : bus_master_t) return natural is begin - return 8; + return 8; -- Add to bus_master_t? end; function id_length(bus_handle : bus_master_t) return natural is begin - return 32; + return 32; -- Add to bus_master_t? + end; + + function size_length(bus_handle : bus_master_t) return natural is + begin + return 3; -- Add to bus_master_t? end; end package body; diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index 16112b868..d9b5907c5 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -33,8 +33,8 @@ architecture a of tb_axi_master is signal arid : std_logic_vector(7 downto 0); --TBD signal araddr : std_logic_vector(31 downto 0); signal arlen : std_logic_vector(7 downto 0); --TBD - signal arsize : std_logic_vector(7 downto 0); --TBD - signal arburst : axi_burst_type_t; --TBD + signal arsize : std_logic_vector(2 downto 0); + signal arburst : axi_burst_type_t; signal rvalid : std_logic; signal rready : std_logic := '0'; @@ -48,8 +48,8 @@ architecture a of tb_axi_master is signal awid : std_logic_vector(7 downto 0); --TBD signal awaddr : std_logic_vector(31 downto 0); signal awlen : std_logic_vector(7 downto 0); --TBD - signal awsize : std_logic_vector(7 downto 0); --TBD - signal awburst : axi_burst_type_t; --TBD + signal awsize : std_logic_vector(2 downto 0); + signal awburst : axi_burst_type_t; signal wvalid : std_logic; signal wready : std_logic := '0'; @@ -92,10 +92,10 @@ begin write_bus(net, bus_handle, x"01234567", x"1122"); elsif run("Test write with axi resp") then - write_axi(net, bus_handle, x"01234567", x"1122", x"12", x"25", axi_resp_slverr); + write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, x"25", axi_resp_slverr); elsif run("Test write with wrong axi resp") then - write_axi(net, bus_handle, x"01234567", x"1122", x"12", x"25", axi_resp_decerr); + write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, x"25", axi_resp_decerr); elsif run("Test single read") then mock(get_logger(bus_handle), debug); @@ -130,7 +130,7 @@ begin check_equal(tmp, rnd.RandSlv(rdata'length), "read data"); else write_axi(net, bus_handle, rnd.RandSlv(awaddr'length), rnd.RandSlv(wdata'length), - x"12", x"25", rnd.RandSlv(axi_resp_t'length)); + x"12", "111" , axi_burst_type_fixed, x"25", rnd.RandSlv(axi_resp_t'length)); end if; end loop; @@ -152,7 +152,7 @@ begin check_equal(timestamp, now, "Read: Second wait had to wait"); elsif run("Test single write with id") then - write_axi(net, bus_handle, x"01234567", x"1122", x"12", x"25"); + write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, x"25"); elsif run("Test single read with id") then read_axi(net, bus_handle, x"01234567", x"00", x"25", axi_resp_okay, tmp); @@ -161,8 +161,14 @@ begin read_axi(net, bus_handle, x"01234567", x"12", x"25", axi_resp_okay, tmp); elsif run("Test single write with len") then - write_axi(net, bus_handle, x"01234567", x"1122", x"12", x"25"); + write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, x"25"); + elsif run("Test single write with size") then + write_axi(net, bus_handle, x"01234567", x"1122", x"12", "010" , axi_burst_type_fixed, x"25"); + + elsif run("Test single write with burst") then + write_axi(net, bus_handle, x"01234567", x"1122", x"12", "010" , axi_burst_type_incr, x"25"); + end if; wait for 100 ns; @@ -482,40 +488,80 @@ begin done <= true; elsif enabled("Test single read with len") then - arready <= '1'; - wait until (arready and arvalid) = '1' and rising_edge(clk); - arready <= '0'; - check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); - check_equal(arlen, std_logic_vector'(x"12"), "arid"); - - rvalid <= '1'; - rresp <= axi_resp_okay; - rdata <= x"5566"; - wait until (rready and rvalid) = '1' and rising_edge(clk); - rvalid <= '0'; - - done <= true; + arready <= '1'; + wait until (arready and arvalid) = '1' and rising_edge(clk); + arready <= '0'; + check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); + check_equal(arlen, std_logic_vector'(x"12"), "arid"); + + rvalid <= '1'; + rresp <= axi_resp_okay; + rdata <= x"5566"; + wait until (rready and rvalid) = '1' and rising_edge(clk); + rvalid <= '0'; + + done <= true; elsif enabled("Test single write with len") then - awready <= '1'; - wait until (awready and awvalid) = '1' and rising_edge(clk); - awready <= '0'; - check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); - check_equal(awlen, std_logic_vector'(x"12"), "awlen"); - - wready <= '1'; - wait until (wready and wvalid) = '1' and rising_edge(clk); - wready <= '0'; - check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); - check_equal(wstrb, std_logic_vector'("11"), "wstrb"); - - bvalid <= '1'; - bresp <= axi_resp_okay; - wait until (bready and bvalid) = '1' and rising_edge(clk); - bvalid <= '0'; - - done <= true; + awready <= '1'; + wait until (awready and awvalid) = '1' and rising_edge(clk); + awready <= '0'; + check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); + check_equal(awlen, std_logic_vector'(x"12"), "awlen"); + + wready <= '1'; + wait until (wready and wvalid) = '1' and rising_edge(clk); + wready <= '0'; + check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); + check_equal(wstrb, std_logic_vector'("11"), "wstrb"); + + bvalid <= '1'; + bresp <= axi_resp_okay; + wait until (bready and bvalid) = '1' and rising_edge(clk); + bvalid <= '0'; + + done <= true; + + elsif enabled("Test single write with size") then + awready <= '1'; + wait until (awready and awvalid) = '1' and rising_edge(clk); + awready <= '0'; + check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); + check_equal(awsize, std_logic_vector'("010"), "awsize"); + + wready <= '1'; + wait until (wready and wvalid) = '1' and rising_edge(clk); + wready <= '0'; + check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); + check_equal(wstrb, std_logic_vector'("11"), "wstrb"); + + bvalid <= '1'; + bresp <= axi_resp_okay; + wait until (bready and bvalid) = '1' and rising_edge(clk); + bvalid <= '0'; + + done <= true; + elsif enabled("Test single write with burst") then + awready <= '1'; + wait until (awready and awvalid) = '1' and rising_edge(clk); + awready <= '0'; + check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); + check_equal(awburst, axi_burst_type_incr, "awburst"); + + wready <= '1'; + wait until (wready and wvalid) = '1' and rising_edge(clk); + wready <= '0'; + check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); + check_equal(wstrb, std_logic_vector'("11"), "wstrb"); + + bvalid <= '1'; + bresp <= axi_resp_okay; + wait until (bready and bvalid) = '1' and rising_edge(clk); + bvalid <= '0'; + + done <= true; + end if; end process; @@ -523,6 +569,8 @@ begin constant a_addr_invalid_value : std_logic_vector(araddr'range) := (others => 'X'); constant a_len_invalid_value : std_logic_vector(arlen'range) := (others => 'X'); constant a_id_invalid_value : std_logic_vector(arid'range) := (others => 'X'); + constant a_size_invalid_value : std_logic_vector(arsize'range) := (others => 'X'); + constant a_burst_invalid_value : std_logic_vector(arburst'range) := (others => 'X'); constant wdata_invalid_value : std_logic_vector(wdata'range) := (others => 'X'); constant wstrb_invalid_value : std_logic_vector(wstrb'range) := (others => 'X'); begin @@ -539,6 +587,9 @@ begin if not awvalid then check_equal(awaddr, a_addr_invalid_value, "AWADDR not X when AWVALID low"); + check_equal(awlen, a_len_invalid_value, "AWLEN not X when ARVALID low"); + check_equal(awsize, a_size_invalid_value, "AWSIZE not X when ARVALID low"); + check_equal(awburst, a_burst_invalid_value, "AWSBURST not X when ARVALID low"); check_equal(awid, a_id_invalid_value, "AWID not X when ARVALID low"); end if; From b06c724d1a3f1be069a000c876825fdae68aa85d Mon Sep 17 00:00:00 2001 From: David Martin Date: Tue, 21 May 2024 09:59:22 +0200 Subject: [PATCH 10/24] Added arsize and arburst to axi master --- .../src/axi_master.vhd | 4 ++ .../src/axi_master_pkg.vhd | 22 +++++++- .../test/tb_axi_master.vhd | 51 ++++++++++++++++--- 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index 6f7296817..2e6eba175 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -100,6 +100,8 @@ begin if drive_invalid then araddr <= (araddr'range => drive_invalid_val); arlen <= (arlen'range => drive_invalid_val); + arsize <= (arsize'range => drive_invalid_val); + arburst <= (arburst'range => drive_invalid_val); arid <= (arid'range => drive_invalid_val); end if; end procedure; @@ -151,6 +153,8 @@ begin if(is_axi_msg(msg_type)) then arlen <= pop_std_ulogic_vector(request_msg); + arsize <= pop_std_ulogic_vector(request_msg); + arburst <= pop_std_ulogic_vector(request_msg); arid <= pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); end if; diff --git a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd index 2fd6df0a1..c4f0f7120 100644 --- a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd @@ -38,6 +38,8 @@ package axi_master_pkg is constant bus_handle : bus_master_t; constant address : std_logic_vector; constant len : std_logic_vector; + constant size : std_logic_vector; + constant burst : axi_burst_type_t; constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; variable reference : inout bus_reference_t); @@ -47,6 +49,8 @@ package axi_master_pkg is constant bus_handle : bus_master_t; constant address : std_logic_vector; constant len : std_logic_vector; + constant size : std_logic_vector; + constant burst : axi_burst_type_t; constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; variable data : inout std_logic_vector); @@ -56,6 +60,8 @@ package axi_master_pkg is constant bus_handle : bus_master_t; constant address : std_logic_vector; constant len : std_logic_vector; + constant size : std_logic_vector; + constant burst : axi_burst_type_t; constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; constant expected : std_logic_vector; @@ -127,11 +133,14 @@ package body axi_master_pkg is constant bus_handle : bus_master_t; constant address : std_logic_vector; constant len : std_logic_vector; + constant size : std_logic_vector; + constant burst : axi_burst_type_t; constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; variable reference : inout bus_reference_t) is variable full_address : std_logic_vector(bus_handle.p_address_length - 1 downto 0) := (others => '0'); variable full_len : std_logic_vector(len_length(bus_handle) - 1 downto 0) := (others => '0'); + variable full_size : std_logic_vector(size_length(bus_handle) - 1 downto 0) := (others => '0'); variable full_id : std_logic_vector(id_length(bus_handle) - 1 downto 0) := (others => '0'); alias request_msg : msg_t is reference; begin @@ -142,6 +151,11 @@ package body axi_master_pkg is full_len(len'length - 1 downto 0) := len; push_std_ulogic_vector(request_msg, full_len); + full_size(size'length - 1 downto 0) := size; + push_std_ulogic_vector(request_msg, full_size); + + push_std_ulogic_vector(request_msg, burst); + if id = "" then full_id := (others => '0'); else @@ -157,12 +171,14 @@ package body axi_master_pkg is constant bus_handle : bus_master_t; constant address : std_logic_vector; constant len : std_logic_vector; + constant size : std_logic_vector; + constant burst : axi_burst_type_t; constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; variable data : inout std_logic_vector) is variable reference : bus_reference_t; begin - read_axi(net, bus_handle, address, len, id, expected_rresp, reference); + read_axi(net, bus_handle, address, len, size, burst, id, expected_rresp, reference); await_read_bus_reply(net, reference, data); end procedure; @@ -170,6 +186,8 @@ package body axi_master_pkg is constant bus_handle : bus_master_t; constant address : std_logic_vector; constant len : std_logic_vector; + constant size : std_logic_vector; + constant burst : axi_burst_type_t; constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; constant expected : std_logic_vector; @@ -194,7 +212,7 @@ package body axi_master_pkg is edata(expected'length - 1 downto 0) := expected; - read_axi(net, bus_handle, address, len, id, expected_rresp, data); + read_axi(net, bus_handle, address, len, size, burst, id, expected_rresp, data); if not std_match(data, edata) then failure(bus_handle.p_logger, base_error); end if; diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index d9b5907c5..fb2148b79 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -108,10 +108,10 @@ begin read_bus(net, bus_handle, x"01234567", tmp); elsif run("Test read with axi resp") then - read_axi(net, bus_handle, x"01234567", x"00", x"25", axi_resp_slverr, tmp); + read_axi(net, bus_handle, x"01234567", x"00", "111" , axi_burst_type_fixed, x"25", axi_resp_slverr, tmp); elsif run("Test read with wrong axi resp") then - read_axi(net, bus_handle, x"01234567", x"00", x"25", axi_resp_exokay, tmp); + read_axi(net, bus_handle, x"01234567", x"00", "111" , axi_burst_type_fixed, x"25", axi_resp_exokay, tmp); elsif run("Test random") then for i in 0 to num_random_tests-1 loop @@ -126,7 +126,7 @@ begin elsif run("Test random axi resp") then for i in 0 to num_random_tests-1 loop if rnd.RandInt(0, 1) = 0 then - read_axi(net, bus_handle, rnd.RandSlv(araddr'length), x"00", x"25", rnd.RandSlv(axi_resp_t'length), tmp); + read_axi(net, bus_handle, rnd.RandSlv(araddr'length), x"00", "111" , axi_burst_type_fixed, x"25", rnd.RandSlv(axi_resp_t'length), tmp); check_equal(tmp, rnd.RandSlv(rdata'length), "read data"); else write_axi(net, bus_handle, rnd.RandSlv(awaddr'length), rnd.RandSlv(wdata'length), @@ -155,10 +155,10 @@ begin write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, x"25"); elsif run("Test single read with id") then - read_axi(net, bus_handle, x"01234567", x"00", x"25", axi_resp_okay, tmp); + read_axi(net, bus_handle, x"01234567", x"00", "111" , axi_burst_type_fixed, x"25", axi_resp_okay, tmp); elsif run("Test single read with len") then - read_axi(net, bus_handle, x"01234567", x"12", x"25", axi_resp_okay, tmp); + read_axi(net, bus_handle, x"01234567", x"12", "111" , axi_burst_type_fixed, x"25", axi_resp_okay, tmp); elsif run("Test single write with len") then write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, x"25"); @@ -168,7 +168,13 @@ begin elsif run("Test single write with burst") then write_axi(net, bus_handle, x"01234567", x"1122", x"12", "010" , axi_burst_type_incr, x"25"); - + + elsif run("Test single read with size") then + read_axi(net, bus_handle, x"01234567", x"12", "101" , axi_burst_type_fixed, x"25", axi_resp_okay, tmp); + + elsif run("Test single read with burst") then + read_axi(net, bus_handle, x"01234567", x"12", "111" , axi_burst_type_incr, x"25", axi_resp_okay, tmp); + end if; wait for 100 ns; @@ -562,6 +568,35 @@ begin done <= true; + elsif enabled("Test single read with size") then + arready <= '1'; + wait until (arready and arvalid) = '1' and rising_edge(clk); + arready <= '0'; + check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); + check_equal(arsize, std_logic_vector'("101"), "arsize"); + + rvalid <= '1'; + rresp <= axi_resp_okay; + rdata <= x"5566"; + wait until (rready and rvalid) = '1' and rising_edge(clk); + rvalid <= '0'; + + done <= true; + + elsif enabled("Test single read with burst") then + arready <= '1'; + wait until (arready and arvalid) = '1' and rising_edge(clk); + arready <= '0'; + check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); + check_equal(arburst, axi_burst_type_incr, "arburst"); + + rvalid <= '1'; + rresp <= axi_resp_okay; + rdata <= x"5566"; + wait until (rready and rvalid) = '1' and rising_edge(clk); + rvalid <= '0'; + + done <= true; end if; end process; @@ -582,6 +617,8 @@ begin if not arvalid then check_equal(araddr, a_addr_invalid_value, "ARADDR not X when ARVALID low"); check_equal(arlen, a_len_invalid_value, "ARLEN not X when ARVALID low"); + check_equal(arsize, a_size_invalid_value, "ARSIZE not X when ARVALID low"); + check_equal(arburst, a_burst_invalid_value, "ARBURST not X when ARVALID low"); check_equal(arid, a_id_invalid_value, "ARID not X when ARVALID low"); end if; @@ -589,7 +626,7 @@ begin check_equal(awaddr, a_addr_invalid_value, "AWADDR not X when AWVALID low"); check_equal(awlen, a_len_invalid_value, "AWLEN not X when ARVALID low"); check_equal(awsize, a_size_invalid_value, "AWSIZE not X when ARVALID low"); - check_equal(awburst, a_burst_invalid_value, "AWSBURST not X when ARVALID low"); + check_equal(awburst, a_burst_invalid_value, "AWBURST not X when ARVALID low"); check_equal(awid, a_id_invalid_value, "AWID not X when ARVALID low"); end if; From 0dc62a7f3d9fd0cf27049eacec7a161eb58b7d07 Mon Sep 17 00:00:00 2001 From: David Martin Date: Tue, 21 May 2024 10:46:51 +0200 Subject: [PATCH 11/24] Added wlast to axi master --- .../src/axi_master.vhd | 3 ++ .../src/axi_master_pkg.vhd | 6 ++- .../test/tb_axi_master.vhd | 42 +++++++++++++++---- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index 2e6eba175..4b2a9afa6 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -120,6 +120,7 @@ begin procedure drive_w_invalid is begin if drive_invalid then + wlast <= drive_invalid_val; wdata <= (wdata'range => drive_invalid_val); wstrb <= (wstrb'range => drive_invalid_val); end if; @@ -188,6 +189,8 @@ begin awsize <= pop_std_ulogic_vector(request_msg); awburst <= pop_std_ulogic_vector(request_msg); awid <= pop_std_ulogic_vector(request_msg)(awid'length -1 downto 0); + + wlast <= pop_std_ulogic(request_msg); end if; expected_resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; diff --git a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd index c4f0f7120..a9f1034ed 100644 --- a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd @@ -28,6 +28,7 @@ package axi_master_pkg is constant len : std_logic_vector; constant size : std_logic_vector; constant burst : axi_burst_type_t; + constant last : std_logic; constant id : std_logic_vector := ""; constant expected_bresp : axi_resp_t := axi_resp_okay; -- default byte enable is all bytes @@ -85,6 +86,7 @@ package body axi_master_pkg is constant len : std_logic_vector; constant size : std_logic_vector; constant burst : axi_burst_type_t; + constant last : std_logic; constant id : std_logic_vector := ""; constant expected_bresp : axi_resp_t := axi_resp_okay; -- default byte enable is all bytes @@ -125,6 +127,8 @@ package body axi_master_pkg is end if; push_std_ulogic_vector(request_msg, full_id); + push_std_ulogic(request_msg, last); + push_std_ulogic_vector(request_msg, expected_bresp); send(net, bus_handle.p_actor, request_msg); end procedure; @@ -155,7 +159,7 @@ package body axi_master_pkg is push_std_ulogic_vector(request_msg, full_size); push_std_ulogic_vector(request_msg, burst); - + if id = "" then full_id := (others => '0'); else diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index fb2148b79..e31834e0d 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -92,10 +92,10 @@ begin write_bus(net, bus_handle, x"01234567", x"1122"); elsif run("Test write with axi resp") then - write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, x"25", axi_resp_slverr); + write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, '0', x"25", axi_resp_slverr); elsif run("Test write with wrong axi resp") then - write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, x"25", axi_resp_decerr); + write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, '0', x"25", axi_resp_decerr); elsif run("Test single read") then mock(get_logger(bus_handle), debug); @@ -130,7 +130,7 @@ begin check_equal(tmp, rnd.RandSlv(rdata'length), "read data"); else write_axi(net, bus_handle, rnd.RandSlv(awaddr'length), rnd.RandSlv(wdata'length), - x"12", "111" , axi_burst_type_fixed, x"25", rnd.RandSlv(axi_resp_t'length)); + x"12", "111" , axi_burst_type_fixed, '0', x"25", rnd.RandSlv(axi_resp_t'length)); end if; end loop; @@ -152,7 +152,7 @@ begin check_equal(timestamp, now, "Read: Second wait had to wait"); elsif run("Test single write with id") then - write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, x"25"); + write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, '0', x"25"); elsif run("Test single read with id") then read_axi(net, bus_handle, x"01234567", x"00", "111" , axi_burst_type_fixed, x"25", axi_resp_okay, tmp); @@ -161,13 +161,13 @@ begin read_axi(net, bus_handle, x"01234567", x"12", "111" , axi_burst_type_fixed, x"25", axi_resp_okay, tmp); elsif run("Test single write with len") then - write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, x"25"); + write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, '0', x"25"); elsif run("Test single write with size") then - write_axi(net, bus_handle, x"01234567", x"1122", x"12", "010" , axi_burst_type_fixed, x"25"); + write_axi(net, bus_handle, x"01234567", x"1122", x"12", "010" , axi_burst_type_fixed, '0', x"25"); elsif run("Test single write with burst") then - write_axi(net, bus_handle, x"01234567", x"1122", x"12", "010" , axi_burst_type_incr, x"25"); + write_axi(net, bus_handle, x"01234567", x"1122", x"12", "010" , axi_burst_type_incr, '0', x"25"); elsif run("Test single read with size") then read_axi(net, bus_handle, x"01234567", x"12", "101" , axi_burst_type_fixed, x"25", axi_resp_okay, tmp); @@ -175,6 +175,9 @@ begin elsif run("Test single read with burst") then read_axi(net, bus_handle, x"01234567", x"12", "111" , axi_burst_type_incr, x"25", axi_resp_okay, tmp); + elsif run("Test single write with last") then + write_axi(net, bus_handle, x"01234567", x"1122", x"12", "010" , axi_burst_type_incr, '1', x"25"); + end if; wait for 100 ns; @@ -597,7 +600,28 @@ begin rvalid <= '0'; done <= true; - end if; + + elsif enabled("Test single write with last") then + awready <= '1'; + wait until (awready and awvalid) = '1' and rising_edge(clk); + awready <= '0'; + check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); + + + wready <= '1'; + wait until (wready and wvalid) = '1' and rising_edge(clk); + wready <= '0'; + check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); + check_equal(wstrb, std_logic_vector'("11"), "wstrb"); + check_equal(wlast, '1', "wlast"); + + bvalid <= '1'; + bresp <= axi_resp_okay; + wait until (bready and bvalid) = '1' and rising_edge(clk); + bvalid <= '0'; + + done <= true; + end if; end process; check_not_valid : process @@ -608,6 +632,7 @@ begin constant a_burst_invalid_value : std_logic_vector(arburst'range) := (others => 'X'); constant wdata_invalid_value : std_logic_vector(wdata'range) := (others => 'X'); constant wstrb_invalid_value : std_logic_vector(wstrb'range) := (others => 'X'); + constant wlast_invalid_value : std_logic := 'X'; begin wait until rising_edge(clk); @@ -633,6 +658,7 @@ begin if not wvalid then check_equal(wdata, wdata_invalid_value, "WDATA not X when WVALID low"); check_equal(wstrb, wstrb_invalid_value, "WSTRB not X when WVALID low"); + check_equal(wlast, wlast_invalid_value, "WLAST not X when WVALID low"); end if; end process; From c5138131c446a0c95768a7e4171e4d15a93df5c9 Mon Sep 17 00:00:00 2001 From: David Martin Date: Wed, 22 May 2024 14:10:51 +0200 Subject: [PATCH 12/24] Added axi rid check in axi_master --- .../vhdl/verification_components/src/axi_master.vhd | 13 +++++++++++-- .../src/axi_slave_private_pkg.vhd | 12 ++++++++++++ .../verification_components/test/tb_axi_master.vhd | 7 +++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index 4b2a9afa6..ff3439604 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -11,6 +11,7 @@ use ieee.std_logic_1164.all; use work.axi_master_pkg.all; use work.axi_pkg.all; use work.axi_slave_private_pkg.check_axi_resp; +use work.axi_slave_private_pkg.check_axi_id; use work.bus_master_pkg.address_length; use work.bus_master_pkg.bus_master_t; use work.bus_master_pkg.byte_enable_length; @@ -134,7 +135,7 @@ begin -- These variables are needed to keep the values for logging when transaction is fully done variable addr_this_transaction : std_logic_vector(awaddr'range) := (others => '0'); variable wdata_this_transaction : std_logic_vector(wdata'range) := (others => '0'); - variable tmp : std_logic_vector(31 downto 0) := (others => '0'); + variable expected_rid : std_logic_vector(rid'range) := (others => '0'); begin -- Initialization drive_ar_invalid; @@ -156,7 +157,9 @@ begin arlen <= pop_std_ulogic_vector(request_msg); arsize <= pop_std_ulogic_vector(request_msg); arburst <= pop_std_ulogic_vector(request_msg); - arid <= pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); + + expected_rid := pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); + arid <= expected_rid; end if; expected_resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; @@ -171,8 +174,14 @@ begin rready <= '1'; wait until (rvalid and rready) = '1' and rising_edge(aclk); rready <= '0'; + check_axi_resp(bus_handle, rresp, expected_resp, "rresp"); + if(is_axi_msg(msg_type)) then + check_axi_id(bus_handle, rid, expected_rid, "rid"); + end if; + + if is_visible(bus_handle.p_logger, debug) then debug(bus_handle.p_logger, "Read 0x" & to_hstring(rdata) & diff --git a/vunit/vhdl/verification_components/src/axi_slave_private_pkg.vhd b/vunit/vhdl/verification_components/src/axi_slave_private_pkg.vhd index 64ef4af9c..31296a061 100644 --- a/vunit/vhdl/verification_components/src/axi_slave_private_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_slave_private_pkg.vhd @@ -103,6 +103,7 @@ package axi_slave_private_pkg is signal net : inout network_t); procedure check_axi_resp(bus_handle : bus_master_t; got, expected : axi_resp_t; msg : string); + procedure check_axi_id(bus_handle : bus_master_t; got, expected : std_logic_vector; msg : string); end package; @@ -583,4 +584,15 @@ package body axi_slave_private_pkg is failure(bus_handle.p_logger, msg & " - Got AXI response " & describe(got) & " expected " & describe(expected)); end if; end; + + procedure check_axi_id(bus_handle : bus_master_t; got, expected : std_logic_vector; msg : string) is + function describe(id : std_logic_vector) return string is + begin + return to_string(id); + end; + begin + if got /= expected then + failure(bus_handle.p_logger, msg & " - Got AXI id " & describe(got) & " expected " & describe(expected)); + end if; + end; end package body; diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index e31834e0d..1c3eff862 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -338,6 +338,7 @@ begin rvalid <= '1'; rresp <= axi_resp_slverr; rdata <= x"0000"; + rid <= x"25"; wait until (rready and rvalid) = '1' and rising_edge(clk); rvalid <= '0'; @@ -352,6 +353,7 @@ begin rvalid <= '1'; rresp <= axi_resp_decerr; rdata <= x"0000"; + rid <= x"25"; mock(bus_logger, failure); wait until (rready and rvalid) = '1' and rising_edge(clk); rvalid <= '0'; @@ -405,6 +407,7 @@ begin rvalid <= '1'; rresp <= rnd.RandSlv(axi_resp_t'length); rdata <= rnd.RandSlv(rdata'length); + rid <= x"25"; wait until (rready and rvalid) = '1' and rising_edge(clk); rvalid <= '0'; else @@ -491,6 +494,7 @@ begin rvalid <= '1'; rresp <= axi_resp_okay; rdata <= x"5566"; + rid <= x"25"; wait until (rready and rvalid) = '1' and rising_edge(clk); rvalid <= '0'; @@ -506,6 +510,7 @@ begin rvalid <= '1'; rresp <= axi_resp_okay; rdata <= x"5566"; + rid <= x"25"; wait until (rready and rvalid) = '1' and rising_edge(clk); rvalid <= '0'; @@ -581,6 +586,7 @@ begin rvalid <= '1'; rresp <= axi_resp_okay; rdata <= x"5566"; + rid <= x"25"; wait until (rready and rvalid) = '1' and rising_edge(clk); rvalid <= '0'; @@ -596,6 +602,7 @@ begin rvalid <= '1'; rresp <= axi_resp_okay; rdata <= x"5566"; + rid <= x"25"; wait until (rready and rvalid) = '1' and rising_edge(clk); rvalid <= '0'; From f3a960cb204964f6bc7ca5317785860fb142e6e2 Mon Sep 17 00:00:00 2001 From: David Martin Date: Wed, 22 May 2024 14:22:55 +0200 Subject: [PATCH 13/24] Added bid check in axi master --- .../verification_components/src/axi_master.vhd | 18 ++++++++++++------ .../test/tb_axi_master.vhd | 8 ++++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index ff3439604..8226eb21c 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -135,7 +135,7 @@ begin -- These variables are needed to keep the values for logging when transaction is fully done variable addr_this_transaction : std_logic_vector(awaddr'range) := (others => '0'); variable wdata_this_transaction : std_logic_vector(wdata'range) := (others => '0'); - variable expected_rid : std_logic_vector(rid'range) := (others => '0'); + variable expected_id : std_logic_vector(rid'range) := (others => '0'); begin -- Initialization drive_ar_invalid; @@ -158,8 +158,8 @@ begin arsize <= pop_std_ulogic_vector(request_msg); arburst <= pop_std_ulogic_vector(request_msg); - expected_rid := pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); - arid <= expected_rid; + expected_id := pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); + arid <= expected_id; end if; expected_resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; @@ -178,10 +178,9 @@ begin check_axi_resp(bus_handle, rresp, expected_resp, "rresp"); if(is_axi_msg(msg_type)) then - check_axi_id(bus_handle, rid, expected_rid, "rid"); + check_axi_id(bus_handle, rid, expected_id, "rid"); end if; - if is_visible(bus_handle.p_logger, debug) then debug(bus_handle.p_logger, "Read 0x" & to_hstring(rdata) & @@ -197,7 +196,9 @@ begin awlen <= pop_std_ulogic_vector(request_msg); awsize <= pop_std_ulogic_vector(request_msg); awburst <= pop_std_ulogic_vector(request_msg); - awid <= pop_std_ulogic_vector(request_msg)(awid'length -1 downto 0); + + expected_id := pop_std_ulogic_vector(request_msg)(awid'length -1 downto 0); + awid <= expected_id; wlast <= pop_std_ulogic(request_msg); end if; @@ -234,8 +235,13 @@ begin bready <= '1'; wait until (bvalid and bready) = '1' and rising_edge(aclk); bready <= '0'; + check_axi_resp(bus_handle, bresp, expected_resp, "bresp"); + if(is_axi_msg(msg_type)) then + check_axi_id(bus_handle, bid, expected_id, "bid"); + end if; + if is_visible(bus_handle.p_logger, debug) then debug(bus_handle.p_logger, "Wrote 0x" & to_hstring(wdata_this_transaction) & diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index 1c3eff862..72a5fe42d 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -270,6 +270,7 @@ begin bvalid <= '1'; bresp <= axi_resp_slverr; + bid <= x"25"; wait until (bready and bvalid) = '1' and rising_edge(clk); bvalid <= '0'; @@ -289,6 +290,7 @@ begin bvalid <= '1'; bresp <= axi_resp_exokay; + bid <= x"25"; mock(bus_logger, failure); wait until (bready and bvalid) = '1' and rising_edge(clk); bvalid <= '0'; @@ -424,6 +426,7 @@ begin bvalid <= '1'; bresp <= rnd.RandSlv(axi_resp_t'length); + bid <= x"25"; wait until (bready and bvalid) = '1' and rising_edge(clk); bvalid <= '0'; end if; @@ -479,6 +482,7 @@ begin bvalid <= '1'; bresp <= axi_resp_okay; + bid <= x"25"; wait until (bready and bvalid) = '1' and rising_edge(clk); bvalid <= '0'; @@ -531,6 +535,7 @@ begin bvalid <= '1'; bresp <= axi_resp_okay; + bid <= x"25"; wait until (bready and bvalid) = '1' and rising_edge(clk); bvalid <= '0'; @@ -551,6 +556,7 @@ begin bvalid <= '1'; bresp <= axi_resp_okay; + bid <= x"25"; wait until (bready and bvalid) = '1' and rising_edge(clk); bvalid <= '0'; @@ -571,6 +577,7 @@ begin bvalid <= '1'; bresp <= axi_resp_okay; + bid <= x"25"; wait until (bready and bvalid) = '1' and rising_edge(clk); bvalid <= '0'; @@ -624,6 +631,7 @@ begin bvalid <= '1'; bresp <= axi_resp_okay; + bid <= x"25"; wait until (bready and bvalid) = '1' and rising_edge(clk); bvalid <= '0'; From 4efcc4f4484d2cdd275f9f91eb613d5086b270e3 Mon Sep 17 00:00:00 2001 From: David Martin Date: Thu, 23 May 2024 13:35:58 +0200 Subject: [PATCH 14/24] Moved reply checks to separated processes --- .../src/axi_master.vhd | 147 +++++++++++------- .../src/axi_master_pkg.vhd | 1 + .../test/tb_axi_master.vhd | 1 + 3 files changed, 96 insertions(+), 53 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index 8226eb21c..909de9dae 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -3,6 +3,7 @@ -- You can obtain one at http://mozilla.org/MPL/2.0/. -- -- Copyright (c) 2014-2024, Lars Asplund lars.anders.asplund@gmail.com +-- Author David Martin david.martin@phios.group library ieee; @@ -71,7 +72,9 @@ entity axi_master is end entity; architecture a of axi_master is - constant reply_queue, message_queue : queue_t := new_queue; + constant read_reply_queue, write_reply_queue, message_queue : queue_t := new_queue; + constant read_addr_queue, read_resp_queue, read_id_queue : queue_t := new_queue; + constant write_addr_queue, write_resp_queue, write_id_queue, write_data_queue : queue_t := new_queue; signal idle : boolean := true; begin @@ -129,13 +132,13 @@ begin variable request_msg : msg_t; variable msg_type : msg_type_t; - variable expected_resp : axi_resp_t; variable w_done, aw_done : boolean; -- These variables are needed to keep the values for logging when transaction is fully done - variable addr_this_transaction : std_logic_vector(awaddr'range) := (others => '0'); - variable wdata_this_transaction : std_logic_vector(wdata'range) := (others => '0'); - variable expected_id : std_logic_vector(rid'range) := (others => '0'); + variable addr : std_logic_vector(awaddr'range) := (others => '0'); + variable data : std_logic_vector(wdata'range) := (others => '0'); + variable id : std_logic_vector(rid'range) := (others => '0'); + variable resp : axi_resp_t; begin -- Initialization drive_ar_invalid; @@ -151,45 +154,36 @@ begin msg_type := message_type(request_msg); if is_read(msg_type) then - addr_this_transaction := pop_std_ulogic_vector(request_msg); + + addr := pop_std_ulogic_vector(request_msg); + araddr <= addr; if(is_axi_msg(msg_type)) then arlen <= pop_std_ulogic_vector(request_msg); arsize <= pop_std_ulogic_vector(request_msg); arburst <= pop_std_ulogic_vector(request_msg); - expected_id := pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); - arid <= expected_id; + id := pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); + arid <= id; + push(read_id_queue, id); end if; - expected_resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; - push(reply_queue, request_msg); + resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; + + push(read_addr_queue, addr); + push(read_resp_queue, resp); + push(read_reply_queue, request_msg); arvalid <= '1'; - araddr <= addr_this_transaction; wait until (arvalid and arready) = '1' and rising_edge(aclk); arvalid <= '0'; drive_ar_invalid; - rready <= '1'; - wait until (rvalid and rready) = '1' and rising_edge(aclk); - rready <= '0'; - - check_axi_resp(bus_handle, rresp, expected_resp, "rresp"); - - if(is_axi_msg(msg_type)) then - check_axi_id(bus_handle, rid, expected_id, "rid"); - end if; - - if is_visible(bus_handle.p_logger, debug) then - debug(bus_handle.p_logger, - "Read 0x" & to_hstring(rdata) & - " from address 0x" & to_hstring(addr_this_transaction)); - end if; - elsif is_write(msg_type) then - addr_this_transaction := pop_std_ulogic_vector(request_msg); - wdata_this_transaction := pop_std_ulogic_vector(request_msg); + addr := pop_std_ulogic_vector(request_msg); + awaddr <= addr; + data := pop_std_ulogic_vector(request_msg); + wdata <= data; wstrb <= pop_std_ulogic_vector(request_msg); if(is_axi_msg(msg_type)) then @@ -197,17 +191,19 @@ begin awsize <= pop_std_ulogic_vector(request_msg); awburst <= pop_std_ulogic_vector(request_msg); - expected_id := pop_std_ulogic_vector(request_msg)(awid'length -1 downto 0); - awid <= expected_id; + id := pop_std_ulogic_vector(request_msg)(awid'length -1 downto 0); + awid <= id; + push(write_id_queue, id); wlast <= pop_std_ulogic(request_msg); end if; - expected_resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; - delete(request_msg); - - awaddr <= addr_this_transaction; - wdata <= wdata_this_transaction; + resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; + + push(write_data_queue, data); + push(write_addr_queue, addr); + push(write_resp_queue, resp); + push(write_reply_queue, request_msg); wvalid <= '1'; awvalid <= '1'; @@ -231,22 +227,6 @@ begin w_done := true; end if; end loop; - - bready <= '1'; - wait until (bvalid and bready) = '1' and rising_edge(aclk); - bready <= '0'; - - check_axi_resp(bus_handle, bresp, expected_resp, "bresp"); - - if(is_axi_msg(msg_type)) then - check_axi_id(bus_handle, bid, expected_id, "bid"); - end if; - - if is_visible(bus_handle.p_logger, debug) then - debug(bus_handle.p_logger, - "Wrote 0x" & to_hstring(wdata_this_transaction) & - " to address 0x" & to_hstring(addr_this_transaction)); - end if; end if; idle <= true; @@ -256,13 +236,74 @@ begin -- Reply in separate process do not destroy alignment with the clock read_reply : process variable request_msg, reply_msg : msg_t; + variable msg_type : msg_type_t; + variable addr : std_logic_vector(awaddr'range) := (others => '0'); + variable resp : axi_resp_t; + variable id : std_logic_vector(rid'range) := (others => '0'); begin + + rready <= '1'; wait until (rvalid and rready) = '1' and rising_edge(aclk); - request_msg := pop(reply_queue); + rready <= '0'; + + request_msg := pop(read_reply_queue); + msg_type := message_type(request_msg); + addr := pop(read_addr_queue); + resp := pop(read_resp_queue); + + if(is_axi_msg(msg_type)) then + id := pop(read_id_queue); + check_axi_id(bus_handle, rid, id, "rid"); + end if; + + check_axi_resp(bus_handle, rresp, resp, "rresp"); + + if is_visible(bus_handle.p_logger, debug) then + debug(bus_handle.p_logger, + "Read 0x" & to_hstring(rdata) & + " from address 0x" & to_hstring(addr)); + end if; + reply_msg := new_msg; push_std_ulogic_vector(reply_msg, rdata); reply(net, request_msg, reply_msg); delete(request_msg); end process; + -- Reply in separate process do not destroy alignment with the clock + write_reply : process + variable request_msg, reply_msg : msg_t; + variable msg_type : msg_type_t; + variable addr : std_logic_vector(awaddr'range) := (others => '0'); + variable data : std_logic_vector(wdata'range) := (others => '0'); + variable resp : axi_resp_t; + variable id : std_logic_vector(rid'range) := (others => '0'); + begin + + bready <= '1'; + wait until (bvalid and bready) = '1' and rising_edge(aclk); + bready <= '0'; + + request_msg := pop(write_reply_queue); + msg_type := message_type(request_msg); + addr := pop(write_addr_queue); + data := pop(write_data_queue); + resp := pop(write_resp_queue); + + if(is_axi_msg(msg_type)) then + id := pop(write_id_queue); + check_axi_id(bus_handle, bid, id, "bid"); + end if; + + check_axi_resp(bus_handle, bresp, resp, "bresp"); + + if is_visible(bus_handle.p_logger, debug) then + debug(bus_handle.p_logger, + "Wrote 0x" & to_hstring(data) & + " to address 0x" & to_hstring(addr)); + end if; + + delete(request_msg); + end process; + end architecture; diff --git a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd index a9f1034ed..ce2431345 100644 --- a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd @@ -3,6 +3,7 @@ -- You can obtain one at http://mozilla.org/MPL/2.0/. -- -- Copyright (c) 2014-2024, Lars Asplund lars.anders.asplund@gmail.com +-- Author David Martin david.martin@phios.group library ieee; diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index 72a5fe42d..fde44765a 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -3,6 +3,7 @@ -- You can obtain one at http://mozilla.org/MPL/2.0/. -- -- Copyright (c) 2014-2024, Lars Asplund lars.anders.asplund@gmail.com +-- Author David Martin david.martin@phios.group library ieee; use ieee.std_logic_1164.all; From 89753ad051a23361cf1c8f8e9cfbb71c347682dc Mon Sep 17 00:00:00 2001 From: David Martin Date: Tue, 28 May 2024 13:37:20 +0200 Subject: [PATCH 15/24] Introduce axi master read burst procedures - dummy --- .../src/axi_master.vhd | 64 +++++++-- .../src/axi_master_pkg.vhd | 127 ++++++++++++++++-- .../test/tb_axi_master.vhd | 18 +-- 3 files changed, 178 insertions(+), 31 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index 909de9dae..c6124482b 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -8,15 +8,16 @@ library ieee; use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library osvvm; +use osvvm.RandomPkg.RandomPType; use work.axi_master_pkg.all; use work.axi_pkg.all; use work.axi_slave_private_pkg.check_axi_resp; use work.axi_slave_private_pkg.check_axi_id; -use work.bus_master_pkg.address_length; -use work.bus_master_pkg.bus_master_t; -use work.bus_master_pkg.byte_enable_length; -use work.bus_master_pkg.data_length; +use work.bus_master_pkg.all; use work.com_pkg.net; use work.com_pkg.receive; use work.com_pkg.reply; @@ -30,7 +31,9 @@ entity axi_master is generic ( bus_handle : bus_master_t; drive_invalid : boolean := true; - drive_invalid_val : std_logic := 'X' + drive_invalid_val : std_logic := 'X'; + write_high_probability : real range 0.0 to 1.0 := 1.0; + read_high_probability : real range 0.0 to 1.0 := 1.0 ); port ( aclk : in std_logic; @@ -73,7 +76,7 @@ end entity; architecture a of axi_master is constant read_reply_queue, write_reply_queue, message_queue : queue_t := new_queue; - constant read_addr_queue, read_resp_queue, read_id_queue : queue_t := new_queue; + constant read_addr_queue, read_resp_queue, read_id_queue, read_len_queue : queue_t := new_queue; constant write_addr_queue, write_resp_queue, write_id_queue, write_data_queue : queue_t := new_queue; signal idle : boolean := true; begin @@ -130,6 +133,7 @@ begin end if; end procedure; + variable rnd : RandomPType; variable request_msg : msg_t; variable msg_type : msg_type_t; variable w_done, aw_done : boolean; @@ -138,9 +142,12 @@ begin variable addr : std_logic_vector(awaddr'range) := (others => '0'); variable data : std_logic_vector(wdata'range) := (others => '0'); variable id : std_logic_vector(rid'range) := (others => '0'); + variable len : std_logic_vector(arlen'range) := (others => '0'); + variable burst : positive; variable resp : axi_resp_t; begin -- Initialization + rnd.InitSeed(rnd'instance_name); drive_ar_invalid; drive_aw_invalid; drive_w_invalid; @@ -154,15 +161,36 @@ begin msg_type := message_type(request_msg); if is_read(msg_type) then + while rnd.Uniform(0.0, 1.0) > read_high_probability loop + wait until rising_edge(aclk); + end loop; addr := pop_std_ulogic_vector(request_msg); araddr <= addr; - if(is_axi_msg(msg_type)) then - arlen <= pop_std_ulogic_vector(request_msg); + if msg_type = bus_read_msg then + arlen(arlen'range) <= (others => '0'); + arsize(arsize'range) <= (others => '0'); + arburst(arburst'range) <= (others => '0'); + arid(arid'range) <= (others => '0'); + elsif msg_type = bus_burst_read_msg then + burst := pop_integer(request_msg); + arlen <= std_logic_vector(to_unsigned(burst, arlen'length)); + arsize(arsize'range) <= (others => '0'); + arburst(arburst'range) <= (others => '0'); + arid(arid'range) <= (others => '0'); + elsif msg_type = axi_read_msg then + arlen(arlen'range) <= (others => '0'); + arsize <= pop_std_ulogic_vector(request_msg); + arburst(arburst'range) <= (others => '0'); + id := pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); + arid <= id; + push(read_id_queue, id); + elsif msg_type = axi_burst_read_msg then + len := pop_std_ulogic_vector(request_msg); + arlen <= len; arsize <= pop_std_ulogic_vector(request_msg); arburst <= pop_std_ulogic_vector(request_msg); - id := pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); arid <= id; push(read_id_queue, id); @@ -180,6 +208,9 @@ begin drive_ar_invalid; elsif is_write(msg_type) then + while rnd.Uniform(0.0, 1.0) > write_high_probability loop + wait until rising_edge(aclk); + end loop; addr := pop_std_ulogic_vector(request_msg); awaddr <= addr; data := pop_std_ulogic_vector(request_msg); @@ -227,6 +258,8 @@ begin w_done := true; end if; end loop; + else + unexpected_msg_type(msg_type); end if; idle <= true; @@ -237,7 +270,7 @@ begin read_reply : process variable request_msg, reply_msg : msg_t; variable msg_type : msg_type_t; - variable addr : std_logic_vector(awaddr'range) := (others => '0'); + variable addr : std_logic_vector(araddr'range) := (others => '0'); variable resp : axi_resp_t; variable id : std_logic_vector(rid'range) := (others => '0'); begin @@ -246,12 +279,20 @@ begin wait until (rvalid and rready) = '1' and rising_edge(aclk); rready <= '0'; + reply_msg := new_msg; request_msg := pop(read_reply_queue); msg_type := message_type(request_msg); addr := pop(read_addr_queue); resp := pop(read_resp_queue); - if(is_axi_msg(msg_type)) then + if msg_type = bus_read_msg then + + elsif msg_type = bus_burst_read_msg then + + elsif msg_type = axi_read_msg then + id := pop(read_id_queue); + check_axi_id(bus_handle, rid, id, "rid"); + elsif msg_type = axi_burst_read_msg then id := pop(read_id_queue); check_axi_id(bus_handle, rid, id, "rid"); end if; @@ -264,7 +305,6 @@ begin " from address 0x" & to_hstring(addr)); end if; - reply_msg := new_msg; push_std_ulogic_vector(reply_msg, rdata); reply(net, request_msg, reply_msg); delete(request_msg); diff --git a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd index ce2431345..02e3d8e81 100644 --- a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd @@ -20,6 +20,8 @@ package axi_master_pkg is constant axi_read_msg : msg_type_t := new_msg_type("read axi "); constant axi_write_msg : msg_type_t := new_msg_type("write axi "); + constant axi_burst_read_msg : msg_type_t := new_msg_type("read axi burst "); + constant axi_burst_write_msg : msg_type_t := new_msg_type("write axi burst "); -- Blocking: Write the bus procedure write_axi(signal net : inout network_t; @@ -37,6 +39,34 @@ package axi_master_pkg is -- Non blocking: Read the bus returning a reference to the future reply procedure read_axi(signal net : inout network_t; + constant bus_handle : bus_master_t; + constant address : std_logic_vector; + constant size : std_logic_vector; + constant id : std_logic_vector := ""; + constant expected_rresp : axi_resp_t := axi_resp_okay; + variable reference : inout bus_reference_t); + + -- Blocking: read bus with immediate reply + procedure read_axi(signal net : inout network_t; + constant bus_handle : bus_master_t; + constant address : std_logic_vector; + constant size : std_logic_vector; + constant id : std_logic_vector := ""; + constant expected_rresp : axi_resp_t := axi_resp_okay; + variable data : inout std_logic_vector); + + -- Blocking: Read bus and check result against expected data + procedure check_axi(signal net : inout network_t; + constant bus_handle : bus_master_t; + constant address : std_logic_vector; + constant size : std_logic_vector; + constant id : std_logic_vector := ""; + constant expected_rresp : axi_resp_t := axi_resp_okay; + constant expected : std_logic_vector; + constant msg : string := ""); + + -- Non blocking: Read the bus returning a reference to the future reply + procedure burst_read_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; constant len : std_logic_vector; @@ -47,7 +77,7 @@ package axi_master_pkg is variable reference : inout bus_reference_t); -- Blocking: read bus with immediate reply - procedure read_axi(signal net : inout network_t; + procedure burst_read_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; constant len : std_logic_vector; @@ -58,7 +88,7 @@ package axi_master_pkg is variable data : inout std_logic_vector); -- Blocking: Read bus and check result against expected data - procedure check_axi(signal net : inout network_t; + procedure burst_check_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; constant len : std_logic_vector; @@ -135,6 +165,83 @@ package body axi_master_pkg is end procedure; procedure read_axi(signal net : inout network_t; + constant bus_handle : bus_master_t; + constant address : std_logic_vector; + constant size : std_logic_vector; + constant id : std_logic_vector := ""; + constant expected_rresp : axi_resp_t := axi_resp_okay; + variable reference : inout bus_reference_t) is + variable full_address : std_logic_vector(bus_handle.p_address_length - 1 downto 0) := (others => '0'); + variable full_size : std_logic_vector(size_length(bus_handle) - 1 downto 0) := (others => '0'); + variable full_id : std_logic_vector(id_length(bus_handle) - 1 downto 0) := (others => '0'); + alias request_msg : msg_t is reference; + begin + request_msg := new_msg(axi_read_msg); + full_address(address'length - 1 downto 0) := address; + push_std_ulogic_vector(request_msg, full_address); + + full_size(size'length - 1 downto 0) := size; + push_std_ulogic_vector(request_msg, full_size); + + if id = "" then + full_id := (others => '0'); + else + full_id(id'length - 1 downto 0) := id; + end if; + push_std_ulogic_vector(request_msg, full_id); + + push_std_ulogic_vector(request_msg, expected_rresp); + send(net, bus_handle.p_actor, request_msg); + end procedure; + + procedure read_axi(signal net : inout network_t; + constant bus_handle : bus_master_t; + constant address : std_logic_vector; + constant size : std_logic_vector; + constant id : std_logic_vector := ""; + constant expected_rresp : axi_resp_t := axi_resp_okay; + variable data : inout std_logic_vector) is + variable reference : bus_reference_t; + begin + read_axi(net, bus_handle, address, size, id, expected_rresp, reference); + await_read_bus_reply(net, reference, data); + end procedure; + + procedure check_axi(signal net : inout network_t; + constant bus_handle : bus_master_t; + constant address : std_logic_vector; + constant size : std_logic_vector; + constant id : std_logic_vector := ""; + constant expected_rresp : axi_resp_t := axi_resp_okay; + constant expected : std_logic_vector; + constant msg : string := "") is + variable data : std_logic_vector(bus_handle.p_data_length - 1 downto 0); + variable edata : std_logic_vector(data'range) := (others => '0'); + + impure function error_prefix return string is + begin + if msg = "" then + return "check_bus(x""" & to_hstring(address) & """)"; + else + return msg; + end if; + end; + + impure function base_error return string is + begin + return error_prefix & " - Got x""" & to_hstring(data) & """ expected x""" & to_hstring(edata) & """"; + end; + begin + + edata(expected'length - 1 downto 0) := expected; + + read_axi(net, bus_handle, address, size, id, expected_rresp, data); + if not std_match(data, edata) then + failure(bus_handle.p_logger, base_error); + end if; + end procedure; + + procedure burst_read_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; constant len : std_logic_vector; @@ -149,7 +256,7 @@ package body axi_master_pkg is variable full_id : std_logic_vector(id_length(bus_handle) - 1 downto 0) := (others => '0'); alias request_msg : msg_t is reference; begin - request_msg := new_msg(axi_read_msg); + request_msg := new_msg(axi_burst_read_msg); full_address(address'length - 1 downto 0) := address; push_std_ulogic_vector(request_msg, full_address); @@ -172,7 +279,7 @@ package body axi_master_pkg is send(net, bus_handle.p_actor, request_msg); end procedure; - procedure read_axi(signal net : inout network_t; + procedure burst_read_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; constant len : std_logic_vector; @@ -183,11 +290,11 @@ package body axi_master_pkg is variable data : inout std_logic_vector) is variable reference : bus_reference_t; begin - read_axi(net, bus_handle, address, len, size, burst, id, expected_rresp, reference); + burst_read_axi(net, bus_handle, address, len, size, burst, id, expected_rresp, reference); await_read_bus_reply(net, reference, data); end procedure; - procedure check_axi(signal net : inout network_t; + procedure burst_check_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; constant len : std_logic_vector; @@ -217,7 +324,7 @@ package body axi_master_pkg is edata(expected'length - 1 downto 0) := expected; - read_axi(net, bus_handle, address, len, size, burst, id, expected_rresp, data); + burst_read_axi(net, bus_handle, address, len, size, burst, id, expected_rresp, data); if not std_match(data, edata) then failure(bus_handle.p_logger, base_error); end if; @@ -225,17 +332,17 @@ package body axi_master_pkg is function is_read(msg_type : msg_type_t) return boolean is begin - return msg_type = bus_read_msg or msg_type = axi_read_msg; + return msg_type = bus_read_msg or msg_type = axi_read_msg or msg_type = bus_burst_read_msg or msg_type = axi_burst_read_msg; end function; function is_write(msg_type : msg_type_t) return boolean is begin - return msg_type = bus_write_msg or msg_type = axi_write_msg; + return msg_type = bus_write_msg or msg_type = axi_write_msg or msg_type = bus_burst_write_msg or msg_type = axi_burst_write_msg; end function; function is_axi_msg(msg_type : msg_type_t) return boolean is begin - return msg_type = axi_read_msg or msg_type = axi_write_msg; + return msg_type = axi_read_msg or msg_type = axi_write_msg or msg_type = axi_burst_read_msg or msg_type = axi_burst_write_msg; end function; function len_length(bus_handle : bus_master_t) return natural is diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index fde44765a..a5110088e 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -109,10 +109,10 @@ begin read_bus(net, bus_handle, x"01234567", tmp); elsif run("Test read with axi resp") then - read_axi(net, bus_handle, x"01234567", x"00", "111" , axi_burst_type_fixed, x"25", axi_resp_slverr, tmp); + read_axi(net, bus_handle, x"01234567", "111", x"25", axi_resp_slverr, tmp); elsif run("Test read with wrong axi resp") then - read_axi(net, bus_handle, x"01234567", x"00", "111" , axi_burst_type_fixed, x"25", axi_resp_exokay, tmp); + read_axi(net, bus_handle, x"01234567", "111", x"25", axi_resp_exokay, tmp); elsif run("Test random") then for i in 0 to num_random_tests-1 loop @@ -127,7 +127,7 @@ begin elsif run("Test random axi resp") then for i in 0 to num_random_tests-1 loop if rnd.RandInt(0, 1) = 0 then - read_axi(net, bus_handle, rnd.RandSlv(araddr'length), x"00", "111" , axi_burst_type_fixed, x"25", rnd.RandSlv(axi_resp_t'length), tmp); + read_axi(net, bus_handle, rnd.RandSlv(araddr'length), "111", x"25", rnd.RandSlv(axi_resp_t'length), tmp); check_equal(tmp, rnd.RandSlv(rdata'length), "read data"); else write_axi(net, bus_handle, rnd.RandSlv(awaddr'length), rnd.RandSlv(wdata'length), @@ -156,10 +156,10 @@ begin write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, '0', x"25"); elsif run("Test single read with id") then - read_axi(net, bus_handle, x"01234567", x"00", "111" , axi_burst_type_fixed, x"25", axi_resp_okay, tmp); + read_axi(net, bus_handle, x"01234567", "111", x"25", axi_resp_okay, tmp); elsif run("Test single read with len") then - read_axi(net, bus_handle, x"01234567", x"12", "111" , axi_burst_type_fixed, x"25", axi_resp_okay, tmp); + read_axi(net, bus_handle, x"01234567", "111", x"25", axi_resp_okay, tmp); elsif run("Test single write with len") then write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, '0', x"25"); @@ -171,10 +171,10 @@ begin write_axi(net, bus_handle, x"01234567", x"1122", x"12", "010" , axi_burst_type_incr, '0', x"25"); elsif run("Test single read with size") then - read_axi(net, bus_handle, x"01234567", x"12", "101" , axi_burst_type_fixed, x"25", axi_resp_okay, tmp); + read_axi(net, bus_handle, x"01234567", "101", x"25", axi_resp_okay, tmp); elsif run("Test single read with burst") then - read_axi(net, bus_handle, x"01234567", x"12", "111" , axi_burst_type_incr, x"25", axi_resp_okay, tmp); + read_axi(net, bus_handle, x"01234567", "111", x"25", axi_resp_okay, tmp); elsif run("Test single write with last") then write_axi(net, bus_handle, x"01234567", x"1122", x"12", "010" , axi_burst_type_incr, '1', x"25"); @@ -510,7 +510,7 @@ begin wait until (arready and arvalid) = '1' and rising_edge(clk); arready <= '0'; check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); - check_equal(arlen, std_logic_vector'(x"12"), "arid"); + --check_equal(arlen, std_logic_vector'(x"12"), "arlen"); rvalid <= '1'; rresp <= axi_resp_okay; @@ -605,7 +605,7 @@ begin wait until (arready and arvalid) = '1' and rising_edge(clk); arready <= '0'; check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); - check_equal(arburst, axi_burst_type_incr, "arburst"); + --check_equal(arburst, axi_burst_type_incr, "arburst"); rvalid <= '1'; rresp <= axi_resp_okay; From b45f3ab20e39e0b0ab05670f0b2b9e46afbf4596 Mon Sep 17 00:00:00 2001 From: David Martin Date: Tue, 28 May 2024 14:24:31 +0200 Subject: [PATCH 16/24] Removed additional data queues --- .../src/axi_master.vhd | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index c6124482b..0b0e557c9 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -76,8 +76,6 @@ end entity; architecture a of axi_master is constant read_reply_queue, write_reply_queue, message_queue : queue_t := new_queue; - constant read_addr_queue, read_resp_queue, read_id_queue, read_len_queue : queue_t := new_queue; - constant write_addr_queue, write_resp_queue, write_id_queue, write_data_queue : queue_t := new_queue; signal idle : boolean := true; begin @@ -166,6 +164,7 @@ begin end loop; addr := pop_std_ulogic_vector(request_msg); + push_std_ulogic_vector(request_msg, addr); araddr <= addr; if msg_type = bus_read_msg then @@ -176,6 +175,7 @@ begin elsif msg_type = bus_burst_read_msg then burst := pop_integer(request_msg); arlen <= std_logic_vector(to_unsigned(burst, arlen'length)); + push_integer(request_msg, burst); arsize(arsize'range) <= (others => '0'); arburst(arburst'range) <= (others => '0'); arid(arid'range) <= (others => '0'); @@ -185,21 +185,20 @@ begin arburst(arburst'range) <= (others => '0'); id := pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); arid <= id; - push(read_id_queue, id); + push_std_ulogic_vector(request_msg, id); elsif msg_type = axi_burst_read_msg then len := pop_std_ulogic_vector(request_msg); + push_std_ulogic_vector(request_msg, len); arlen <= len; arsize <= pop_std_ulogic_vector(request_msg); arburst <= pop_std_ulogic_vector(request_msg); id := pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); arid <= id; - push(read_id_queue, id); + push_std_ulogic_vector(request_msg, id); end if; resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; - - push(read_addr_queue, addr); - push(read_resp_queue, resp); + push(request_msg, resp); push(read_reply_queue, request_msg); arvalid <= '1'; @@ -212,8 +211,10 @@ begin wait until rising_edge(aclk); end loop; addr := pop_std_ulogic_vector(request_msg); + push_std_ulogic_vector(request_msg, addr); awaddr <= addr; data := pop_std_ulogic_vector(request_msg); + push_std_ulogic_vector(request_msg, data); wdata <= data; wstrb <= pop_std_ulogic_vector(request_msg); @@ -223,17 +224,14 @@ begin awburst <= pop_std_ulogic_vector(request_msg); id := pop_std_ulogic_vector(request_msg)(awid'length -1 downto 0); + push_std_ulogic_vector(request_msg, id); awid <= id; - push(write_id_queue, id); - + wlast <= pop_std_ulogic(request_msg); end if; resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; - - push(write_data_queue, data); - push(write_addr_queue, addr); - push(write_resp_queue, resp); + push_std_ulogic_vector(request_msg, resp); push(write_reply_queue, request_msg); wvalid <= '1'; @@ -282,21 +280,21 @@ begin reply_msg := new_msg; request_msg := pop(read_reply_queue); msg_type := message_type(request_msg); - addr := pop(read_addr_queue); - resp := pop(read_resp_queue); - + addr := pop_std_ulogic_vector(request_msg); + if msg_type = bus_read_msg then elsif msg_type = bus_burst_read_msg then elsif msg_type = axi_read_msg then - id := pop(read_id_queue); + id := pop_std_ulogic_vector(request_msg); check_axi_id(bus_handle, rid, id, "rid"); elsif msg_type = axi_burst_read_msg then - id := pop(read_id_queue); + id := pop_std_ulogic_vector(request_msg); check_axi_id(bus_handle, rid, id, "rid"); end if; + resp := pop_std_ulogic_vector(request_msg); check_axi_resp(bus_handle, rresp, resp, "rresp"); if is_visible(bus_handle.p_logger, debug) then @@ -326,15 +324,15 @@ begin request_msg := pop(write_reply_queue); msg_type := message_type(request_msg); - addr := pop(write_addr_queue); - data := pop(write_data_queue); - resp := pop(write_resp_queue); + addr := pop_std_ulogic_vector(request_msg); + data := pop_std_ulogic_vector(request_msg); if(is_axi_msg(msg_type)) then - id := pop(write_id_queue); + id := pop_std_ulogic_vector(request_msg); check_axi_id(bus_handle, bid, id, "bid"); end if; + resp := pop_std_ulogic_vector(request_msg); check_axi_resp(bus_handle, bresp, resp, "bresp"); if is_visible(bus_handle.p_logger, debug) then From 44f2381f5c3f09585f9e0a1e38ec6ae1e8dd3563 Mon Sep 17 00:00:00 2001 From: David Martin Date: Tue, 4 Jun 2024 16:28:52 +0200 Subject: [PATCH 17/24] Added axi read burst and refactoring --- .../src/axi_master.vhd | 128 ++-- .../src/axi_master_pkg.vhd | 103 +-- .../test/tb_axi_master.vhd | 674 ++++-------------- 3 files changed, 248 insertions(+), 657 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index 0b0e557c9..098a44556 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -9,6 +9,7 @@ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; +use ieee.math_real.all; library osvvm; use osvvm.RandomPkg.RandomPType; @@ -131,17 +132,22 @@ begin end if; end procedure; + function get_full_size return std_logic_vector is + begin + return std_logic_vector(to_unsigned(integer(ceil(log2(real(rdata'length/8)))), arsize'length)); + end function; + variable rnd : RandomPType; variable request_msg : msg_t; variable msg_type : msg_type_t; variable w_done, aw_done : boolean; - -- These variables are needed to keep the values for logging when transaction is fully done variable addr : std_logic_vector(awaddr'range) := (others => '0'); variable data : std_logic_vector(wdata'range) := (others => '0'); variable id : std_logic_vector(rid'range) := (others => '0'); - variable len : std_logic_vector(arlen'range) := (others => '0'); - variable burst : positive; + variable len : natural := 0; + variable size : std_logic_vector(arsize'range) := (others => '0'); + variable burst : std_logic_vector(arburst'range) := (others => '0'); variable resp : axi_resp_t; begin -- Initialization @@ -164,41 +170,47 @@ begin end loop; addr := pop_std_ulogic_vector(request_msg); - push_std_ulogic_vector(request_msg, addr); - araddr <= addr; if msg_type = bus_read_msg then - arlen(arlen'range) <= (others => '0'); - arsize(arsize'range) <= (others => '0'); - arburst(arburst'range) <= (others => '0'); - arid(arid'range) <= (others => '0'); + len := 0; + size := get_full_size; + burst := axi_burst_type_fixed; + id(id'range) := (others => '0'); elsif msg_type = bus_burst_read_msg then - burst := pop_integer(request_msg); - arlen <= std_logic_vector(to_unsigned(burst, arlen'length)); - push_integer(request_msg, burst); - arsize(arsize'range) <= (others => '0'); - arburst(arburst'range) <= (others => '0'); - arid(arid'range) <= (others => '0'); + len := pop_integer(request_msg) - 1; -- bring bus burst down to axi zero based indexing + size := get_full_size; + burst := axi_burst_type_incr; + id(id'range) := (others => '0'); elsif msg_type = axi_read_msg then - arlen(arlen'range) <= (others => '0'); - arsize <= pop_std_ulogic_vector(request_msg); - arburst(arburst'range) <= (others => '0'); + len := 0; + size := pop_std_ulogic_vector(request_msg); + burst := axi_burst_type_fixed; id := pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); - arid <= id; - push_std_ulogic_vector(request_msg, id); elsif msg_type = axi_burst_read_msg then - len := pop_std_ulogic_vector(request_msg); - push_std_ulogic_vector(request_msg, len); - arlen <= len; - arsize <= pop_std_ulogic_vector(request_msg); - arburst <= pop_std_ulogic_vector(request_msg); + len := to_integer(unsigned(pop_std_ulogic_vector(request_msg))); + size := pop_std_ulogic_vector(request_msg); + burst := pop_std_ulogic_vector(request_msg); id := pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); - arid <= id; - push_std_ulogic_vector(request_msg, id); end if; + araddr <= addr; + push_std_ulogic_vector(request_msg, addr); + + arlen <= std_logic_vector(to_unsigned(len, arlen'length)); + push_integer(request_msg, len); + + arsize <= size; + push_std_ulogic_vector(request_msg, size); + + arburst <= burst; + push_std_ulogic_vector(request_msg, burst); + + arid <= id; + push_std_ulogic_vector(request_msg, id); + resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; push(request_msg, resp); + push(read_reply_queue, request_msg); arvalid <= '1'; @@ -226,7 +238,7 @@ begin id := pop_std_ulogic_vector(request_msg)(awid'length -1 downto 0); push_std_ulogic_vector(request_msg, id); awid <= id; - + wlast <= pop_std_ulogic(request_msg); end if; @@ -268,42 +280,56 @@ begin read_reply : process variable request_msg, reply_msg : msg_t; variable msg_type : msg_type_t; - variable addr : std_logic_vector(araddr'range) := (others => '0'); - variable resp : axi_resp_t; + variable addr : std_logic_vector(awaddr'range) := (others => '0'); variable id : std_logic_vector(rid'range) := (others => '0'); + variable len : natural := 0; + variable size : std_logic_vector(arsize'range) := (others => '0'); + variable burst : std_logic_vector(arburst'range) := (others => '0'); + variable resp : axi_resp_t; + + procedure write_debug is + begin + if is_visible(bus_handle.p_logger, debug) then + debug(bus_handle.p_logger, + "Read 0x" & to_hstring(rdata) & + " from address 0x" & to_hstring(addr)); + end if; + end procedure; begin rready <= '1'; wait until (rvalid and rready) = '1' and rising_edge(aclk); - rready <= '0'; - + reply_msg := new_msg; request_msg := pop(read_reply_queue); msg_type := message_type(request_msg); - addr := pop_std_ulogic_vector(request_msg); - - if msg_type = bus_read_msg then - elsif msg_type = bus_burst_read_msg then - - elsif msg_type = axi_read_msg then - id := pop_std_ulogic_vector(request_msg); - check_axi_id(bus_handle, rid, id, "rid"); - elsif msg_type = axi_burst_read_msg then - id := pop_std_ulogic_vector(request_msg); - check_axi_id(bus_handle, rid, id, "rid"); + addr := pop_std_ulogic_vector(request_msg); + len := pop_integer(request_msg); + size := pop_std_ulogic_vector(request_msg); + burst := pop_std_ulogic_vector(request_msg); + id := pop_std_ulogic_vector(request_msg); + resp := pop(request_msg); + + if msg_type = bus_burst_read_msg or msg_type = axi_burst_read_msg then + push_integer(reply_msg, len + 1); -- bring axi burst up to bus one based indexing end if; - resp := pop_std_ulogic_vector(request_msg); + -- first iteration + check_axi_id(bus_handle, rid, id, "rid"); check_axi_resp(bus_handle, rresp, resp, "rresp"); - - if is_visible(bus_handle.p_logger, debug) then - debug(bus_handle.p_logger, - "Read 0x" & to_hstring(rdata) & - " from address 0x" & to_hstring(addr)); - end if; - + write_debug; push_std_ulogic_vector(reply_msg, rdata); + + -- burst iterations + for i in 0 to len - 1 loop + wait until (rvalid and rready) = '1' and rising_edge(aclk); + check_axi_id(bus_handle, rid, id, "rid"); + check_axi_resp(bus_handle, rresp, resp, "rresp"); + write_debug; + push_std_ulogic_vector(reply_msg, rdata); + end loop; + reply(net, request_msg, reply_msg); delete(request_msg); end process; diff --git a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd index 02e3d8e81..860947b6c 100644 --- a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd @@ -15,6 +15,7 @@ use work.bus_master_pkg.all; use work.com_pkg.send; use work.com_types_pkg.all; use work.logger_pkg.all; +use work.queue_pkg.all; package axi_master_pkg is @@ -85,19 +86,19 @@ package axi_master_pkg is constant burst : axi_burst_type_t; constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; - variable data : inout std_logic_vector); + constant data : queue_t); -- Blocking: Read bus and check result against expected data - procedure burst_check_axi(signal net : inout network_t; - constant bus_handle : bus_master_t; - constant address : std_logic_vector; - constant len : std_logic_vector; - constant size : std_logic_vector; - constant burst : axi_burst_type_t; - constant id : std_logic_vector := ""; - constant expected_rresp : axi_resp_t := axi_resp_okay; - constant expected : std_logic_vector; - constant msg : string := ""); + -- procedure burst_check_axi(signal net : inout network_t; + -- constant bus_handle : bus_master_t; + -- constant address : std_logic_vector; + -- constant len : std_logic_vector; + -- constant size : std_logic_vector; + -- constant burst : axi_burst_type_t; + -- constant id : std_logic_vector := ""; + -- constant expected_rresp : axi_resp_t := axi_resp_okay; + -- constant expected : std_logic_vector; + -- constant msg : string := ""); function is_read(msg_type : msg_type_t) return boolean; function is_write(msg_type : msg_type_t) return boolean; @@ -287,48 +288,48 @@ package body axi_master_pkg is constant burst : axi_burst_type_t; constant id : std_logic_vector := ""; constant expected_rresp : axi_resp_t := axi_resp_okay; - variable data : inout std_logic_vector) is + constant data : queue_t) is variable reference : bus_reference_t; begin burst_read_axi(net, bus_handle, address, len, size, burst, id, expected_rresp, reference); - await_read_bus_reply(net, reference, data); + await_burst_read_bus_reply(net, bus_handle, data, reference); end procedure; - procedure burst_check_axi(signal net : inout network_t; - constant bus_handle : bus_master_t; - constant address : std_logic_vector; - constant len : std_logic_vector; - constant size : std_logic_vector; - constant burst : axi_burst_type_t; - constant id : std_logic_vector := ""; - constant expected_rresp : axi_resp_t := axi_resp_okay; - constant expected : std_logic_vector; - constant msg : string := "") is - variable data : std_logic_vector(bus_handle.p_data_length - 1 downto 0); - variable edata : std_logic_vector(data'range) := (others => '0'); - - impure function error_prefix return string is - begin - if msg = "" then - return "check_bus(x""" & to_hstring(address) & """)"; - else - return msg; - end if; - end; - - impure function base_error return string is - begin - return error_prefix & " - Got x""" & to_hstring(data) & """ expected x""" & to_hstring(edata) & """"; - end; - begin - - edata(expected'length - 1 downto 0) := expected; - - burst_read_axi(net, bus_handle, address, len, size, burst, id, expected_rresp, data); - if not std_match(data, edata) then - failure(bus_handle.p_logger, base_error); - end if; - end procedure; + -- procedure burst_check_axi(signal net : inout network_t; + -- constant bus_handle : bus_master_t; + -- constant address : std_logic_vector; + -- constant len : std_logic_vector; + -- constant size : std_logic_vector; + -- constant burst : axi_burst_type_t; + -- constant id : std_logic_vector := ""; + -- constant expected_rresp : axi_resp_t := axi_resp_okay; + -- constant expected : std_logic_vector; + -- constant msg : string := "") is + -- variable data : std_logic_vector(bus_handle.p_data_length - 1 downto 0); + -- variable edata : std_logic_vector(data'range) := (others => '0'); + + -- impure function error_prefix return string is + -- begin + -- if msg = "" then + -- return "check_bus(x""" & to_hstring(address) & """)"; + -- else + -- return msg; + -- end if; + -- end; + + -- impure function base_error return string is + -- begin + -- return error_prefix & " - Got x""" & to_hstring(data) & """ expected x""" & to_hstring(edata) & """"; + -- end; + -- begin + + -- edata(expected'length - 1 downto 0) := expected; + + -- burst_read_axi(net, bus_handle, address, len, size, burst, id, expected_rresp, data); + -- if not std_match(data, edata) then + -- failure(bus_handle.p_logger, base_error); + -- end if; + -- end procedure; function is_read(msg_type : msg_type_t) return boolean is begin @@ -347,16 +348,16 @@ package body axi_master_pkg is function len_length(bus_handle : bus_master_t) return natural is begin - return 8; -- Add to bus_master_t? + return 8; -- TODO Add to bus_master_t? end; function id_length(bus_handle : bus_master_t) return natural is begin - return 32; -- Add to bus_master_t? + return 32; -- TODO Add to bus_master_t? end; function size_length(bus_handle : bus_master_t) return natural is begin - return 3; -- Add to bus_master_t? + return 3; -- TODO Add to bus_master_t? end; end package body; diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index a5110088e..320a63a21 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -16,6 +16,8 @@ context work.com_context; use work.axi_pkg.all; use work.bus_master_pkg.all; use work.axi_master_pkg.all; +use work.axi_slave_pkg.all; +use work.memory_pkg.all; library osvvm; use osvvm.RandomPkg.all; @@ -66,580 +68,121 @@ architecture a of tb_axi_master is constant bus_handle : bus_master_t := new_bus(data_length => wdata'length, address_length => awaddr'length); - signal start, done : boolean := false; + constant memory : memory_t := new_memory; + constant axi_rd_slave : axi_slave_t := new_axi_slave(memory => memory, + logger => get_logger("axi_rd_slave")); + + constant axi_wr_slave : axi_slave_t := new_axi_slave(memory => memory, + logger => get_logger("axi_wr_slave")); + + constant tb_logger : logger_t := get_logger("tb"); begin main : process - variable tmp : std_logic_vector(rdata'range); + variable rnd : RandomPType; - variable timestamp : time; + + procedure setup_and_set_random_data_read_memory( + memory : memory_t; + num_words : positive; + width : positive; + data : queue_t + ) is + variable rd_buffer : buffer_t; + variable rand : std_logic_vector(width - 1 downto 0); + begin + clear(memory); + rd_buffer := allocate(memory, + num_bytes => num_words * (width / 8), + name => rd_buffer'simple_name, + permissions => read_only); + + for i in 0 to num_words - 1 loop + rand := rnd.RandSlv(width); + write_word(memory, base_address(rd_buffer) + (i*(width/8)), rand); + push(data, rand); + end loop; + end; + + variable read_data_queue : queue_t := new_queue; + variable memory_data_queue : queue_t := new_queue; + + variable read_tmp : std_logic_vector(rdata'range); + variable memory_tmp : std_logic_vector(rdata'range); + + variable burst : natural := 0; begin test_runner_setup(runner, runner_cfg); rnd.InitSeed("common_seed"); - start <= true; wait for 0 ns; - if run("Test single write") then - mock(get_logger(bus_handle), debug); - write_bus(net, bus_handle, x"01234567", x"1122"); - wait_until_idle(net, bus_handle); - check_only_log(get_logger(bus_handle), "Wrote 0x1122 to address 0x01234567", debug); - unmock(get_logger(bus_handle)); - - elsif run("Test single write with byte enable") then - write_bus(net, bus_handle, x"01234567", x"1122", byte_enable => "10"); - - elsif run("Test write not okay") then - write_bus(net, bus_handle, x"01234567", x"1122"); - - elsif run("Test write with axi resp") then - write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, '0', x"25", axi_resp_slverr); - - elsif run("Test write with wrong axi resp") then - write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, '0', x"25", axi_resp_decerr); - - elsif run("Test single read") then - mock(get_logger(bus_handle), debug); - read_bus(net, bus_handle, x"01234567", tmp); - check_equal(tmp, std_logic_vector'(x"5566"), "read data"); - check_only_log(get_logger(bus_handle), "Read 0x5566 from address 0x01234567", debug); - unmock(get_logger(bus_handle)); - - elsif run("Test read not okay") then - read_bus(net, bus_handle, x"01234567", tmp); - - elsif run("Test read with axi resp") then - read_axi(net, bus_handle, x"01234567", "111", x"25", axi_resp_slverr, tmp); - - elsif run("Test read with wrong axi resp") then - read_axi(net, bus_handle, x"01234567", "111", x"25", axi_resp_exokay, tmp); - - elsif run("Test random") then - for i in 0 to num_random_tests-1 loop - if rnd.RandInt(0, 1) = 0 then - read_bus(net, bus_handle, rnd.RandSlv(araddr'length), tmp); - check_equal(tmp, rnd.RandSlv(rdata'length), "read data"); - else - write_bus(net, bus_handle, rnd.RandSlv(awaddr'length), rnd.RandSlv(wdata'length)); - end if; - end loop; - - elsif run("Test random axi resp") then - for i in 0 to num_random_tests-1 loop - if rnd.RandInt(0, 1) = 0 then - read_axi(net, bus_handle, rnd.RandSlv(araddr'length), "111", x"25", rnd.RandSlv(axi_resp_t'length), tmp); - check_equal(tmp, rnd.RandSlv(rdata'length), "read data"); - else - write_axi(net, bus_handle, rnd.RandSlv(awaddr'length), rnd.RandSlv(wdata'length), - x"12", "111" , axi_burst_type_fixed, '0', x"25", rnd.RandSlv(axi_resp_t'length)); - end if; + if run("Test read with read_bus") then + for n in 0 to 4 loop + info(tb_logger, "Setup..."); + burst := 1; + setup_and_set_random_data_read_memory(memory, burst, rdata'length, memory_data_queue); + info(tb_logger, "Reading..."); + read_bus(net, bus_handle, 0, read_tmp); + info(tb_logger, "Compare..."); + memory_tmp := pop(memory_data_queue); + check_equal(read_tmp, memory_tmp, "read data"); + check_true(is_empty(memory_data_queue), "memory_data_queue not flushed"); end loop; - - elsif run("Test idle when idle") then - wait until rising_edge(clk); - write_bus(net, bus_handle, x"01234567", x"1122"); - wait for 0 ps; - timestamp := now; - wait_until_idle(net, bus_handle); - check(now > timestamp, "Write: First wait did not have to wait"); - timestamp := now; - wait_until_idle(net, bus_handle); - check_equal(timestamp, now, "Write: Second wait had to wait"); - - wait until rising_edge(clk); - read_bus(net, bus_handle, x"01234567", tmp); - timestamp := now; - wait_until_idle(net, bus_handle); - check_equal(timestamp, now, "Read: Second wait had to wait"); - - elsif run("Test single write with id") then - write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, '0', x"25"); - - elsif run("Test single read with id") then - read_axi(net, bus_handle, x"01234567", "111", x"25", axi_resp_okay, tmp); - - elsif run("Test single read with len") then - read_axi(net, bus_handle, x"01234567", "111", x"25", axi_resp_okay, tmp); - - elsif run("Test single write with len") then - write_axi(net, bus_handle, x"01234567", x"1122", x"12", "111" , axi_burst_type_fixed, '0', x"25"); - elsif run("Test single write with size") then - write_axi(net, bus_handle, x"01234567", x"1122", x"12", "010" , axi_burst_type_fixed, '0', x"25"); - - elsif run("Test single write with burst") then - write_axi(net, bus_handle, x"01234567", x"1122", x"12", "010" , axi_burst_type_incr, '0', x"25"); - - elsif run("Test single read with size") then - read_axi(net, bus_handle, x"01234567", "101", x"25", axi_resp_okay, tmp); - - elsif run("Test single read with burst") then - read_axi(net, bus_handle, x"01234567", "111", x"25", axi_resp_okay, tmp); + elsif run("Test read with read_axi") then + for n in 0 to 4 loop + info(tb_logger, "Setup..."); + burst := 1; + setup_and_set_random_data_read_memory(memory, burst, rdata'length, memory_data_queue); + info(tb_logger, "Reading..."); + read_axi(net, bus_handle, x"00000000", "001", x"25", axi_resp_okay, read_tmp); + info(tb_logger, "Compare..."); + memory_tmp := pop(memory_data_queue); + check_equal(read_tmp, memory_tmp, "read data"); + check_true(is_empty(memory_data_queue), "memory_data_queue not flushed"); + end loop; - elsif run("Test single write with last") then - write_axi(net, bus_handle, x"01234567", x"1122", x"12", "010" , axi_burst_type_incr, '1', x"25"); + elsif run("Test random burstcount read with burst_read_bus") then + for n in 0 to 4 loop + info(tb_logger, "Setup..."); + burst := rnd.RandInt(1, 255); + setup_and_set_random_data_read_memory(memory, burst, rdata'length, memory_data_queue); + info(tb_logger, "Reading..."); + burst_read_bus(net, bus_handle, 0, burst, read_data_queue); + info(tb_logger, "Compare..."); + for i in 0 to burst - 1 loop + read_tmp := pop(read_data_queue); + memory_tmp := pop(memory_data_queue); + check_equal(read_tmp, memory_tmp, "read data"); + end loop; + check_true(is_empty(read_data_queue), "read_data_queue not flushed"); + check_true(is_empty(memory_data_queue), "memory_data_queue not flushed"); + end loop; - end if; + elsif run("Test random burstcount read with burst_read_axi") then + for n in 0 to 4 loop + info(tb_logger, "Setup..."); + burst := rnd.RandInt(1, 255); + setup_and_set_random_data_read_memory(memory, burst+1, rdata'length, memory_data_queue); + info(tb_logger, "Reading..."); + burst_read_axi(net, bus_handle, x"00000000", std_logic_vector(to_unsigned(burst, arlen'length)), "001", axi_burst_type_incr, x"25", axi_resp_okay, read_data_queue); + info(tb_logger, "Compare..."); + for i in 0 to burst loop + read_tmp := pop(read_data_queue); + memory_tmp := pop(memory_data_queue); + check_equal(read_tmp, memory_tmp, "read data"); + end loop; + check_true(is_empty(read_data_queue), "read_data_queue not flushed"); + check_true(is_empty(memory_data_queue), "memory_data_queue not flushed"); + end loop; + end if; wait for 100 ns; - if not done then - wait until done; - end if; - test_runner_cleanup(runner); end process; test_runner_watchdog(runner, 100 us); - - support : process - variable rnd : RandomPType; - begin - rnd.InitSeed("common_seed"); - - wait until start; - - if enabled("Test single write") then - awready <= '1'; - wait until (awready and awvalid) = '1' and rising_edge(clk); - awready <= '0'; - check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); - - wready <= '1'; - wait until (wready and wvalid) = '1' and rising_edge(clk); - wready <= '0'; - check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); - check_equal(wstrb, std_logic_vector'("11"), "wstrb"); - - bvalid <= '1'; - bresp <= axi_resp_okay; - wait until (bready and bvalid) = '1' and rising_edge(clk); - bvalid <= '0'; - - done <= true; - - elsif enabled("Test single write with byte enable") then - awready <= '1'; - wait until (awready and awvalid) = '1' and rising_edge(clk); - awready <= '0'; - check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); - - wready <= '1'; - wait until (wready and wvalid) = '1' and rising_edge(clk); - wready <= '0'; - check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); - check_equal(wstrb, std_logic_vector'("10"), "wstrb"); - - bvalid <= '1'; - bresp <= axi_resp_okay; - wait until (bready and bvalid) = '1' and rising_edge(clk); - bvalid <= '0'; - - done <= true; - - elsif enabled("Test write not okay") then - awready <= '1'; - wait until (awready and awvalid) = '1' and rising_edge(clk); - awready <= '0'; - - wready <= '1'; - wait until (wready and wvalid) = '1' and rising_edge(clk); - wready <= '0'; - - bvalid <= '1'; - bresp <= axi_resp_slverr; - mock(bus_logger, failure); - wait until (bready and bvalid) = '1' and rising_edge(clk); - bvalid <= '0'; - wait until mock_queue_length > 0 for 0 ns; - check_only_log(bus_logger, "bresp - Got AXI response SLVERR(10) expected OKAY(00)", failure); - unmock(bus_logger); - - done <= true; - - elsif enabled("Test write with axi resp") then - awready <= '1'; - wait until (awready and awvalid) = '1' and rising_edge(clk); - awready <= '0'; - check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); - - wready <= '1'; - wait until (wready and wvalid) = '1' and rising_edge(clk); - wready <= '0'; - check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); - check_equal(wstrb, std_logic_vector'("11"), "wstrb"); - - bvalid <= '1'; - bresp <= axi_resp_slverr; - bid <= x"25"; - wait until (bready and bvalid) = '1' and rising_edge(clk); - bvalid <= '0'; - - done <= true; - - elsif enabled("Test write with wrong axi resp") then - awready <= '1'; - wait until (awready and awvalid) = '1' and rising_edge(clk); - awready <= '0'; - check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); - - wready <= '1'; - wait until (wready and wvalid) = '1' and rising_edge(clk); - wready <= '0'; - check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); - check_equal(wstrb, std_logic_vector'("11"), "wstrb"); - - bvalid <= '1'; - bresp <= axi_resp_exokay; - bid <= x"25"; - mock(bus_logger, failure); - wait until (bready and bvalid) = '1' and rising_edge(clk); - bvalid <= '0'; - wait until mock_queue_length > 0 for 0 ns; - check_only_log(bus_logger, "bresp - Got AXI response EXOKAY(01) expected DECERR(11)", failure); - unmock(bus_logger); - - done <= true; - - elsif enabled("Test single read") then - arready <= '1'; - wait until (arready and arvalid) = '1' and rising_edge(clk); - arready <= '0'; - check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); - - rvalid <= '1'; - rresp <= axi_resp_okay; - rdata <= x"5566"; - wait until (rready and rvalid) = '1' and rising_edge(clk); - rvalid <= '0'; - - done <= true; - - elsif enabled("Test read not okay") then - arready <= '1'; - wait until (arready and arvalid) = '1' and rising_edge(clk); - arready <= '0'; - - rvalid <= '1'; - rresp <= axi_resp_decerr; - rdata <= x"5566"; - mock(bus_logger, failure); - wait until (rready and rvalid) = '1' and rising_edge(clk); - rvalid <= '0'; - wait until mock_queue_length > 0 for 0 ns; - check_only_log(bus_logger, "rresp - Got AXI response DECERR(11) expected OKAY(00)", failure); - unmock(bus_logger); - - done <= true; - - elsif enabled("Test read with axi resp") then - arready <= '1'; - wait until (arready and arvalid) = '1' and rising_edge(clk); - arready <= '0'; - check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); - - rvalid <= '1'; - rresp <= axi_resp_slverr; - rdata <= x"0000"; - rid <= x"25"; - wait until (rready and rvalid) = '1' and rising_edge(clk); - rvalid <= '0'; - - done <= true; - - elsif enabled("Test read with wrong axi resp") then - arready <= '1'; - wait until (arready and arvalid) = '1' and rising_edge(clk); - arready <= '0'; - check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); - - rvalid <= '1'; - rresp <= axi_resp_decerr; - rdata <= x"0000"; - rid <= x"25"; - mock(bus_logger, failure); - wait until (rready and rvalid) = '1' and rising_edge(clk); - rvalid <= '0'; - wait until mock_queue_length > 0 for 0 ns; - check_only_log(bus_logger, "rresp - Got AXI response DECERR(11) expected EXOKAY(01)", failure); - unmock(bus_logger); - - done <= true; - - elsif enabled("Test random") then - for i in 0 to num_random_tests-1 loop - if rnd.RandInt(0, 1) = 0 then - arready <= '1'; - wait until (arready and arvalid) = '1' and rising_edge(clk); - arready <= '0'; - check_equal(araddr, rnd.RandSlv(araddr'length), "araddr"); - - rvalid <= '1'; - rresp <= axi_resp_okay; - rdata <= rnd.RandSlv(rdata'length); - wait until (rready and rvalid) = '1' and rising_edge(clk); - rvalid <= '0'; - else - awready <= '1'; - wait until (awready and awvalid) = '1' and rising_edge(clk); - awready <= '0'; - check_equal(awaddr, rnd.RandSlv(awaddr'length), "awaddr"); - - wready <= '1'; - wait until (wready and wvalid) = '1' and rising_edge(clk); - wready <= '0'; - check_equal(wdata, rnd.RandSlv(wdata'length), "wdata"); - check_equal(wstrb, std_logic_vector'("11"), "wstrb"); - - bvalid <= '1'; - bresp <= axi_resp_okay; - wait until (bready and bvalid) = '1' and rising_edge(clk); - bvalid <= '0'; - end if; - end loop; - done <= true; - - elsif enabled("Test random axi resp") then - for i in 0 to num_random_tests-1 loop - if rnd.RandInt(0, 1) = 0 then - arready <= '1'; - wait until (arready and arvalid) = '1' and rising_edge(clk); - arready <= '0'; - check_equal(araddr, rnd.RandSlv(araddr'length), "araddr"); - - rvalid <= '1'; - rresp <= rnd.RandSlv(axi_resp_t'length); - rdata <= rnd.RandSlv(rdata'length); - rid <= x"25"; - wait until (rready and rvalid) = '1' and rising_edge(clk); - rvalid <= '0'; - else - awready <= '1'; - wait until (awready and awvalid) = '1' and rising_edge(clk); - awready <= '0'; - check_equal(awaddr, rnd.RandSlv(awaddr'length), "awaddr"); - - wready <= '1'; - wait until (wready and wvalid) = '1' and rising_edge(clk); - wready <= '0'; - check_equal(wdata, rnd.RandSlv(wdata'length), "wdata"); - check_equal(wstrb, std_logic_vector'("11"), "wstrb"); - - bvalid <= '1'; - bresp <= rnd.RandSlv(axi_resp_t'length); - bid <= x"25"; - wait until (bready and bvalid) = '1' and rising_edge(clk); - bvalid <= '0'; - end if; - end loop; - done <= true; - - elsif enabled("Test idle when idle") then - wait until rising_edge(clk); - awready <= '1'; - wait until (awready and awvalid) = '1' and rising_edge(clk); - awready <= '0'; - check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); - - wait until rising_edge(clk); - wready <= '1'; - wait until (wready and wvalid) = '1' and rising_edge(clk); - wready <= '0'; - check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); - check_equal(wstrb, std_logic_vector'("11"), "wstrb"); - - wait until rising_edge(clk); - bvalid <= '1'; - bresp <= axi_resp_okay; - wait until (bready and bvalid) = '1' and rising_edge(clk); - bvalid <= '0'; - - wait until rising_edge(clk); - arready <= '1'; - wait until (arready and arvalid) = '1' and rising_edge(clk); - arready <= '0'; - check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); - - wait until rising_edge(clk); - rvalid <= '1'; - rresp <= axi_resp_okay; - rdata <= x"5566"; - wait until (rready and rvalid) = '1' and rising_edge(clk); - rvalid <= '0'; - - done <= true; - elsif enabled("Test single write with id") then - awready <= '1'; - wait until (awready and awvalid) = '1' and rising_edge(clk); - awready <= '0'; - check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); - check_equal(awid, std_logic_vector'(x"25"), "awid"); - - wready <= '1'; - wait until (wready and wvalid) = '1' and rising_edge(clk); - wready <= '0'; - check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); - check_equal(wstrb, std_logic_vector'("11"), "wstrb"); - - bvalid <= '1'; - bresp <= axi_resp_okay; - bid <= x"25"; - wait until (bready and bvalid) = '1' and rising_edge(clk); - bvalid <= '0'; - - done <= true; - - elsif enabled("Test single read with id") then - arready <= '1'; - wait until (arready and arvalid) = '1' and rising_edge(clk); - arready <= '0'; - check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); - check_equal(arid, std_logic_vector'(x"25"), "arid"); - - rvalid <= '1'; - rresp <= axi_resp_okay; - rdata <= x"5566"; - rid <= x"25"; - wait until (rready and rvalid) = '1' and rising_edge(clk); - rvalid <= '0'; - - done <= true; - - elsif enabled("Test single read with len") then - arready <= '1'; - wait until (arready and arvalid) = '1' and rising_edge(clk); - arready <= '0'; - check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); - --check_equal(arlen, std_logic_vector'(x"12"), "arlen"); - - rvalid <= '1'; - rresp <= axi_resp_okay; - rdata <= x"5566"; - rid <= x"25"; - wait until (rready and rvalid) = '1' and rising_edge(clk); - rvalid <= '0'; - - done <= true; - - elsif enabled("Test single write with len") then - awready <= '1'; - wait until (awready and awvalid) = '1' and rising_edge(clk); - awready <= '0'; - check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); - check_equal(awlen, std_logic_vector'(x"12"), "awlen"); - - wready <= '1'; - wait until (wready and wvalid) = '1' and rising_edge(clk); - wready <= '0'; - check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); - check_equal(wstrb, std_logic_vector'("11"), "wstrb"); - - bvalid <= '1'; - bresp <= axi_resp_okay; - bid <= x"25"; - wait until (bready and bvalid) = '1' and rising_edge(clk); - bvalid <= '0'; - - done <= true; - - elsif enabled("Test single write with size") then - awready <= '1'; - wait until (awready and awvalid) = '1' and rising_edge(clk); - awready <= '0'; - check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); - check_equal(awsize, std_logic_vector'("010"), "awsize"); - - wready <= '1'; - wait until (wready and wvalid) = '1' and rising_edge(clk); - wready <= '0'; - check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); - check_equal(wstrb, std_logic_vector'("11"), "wstrb"); - - bvalid <= '1'; - bresp <= axi_resp_okay; - bid <= x"25"; - wait until (bready and bvalid) = '1' and rising_edge(clk); - bvalid <= '0'; - - done <= true; - - elsif enabled("Test single write with burst") then - awready <= '1'; - wait until (awready and awvalid) = '1' and rising_edge(clk); - awready <= '0'; - check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); - check_equal(awburst, axi_burst_type_incr, "awburst"); - - wready <= '1'; - wait until (wready and wvalid) = '1' and rising_edge(clk); - wready <= '0'; - check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); - check_equal(wstrb, std_logic_vector'("11"), "wstrb"); - - bvalid <= '1'; - bresp <= axi_resp_okay; - bid <= x"25"; - wait until (bready and bvalid) = '1' and rising_edge(clk); - bvalid <= '0'; - - done <= true; - - elsif enabled("Test single read with size") then - arready <= '1'; - wait until (arready and arvalid) = '1' and rising_edge(clk); - arready <= '0'; - check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); - check_equal(arsize, std_logic_vector'("101"), "arsize"); - - rvalid <= '1'; - rresp <= axi_resp_okay; - rdata <= x"5566"; - rid <= x"25"; - wait until (rready and rvalid) = '1' and rising_edge(clk); - rvalid <= '0'; - - done <= true; - - elsif enabled("Test single read with burst") then - arready <= '1'; - wait until (arready and arvalid) = '1' and rising_edge(clk); - arready <= '0'; - check_equal(araddr, std_logic_vector'(x"01234567"), "araddr"); - --check_equal(arburst, axi_burst_type_incr, "arburst"); - - rvalid <= '1'; - rresp <= axi_resp_okay; - rdata <= x"5566"; - rid <= x"25"; - wait until (rready and rvalid) = '1' and rising_edge(clk); - rvalid <= '0'; - - done <= true; - - elsif enabled("Test single write with last") then - awready <= '1'; - wait until (awready and awvalid) = '1' and rising_edge(clk); - awready <= '0'; - check_equal(awaddr, std_logic_vector'(x"01234567"), "awaddr"); - - - wready <= '1'; - wait until (wready and wvalid) = '1' and rising_edge(clk); - wready <= '0'; - check_equal(wdata, std_logic_vector'(x"1122"), "wdata"); - check_equal(wstrb, std_logic_vector'("11"), "wstrb"); - check_equal(wlast, '1', "wlast"); - - bvalid <= '1'; - bresp <= axi_resp_okay; - bid <= x"25"; - wait until (bready and bvalid) = '1' and rising_edge(clk); - bvalid <= '0'; - - done <= true; - end if; - end process; - check_not_valid : process constant a_addr_invalid_value : std_logic_vector(araddr'range) := (others => 'X'); constant a_len_invalid_value : std_logic_vector(arlen'range) := (others => 'X'); @@ -682,7 +225,7 @@ begin generic map ( bus_handle => bus_handle) port map ( - aclk => clk, + aclk => clk, arvalid => arvalid, arready => arready, @@ -718,6 +261,27 @@ begin bid => bid, bresp => bresp); + read_slave : entity work.axi_read_slave + generic map ( + axi_slave => axi_rd_slave) + port map ( + aclk => clk, + + arvalid => arvalid, + arready => arready, + arid => arid, + araddr => araddr, + arlen => arlen, + arsize => arsize, + arburst => arburst, + + rvalid => rvalid, + rready => rready, + rid => rid, + rdata => rdata, + rresp => rresp, + rlast => rlast); + clk <= not clk after 5 ns; end architecture; From 59f59ae5308b4c3a68fda0fd022905258504cc7c Mon Sep 17 00:00:00 2001 From: David Martin Date: Mon, 10 Jun 2024 10:49:55 +0200 Subject: [PATCH 18/24] Added write_bus and write_axi --- .../src/axi_master.vhd | 63 +++++++++----- .../src/axi_master_pkg.vhd | 79 ++++++++++++++--- .../test/tb_axi_master.vhd | 84 ++++++++++++++++++- 3 files changed, 192 insertions(+), 34 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index 098a44556..837488dfd 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -148,6 +148,7 @@ begin variable len : natural := 0; variable size : std_logic_vector(arsize'range) := (others => '0'); variable burst : std_logic_vector(arburst'range) := (others => '0'); + variable byteenable : std_logic_vector(wstrb'range) := (others => '0'); variable resp : axi_resp_t; begin -- Initialization @@ -222,26 +223,49 @@ begin while rnd.Uniform(0.0, 1.0) > write_high_probability loop wait until rising_edge(aclk); end loop; + addr := pop_std_ulogic_vector(request_msg); - push_std_ulogic_vector(request_msg, addr); - awaddr <= addr; data := pop_std_ulogic_vector(request_msg); - push_std_ulogic_vector(request_msg, data); - wdata <= data; - wstrb <= pop_std_ulogic_vector(request_msg); + byteenable := pop_std_ulogic_vector(request_msg); + + if msg_type = bus_write_msg then + len := 0; + size := get_full_size; + burst := axi_burst_type_fixed; + id(id'range) := (others => '0'); + elsif msg_type = bus_burst_write_msg then + len := pop_integer(request_msg) - 1; -- bring bus burst down to axi zero based indexing + size := get_full_size; + burst := axi_burst_type_incr; + id(id'range) := (others => '0'); + elsif msg_type = axi_write_msg then + len := 0; + size := pop_std_ulogic_vector(request_msg); + burst := axi_burst_type_fixed; + id := pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); + elsif msg_type = axi_burst_write_msg then + len := to_integer(unsigned(pop_std_ulogic_vector(request_msg))); + size := pop_std_ulogic_vector(request_msg); + burst := pop_std_ulogic_vector(request_msg); + id := pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); + end if; - if(is_axi_msg(msg_type)) then - awlen <= pop_std_ulogic_vector(request_msg); - awsize <= pop_std_ulogic_vector(request_msg); - awburst <= pop_std_ulogic_vector(request_msg); + awaddr <= addr; + push_std_ulogic_vector(request_msg, addr); - id := pop_std_ulogic_vector(request_msg)(awid'length -1 downto 0); - push_std_ulogic_vector(request_msg, id); - awid <= id; + awlen <= std_logic_vector(to_unsigned(len, awlen'length)); + awsize <= size; + awburst <= burst; - wlast <= pop_std_ulogic(request_msg); - end if; + awid <= id; + push_std_ulogic_vector(request_msg, id); + wdata <= data; + push_std_ulogic_vector(request_msg, data); + + wstrb <= byteenable; + wlast <= '1'; + resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; push_std_ulogic_vector(request_msg, resp); push(write_reply_queue, request_msg); @@ -268,6 +292,8 @@ begin w_done := true; end if; end loop; + + else unexpected_msg_type(msg_type); end if; @@ -351,14 +377,11 @@ begin request_msg := pop(write_reply_queue); msg_type := message_type(request_msg); addr := pop_std_ulogic_vector(request_msg); + id := pop_std_ulogic_vector(request_msg); data := pop_std_ulogic_vector(request_msg); - - if(is_axi_msg(msg_type)) then - id := pop_std_ulogic_vector(request_msg); - check_axi_id(bus_handle, bid, id, "bid"); - end if; - resp := pop_std_ulogic_vector(request_msg); + + check_axi_id(bus_handle, bid, id, "bid"); check_axi_resp(bus_handle, bresp, resp, "bresp"); if is_visible(bus_handle.p_logger, debug) then diff --git a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd index 860947b6c..d97c40d46 100644 --- a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd @@ -26,17 +26,28 @@ package axi_master_pkg is -- Blocking: Write the bus procedure write_axi(signal net : inout network_t; - constant bus_handle : bus_master_t; - constant address : std_logic_vector; - constant data : std_logic_vector; - constant len : std_logic_vector; - constant size : std_logic_vector; - constant burst : axi_burst_type_t; - constant last : std_logic; - constant id : std_logic_vector := ""; - constant expected_bresp : axi_resp_t := axi_resp_okay; - -- default byte enable is all bytes - constant byte_enable : std_logic_vector := ""); + constant bus_handle : bus_master_t; + constant address : std_logic_vector; + constant data : std_logic_vector; + constant size : std_logic_vector; + constant id : std_logic_vector := ""; + constant expected_bresp : axi_resp_t := axi_resp_okay; + -- default byte enable is all bytes + constant byte_enable : std_logic_vector := ""); + + -- Blocking: Burst write the bus + procedure burst_write_axi(signal net : inout network_t; + constant bus_handle : bus_master_t; + constant address : std_logic_vector; + constant data : std_logic_vector; + constant len : std_logic_vector; + constant size : std_logic_vector; + constant burst : axi_burst_type_t; + constant last : std_logic; + constant id : std_logic_vector := ""; + constant expected_bresp : axi_resp_t := axi_resp_okay; + -- default byte enable is all bytes + constant byte_enable : std_logic_vector := ""); -- Non blocking: Read the bus returning a reference to the future reply procedure read_axi(signal net : inout network_t; @@ -112,6 +123,50 @@ end package; package body axi_master_pkg is procedure write_axi(signal net : inout network_t; + constant bus_handle : bus_master_t; + constant address : std_logic_vector; + constant data : std_logic_vector; + constant size : std_logic_vector; + constant id : std_logic_vector := ""; + constant expected_bresp : axi_resp_t := axi_resp_okay; + -- default byte enable is all bytes + constant byte_enable : std_logic_vector := "") is + variable request_msg : msg_t := new_msg(axi_write_msg); + variable full_data : std_logic_vector(bus_handle.p_data_length - 1 downto 0) := (others => '0'); + variable full_address : std_logic_vector(bus_handle.p_address_length - 1 downto 0) := (others => '0'); + variable full_byte_enable : std_logic_vector(byte_enable_length(bus_handle) - 1 downto 0); + variable full_len : std_logic_vector(len_length(bus_handle) - 1 downto 0) := (others => '0'); + variable full_size : std_logic_vector(size_length(bus_handle) - 1 downto 0) := (others => '0'); + variable full_id : std_logic_vector(id_length(bus_handle) - 1 downto 0) := (others => '0'); + begin + full_address(address'length - 1 downto 0) := address; + push_std_ulogic_vector(request_msg, full_address); + + full_data(data'length - 1 downto 0) := data; + push_std_ulogic_vector(request_msg, full_data); + + if byte_enable = "" then + full_byte_enable := (others => '1'); + else + full_byte_enable(byte_enable'length - 1 downto 0) := byte_enable; + end if; + push_std_ulogic_vector(request_msg, full_byte_enable); + + full_size(size'length - 1 downto 0) := size; + push_std_ulogic_vector(request_msg, full_size); + + if id = "" then + full_id := (others => '0'); + else + full_id(id'length - 1 downto 0) := id; + end if; + push_std_ulogic_vector(request_msg, full_id); + + push_std_ulogic_vector(request_msg, expected_bresp); + send(net, bus_handle.p_actor, request_msg); + end procedure; + + procedure burst_write_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; constant data : std_logic_vector; @@ -123,7 +178,7 @@ package body axi_master_pkg is constant expected_bresp : axi_resp_t := axi_resp_okay; -- default byte enable is all bytes constant byte_enable : std_logic_vector := "") is - variable request_msg : msg_t := new_msg(axi_write_msg); + variable request_msg : msg_t := new_msg(axi_burst_write_msg); variable full_data : std_logic_vector(bus_handle.p_data_length - 1 downto 0) := (others => '0'); variable full_address : std_logic_vector(bus_handle.p_address_length - 1 downto 0) := (others => '0'); variable full_byte_enable : std_logic_vector(byte_enable_length(bus_handle) - 1 downto 0); diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index 320a63a21..5f7051577 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -104,6 +104,37 @@ begin end loop; end; + procedure setup_and_set_random_data_write_memory( + memory : memory_t; + num_words : positive; + width : positive; + data : queue_t + ) is + variable wt_buffer : buffer_t; + variable rand : std_logic_vector(width - 1 downto 0); + begin + clear(memory); + wt_buffer := allocate(memory, + num_bytes => num_words * (width / 8), + name => wt_buffer'simple_name, + permissions => write_only); + + for i in 0 to num_words - 1 loop + rand := rnd.RandSlv(width); + set_expected_word(memory, base_address(wt_buffer) + (i*(width/8)), rand); + push(data, rand); + end loop; + end; + + procedure wait_on_data_write_memory( + memory : memory_t + ) is + begin + while not expected_was_written(memory) loop + wait for 1 ns; + end loop; + end; + variable read_data_queue : queue_t := new_queue; variable memory_data_queue : queue_t := new_queue; @@ -128,7 +159,7 @@ begin check_equal(read_tmp, memory_tmp, "read data"); check_true(is_empty(memory_data_queue), "memory_data_queue not flushed"); end loop; - + elsif run("Test read with read_axi") then for n in 0 to 4 loop info(tb_logger, "Setup..."); @@ -175,7 +206,31 @@ begin check_true(is_empty(read_data_queue), "read_data_queue not flushed"); check_true(is_empty(memory_data_queue), "memory_data_queue not flushed"); end loop; - end if; + + elsif run("Test write with write_bus") then + for n in 0 to 4 loop + info(tb_logger, "Setup..."); + burst := 1; + setup_and_set_random_data_write_memory(memory, burst, rdata'length, memory_data_queue); + info(tb_logger, "Reading..."); + write_bus(net, bus_handle, 0, pop(memory_data_queue)); + info(tb_logger, "Compare..."); + check_true(is_empty(memory_data_queue), "memory_data_queue not flushed"); + wait_on_data_write_memory(memory); + end loop; + + elsif run("Test write with write_axi") then + for n in 0 to 4 loop + info(tb_logger, "Setup..."); + burst := 1; + setup_and_set_random_data_write_memory(memory, burst, rdata'length, memory_data_queue); + info(tb_logger, "Reading..."); + write_axi(net, bus_handle, x"00000000", pop(memory_data_queue), "001", x"25", axi_resp_okay); + info(tb_logger, "Compare..."); + check_true(is_empty(memory_data_queue), "memory_data_queue not flushed"); + wait_on_data_write_memory(memory); + end loop; + end if; wait for 100 ns; @@ -282,6 +337,31 @@ begin rresp => rresp, rlast => rlast); + write_slave : entity work.axi_write_slave + generic map ( + axi_slave => axi_wr_slave) + port map ( + aclk => clk, + + awvalid => awvalid, + awready => awready, + awid => awid, + awaddr => awaddr, + awlen => awlen, + awsize => awsize, + awburst => awburst, + + wvalid => wvalid, + wready => wready, + wdata => wdata, + wstrb => wstrb, + wlast => wlast, + + bvalid => bvalid, + bready => bready, + bid => bid, + bresp => bresp); + clk <= not clk after 5 ns; end architecture; From 1f53450aaad230d4e36d79003b8aa449eb70b80d Mon Sep 17 00:00:00 2001 From: developer Date: Wed, 12 Jun 2024 14:05:45 +0200 Subject: [PATCH 19/24] Added burst write bus --- .../src/axi_master.vhd | 86 +++++++++++-------- .../test/tb_axi_master.vhd | 16 +++- 2 files changed, 65 insertions(+), 37 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index 837488dfd..ad82aded7 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -132,11 +132,16 @@ begin end if; end procedure; - function get_full_size return std_logic_vector is + function get_full_read_size return std_logic_vector is begin return std_logic_vector(to_unsigned(integer(ceil(log2(real(rdata'length/8)))), arsize'length)); end function; + function get_full_write_size return std_logic_vector is + begin + return std_logic_vector(to_unsigned(integer(ceil(log2(real(wdata'length/8)))), awsize'length)); + end function; + variable rnd : RandomPType; variable request_msg : msg_t; variable msg_type : msg_type_t; @@ -174,12 +179,12 @@ begin if msg_type = bus_read_msg then len := 0; - size := get_full_size; + size := get_full_read_size; burst := axi_burst_type_fixed; id(id'range) := (others => '0'); elsif msg_type = bus_burst_read_msg then len := pop_integer(request_msg) - 1; -- bring bus burst down to axi zero based indexing - size := get_full_size; + size := get_full_read_size; burst := axi_burst_type_incr; id(id'range) := (others => '0'); elsif msg_type = axi_read_msg then @@ -225,74 +230,92 @@ begin end loop; addr := pop_std_ulogic_vector(request_msg); - data := pop_std_ulogic_vector(request_msg); - byteenable := pop_std_ulogic_vector(request_msg); if msg_type = bus_write_msg then + data := pop_std_ulogic_vector(request_msg); + byteenable := pop_std_ulogic_vector(request_msg); len := 0; - size := get_full_size; + size := get_full_write_size; burst := axi_burst_type_fixed; id(id'range) := (others => '0'); - elsif msg_type = bus_burst_write_msg then + elsif msg_type = bus_burst_write_msg then + byteenable(byteenable'range) := (others => '1'); -- not set in bus master pkg len := pop_integer(request_msg) - 1; -- bring bus burst down to axi zero based indexing - size := get_full_size; + data := pop_std_ulogic_vector(request_msg); + size := get_full_write_size; burst := axi_burst_type_incr; id(id'range) := (others => '0'); elsif msg_type = axi_write_msg then + data := pop_std_ulogic_vector(request_msg); + byteenable := pop_std_ulogic_vector(request_msg); len := 0; size := pop_std_ulogic_vector(request_msg); burst := axi_burst_type_fixed; id := pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); elsif msg_type = axi_burst_write_msg then + data := pop_std_ulogic_vector(request_msg); + byteenable := pop_std_ulogic_vector(request_msg); len := to_integer(unsigned(pop_std_ulogic_vector(request_msg))); size := pop_std_ulogic_vector(request_msg); burst := pop_std_ulogic_vector(request_msg); id := pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); end if; - awaddr <= addr; - push_std_ulogic_vector(request_msg, addr); + resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; + + w_done := false; + aw_done := false; + -- first iteration + awvalid <= '1'; + awaddr <= addr; awlen <= std_logic_vector(to_unsigned(len, awlen'length)); awsize <= size; awburst <= burst; - awid <= id; - push_std_ulogic_vector(request_msg, id); + wvalid <= '1'; wdata <= data; - push_std_ulogic_vector(request_msg, data); - wstrb <= byteenable; - wlast <= '1'; - - resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; - push_std_ulogic_vector(request_msg, resp); - push(write_reply_queue, request_msg); - - wvalid <= '1'; - awvalid <= '1'; + wlast <= '1' when len = 0 else '0'; - w_done := false; - aw_done := false; while not (w_done and aw_done) loop wait until ((awvalid and awready) = '1' or (wvalid and wready) = '1') and rising_edge(aclk); if (awvalid and awready) = '1' then awvalid <= '0'; drive_aw_invalid; - aw_done := true; end if; if (wvalid and wready) = '1' then - wvalid <= '0'; - drive_w_invalid; - w_done := true; + if len = 0 then + wvalid <= '0'; + drive_w_invalid; + w_done := true; + else + -- burst iterations + len := len - 1; + data := pop_std_ulogic_vector(request_msg); + wdata <= data; + wstrb <= byteenable; + wlast <= '1' when len = 0 else '0'; + end if; + + if is_visible(bus_handle.p_logger, debug) then + debug(bus_handle.p_logger, + "Wrote 0x" & to_hstring(data) & + " to address 0x" & to_hstring(addr)); + end if; end if; + end loop; + push_std_ulogic_vector(request_msg, addr); + push_std_ulogic_vector(request_msg, id); + push_std_ulogic_vector(request_msg, resp); + push(write_reply_queue, request_msg); else unexpected_msg_type(msg_type); @@ -378,18 +401,11 @@ begin msg_type := message_type(request_msg); addr := pop_std_ulogic_vector(request_msg); id := pop_std_ulogic_vector(request_msg); - data := pop_std_ulogic_vector(request_msg); resp := pop_std_ulogic_vector(request_msg); check_axi_id(bus_handle, bid, id, "bid"); check_axi_resp(bus_handle, bresp, resp, "bresp"); - if is_visible(bus_handle.p_logger, debug) then - debug(bus_handle.p_logger, - "Wrote 0x" & to_hstring(data) & - " to address 0x" & to_hstring(addr)); - end if; - delete(request_msg); end process; diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index 5f7051577..8563d7dfc 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -211,7 +211,7 @@ begin for n in 0 to 4 loop info(tb_logger, "Setup..."); burst := 1; - setup_and_set_random_data_write_memory(memory, burst, rdata'length, memory_data_queue); + setup_and_set_random_data_write_memory(memory, burst, wdata'length, memory_data_queue); info(tb_logger, "Reading..."); write_bus(net, bus_handle, 0, pop(memory_data_queue)); info(tb_logger, "Compare..."); @@ -223,13 +223,25 @@ begin for n in 0 to 4 loop info(tb_logger, "Setup..."); burst := 1; - setup_and_set_random_data_write_memory(memory, burst, rdata'length, memory_data_queue); + setup_and_set_random_data_write_memory(memory, burst, wdata'length, memory_data_queue); info(tb_logger, "Reading..."); write_axi(net, bus_handle, x"00000000", pop(memory_data_queue), "001", x"25", axi_resp_okay); info(tb_logger, "Compare..."); check_true(is_empty(memory_data_queue), "memory_data_queue not flushed"); wait_on_data_write_memory(memory); end loop; + + elsif run("Test random burstcount write with burst_write_bus") then + for n in 0 to 4 loop + info(tb_logger, "Setup..."); + burst := rnd.RandInt(1, 255); + setup_and_set_random_data_write_memory(memory, burst, wdata'length, memory_data_queue); + info(tb_logger, "Reading..."); + burst_write_bus(net, bus_handle, x"00000000", burst, memory_data_queue); + info(tb_logger, "Compare..."); + check_true(is_empty(memory_data_queue), "memory_data_queue not flushed"); + wait_on_data_write_memory(memory); + end loop; end if; wait for 100 ns; From 947388e110c71f8966d01b732992eab705423763 Mon Sep 17 00:00:00 2001 From: developer Date: Wed, 12 Jun 2024 14:27:43 +0200 Subject: [PATCH 20/24] Added burst write axi --- .../verification_components/src/axi_master.vhd | 8 +++++--- .../src/axi_master_pkg.vhd | 17 ++++++++--------- .../test/tb_axi_master.vhd | 13 +++++++++++++ 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index ad82aded7..5d87f02d2 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -238,6 +238,7 @@ begin size := get_full_write_size; burst := axi_burst_type_fixed; id(id'range) := (others => '0'); + resp := axi_resp_okay; elsif msg_type = bus_burst_write_msg then byteenable(byteenable'range) := (others => '1'); -- not set in bus master pkg len := pop_integer(request_msg) - 1; -- bring bus burst down to axi zero based indexing @@ -245,6 +246,7 @@ begin size := get_full_write_size; burst := axi_burst_type_incr; id(id'range) := (others => '0'); + resp := axi_resp_okay; elsif msg_type = axi_write_msg then data := pop_std_ulogic_vector(request_msg); byteenable := pop_std_ulogic_vector(request_msg); @@ -252,17 +254,17 @@ begin size := pop_std_ulogic_vector(request_msg); burst := axi_burst_type_fixed; id := pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); + resp := pop_std_ulogic_vector(request_msg); elsif msg_type = axi_burst_write_msg then - data := pop_std_ulogic_vector(request_msg); byteenable := pop_std_ulogic_vector(request_msg); len := to_integer(unsigned(pop_std_ulogic_vector(request_msg))); size := pop_std_ulogic_vector(request_msg); burst := pop_std_ulogic_vector(request_msg); id := pop_std_ulogic_vector(request_msg)(arid'length -1 downto 0); + resp := pop_std_ulogic_vector(request_msg); + data := pop_std_ulogic_vector(request_msg); end if; - resp := pop_std_ulogic_vector(request_msg) when is_axi_msg(msg_type) else axi_resp_okay; - w_done := false; aw_done := false; diff --git a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd index d97c40d46..02614d4c7 100644 --- a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd @@ -39,11 +39,10 @@ package axi_master_pkg is procedure burst_write_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; - constant data : std_logic_vector; constant len : std_logic_vector; constant size : std_logic_vector; constant burst : axi_burst_type_t; - constant last : std_logic; + constant data : queue_t; constant id : std_logic_vector := ""; constant expected_bresp : axi_resp_t := axi_resp_okay; -- default byte enable is all bytes @@ -169,11 +168,10 @@ package body axi_master_pkg is procedure burst_write_axi(signal net : inout network_t; constant bus_handle : bus_master_t; constant address : std_logic_vector; - constant data : std_logic_vector; constant len : std_logic_vector; constant size : std_logic_vector; constant burst : axi_burst_type_t; - constant last : std_logic; + constant data : queue_t; constant id : std_logic_vector := ""; constant expected_bresp : axi_resp_t := axi_resp_okay; -- default byte enable is all bytes @@ -189,9 +187,6 @@ package body axi_master_pkg is full_address(address'length - 1 downto 0) := address; push_std_ulogic_vector(request_msg, full_address); - full_data(data'length - 1 downto 0) := data; - push_std_ulogic_vector(request_msg, full_data); - if byte_enable = "" then full_byte_enable := (others => '1'); else @@ -214,9 +209,13 @@ package body axi_master_pkg is end if; push_std_ulogic_vector(request_msg, full_id); - push_std_ulogic(request_msg, last); - push_std_ulogic_vector(request_msg, expected_bresp); + + for i in 0 to to_integer(unsigned(len)) loop + full_data(bus_handle.p_data_length-1 downto 0) := pop(data); + push_std_ulogic_vector(request_msg, full_data); + end loop; + send(net, bus_handle.p_actor, request_msg); end procedure; diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index 8563d7dfc..681877252 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -242,6 +242,19 @@ begin check_true(is_empty(memory_data_queue), "memory_data_queue not flushed"); wait_on_data_write_memory(memory); end loop; + + elsif run("Test random burstcount write with burst_write_axi") then + for n in 0 to 4 loop + info(tb_logger, "Setup..."); + burst := rnd.RandInt(1, 255); + setup_and_set_random_data_write_memory(memory, burst+1, wdata'length, memory_data_queue); + info(tb_logger, "Reading..."); + burst_write_axi(net, bus_handle, x"00000000", std_logic_vector(to_unsigned(burst, awlen'length)),"001", axi_burst_type_incr, memory_data_queue, x"25", axi_resp_okay); + info(tb_logger, "Compare..."); + check_true(is_empty(memory_data_queue), "memory_data_queue not flushed"); + wait_on_data_write_memory(memory); + end loop; + end if; wait for 100 ns; From e72ca73d0a4fbf75d32b8801edd5779984f800aa Mon Sep 17 00:00:00 2001 From: developer Date: Thu, 18 Jul 2024 09:42:44 +0200 Subject: [PATCH 21/24] Added single axi_master_t generic to align with VC standard --- .../src/axi_master.vhd | 74 +++++++++---------- .../src/axi_master_pkg.vhd | 46 ++++++++++++ .../test/tb_axi_master.vhd | 22 +++--- 3 files changed, 92 insertions(+), 50 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index 5d87f02d2..086e1099e 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -30,11 +30,7 @@ use work.sync_pkg.all; entity axi_master is generic ( - bus_handle : bus_master_t; - drive_invalid : boolean := true; - drive_invalid_val : std_logic := 'X'; - write_high_probability : real range 0.0 to 1.0 := 1.0; - read_high_probability : real range 0.0 to 1.0 := 1.0 + axi_master_handle : axi_master_t ); port ( aclk : in std_logic; @@ -42,7 +38,7 @@ entity axi_master is arvalid : out std_logic := '0'; arready : in std_logic; arid : out std_logic_vector; - araddr : out std_logic_vector(address_length(bus_handle) - 1 downto 0) := (others => '0'); + araddr : out std_logic_vector(address_length(axi_master_handle.p_bus_handle) - 1 downto 0) := (others => '0'); arlen : out std_logic_vector; arsize : out std_logic_vector; arburst : out axi_burst_type_t; @@ -50,22 +46,22 @@ entity axi_master is rvalid : in std_logic; rready : out std_logic := '0'; rid : in std_logic_vector; - rdata : in std_logic_vector(data_length(bus_handle) - 1 downto 0); + rdata : in std_logic_vector(data_length(axi_master_handle.p_bus_handle) - 1 downto 0); rresp : in axi_resp_t; rlast : in std_logic; awvalid : out std_logic := '0'; awready : in std_logic := '0'; awid : out std_logic_vector; - awaddr : out std_logic_vector(address_length(bus_handle) - 1 downto 0) := (others => '0'); + awaddr : out std_logic_vector(address_length(axi_master_handle.p_bus_handle) - 1 downto 0) := (others => '0'); awlen : out std_logic_vector; awsize : out std_logic_vector; awburst : out axi_burst_type_t; wvalid : out std_logic; wready : in std_logic := '0'; - wdata : out std_logic_vector(data_length(bus_handle) - 1 downto 0) := (others => '0'); - wstrb : out std_logic_vector(byte_enable_length(bus_handle) - 1 downto 0) := (others => '0'); + wdata : out std_logic_vector(data_length(axi_master_handle.p_bus_handle) - 1 downto 0) := (others => '0'); + wstrb : out std_logic_vector(byte_enable_length(axi_master_handle.p_bus_handle) - 1 downto 0) := (others => '0'); wlast : out std_logic; bvalid : in std_logic; @@ -84,7 +80,7 @@ begin variable request_msg : msg_t; variable msg_type : msg_type_t; begin - receive(net, bus_handle.p_actor, request_msg); + receive(net, axi_master_handle.p_bus_handle.p_actor, request_msg); msg_type := message_type(request_msg); if is_read(msg_type) or is_write(msg_type) then @@ -103,32 +99,32 @@ begin bus_process : process procedure drive_ar_invalid is begin - if drive_invalid then - araddr <= (araddr'range => drive_invalid_val); - arlen <= (arlen'range => drive_invalid_val); - arsize <= (arsize'range => drive_invalid_val); - arburst <= (arburst'range => drive_invalid_val); - arid <= (arid'range => drive_invalid_val); + if axi_master_handle.p_drive_invalid then + araddr <= (araddr'range => axi_master_handle.p_drive_invalid_val); + arlen <= (arlen'range => axi_master_handle.p_drive_invalid_val); + arsize <= (arsize'range => axi_master_handle.p_drive_invalid_val); + arburst <= (arburst'range => axi_master_handle.p_drive_invalid_val); + arid <= (arid'range => axi_master_handle.p_drive_invalid_val); end if; end procedure; procedure drive_aw_invalid is begin - if drive_invalid then - awaddr <= (awaddr'range => drive_invalid_val); - awlen <= (awlen'range => drive_invalid_val); - awsize <= (awsize'range => drive_invalid_val); - awburst <= (awburst'range => drive_invalid_val); - awid <= (arid'range => drive_invalid_val); + if axi_master_handle.p_drive_invalid then + awaddr <= (awaddr'range => axi_master_handle.p_drive_invalid_val); + awlen <= (awlen'range => axi_master_handle.p_drive_invalid_val); + awsize <= (awsize'range => axi_master_handle.p_drive_invalid_val); + awburst <= (awburst'range => axi_master_handle.p_drive_invalid_val); + awid <= (arid'range => axi_master_handle.p_drive_invalid_val); end if; end procedure; procedure drive_w_invalid is begin - if drive_invalid then - wlast <= drive_invalid_val; - wdata <= (wdata'range => drive_invalid_val); - wstrb <= (wstrb'range => drive_invalid_val); + if axi_master_handle.p_drive_invalid then + wlast <= axi_master_handle.p_drive_invalid_val; + wdata <= (wdata'range => axi_master_handle.p_drive_invalid_val); + wstrb <= (wstrb'range => axi_master_handle.p_drive_invalid_val); end if; end procedure; @@ -171,7 +167,7 @@ begin msg_type := message_type(request_msg); if is_read(msg_type) then - while rnd.Uniform(0.0, 1.0) > read_high_probability loop + while rnd.Uniform(0.0, 1.0) > axi_master_handle.p_read_high_probability loop wait until rising_edge(aclk); end loop; @@ -225,7 +221,7 @@ begin drive_ar_invalid; elsif is_write(msg_type) then - while rnd.Uniform(0.0, 1.0) > write_high_probability loop + while rnd.Uniform(0.0, 1.0) > axi_master_handle.p_write_high_probability loop wait until rising_edge(aclk); end loop; @@ -305,8 +301,8 @@ begin wlast <= '1' when len = 0 else '0'; end if; - if is_visible(bus_handle.p_logger, debug) then - debug(bus_handle.p_logger, + if is_visible(axi_master_handle.p_bus_handle.p_logger, debug) then + debug(axi_master_handle.p_bus_handle.p_logger, "Wrote 0x" & to_hstring(data) & " to address 0x" & to_hstring(addr)); end if; @@ -340,8 +336,8 @@ begin procedure write_debug is begin - if is_visible(bus_handle.p_logger, debug) then - debug(bus_handle.p_logger, + if is_visible(axi_master_handle.p_bus_handle.p_logger, debug) then + debug(axi_master_handle.p_bus_handle.p_logger, "Read 0x" & to_hstring(rdata) & " from address 0x" & to_hstring(addr)); end if; @@ -367,16 +363,16 @@ begin end if; -- first iteration - check_axi_id(bus_handle, rid, id, "rid"); - check_axi_resp(bus_handle, rresp, resp, "rresp"); + check_axi_id(axi_master_handle.p_bus_handle, rid, id, "rid"); + check_axi_resp(axi_master_handle.p_bus_handle, rresp, resp, "rresp"); write_debug; push_std_ulogic_vector(reply_msg, rdata); -- burst iterations for i in 0 to len - 1 loop wait until (rvalid and rready) = '1' and rising_edge(aclk); - check_axi_id(bus_handle, rid, id, "rid"); - check_axi_resp(bus_handle, rresp, resp, "rresp"); + check_axi_id(axi_master_handle.p_bus_handle, rid, id, "rid"); + check_axi_resp(axi_master_handle.p_bus_handle, rresp, resp, "rresp"); write_debug; push_std_ulogic_vector(reply_msg, rdata); end loop; @@ -405,8 +401,8 @@ begin id := pop_std_ulogic_vector(request_msg); resp := pop_std_ulogic_vector(request_msg); - check_axi_id(bus_handle, bid, id, "bid"); - check_axi_resp(bus_handle, bresp, resp, "bresp"); + check_axi_id(axi_master_handle.p_bus_handle, bid, id, "bid"); + check_axi_resp(axi_master_handle.p_bus_handle, bresp, resp, "bresp"); delete(request_msg); end process; diff --git a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd index 02614d4c7..a6a578295 100644 --- a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd @@ -19,6 +19,27 @@ use work.queue_pkg.all; package axi_master_pkg is + -- Handle to VC instance + type axi_master_t is record + -- These fields are private, do not use directly + p_bus_handle : bus_master_t; + p_drive_invalid : boolean; + p_drive_invalid_val : std_logic; + p_write_high_probability : real range 0.0 to 1.0; + p_read_high_probability : real range 0.0 to 1.0; + end record; + + impure function new_axi_master(data_length : natural; + address_length : natural; + byte_length : natural := 8; + logger : logger_t := bus_logger; + actor : actor_t := null_actor; + drive_invalid : boolean := true; + drive_invalid_val : std_logic := 'X'; + write_high_probability : real := 1.0; + read_high_probability : real := 1.0 + ) return axi_master_t; + constant axi_read_msg : msg_type_t := new_msg_type("read axi "); constant axi_write_msg : msg_type_t := new_msg_type("write axi "); constant axi_burst_read_msg : msg_type_t := new_msg_type("read axi burst "); @@ -120,6 +141,31 @@ package axi_master_pkg is end package; package body axi_master_pkg is + impure function new_axi_master(data_length : natural; + address_length : natural; + byte_length : natural := 8; + logger : logger_t := bus_logger; + actor : actor_t := null_actor; + drive_invalid : boolean := true; + drive_invalid_val : std_logic := 'X'; + write_high_probability : real := 1.0; + read_high_probability : real := 1.0 + ) return axi_master_t is + variable bus_handle : bus_master_t := new_bus( + data_length, + address_length, + byte_length, + logger, + actor + ); + begin + return ( + p_bus_handle => bus_handle, + p_drive_invalid => drive_invalid, + p_drive_invalid_val => drive_invalid_val, + p_write_high_probability => write_high_probability, + p_read_high_probability => read_high_probability); + end; procedure write_axi(signal net : inout network_t; constant bus_handle : bus_master_t; diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index 681877252..abdb80184 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -65,8 +65,8 @@ architecture a of tb_axi_master is signal bid : std_logic_vector(7 downto 0); --TBD signal bresp : std_logic_vector(1 downto 0); - constant bus_handle : bus_master_t := new_bus(data_length => wdata'length, - address_length => awaddr'length); + constant axi_master_handle : axi_master_t := new_axi_master(data_length => wdata'length, + address_length => awaddr'length); constant memory : memory_t := new_memory; constant axi_rd_slave : axi_slave_t := new_axi_slave(memory => memory, @@ -153,7 +153,7 @@ begin burst := 1; setup_and_set_random_data_read_memory(memory, burst, rdata'length, memory_data_queue); info(tb_logger, "Reading..."); - read_bus(net, bus_handle, 0, read_tmp); + read_bus(net, axi_master_handle.p_bus_handle, 0, read_tmp); info(tb_logger, "Compare..."); memory_tmp := pop(memory_data_queue); check_equal(read_tmp, memory_tmp, "read data"); @@ -166,7 +166,7 @@ begin burst := 1; setup_and_set_random_data_read_memory(memory, burst, rdata'length, memory_data_queue); info(tb_logger, "Reading..."); - read_axi(net, bus_handle, x"00000000", "001", x"25", axi_resp_okay, read_tmp); + read_axi(net, axi_master_handle.p_bus_handle, x"00000000", "001", x"25", axi_resp_okay, read_tmp); info(tb_logger, "Compare..."); memory_tmp := pop(memory_data_queue); check_equal(read_tmp, memory_tmp, "read data"); @@ -179,7 +179,7 @@ begin burst := rnd.RandInt(1, 255); setup_and_set_random_data_read_memory(memory, burst, rdata'length, memory_data_queue); info(tb_logger, "Reading..."); - burst_read_bus(net, bus_handle, 0, burst, read_data_queue); + burst_read_bus(net, axi_master_handle.p_bus_handle, 0, burst, read_data_queue); info(tb_logger, "Compare..."); for i in 0 to burst - 1 loop read_tmp := pop(read_data_queue); @@ -196,7 +196,7 @@ begin burst := rnd.RandInt(1, 255); setup_and_set_random_data_read_memory(memory, burst+1, rdata'length, memory_data_queue); info(tb_logger, "Reading..."); - burst_read_axi(net, bus_handle, x"00000000", std_logic_vector(to_unsigned(burst, arlen'length)), "001", axi_burst_type_incr, x"25", axi_resp_okay, read_data_queue); + burst_read_axi(net, axi_master_handle.p_bus_handle, x"00000000", std_logic_vector(to_unsigned(burst, arlen'length)), "001", axi_burst_type_incr, x"25", axi_resp_okay, read_data_queue); info(tb_logger, "Compare..."); for i in 0 to burst loop read_tmp := pop(read_data_queue); @@ -213,7 +213,7 @@ begin burst := 1; setup_and_set_random_data_write_memory(memory, burst, wdata'length, memory_data_queue); info(tb_logger, "Reading..."); - write_bus(net, bus_handle, 0, pop(memory_data_queue)); + write_bus(net, axi_master_handle.p_bus_handle, 0, pop(memory_data_queue)); info(tb_logger, "Compare..."); check_true(is_empty(memory_data_queue), "memory_data_queue not flushed"); wait_on_data_write_memory(memory); @@ -225,7 +225,7 @@ begin burst := 1; setup_and_set_random_data_write_memory(memory, burst, wdata'length, memory_data_queue); info(tb_logger, "Reading..."); - write_axi(net, bus_handle, x"00000000", pop(memory_data_queue), "001", x"25", axi_resp_okay); + write_axi(net, axi_master_handle.p_bus_handle, x"00000000", pop(memory_data_queue), "001", x"25", axi_resp_okay); info(tb_logger, "Compare..."); check_true(is_empty(memory_data_queue), "memory_data_queue not flushed"); wait_on_data_write_memory(memory); @@ -237,7 +237,7 @@ begin burst := rnd.RandInt(1, 255); setup_and_set_random_data_write_memory(memory, burst, wdata'length, memory_data_queue); info(tb_logger, "Reading..."); - burst_write_bus(net, bus_handle, x"00000000", burst, memory_data_queue); + burst_write_bus(net, axi_master_handle.p_bus_handle, x"00000000", burst, memory_data_queue); info(tb_logger, "Compare..."); check_true(is_empty(memory_data_queue), "memory_data_queue not flushed"); wait_on_data_write_memory(memory); @@ -249,7 +249,7 @@ begin burst := rnd.RandInt(1, 255); setup_and_set_random_data_write_memory(memory, burst+1, wdata'length, memory_data_queue); info(tb_logger, "Reading..."); - burst_write_axi(net, bus_handle, x"00000000", std_logic_vector(to_unsigned(burst, awlen'length)),"001", axi_burst_type_incr, memory_data_queue, x"25", axi_resp_okay); + burst_write_axi(net, axi_master_handle.p_bus_handle, x"00000000", std_logic_vector(to_unsigned(burst, awlen'length)),"001", axi_burst_type_incr, memory_data_queue, x"25", axi_resp_okay); info(tb_logger, "Compare..."); check_true(is_empty(memory_data_queue), "memory_data_queue not flushed"); wait_on_data_write_memory(memory); @@ -303,7 +303,7 @@ begin dut : entity work.axi_master generic map ( - bus_handle => bus_handle) + axi_master_handle => axi_master_handle) port map ( aclk => clk, From cf81eda70ca9f16fe5586b49b77d8e720050e1a5 Mon Sep 17 00:00:00 2001 From: David Martin Date: Thu, 22 Aug 2024 14:42:58 +0200 Subject: [PATCH 22/24] Added areset_n signal to axi_master read --- .../src/axi_master.vhd | 90 ++++++++++++------- .../test/tb_axi_master.vhd | 35 +++++++- 2 files changed, 89 insertions(+), 36 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index 086e1099e..ece56b75a 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -34,7 +34,8 @@ entity axi_master is ); port ( aclk : in std_logic; - + areset_n : in std_logic; + arvalid : out std_logic := '0'; arready : in std_logic; arid : out std_logic_vector; @@ -128,6 +129,16 @@ begin end if; end procedure; + procedure drive_idle is + begin + arvalid <= '0'; + awvalid <= '0'; + wvalid <= '0'; + drive_ar_invalid; + drive_aw_invalid; + drive_w_invalid; + end procedure; + function get_full_read_size return std_logic_vector is begin return std_logic_vector(to_unsigned(integer(ceil(log2(real(rdata'length/8)))), arsize'length)); @@ -154,12 +165,10 @@ begin begin -- Initialization rnd.InitSeed(rnd'instance_name); - drive_ar_invalid; - drive_aw_invalid; - drive_w_invalid; + drive_idle; loop - wait until rising_edge(aclk) and not is_empty(message_queue); + wait until rising_edge(aclk) and not is_empty(message_queue) and areset_n = '1'; idle <= false; wait for 0 ps; @@ -167,8 +176,8 @@ begin msg_type := message_type(request_msg); if is_read(msg_type) then - while rnd.Uniform(0.0, 1.0) > axi_master_handle.p_read_high_probability loop - wait until rising_edge(aclk); + while rnd.Uniform(0.0, 1.0) > axi_master_handle.p_read_high_probability and areset_n = '1' loop + wait until rising_edge(aclk) or areset_n = '0'; end loop; addr := pop_std_ulogic_vector(request_msg); @@ -216,7 +225,7 @@ begin push(read_reply_queue, request_msg); arvalid <= '1'; - wait until (arvalid and arready) = '1' and rising_edge(aclk); + wait until ((arvalid and arready) = '1' and rising_edge(aclk)) or areset_n = '0'; arvalid <= '0'; drive_ar_invalid; @@ -319,6 +328,14 @@ begin unexpected_msg_type(msg_type); end if; + if areset_n = '0' then + drive_idle; + flush(read_reply_queue); + flush(write_reply_queue); + flush(message_queue); + wait for 0 ps; + end if; + idle <= true; end loop; end process; @@ -345,40 +362,47 @@ begin begin rready <= '1'; - wait until (rvalid and rready) = '1' and rising_edge(aclk); + wait until ((rvalid and rready) = '1' and rising_edge(aclk)); - reply_msg := new_msg; - request_msg := pop(read_reply_queue); - msg_type := message_type(request_msg); - - addr := pop_std_ulogic_vector(request_msg); - len := pop_integer(request_msg); - size := pop_std_ulogic_vector(request_msg); - burst := pop_std_ulogic_vector(request_msg); - id := pop_std_ulogic_vector(request_msg); - resp := pop(request_msg); + if areset_n = '1' then + reply_msg := new_msg; + request_msg := pop(read_reply_queue); + msg_type := message_type(request_msg); - if msg_type = bus_burst_read_msg or msg_type = axi_burst_read_msg then - push_integer(reply_msg, len + 1); -- bring axi burst up to bus one based indexing - end if; + addr := pop_std_ulogic_vector(request_msg); + len := pop_integer(request_msg); + size := pop_std_ulogic_vector(request_msg); + burst := pop_std_ulogic_vector(request_msg); + id := pop_std_ulogic_vector(request_msg); + resp := pop(request_msg); - -- first iteration - check_axi_id(axi_master_handle.p_bus_handle, rid, id, "rid"); - check_axi_resp(axi_master_handle.p_bus_handle, rresp, resp, "rresp"); - write_debug; - push_std_ulogic_vector(reply_msg, rdata); + if msg_type = bus_burst_read_msg or msg_type = axi_burst_read_msg then + push_integer(reply_msg, len + 1); -- bring axi burst up to bus one based indexing + end if; - -- burst iterations - for i in 0 to len - 1 loop - wait until (rvalid and rready) = '1' and rising_edge(aclk); + -- first iteration check_axi_id(axi_master_handle.p_bus_handle, rid, id, "rid"); check_axi_resp(axi_master_handle.p_bus_handle, rresp, resp, "rresp"); write_debug; push_std_ulogic_vector(reply_msg, rdata); - end loop; - reply(net, request_msg, reply_msg); - delete(request_msg); + -- burst iterations + for i in 0 to len - 1 loop + wait until ((rvalid and rready) = '1' and rising_edge(aclk)) or areset_n = '0'; + if areset_n = '0' then + exit; + end if; + check_axi_id(axi_master_handle.p_bus_handle, rid, id, "rid"); + check_axi_resp(axi_master_handle.p_bus_handle, rresp, resp, "rresp"); + write_debug; + push_std_ulogic_vector(reply_msg, rdata); + end loop; + + if areset_n = '1' then + reply(net, request_msg, reply_msg); + delete(request_msg); + end if; + end if; end process; -- Reply in separate process do not destroy alignment with the clock diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index abdb80184..d8e96f7ab 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -29,7 +29,8 @@ end entity; architecture a of tb_axi_master is constant num_random_tests : integer := 128; - signal clk : std_logic := '0'; + signal clk : std_logic := '0'; + signal areset_n : std_logic := '0'; signal arvalid : std_logic; signal arready : std_logic := '0'; @@ -70,10 +71,16 @@ architecture a of tb_axi_master is constant memory : memory_t := new_memory; constant axi_rd_slave : axi_slave_t := new_axi_slave(memory => memory, - logger => get_logger("axi_rd_slave")); + logger => get_logger("axi_rd_slave"), + address_stall_probability => 0.5, + data_stall_probability => 0.5, + write_response_stall_probability => 0.5); constant axi_wr_slave : axi_slave_t := new_axi_slave(memory => memory, - logger => get_logger("axi_wr_slave")); + logger => get_logger("axi_wr_slave"), + address_stall_probability => 0.5, + data_stall_probability => 0.5, + write_response_stall_probability => 0.5); constant tb_logger : logger_t := get_logger("tb"); begin @@ -142,9 +149,12 @@ begin variable memory_tmp : std_logic_vector(rdata'range); variable burst : natural := 0; + + variable reference : bus_reference_t; begin test_runner_setup(runner, runner_cfg); rnd.InitSeed("common_seed"); + areset_n <= '1'; wait for 0 ns; if run("Test read with read_bus") then @@ -255,6 +265,24 @@ begin wait_on_data_write_memory(memory); end loop; + elsif run("Test read asyncron reset") then + info(tb_logger, "Setup..."); + burst := 1; + setup_and_set_random_data_read_memory(memory, burst, rdata'length, memory_data_queue); + info(tb_logger, "Reading..."); + read_axi(net, axi_master_handle.p_bus_handle, x"00000000", "001", x"25", axi_resp_okay, reference); + info(tb_logger, "Sync on clk edge..."); + wait until rising_edge(clk); + info(tb_logger, "Set reset asyncron..."); + wait until rising_edge(arvalid); + areset_n <= '0' after 2ns; + wait until rising_edge(clk); + check_equal(arvalid, '0', "ARVALID not 0 when ARESET_N low"); + wait until rising_edge(clk); + info(tb_logger, "Release reset asyncron..."); + areset_n <= '1' after 0ps; + wait until rising_edge(clk); + check_equal(arvalid, '0', "ARVALID not 0 after ARESET_N low"); end if; wait for 100 ns; @@ -306,6 +334,7 @@ begin axi_master_handle => axi_master_handle) port map ( aclk => clk, + areset_n => areset_n, arvalid => arvalid, arready => arready, From 5a9b915d296c74b8ec288d2c7436dda92dfad82b Mon Sep 17 00:00:00 2001 From: David Martin Date: Wed, 28 Aug 2024 15:23:19 +0200 Subject: [PATCH 23/24] Added areset_n signal to axi_master write --- .../src/axi_master.vhd | 40 +++++++++++-------- .../test/tb_axi_master.vhd | 23 ++++++++++- 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index ece56b75a..3a9f72216 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -230,8 +230,8 @@ begin drive_ar_invalid; elsif is_write(msg_type) then - while rnd.Uniform(0.0, 1.0) > axi_master_handle.p_write_high_probability loop - wait until rising_edge(aclk); + while rnd.Uniform(0.0, 1.0) > axi_master_handle.p_write_high_probability and areset_n = '1' loop + wait until rising_edge(aclk) or areset_n = '0'; end loop; addr := pop_std_ulogic_vector(request_msg); @@ -287,7 +287,11 @@ begin wlast <= '1' when len = 0 else '0'; while not (w_done and aw_done) loop - wait until ((awvalid and awready) = '1' or (wvalid and wready) = '1') and rising_edge(aclk); + wait until (((awvalid and awready) = '1' or (wvalid and wready) = '1') and rising_edge(aclk)) or areset_n = '0'; + + if areset_n = '0' then + exit; + end if; if (awvalid and awready) = '1' then awvalid <= '0'; @@ -319,10 +323,12 @@ begin end loop; - push_std_ulogic_vector(request_msg, addr); - push_std_ulogic_vector(request_msg, id); - push_std_ulogic_vector(request_msg, resp); - push(write_reply_queue, request_msg); + if areset_n = '1' then + push_std_ulogic_vector(request_msg, addr); + push_std_ulogic_vector(request_msg, id); + push_std_ulogic_vector(request_msg, resp); + push(write_reply_queue, request_msg); + end if; else unexpected_msg_type(msg_type); @@ -417,18 +423,20 @@ begin bready <= '1'; wait until (bvalid and bready) = '1' and rising_edge(aclk); - bready <= '0'; + if areset_n = '1' then + bready <= '0'; - request_msg := pop(write_reply_queue); - msg_type := message_type(request_msg); - addr := pop_std_ulogic_vector(request_msg); - id := pop_std_ulogic_vector(request_msg); - resp := pop_std_ulogic_vector(request_msg); + request_msg := pop(write_reply_queue); + msg_type := message_type(request_msg); + addr := pop_std_ulogic_vector(request_msg); + id := pop_std_ulogic_vector(request_msg); + resp := pop_std_ulogic_vector(request_msg); - check_axi_id(axi_master_handle.p_bus_handle, bid, id, "bid"); - check_axi_resp(axi_master_handle.p_bus_handle, bresp, resp, "bresp"); + check_axi_id(axi_master_handle.p_bus_handle, bid, id, "bid"); + check_axi_resp(axi_master_handle.p_bus_handle, bresp, resp, "bresp"); - delete(request_msg); + delete(request_msg); + end if; end process; end architecture; diff --git a/vunit/vhdl/verification_components/test/tb_axi_master.vhd b/vunit/vhdl/verification_components/test/tb_axi_master.vhd index d8e96f7ab..4bcb44e7c 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -277,12 +277,31 @@ begin wait until rising_edge(arvalid); areset_n <= '0' after 2ns; wait until rising_edge(clk); - check_equal(arvalid, '0', "ARVALID not 0 when ARESET_N low"); + check_equal(arvalid, '0', "ARVALID 0 when ARESET_N low"); wait until rising_edge(clk); info(tb_logger, "Release reset asyncron..."); areset_n <= '1' after 0ps; wait until rising_edge(clk); - check_equal(arvalid, '0', "ARVALID not 0 after ARESET_N low"); + check_equal(arvalid, '0', "ARVALID 0 after ARESET_N low"); + elsif run("Test write asyncron reset") then + info(tb_logger, "Setup..."); + burst := 1; + setup_and_set_random_data_write_memory(memory, burst, wdata'length, memory_data_queue); + info(tb_logger, "Reading..."); + write_axi(net, axi_master_handle.p_bus_handle, x"00000000", pop(memory_data_queue), "001", x"25", axi_resp_okay); + info(tb_logger, "Sync on clk edge..."); + wait until rising_edge(clk); + info(tb_logger, "Set reset asyncron..."); + wait until rising_edge(awvalid); + areset_n <= '0' after 2ns; + wait until rising_edge(clk); + check_equal(arvalid, '0', "AWVALID 0 when ARESET_N low"); + wait until rising_edge(clk); + info(tb_logger, "Release reset asyncron..."); + areset_n <= '1' after 0ps; + wait until rising_edge(clk); + check_equal(awvalid, '0', "AWVALID 0 after ARESET_N low"); + check_equal(wvalid, '0', "WVALID 0 after ARESET_N low"); end if; wait for 100 ns; From ccf8c68abb6c9bc4dcc7b6ab0a3743454fe39d85 Mon Sep 17 00:00:00 2001 From: David Martin Date: Thu, 28 Nov 2024 10:27:33 +0100 Subject: [PATCH 24/24] Added id, unexpected message type policy and test runner lock - rule 4, 5, 10, 12 --- .../src/axi_master.vhd | 16 +++++- .../src/axi_master_pkg.vhd | 54 ++++++++++++++----- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/vunit/vhdl/verification_components/src/axi_master.vhd b/vunit/vhdl/verification_components/src/axi_master.vhd index 3a9f72216..687384991 100644 --- a/vunit/vhdl/verification_components/src/axi_master.vhd +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -27,6 +27,10 @@ use work.log_levels_pkg.all; use work.logger_pkg.all; use work.queue_pkg.all; use work.sync_pkg.all; +use work.vc_pkg.all; +use work.runner_pkg.all; +use work.run_pkg.all; +use work.run_types_pkg.all; entity axi_master is generic ( @@ -92,7 +96,9 @@ begin end if; handle_wait_until_idle(net, msg_type, request_msg); else - unexpected_msg_type(msg_type); + if axi_master_handle.p_unexpected_msg_type_policy = fail then + unexpected_msg_type(msg_type); + end if; end if; end process; @@ -162,13 +168,19 @@ begin variable burst : std_logic_vector(arburst'range) := (others => '0'); variable byteenable : std_logic_vector(wstrb'range) := (others => '0'); variable resp : axi_resp_t; + constant key : key_t := get_entry_key(test_runner_cleanup); begin -- Initialization rnd.InitSeed(rnd'instance_name); drive_idle; loop - wait until rising_edge(aclk) and not is_empty(message_queue) and areset_n = '1'; + if is_empty(message_queue) then + unlock(runner, key); + wait until rising_edge(aclk) and not is_empty(message_queue) and areset_n = '1'; + end if; + lock(runner, key); + idle <= false; wait for 0 ps; diff --git a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd index a6a578295..4fc0bdf1e 100644 --- a/vunit/vhdl/verification_components/src/axi_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd @@ -12,28 +12,35 @@ use ieee.numeric_std.all; use work.axi_pkg.all; use work.bus_master_pkg.all; -use work.com_pkg.send; +use work.com_pkg.all; use work.com_types_pkg.all; use work.logger_pkg.all; +use work.id_pkg.all; use work.queue_pkg.all; +use work.vc_pkg.all; package axi_master_pkg is -- Handle to VC instance type axi_master_t is record - -- These fields are private, do not use directly + -- Private + p_id : id_t; p_bus_handle : bus_master_t; p_drive_invalid : boolean; p_drive_invalid_val : std_logic; p_write_high_probability : real range 0.0 to 1.0; p_read_high_probability : real range 0.0 to 1.0; + p_unexpected_msg_type_policy : unexpected_msg_type_policy_t; end record; - impure function new_axi_master(data_length : natural; + impure function new_axi_master( + id : id_t := null_id; + data_length : natural; address_length : natural; byte_length : natural := 8; logger : logger_t := bus_logger; actor : actor_t := null_actor; + unexpected_msg_type_policy : unexpected_msg_type_policy_t := fail; drive_invalid : boolean := true; drive_invalid_val : std_logic := 'X'; write_high_probability : real := 1.0; @@ -141,30 +148,51 @@ package axi_master_pkg is end package; package body axi_master_pkg is - impure function new_axi_master(data_length : natural; + impure function new_axi_master( + id : id_t := null_id; + data_length : natural; address_length : natural; byte_length : natural := 8; logger : logger_t := bus_logger; actor : actor_t := null_actor; + unexpected_msg_type_policy : unexpected_msg_type_policy_t := fail; drive_invalid : boolean := true; drive_invalid_val : std_logic := 'X'; write_high_probability : real := 1.0; read_high_probability : real := 1.0 ) return axi_master_t is - variable bus_handle : bus_master_t := new_bus( - data_length, - address_length, - byte_length, - logger, - actor - ); + impure function create_bus (logger : logger_t) return bus_master_t is + begin + return new_bus( + data_length => data_length, + address_length => address_length, + logger => logger, + actor => actor + ); + end function; + variable logger_tmp : logger_t := null_logger; + variable id_tmp : id_t := null_id; + constant parent : id_t := get_id("vunit_lib:axi_master"); begin + if id = null_id then + id_tmp := get_id(to_string(num_children(parent) + 1), parent); + else + id_tmp := id; + end if; + if logger = null_logger then + logger_tmp := get_logger(id_tmp); + else + logger_tmp := logger; + end if; return ( - p_bus_handle => bus_handle, + p_id => id_tmp, + p_bus_handle => create_bus(logger_tmp), p_drive_invalid => drive_invalid, p_drive_invalid_val => drive_invalid_val, p_write_high_probability => write_high_probability, - p_read_high_probability => read_high_probability); + p_read_high_probability => read_high_probability, + p_unexpected_msg_type_policy => unexpected_msg_type_policy + ); end; procedure write_axi(signal net : inout network_t;