diff --git a/hw/dv/vip/axi4_vip/axi4_vip.core b/hw/dv/vip/axi4_vip/axi4_vip.core new file mode 100644 index 000000000..571442871 --- /dev/null +++ b/hw/dv/vip/axi4_vip/axi4_vip.core @@ -0,0 +1,28 @@ +CAPI=2: +# Copyright lowRISC contributors (COSMIC project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name : lowrisc:dv:axi4_vip:0.1 + +filesets: + files_dv: + files: + - axi4_vip_if.sv + - axi4_vip_pkg.sv + - axi4_vip_defines.svh: {is_include_file: true} + - axi4_vip_types.svh: {is_include_file: true} + - axi4_vip_cfg.svh: {is_include_file: true} + - axi4_vip_item.svh: {is_include_file: true} + - axi4_vip_driver.svh: {is_include_file: true} + - axi4_vip_sequencer.svh: {is_include_file: true} + - axi4_vip_monitor.svh: {is_include_file: true} + - axi4_vip_manager_agent.svh: {is_include_file: true} + - axi4_vip_subordinate_agent.svh: {is_include_file: true} + - axi4_vip_env.svh: {is_include_file: true} + file_type: systemVerilogSource + +targets: + default: + filesets: + - files_dv \ No newline at end of file diff --git a/hw/dv/vip/axi4_vip/axi4_vip_cfg.svh b/hw/dv/vip/axi4_vip/axi4_vip_cfg.svh new file mode 100644 index 000000000..c2228fb4f --- /dev/null +++ b/hw/dv/vip/axi4_vip/axi4_vip_cfg.svh @@ -0,0 +1,104 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`ifndef AXI4_VIP_CFG_SVH +`define AXI4_VIP_CFG_SVH + +class axi4_vip_cfg extends uvm_object; + + // Currently this is a passive VIP (monitor only) + string m_inst_id = "AXI4"; + bit m_has_manager = 0; + uvm_active_passive_enum m_manager_active_passive = UVM_PASSIVE; + bit m_has_subordinate = 0; + uvm_active_passive_enum m_subordinate_active_passive = UVM_PASSIVE; + + // Future placeholders + bit m_has_coverage = 1; + bit m_has_checker = 1; + + // actual bus widths (<= max defines) + int unsigned m_id_width = 16; + int unsigned m_addr_width = 64; + int unsigned m_data_width = 512; + int unsigned m_user_width = 32; + int unsigned m_region_width = 8; + int unsigned m_qos_width = 8; + + `uvm_object_utils_begin(axi4_vip_cfg) + `uvm_field_string( m_inst_id, UVM_DEFAULT | UVM_STRING) + `uvm_field_int ( m_has_manager, UVM_DEFAULT) + `uvm_field_int ( m_has_subordinate, UVM_DEFAULT) + `uvm_field_int ( m_has_coverage, UVM_DEFAULT) + `uvm_field_int ( m_has_checker, UVM_DEFAULT) + `uvm_field_enum (uvm_active_passive_enum, m_manager_active_passive, UVM_DEFAULT) + `uvm_field_enum (uvm_active_passive_enum, m_subordinate_active_passive, UVM_DEFAULT) + `uvm_field_int ( m_id_width, UVM_DEFAULT) + `uvm_field_int ( m_addr_width, UVM_DEFAULT) + `uvm_field_int ( m_data_width, UVM_DEFAULT) + `uvm_field_int ( m_user_width, UVM_DEFAULT) + `uvm_field_int ( m_region_width, UVM_DEFAULT) + `uvm_field_int ( m_qos_width, UVM_DEFAULT) + `uvm_object_utils_end + + // External Method Declarations + extern function new(string name="axi4_vip_cfg"); + + extern virtual function void set_config( + string inst_id = "", + bit has_manager = 0, + uvm_active_passive_enum manager_active_passive = UVM_PASSIVE, + bit has_subordinate = 0, + uvm_active_passive_enum subordinate_active_passive = UVM_PASSIVE, + bit has_coverage = 0, + bit has_checker = 0, + int unsigned id_width = 16, + int unsigned addr_width = 64, + int unsigned data_width = 512, + int unsigned user_width = 32, + int unsigned region_width = 8, + int unsigned qos_width = 8 + ); + +endclass : axi4_vip_cfg + +//------------------------------------------------------------------------------ +// External Method Implementations +//------------------------------------------------------------------------------ + +function axi4_vip_cfg::new(string name="axi4_vip_cfg"); + super.new(name); +endfunction : new + +function void axi4_vip_cfg::set_config( + string inst_id = "", + bit has_manager = 0, + uvm_active_passive_enum manager_active_passive = UVM_PASSIVE, + bit has_subordinate = 0, + uvm_active_passive_enum subordinate_active_passive = UVM_PASSIVE, + bit has_coverage = 0, + bit has_checker = 0, + int unsigned id_width = 16, + int unsigned addr_width = 64, + int unsigned data_width = 512, + int unsigned user_width = 32, + int unsigned region_width = 8, + int unsigned qos_width = 8 +); + m_inst_id = inst_id; + m_has_manager = has_manager; + m_manager_active_passive = manager_active_passive; + m_has_subordinate = has_subordinate; + m_subordinate_active_passive = subordinate_active_passive; + m_has_coverage = has_coverage; + m_has_checker = has_checker; + m_id_width = id_width; + m_addr_width = addr_width; + m_data_width = data_width; + m_user_width = user_width; + m_region_width = region_width; + m_qos_width = qos_width; +endfunction : set_config + +`endif // AXI4_VIP_CFG_SVH \ No newline at end of file diff --git a/hw/dv/vip/axi4_vip/axi4_vip_defines.svh b/hw/dv/vip/axi4_vip/axi4_vip_defines.svh new file mode 100644 index 000000000..85dc2aeb2 --- /dev/null +++ b/hw/dv/vip/axi4_vip/axi4_vip_defines.svh @@ -0,0 +1,16 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`ifndef AXI4_VIP_DEFINES_SVH +`define AXI4_VIP_DEFINES_SVH + +// maximum supported bus widths +`define AXI4_MAX_ID_WIDTH 16 +`define AXI4_MAX_ADDR_WIDTH 64 +`define AXI4_MAX_DATA_WIDTH 1024 +`define AXI4_MAX_USER_WIDTH 32 +`define AXI4_MAX_REGION_WIDTH 8 +`define AXI4_MAX_QOS_WIDTH 8 + +`endif // AXI4_VIP_DEFINES_SVH \ No newline at end of file diff --git a/hw/dv/vip/axi4_vip/axi4_vip_driver.svh b/hw/dv/vip/axi4_vip/axi4_vip_driver.svh new file mode 100644 index 000000000..daa3ab36f --- /dev/null +++ b/hw/dv/vip/axi4_vip/axi4_vip_driver.svh @@ -0,0 +1,49 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`ifndef AXI4_VIP_DRIVER_SVH +`define AXI4_VIP_DRIVER_SVH + +class axi4_vip_driver extends uvm_driver #(axi4_vip_item); + + `uvm_component_utils(axi4_vip_driver) + + axi4_vip_cfg m_cfg; + virtual axi4_vip_if vif; + + // External Method Declarations + extern function new(string name, uvm_component parent); + extern function void build_phase(uvm_phase phase); + extern task run_phase(uvm_phase phase); + +endclass : axi4_vip_driver + +//------------------------------------------------------------------------------ +// External Method Implementations +//------------------------------------------------------------------------------ + +function axi4_vip_driver::new(string name, uvm_component parent); + super.new(name, parent); +endfunction : new + +function void axi4_vip_driver::build_phase(uvm_phase phase); + super.build_phase(phase); + if (! uvm_config_db #(axi4_vip_cfg)::get(this, "", "m_cfg", m_cfg)) begin + `uvm_fatal("NOCFG", {"Configuration item must be set for: ", get_full_name(), "m_cfg"}) + end + + if (! uvm_config_db #(virtual interface axi4_vip_if)::get(this, get_full_name(),"vif", vif)) begin + `uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"}) + end +endfunction : build_phase + +task axi4_vip_driver::run_phase(uvm_phase phase); + forever begin + // TODO: Placeholder + seq_item_port.get_next_item(req); + seq_item_port.item_done(); + end +endtask : run_phase + +`endif // AXI4_VIP_DRIVER_SVH \ No newline at end of file diff --git a/hw/dv/vip/axi4_vip/axi4_vip_env.svh b/hw/dv/vip/axi4_vip/axi4_vip_env.svh new file mode 100644 index 000000000..333c24243 --- /dev/null +++ b/hw/dv/vip/axi4_vip/axi4_vip_env.svh @@ -0,0 +1,47 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`ifndef AXI4_VIP_ENV_SVH +`define AXI4_VIP_ENV_SVH + +class axi4_vip_env extends uvm_env; + + `uvm_component_utils(axi4_vip_env) + + axi4_vip_cfg m_cfg; + + axi4_vip_manager_agent m_manager; + axi4_vip_subordinate_agent m_subordinate; + + // External Method Declarations + extern function new(string name, uvm_component parent); + extern function void build_phase(uvm_phase phase); + +endclass : axi4_vip_env + +//------------------------------------------------------------------------------ +// External Method Implementations +//------------------------------------------------------------------------------ + +function axi4_vip_env::new(string name, uvm_component parent); + super.new(name, parent); +endfunction : new + +function void axi4_vip_env::build_phase(uvm_phase phase); + super.build_phase(phase); + + if (! uvm_config_db #(axi4_vip_cfg)::get(this, "", "m_cfg", m_cfg)) begin + `uvm_fatal("NOCFG", {"Configuration item must be set for: ", get_full_name(), "m_cfg"}) + end + + if (m_cfg.m_has_manager == 1) begin + m_manager = axi4_vip_manager_agent::type_id::create("m_manager", this); + end + + if (m_cfg.m_has_subordinate == 1) begin + m_subordinate = axi4_vip_subordinate_agent::type_id::create("m_subordinate", this); + end +endfunction : build_phase + +`endif // AXI4_VIP_ENV_SVH \ No newline at end of file diff --git a/hw/dv/vip/axi4_vip/axi4_vip_if.sv b/hw/dv/vip/axi4_vip/axi4_vip_if.sv new file mode 100644 index 000000000..e88b6240f --- /dev/null +++ b/hw/dv/vip/axi4_vip/axi4_vip_if.sv @@ -0,0 +1,159 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`ifndef __AXI4_VIP_IF_SV +`define __AXI4_VIP_IF_SV + +interface axi4_vip_if #( + parameter int ID_WIDTH = 4, + parameter int ADDR_WIDTH = 32, + parameter int DATA_WIDTH = 64, + parameter int USER_WIDTH = 8, + parameter int REGION_WIDTH = 4, + parameter int QOS_WIDTH = 4 +)( + input logic aclk, + input logic aresetn +); + + // ========================================================= + // write address channel + // ========================================================= + logic awvalid; + logic awready; + logic [ID_WIDTH-1:0] awid; + logic [ADDR_WIDTH-1:0] awaddr; + logic [7:0] awlen; + logic [2:0] awsize; + logic [1:0] awburst; + logic awlock; + logic [3:0] awcache; + logic [2:0] awprot; + logic [QOS_WIDTH-1:0] awqos; + logic [REGION_WIDTH-1:0] awregion; + logic [USER_WIDTH-1:0] awuser; + + // ========================================================= + // write data channel + // ========================================================= + logic wvalid; + logic wready; + logic [DATA_WIDTH-1:0] wdata; + logic [(DATA_WIDTH/8)-1:0] wstrb; + logic wlast; + logic [USER_WIDTH-1:0] wuser; + + // ========================================================= + // write response channel + // ========================================================= + logic bvalid; + logic bready; + logic [ID_WIDTH-1:0] bid; + logic [1:0] bresp; + logic [USER_WIDTH-1:0] buser; + + // ========================================================= + // read address channel + // ========================================================= + logic arvalid; + logic arready; + logic [ID_WIDTH-1:0] arid; + logic [ADDR_WIDTH-1:0] araddr; + logic [7:0] arlen; + logic [2:0] arsize; + logic [1:0] arburst; + logic arlock; + logic [3:0] arcache; + logic [2:0] arprot; + logic [QOS_WIDTH-1:0] arqos; + logic [REGION_WIDTH-1:0] arregion; + logic [USER_WIDTH-1:0] aruser; + + // ========================================================= + // read data channel + // ========================================================= + logic rvalid; + logic rready; + logic [ID_WIDTH-1:0] rid; + logic [DATA_WIDTH-1:0] rdata; + logic [1:0] rresp; + logic rlast; + logic [USER_WIDTH-1:0] ruser; + + // manager clocking block + clocking manager_cb @(posedge aclk); + + // write address + output awvalid, awid, awaddr, awlen, awsize, awburst; + output awlock, awcache, awprot, awqos, awregion, awuser; + input awready; + + // write data + output wvalid, wdata, wstrb, wlast, wuser; + input wready; + + // write response + input bvalid, bid, bresp, buser; + output bready; + + // read address + output arvalid, arid, araddr, arlen, arsize, arburst; + output arlock, arcache, arprot, arqos, arregion, aruser; + input arready; + + // read data + input rvalid, rid, rdata, rresp, rlast, ruser; + output rready; + + endclocking + + + // subordinate clocking block + clocking subordinate_cb @(posedge aclk); + + // write address + input awvalid, awid, awaddr, awlen, awsize, awburst; + input awlock, awcache, awprot, awqos, awregion, awuser; + output awready; + + // write data + input wvalid, wdata, wstrb, wlast, wuser; + output wready; + + // write response + output bvalid, bid, bresp, buser; + input bready; + + // read address + input arvalid, arid, araddr, arlen, arsize, arburst; + input arlock, arcache, arprot, arqos, arregion, aruser; + output arready; + + // read data + output rvalid, rid, rdata, rresp, rlast, ruser; + input rready; + + endclocking + + + // monitor clocking block + clocking monitor_cb @(posedge aclk); + + input awvalid, awready, awid, awaddr, awlen, awsize, awburst; + input awlock, awcache, awprot, awqos, awregion, awuser; + + input wvalid, wready, wdata, wstrb, wlast, wuser; + + input bvalid, bready, bid, bresp, buser; + + input arvalid, arready, arid, araddr, arlen, arsize, arburst; + input arlock, arcache, arprot, arqos, arregion, aruser; + + input rvalid, rready, rid, rdata, rresp, rlast, ruser; + + endclocking + +endinterface + +`endif // __AXI4_VIP_IF_SV \ No newline at end of file diff --git a/hw/dv/vip/axi4_vip/axi4_vip_item.svh b/hw/dv/vip/axi4_vip/axi4_vip_item.svh new file mode 100644 index 000000000..e5bdb5ad4 --- /dev/null +++ b/hw/dv/vip/axi4_vip/axi4_vip_item.svh @@ -0,0 +1,160 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`ifndef axi4_vip_item_SVH +`define axi4_vip_item_SVH + +class axi4_vip_item extends uvm_sequence_item; + + // observation type + axi_obs_t obs_kind; + axi_dir_t dir; + + // ------------------------------------------------- + // Write Address Channel + // ------------------------------------------------- + rand bit [`AXI4_MAX_ID_WIDTH-1:0] awid; + rand bit [`AXI4_MAX_ADDR_WIDTH-1:0] awaddr; + rand bit [7:0] awlen; + rand bit [2:0] awsize; + rand bit [1:0] awburst; + rand bit awlock; + rand bit [3:0] awcache; + rand bit [2:0] awprot; + rand bit [`AXI4_MAX_QOS_WIDTH-1:0] awqos; + rand bit [`AXI4_MAX_REGION_WIDTH-1:0] awregion; + rand bit [`AXI4_MAX_USER_WIDTH-1:0] awuser; + + // ------------------------------------------------- + // Write Data Channel (Queues for multi-beat bursts) + // ------------------------------------------------- + rand bit [`AXI4_MAX_DATA_WIDTH-1:0] wdata[$]; + rand bit [`AXI4_MAX_DATA_WIDTH/8-1:0] wstrb[$]; + rand bit wlast[$]; + rand bit [`AXI4_MAX_USER_WIDTH-1:0] wuser[$]; + + // ------------------------------------------------- + // Write Response Channel + // ------------------------------------------------- + rand bit [`AXI4_MAX_ID_WIDTH-1:0] bid; + rand bit [1:0] bresp; + rand bit [`AXI4_MAX_USER_WIDTH-1:0] buser; + + // ------------------------------------------------- + // Read Address Channel + // ------------------------------------------------- + rand bit [`AXI4_MAX_ID_WIDTH-1:0] arid; + rand bit [`AXI4_MAX_ADDR_WIDTH-1:0] araddr; + rand bit [7:0] arlen; + rand bit [2:0] arsize; + rand bit [1:0] arburst; + rand bit arlock; + rand bit [3:0] arcache; + rand bit [2:0] arprot; + rand bit [`AXI4_MAX_QOS_WIDTH-1:0] arqos; + rand bit [`AXI4_MAX_REGION_WIDTH-1:0] arregion; + rand bit [`AXI4_MAX_USER_WIDTH-1:0] aruser; + + // ------------------------------------------------- + // Read Data Channel + // ------------------------------------------------- + rand bit [`AXI4_MAX_ID_WIDTH-1:0] rid; + rand bit [`AXI4_MAX_DATA_WIDTH-1:0] rdata[$]; + rand bit [1:0] rresp[$]; + rand bit rlast[$]; + rand bit [`AXI4_MAX_USER_WIDTH-1:0] ruser[$]; + + // ------------------------------------------------- + // UVM Automation Macros + // ------------------------------------------------- + `uvm_object_utils_begin(axi4_vip_item) + `uvm_field_enum(axi_obs_t, obs_kind, UVM_ALL_ON) + `uvm_field_enum(axi_dir_t, dir, UVM_ALL_ON) + + // Write Address + `uvm_field_int(awid, UVM_ALL_ON) + `uvm_field_int(awaddr, UVM_ALL_ON) + `uvm_field_int(awlen, UVM_ALL_ON) + `uvm_field_int(awsize, UVM_ALL_ON) + `uvm_field_int(awburst, UVM_ALL_ON) + `uvm_field_int(awlock, UVM_ALL_ON) + `uvm_field_int(awcache, UVM_ALL_ON) + `uvm_field_int(awprot, UVM_ALL_ON) + `uvm_field_int(awqos, UVM_ALL_ON) + `uvm_field_int(awregion, UVM_ALL_ON) + `uvm_field_int(awuser, UVM_ALL_ON) + + // Write Data (Queues) + `uvm_field_queue_int(wdata, UVM_ALL_ON) + `uvm_field_queue_int(wstrb, UVM_ALL_ON) + `uvm_field_queue_int(wlast, UVM_ALL_ON) + `uvm_field_queue_int(wuser, UVM_ALL_ON) + + // Write Response + `uvm_field_int(bid, UVM_ALL_ON) + `uvm_field_int(bresp, UVM_ALL_ON) + `uvm_field_int(buser, UVM_ALL_ON) + + // Read Address + `uvm_field_int(arid, UVM_ALL_ON) + `uvm_field_int(araddr, UVM_ALL_ON) + `uvm_field_int(arlen, UVM_ALL_ON) + `uvm_field_int(arsize, UVM_ALL_ON) + `uvm_field_int(arburst, UVM_ALL_ON) + `uvm_field_int(arlock, UVM_ALL_ON) + `uvm_field_int(arcache, UVM_ALL_ON) + `uvm_field_int(arprot, UVM_ALL_ON) + `uvm_field_int(arqos, UVM_ALL_ON) + `uvm_field_int(arregion, UVM_ALL_ON) + `uvm_field_int(aruser, UVM_ALL_ON) + + // Read Data (Queues) + `uvm_field_int(rid, UVM_ALL_ON) + `uvm_field_queue_int(rdata, UVM_ALL_ON) + `uvm_field_queue_int(rresp, UVM_ALL_ON) + `uvm_field_queue_int(rlast, UVM_ALL_ON) + `uvm_field_queue_int(ruser, UVM_ALL_ON) + `uvm_object_utils_end + + // ------------------------------------------------- + // Constraints (Stay inside class) + // ------------------------------------------------- + constraint c_awlen_wdata_match { + if (dir == AXI_WRITE) { + wdata.size() == (awlen + 1); + wstrb.size() == wdata.size(); + wlast.size() == wdata.size(); + foreach (wlast[i]) wlast[i] == (i == awlen); + } + } + + constraint c_arlen_rdata_match { + if (dir == AXI_READ) { + rdata.size() == (arlen + 1); + rresp.size() == rdata.size(); + rlast.size() == rdata.size(); + foreach (rlast[i]) rlast[i] == (i == arlen); + } + } + + // External Method Declarations + extern function new(string name="axi4_vip_item"); + extern virtual function axi4_vip_item clone(); + +endclass : axi4_vip_item + +//------------------------------------------------------------------------------ +// External Method Implementations +//------------------------------------------------------------------------------ + +function axi4_vip_item::new(string name="axi4_vip_item"); + super.new(name); +endfunction : new + +function axi4_vip_item axi4_vip_item::clone(); + clone = new(); + clone.copy(this); +endfunction : clone + +`endif // axi4_vip_item_SVH \ No newline at end of file diff --git a/hw/dv/vip/axi4_vip/axi4_vip_manager_agent.svh b/hw/dv/vip/axi4_vip/axi4_vip_manager_agent.svh new file mode 100644 index 000000000..f30c21a6e --- /dev/null +++ b/hw/dv/vip/axi4_vip/axi4_vip_manager_agent.svh @@ -0,0 +1,55 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`ifndef __AXI4_VIP_manager_AGENT_SVH +`define __AXI4_VIP_manager_AGENT_SVH + +class axi4_vip_manager_agent extends uvm_agent; + + `uvm_component_utils(axi4_vip_manager_agent) + + axi4_vip_cfg m_cfg; + + axi4_vip_monitor m_monitor; + axi4_vip_driver m_driver; + axi4_vip_sequencer m_sequencer; + + // External Method Declarations + extern function new(string name, uvm_component parent); + extern function void build_phase(uvm_phase phase); + extern function void connect_phase(uvm_phase phase); + +endclass : axi4_vip_manager_agent + +//------------------------------------------------------------------------------ +// External Method Implementations +//------------------------------------------------------------------------------ + +function axi4_vip_manager_agent::new(string name, uvm_component parent); + super.new(name, parent); +endfunction : new + +function void axi4_vip_manager_agent::build_phase(uvm_phase phase); + super.build_phase(phase); + + if (!uvm_config_db#(axi4_vip_cfg)::get(this,"","m_cfg",m_cfg)) begin + `uvm_fatal("NOCFG", {"Configuration item must be set for: ", get_full_name(), "m_cfg"}) + end + + m_monitor = axi4_vip_monitor::type_id::create("m_monitor", this); + + if (m_cfg.m_manager_active_passive == UVM_ACTIVE) begin + m_driver = axi4_vip_driver ::type_id::create("m_driver", this); + m_sequencer = axi4_vip_sequencer::type_id::create("m_sequencer", this); + end +endfunction : build_phase + +function void axi4_vip_manager_agent::connect_phase(uvm_phase phase); + // Future placeholder, UVM_ACTIVE is not supported + if (m_cfg.m_manager_active_passive == UVM_ACTIVE) begin + m_driver.seq_item_port.connect(m_sequencer.seq_item_export); + end +endfunction : connect_phase + +`endif // __AXI4_VIP_manager_AGENT_SVH \ No newline at end of file diff --git a/hw/dv/vip/axi4_vip/axi4_vip_monitor.svh b/hw/dv/vip/axi4_vip/axi4_vip_monitor.svh new file mode 100644 index 000000000..1eeada297 --- /dev/null +++ b/hw/dv/vip/axi4_vip/axi4_vip_monitor.svh @@ -0,0 +1,287 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`ifndef __AXI4_VIP_MONITOR_SVH +`define __AXI4_VIP_MONITOR_SVH + +class axi4_vip_monitor extends uvm_monitor; + + `uvm_component_utils(axi4_vip_monitor) + + axi4_vip_cfg m_cfg; + virtual axi4_vip_if vif; + + // Analysis Ports + uvm_analysis_port #(uvm_sequence_item) aw_ap; + uvm_analysis_port #(uvm_sequence_item) w_ap; + uvm_analysis_port #(uvm_sequence_item) ar_ap; + uvm_analysis_port #(uvm_sequence_item) r_ap; + uvm_analysis_port #(uvm_sequence_item) tx_ap; + + // --- Internal Storage --- + axi4_vip_item aw_pending_q[$]; + axi4_vip_item w_pending_q[$]; + + // ID-indexed queues to pair Request with Response + axi4_vip_item write_q_by_id [bit [`AXI4_MAX_ID_WIDTH-1:0]] [$]; + axi4_vip_item read_q_by_id [bit [`AXI4_MAX_ID_WIDTH-1:0]] [$]; + + // Process handles for granular thread control + local process aw_proc, w_proc, b_proc, ar_proc, r_proc; + + // External Method Declarations + extern function new(string name, uvm_component parent); + extern function void build_phase(uvm_phase phase); + extern task run_phase(uvm_phase phase); + extern function void stop_processes(); + extern function void cleanup_queues(); + extern task collect_aw_channel(); + extern task collect_w_channel(); + extern task collect_b_channel(); + extern task collect_ar_channel(); + extern task collect_r_channel(); + extern function void merge_tx(axi4_vip_item req, axi4_vip_item data); + +endclass : axi4_vip_monitor + +//------------------------------------------------------------------------------ +// External Method Implementations +//------------------------------------------------------------------------------ + +function axi4_vip_monitor::new(string name, uvm_component parent); + super.new(name, parent); +endfunction : new + +function void axi4_vip_monitor::build_phase(uvm_phase phase); + super.build_phase(phase); + if (!uvm_config_db #(axi4_vip_cfg)::get(this, "", "m_cfg", m_cfg)) begin + `uvm_fatal("NOCFG", {"Configuration item must be set for: ", get_full_name(), ".m_cfg"}) + end + if (!uvm_config_db #(virtual axi4_vip_if)::get(this, get_full_name(), "vif", vif)) begin + `uvm_fatal("NOVIF", {"virtual interface must be set for: ", get_full_name(), ".vif"}) + end + + aw_ap = new("aw_ap", this); + w_ap = new("w_ap", this); + ar_ap = new("ar_ap", this); + r_ap = new("r_ap", this); + tx_ap = new("tx_ap", this); +endfunction : build_phase + +task axi4_vip_monitor::run_phase(uvm_phase phase); + forever begin + wait(vif.aresetn === 1'b1); + + fork + begin aw_proc = process::self(); collect_aw_channel(); end + begin w_proc = process::self(); collect_w_channel(); end + begin b_proc = process::self(); collect_b_channel(); end + begin ar_proc = process::self(); collect_ar_channel(); end + begin r_proc = process::self(); collect_r_channel(); end + join_none + + wait(vif.aresetn === 1'b0); + stop_processes(); + cleanup_queues(); + end +endtask : run_phase + +function void axi4_vip_monitor::stop_processes(); + process p_list[$] = {aw_proc, w_proc, b_proc, ar_proc, r_proc}; + foreach (p_list[i]) begin + if (p_list[i] != null) begin + p_list[i].kill(); + end + end +endfunction : stop_processes + +function void axi4_vip_monitor::cleanup_queues(); + aw_pending_q.delete(); + w_pending_q.delete(); + write_q_by_id.delete(); + read_q_by_id.delete(); +endfunction : cleanup_queues + +task axi4_vip_monitor::collect_aw_channel(); + bit [`AXI4_MAX_ID_WIDTH-1:0] id_one = 1'b1; + bit [`AXI4_MAX_ADDR_WIDTH-1:0] addr_one = 1'b1; + bit [`AXI4_MAX_USER_WIDTH-1:0] user_one = 1'b1; + bit [`AXI4_MAX_REGION_WIDTH-1:0] region_one = 1'b1; + bit [`AXI4_MAX_QOS_WIDTH-1:0] qos_one = 1'b1; + + forever begin + @(vif.monitor_cb); + if (vif.monitor_cb.awvalid && vif.monitor_cb.awready) begin + axi4_vip_item tr = axi4_vip_item::type_id::create("aw_tr"); + tr.dir = AXI_WRITE; + tr.obs_kind = AXI_AW_CH; + + tr.awid = vif.monitor_cb.awid & ((id_one << m_cfg.m_id_width) - 1); + tr.awaddr = vif.monitor_cb.awaddr & ((addr_one << m_cfg.m_addr_width) - 1); + tr.awuser = vif.monitor_cb.awuser & ((user_one << m_cfg.m_user_width) - 1); + tr.awregion = vif.monitor_cb.awregion & ((region_one << m_cfg.m_region_width) - 1); + tr.awqos = vif.monitor_cb.awqos & ((qos_one << m_cfg.m_qos_width) - 1); + + tr.awlen = vif.monitor_cb.awlen; + tr.awsize = vif.monitor_cb.awsize; + tr.awburst = vif.monitor_cb.awburst; + tr.awlock = vif.monitor_cb.awlock; + tr.awcache = vif.monitor_cb.awcache; + tr.awprot = vif.monitor_cb.awprot; + + if (w_pending_q.size() > 0) begin + axi4_vip_item w_tr = w_pending_q.pop_front(); + merge_tx(tr, w_tr); + write_q_by_id[tr.awid].push_back(w_tr); + end else begin + aw_pending_q.push_back(tr); + end + `uvm_info(get_full_name(), $sformatf("AW collected: ID=%0h Addr=%0h", tr.awid, tr.awaddr), UVM_MEDIUM) + aw_ap.write(tr.clone()); + end + end +endtask : collect_aw_channel + +task axi4_vip_monitor::collect_w_channel(); + bit [`AXI4_MAX_DATA_WIDTH-1:0] data_one = 1'b1; + bit [`AXI4_MAX_USER_WIDTH-1:0] user_one = 1'b1; + axi4_vip_item current_burst; + + forever begin + @(vif.monitor_cb); + if (vif.monitor_cb.wvalid && vif.monitor_cb.wready) begin + if (current_burst == null) begin + current_burst = axi4_vip_item::type_id::create("w_burst"); + end + + current_burst.dir = AXI_WRITE; + current_burst.wdata.push_back(vif.monitor_cb.wdata & ((data_one << m_cfg.m_data_width) - 1)); + current_burst.wstrb.push_back(vif.monitor_cb.wstrb & ((data_one << (m_cfg.m_data_width/8)) - 1)); + current_burst.wuser.push_back(vif.monitor_cb.wuser & ((user_one << m_cfg.m_user_width) - 1)); + current_burst.wlast.push_back(vif.monitor_cb.wlast); + + if (vif.monitor_cb.wlast) begin + if (aw_pending_q.size() > 0) begin + axi4_vip_item aw_tr = aw_pending_q.pop_front(); + merge_tx(aw_tr, current_burst); + write_q_by_id[aw_tr.awid].push_back(current_burst); + end else begin + w_pending_q.push_back(current_burst); + end + current_burst.obs_kind = AXI_W_CH; + `uvm_info(get_full_name(), "W burst collected", UVM_MEDIUM) + w_ap.write(current_burst.clone()); + current_burst = null; + end + end + end +endtask : collect_w_channel + +task axi4_vip_monitor::collect_b_channel(); + bit [`AXI4_MAX_ID_WIDTH-1:0] id_one = 1'b1; + bit [`AXI4_MAX_USER_WIDTH-1:0] user_one = 1'b1; + bit [`AXI4_MAX_ID_WIDTH-1:0] id; + + forever begin + @(vif.monitor_cb); + if (vif.monitor_cb.bvalid && vif.monitor_cb.bready) begin + id = vif.monitor_cb.bid & ((id_one << m_cfg.m_id_width) - 1); + if (write_q_by_id.exists(id) && write_q_by_id[id].size() > 0) begin + axi4_vip_item tr = write_q_by_id[id].pop_front(); + tr.obs_kind = AXI_FULL_WRITE_TR; + tr.bid = id; + tr.bresp = vif.monitor_cb.bresp; + tr.buser = vif.monitor_cb.buser & ((user_one << m_cfg.m_user_width) - 1); + `uvm_info(get_full_name(), $sformatf("FULL Write complete: ID=%0h", id), UVM_LOW) + tx_ap.write(tr.clone()); + end else begin + `uvm_error("MON_B", $sformatf("B-Response for unexpected ID: %0h", id)) + end + end + end +endtask : collect_b_channel + +task axi4_vip_monitor::collect_ar_channel(); + bit [`AXI4_MAX_ID_WIDTH-1:0] id_one = 1'b1; + bit [`AXI4_MAX_ADDR_WIDTH-1:0] addr_one = 1'b1; + bit [`AXI4_MAX_USER_WIDTH-1:0] user_one = 1'b1; + bit [`AXI4_MAX_REGION_WIDTH-1:0] region_one = 1'b1; + bit [`AXI4_MAX_QOS_WIDTH-1:0] qos_one = 1'b1; + + forever begin + @(vif.monitor_cb); + if (vif.monitor_cb.arvalid && vif.monitor_cb.arready) begin + axi4_vip_item tr = axi4_vip_item::type_id::create("ar_tr"); + tr.dir = AXI_READ; + tr.obs_kind = AXI_AR_CH; + + tr.arid = vif.monitor_cb.arid & ((id_one << m_cfg.m_id_width) - 1); + tr.araddr = vif.monitor_cb.araddr & ((addr_one << m_cfg.m_addr_width) - 1); + tr.aruser = vif.monitor_cb.aruser & ((user_one << m_cfg.m_user_width) - 1); + tr.arregion = vif.monitor_cb.arregion & ((region_one << m_cfg.m_region_width) - 1); + tr.arqos = vif.monitor_cb.arqos & ((qos_one << m_cfg.m_qos_width) - 1); + + tr.arlen = vif.monitor_cb.arlen; + tr.arsize = vif.monitor_cb.arsize; + tr.arburst = vif.monitor_cb.arburst; + tr.arlock = vif.monitor_cb.arlock; + tr.arcache = vif.monitor_cb.arcache; + tr.arprot = vif.monitor_cb.arprot; + + read_q_by_id[tr.arid].push_back(tr); + `uvm_info(get_full_name(), $sformatf("AR collected: ID=%0h Addr=%0h", tr.arid, tr.araddr), UVM_MEDIUM) + ar_ap.write(tr.clone()); + end + end +endtask : collect_ar_channel + +task axi4_vip_monitor::collect_r_channel(); + bit [`AXI4_MAX_ID_WIDTH-1:0] id_one = 1'b1; + bit [`AXI4_MAX_DATA_WIDTH-1:0] data_one = 1'b1; + bit [`AXI4_MAX_USER_WIDTH-1:0] user_one = 1'b1; + bit [`AXI4_MAX_ID_WIDTH-1:0] id; + + forever begin + @(vif.monitor_cb); + if (vif.monitor_cb.rvalid && vif.monitor_cb.rready) begin + id = vif.monitor_cb.rid & ((id_one << m_cfg.m_id_width) - 1); + if (read_q_by_id.exists(id) && read_q_by_id[id].size() > 0) begin + axi4_vip_item tr = read_q_by_id[id][0]; // Peek + tr.rid = id; + tr.rdata.push_back(vif.monitor_cb.rdata & ((data_one << m_cfg.m_data_width) - 1)); + tr.rresp.push_back(vif.monitor_cb.rresp); + tr.ruser.push_back(vif.monitor_cb.ruser & ((user_one << m_cfg.m_user_width) - 1)); + + if (vif.monitor_cb.rlast) begin + void'(read_q_by_id[id].pop_front()); + tr.obs_kind = AXI_FULL_READ_TR; + `uvm_info(get_full_name(), $sformatf("FULL Read complete: ID=%0h", id), UVM_LOW) + tx_ap.write(tr.clone()); + end else begin + tr.obs_kind = AXI_R_CH; + end + r_ap.write(tr.clone()); + end else begin + `uvm_error("MON_R", $sformatf("R-Data for unexpected ID: %0h", id)) + end + end + end +endtask : collect_r_channel + +function void axi4_vip_monitor::merge_tx(axi4_vip_item req, axi4_vip_item data); + data.dir = req.dir; + data.awid = req.awid; + data.awaddr = req.awaddr; + data.awlen = req.awlen; + data.awsize = req.awsize; + data.awburst = req.awburst; + data.awlock = req.awlock; + data.awcache = req.awcache; + data.awprot = req.awprot; + data.awqos = req.awqos; + data.awregion = req.awregion; + data.awuser = req.awuser; +endfunction : merge_tx + +`endif // __AXI4_VIP_MONITOR_SVH \ No newline at end of file diff --git a/hw/dv/vip/axi4_vip/axi4_vip_pkg.sv b/hw/dv/vip/axi4_vip/axi4_vip_pkg.sv new file mode 100644 index 000000000..e1493c35b --- /dev/null +++ b/hw/dv/vip/axi4_vip/axi4_vip_pkg.sv @@ -0,0 +1,33 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`ifndef __AXI4_VIP_PKG_SV +`define __AXI4_VIP_PKG_SV + +`include "axi4_vip_if.sv" + +package axi4_vip_pkg; + + import uvm_pkg::*; + `include "uvm_macros.svh" + + `include "axi4_vip_defines.svh" + `include "axi4_vip_types.svh" + + `include "axi4_vip_cfg.svh" + + `include "axi4_vip_item.svh" + + `include "axi4_vip_driver.svh" + `include "axi4_vip_sequencer.svh" + + `include "axi4_vip_monitor.svh" + `include "axi4_vip_manager_agent.svh" + `include "axi4_vip_subordinate_agent.svh" + + `include "axi4_vip_env.svh" + +endpackage + +`endif // __AXI4_VIP_PKG_SV \ No newline at end of file diff --git a/hw/dv/vip/axi4_vip/axi4_vip_sequencer.svh b/hw/dv/vip/axi4_vip/axi4_vip_sequencer.svh new file mode 100644 index 000000000..63060776b --- /dev/null +++ b/hw/dv/vip/axi4_vip/axi4_vip_sequencer.svh @@ -0,0 +1,25 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`ifndef AXI4_VIP_SEQUENCER_SVH +`define AXI4_VIP_SEQUENCER_SVH + +class axi4_vip_sequencer extends uvm_sequencer #(axi4_vip_item); + + `uvm_component_utils(axi4_vip_sequencer) + + // External Method Declarations + extern function new(string name, uvm_component parent); + +endclass : axi4_vip_sequencer + +//------------------------------------------------------------------------------ +// External Method Implementations +//------------------------------------------------------------------------------ + +function axi4_vip_sequencer::new(string name, uvm_component parent); + super.new(name, parent); +endfunction : new + +`endif // AXI4_VIP_SEQUENCER_SVH \ No newline at end of file diff --git a/hw/dv/vip/axi4_vip/axi4_vip_subordinate_agent.svh b/hw/dv/vip/axi4_vip/axi4_vip_subordinate_agent.svh new file mode 100644 index 000000000..7661aa0a9 --- /dev/null +++ b/hw/dv/vip/axi4_vip/axi4_vip_subordinate_agent.svh @@ -0,0 +1,56 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`ifndef __AXI4_VIP_subordinate_AGENT_SVH +`define __AXI4_VIP_subordinate_AGENT_SVH + +class axi4_vip_subordinate_agent extends uvm_agent; + + `uvm_component_utils(axi4_vip_subordinate_agent) + + axi4_vip_cfg m_cfg; + + axi4_vip_monitor m_monitor; + axi4_vip_driver m_driver; + axi4_vip_sequencer m_sequencer; + + // External Method Declarations + extern function new(string name, uvm_component parent); + extern function void build_phase(uvm_phase phase); + extern function void connect_phase(uvm_phase phase); + +endclass : axi4_vip_subordinate_agent + +//------------------------------------------------------------------------------ +// External Method Implementations +//------------------------------------------------------------------------------ + +function axi4_vip_subordinate_agent::new(string name, uvm_component parent); + super.new(name, parent); +endfunction : new + +function void axi4_vip_subordinate_agent::build_phase(uvm_phase phase); + super.build_phase(phase); + + if (!uvm_config_db#(axi4_vip_cfg)::get(this,"","m_cfg",m_cfg)) begin + `uvm_fatal("NOCFG", {"Configuration item must be set for: ", get_full_name(), "m_config"}) + end + + m_monitor = axi4_vip_monitor::type_id::create("m_monitor", this); + + // Future placeholder + if (m_cfg.m_subordinate_active_passive == UVM_ACTIVE) begin + m_driver = axi4_vip_driver ::type_id::create("m_driver", this); + m_sequencer = axi4_vip_sequencer::type_id::create("m_sequencer", this); + end +endfunction : build_phase + +function void axi4_vip_subordinate_agent::connect_phase(uvm_phase phase); + // Future placeholder, UVM_ACTIVE is not supported + if (m_cfg.m_subordinate_active_passive == UVM_ACTIVE) begin + m_driver.seq_item_port.connect(m_sequencer.seq_item_export); + end +endfunction : connect_phase + +`endif // __AXI4_VIP_subordinate_AGENT_SVH \ No newline at end of file diff --git a/hw/dv/vip/axi4_vip/axi4_vip_types.svh b/hw/dv/vip/axi4_vip/axi4_vip_types.svh new file mode 100644 index 000000000..7176ed2d0 --- /dev/null +++ b/hw/dv/vip/axi4_vip/axi4_vip_types.svh @@ -0,0 +1,19 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`ifndef AXI4_VIP_TYPES_SVH +`define AXI4_VIP_TYPES_SVH + +typedef enum {AXI_READ, AXI_WRITE} axi_dir_t; + +typedef enum { + AXI_AW_CH, + AXI_W_CH, + AXI_FULL_WRITE_TR, + AXI_AR_CH, + AXI_R_CH, + AXI_FULL_READ_TR +} axi_obs_t; + +`endif // AXI4_VIP_TYPES_SVH \ No newline at end of file diff --git a/hw/top_chip/dv/env/top_chip_dv_axi_scoreboard.sv b/hw/top_chip/dv/env/top_chip_dv_axi_scoreboard.sv new file mode 100644 index 000000000..049f3e438 --- /dev/null +++ b/hw/top_chip/dv/env/top_chip_dv_axi_scoreboard.sv @@ -0,0 +1,191 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +class top_chip_dv_axi_scoreboard extends uvm_scoreboard; + `uvm_component_utils(top_chip_dv_axi_scoreboard) + + axi_addr_range_t mem_map[$]; + string default_subordinate_id = "INTERNAL_XBAR_DEFAULT"; + + // Analysis Implementation Ports + `uvm_analysis_imp_decl(_mgr0_cva6) + `uvm_analysis_imp_decl(_sub0_sram) + `uvm_analysis_imp_decl(_sub1_mailbox) + `uvm_analysis_imp_decl(_sub2_tlcrossbar) + `uvm_analysis_imp_decl(_sub3_dram) + + uvm_analysis_imp_mgr0_cva6 #(uvm_sequence_item, top_chip_dv_axi_scoreboard) mgr0_cva6_imp; + uvm_analysis_imp_sub0_sram #(uvm_sequence_item, top_chip_dv_axi_scoreboard) sub0_sram_imp; + uvm_analysis_imp_sub1_mailbox #(uvm_sequence_item, top_chip_dv_axi_scoreboard) sub1_mailbox_imp; + uvm_analysis_imp_sub2_tlcrossbar #(uvm_sequence_item, top_chip_dv_axi_scoreboard) sub2_tlcrossbar_imp; + uvm_analysis_imp_sub3_dram #(uvm_sequence_item, top_chip_dv_axi_scoreboard) sub3_dram_imp; + + // Queues to handle out-of-order monitor arrivals + // [SubordinateName][MaskedID] + axi4_vip_item expect_q[string][bit[top_pkg::AxiIdWidth-1:0]][$]; // Manager arrived first + axi4_vip_item actual_q[string][bit[top_pkg::AxiIdWidth-1:0]][$]; // Subordinate arrived first + + // External Method Declarations + extern function new(string name, uvm_component parent); + extern virtual function void build_phase(uvm_phase phase); + extern function bit [63:0] get_orig_id(bit [top_pkg::AxiIdWidth-1:0] full_id); + extern function string decode_addr(bit [63:0] addr); + extern virtual function void perform_comparison(axi4_vip_item exp, axi4_vip_item act, string slv); + extern virtual function void write_mgr0_cva6(uvm_sequence_item item); + extern virtual function void check_subordinate_arrival(uvm_sequence_item item, string slv_id); + extern virtual function void write_sub0_sram(uvm_sequence_item tr); + extern virtual function void write_sub1_mailbox(uvm_sequence_item tr); + extern virtual function void write_sub2_tlcrossbar(uvm_sequence_item tr); + extern virtual function void write_sub3_dram(uvm_sequence_item tr); + extern virtual function void check_phase(uvm_phase phase); + +endclass : top_chip_dv_axi_scoreboard + +//------------------------------------------------------------------------------ +// External Method Implementations +//------------------------------------------------------------------------------ + +function top_chip_dv_axi_scoreboard::new(string name, uvm_component parent); + super.new(name, parent); + mgr0_cva6_imp = new("mgr0_cva6_imp", this); + sub0_sram_imp = new("sub0_sram_imp", this); + sub1_mailbox_imp = new("sub1_mailbox_imp", this); + sub2_tlcrossbar_imp = new("sub2_tlcrossbar_imp", this); + sub3_dram_imp = new("sub3_dram_imp", this); +endfunction : new + +function void top_chip_dv_axi_scoreboard::build_phase(uvm_phase phase); + super.build_phase(phase); + + // Specific Address Mapping + mem_map.push_back('{"sub0_sram", (top_pkg::SRAMBase), (top_pkg::SRAMBase + top_pkg::SRAMLength - 1)}); + mem_map.push_back('{"sub1_mailbox", (top_pkg::MailboxBase), (top_pkg::MailboxBase + top_pkg::MailboxLength - 1)}); + mem_map.push_back('{"sub2_tlcrossbar", (top_pkg::TlCrossbarBase), (top_pkg::TlCrossbarBase + top_pkg::TlCrossbarBase - 1)}); + mem_map.push_back('{"sub3_dram", (top_pkg::DRAMBase), (top_pkg::DRAMBase + top_pkg::DRAMBase - 1)}); +endfunction : build_phase + +function bit [top_pkg::AxiIdWidth-1:0] top_chip_dv_axi_scoreboard::get_orig_id(bit [63:0] full_id); + return full_id & ((1 << top_pkg::AxiIdWidth) - 1); +endfunction : get_orig_id + +function string top_chip_dv_axi_scoreboard::decode_addr(bit [63:0] addr); + foreach (mem_map[i]) begin + if (addr >= mem_map[i].start_addr && addr <= mem_map[i].end_addr) + return mem_map[i].subordinate_name; + end + return default_subordinate_id; +endfunction : decode_addr + +function void top_chip_dv_axi_scoreboard::perform_comparison(axi4_vip_item exp, axi4_vip_item act, string slv); + bit [top_pkg::AxiIdWidth-1:0] mid = get_orig_id((act.dir == AXI_WRITE) ? act.bid : act.rid); + + if (act.dir == AXI_WRITE) begin + if (act.awaddr !== exp.awaddr || act.awlen !== exp.awlen || + act.awsize !== exp.awsize || act.awburst !== exp.awburst) begin + `uvm_error("SCB_ATTR_WR", $sformatf("Write Attribute mismatch on %s ID:%h", slv, mid)) + end + + if (act.wdata != exp.wdata) begin + `uvm_error("SCB_WDATA", $sformatf("Write Data mismatch on %s ID:%h", slv, mid)) + end + + if (act.wstrb != exp.wstrb) begin + `uvm_error("SCB_WSTRB", $sformatf("Write Strobe mismatch on %s ID:%h", slv, mid)) + end + end else begin + if (act.araddr !== exp.araddr || act.arlen !== exp.arlen || + act.arsize !== exp.arsize || act.arburst !== exp.arburst) begin + `uvm_error("SCB_ATTR_RD", $sformatf("Read Attribute mismatch on %s ID:%h", slv, mid)) + end + + if (act.rdata != exp.rdata) begin + `uvm_error("SCB_RDATA", $sformatf("Read Data mismatch on %s ID:%h", slv, mid)) + end + + if (act.rresp != exp.rresp) begin + `uvm_error("SCB_RRESP", $sformatf("Read Response mismatch on %s ID:%h", slv, mid)) + end + end +endfunction : perform_comparison + +function void top_chip_dv_axi_scoreboard::write_mgr0_cva6(uvm_sequence_item item); + axi4_vip_item tr; + if (!$cast(tr, item)) begin + `uvm_fatal("TYPE", "Cast failed") + end + + begin + bit [63:0] addr = (tr.dir == AXI_WRITE) ? tr.awaddr : tr.araddr; + bit [63:0] id = (tr.dir == AXI_WRITE) ? tr.awid : tr.arid; + string target_slv = decode_addr(addr); + bit [63:0] mid = get_orig_id(id); + + if (target_slv == default_subordinate_id) begin + // Decoder error check would go here + end else begin + if (actual_q[target_slv].exists(mid) && actual_q[target_slv][mid].size() > 0) begin + axi4_vip_item act_tr = actual_q[target_slv][mid].pop_front(); + perform_comparison(tr, act_tr, target_slv); + if (actual_q[target_slv][mid].size() == 0) actual_q[target_slv].delete(mid); + end else begin + axi4_vip_item exp_tr; + $cast(exp_tr, tr.clone()); + expect_q[target_slv][mid].push_back(exp_tr); + end + end + end +endfunction : write_mgr0 + +function void top_chip_dv_axi_scoreboard::check_subordinate_arrival(uvm_sequence_item item, string slv_id); + axi4_vip_item act; + if (!$cast(act, item)) `uvm_fatal("TYPE", "Cast failed") + + begin + bit [63:0] mid = get_orig_id((act.dir == AXI_WRITE) ? act.bid : act.rid); + + if (expect_q[slv_id].exists(mid) && expect_q[slv_id][mid].size() > 0) begin + axi4_vip_item exp_tr = expect_q[slv_id][mid].pop_front(); + perform_comparison(exp_tr, act, slv_id); + if (expect_q[slv_id][mid].size() == 0) expect_q[slv_id].delete(mid); + end else begin + axi4_vip_item act_tr; + $cast(act_tr, act.clone()); + actual_q[slv_id][mid].push_back(act_tr); + end + end +endfunction : check_subordinate_arrival + +function void top_chip_dv_axi_scoreboard::write_sub0_sram(uvm_sequence_item tr); + check_subordinate_arrival(tr, "sub0_sram"); +endfunction : write_sub0 + +function void top_chip_dv_axi_scoreboard::write_sub1_mailbox(uvm_sequence_item tr); + check_subordinate_arrival(tr, "sub1_mailbox"); +endfunction : write_sub1 + +function void top_chip_dv_axi_scoreboard::write_sub2_tlcrossbar(uvm_sequence_item tr); + check_subordinate_arrival(tr, "sub2_tlcrossbar"); +endfunction : write_sub2 + +function void top_chip_dv_axi_scoreboard::write_sub3_dram(uvm_sequence_item tr); + check_subordinate_arrival(tr, "sub3_dram"); +endfunction : write_sub3 + +function void top_chip_dv_axi_scoreboard::check_phase(uvm_phase phase); + super.check_phase(phase); + + // Check for requests that entered the fabric but never exited + foreach (expect_q[s, i]) begin + if (expect_q[s][i].size() > 0) begin + `uvm_error("SCB_DRAIN_DROP", $sformatf("DROPPED: Master req for %s (ID %h) lost in fabric", s, i)) + end + end + + // Check for responses that exited the fabric but weren't requested/seen by Master + foreach (actual_q[s, i]) begin + if (actual_q[s][i].size() > 0) begin + `uvm_error("SCB_DRAIN_GHOST", $sformatf("GHOST: Slave %s (ID %h) responded but Master missed it", s, i)) + end + end +endfunction : check_phase \ No newline at end of file diff --git a/hw/top_chip/dv/env/top_chip_dv_env.core b/hw/top_chip/dv/env/top_chip_dv_env.core index 26dddaeaf..3bd17d135 100644 --- a/hw/top_chip/dv/env/top_chip_dv_env.core +++ b/hw/top_chip/dv/env/top_chip_dv_env.core @@ -11,12 +11,14 @@ filesets: - lowrisc:dv:dv_utils - lowrisc:dv:mem_bkdr_util - lowrisc:dv:uart_agent + - lowrisc:dv:axi4_vip:0.1 - lowrisc:dv:common_ifs files: - top_chip_dv_env_pkg.sv - mem_clear_util.sv: {is_include_file: true} - top_chip_dv_env_cfg.sv: {is_include_file: true} - top_chip_dv_env_cov.sv: {is_include_file: true} + - top_chip_dv_axi_scoreboard.sv: {is_include_file: true} - top_chip_dv_env.sv: {is_include_file: true} - top_chip_dv_virtual_sequencer.sv: {is_include_file: true} - seq_lib/top_chip_dv_vseq_list.sv: {is_include_file: true} diff --git a/hw/top_chip/dv/env/top_chip_dv_env.sv b/hw/top_chip/dv/env/top_chip_dv_env.sv index 096fd6853..5175c4aa5 100644 --- a/hw/top_chip/dv/env/top_chip_dv_env.sv +++ b/hw/top_chip/dv/env/top_chip_dv_env.sv @@ -12,7 +12,11 @@ class top_chip_dv_env extends uvm_env; mem_bkdr_util mem_bkdr_util_h[chip_mem_e]; // Agents - uart_agent m_uart_agent; + uart_agent m_uart_agent; + axi4_vip_env m_mgr_axi[]; + axi4_vip_env m_sub_axi[]; + + top_chip_dv_axi_scoreboard m_axi_scb; // Standard SV/UVM methods extern function new(string name="", uvm_component parent=null); @@ -29,6 +33,9 @@ function top_chip_dv_env::new(string name="", uvm_component parent=null); endfunction : new function void top_chip_dv_env::build_phase(uvm_phase phase); + top_pkg::axi_hosts_t axi_mgr_name; + top_pkg::axi_devices_t axi_sub_name; + super.build_phase(phase); foreach (CHIP_MEM_LIST[i]) begin @@ -70,6 +77,20 @@ function void top_chip_dv_env::build_phase(uvm_phase phase); m_uart_agent = uart_agent::type_id::create("m_uart_agent", this); uvm_config_db#(uart_agent_cfg)::set(this, "m_uart_agent*", "cfg", cfg.m_uart_agent_cfg); + m_mgr_axi = new[NUM_OF_MGR_AXI_IFS]; + foreach (m_mgr_axi[i]) begin + axi_mgr_name = top_pkg::axi_hosts_t'(i); + m_mgr_axi[i] = axi4_vip_env::type_id::create(.name($sformatf("m_mgr_axi_%s", axi_mgr_name.name())), .parent(this)); + end + + m_sub_axi = new[NUM_OF_SUB_AXI_IFS]; + foreach (m_sub_axi[i]) begin + axi_sub_name = top_pkg::axi_devices_t'(i); + m_sub_axi[i] = axi4_vip_env::type_id::create(.name($sformatf("m_sub_axi_%s", axi_sub_name.name())), .parent(this)); + end + + m_axi_scb = top_chip_dv_axi_scoreboard::type_id::create("m_axi_scb", this); + uvm_config_db#(top_chip_dv_env_cfg)::set(this, "", "cfg", cfg); top_vsqr = top_chip_dv_virtual_sequencer::type_id::create("top_vsqr", this); @@ -86,6 +107,12 @@ function void top_chip_dv_env::connect_phase(uvm_phase phase); // Connect monitor output to matching FIFO in the virtual sequencer. // Allows virtual sequences to check TX items. m_uart_agent.monitor.tx_analysis_port.connect(top_vsqr.uart_tx_fifo.analysis_export); + + m_mgr_axi[top_pkg::CVA6] .m_manager .m_monitor.tx_ap.connect(m_axi_scb.mgr0_cva6_imp); + m_sub_axi[top_pkg::SRAM] .m_subordinate.m_monitor.tx_ap.connect(m_axi_scb.sub0_sram_imp); + m_sub_axi[top_pkg::Mailbox] .m_subordinate.m_monitor.tx_ap.connect(m_axi_scb.sub1_mailbox_imp); + m_sub_axi[top_pkg::TlCrossbar].m_subordinate.m_monitor.tx_ap.connect(m_axi_scb.sub2_tlcrossbar_imp); + m_sub_axi[top_pkg::DRAM] .m_subordinate.m_monitor.tx_ap.connect(m_axi_scb.sub3_dram_imp); endfunction : connect_phase task top_chip_dv_env::load_memories(); diff --git a/hw/top_chip/dv/env/top_chip_dv_env_cfg.sv b/hw/top_chip/dv/env/top_chip_dv_env_cfg.sv index 47beeb1b6..b235f0373 100644 --- a/hw/top_chip/dv/env/top_chip_dv_env_cfg.sv +++ b/hw/top_chip/dv/env/top_chip_dv_env_cfg.sv @@ -15,6 +15,8 @@ class top_chip_dv_env_cfg extends uvm_object; // External interface agent configs rand uart_agent_cfg m_uart_agent_cfg; + axi4_vip_cfg m_axi_mgr_cfg[]; + axi4_vip_cfg m_axi_sub_cfg[]; `uvm_object_utils_begin(top_chip_dv_env_cfg) `uvm_object_utils_end diff --git a/hw/top_chip/dv/env/top_chip_dv_env_pkg.sv b/hw/top_chip/dv/env/top_chip_dv_env_pkg.sv index e956b0a09..c82e57fcf 100644 --- a/hw/top_chip/dv/env/top_chip_dv_env_pkg.sv +++ b/hw/top_chip/dv/env/top_chip_dv_env_pkg.sv @@ -9,6 +9,7 @@ package top_chip_dv_env_pkg; import mem_bkdr_util_pkg::*; import sw_test_status_pkg::*; import uart_agent_pkg::*; + import axi4_vip_pkg::*; // Macro includes `include "uvm_macros.svh" @@ -20,6 +21,21 @@ package top_chip_dv_env_pkg; typedef chip_mem_e chip_mem_list_t[$]; + typedef enum bit[2:0] { + mst0 = 0, + slv0 = 1, + slv1 = 2, + slv2 = 3, + slv3 = 4 + } axi_if_t; + + // Local Address Map Struct + typedef struct { + string subordinate_name; + bit [63:0] start_addr; + bit [63:0] end_addr; + } axi_addr_range_t; + // Generate the list of all chip_mem_e values, this helps to simplify iterating over them with // foreach loops. const chip_mem_list_t CHIP_MEM_LIST = chip_mem_values(); @@ -46,11 +62,16 @@ package top_chip_dv_env_pkg; parameter bit [31:0] SW_DV_TEST_STATUS_ADDR = SW_DV_START_ADDR + 'h00; parameter bit [31:0] SW_DV_LOG_ADDR = SW_DV_START_ADDR + 'h04; + // Manual set is necessary + localparam int NUM_OF_MGR_AXI_IFS = 1; + localparam int NUM_OF_SUB_AXI_IFS = 4; + // File includes `include "mem_clear_util.sv" `include "top_chip_dv_env_cfg.sv" `include "top_chip_dv_env_cov.sv" `include "top_chip_dv_virtual_sequencer.sv" + `include "top_chip_dv_axi_scoreboard.sv" `include "top_chip_dv_env.sv" `include "top_chip_dv_vseq_list.sv" endpackage : top_chip_dv_env_pkg diff --git a/hw/top_chip/dv/tb/axi_vip_connections.sv b/hw/top_chip/dv/tb/axi_vip_connections.sv new file mode 100644 index 000000000..b1d16051e --- /dev/null +++ b/hw/top_chip/dv/tb/axi_vip_connections.sv @@ -0,0 +1,310 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// This AXI4 VIP shall be always UVM_PASSIVE on top level + // LHS is the VIP, RHS is the RTL + // ========================================================= + // mst0 - Tapping the XBAR Slave Port 0 (Master VIP side) + // ========================================================= + assign axi4_mgr_if[top_pkg::CVA6].aclk = clk; + assign axi4_mgr_if[top_pkg::CVA6].aresetn = rst_n; + + always_comb begin + // Request signals (Master -> XBAR) + axi4_mgr_if[top_pkg::CVA6].awvalid = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].aw_valid; + axi4_mgr_if[top_pkg::CVA6].awid = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].aw.id; + axi4_mgr_if[top_pkg::CVA6].awaddr = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].aw.addr; + axi4_mgr_if[top_pkg::CVA6].awlen = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].aw.len; + axi4_mgr_if[top_pkg::CVA6].awsize = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].aw.size; + axi4_mgr_if[top_pkg::CVA6].awburst = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].aw.burst; + axi4_mgr_if[top_pkg::CVA6].awlock = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].aw.lock; + axi4_mgr_if[top_pkg::CVA6].awcache = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].aw.cache; + axi4_mgr_if[top_pkg::CVA6].awprot = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].aw.prot; + axi4_mgr_if[top_pkg::CVA6].awqos = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].aw.qos; + axi4_mgr_if[top_pkg::CVA6].awregion = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].aw.region; + axi4_mgr_if[top_pkg::CVA6].awuser = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].aw.user; + + axi4_mgr_if[top_pkg::CVA6].wvalid = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].w_valid; + axi4_mgr_if[top_pkg::CVA6].wdata = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].w.data; + axi4_mgr_if[top_pkg::CVA6].wstrb = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].w.strb; + axi4_mgr_if[top_pkg::CVA6].wlast = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].w.last; + axi4_mgr_if[top_pkg::CVA6].wuser = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].w.user; + + axi4_mgr_if[top_pkg::CVA6].arvalid = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].ar_valid; + axi4_mgr_if[top_pkg::CVA6].arid = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].ar.id; + axi4_mgr_if[top_pkg::CVA6].araddr = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].ar.addr; + axi4_mgr_if[top_pkg::CVA6].arlen = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].ar.len; + axi4_mgr_if[top_pkg::CVA6].arsize = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].ar.size; + axi4_mgr_if[top_pkg::CVA6].arburst = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].ar.burst; + axi4_mgr_if[top_pkg::CVA6].arlock = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].ar.lock; + axi4_mgr_if[top_pkg::CVA6].arcache = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].ar.cache; + axi4_mgr_if[top_pkg::CVA6].arprot = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].ar.prot; + axi4_mgr_if[top_pkg::CVA6].arqos = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].ar.qos; + axi4_mgr_if[top_pkg::CVA6].arregion = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].ar.region; + axi4_mgr_if[top_pkg::CVA6].aruser = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].ar.user; + + axi4_mgr_if[top_pkg::CVA6].bready = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].b_ready; + axi4_mgr_if[top_pkg::CVA6].rready = `AXI_XBAR_HIER.slv_ports_req_i[top_pkg::CVA6].r_ready; + + // Response signals (XBAR -> Master) + axi4_mgr_if[top_pkg::CVA6].awready = `AXI_XBAR_HIER.slv_ports_resp_o[top_pkg::CVA6].aw_ready; + axi4_mgr_if[top_pkg::CVA6].wready = `AXI_XBAR_HIER.slv_ports_resp_o[top_pkg::CVA6].w_ready; + axi4_mgr_if[top_pkg::CVA6].arready = `AXI_XBAR_HIER.slv_ports_resp_o[top_pkg::CVA6].ar_ready; + + axi4_mgr_if[top_pkg::CVA6].bvalid = `AXI_XBAR_HIER.slv_ports_resp_o[top_pkg::CVA6].b_valid; + axi4_mgr_if[top_pkg::CVA6].bid = `AXI_XBAR_HIER.slv_ports_resp_o[top_pkg::CVA6].b.id; + axi4_mgr_if[top_pkg::CVA6].bresp = `AXI_XBAR_HIER.slv_ports_resp_o[top_pkg::CVA6].b.resp; + axi4_mgr_if[top_pkg::CVA6].buser = `AXI_XBAR_HIER.slv_ports_resp_o[top_pkg::CVA6].b.user; + + axi4_mgr_if[top_pkg::CVA6].rvalid = `AXI_XBAR_HIER.slv_ports_resp_o[top_pkg::CVA6].r_valid; + axi4_mgr_if[top_pkg::CVA6].rid = `AXI_XBAR_HIER.slv_ports_resp_o[top_pkg::CVA6].r.id; + axi4_mgr_if[top_pkg::CVA6].rdata = `AXI_XBAR_HIER.slv_ports_resp_o[top_pkg::CVA6].r.data; + axi4_mgr_if[top_pkg::CVA6].rresp = `AXI_XBAR_HIER.slv_ports_resp_o[top_pkg::CVA6].r.resp; + axi4_mgr_if[top_pkg::CVA6].rlast = `AXI_XBAR_HIER.slv_ports_resp_o[top_pkg::CVA6].r.last; + axi4_mgr_if[top_pkg::CVA6].ruser = `AXI_XBAR_HIER.slv_ports_resp_o[top_pkg::CVA6].r.user; + end + + // ========================================================= + // slv0 - Tapping the XBAR Master Port 0 (Slave VIP side) + // ========================================================= + assign axi4_sub_if[top_pkg::SRAM].aclk = clk; + assign axi4_sub_if[top_pkg::SRAM].aresetn = rst_n; + + always_comb begin + // Request signals (XBAR -> Slave) + axi4_sub_if[top_pkg::SRAM].awvalid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].aw_valid; + axi4_sub_if[top_pkg::SRAM].awid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].aw.id; + axi4_sub_if[top_pkg::SRAM].awaddr = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].aw.addr; + axi4_sub_if[top_pkg::SRAM].awlen = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].aw.len; + axi4_sub_if[top_pkg::SRAM].awsize = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].aw.size; + axi4_sub_if[top_pkg::SRAM].awburst = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].aw.burst; + axi4_sub_if[top_pkg::SRAM].awlock = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].aw.lock; + axi4_sub_if[top_pkg::SRAM].awcache = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].aw.cache; + axi4_sub_if[top_pkg::SRAM].awprot = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].aw.prot; + axi4_sub_if[top_pkg::SRAM].awqos = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].aw.qos; + axi4_sub_if[top_pkg::SRAM].awregion = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].aw.region; + axi4_sub_if[top_pkg::SRAM].awuser = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].aw.user; + + axi4_sub_if[top_pkg::SRAM].wvalid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].w_valid; + axi4_sub_if[top_pkg::SRAM].wdata = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].w.data; + axi4_sub_if[top_pkg::SRAM].wstrb = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].w.strb; + axi4_sub_if[top_pkg::SRAM].wlast = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].w.last; + axi4_sub_if[top_pkg::SRAM].wuser = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].w.user; + + axi4_sub_if[top_pkg::SRAM].arvalid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].ar_valid; + axi4_sub_if[top_pkg::SRAM].arid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].ar.id; + axi4_sub_if[top_pkg::SRAM].araddr = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].ar.addr; + axi4_sub_if[top_pkg::SRAM].arlen = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].ar.len; + axi4_sub_if[top_pkg::SRAM].arsize = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].ar.size; + axi4_sub_if[top_pkg::SRAM].arburst = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].ar.burst; + axi4_sub_if[top_pkg::SRAM].arlock = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].ar.lock; + axi4_sub_if[top_pkg::SRAM].arcache = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].ar.cache; + axi4_sub_if[top_pkg::SRAM].arprot = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].ar.prot; + axi4_sub_if[top_pkg::SRAM].arqos = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].ar.qos; + axi4_sub_if[top_pkg::SRAM].arregion = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].ar.region; + axi4_sub_if[top_pkg::SRAM].aruser = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].ar.user; + + axi4_sub_if[top_pkg::SRAM].bready = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].b_ready; + axi4_sub_if[top_pkg::SRAM].rready = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::SRAM].r_ready; + + // Response signals (Slave -> XBAR) + axi4_sub_if[top_pkg::SRAM].awready = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::SRAM].aw_ready; + axi4_sub_if[top_pkg::SRAM].wready = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::SRAM].w_ready; + axi4_sub_if[top_pkg::SRAM].arready = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::SRAM].ar_ready; + + axi4_sub_if[top_pkg::SRAM].bvalid = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::SRAM].b_valid; + axi4_sub_if[top_pkg::SRAM].bid = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::SRAM].b.id; + axi4_sub_if[top_pkg::SRAM].bresp = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::SRAM].b.resp; + axi4_sub_if[top_pkg::SRAM].buser = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::SRAM].b.user; + + axi4_sub_if[top_pkg::SRAM].rvalid = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::SRAM].r_valid; + axi4_sub_if[top_pkg::SRAM].rid = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::SRAM].r.id; + axi4_sub_if[top_pkg::SRAM].rdata = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::SRAM].r.data; + axi4_sub_if[top_pkg::SRAM].rresp = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::SRAM].r.resp; + axi4_sub_if[top_pkg::SRAM].rlast = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::SRAM].r.last; + axi4_sub_if[top_pkg::SRAM].ruser = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::SRAM].r.user; + end + + // ========================================================= + // slv1 - Tapping the XBAR Master Port 1 (Slave VIP side) + // ========================================================= + assign axi4_sub_if[top_pkg::Mailbox].aclk = clk; + assign axi4_sub_if[top_pkg::Mailbox].aresetn = rst_n; + + always_comb begin + // Request signals (XBAR -> Slave) + axi4_sub_if[top_pkg::Mailbox].awvalid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].aw_valid; + axi4_sub_if[top_pkg::Mailbox].awid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].aw.id; + axi4_sub_if[top_pkg::Mailbox].awaddr = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].aw.addr; + axi4_sub_if[top_pkg::Mailbox].awlen = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].aw.len; + axi4_sub_if[top_pkg::Mailbox].awsize = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].aw.size; + axi4_sub_if[top_pkg::Mailbox].awburst = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].aw.burst; + axi4_sub_if[top_pkg::Mailbox].awlock = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].aw.lock; + axi4_sub_if[top_pkg::Mailbox].awcache = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].aw.cache; + axi4_sub_if[top_pkg::Mailbox].awprot = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].aw.prot; + axi4_sub_if[top_pkg::Mailbox].awqos = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].aw.qos; + axi4_sub_if[top_pkg::Mailbox].awregion = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].aw.region; + axi4_sub_if[top_pkg::Mailbox].awuser = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].aw.user; + + axi4_sub_if[top_pkg::Mailbox].wvalid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].w_valid; + axi4_sub_if[top_pkg::Mailbox].wdata = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].w.data; + axi4_sub_if[top_pkg::Mailbox].wstrb = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].w.strb; + axi4_sub_if[top_pkg::Mailbox].wlast = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].w.last; + axi4_sub_if[top_pkg::Mailbox].wuser = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].w.user; + + axi4_sub_if[top_pkg::Mailbox].arvalid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].ar_valid; + axi4_sub_if[top_pkg::Mailbox].arid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].ar.id; + axi4_sub_if[top_pkg::Mailbox].araddr = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].ar.addr; + axi4_sub_if[top_pkg::Mailbox].arlen = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].ar.len; + axi4_sub_if[top_pkg::Mailbox].arsize = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].ar.size; + axi4_sub_if[top_pkg::Mailbox].arburst = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].ar.burst; + axi4_sub_if[top_pkg::Mailbox].arlock = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].ar.lock; + axi4_sub_if[top_pkg::Mailbox].arcache = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].ar.cache; + axi4_sub_if[top_pkg::Mailbox].arprot = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].ar.prot; + axi4_sub_if[top_pkg::Mailbox].arqos = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].ar.qos; + axi4_sub_if[top_pkg::Mailbox].arregion = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].ar.region; + axi4_sub_if[top_pkg::Mailbox].aruser = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].ar.user; + + axi4_sub_if[top_pkg::Mailbox].bready = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].b_ready; + axi4_sub_if[top_pkg::Mailbox].rready = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::Mailbox].r_ready; + + // Response signals (Slave -> XBAR) + axi4_sub_if[top_pkg::Mailbox].awready = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::Mailbox].aw_ready; + axi4_sub_if[top_pkg::Mailbox].wready = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::Mailbox].w_ready; + axi4_sub_if[top_pkg::Mailbox].arready = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::Mailbox].ar_ready; + + axi4_sub_if[top_pkg::Mailbox].bvalid = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::Mailbox].b_valid; + axi4_sub_if[top_pkg::Mailbox].bid = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::Mailbox].b.id; + axi4_sub_if[top_pkg::Mailbox].bresp = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::Mailbox].b.resp; + axi4_sub_if[top_pkg::Mailbox].buser = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::Mailbox].b.user; + + axi4_sub_if[top_pkg::Mailbox].rvalid = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::Mailbox].r_valid; + axi4_sub_if[top_pkg::Mailbox].rid = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::Mailbox].r.id; + axi4_sub_if[top_pkg::Mailbox].rdata = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::Mailbox].r.data; + axi4_sub_if[top_pkg::Mailbox].rresp = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::Mailbox].r.resp; + axi4_sub_if[top_pkg::Mailbox].rlast = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::Mailbox].r.last; + axi4_sub_if[top_pkg::Mailbox].ruser = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::Mailbox].r.user; + end + + // ========================================================= + // slv2 - Tapping the XBAR Master Port 2 (Slave VIP side) + // ========================================================= + assign axi4_sub_if[top_pkg::TlCrossbar].aclk = clk; + assign axi4_sub_if[top_pkg::TlCrossbar].aresetn = rst_n; + + always_comb begin + // Request signals (XBAR -> Slave) + axi4_sub_if[top_pkg::TlCrossbar].awvalid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].aw_valid; + axi4_sub_if[top_pkg::TlCrossbar].awid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].aw.id; + axi4_sub_if[top_pkg::TlCrossbar].awaddr = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].aw.addr; + axi4_sub_if[top_pkg::TlCrossbar].awlen = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].aw.len; + axi4_sub_if[top_pkg::TlCrossbar].awsize = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].aw.size; + axi4_sub_if[top_pkg::TlCrossbar].awburst = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].aw.burst; + axi4_sub_if[top_pkg::TlCrossbar].awlock = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].aw.lock; + axi4_sub_if[top_pkg::TlCrossbar].awcache = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].aw.cache; + axi4_sub_if[top_pkg::TlCrossbar].awprot = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].aw.prot; + axi4_sub_if[top_pkg::TlCrossbar].awqos = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].aw.qos; + axi4_sub_if[top_pkg::TlCrossbar].awregion = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].aw.region; + axi4_sub_if[top_pkg::TlCrossbar].awuser = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].aw.user; + + axi4_sub_if[top_pkg::TlCrossbar].wvalid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].w_valid; + axi4_sub_if[top_pkg::TlCrossbar].wdata = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].w.data; + axi4_sub_if[top_pkg::TlCrossbar].wstrb = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].w.strb; + axi4_sub_if[top_pkg::TlCrossbar].wlast = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].w.last; + axi4_sub_if[top_pkg::TlCrossbar].wuser = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].w.user; + + axi4_sub_if[top_pkg::TlCrossbar].arvalid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].ar_valid; + axi4_sub_if[top_pkg::TlCrossbar].arid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].ar.id; + axi4_sub_if[top_pkg::TlCrossbar].araddr = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].ar.addr; + axi4_sub_if[top_pkg::TlCrossbar].arlen = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].ar.len; + axi4_sub_if[top_pkg::TlCrossbar].arsize = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].ar.size; + axi4_sub_if[top_pkg::TlCrossbar].arburst = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].ar.burst; + axi4_sub_if[top_pkg::TlCrossbar].arlock = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].ar.lock; + axi4_sub_if[top_pkg::TlCrossbar].arcache = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].ar.cache; + axi4_sub_if[top_pkg::TlCrossbar].arprot = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].ar.prot; + axi4_sub_if[top_pkg::TlCrossbar].arqos = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].ar.qos; + axi4_sub_if[top_pkg::TlCrossbar].arregion = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].ar.region; + axi4_sub_if[top_pkg::TlCrossbar].aruser = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].ar.user; + + axi4_sub_if[top_pkg::TlCrossbar].bready = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].b_ready; + axi4_sub_if[top_pkg::TlCrossbar].rready = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::TlCrossbar].r_ready; + + // Response signals (Slave -> XBAR) + axi4_sub_if[top_pkg::TlCrossbar].awready = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::TlCrossbar].aw_ready; + axi4_sub_if[top_pkg::TlCrossbar].wready = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::TlCrossbar].w_ready; + axi4_sub_if[top_pkg::TlCrossbar].arready = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::TlCrossbar].ar_ready; + + axi4_sub_if[top_pkg::TlCrossbar].bvalid = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::TlCrossbar].b_valid; + axi4_sub_if[top_pkg::TlCrossbar].bid = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::TlCrossbar].b.id; + axi4_sub_if[top_pkg::TlCrossbar].bresp = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::TlCrossbar].b.resp; + axi4_sub_if[top_pkg::TlCrossbar].buser = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::TlCrossbar].b.user; + + axi4_sub_if[top_pkg::TlCrossbar].rvalid = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::TlCrossbar].r_valid; + axi4_sub_if[top_pkg::TlCrossbar].rid = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::TlCrossbar].r.id; + axi4_sub_if[top_pkg::TlCrossbar].rdata = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::TlCrossbar].r.data; + axi4_sub_if[top_pkg::TlCrossbar].rresp = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::TlCrossbar].r.resp; + axi4_sub_if[top_pkg::TlCrossbar].rlast = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::TlCrossbar].r.last; + axi4_sub_if[top_pkg::TlCrossbar].ruser = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::TlCrossbar].r.user; + end + + // ========================================================= + // slv3 - Tapping the XBAR Master Port 2 (Slave VIP side) + // ========================================================= + assign axi4_sub_if[top_pkg::DRAM].aclk = clk; + assign axi4_sub_if[top_pkg::DRAM].aresetn = rst_n; + + always_comb begin + // Request signals (XBAR -> Slave) + axi4_sub_if[top_pkg::DRAM].awvalid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].aw_valid; + axi4_sub_if[top_pkg::DRAM].awid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].aw.id; + axi4_sub_if[top_pkg::DRAM].awaddr = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].aw.addr; + axi4_sub_if[top_pkg::DRAM].awlen = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].aw.len; + axi4_sub_if[top_pkg::DRAM].awsize = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].aw.size; + axi4_sub_if[top_pkg::DRAM].awburst = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].aw.burst; + axi4_sub_if[top_pkg::DRAM].awlock = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].aw.lock; + axi4_sub_if[top_pkg::DRAM].awcache = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].aw.cache; + axi4_sub_if[top_pkg::DRAM].awprot = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].aw.prot; + axi4_sub_if[top_pkg::DRAM].awqos = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].aw.qos; + axi4_sub_if[top_pkg::DRAM].awregion = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].aw.region; + axi4_sub_if[top_pkg::DRAM].awuser = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].aw.user; + + axi4_sub_if[top_pkg::DRAM].wvalid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].w_valid; + axi4_sub_if[top_pkg::DRAM].wdata = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].w.data; + axi4_sub_if[top_pkg::DRAM].wstrb = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].w.strb; + axi4_sub_if[top_pkg::DRAM].wlast = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].w.last; + axi4_sub_if[top_pkg::DRAM].wuser = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].w.user; + + axi4_sub_if[top_pkg::DRAM].arvalid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].ar_valid; + axi4_sub_if[top_pkg::DRAM].arid = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].ar.id; + axi4_sub_if[top_pkg::DRAM].araddr = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].ar.addr; + axi4_sub_if[top_pkg::DRAM].arlen = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].ar.len; + axi4_sub_if[top_pkg::DRAM].arsize = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].ar.size; + axi4_sub_if[top_pkg::DRAM].arburst = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].ar.burst; + axi4_sub_if[top_pkg::DRAM].arlock = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].ar.lock; + axi4_sub_if[top_pkg::DRAM].arcache = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].ar.cache; + axi4_sub_if[top_pkg::DRAM].arprot = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].ar.prot; + axi4_sub_if[top_pkg::DRAM].arqos = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].ar.qos; + axi4_sub_if[top_pkg::DRAM].arregion = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].ar.region; + axi4_sub_if[top_pkg::DRAM].aruser = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].ar.user; + + axi4_sub_if[top_pkg::DRAM].bready = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].b_ready; + axi4_sub_if[top_pkg::DRAM].rready = `AXI_XBAR_HIER.mst_ports_req_o[top_pkg::DRAM].r_ready; + + // Response signals (Slave -> XBAR) + axi4_sub_if[top_pkg::DRAM].awready = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::DRAM].aw_ready; + axi4_sub_if[top_pkg::DRAM].wready = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::DRAM].w_ready; + axi4_sub_if[top_pkg::DRAM].arready = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::DRAM].ar_ready; + + axi4_sub_if[top_pkg::DRAM].bvalid = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::DRAM].b_valid; + axi4_sub_if[top_pkg::DRAM].bid = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::DRAM].b.id; + axi4_sub_if[top_pkg::DRAM].bresp = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::DRAM].b.resp; + axi4_sub_if[top_pkg::DRAM].buser = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::DRAM].b.user; + + axi4_sub_if[top_pkg::DRAM].rvalid = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::DRAM].r_valid; + axi4_sub_if[top_pkg::DRAM].rid = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::DRAM].r.id; + axi4_sub_if[top_pkg::DRAM].rdata = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::DRAM].r.data; + axi4_sub_if[top_pkg::DRAM].rresp = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::DRAM].r.resp; + axi4_sub_if[top_pkg::DRAM].rlast = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::DRAM].r.last; + axi4_sub_if[top_pkg::DRAM].ruser = `AXI_XBAR_HIER.mst_ports_resp_i[top_pkg::DRAM].r.user; + end diff --git a/hw/top_chip/dv/tb/chip_hier_macros.svh b/hw/top_chip/dv/tb/chip_hier_macros.svh index 35eb5bb16..2fc13ca1c 100644 --- a/hw/top_chip/dv/tb/chip_hier_macros.svh +++ b/hw/top_chip/dv/tb/chip_hier_macros.svh @@ -7,6 +7,7 @@ `define CPU_HIER `SYSTEM_HIER.i_cva6 `define SRAM_MEM_HIER `SYSTEM_HIER.u_axi_sram.u_ram.mem `define TAG_MEM_HIER `SYSTEM_HIER.u_axi_sram.u_tag_mem_prim.mem +`define AXI_XBAR_HIER `SYSTEM_HIER.u_axi_xbar // Testbench related `define SIM_SRAM_IF u_sim_sram.u_sim_sram_if diff --git a/hw/top_chip/dv/tb/tb.sv b/hw/top_chip/dv/tb/tb.sv index 12c25dbc2..af7218564 100644 --- a/hw/top_chip/dv/tb/tb.sv +++ b/hw/top_chip/dv/tb/tb.sv @@ -10,6 +10,7 @@ module tb; import mem_bkdr_util_pkg::mem_bkdr_util; import top_chip_dv_env_pkg::*; import top_chip_dv_test_pkg::*; + import axi4_vip_pkg::*; import top_chip_dv_env_pkg::SW_DV_START_ADDR; import top_chip_dv_env_pkg::SW_DV_TEST_STATUS_ADDR; @@ -30,6 +31,11 @@ module tb; clk_rst_if sys_clk_if(.clk(clk), .rst_n(rst_n)); clk_rst_if peri_clk_if(.clk(peri_clk), .rst_n(peri_rst_n)); uart_if uart_if(); + axi4_vip_if axi4_mgr_if[NUM_OF_MGR_AXI_IFS](); + axi4_vip_if axi4_sub_if[NUM_OF_SUB_AXI_IFS](); + + // AXI VIP connections are included from a separate file for better reading + `include "axi_vip_connections.sv" // ------ Mock DRAM ------ top_pkg::axi_dram_req_t dram_req; @@ -181,6 +187,13 @@ module tb; uvm_config_db#(virtual clk_rst_if)::set(null, "*", "peri_clk_if", peri_clk_if); uvm_config_db#(virtual uart_if)::set(null, "*.env.m_uart_agent*", "vif", uart_if); + // AXI VIFs + uvm_config_db#(virtual axi4_vip_if)::set(null, "*.m_mgr_axi_CVA6.*", "vif", axi4_mgr_if[top_pkg::CVA6]); + uvm_config_db#(virtual axi4_vip_if)::set(null, "*.m_sub_axi_SRAM.*", "vif", axi4_sub_if[top_pkg::SRAM]); + uvm_config_db#(virtual axi4_vip_if)::set(null, "*.m_sub_axi_Mailbox.*", "vif", axi4_sub_if[top_pkg::Mailbox]); + uvm_config_db#(virtual axi4_vip_if)::set(null, "*.m_sub_axi_TlCrossbar.*", "vif", axi4_sub_if[top_pkg::TlCrossbar]); + uvm_config_db#(virtual axi4_vip_if)::set(null, "*.m_sub_axi_DRAM.*", "vif", axi4_sub_if[top_pkg::DRAM]); + // SW logger and test status interfaces. uvm_config_db#(virtual sw_test_status_if)::set( null, "*.env", "sw_test_status_vif", `SIM_SRAM_IF.u_sw_test_status_if); diff --git a/hw/top_chip/dv/test/top_chip_dv_base_test.sv b/hw/top_chip/dv/test/top_chip_dv_base_test.sv index 58813d062..bbdf1c9a0 100644 --- a/hw/top_chip/dv/test/top_chip_dv_base_test.sv +++ b/hw/top_chip/dv/test/top_chip_dv_base_test.sv @@ -28,6 +28,11 @@ function top_chip_dv_base_test::new(string name="", uvm_component parent=null); endfunction : new function void top_chip_dv_base_test::build_phase(uvm_phase phase); + axi4_vip_cfg axi_mgr_cfg[]; + axi4_vip_cfg axi_sub_cfg[]; + top_pkg::axi_hosts_t axi_mgr_name; + top_pkg::axi_devices_t axi_sub_name; + dv_report_server m_dv_report_server = new(); uvm_report_server::set_server(m_dv_report_server); @@ -36,6 +41,114 @@ function void top_chip_dv_base_test::build_phase(uvm_phase phase); env = top_chip_dv_env::type_id::create("env", this); env.cfg = top_chip_dv_env_cfg::type_id::create("cfg", this); env.cfg.initialize(); + + // AXI VIP configuration + axi_mgr_cfg = new[NUM_OF_MGR_AXI_IFS]; + env.cfg.m_axi_mgr_cfg = new[NUM_OF_MGR_AXI_IFS]; + foreach (axi_mgr_cfg[i]) begin + axi_mgr_name = top_pkg::axi_hosts_t'(i); + axi_mgr_cfg[i] = axi4_vip_cfg::type_id::create(.name($sformatf("m_axi_%s_cfg", axi_mgr_name.name())), .parent(this)); + + case (axi_mgr_name) + top_pkg::CVA6: begin + axi_mgr_cfg[i].set_config(.inst_id (axi_mgr_name.name()), + .has_manager (1), + .manager_active_passive (UVM_PASSIVE), + .has_subordinate (0), + .subordinate_active_passive (UVM_PASSIVE), + .has_coverage (0), + .has_checker (0), + .id_width (top_pkg::AxiIdWidth), + .addr_width (top_pkg::AxiAddrWidth), + .data_width (top_pkg::AxiDataWidth), + .user_width (top_pkg::AxiUserWidth), + .region_width ( 4), + .qos_width ( 4) + ); + end + endcase + + uvm_config_db#(axi4_vip_cfg)::set(this, $sformatf("env.m_mgr_axi_%s*", axi_mgr_name.name()), "m_cfg", axi_mgr_cfg[i]); + env.cfg.m_axi_mgr_cfg[i] = axi_mgr_cfg[i]; + end + + axi_sub_cfg = new[NUM_OF_SUB_AXI_IFS]; + env.cfg.m_axi_sub_cfg = new[NUM_OF_SUB_AXI_IFS]; + foreach (axi_sub_cfg[i]) begin + axi_sub_name = top_pkg::axi_devices_t'(i); + axi_sub_cfg[i] = axi4_vip_cfg::type_id::create(.name($sformatf("m_axi_%s_cfg", axi_sub_name.name())), .parent(this)); + + case (axi_sub_name) + top_pkg::SRAM: begin + axi_sub_cfg[i].set_config(.inst_id (axi_sub_name.name()), + .has_manager (0), + .manager_active_passive (UVM_PASSIVE), + .has_subordinate (1), + .subordinate_active_passive (UVM_PASSIVE), + .has_coverage (0), + .has_checker (0), + .id_width (top_pkg::AxiIdWidth), + .addr_width (top_pkg::AxiAddrWidth), + .data_width (top_pkg::AxiDataWidth), + .user_width (top_pkg::AxiUserWidth), + .region_width ( 4), + .qos_width ( 4) + ); + end + top_pkg::Mailbox: begin + axi_sub_cfg[i].set_config(.inst_id (axi_sub_name.name()), + .has_manager (0), + .manager_active_passive (UVM_PASSIVE), + .has_subordinate (1), + .subordinate_active_passive (UVM_PASSIVE), + .has_coverage (0), + .has_checker (0), + .id_width (top_pkg::AxiIdWidth), + .addr_width (top_pkg::AxiAddrWidth), + .data_width (top_pkg::AxiDataWidth), + .user_width (top_pkg::AxiUserWidth), + .region_width ( 4), + .qos_width ( 4) + ); + end + top_pkg::TlCrossbar: begin + axi_sub_cfg[i].set_config(.inst_id (axi_sub_name.name()), + .has_manager (0), + .manager_active_passive (UVM_PASSIVE), + .has_subordinate (1), + .subordinate_active_passive (UVM_PASSIVE), + .has_coverage (0), + .has_checker (0), + .id_width (top_pkg::AxiIdWidth), + .addr_width (top_pkg::AxiAddrWidth), + .data_width (top_pkg::AxiDataWidth), + .user_width (top_pkg::AxiUserWidth), + .region_width ( 4), + .qos_width ( 4) + ); + end + top_pkg::DRAM: begin + axi_sub_cfg[i].set_config(.inst_id (axi_sub_name.name()), + .has_manager (0), + .manager_active_passive (UVM_PASSIVE), + .has_subordinate (1), + .subordinate_active_passive (UVM_PASSIVE), + .has_coverage (0), + .has_checker (0), + .id_width (top_pkg::AxiIdWidth), + .addr_width (top_pkg::AxiAddrWidth), + .data_width (top_pkg::AxiDataWidth), + .user_width (top_pkg::AxiUserWidth), + .region_width ( 4), + .qos_width ( 4) + ); + end + endcase + + uvm_config_db#(axi4_vip_cfg)::set(this, $sformatf("env.m_sub_axi_%s*", axi_sub_name.name()), "m_cfg", axi_sub_cfg[i]); + env.cfg.m_axi_sub_cfg[i] = axi_sub_cfg[i]; + end + endfunction : build_phase function void top_chip_dv_base_test::connect_phase(uvm_phase phase); diff --git a/hw/top_chip/dv/test/top_chip_dv_test_pkg.sv b/hw/top_chip/dv/test/top_chip_dv_test_pkg.sv index 11f5b0b27..f41a285dd 100644 --- a/hw/top_chip/dv/test/top_chip_dv_test_pkg.sv +++ b/hw/top_chip/dv/test/top_chip_dv_test_pkg.sv @@ -6,6 +6,7 @@ package top_chip_dv_test_pkg; import uvm_pkg::*; import dv_utils_pkg::*; import top_chip_dv_env_pkg::*; + import axi4_vip_pkg::*; `include "uvm_macros.svh" `include "dv_macros.svh" diff --git a/hw/top_chip/dv/top_chip_sim.core b/hw/top_chip/dv/top_chip_sim.core index 400dbaf69..5384d57db 100644 --- a/hw/top_chip/dv/top_chip_sim.core +++ b/hw/top_chip/dv/top_chip_sim.core @@ -25,9 +25,11 @@ filesets: - lowrisc:dv:xbar_macros - lowrisc:dv_dpi_c:uartdpi:0.1 - lowrisc:dv_dpi_sv:uartdpi:0.1 + - lowrisc:dv:axi4_vip:0.1 files: - tb/tb.sv - tb/chip_hier_macros.svh: {is_include_file: true} + - tb/axi_vip_connections.sv: {is_include_file: true} - verilator/dram_wrapper_sim.sv file_type: systemVerilogSource