diff --git a/dv/uvm/icache/dv/env/ibex_icache_scoreboard.sv b/dv/uvm/icache/dv/env/ibex_icache_scoreboard.sv index 33caf76c..37bc2591 100644 --- a/dv/uvm/icache/dv/env/ibex_icache_scoreboard.sv +++ b/dv/uvm/icache/dv/env/ibex_icache_scoreboard.sv @@ -11,7 +11,7 @@ class ibex_icache_scoreboard // TLM agent fifos uvm_tlm_analysis_fifo #(ibex_icache_core_bus_item) core_fifo; - uvm_tlm_analysis_fifo #(ibex_icache_mem_resp_item) mem_fifo; + uvm_tlm_analysis_fifo #(ibex_icache_mem_bus_item) mem_fifo; `uvm_component_new @@ -42,10 +42,10 @@ class ibex_icache_scoreboard endtask virtual task process_mem_fifo(); - ibex_icache_mem_resp_item item; + ibex_icache_mem_bus_item item; forever begin mem_fifo.get(item); - `uvm_info(`gfn, $sformatf("received ibex_mem_intf_seq item:\n%0s", item.sprint()), UVM_HIGH) + `uvm_info(`gfn, $sformatf("received mem transaction:\n%0s", item.sprint()), UVM_HIGH) end endtask diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent.core b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent.core index e05d8f73..016afc18 100644 --- a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent.core +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent.core @@ -15,6 +15,7 @@ filesets: - ibex_icache_mem_agent_pkg.sv - ibex_icache_mem_req_item.sv: {is_include_file: true} - ibex_icache_mem_resp_item.sv: {is_include_file: true} + - ibex_icache_mem_bus_item.sv: {is_include_file: true} - ibex_icache_mem_agent_cfg.sv: {is_include_file: true} - ibex_icache_mem_agent_cov.sv: {is_include_file: true} - ibex_icache_mem_driver.sv: {is_include_file: true} diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent_pkg.sv b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent_pkg.sv index a2a1eefd..f81f53aa 100644 --- a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent_pkg.sv +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_agent_pkg.sv @@ -17,6 +17,7 @@ package ibex_icache_mem_agent_pkg; // package sources `include "ibex_icache_mem_req_item.sv" `include "ibex_icache_mem_resp_item.sv" + `include "ibex_icache_mem_bus_item.sv" `include "ibex_icache_mem_model.sv" `include "ibex_icache_mem_agent_cfg.sv" `include "ibex_icache_mem_agent_cov.sv" diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_bus_item.sv b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_bus_item.sv new file mode 100644 index 00000000..d5cbd256 --- /dev/null +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_bus_item.sv @@ -0,0 +1,32 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// A transaction item that represents something happening on the memory bus. A 'request' is +// initiated by the cache and comes with an address. A 'response' comes from the memory system +// (including possibly the PMP checker). It comes with data and error flags. + +class ibex_icache_mem_bus_item extends uvm_sequence_item; + + // Is this a request or a response? + logic is_response; + + // Request address (only valid for request transactions) + logic [31:0] address; + + // Response data and error flags (only valid for response transactions) + logic [31:0] rdata; + logic err; + logic pmp_err; + + `uvm_object_utils_begin(ibex_icache_mem_bus_item) + `uvm_field_int(is_response, UVM_DEFAULT) + `uvm_field_int(address, UVM_DEFAULT | UVM_HEX) + `uvm_field_int(rdata, UVM_DEFAULT | UVM_HEX) + `uvm_field_int(err, UVM_DEFAULT) + `uvm_field_int(pmp_err, UVM_DEFAULT) + `uvm_object_utils_end + + `uvm_object_new + +endclass diff --git a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_monitor.sv b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_monitor.sv index 56a26188..766b6b66 100644 --- a/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_monitor.sv +++ b/dv/uvm/icache/dv/ibex_icache_mem_agent/ibex_icache_mem_monitor.sv @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 class ibex_icache_mem_monitor - extends dv_base_monitor #(.ITEM_T (ibex_icache_mem_resp_item), + extends dv_base_monitor #(.ITEM_T (ibex_icache_mem_bus_item), .CFG_T (ibex_icache_mem_agent_cfg), .COV_T (ibex_icache_mem_agent_cov)); @@ -13,7 +13,7 @@ class ibex_icache_mem_monitor // the base class provides the following handles for use: // ibex_icache_mem_agent_cfg: cfg // ibex_icache_mem_agent_cov: cov - // uvm_analysis_port #(ibex_icache_resp_item): analysis_port + // uvm_analysis_port #(ibex_icache_mem_bus_item): analysis_port // Incoming requests. This gets hooked up to the sequencer to service requests uvm_analysis_port #(ibex_icache_mem_req_item) request_port; @@ -32,6 +32,7 @@ class ibex_icache_mem_monitor fork collect_requests(); collect_grants(); + collect_responses(); join endtask @@ -69,6 +70,40 @@ class ibex_icache_mem_monitor end endtask + task automatic collect_responses(); + ibex_icache_mem_bus_item bus_trans; + + forever begin + // A response is signalled by either rvalid or pmp_err being true. Both are possible on the + // same cycle, corresponding to two different requests. + // + // Note that we're sampling on posedge clk. A PMP error that is signalled combinatorially as a + // response to a request will be spotted on the following clock cycle (the same time as the + // cache sees it). + if (cfg.vif.monitor_cb.pmp_err) begin + bus_trans = ibex_icache_mem_bus_item::type_id::create("bus_trans"); + bus_trans.is_response = 1'b1; + bus_trans.address = '0; + bus_trans.rdata = '0; + bus_trans.err = 0; + bus_trans.pmp_err = 1'b1; + analysis_port.write(bus_trans); + end + + if (cfg.vif.monitor_cb.rvalid) begin + bus_trans = ibex_icache_mem_bus_item::type_id::create("bus_trans"); + bus_trans.is_response = 1'b1; + bus_trans.address = '0; + bus_trans.rdata = cfg.vif.monitor_cb.rdata; + bus_trans.err = cfg.vif.monitor_cb.err; + bus_trans.pmp_err = 0; + analysis_port.write(bus_trans); + end + + @(cfg.vif.monitor_cb); + end + endtask + // This is called immediately when an address is requested and is used to drive the PMP response function automatic void new_request(logic [31:0] addr); ibex_icache_mem_req_item item = new("item"); @@ -81,12 +116,22 @@ class ibex_icache_mem_monitor // This is called on a clock edge when an request is granted function automatic void new_grant(logic [31:0] addr); - ibex_icache_mem_req_item item = new("item"); + ibex_icache_mem_req_item item; + ibex_icache_mem_bus_item bus_trans; + item = ibex_icache_mem_req_item::type_id::create("item"); item.is_grant = 1'b1; - item.address = addr; + item.address = addr; `DV_CHECK_RANDOMIZE_FATAL(item) request_port.write(item); + + bus_trans = ibex_icache_mem_bus_item::type_id::create("bus_trans"); + bus_trans.is_response = 1'b0; + bus_trans.address = addr; + bus_trans.rdata = '0; + bus_trans.err = 0; + bus_trans.pmp_err = 0; + analysis_port.write(bus_trans); endfunction endclass