Add a monitor to the icache <-> mem interface in UVM testbench

This is enough to report transactions up to the scoreboard. At the
moment, there's nothing listening, but you can see them going through
with

    make run VERBOSITY=h

and then looking at the dumps in run.log.
This commit is contained in:
Rupert Swarbrick 2020-04-13 09:44:19 +01:00 committed by Rupert Swarbrick
parent d7c90e519e
commit 9af4b3973c
5 changed files with 86 additions and 7 deletions

View file

@ -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

View file

@ -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}

View file

@ -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"

View file

@ -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

View file

@ -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