mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-23 13:27:10 -04:00
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:
parent
272e35521c
commit
99471e5d25
8 changed files with 73 additions and 27 deletions
|
@ -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}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue