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:
Rupert Swarbrick 2020-06-17 16:42:23 +01:00 committed by Rupert Swarbrick
parent 962fc8020c
commit 96cf24a41a
10 changed files with 127 additions and 21 deletions

View file

@ -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"]
}
]
}

View file

@ -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:

View file

@ -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

View file

@ -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

View 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

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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"]
}
]
}