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..3a9f72216 --- /dev/null +++ b/vunit/vhdl/verification_components/src/axi_master.vhd @@ -0,0 +1,442 @@ +-- 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 +-- Author David Martin david.martin@phios.group + + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.math_real.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.all; +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 ( + axi_master_handle : axi_master_t + ); + port ( + aclk : in std_logic; + areset_n : in std_logic; + + arvalid : out std_logic := '0'; + arready : in std_logic; + arid : out std_logic_vector; + 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; + + rvalid : in std_logic; + rready : out std_logic := '0'; + rid : in std_logic_vector; + 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(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(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; + 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 read_reply_queue, write_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, 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 + 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 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 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 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; + + 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)); + 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; + variable w_done, aw_done : boolean; + + 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 : 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 + rnd.InitSeed(rnd'instance_name); + drive_idle; + + loop + wait until rising_edge(aclk) and not is_empty(message_queue) and areset_n = '1'; + idle <= false; + wait for 0 ps; + + request_msg := pop(message_queue); + 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 and areset_n = '1' loop + wait until rising_edge(aclk) or areset_n = '0'; + end loop; + + addr := pop_std_ulogic_vector(request_msg); + + if msg_type = bus_read_msg then + len := 0; + 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_read_size; + burst := axi_burst_type_incr; + id(id'range) := (others => '0'); + elsif msg_type = axi_read_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_read_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; + + 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'; + wait until ((arvalid and arready) = '1' and rising_edge(aclk)) or areset_n = '0'; + arvalid <= '0'; + drive_ar_invalid; + + elsif is_write(msg_type) then + 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); + + 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_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 + data := pop_std_ulogic_vector(request_msg); + 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); + 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); + resp := pop_std_ulogic_vector(request_msg); + elsif msg_type = axi_burst_write_msg then + 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; + + 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; + + wvalid <= '1'; + wdata <= data; + wstrb <= byteenable; + 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)) or areset_n = '0'; + + if areset_n = '0' then + exit; + end if; + + if (awvalid and awready) = '1' then + awvalid <= '0'; + drive_aw_invalid; + aw_done := true; + end if; + + if (wvalid and wready) = '1' then + + 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(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; + end if; + + end loop; + + 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); + 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; + + -- 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 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(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; + end procedure; + begin + + rready <= '1'; + wait until ((rvalid and rready) = '1' and rising_edge(aclk)); + + if areset_n = '1' then + 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 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; + + -- 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); + + -- 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 + 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); + 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); + + 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 if; + 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..a6a578295 --- /dev/null +++ b/vunit/vhdl/verification_components/src/axi_master_pkg.vhd @@ -0,0 +1,463 @@ +-- 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 +-- Author David Martin david.martin@phios.group + + +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; +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 "); + 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; + 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 len : std_logic_vector; + constant size : std_logic_vector; + constant burst : axi_burst_type_t; + constant data : queue_t; + 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; + 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; + 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); + + -- Blocking: read bus with immediate 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; + 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 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 := ""); + + 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; + + 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 + 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; + 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 len : std_logic_vector; + constant size : std_logic_vector; + constant burst : axi_burst_type_t; + constant data : queue_t; + 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_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); + 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); + + 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_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 + 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); + + 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; + + 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; + 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 + request_msg := new_msg(axi_burst_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, 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 + 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 burst_read_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 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_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; + + function is_read(msg_type : msg_type_t) return boolean is + begin + 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 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 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 + begin + return 8; -- TODO Add to bus_master_t? + end; + + function id_length(bus_handle : bus_master_t) return natural is + begin + return 32; -- TODO Add to bus_master_t? + end; + + function size_length(bus_handle : bus_master_t) return natural is + begin + return 3; -- TODO Add to bus_master_t? + end; +end package body; 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 603984ed9..f4cfd0dbb 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 new file mode 100644 index 000000000..4bcb44e7c --- /dev/null +++ b/vunit/vhdl/verification_components/test/tb_axi_master.vhd @@ -0,0 +1,440 @@ +-- 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 +-- Author David Martin david.martin@phios.group + +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; +use work.axi_slave_pkg.all; +use work.memory_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 areset_n : 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(2 downto 0); + signal arburst : axi_burst_type_t; + + 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(2 downto 0); + signal awburst : axi_burst_type_t; + + 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 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, + 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"), + 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 + + main : process + + variable rnd : RandomPType; + + 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; + + 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; + + variable read_tmp : std_logic_vector(rdata'range); + 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 + 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, 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"); + 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..."); + 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, 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 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, 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); + 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; + + 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, 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); + 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; + + 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, wdata'length, memory_data_queue); + info(tb_logger, "Reading..."); + 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); + 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, 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, "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, 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); + 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, 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); + 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 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 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; + + test_runner_cleanup(runner); + end process; + test_runner_watchdog(runner, 100 us); + + 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 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'); + constant wlast_invalid_value : std_logic := '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"); + 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; + + 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, "AWBURST not X when ARVALID low"); + check_equal(awid, a_id_invalid_value, "AWID not X when ARVALID 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"); + check_equal(wlast, wlast_invalid_value, "WLAST not X when WVALID low"); + end if; + end process; + + dut : entity work.axi_master + generic map ( + axi_master_handle => axi_master_handle) + port map ( + aclk => clk, + areset_n => areset_n, + + 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); + + 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); + + 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;