mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 12:57:13 -04:00
Add a stress_all_with_reset ICache test
This is like the stress_all test, picking other sequences at random and running them back-to-back. The difference is in the reset behaviour, where we randomly pull the reset line at unexpected times to try to trigger any strange glitches this might cause. This requires slight changes to the core and memory drivers, which need to learn to stop and return early from the current item when they see a reset.
This commit is contained in:
parent
962fc8020c
commit
96cf24a41a
10 changed files with 127 additions and 21 deletions
|
@ -138,7 +138,7 @@
|
|||
Tests are selected from the sequences above. Add occasional
|
||||
resets (in the middle of sequences)'''
|
||||
milestone: V2
|
||||
tests: []
|
||||
tests: ["ibex_icache_stress_all_with_reset"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
1
dv/uvm/icache/dv/env/ibex_icache_env.core
vendored
1
dv/uvm/icache/dv/env/ibex_icache_env.core
vendored
|
@ -28,6 +28,7 @@ filesets:
|
|||
- seq_lib/ibex_icache_many_errors_vseq.sv: {is_include_file: true}
|
||||
- seq_lib/ibex_icache_ecc_vseq.sv: {is_include_file: true}
|
||||
- seq_lib/ibex_icache_combo_vseq.sv: {is_include_file: true}
|
||||
- seq_lib/ibex_icache_reset_vseq.sv: {is_include_file: true}
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
|
|
4
dv/uvm/icache/dv/env/ibex_icache_env.sv
vendored
4
dv/uvm/icache/dv/env/ibex_icache_env.sv
vendored
|
@ -113,8 +113,8 @@ class ibex_icache_env extends dv_base_env #(
|
|||
// is triggered.
|
||||
heartbeat.start(hb_event);
|
||||
forever begin
|
||||
// Every 2000 clocks, check the heartbeat monitor
|
||||
cfg.core_agent_cfg.vif.wait_clks(2000);
|
||||
// Every 2000 clocks, check the heartbeat monitor (not stopping early on reset)
|
||||
cfg.core_agent_cfg.vif.wait_clks(2000, 1'b0);
|
||||
hb_event.trigger();
|
||||
end
|
||||
endtask
|
||||
|
|
|
@ -27,6 +27,10 @@ class ibex_icache_combo_vseq
|
|||
"ibex_icache_many_errors_vseq",
|
||||
"ibex_icache_passthru_vseq"};
|
||||
|
||||
// If this is set, occasionally reset the DUT and start a new sequence at a time that the core
|
||||
// sequence wouldn't normally expect.
|
||||
bit random_reset = 1'b0;
|
||||
|
||||
// How many sequences have we executed so far?
|
||||
int unsigned seqs_so_far = 0;
|
||||
|
||||
|
@ -53,7 +57,13 @@ class ibex_icache_combo_vseq
|
|||
// little.
|
||||
trans_now = $urandom_range(50, 100);
|
||||
|
||||
should_reset = $urandom_range(0, 1);
|
||||
// We don't need to reset if seq_idx == 0 (because we did a reset before starting this task).
|
||||
// Otherwise, we always reset between sequences if random_reset is true. We'd always need to
|
||||
// if we killed the previous sequence, and it's easier not to bother tracking properly. If
|
||||
// random_reset is false (the usual back-to-back sequence test), we reset 1 time in 2.
|
||||
if (seq_idx == 0) should_reset = 1'b0;
|
||||
else if (random_reset) should_reset = 1'b1;
|
||||
else should_reset = $urandom_range(0, 1);
|
||||
|
||||
`uvm_info(`gfn,
|
||||
$sformatf("Running sequence '%s' (%0d transactions; reset=%0d).",
|
||||
|
@ -70,7 +80,15 @@ class ibex_icache_combo_vseq
|
|||
child_seq.do_dut_init = should_reset;
|
||||
child_seq.prev_sequence = prev_seq;
|
||||
|
||||
child_seq.start(p_sequencer, this);
|
||||
// The memory agent is careful to avoid consuming requests from its sequencer's request_fifo
|
||||
// until it has handled them. This is important if we're not resetting (it essentially allows
|
||||
// the sequence to change under the feet of the rest of the environment without it noticing),
|
||||
// but we need to make sure we discard any pending requests on an actual reset. Do that here.
|
||||
if (should_reset && seqs_so_far > 0) begin
|
||||
p_sequencer.mem_sequencer_h.request_fifo.flush();
|
||||
end
|
||||
|
||||
run_sequence();
|
||||
|
||||
prev_seq = child_seq;
|
||||
trans_so_far += trans_now;
|
||||
|
@ -78,4 +96,33 @@ class ibex_icache_combo_vseq
|
|||
end
|
||||
endtask : body
|
||||
|
||||
// Run a sequence. If random_reset = 0, this will run to completion. Otherwise, the sequence may
|
||||
// be stopped early.
|
||||
protected task run_sequence();
|
||||
int unsigned cycles_till_reset;
|
||||
bit reached_timeout = 1'b0;
|
||||
|
||||
if (!random_reset) begin
|
||||
child_seq.start(p_sequencer, this);
|
||||
end else begin
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(cycles_till_reset,
|
||||
cycles_till_reset dist {
|
||||
[100:500] :/ 1,
|
||||
[501:1000] :/ 4
|
||||
};)
|
||||
fork
|
||||
child_seq.start(p_sequencer, this);
|
||||
begin
|
||||
repeat (cycles_till_reset) @(cfg.clk_rst_vif.cb);
|
||||
reached_timeout = 1'b1;
|
||||
end
|
||||
join_any
|
||||
end
|
||||
|
||||
if (reached_timeout) child_seq.kill();
|
||||
|
||||
// Kill the timer process if it's still going.
|
||||
disable fork;
|
||||
endtask : run_sequence
|
||||
|
||||
endclass : ibex_icache_combo_vseq
|
||||
|
|
20
dv/uvm/icache/dv/env/seq_lib/ibex_icache_reset_vseq.sv
vendored
Normal file
20
dv/uvm/icache/dv/env/seq_lib/ibex_icache_reset_vseq.sv
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// A version of the combination vseq that injects resets at unexpected times.
|
||||
|
||||
class ibex_icache_reset_vseq extends ibex_icache_combo_vseq;
|
||||
|
||||
`uvm_object_utils(ibex_icache_reset_vseq)
|
||||
`uvm_object_new
|
||||
|
||||
task pre_do (bit is_item);
|
||||
super.pre_do(is_item);
|
||||
|
||||
// Enable "random reset" functionality, which resets the DUT (and starts a new sequence) at
|
||||
// random times.
|
||||
random_reset = 1'b1;
|
||||
endtask : pre_do
|
||||
|
||||
endclass : ibex_icache_reset_vseq
|
|
@ -11,3 +11,4 @@
|
|||
`include "ibex_icache_many_errors_vseq.sv"
|
||||
`include "ibex_icache_ecc_vseq.sv"
|
||||
`include "ibex_icache_combo_vseq.sv"
|
||||
`include "ibex_icache_reset_vseq.sv"
|
||||
|
|
|
@ -108,7 +108,8 @@ class ibex_icache_core_driver
|
|||
cfg.vif.driver_cb.enable <= req.enable;
|
||||
|
||||
// Lower req, invalidate and set new seed immediately. After req_low_cycles cycles, start
|
||||
// reading instructions. Wiggle the branch_spec line the whole time.
|
||||
// reading instructions (providing there hasn't been a reset). Wiggle the branch_spec line the
|
||||
// whole time.
|
||||
fork
|
||||
begin
|
||||
fork
|
||||
|
@ -116,7 +117,7 @@ class ibex_icache_core_driver
|
|||
if (req.invalidate) invalidate();
|
||||
if (req.new_seed != 0) drive_new_seed(req.new_seed);
|
||||
join
|
||||
read_insns(rsp, req.num_insns);
|
||||
if (cfg.vif.rst_n) read_insns(rsp, req.num_insns);
|
||||
end
|
||||
drive_branch_spec();
|
||||
join_any
|
||||
|
@ -136,6 +137,8 @@ class ibex_icache_core_driver
|
|||
rsp.saw_error = 1'b1;
|
||||
break;
|
||||
end
|
||||
// Return early on reset
|
||||
if (!cfg.vif.rst_n) break;
|
||||
end
|
||||
endtask
|
||||
|
||||
|
@ -151,30 +154,34 @@ class ibex_icache_core_driver
|
|||
virtual task automatic read_insn();
|
||||
int unsigned delay;
|
||||
|
||||
// Maybe (1 time in 10) wait for a valid signal before even considering asserting ready.
|
||||
if ($urandom_range(9) == 0)
|
||||
wait (cfg.vif.driver_cb.valid);
|
||||
// Maybe (1 time in 10) wait for a valid signal before even considering asserting ready. Stops
|
||||
// early on reset.
|
||||
if ($urandom_range(9) == 0) begin
|
||||
cfg.vif.wait_valid();
|
||||
if (!cfg.vif.rst_n)
|
||||
return;
|
||||
end
|
||||
|
||||
// Then pick how long we wait before asserting that we are ready.
|
||||
//
|
||||
// TODO: Make this configurable and weight 0 more heavily.
|
||||
cfg.vif.wait_clks($urandom_range(3));
|
||||
|
||||
// Assert ready and then wait until valid
|
||||
// Assert ready and then wait until valid. If we see a reset, we stop early
|
||||
cfg.vif.driver_cb.ready <= 1'b1;
|
||||
while (1'b1) begin
|
||||
@(cfg.vif.driver_cb);
|
||||
if (cfg.vif.driver_cb.valid)
|
||||
@(cfg.vif.driver_cb or negedge cfg.vif.rst_n);
|
||||
if (cfg.vif.driver_cb.valid || !cfg.vif.rst_n)
|
||||
break;
|
||||
end
|
||||
|
||||
cfg.vif.driver_cb.ready <= 1'b0;
|
||||
endtask
|
||||
|
||||
// Lower the req line for the given number of cycles
|
||||
// Lower the req line for the given number of cycles. Returns early on reset
|
||||
virtual task automatic lower_req(int unsigned num_cycles);
|
||||
cfg.vif.driver_cb.req <= 1'b0;
|
||||
repeat (num_cycles) @(cfg.vif.driver_cb);
|
||||
cfg.vif.wait_clks(num_cycles);
|
||||
cfg.vif.driver_cb.req <= 1'b1;
|
||||
endtask
|
||||
|
||||
|
|
|
@ -95,9 +95,28 @@ interface ibex_icache_core_if (input clk, input rst_n);
|
|||
driver_cb.invalidate <= 1'b0;
|
||||
endtask
|
||||
|
||||
// A task that waits for num_clks posedges on the clk signal
|
||||
task automatic wait_clks(int num_clks);
|
||||
repeat (num_clks) @(driver_cb);
|
||||
// A task that waits for num_clks posedges on the clk signal. Returns early on reset if
|
||||
// stop_on_reset is true.
|
||||
task automatic wait_clks(int num_clks, bit stop_on_reset = 1'b1);
|
||||
if (stop_on_reset && !rst_n) return;
|
||||
if (stop_on_reset) begin
|
||||
fork
|
||||
repeat (num_clks) @(driver_cb);
|
||||
@(negedge rst_n);
|
||||
join_any
|
||||
disable fork;
|
||||
end else begin
|
||||
repeat (num_clks) @(driver_cb);
|
||||
end
|
||||
endtask
|
||||
|
||||
// Wait until the valid signal goes high. Returns early on reset
|
||||
task automatic wait_valid();
|
||||
fork
|
||||
@(negedge rst_n);
|
||||
wait (driver_cb.valid);
|
||||
join_any
|
||||
disable fork;
|
||||
endtask
|
||||
|
||||
// Reset all the signals from the core to the cache (the other direction is controlled by the
|
||||
|
|
|
@ -55,9 +55,14 @@ interface ibex_icache_mem_if (input clk,
|
|||
driver_cb.gnt <= 1'b0;
|
||||
endtask
|
||||
|
||||
// Wait for num_clks posedges on the clk signal
|
||||
// Wait for num_clks posedges on the clk signal. Returns early on a reset.
|
||||
task automatic wait_clks(int num_clks);
|
||||
repeat (num_clks) @(driver_cb);
|
||||
if (!rst_n) return;
|
||||
fork
|
||||
repeat (num_clks) @(driver_cb);
|
||||
@(negedge rst_n);
|
||||
join_any
|
||||
disable fork;
|
||||
endtask
|
||||
|
||||
// Drive a response with the given rdata and possible error signals for a single cycle
|
||||
|
|
|
@ -101,6 +101,11 @@
|
|||
name: ibex_icache_stress_all
|
||||
uvm_test_seq: ibex_icache_combo_vseq
|
||||
}
|
||||
|
||||
{
|
||||
name: ibex_icache_stress_all_with_reset
|
||||
uvm_test_seq: ibex_icache_reset_vseq
|
||||
}
|
||||
]
|
||||
|
||||
// List of regressions.
|
||||
|
@ -114,7 +119,8 @@
|
|||
"ibex_icache_back_line",
|
||||
"ibex_icache_many_errors",
|
||||
"ibex_icache_ecc",
|
||||
"ibex_icache_stress_all"]
|
||||
"ibex_icache_stress_all",
|
||||
"ibex_icache_stress_all_with_reset"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue