Always branch after an error in icache UVM tests

If the cache returns an error to the core, the core must then issue a
branch before it tries to fetch again from the cache. This patch makes
this work by getting the core driver to respond with a (newly defined)
ibex_icache_core_rsp_item containing an error flag.
This commit is contained in:
Rupert Swarbrick 2020-04-28 11:22:51 +01:00 committed by Rupert Swarbrick
parent 272e35521c
commit 99471e5d25
8 changed files with 73 additions and 27 deletions

View file

@ -13,7 +13,8 @@ filesets:
- ibex_icache_core_if.sv
- ibex_icache_core_protocol_checker.sv
- ibex_icache_core_agent_pkg.sv
- ibex_icache_core_item.sv: {is_include_file: true}
- ibex_icache_core_req_item.sv: {is_include_file: true}
- ibex_icache_core_rsp_item.sv: {is_include_file: true}
- ibex_icache_core_bus_item.sv: {is_include_file: true}
- ibex_icache_core_agent_cfg.sv: {is_include_file: true}
- ibex_icache_core_agent_cov.sv: {is_include_file: true}

View file

@ -26,7 +26,8 @@ package ibex_icache_core_agent_pkg;
`include "dv_macros.svh"
// package sources
`include "ibex_icache_core_item.sv"
`include "ibex_icache_core_req_item.sv"
`include "ibex_icache_core_rsp_item.sv"
`include "ibex_icache_core_bus_item.sv"
`include "ibex_icache_core_agent_cfg.sv"
`include "ibex_icache_core_agent_cov.sv"

View file

@ -2,7 +2,10 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
class ibex_icache_core_driver extends dv_base_driver #(ibex_icache_core_item, ibex_icache_core_agent_cfg);
class ibex_icache_core_driver
extends dv_base_driver #(.ITEM_T (ibex_icache_core_req_item),
.RSP_ITEM_T (ibex_icache_core_rsp_item),
.CFG_T (ibex_icache_core_agent_cfg));
`uvm_component_utils(ibex_icache_core_driver)
`uvm_component_new
@ -18,18 +21,25 @@ class ibex_icache_core_driver extends dv_base_driver #(ibex_icache_core_item, ib
// drive trans received from sequencer
virtual task automatic get_and_drive();
ibex_icache_core_rsp_item rsp;
forever begin
seq_item_port.get_next_item(req);
`uvm_info(`gfn, $sformatf("rcvd item:\n%0s", req.sprint()), UVM_HIGH)
rsp = ibex_icache_core_rsp_item::type_id::create("rsp");
rsp.set_id_info(req);
rsp.saw_error = 1'b0;
case (req.trans_type)
ICacheCoreTransTypeBranch: drive_branch_trans(req);
ICacheCoreTransTypeReq: drive_req_trans(req);
ICacheCoreTransTypeBranch: drive_branch_trans(rsp, req);
ICacheCoreTransTypeReq: drive_req_trans(rsp, req);
default: `uvm_fatal(`gfn, "Unknown transaction type")
endcase
`uvm_info(`gfn, "item sent", UVM_HIGH)
seq_item_port.item_done();
seq_item_port.item_done(rsp);
end
endtask
@ -37,7 +47,8 @@ class ibex_icache_core_driver extends dv_base_driver #(ibex_icache_core_item, ib
//
// This concurrently asserts branch with a given address for a cycle while doing the usual
// (enable/disable, invalidate, read instructions).
virtual task automatic drive_branch_trans(ibex_icache_core_item req);
task automatic drive_branch_trans(ibex_icache_core_rsp_item rsp,
ibex_icache_core_req_item req);
// Make sure that req is enabled (has no effect unless this is the first transaction)
cfg.vif.driver_cb.req <= 1'b1;
@ -49,7 +60,7 @@ class ibex_icache_core_driver extends dv_base_driver #(ibex_icache_core_item, ib
fork
cfg.vif.branch_to(req.branch_addr);
if (req.invalidate) invalidate();
read_insns(req.num_insns);
read_insns(rsp, req.num_insns);
join
endtask
@ -57,7 +68,8 @@ class ibex_icache_core_driver extends dv_base_driver #(ibex_icache_core_item, ib
//
// This lowers req for zero or more cycles, at the same time as setting the enable pin and (maybe)
// pulsing the invalidate line. Once that is done, it reads zero or more instructions.
virtual task automatic drive_req_trans(ibex_icache_core_item req);
task automatic drive_req_trans(ibex_icache_core_rsp_item rsp,
ibex_icache_core_req_item req);
int unsigned req_low_cycles;
bit allow_no_low_cycles;
@ -80,16 +92,19 @@ class ibex_icache_core_driver extends dv_base_driver #(ibex_icache_core_item, ib
if (req_low_cycles > 0) lower_req(req_low_cycles);
if (req.invalidate) invalidate();
join
read_insns(req.num_insns);
read_insns(rsp, req.num_insns);
endtask
// Read up to num_insns instructions from the cache, stopping early on an error
virtual task automatic read_insns(int num_insns);
// Read up to num_insns instructions from the cache, stopping early on an error. If there was an
// error, fill in the saw_error flag in rsp (which will be passed back to the sequence).
task automatic read_insns(ibex_icache_core_rsp_item rsp, int num_insns);
for (int i = 0; i < num_insns; i++) begin
read_insn();
// Spot any error and exit early
if (cfg.vif.driver_cb.err)
if (cfg.vif.driver_cb.err) begin
rsp.saw_error = 1'b1;
break;
end
end
endtask

View file

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
class ibex_icache_core_item extends uvm_sequence_item;
class ibex_icache_core_req_item extends uvm_sequence_item;
// The type of transaction
rand ibex_icache_core_trans_type_e trans_type;
@ -62,7 +62,7 @@ class ibex_icache_core_item extends uvm_sequence_item;
}
`uvm_object_utils_begin(ibex_icache_core_item)
`uvm_object_utils_begin(ibex_icache_core_req_item)
`uvm_field_enum(ibex_icache_core_trans_type_e, trans_type, UVM_DEFAULT)
`uvm_field_int (branch_addr, UVM_DEFAULT | UVM_HEX)
`uvm_field_int (toggle_enable, UVM_DEFAULT)

View file

@ -0,0 +1,19 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
class ibex_icache_core_rsp_item extends uvm_sequence_item;
// A sequence item that is used for responses from the driver back to the sequence. This is needed
// so that we can spot when there was an error signalled by the core (which means the next
// sequence item will need to be a branch).
bit saw_error;
`uvm_object_utils_begin(ibex_icache_core_rsp_item)
`uvm_field_int (saw_error, UVM_DEFAULT)
`uvm_object_utils_end
`uvm_object_new
endclass

View file

@ -2,8 +2,10 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
class ibex_icache_core_sequencer extends dv_base_sequencer #(.ITEM_T (ibex_icache_core_item),
.CFG_T (ibex_icache_core_agent_cfg));
class ibex_icache_core_sequencer
extends dv_base_sequencer #(.ITEM_T (ibex_icache_core_req_item),
.RSP_ITEM_T (ibex_icache_core_rsp_item),
.CFG_T (ibex_icache_core_agent_cfg));
`uvm_component_utils(ibex_icache_core_sequencer)
`uvm_component_new

View file

@ -3,7 +3,8 @@
// SPDX-License-Identifier: Apache-2.0
class ibex_icache_core_base_seq extends dv_base_seq #(
.REQ (ibex_icache_core_item),
.REQ (ibex_icache_core_req_item),
.RSP (ibex_icache_core_rsp_item),
.CFG_T (ibex_icache_core_agent_cfg),
.SEQUENCER_T (ibex_icache_core_sequencer)
);

View file

@ -13,19 +13,26 @@ class ibex_icache_core_sanity_seq extends ibex_icache_core_base_seq;
constraint c_count { count > 0; count < 100; }
task body();
// Generate a request which is constrained to have trans_type ICacheCoreTransTypeBranch: the
// core must start with a branch to tell the cache where to fetch from in the first place.
req = ibex_icache_core_item::type_id::create("req");
start_item(req);
`DV_CHECK_RANDOMIZE_WITH_FATAL(req, req.trans_type == ICacheCoreTransTypeBranch;)
finish_item(req);
// If this is set, the next request will be constrained to have trans_type
// ICacheCoreTransTypeBranch. It's initially 1 because the core must start with a branch to tell
// the cache where to fetch from in the first place.
bit force_branch = 1'b1;
req = ibex_icache_core_req_item::type_id::create("req");
rsp = ibex_icache_core_rsp_item::type_id::create("rsp");
// Generate and run count ibex_icache_item sequence items (with no other constraint) through the
// req port.
repeat (count - 1) begin
start_item(req);
`DV_CHECK_RANDOMIZE_FATAL(req)
if (force_branch) begin
`DV_CHECK_RANDOMIZE_WITH_FATAL(req, req.trans_type == ICacheCoreTransTypeBranch;)
end else begin
`DV_CHECK_RANDOMIZE_FATAL(req)
end
finish_item(req);
get_response(rsp);
// The next transaction must start with a branch if this one ended with an error.
force_branch = rsp.saw_error;
end
endtask
endclass