mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-22 13:07:46 -04:00
Add passthru test for ICache
This test constrains the address range (giving the cache a chance to do some caching), but leaves the cache disabled. Seed changes are more frequent than usual, to give us a good chance to spot any caching that shouldn't have happened.
This commit is contained in:
parent
ec42eb4409
commit
d750d3e53e
12 changed files with 159 additions and 30 deletions
|
@ -36,7 +36,7 @@
|
|||
could check this, but the unconstrained branch addresses mean it's
|
||||
very unlikely to see much caching going on.'''
|
||||
milestone: V2
|
||||
tests: []
|
||||
tests: ["ibex_icache_passthru"]
|
||||
}
|
||||
|
||||
{
|
||||
|
|
1
dv/uvm/icache/dv/env/ibex_icache_env.core
vendored
1
dv/uvm/icache/dv/env/ibex_icache_env.core
vendored
|
@ -20,6 +20,7 @@ filesets:
|
|||
- seq_lib/ibex_icache_vseq_list.sv: {is_include_file: true}
|
||||
- seq_lib/ibex_icache_base_vseq.sv: {is_include_file: true}
|
||||
- seq_lib/ibex_icache_sanity_vseq.sv: {is_include_file: true}
|
||||
- seq_lib/ibex_icache_passthru_vseq.sv: {is_include_file: true}
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
|
|
34
dv/uvm/icache/dv/env/seq_lib/ibex_icache_passthru_vseq.sv
vendored
Normal file
34
dv/uvm/icache/dv/env/seq_lib/ibex_icache_passthru_vseq.sv
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
class ibex_icache_passthru_vseq extends ibex_icache_base_vseq;
|
||||
|
||||
`uvm_object_utils(ibex_icache_passthru_vseq)
|
||||
`uvm_object_new
|
||||
|
||||
// A passthru sequence for the core agent and a basic slave sequence for the memory agent
|
||||
ibex_icache_core_passthru_seq core_seq;
|
||||
ibex_icache_mem_resp_seq mem_seq;
|
||||
|
||||
task body();
|
||||
// Start the core and memory sequences. We use fork/join_any so that we don't wait for the
|
||||
// memory sequence (which is reactive so will never finish).
|
||||
fork
|
||||
begin
|
||||
`uvm_create_on(core_seq, p_sequencer.core_sequencer_h)
|
||||
`DV_CHECK_RANDOMIZE_FATAL(core_seq)
|
||||
core_seq.start(p_sequencer.core_sequencer_h);
|
||||
end
|
||||
begin
|
||||
`uvm_create_on(mem_seq, p_sequencer.mem_sequencer_h)
|
||||
// Increase the frequency of seed updates
|
||||
mem_seq.gap_between_seeds = 49;
|
||||
|
||||
`DV_CHECK_RANDOMIZE_FATAL(mem_seq)
|
||||
mem_seq.start(p_sequencer.mem_sequencer_h);
|
||||
end
|
||||
join_any
|
||||
endtask : body
|
||||
|
||||
endclass : ibex_icache_passthru_vseq
|
|
@ -4,3 +4,4 @@
|
|||
|
||||
`include "ibex_icache_base_vseq.sv"
|
||||
`include "ibex_icache_sanity_vseq.sv"
|
||||
`include "ibex_icache_passthru_vseq.sv"
|
||||
|
|
|
@ -24,6 +24,7 @@ filesets:
|
|||
- ibex_icache_core_agent.sv: {is_include_file: true}
|
||||
- seq_lib/ibex_icache_core_base_seq.sv: {is_include_file: true}
|
||||
- seq_lib/ibex_icache_core_sanity_seq.sv: {is_include_file: true}
|
||||
- seq_lib/ibex_icache_core_passthru_seq.sv: {is_include_file: true}
|
||||
- seq_lib/ibex_icache_core_seq_list.sv: {is_include_file: true}
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
|
|
@ -12,8 +12,85 @@ class ibex_icache_core_base_seq extends dv_base_seq #(
|
|||
|
||||
`uvm_object_new
|
||||
|
||||
// Number of test items (note that a single test item may contain many instruction fetches)
|
||||
protected rand int count;
|
||||
constraint c_count { count inside {[800:1000]}; }
|
||||
|
||||
// The base address used when constrain_branches is true.
|
||||
protected rand bit[31:0] base_addr;
|
||||
|
||||
// If this is set, the next request should 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.
|
||||
protected bit force_branch = 1'b1;
|
||||
|
||||
// If this is set, any branch target address should be within 64 bytes of base_addr and runs of
|
||||
// instructions should have a maximum length of 100.
|
||||
protected bit constrain_branches = 1'b0;
|
||||
|
||||
// A count of the number of instructions fetched since the last branch. This is only important
|
||||
// when constrain_branches is true, in which case we want to ensure that we don't fetch too much
|
||||
// in a straight line between branches.
|
||||
protected int unsigned insns_since_branch = 0;
|
||||
|
||||
// If this bit is set, we will never enable the cache
|
||||
protected bit force_disable = 1'b0;
|
||||
|
||||
virtual task body();
|
||||
`uvm_fatal(`gtn, "Need to override this when you extend from this class!")
|
||||
endtask
|
||||
|
||||
// Generate and run a single item using class parameters
|
||||
protected task run_req(ibex_icache_core_req_item req, ibex_icache_core_rsp_item rsp);
|
||||
start_item(req);
|
||||
|
||||
if (constrain_branches && insns_since_branch >= 100)
|
||||
force_branch = 1'b1;
|
||||
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(
|
||||
req,
|
||||
|
||||
// Force a branch if necessary
|
||||
force_branch -> req.trans_type == ICacheCoreTransTypeBranch;
|
||||
|
||||
// If this is a branch and constrain_branches is true then constrain any branch target.
|
||||
(constrain_branches && (req.trans_type == ICacheCoreTransTypeBranch)) ->
|
||||
req.branch_addr inside {[base_addr:(base_addr + 64)]};
|
||||
|
||||
// If this is a branch and constrain_branches is true, we can ask for up to 100 instructions
|
||||
// (independent of insns_since_branch)
|
||||
(constrain_branches && (req.trans_type == ICacheCoreTransTypeBranch)) ->
|
||||
num_insns <= 100;
|
||||
|
||||
// If this isn't a branch and constrain_branches is true, we can ask for up to 100 -
|
||||
// insns_since_branch instructions. This will be positive because of the check above.
|
||||
(constrain_branches && (req.trans_type != ICacheCoreTransTypeBranch)) ->
|
||||
num_insns <= 100 - insns_since_branch;
|
||||
|
||||
force_disable -> !toggle_enable;
|
||||
)
|
||||
|
||||
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;
|
||||
|
||||
// Update insns_since_branch. Note that this will be an overestimate if we saw an error, but
|
||||
// that doesn't matter because we'll force a branch next time either way.
|
||||
insns_since_branch = (((req.trans_type == ICacheCoreTransTypeBranch) ? 0 : insns_since_branch) +
|
||||
req.num_insns);
|
||||
endtask
|
||||
|
||||
// Generate and run count items. Subclasses probably want to configure the parameters above before
|
||||
// running this.
|
||||
protected task run_reqs();
|
||||
req = ibex_icache_core_req_item::type_id::create("req");
|
||||
rsp = ibex_icache_core_rsp_item::type_id::create("rsp");
|
||||
|
||||
repeat (count - 1) begin
|
||||
run_req(req, rsp);
|
||||
end
|
||||
endtask
|
||||
|
||||
endclass
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Passthru test sequence
|
||||
//
|
||||
// This is used for the passthru test. We constrain branch targets and leave the cache disabled.
|
||||
|
||||
class ibex_icache_core_passthru_seq extends ibex_icache_core_base_seq;
|
||||
`uvm_object_utils(ibex_icache_core_passthru_seq)
|
||||
`uvm_object_new
|
||||
|
||||
task body();
|
||||
// Overrides for base sequence
|
||||
constrain_branches = 1'b1;
|
||||
force_disable = 1'b1;
|
||||
|
||||
run_reqs();
|
||||
endtask
|
||||
|
||||
endclass
|
|
@ -5,34 +5,14 @@
|
|||
// Sanity test seq
|
||||
//
|
||||
// This is unlikely to find many cache hits (since it branches all over the 4GiB address space).
|
||||
|
||||
class ibex_icache_core_sanity_seq extends ibex_icache_core_base_seq;
|
||||
`uvm_object_utils(ibex_icache_core_sanity_seq)
|
||||
`uvm_object_new
|
||||
|
||||
rand int count;
|
||||
constraint c_count { count inside {[800:1000]}; }
|
||||
|
||||
task body();
|
||||
// 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");
|
||||
|
||||
repeat (count - 1) begin
|
||||
start_item(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
|
||||
// No overrides needed in base sequence
|
||||
run_reqs();
|
||||
endtask
|
||||
|
||||
endclass
|
||||
|
|
|
@ -4,3 +4,4 @@
|
|||
|
||||
`include "ibex_icache_core_base_seq.sv"
|
||||
`include "ibex_icache_core_sanity_seq.sv"
|
||||
`include "ibex_icache_core_passthru_seq.sv"
|
||||
|
|
|
@ -9,6 +9,7 @@ class ibex_icache_mem_resp_item extends uvm_sequence_item;
|
|||
int unsigned min_response_delay = 0;
|
||||
int unsigned mid_response_delay = 5;
|
||||
int unsigned max_response_delay = 50;
|
||||
int unsigned gap_between_seeds = 499;
|
||||
|
||||
// True if this is a granted request. Otherwise, this is the first time we've seen an address (and
|
||||
// we might need to drive the PMP line).
|
||||
|
@ -40,7 +41,7 @@ class ibex_icache_mem_resp_item extends uvm_sequence_item;
|
|||
|
||||
constraint c_seed_dist {
|
||||
seed dist {
|
||||
32'd0 :/ 499,
|
||||
32'd0 :/ gap_between_seeds,
|
||||
[1:32'hffffffff] :/ 1
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,7 +6,12 @@
|
|||
|
||||
class ibex_icache_mem_resp_seq extends ibex_icache_mem_base_seq;
|
||||
|
||||
ibex_icache_mem_model #(.BusWidth (32)) mem_model;
|
||||
// Knobs
|
||||
//
|
||||
// gap_between_seeds is the expected number of memory fetches between each seed update.
|
||||
int unsigned gap_between_seeds = 499;
|
||||
|
||||
protected ibex_icache_mem_model #(.BusWidth (32)) mem_model;
|
||||
|
||||
// We pick new seeds when we spot a request (rather than when we spot a grant) to ensure that
|
||||
// any given fetch corresponds to exactly one seed. Unfortunately, there's a race if these two
|
||||
|
@ -37,6 +42,9 @@ class ibex_icache_mem_resp_seq extends ibex_icache_mem_base_seq;
|
|||
ibex_icache_mem_req_item req_item = new("req_item");
|
||||
ibex_icache_mem_resp_item resp_item = new("resp_item");
|
||||
|
||||
// Set knob to control randomization
|
||||
resp_item.gap_between_seeds = gap_between_seeds;
|
||||
|
||||
forever begin
|
||||
// Wait for a transaction request.
|
||||
p_sequencer.request_fifo.get(req_item);
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
|
||||
// Import additional common sim cfg files.
|
||||
// TODO: remove imported cfgs that do not apply.
|
||||
import_cfgs: [// Project wide common sim cfg file
|
||||
"{proj_root}/dv/uvm/data/common_sim_cfg.hjson"]
|
||||
|
||||
|
@ -45,14 +44,19 @@
|
|||
run_opts: ["+test_timeout_ns=1000000000"]
|
||||
}
|
||||
|
||||
// TODO: add more tests here
|
||||
{
|
||||
name: ibex_icache_passthru
|
||||
uvm_test_seq: ibex_icache_passthru_vseq
|
||||
run_opts: ["+test_timeout_ns=1000000000"]
|
||||
}
|
||||
]
|
||||
|
||||
// List of regressions.
|
||||
regressions: [
|
||||
{
|
||||
name: sanity
|
||||
tests: ["ibex_icache_sanity"]
|
||||
tests: ["ibex_icache_sanity",
|
||||
"ibex_icache_passthru"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue