mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 04:47:25 -04:00
Add a double_fault detector to core_ibex uvm environment
Add a new scoreboard component to the core_ibex uvm environment, which contains a double_fault detector task. This uses the top-level output 'double_fault_seen_o' to count the number of total and consecutive double_faults seen with a test. A helper task allows the base_test to wait upon each of these counters reaching the configured thresholds, and then to end the test early with a passing result. The default thresholds are 100 for consecutive faults, and 1000 for total faults. The double_fault detector is disabled by default. A plusarg '+enable_double_fault_detector=1' enables the checker. This commit enables it for only the 'pmp_full_random_test', as that is a useful test candidate to begin with.
This commit is contained in:
parent
083fe2a54f
commit
b214fa1c72
8 changed files with 167 additions and 16 deletions
|
@ -20,6 +20,7 @@ interface core_ibex_dut_probe_if(input logic clk);
|
|||
ibex_pkg::priv_lvl_e priv_mode;
|
||||
ibex_pkg::ctrl_fsm_e ctrl_fsm_cs;
|
||||
logic debug_mode;
|
||||
logic double_fault_seen;
|
||||
|
||||
clocking dut_cb @(posedge clk);
|
||||
output fetch_enable;
|
||||
|
@ -38,6 +39,7 @@ interface core_ibex_dut_probe_if(input logic clk);
|
|||
input priv_mode;
|
||||
input ctrl_fsm_cs;
|
||||
input debug_mode;
|
||||
input double_fault_seen;
|
||||
endclocking
|
||||
|
||||
initial begin
|
||||
|
|
15
dv/uvm/core_ibex/env/core_ibex_env.sv
vendored
15
dv/uvm/core_ibex/env/core_ibex_env.sv
vendored
|
@ -14,6 +14,7 @@ class core_ibex_env extends uvm_env;
|
|||
core_ibex_vseqr vseqr;
|
||||
core_ibex_env_cfg cfg;
|
||||
scrambling_key_agent scrambling_key_agent_h;
|
||||
core_ibex_scoreboard scoreboard;
|
||||
|
||||
`uvm_component_utils(core_ibex_env)
|
||||
`uvm_component_new
|
||||
|
@ -23,6 +24,14 @@ class core_ibex_env extends uvm_env;
|
|||
if (!uvm_config_db#(core_ibex_env_cfg)::get(this, "", "cfg", cfg)) begin
|
||||
`uvm_fatal(get_full_name(), "Cannot get cfg")
|
||||
end
|
||||
if (!uvm_config_db#(virtual clk_rst_if)::get(this, "", "clk_if",
|
||||
cfg.ibex_clk_vif)) begin
|
||||
`uvm_fatal(`gfn, "failed to get ibex clk_if from uvm_config_db")
|
||||
end
|
||||
if (!uvm_config_db#(virtual core_ibex_dut_probe_if)::get(this, "", "dut_if",
|
||||
cfg.ibex_dut_vif)) begin
|
||||
`uvm_fatal(`gfn, "failed to get ibex dut_if from uvm_config_db")
|
||||
end
|
||||
data_if_response_agent = ibex_mem_intf_response_agent::type_id::
|
||||
create("data_if_response_agent", this);
|
||||
instr_if_response_agent = ibex_mem_intf_response_agent::type_id::
|
||||
|
@ -37,6 +46,8 @@ class core_ibex_env extends uvm_env;
|
|||
cfg.scrambling_key_cfg.if_mode = dv_utils_pkg::Device;
|
||||
// Create virtual sequencer
|
||||
vseqr = core_ibex_vseqr::type_id::create("vseqr", this);
|
||||
// Create scoreboard
|
||||
scoreboard = core_ibex_scoreboard::type_id::create("scoreboard", this);
|
||||
endfunction : build_phase
|
||||
|
||||
function void connect_phase(uvm_phase phase);
|
||||
|
@ -48,6 +59,10 @@ class core_ibex_env extends uvm_env;
|
|||
cosim_agent.dmem_port);
|
||||
instr_if_response_agent.monitor.item_collected_port.connect(
|
||||
cosim_agent.imem_port);
|
||||
if (cfg.enable_double_fault_detector) begin
|
||||
cosim_agent.rvfi_monitor.item_collected_port.connect(
|
||||
scoreboard.rvfi_port.analysis_export);
|
||||
end
|
||||
endfunction : connect_phase
|
||||
|
||||
function void reset();
|
||||
|
|
10
dv/uvm/core_ibex/env/core_ibex_env_cfg.sv
vendored
10
dv/uvm/core_ibex/env/core_ibex_env_cfg.sv
vendored
|
@ -4,6 +4,9 @@
|
|||
|
||||
class core_ibex_env_cfg extends uvm_object;
|
||||
|
||||
virtual clk_rst_if ibex_clk_vif;
|
||||
virtual core_ibex_dut_probe_if ibex_dut_vif;
|
||||
|
||||
bit enable_irq_single_seq;
|
||||
bit enable_irq_multiple_seq;
|
||||
bit enable_irq_nmi_seq;
|
||||
|
@ -17,7 +20,13 @@ class core_ibex_env_cfg extends uvm_object;
|
|||
bit[31:0] signature_addr;
|
||||
rand scrambling_key_agent_cfg scrambling_key_cfg;
|
||||
|
||||
// Double-Fault detection in scoreboard
|
||||
bit enable_double_fault_detector = 0;
|
||||
int unsigned double_fault_threshold_consecutive = 100;
|
||||
int unsigned double_fault_threshold_total = 1000;
|
||||
|
||||
`uvm_object_utils_begin(core_ibex_env_cfg)
|
||||
`uvm_field_int(enable_double_fault_detector, UVM_DEFAULT)
|
||||
`uvm_field_int(enable_irq_single_seq, UVM_DEFAULT)
|
||||
`uvm_field_int(enable_irq_multiple_seq, UVM_DEFAULT)
|
||||
`uvm_field_int(enable_irq_nmi_seq, UVM_DEFAULT)
|
||||
|
@ -33,6 +42,7 @@ class core_ibex_env_cfg extends uvm_object;
|
|||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
void'($value$plusargs("enable_double_fault_detector=%0d", enable_double_fault_detector));
|
||||
void'($value$plusargs("enable_irq_single_seq=%0d", enable_irq_single_seq));
|
||||
void'($value$plusargs("enable_irq_multiple_seq=%0d", enable_irq_multiple_seq));
|
||||
void'($value$plusargs("enable_irq_nmi_seq=%0d", enable_irq_nmi_seq));
|
||||
|
|
1
dv/uvm/core_ibex/env/core_ibex_env_pkg.sv
vendored
1
dv/uvm/core_ibex/env/core_ibex_env_pkg.sv
vendored
|
@ -23,6 +23,7 @@ package core_ibex_env_pkg;
|
|||
|
||||
`include "core_ibex_vseqr.sv"
|
||||
`include "core_ibex_env_cfg.sv"
|
||||
`include "core_ibex_scoreboard.sv"
|
||||
`include "core_ibex_env.sv"
|
||||
|
||||
endpackage
|
||||
|
|
108
dv/uvm/core_ibex/env/core_ibex_scoreboard.sv
vendored
Normal file
108
dv/uvm/core_ibex/env/core_ibex_scoreboard.sv
vendored
Normal file
|
@ -0,0 +1,108 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
class core_ibex_scoreboard extends uvm_scoreboard;
|
||||
|
||||
uvm_tlm_analysis_fifo #(ibex_rvfi_seq_item) rvfi_port;
|
||||
core_ibex_env_cfg cfg;
|
||||
|
||||
// Events for Double-Fault detection
|
||||
uvm_event fault_threshold_consecutive_reached, fault_threshold_total_reached;
|
||||
|
||||
`uvm_component_utils(core_ibex_scoreboard)
|
||||
`uvm_component_new
|
||||
|
||||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
if (!uvm_config_db#(core_ibex_env_cfg)::get(this, "", "cfg", cfg)) begin
|
||||
`uvm_fatal(get_full_name(), "Cannot get cfg")
|
||||
end
|
||||
rvfi_port = new("rvfi_port_scoreboard", this);
|
||||
endfunction : build_phase
|
||||
|
||||
task run_phase(uvm_phase phase);
|
||||
super.run_phase(phase);
|
||||
fork
|
||||
double_fault_detector();
|
||||
join_none
|
||||
endtask
|
||||
|
||||
task double_fault_detector();
|
||||
int unsigned double_fault_cnt_total = 0;
|
||||
int unsigned double_fault_cnt_consecutive = 0;
|
||||
bit double_fault_pulse_seen = 1'b0;
|
||||
|
||||
ibex_rvfi_seq_item rvfi_instr;
|
||||
|
||||
fault_threshold_consecutive_reached = new();
|
||||
fault_threshold_total_reached = new();
|
||||
|
||||
// There are two observable side-effects of a double fault in the Ibex:
|
||||
// - CPUCTRL.double_fault_seen is set to '1
|
||||
// - The top-level output double_fault_seen_o is asserted for one cycle
|
||||
|
||||
fork
|
||||
// Increment a counter whenever a double_fault was indicated for the last
|
||||
// rvfi_seq_item created. When the counter reaches a threshold, create an event.
|
||||
begin
|
||||
forever begin
|
||||
rvfi_port.get(rvfi_instr);
|
||||
if (double_fault_pulse_seen) begin
|
||||
// There must have been a double_fault during the previous retired insn.
|
||||
double_fault_pulse_seen = 1'b0;
|
||||
double_fault_cnt_total++;
|
||||
double_fault_cnt_consecutive++;
|
||||
end else begin
|
||||
// Reset the consecutive counter.
|
||||
double_fault_cnt_consecutive = 0;
|
||||
end
|
||||
|
||||
|
||||
// Create an event if either counter reaches its threshold value, then reset the counter.
|
||||
if (double_fault_cnt_consecutive == cfg.double_fault_threshold_consecutive) begin
|
||||
fault_threshold_consecutive_reached.trigger();
|
||||
double_fault_cnt_consecutive = 0;
|
||||
end
|
||||
if (double_fault_cnt_total == cfg.double_fault_threshold_total) begin
|
||||
fault_threshold_total_reached.trigger();
|
||||
double_fault_cnt_total = 0;
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
// Latch a signal to show that we have seen a double_fault.
|
||||
// The pulse may be receieved sometime before the rvfi_seq_item.
|
||||
begin
|
||||
forever begin
|
||||
@(posedge cfg.ibex_dut_vif.double_fault_seen);
|
||||
double_fault_pulse_seen = 1'b1;
|
||||
cfg.ibex_clk_vif.wait_clks(1);
|
||||
end
|
||||
end
|
||||
join_none
|
||||
|
||||
endtask // double_fault_detector
|
||||
|
||||
// Helper method which returns if either of the counter thresholds are reached.
|
||||
virtual task dfd_wait_for_pass_events();
|
||||
fork
|
||||
begin
|
||||
fault_threshold_total_reached.wait_trigger();
|
||||
`uvm_info(`gfn,
|
||||
$sformatf({"double_fault detector : reached threshold [%0d] ",
|
||||
"for total double faults seen."}, cfg.double_fault_threshold_total),
|
||||
UVM_LOW)
|
||||
end
|
||||
begin
|
||||
fault_threshold_consecutive_reached.wait_trigger();
|
||||
`uvm_info(`gfn,
|
||||
$sformatf({"double_fault detector : reached threshold [%0d] ",
|
||||
"for consecutive double faults seen."}, cfg.double_fault_threshold_consecutive),
|
||||
UVM_LOW)
|
||||
end
|
||||
join_any
|
||||
disable fork;
|
||||
endtask
|
||||
|
||||
endclass
|
|
@ -744,7 +744,9 @@
|
|||
+instr_cnt=6000
|
||||
+pmp_max_offset=00024000
|
||||
+pmp_randomize=1
|
||||
+pmp_allow_addr_overlap=1
|
||||
+pmp_allow_illegal_tor=1
|
||||
sim_opts: >
|
||||
+enable_double_fault_detector=1
|
||||
rtl_test: core_ibex_base_test
|
||||
rtl_params:
|
||||
PMPEnable: 1
|
||||
|
|
|
@ -148,7 +148,7 @@ module core_ibex_tb_top;
|
|||
|
||||
.debug_req_i (dut_if.debug_req ),
|
||||
.crash_dump_o ( ),
|
||||
.double_fault_seen_o ( ),
|
||||
.double_fault_seen_o (dut_if.double_fault_seen ),
|
||||
|
||||
.fetch_enable_i (dut_if.fetch_enable ),
|
||||
.alert_minor_o (dut_if.alert_minor ),
|
||||
|
|
|
@ -211,38 +211,51 @@ class core_ibex_base_test extends uvm_test;
|
|||
end
|
||||
endfunction
|
||||
|
||||
// Use a RISCV_DV handshake signature to end the test.
|
||||
// This process uses a different signature address (cfg.signature_addr - 0x4)
|
||||
// Watch for all of the different critera for test pass/failure here
|
||||
virtual task wait_for_test_done();
|
||||
bit result;
|
||||
|
||||
// Make use of the 'test_done_port' which subscribes to all memory interface items.
|
||||
// We can then watch for the correct message in isolation.
|
||||
fork
|
||||
// - Use a RISCV_DV handshake signature to end the test.
|
||||
// This process uses a different signature address (cfg.signature_addr - 0x4)
|
||||
// Make use of the 'test_done_port' which subscribes to all memory interface items.
|
||||
// We can then watch for the correct message in isolation.
|
||||
begin
|
||||
wait_for_mem_txn((cfg.signature_addr - 4'h4), TEST_RESULT, test_done_port);
|
||||
result = signature_data_q.pop_front();
|
||||
if (result == TEST_PASS) begin
|
||||
test_done = 1'b1;
|
||||
`uvm_info(`gfn, "Test PASSED!", UVM_LOW)
|
||||
vseq.stop();
|
||||
check_perf_stats();
|
||||
// De-assert fetch enable to finish the test
|
||||
clk_vif.wait_clks(10);
|
||||
dut_vif.dut_cb.fetch_enable <= ibex_pkg::FetchEnableOff;
|
||||
// Wait some time for the remaining instruction to finish
|
||||
clk_vif.wait_clks(3000);
|
||||
`uvm_info(`gfn, "Test done due to RISCV-DV handshake (payload=TEST_PASS)", UVM_LOW)
|
||||
end else if (result == TEST_FAIL) begin
|
||||
`uvm_fatal(`gfn, "Test FAILED!")
|
||||
`uvm_fatal(`gfn, "Test failed due to RISCV-DV handshake (payload=TEST_FAIL)")
|
||||
end else begin
|
||||
`uvm_fatal(`gfn, "Incorrectly formed handshake received at test-control address.")
|
||||
end
|
||||
end
|
||||
// - End the test if we see too many of the following...
|
||||
// - double_faults
|
||||
begin
|
||||
if (cfg.enable_double_fault_detector) begin
|
||||
env.scoreboard.dfd_wait_for_pass_events();
|
||||
`uvm_info(`gfn, "Test done due to double_fault detector.", UVM_LOW)
|
||||
end else begin
|
||||
wait (test_done == 1'b1);
|
||||
end
|
||||
end
|
||||
// - End the test by timeout if it doesn't terminate within a reasonable time.
|
||||
begin
|
||||
clk_vif.wait_clks(timeout_in_cycles);
|
||||
`uvm_fatal(`gfn, "TEST TIMEOUT!!")
|
||||
end
|
||||
join_any
|
||||
|
||||
test_done = 1'b1;
|
||||
vseq.stop();
|
||||
check_perf_stats();
|
||||
// De-assert fetch enable to finish the test
|
||||
clk_vif.wait_clks(10);
|
||||
dut_vif.dut_cb.fetch_enable <= ibex_pkg::FetchEnableOff;
|
||||
// Wait some time for the remaining instruction to finish
|
||||
clk_vif.wait_clks(3000);
|
||||
endtask
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue