Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[dv] Integrity error generation in memory busses #1811

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ci/vars.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# end up as float otherwise).
variables:
VERILATOR_VERSION: "v4.104"
IBEX_COSIM_VERSION: "0dc2de5d"
IBEX_COSIM_VERSION: "6272327d"
RISCV_TOOLCHAIN_TAR_VERSION: "20220210-1"
RISCV_TOOLCHAIN_TAR_VARIANT: "lowrisc-toolchain-gcc-rv32imcb"
RISCV_COMPLIANCE_GIT_VERSION: "844c6660ef3f0d9b96957991109dfd80cc4938e2"
Expand Down
6 changes: 6 additions & 0 deletions dv/cosim/cosim.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ class Cosim {
// When an NMI is due to be taken that will occur at the next call of `step`.
virtual void set_nmi(bool nmi) = 0;

// Set the state of the internal NMI (non-maskable interrupt) line.
// Behaviour wise this is almost as same as external NMI case explained at
// set_nmi method. Difference is that this one is a response from Ibex rather
// than an input.
virtual void set_nmi_int(bool nmi_int) = 0;

// Set the debug request.
//
// When set to true the core will enter debug mode at the next step
Expand Down
5 changes: 5 additions & 0 deletions dv/cosim/cosim_dpi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ void riscv_cosim_set_nmi(Cosim *cosim, svBit nmi) {
cosim->set_nmi(nmi);
}

void riscv_cosim_set_nmi_int(Cosim *cosim, svBit nmi_int) {
assert(cosim);

cosim->set_nmi_int(nmi_int);
}
void riscv_cosim_set_debug_req(Cosim *cosim, svBit debug_req) {
assert(cosim);

Expand Down
1 change: 1 addition & 0 deletions dv/cosim/cosim_dpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ int riscv_cosim_step(Cosim *cosim, const svBitVecVal *write_reg,
svBit sync_trap);
void riscv_cosim_set_mip(Cosim *cosim, const svBitVecVal *mip);
void riscv_cosim_set_nmi(Cosim *cosim, svBit nmi);
void riscv_cosim_set_nmi_int(Cosim *cosim, svBit nmi_int);
void riscv_cosim_set_debug_req(Cosim *cosim, svBit debug_req);
void riscv_cosim_set_mcycle(Cosim *cosim, svBitVecVal *mcycle);
void riscv_cosim_set_csr(Cosim *cosim, const int csr_id,
Expand Down
1 change: 1 addition & 0 deletions dv/cosim/cosim_dpi.svh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import "DPI-C" function int riscv_cosim_step(chandle cosim_handle, bit [4:0] wri
bit [31:0] write_reg_data, bit [31:0] pc, bit sync_trap);
import "DPI-C" function void riscv_cosim_set_mip(chandle cosim_handle, bit [31:0] mip);
import "DPI-C" function void riscv_cosim_set_nmi(chandle cosim_handle, bit nmi);
import "DPI-C" function void riscv_cosim_set_nmi_int(chandle cosim_handle, bit nmi_int);
import "DPI-C" function void riscv_cosim_set_debug_req(chandle cosim_handle, bit debug_req);
import "DPI-C" function void riscv_cosim_set_mcycle(chandle cosim_handle, bit [63:0] mcycle);
import "DPI-C" function void riscv_cosim_set_csr(chandle cosim_handle, int csr_id,
Expand Down
23 changes: 22 additions & 1 deletion dv/cosim/spike_cosim.cc
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,8 @@ bool SpikeCosim::step(uint32_t write_reg, uint32_t write_reg_data,

if (processor->get_state()->last_inst_pc == PC_INVALID) {
if (!(processor->get_state()->mcause->read() & 0x80000000) ||
processor->get_state()->debug_mode) { // (Async-Traps are disabled in debug mode)
processor->get_state()
->debug_mode) { // (Async-Traps are disabled in debug mode)
// Spike encountered a synchronous trap
pending_sync_exception = true;

Expand Down Expand Up @@ -358,6 +359,12 @@ bool SpikeCosim::check_sync_trap(uint32_t write_reg,
return false;
}

// If we see an internal NMI, that means we receive an extra memory intf item.
// Deleting that is necessary since next Load/Store would fail otherwise.
if (processor->get_state()->mcause->read() == 0xFFFFFFE0) {
pending_dside_accesses.erase(pending_dside_accesses.begin());
}

// Errors may have been generated outside of step() (e.g. in
// check_mem_access()), return false if there are any.
if (errors.size() != 0) {
Expand Down Expand Up @@ -480,6 +487,20 @@ void SpikeCosim::set_nmi(bool nmi) {
}
}

void SpikeCosim::set_nmi_int(bool nmi_int) {
if (nmi_int && !nmi_mode && !processor->get_state()->debug_mode) {
processor->get_state()->nmi_int = true;
nmi_mode = true;

// When NMI is set it is guaranteed NMI trap will be taken at the next step
// so save CSR state for recoverable NMI to mstack now.
mstack.mpp = get_field(processor->get_csr(CSR_MSTATUS), MSTATUS_MPP);
mstack.mpie = get_field(processor->get_csr(CSR_MSTATUS), MSTATUS_MPIE);
mstack.epc = processor->get_csr(CSR_MEPC);
mstack.cause = processor->get_csr(CSR_MCAUSE);
}
}

void SpikeCosim::set_debug_req(bool debug_req) {
processor->halt_request =
debug_req ? processor_t::HR_REGULAR : processor_t::HR_NONE;
Expand Down
1 change: 1 addition & 0 deletions dv/cosim/spike_cosim.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ class SpikeCosim : public simif_t, public Cosim {
uint32_t initial_spike_pc);
void set_mip(uint32_t mip) override;
void set_nmi(bool nmi) override;
void set_nmi_int(bool nmi_int) override;
void set_debug_req(bool debug_req) override;
void set_mcycle(uint64_t mcycle) override;
void set_csr(const int csr_num, const uint32_t new_val) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ class ibex_cosim_scoreboard extends uvm_scoreboard;
end

riscv_cosim_set_nmi(cosim_handle, rvfi_instr.nmi);
riscv_cosim_set_nmi_int(cosim_handle, rvfi_instr.nmi_int);
riscv_cosim_set_mip(cosim_handle, rvfi_instr.mip);
riscv_cosim_set_debug_req(cosim_handle, rvfi_instr.debug_req);
riscv_cosim_set_mcycle(cosim_handle, rvfi_instr.mcycle);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class ibex_rvfi_monitor extends uvm_monitor;
trans_collected.order = vif.monitor_cb.order;
trans_collected.mip = vif.monitor_cb.ext_mip;
trans_collected.nmi = vif.monitor_cb.ext_nmi;
trans_collected.nmi_int = vif.monitor_cb.ext_nmi_int;
trans_collected.debug_req = vif.monitor_cb.ext_debug_req;
trans_collected.mcycle = vif.monitor_cb.ext_mcycle;
trans_collected.ic_scr_key_valid = vif.monitor_cb.ext_ic_scr_key_valid;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class ibex_rvfi_seq_item extends uvm_sequence_item;
bit [63:0] order;
bit [31:0] mip;
bit nmi;
bit nmi_int;
bit debug_req;
bit [63:0] mcycle;

Expand All @@ -25,6 +26,7 @@ class ibex_rvfi_seq_item extends uvm_sequence_item;
`uvm_field_int (order, UVM_DEFAULT)
`uvm_field_int (mip, UVM_DEFAULT)
`uvm_field_int (nmi, UVM_DEFAULT)
`uvm_field_int (nmi_int, UVM_DEFAULT)
`uvm_field_int (debug_req, UVM_DEFAULT)
`uvm_field_int (mcycle, UVM_DEFAULT)
`uvm_field_sarray_int (mhpmcounters, UVM_DEFAULT)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class ibex_mem_intf_response_seq extends uvm_sequence #(ibex_mem_intf_seq_item);

ibex_mem_intf_seq_item item;
mem_model m_mem;
bit enable_intg_error = 1'b0;
bit enable_error = 1'b0;
// Used to ensure that whenever inject_error() is called, the very next transaction will inject an
// error, and that enable_error will not be flipped back to 0 immediately
Expand Down Expand Up @@ -60,6 +61,12 @@ class ibex_mem_intf_response_seq extends uvm_sequence #(ibex_mem_intf_seq_item);
enable_error = 1'b0;
error_synch = 1'b1;
aligned_addr = {req.addr[DATA_WIDTH-1:2], 2'b0};
// Do not inject any error to the handshake test_control_addr
// TODO: Parametrize this. Until then, this needs to be changed manually.
if (aligned_addr inside {32'h8ffffff8, 32'h8ffffffc}) begin
req.error = 1'b0;
enable_intg_error = 1'b0;
end
if (req.error) begin
`DV_CHECK_STD_RANDOMIZE_FATAL(rand_data)
req.data = rand_data;
Expand All @@ -85,7 +92,10 @@ class ibex_mem_intf_response_seq extends uvm_sequence #(ibex_mem_intf_seq_item);

// If data_was_uninitialized is true then we want to force bad integrity bits: invert the
// correct ones, which we know will break things for the codes we use.
if (data_was_uninitialized) req.intg = ~req.intg;
if (data_was_uninitialized || enable_intg_error) begin
req.intg = ~req.intg;
enable_intg_error = 1'b0;
end

`uvm_info(get_full_name(), $sformatf("Response transfer:\n%0s", req.sprint()), UVM_HIGH)
start_item(req);
Expand All @@ -106,6 +116,10 @@ class ibex_mem_intf_response_seq extends uvm_sequence #(ibex_mem_intf_seq_item);
this.enable_error = 1'b1;
endfunction

virtual function void inject_intg_error();
this.enable_intg_error = 1'b1;
endfunction

virtual function bit get_error_synch();
return this.error_synch;
endfunction
Expand Down
3 changes: 3 additions & 0 deletions dv/uvm/core_ibex/env/core_ibex_env_cfg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ 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_mem_intg_err;
bit enable_irq_single_seq;
bit enable_irq_multiple_seq;
bit enable_irq_nmi_seq;
Expand All @@ -31,6 +32,7 @@ class core_ibex_env_cfg extends uvm_object;
`uvm_object_utils_begin(core_ibex_env_cfg)
`uvm_field_int(enable_double_fault_detector, UVM_DEFAULT)
`uvm_field_int(is_double_fault_detected_fatal, UVM_DEFAULT)
`uvm_field_int(enable_mem_intg_err, 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)
Expand All @@ -48,6 +50,7 @@ class core_ibex_env_cfg extends uvm_object;
super.new(name);
void'($value$plusargs("enable_double_fault_detector=%0d", enable_double_fault_detector));
void'($value$plusargs("is_double_fault_detected_fatal=%0d", is_double_fault_detected_fatal));
void'($value$plusargs("enable_mem_intg_err=%0d", enable_mem_intg_err));
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));
Expand Down
2 changes: 2 additions & 0 deletions dv/uvm/core_ibex/env/core_ibex_rvfi_if.sv
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ interface core_ibex_rvfi_if(input logic clk);
logic [31:0] mem_wdata;
logic [31:0] ext_mip;
logic ext_nmi;
logic ext_nmi_int;
logic [31:0] ext_debug_req;
logic [63:0] ext_mcycle;

Expand Down Expand Up @@ -61,6 +62,7 @@ interface core_ibex_rvfi_if(input logic clk);
input mem_wdata;
input ext_mip;
input ext_nmi;
input ext_nmi_int;
input ext_debug_req;
input ext_mcycle;
input ext_mhpmcounters;
Expand Down
21 changes: 21 additions & 0 deletions dv/uvm/core_ibex/riscv_dv_extension/testlist.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,27 @@
+suppress_pmp_setup=1
rtl_test: core_ibex_mem_error_test
sim_opts: >
+enable_mem_intg_err=0
+enable_double_fault_detector=0
+require_signature_addr=1
compare_opts:
compare_final_value_only: 1

- test: riscv_mem_intg_error_test
description: >
Normal random instruction test, but randomly insert memory load/store integrity errors
iterations: 15
gen_test: riscv_rand_instr_test
gen_opts: >
+require_signature_addr=1
+instr_cnt=10000
+randomize_csr=1
+enable_unaligned_load_store=1
+suppress_pmp_setup=1
rtl_test: core_ibex_mem_error_test
sim_opts: >
+enable_mem_intg_err=1
+enable_double_fault_detector=0
+require_signature_addr=1
compare_opts:
compare_final_value_only: 1
Expand Down
6 changes: 4 additions & 2 deletions dv/uvm/core_ibex/tb/core_ibex_tb_top.sv
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,9 @@ module core_ibex_tb_top;
);

// We should never see any alerts triggered in normal testing
`ASSERT(NoAlertsTriggered,
`ASSERT(NoAlertsTriggered_A,
!dut_if.alert_minor && !dut_if.alert_major_internal && !dut_if.alert_major_bus, clk, !rst_n)
`DV_ASSERT_CTRL("NoAlertsTriggered", core_ibex_tb_top.NoAlertsTriggered_A)

// Data load/store vif connection
assign data_mem_vif.reset = ~rst_n;
Expand All @@ -184,13 +185,14 @@ module core_ibex_tb_top;
assign rvfi_if.rd_addr = dut.rvfi_rd_addr;
assign rvfi_if.rd_wdata = dut.rvfi_rd_wdata;
assign rvfi_if.pc_rdata = dut.rvfi_pc_rdata;
assign rvfi_if_pc_wdata = dut.rvfi_pc_wdata;
assign rvfi_if.pc_wdata = dut.rvfi_pc_wdata;
assign rvfi_if.mem_addr = dut.rvfi_mem_addr;
assign rvfi_if.mem_rmask = dut.rvfi_mem_rmask;
assign rvfi_if.mem_rdata = dut.rvfi_mem_rdata;
assign rvfi_if.mem_wdata = dut.rvfi_mem_wdata;
assign rvfi_if.ext_mip = dut.rvfi_ext_mip;
assign rvfi_if.ext_nmi = dut.rvfi_ext_nmi;
assign rvfi_if.ext_nmi_int = dut.rvfi_ext_nmi_int;
assign rvfi_if.ext_debug_req = dut.rvfi_ext_debug_req;
assign rvfi_if.ext_mcycle = dut.rvfi_ext_mcycle;
assign rvfi_if.ext_mhpmcounters = dut.rvfi_ext_mhpmcounters;
Expand Down
43 changes: 33 additions & 10 deletions dv/uvm/core_ibex/tests/core_ibex_new_seq_lib.sv
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ class core_base_new_seq #(type REQ = uvm_sequence_item) extends uvm_sequence #(R

`uvm_info(`gfn, $sformatf("Running the \"%s\" schedule for stimulus generation",
iteration_modes.name()), UVM_LOW)
stop_seq = 1'b0;
seq_finished = 1'b0;
case (iteration_modes)
SingleRun: begin
drive_stimulus();
Expand All @@ -72,6 +74,7 @@ class core_base_new_seq #(type REQ = uvm_sequence_item) extends uvm_sequence #(R
`DV_CHECK_FATAL(iteration_cnt != 0)
`uvm_info(`gfn, $sformatf("Number of stimulus iterations = %0d", iteration_cnt), UVM_LOW)
for (int i = 0; i <= iteration_cnt; i++) begin
`uvm_info(`gfn, $sformatf("Running %0d/%0d", i, iteration_cnt), UVM_LOW)
drive_stimulus();
end
end
Expand Down Expand Up @@ -198,45 +201,65 @@ class debug_new_seq extends core_base_new_seq#(irq_seq_item);

endclass

class memory_error_seq extends core_base_new_seq#(irq_seq_item);
class memory_error_seq extends core_base_new_seq#(ibex_mem_intf_seq_item);
core_ibex_vseq vseq;
rand bit choose_side;
bit start_seq = 0; // Use this bit to start any unique sequence once

rand error_type_e err_type = PickErr;
rand bit inject_intg_err;
// CONTROL_KNOB: Configure the rate between seeing an integrity error versus seeing a bus error.
int unsigned intg_err_pct = 50;
constraint inject_intg_err_c {
inject_intg_err dist {1 :/ intg_err_pct,
0 :/ 100 - intg_err_pct};
}

`uvm_object_utils(memory_error_seq)
`uvm_declare_p_sequencer(core_ibex_vseqr)

function new (string name = "");
super.new(name);
vseq = core_ibex_vseq::type_id::create("vseq");
endfunction

virtual task send_req();
case (err_type)
IsideErr: begin
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(inject_intg_err)
// If we expect to see only bus errors, we can enable this assertion. Otherwise
// integrity errors would cause alerts to trigger.
`DV_ASSERT_CTRL_REQ("NoAlertsTriggered", intg_err_pct == 0)
case ({err_type, inject_intg_err})
{IsideErr, 1'b0}: begin
vseq.instr_intf_seq.inject_error();
end
DsideErr: begin
{DsideErr, 1'b0}: begin
vseq.data_intf_seq.inject_error();
end
PickErr: begin
{PickErr, 1'b0}: begin
`DV_CHECK_STD_RANDOMIZE_FATAL(choose_side)
if (choose_side) begin
vseq.instr_intf_seq.inject_error();
end else begin
vseq.data_intf_seq.inject_error();
end
end
{IsideErr, 1'b1}: begin
vseq.instr_intf_seq.inject_intg_error();
end
{DsideErr, 1'b1}: begin
vseq.data_intf_seq.inject_intg_error();
end
{PickErr, 1'b1}: begin
`DV_CHECK_STD_RANDOMIZE_FATAL(choose_side)
if (choose_side) begin
vseq.instr_intf_seq.inject_intg_error();
end else begin
vseq.data_intf_seq.inject_intg_error();
end
end
default: begin
// DO nothing
end
endcase
if(!start_seq) begin
vseq.start(p_sequencer);
start_seq = 1;
end
endtask

endclass: memory_error_seq
Expand Down
Loading