[dv] Add integrity test for passthru mem
Addressed #9546
For detail sequences, please refer to the added testplan
Signed-off-by: Weicai Yang <weicai@google.com>
diff --git a/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq.sv b/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq.sv
index 49fe26c..e96d17a 100644
--- a/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq.sv
+++ b/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq.sv
@@ -35,6 +35,9 @@
// knobs to lock shadow register write access if fatal storage error occurred
bit do_lock_shadow_reg = 1'b1;
+ // knob to enable/disable running csr_vseq with passthru_mem_tl_intg_err
+ bit en_csr_vseq_w_passthru_mem_intg = 1;
+
// csr queues
dv_base_reg all_csrs[$];
dv_base_reg intr_state_csrs[$];
@@ -212,15 +215,16 @@
input tl_intg_err_e tl_intg_err_type = TlIntgErrNone,
input int req_abort_pct = 0);
+ cip_tl_seq_item rsp;
if (blocking) begin
- tl_access_sub(addr, write, data, completed, saw_err, mask, check_rsp, exp_err_rsp, exp_data,
- compare_mask, check_exp_data, req_abort_pct, instr_type, tl_sequencer_h,
- tl_intg_err_type);
+ tl_access_sub(addr, write, data, completed, saw_err, rsp, mask, check_rsp,
+ exp_err_rsp, exp_data, compare_mask, check_exp_data, req_abort_pct,
+ instr_type, tl_sequencer_h, tl_intg_err_type);
end else begin
fork
- tl_access_sub(addr, write, data, completed, saw_err, mask, check_rsp, exp_err_rsp, exp_data,
- compare_mask, check_exp_data, req_abort_pct, instr_type, tl_sequencer_h,
- tl_intg_err_type);
+ tl_access_sub(addr, write, data, completed, saw_err, rsp, mask, check_rsp,
+ exp_err_rsp, exp_data, compare_mask, check_exp_data, req_abort_pct,
+ instr_type, tl_sequencer_h, tl_intg_err_type);
join_none
// Add #0 to ensure that this thread starts executing before any subsequent call
#0;
@@ -232,6 +236,7 @@
inout bit [BUS_DW-1:0] data,
output bit completed,
output bit saw_err,
+ output cip_tl_seq_item rsp,
input bit [BUS_DBW-1:0] mask = '1,
input bit check_rsp = 1'b1,
input bit exp_err_rsp = 1'b0,
@@ -260,8 +265,10 @@
mask == local::mask;
data == local::data;)
`uvm_send_pri(tl_seq, 100)
+ rsp = tl_seq.rsp;
+
if (!write) begin
- data = tl_seq.rsp.d_data;
+ data = rsp.d_data;
if (check_exp_data && !cfg.under_reset) begin
bit [BUS_DW-1:0] masked_data = data & compare_mask;
exp_data &= compare_mask;
@@ -269,13 +276,14 @@
end
end
if (check_rsp && !cfg.under_reset && tl_intg_err_type == TlIntgErrNone) begin
- `DV_CHECK_EQ(tl_seq.rsp.d_error, exp_err_rsp, "unexpected error response")
+ `DV_CHECK_EQ(rsp.d_error, exp_err_rsp, "unexpected error response")
end
+
// Expose whether the transaction ran and whether it generated an error. Note that we
// probably only want to do a RAL update if it ran and caused no error.
- completed = tl_seq.rsp.rsp_completed;
- saw_err = tl_seq.rsp.d_error;
+ completed = rsp.rsp_completed;
+ saw_err = rsp.d_error;
csr_utils_pkg::decrement_outstanding_access();,
// thread to check timeout
@@ -393,6 +401,7 @@
// Each iteration only sends 1 item with TL integrity error. Increase to send at least
// 10 x num_times integrity errors
"tl_intg_err": run_tl_intg_err_vseq(10 * num_times);
+ "passthru_mem_tl_intg_err": run_passthru_mem_tl_intg_err_vseq(10 * num_times);
"stress_all_with_rand_reset": run_plusarg_vseq_with_rand_reset(num_times);
"same_csr_outstanding": run_same_csr_outstanding_vseq(num_times);
"shadow_reg_errors": run_shadow_reg_errors(num_times);
diff --git a/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq__tl_errors.svh b/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq__tl_errors.svh
index d1c7090..d11467a 100644
--- a/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq__tl_errors.svh
+++ b/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq__tl_errors.svh
@@ -266,6 +266,17 @@
endtask
virtual task run_tl_intg_err_vseq_sub(int num_times = 1, string ral_name);
+ uvm_mem mems[$];
+ dv_base_mem passthru_mems[$];
+
+ cfg.ral_models[ral_name].get_memories(mems);
+
+ foreach (mems[i]) begin
+ dv_base_mem dv_mem;
+ `downcast(dv_mem, mems[i])
+ if (dv_mem.get_data_intg_passthru()) passthru_mems.push_back(dv_mem);
+ end
+
fork
// run csr_rw seq to send some normal CSR accesses in parallel
begin
@@ -334,4 +345,89 @@
join
endtask
+virtual task run_passthru_mem_tl_intg_err_vseq(int num_times = 1);
+ for (int trans = 1; trans <= num_times; trans++) begin
+ `uvm_info(`gfn, $sformatf("Running run_passthru_mem_tl_intg_err_vseq %0d/%0d",
+ trans, num_times),
+ UVM_LOW)
+ `loop_ral_models_to_create_threads(run_passthru_mem_tl_intg_err_vseq_sub(num_times, ral_name);)
+ dut_init("HARD");
+ end
+ csr_utils_pkg::wait_no_outstanding_access();
+endtask
+
+virtual task run_passthru_mem_tl_intg_err_vseq_sub(int num_times = 1, string ral_name);
+ uvm_mem mems[$];
+ dv_base_mem passthru_mems[$];
+
+ cfg.ral_models[ral_name].get_memories(mems);
+
+ foreach (mems[i]) begin
+ dv_base_mem dv_mem;
+ `downcast(dv_mem, mems[i])
+ if (dv_mem.get_data_intg_passthru()) passthru_mems.push_back(dv_mem);
+ end
+
+ fork
+ // run csr_rw seq to send some normal CSR accesses in parallel
+ if (en_csr_vseq_w_passthru_mem_intg) begin
+ `uvm_info(`gfn, "Run csr_rw seq", UVM_HIGH)
+ run_csr_vseq(.csr_test_type("rw"), .ral_name(ral_name));
+ end
+ begin
+ if (passthru_mems.size > 0) begin
+ cfg.disable_d_user_data_intg_check_for_passthru_mem = 1;
+ test_intg_err_in_passthru_mem(passthru_mems);
+ cfg.disable_d_user_data_intg_check_for_passthru_mem = 0;
+ end
+ end
+ join
+endtask
+
+virtual task test_intg_err_in_passthru_mem(const ref dv_base_mem mems[$]);
+ foreach (mems[i]) begin
+ bit [BUS_AW-1:0] offset;
+ bit [BUS_AW-1:0] addr;
+ bit [BUS_DW-1:0] data;
+ string ral_name;
+ cip_tl_seq_item tl_access_rsp;
+ bit completed, saw_err;
+ bit data_intg_ok;
+
+ offset = $urandom_range(0, mems[i].get_n_bytes() - 1);
+ addr = mems[i].get_address(offset);
+ ral_name = mems[i].get_parent().get_name();
+
+ // Before inject faults, this read should have correct integrity
+ tl_access_sub(.addr(addr), .write(0), .data(data), .completed(completed), .saw_err(saw_err),
+ .check_rsp(1), .rsp(tl_access_rsp),
+ .tl_sequencer_h(p_sequencer.tl_sequencer_hs[ral_name]));
+ `DV_CHECK_EQ(completed, 1)
+ `DV_CHECK_EQ(saw_err, 0)
+ tl_access_rsp.is_d_chan_intg_ok(.en_rsp_intg_chk(1),
+ .en_data_intg_chk(1),
+ .throw_error(1));
+
+ `uvm_info(`gfn, $sformatf("Backdoor inject intg fault to %s addr 0x%0h", ral_name, addr),
+ UVM_LOW)
+ inject_intg_fault_in_passthru_mem(mems[i], addr);
+
+ // Issue a read on the address that has been injected with integrity error
+ tl_access_sub(.addr(addr), .write(0), .data(data), .completed(completed), .saw_err(saw_err),
+ .check_rsp(1), .rsp(tl_access_rsp),
+ .tl_sequencer_h(p_sequencer.tl_sequencer_hs[ral_name]));
+ `DV_CHECK_EQ(completed, 1)
+ `DV_CHECK_EQ(saw_err, 0)
+ // data integrity should be wrong
+ data_intg_ok = tl_access_rsp.is_d_chan_intg_ok(.en_rsp_intg_chk(0),
+ .en_data_intg_chk(1),
+ .throw_error(0));
+ `DV_CHECK_EQ(data_intg_ok, 0)
+ end
+endtask
+
+virtual function void inject_intg_fault_in_passthru_mem(dv_base_mem mem, bit [BUS_AW-1:0] addr);
+ `uvm_fatal(`gfn, "This must be overridden in extended block common_vseq")
+endfunction
+
`undef create_tl_access_error_case
diff --git a/hw/dv/tools/dvsim/testplans/passthru_mem_intg_testplan.hjson b/hw/dv/tools/dvsim/testplans/passthru_mem_intg_testplan.hjson
new file mode 100644
index 0000000..fbe92f7
--- /dev/null
+++ b/hw/dv/tools/dvsim/testplans/passthru_mem_intg_testplan.hjson
@@ -0,0 +1,24 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+{
+ testpoints: [
+ {
+ name: passthru_mem_tl_intg_err
+ desc: '''Verify data integrity is stored in the passthru memory rather than generated after
+ a read.
+
+ - Randomly read a memory location and check the data integrity is correct.
+ - Backdoor inject fault into this location.
+ - Check the data integrity is incorrect but there is no d_error as the memory block
+ should just pass the stored data and integrity to the processor where the
+ integrity is compared.
+ - Above sequences will be run with `csr_rw_vseq` to ensure it won't affect CSR
+ accesses.
+ '''
+ milestone: V2
+ tests: ["{name}_passthru_mem_tl_intg_err"]
+ }
+ ]
+}
+
diff --git a/hw/dv/tools/dvsim/tests/passthru_mem_intg_tests.hjson b/hw/dv/tools/dvsim/tests/passthru_mem_intg_tests.hjson
new file mode 100644
index 0000000..ec89813
--- /dev/null
+++ b/hw/dv/tools/dvsim/tests/passthru_mem_intg_tests.hjson
@@ -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
+{
+ build_modes: [
+ {
+ name: cover_reg_top
+ }
+ ]
+
+ tests: [
+ {
+ name: "{name}_passthru_mem_tl_intg_err"
+ build_mode: "cover_reg_top"
+ uvm_test_seq: "{name}_common_vseq"
+ run_opts: ["+run_passthru_mem_tl_intg_err"]
+ reseed: 20
+ }
+ ]
+}