Pass mem_err_shift to the ICache memory model on each error check

This has no immediate effect, but it means that the memory agent's
config's "mem_err_shift" value can be changed in the middle of the
test, rather than being fixed in the build_phase.
This commit is contained in:
Rupert Swarbrick 2020-06-16 11:27:57 +01:00 committed by Rupert Swarbrick
parent 48febdc5d6
commit b49f153a50
3 changed files with 18 additions and 23 deletions

View file

@ -119,8 +119,7 @@ class ibex_icache_scoreboard
seed_fifo = new("seed_fifo", this);
mem_model = new("mem_model",
cfg.mem_agent_cfg.disable_pmp_errs,
cfg.mem_agent_cfg.disable_mem_errs,
cfg.mem_agent_cfg.mem_err_shift);
cfg.mem_agent_cfg.disable_mem_errs);
endfunction
task run_phase(uvm_phase phase);
@ -406,7 +405,8 @@ class ibex_icache_scoreboard
return is_fetch_compatible_1(seen_insn_data,
seen_err,
mem_model.is_either_error(seed, addr_lo),
mem_model.is_either_error(seed, addr_lo,
cfg.mem_agent_cfg.mem_err_shift),
rdata[31:0],
seed,
chatty);
@ -445,13 +445,13 @@ class ibex_icache_scoreboard
lo_bits_to_drop = BusWidth - lo_bits_to_take;
// Do the first read (from the low address) and shift right to drop the bits that we don't need.
exp_err_lo = mem_model.is_either_error(seed_lo, addr_lo);
exp_err_lo = mem_model.is_either_error(seed_lo, addr_lo, cfg.mem_agent_cfg.mem_err_shift);
rdata = mem_model.read_data(seed_lo, addr_lo) >> lo_bits_to_drop;
exp_data = rdata[31:0];
// Now do the second read (from the upper address). Shift the result up by lo_bits_to_take,
// which will discard some top bits. Then extract 32 bits and OR with what we have so far.
exp_err_hi = mem_model.is_either_error(seed_hi, addr_hi);
exp_err_hi = mem_model.is_either_error(seed_hi, addr_hi, cfg.mem_agent_cfg.mem_err_shift);
rdata = mem_model.read_data(seed_hi, addr_hi) << lo_bits_to_take;
exp_data = exp_data | rdata[31:0];

View file

@ -29,29 +29,24 @@ class ibex_icache_mem_model #(parameter int unsigned BusWidth = 32) extends uvm_
// If set, disable memory errors
protected bit no_mem_errs;
// The power of two by which to divide the address space to get the error range: see is_error for
// details.
protected int unsigned error_shift;
function new(string name="",
bit disable_pmp_errs=0,
bit disable_mem_errs=0,
int unsigned err_shift=3);
bit disable_mem_errs=0);
no_pmp_errs = disable_pmp_errs;
no_mem_errs = disable_mem_errs;
error_shift = err_shift;
endfunction
`uvm_object_utils_begin(ibex_icache_mem_model)
`uvm_field_int (no_pmp_errs, UVM_DEFAULT)
`uvm_field_int (no_mem_errs, UVM_DEFAULT)
`uvm_field_int (error_shift, UVM_DEFAULT)
`uvm_object_utils_end
// Return true if reading BusWidth bits from address intersects with the error range given by the
// current seed. The error range has a length of (1/2^error_shift) times the size of the address
// space.
protected function automatic logic is_error(bit [31:0] seed, logic [31:0] address);
protected function automatic logic
is_error(bit [31:0] seed, logic [31:0] address, int unsigned error_shift);
logic [31:0] rng_lo, rng_hi, rng_w0, rng_w1;
rng_lo = seed ^ 32'hdeadbeef;
rng_w0 = 32'd1 << (32 - error_shift);
@ -65,18 +60,18 @@ class ibex_icache_mem_model #(parameter int unsigned BusWidth = 32) extends uvm_
endfunction
// Return true if reading BusWidth bits from address should give a PMP error
function automatic logic is_pmp_error(bit [31:0] seed, logic [31:0] address);
return (! no_pmp_errs) && is_error(seed, address ^ 32'h12344321);
function automatic logic is_pmp_error(bit [31:0] seed, logic [31:0] addr, int unsigned err_shift);
return (! no_pmp_errs) && is_error(seed, addr ^ 32'h12344321, err_shift);
endfunction
// Return true if reading BusWidth bits from address should give a memory error
function automatic logic is_mem_error(bit [31:0] seed, logic [31:0] address);
return (! no_mem_errs) && is_error(seed, address ^ 32'hf00dbeef);
function automatic logic is_mem_error(bit [31:0] seed, logic [31:0] addr, int unsigned err_shift);
return (! no_mem_errs) && is_error(seed, addr ^ 32'hf00dbeef, err_shift);
endfunction
// Return true if reading BusWidth bits from address should give some sort of error
function automatic logic is_either_error(bit [31:0] seed, logic [31:0] address);
return is_pmp_error(seed, address) || is_mem_error(seed, address);
function automatic logic is_either_error(bit [31:0] seed, logic [31:0] addr, int unsigned err_shift);
return is_pmp_error(seed, addr, err_shift) || is_mem_error(seed, addr, err_shift);
endfunction
// Return BusWidth bits of data from reading at address.

View file

@ -32,7 +32,7 @@ class ibex_icache_mem_resp_seq extends ibex_icache_mem_base_seq;
task pre_start();
super.pre_start();
mem_model = new("mem_model", cfg.disable_pmp_errs, cfg.disable_mem_errs, cfg.mem_err_shift);
mem_model = new("mem_model", cfg.disable_pmp_errs, cfg.disable_mem_errs);
endtask
task body();
@ -75,7 +75,7 @@ class ibex_icache_mem_resp_seq extends ibex_icache_mem_base_seq;
resp_item.is_grant = 1'b0;
resp_item.address = req_item.address;
resp_item.rdata = 'X;
resp_item.err = mem_model.is_pmp_error(cur_seed, req_item.address);
resp_item.err = mem_model.is_pmp_error(cur_seed, req_item.address, cfg.mem_err_shift);
start_item(resp_item);
`DV_CHECK_RANDOMIZE_FATAL(resp_item)
@ -116,7 +116,7 @@ class ibex_icache_mem_resp_seq extends ibex_icache_mem_base_seq;
// Using the seed that we saw for the request, check the memory model for a (non-PMP) error
// at this address. On success, look up the memory data too.
resp_item.is_grant = 1'b1;
resp_item.err = mem_model.is_mem_error(gnt_seed, req_item.address);
resp_item.err = mem_model.is_mem_error(gnt_seed, req_item.address, cfg.mem_err_shift);
resp_item.address = req_item.address;
resp_item.rdata = resp_item.err ? 'X : mem_model.read_data(gnt_seed, req_item.address);