[csrng, dv] Test CSRNG interrupts, alerts and errors
- Add vseqs for CSRNG interrupt, alert and error tests
- Update the related config files to include the interrupt, alert and error tests
- Add a virtual assert interface to turn off assertions with long paths
- Move the path references in the test vseqs to a separate path interface
Signed-off-by: Muqing Liu <muqing.liu@wdc.com>
diff --git a/hw/ip/csrng/data/csrng_testplan.hjson b/hw/ip/csrng/data/csrng_testplan.hjson
index ad4b076..56f1b8e 100644
--- a/hw/ip/csrng/data/csrng_testplan.hjson
+++ b/hw/ip/csrng/data/csrng_testplan.hjson
@@ -13,8 +13,8 @@
{
name: smoke
desc: '''
- Verify sending instantiate/generate cmds via SW path.
- Verify reading genbits via SW path.
+ Verify sending instantiate/generate cmds via SW path.
+ Verify reading genbits via SW path.
'''
milestone: V1
tests: ["csrng_smoke"]
diff --git a/hw/ip/csrng/dv/csrng_sim_cfg.hjson b/hw/ip/csrng/dv/csrng_sim_cfg.hjson
index 70ddb1e..a1a7f65 100644
--- a/hw/ip/csrng/dv/csrng_sim_cfg.hjson
+++ b/hw/ip/csrng/dv/csrng_sim_cfg.hjson
@@ -69,6 +69,24 @@
uvm_test_seq: csrng_stress_all_vseq
}
+ {
+ name: csrng_intr
+ uvm_test: csrng_intr_test
+ uvm_test_seq: csrng_intr_vseq
+ }
+
+ {
+ name: csrng_alert
+ uvm_test: csrng_alert_test
+ uvm_test_seq: csrng_alert_vseq
+ }
+
+ {
+ name: csrng_err
+ uvm_test: csrng_intr_test
+ uvm_test_seq: csrng_err_vseq
+ }
+
// TODO: add more tests here
]
diff --git a/hw/ip/csrng/dv/env/csrng_env.core b/hw/ip/csrng/dv/env/csrng_env.core
index ba8f1ac..2ad9e28 100644
--- a/hw/ip/csrng/dv/env/csrng_env.core
+++ b/hw/ip/csrng/dv/env/csrng_env.core
@@ -18,6 +18,7 @@
- lowrisc:dv:aes_model_dpi
files:
- csrng_env_pkg.sv
+ - csrng_path_if.sv
- csrng_env_cfg.sv: {is_include_file: true}
- csrng_env_cov.sv: {is_include_file: true}
- csrng_virtual_sequencer.sv: {is_include_file: true}
@@ -29,6 +30,9 @@
- seq_lib/csrng_smoke_vseq.sv: {is_include_file: true}
- seq_lib/csrng_cmds_vseq.sv: {is_include_file: true}
- seq_lib/csrng_stress_all_vseq.sv: {is_include_file: true}
+ - seq_lib/csrng_intr_vseq.sv: {is_include_file: true}
+ - seq_lib/csrng_alert_vseq.sv: {is_include_file: true}
+ - seq_lib/csrng_err_vseq.sv: {is_include_file: true}
file_type: systemVerilogSource
generate:
diff --git a/hw/ip/csrng/dv/env/csrng_env.sv b/hw/ip/csrng/dv/env/csrng_env.sv
index a878ac0..8b25266 100644
--- a/hw/ip/csrng/dv/env/csrng_env.sv
+++ b/hw/ip/csrng/dv/env/csrng_env.sv
@@ -57,12 +57,18 @@
cfg.lc_hw_debug_en_vif)) begin
`uvm_fatal(get_full_name(), "failed to get lc_hw_debug_en_vif from uvm_config_db")
end
+ // config csrng path virtual interface
+ if (!uvm_config_db#(virtual csrng_path_if)::
+ get(this, "", "csrng_path_vif", cfg.csrng_path_vif)) begin
+ `uvm_fatal(`gfn, "failed to get csrng_path_vif from uvm_config_db")
+ end
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
if (cfg.en_scb) begin
- m_entropy_src_agent.monitor.analysis_port.connect(scoreboard.entropy_src_fifo.analysis_export);
+ m_entropy_src_agent.monitor.analysis_port.connect(
+ scoreboard.entropy_src_fifo.analysis_export);
for (int i = 0; i < NUM_HW_APPS; i++) begin
m_edn_agent[i].monitor.analysis_port.connect(scoreboard.csrng_cmd_fifo[i].analysis_export);
end
diff --git a/hw/ip/csrng/dv/env/csrng_env_cfg.sv b/hw/ip/csrng/dv/env/csrng_env_cfg.sv
index 13ab7cf..e42a3e8 100644
--- a/hw/ip/csrng/dv/env/csrng_env_cfg.sv
+++ b/hw/ip/csrng/dv/env/csrng_env_cfg.sv
@@ -18,23 +18,45 @@
virtual pins_if#(MuBi8Width) otp_en_cs_sw_app_read_vif;
virtual pins_if#(MuBi4Width) lc_hw_debug_en_vif;
+ virtual csrng_assert_if csrng_assert_vif; // handle to csrng assert interface
+
+ virtual csrng_path_if csrng_path_vif; // handle to csrng path interface
+
// Knobs & Weights
uint otp_en_cs_sw_app_read_pct, lc_hw_debug_en_pct, regwen_pct,
enable_pct, sw_app_enable_pct, read_int_state_pct,
check_int_state_pct, num_cmds_min, num_cmds_max, aes_halt_pct,
min_aes_halt_clks, max_aes_halt_clks;
+ bit use_invalid_mubi;
+
rand bit check_int_state, regwen, hw_app[NUM_HW_APPS], sw_app, aes_halt;
rand mubi4_t enable, sw_app_enable, read_int_state;
rand lc_tx_t lc_hw_debug_en;
rand mubi8_t otp_en_cs_sw_app_read;
+ rand fatal_err_e which_fatal_err;
+ rand err_code_e which_err_code;
+ rand which_fifo_e which_fifo;
+ rand which_fifo_err_e which_fifo_err;
+ rand invalid_mubi_e which_invalid_mubi;
+
// Variables (+1 is for the SW APP)
bit compliance[NUM_HW_APPS + 1], status[NUM_HW_APPS + 1];
bit [csrng_env_pkg::KEY_LEN-1:0] key[NUM_HW_APPS + 1];
bit [csrng_env_pkg::BLOCK_LEN-1:0] v[NUM_HW_APPS + 1];
bit [csrng_env_pkg::RSD_CTR_LEN-1:0] reseed_counter[NUM_HW_APPS + 1];
+ int NHwApps = 2;
+ int NApps = NHwApps + 1;
+ int Sp2VWidth = 3;
+
+ rand uint which_hw_inst_exc;
+ constraint which_hw_inst_exc_c { which_hw_inst_exc inside {[0:NHwApps-1]};}
+
+ rand uint which_sp2v;
+ constraint which_sp2v_c { which_sp2v inside {[0:Sp2VWidth-1]};}
+
constraint otp_en_cs_sw_app_read_c { otp_en_cs_sw_app_read dist {
MuBi8True :/ otp_en_cs_sw_app_read_pct,
MuBi8False :/ (100 - otp_en_cs_sw_app_read_pct) };}
@@ -66,6 +88,24 @@
1 :/ aes_halt_pct,
0 :/ (100 - aes_halt_pct) };}
+ // Functions
+ function void post_randomize();
+ if (use_invalid_mubi) begin
+ prim_mubi_pkg::mubi4_t invalid_mubi_val;
+ invalid_mubi_val = get_rand_mubi4_val(.t_weight(0), .f_weight(0), .other_weight(1));
+
+ csrng_assert_vif.assert_off_alert();
+ case (which_invalid_mubi)
+ invalid_enable: enable = invalid_mubi_val;
+ invalid_sw_app_enable: sw_app_enable = invalid_mubi_val;
+ invalid_read_int_state: read_int_state = invalid_mubi_val;
+ default: begin
+ `uvm_fatal(`gfn, "Invalid case! (bug in environment)")
+ end
+ endcase // case (which_invalid_mubi)
+ end
+ endfunction // post_randomize
+
virtual function void initialize(bit [31:0] csr_base_addr = '1);
list_of_alerts = csrng_env_pkg::LIST_OF_ALERTS;
tl_intg_alert_name = "fatal_alert";
@@ -89,6 +129,12 @@
num_interrupts = ral.intr_state.get_n_used_bits();
end
end
+
+ // get csrng assert interface handle
+ if (!uvm_config_db#(virtual csrng_assert_if)::
+ get(null, "*.env" , "csrng_assert_vif", csrng_assert_vif)) begin
+ `uvm_fatal(`gfn, $sformatf("FAILED TO GET HANDLE TO ASSERT IF"))
+ end
endfunction
// Check internal state w/ optional compare
diff --git a/hw/ip/csrng/dv/env/csrng_env_pkg.sv b/hw/ip/csrng/dv/env/csrng_env_pkg.sv
index e24f3aa..bc27437 100644
--- a/hw/ip/csrng/dv/env/csrng_env_pkg.sv
+++ b/hw/ip/csrng/dv/env/csrng_env_pkg.sv
@@ -46,6 +46,121 @@
FifoErr = 3
} csrng_intr_e;
+ typedef enum int {
+ invalid_enable = 0,
+ invalid_sw_app_enable = 1,
+ invalid_read_int_state = 2
+ } invalid_mubi_e;
+
+ typedef enum int {
+ sfifo_cmd_error = 0,
+ sfifo_genbits_error = 1,
+ sfifo_cmdreq_error = 2,
+ sfifo_rcstage_error = 3,
+ sfifo_keyvrc_error = 4,
+ sfifo_updreq_error = 5,
+ sfifo_bencreq_error = 6,
+ sfifo_bencack_error = 7,
+ sfifo_pdata_error = 8,
+ sfifo_final_error = 9,
+ sfifo_gbencack_error = 10,
+ sfifo_grcstage_error = 11,
+ sfifo_ggenreq_error = 12,
+ sfifo_gadstage_error = 13,
+ sfifo_ggenbits_error = 14,
+ sfifo_blkenc_error = 15,
+ cmd_stage_sm_error = 16,
+ main_sm_error = 17,
+ drbg_gen_sm_error = 18,
+ drbg_updbe_sm_error = 19,
+ drbg_updob_sm_error = 20,
+ aes_cipher_sm_error = 21,
+ cmd_gen_cnt_error = 22,
+ fifo_write_error = 23,
+ fifo_read_error = 24,
+ fifo_state_error = 25
+ } fatal_err_e;
+
+ typedef enum int {
+ sfifo_cmd_err = 0,
+ sfifo_genbits_err = 1,
+ sfifo_cmdreq_err = 2,
+ sfifo_rcstage_err = 3,
+ sfifo_keyvrc_err = 4,
+ sfifo_updreq_err = 5,
+ sfifo_bencreq_err = 6,
+ sfifo_bencack_err = 7,
+ sfifo_pdata_err = 8,
+ sfifo_final_err = 9,
+ sfifo_gbencack_err = 10,
+ sfifo_grcstage_err = 11,
+ sfifo_ggenreq_err = 12,
+ sfifo_gadstage_err = 13,
+ sfifo_ggenbits_err = 14,
+ sfifo_blkenc_err = 15,
+ cmd_stage_sm_err = 16,
+ main_sm_err = 17,
+ drbg_gen_sm_err = 18,
+ drbg_updbe_sm_err = 19,
+ drbg_updob_sm_err = 20,
+ aes_cipher_sm_err = 21,
+ cmd_gen_cnt_err = 22,
+ fifo_write_err = 23,
+ fifo_read_err = 24,
+ fifo_state_err = 25,
+ sfifo_cmd_err_test = 26,
+ sfifo_genbits_err_test = 27,
+ sfifo_cmdreq_err_test = 28,
+ sfifo_rcstage_err_test = 29,
+ sfifo_keyvrc_err_test = 30,
+ sfifo_updreq_err_test = 31,
+ sfifo_bencreq_err_test = 32,
+ sfifo_bencack_err_test = 33,
+ sfifo_pdata_err_test = 34,
+ sfifo_final_err_test = 35,
+ sfifo_gbencack_err_test = 36,
+ sfifo_grcstage_err_test = 37,
+ sfifo_ggenreq_err_test = 38,
+ sfifo_gadstage_err_test = 39,
+ sfifo_ggenbits_err_test = 40,
+ sfifo_blkenc_err_test = 41,
+ cmd_stage_sm_err_test = 42,
+ main_sm_err_test = 43,
+ drbg_gen_sm_err_test = 44,
+ drbg_updbe_sm_err_test = 45,
+ drbg_updob_sm_err_test = 46,
+ aes_cipher_sm_err_test = 47,
+ cmd_gen_cnt_err_test = 48,
+ fifo_write_err_test = 49,
+ fifo_read_err_test = 50,
+ fifo_state_err_test = 51
+ } err_code_e;
+
+ typedef enum int {
+ sfifo_blkenc = 0,
+ sfifo_ggenbits = 1,
+ sfifo_gadstage = 2,
+ sfifo_ggenreq = 3,
+ sfifo_grcstage = 4,
+ sfifo_gbencack = 5,
+ sfifo_final = 6,
+ sfifo_pdata = 7,
+ sfifo_bencack = 8,
+ sfifo_bencreq = 9,
+ sfifo_updreq = 10,
+ sfifo_keyvrc = 11,
+ sfifo_rcstage = 12,
+ sfifo_cmdreq = 13,
+ sfifo_genbits = 14,
+ sfifo_cmd = 15
+ } which_fifo_e;
+
+ typedef enum int {
+ fifo_write = 0,
+ fifo_read = 1,
+ fifo_state = 2
+ } which_fifo_err_e;
+
// functions
// package sources
diff --git a/hw/ip/csrng/dv/env/csrng_path_if.sv b/hw/ip/csrng/dv/env/csrng_path_if.sv
new file mode 100644
index 0000000..e16cb5a
--- /dev/null
+++ b/hw/ip/csrng/dv/env/csrng_path_if.sv
@@ -0,0 +1,59 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// This interface deals with the force paths in CSRNG interrupt and error tests
+
+interface csrng_path_if
+(
+ input csrng_cmd_i
+);
+
+ import uvm_pkg::*;
+
+ string core_path = "tb.dut.u_csrng_core";
+
+ function automatic string cs_hw_inst_exc_path(string which_path, int which_hw_inst_exc);
+ return {core_path, $sformatf(".cmd_stage_%s[%0d]", which_path, which_hw_inst_exc)};
+ endfunction // cs_hw_inst_exc_path
+
+ function automatic string fifo_err_path(int NHwApps, string fifo_name, string which_path);
+ case (fifo_name) inside
+ "sfifo_cmd", "sfifo_genbits": return {core_path, $sformatf(".gen_cmd_stage[%0d]", NHwApps),
+ ".u_csrng_cmd_stage.", fifo_name, "_", which_path};
+ "sfifo_cmdreq", "sfifo_rcstage", "sfifo_keyvrc": return {core_path, ".u_csrng_ctr_drbg_cmd.",
+ fifo_name, "_", which_path};
+ "sfifo_updreq", "sfifo_bencreq", "sfifo_bencack", "sfifo_pdata", "sfifo_final": return
+ {core_path, ".u_csrng_ctr_drbg_upd.", fifo_name, "_", which_path};
+ "sfifo_gbencack", "sfifo_grcstage", "sfifo_ggenreq", "sfifo_gadstage", "sfifo_ggenbits":
+ return {core_path,".u_csrng_ctr_drbg_gen.sfifo_", fifo_name.substr(7, fifo_name.len()-1),
+ "_", which_path};
+ "sfifo_blkenc": return {core_path, ".u_csrng_block_encrypt.", fifo_name, "_", which_path};
+ default: `uvm_fatal("csrng_path_if", "Invalid fifo name!")
+ endcase // case (fifo_name.substr(6, fifo_name.len()-1))
+ endfunction // fifo_err_path
+
+ function automatic string sm_err_path(string which_sm, int NHwApps);
+ case (which_sm)
+ "cmd_stage_sm": return {core_path, $sformatf(".gen_cmd_stage[%0d]", NHwApps),
+ ".u_csrng_cmd_stage.state_q"};
+ "main_sm": return {core_path, ".u_csrng_main_sm.state_q"};
+ "drbg_gen_sm": return {core_path, ".u_csrng_ctr_drbg_gen.state_q"};
+ "drbg_updbe_sm": return {core_path, ".u_csrng_ctr_drbg_upd.blk_enc_state_q"};
+ "drbg_updob_sm": return {core_path, ".u_csrng_ctr_drbg_upd.outblk_state_q"};
+ default: `uvm_fatal("csrng_path_if", "Invalid sm name!")
+ endcase // case (which_sm)
+ endfunction // sm_err_path
+
+ function automatic string aes_cipher_sm_err_path(int which_sp2v, string which_path);
+ return {core_path, ".u_csrng_block_encrypt.u_aes_cipher_core.u_aes_cipher_control",
+ $sformatf(".gen_fsm[%0d].gen_fsm_%s", which_sp2v, which_path),
+ ".u_aes_cipher_control_fsm_i.u_aes_cipher_control_fsm",
+ ".aes_cipher_ctrl_cs"};
+ endfunction // aes_cipher_sm_err_path
+
+ function automatic string cmd_gen_cnt_err_path(int NHwApps);
+ return {core_path, $sformatf(".gen_cmd_stage[%0d]", NHwApps),
+ ".u_csrng_cmd_stage.u_prim_count_cmd_gen_cntr.gen_cross_cnt_hardening.msb"};
+ endfunction // cmd_gen_cnt_err_path
+endinterface // csrng_path_if
diff --git a/hw/ip/csrng/dv/env/seq_lib/csrng_alert_vseq.sv b/hw/ip/csrng/dv/env/seq_lib/csrng_alert_vseq.sv
new file mode 100644
index 0000000..b3745c7
--- /dev/null
+++ b/hw/ip/csrng/dv/env/seq_lib/csrng_alert_vseq.sv
@@ -0,0 +1,109 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// Test recoverable alerts with invalid mubi data type inputs and cs_bus_cmp_alert
+
+class csrng_alert_vseq extends csrng_base_vseq;
+ `uvm_object_utils(csrng_alert_vseq)
+
+ `uvm_object_new
+
+ bit [31:0] exp_recov_alert_sts;
+ csrng_item cs_item;
+
+ task body();
+ int first_index;
+ string reg_name;
+ string fld_name;
+ uvm_reg csr;
+ uvm_reg_field fld;
+
+ // Initiate with invalid mubi data
+ csrng_init();
+ cfg.clk_rst_vif.wait_clks(100);
+
+ // Check the recov_alert_sts register
+ reg_name = "recov_alert_sts";
+ fld_name = cfg.which_invalid_mubi.name();
+
+ first_index = find_index("_", fld_name, "first");
+ csr = ral.get_reg_by_name(reg_name);
+ fld = csr.get_field_by_name({fld_name.substr(first_index+1, fld_name.len()-1), "_field_alert"});
+
+ exp_recov_alert_sts = 32'b0;
+ exp_recov_alert_sts[fld.get_lsb_pos()] = 1;
+ csr_rd_check(.ptr(ral.recov_alert_sts), .compare_value(exp_recov_alert_sts));
+
+ cfg.clk_rst_vif.wait_clks(100);
+ // Write valid values
+ ral.ctrl.enable.set(prim_mubi_pkg::MuBi4True);
+ ral.ctrl.sw_app_enable.set(prim_mubi_pkg::MuBi4True);
+ ral.ctrl.read_int_state.set(prim_mubi_pkg::MuBi4True);
+ csr_update(.csr(ral.ctrl));
+
+ // Clear recov_alert_sts register
+ csr_wr(.ptr(ral.recov_alert_sts), .value(32'b0));
+
+ // Check recov_alert_sts register
+ cfg.clk_rst_vif.wait_clks(100);
+ csr_rd_check(.ptr(ral.recov_alert_sts), .compare_value(0));
+
+ // Test cs_bus_cmp_alert
+
+ ral.ctrl.read_int_state.set(4'hA);
+ // Wait for CSRNG cmd_rdy
+ csr_spinwait(.ptr(ral.sw_cmd_sts.cmd_rdy), .exp_data(1'b1));
+
+ cs_item = csrng_item::type_id::create("cs_item");
+
+ // Here we force CSRNG to generate two identical outputs to trigger a cs_bus_cmp_alert
+ // Write CSRNG Cmd_Req - Instantiate Command
+ cs_item.acmd = csrng_pkg::INS;
+ cs_item.clen = 'h0;
+ cs_item.flags = 'h1;
+ cs_item.glen = 'h0;
+ `uvm_info(`gfn, $sformatf("%s", cs_item.convert2string()), UVM_DEBUG)
+ send_cmd_req(SW_APP, cs_item);
+
+ // Write CSRNG Cmd_Req Register - Generate Command
+ cs_item.acmd = csrng_pkg::GEN;
+ cs_item.clen = 'h0;
+ cs_item.flags = 'h1;
+ cs_item.glen = 'h1;
+ `uvm_info(`gfn, $sformatf("%s", cs_item.convert2string()), UVM_DEBUG)
+ send_cmd_req(SW_APP, cs_item);
+
+ // Write CSRNG Cmd_Req - Instantiate Command
+ cs_item.acmd = csrng_pkg::INS;
+ cs_item.clen = 'h0;
+ cs_item.flags = 'h1;
+ cs_item.glen = 'h0;
+ `uvm_info(`gfn, $sformatf("%s", cs_item.convert2string()), UVM_DEBUG)
+ send_cmd_req(SW_APP, cs_item);
+
+ // Write CSRNG Cmd_Req Register - Generate Command
+ cs_item.acmd = csrng_pkg::GEN;
+ cs_item.clen = 'h0;
+ cs_item.flags = 'h1;
+ cs_item.glen = 'h1;
+ `uvm_info(`gfn, $sformatf("%s", cs_item.convert2string()), UVM_DEBUG)
+ send_cmd_req(SW_APP, cs_item);
+
+ // Check the recov_alert_sts register
+ exp_recov_alert_sts = 32'b0;
+ exp_recov_alert_sts[ral.recov_alert_sts.cs_bus_cmp_alert.get_lsb_pos()] = 1;
+ csr_rd_check(.ptr(ral.recov_alert_sts), .compare_value(exp_recov_alert_sts));
+
+ // Clear recov_alert_sts register
+ csr_wr(.ptr(ral.recov_alert_sts), .value(32'b0));
+
+ // Check recov_alert_sts register
+ cfg.clk_rst_vif.wait_clks(100);
+ csr_rd_check(.ptr(ral.recov_alert_sts), .compare_value(0));
+
+ // Turn assertions back on
+ cfg.csrng_assert_vif.assert_on_alert();
+ endtask : body
+
+endclass : csrng_alert_vseq
diff --git a/hw/ip/csrng/dv/env/seq_lib/csrng_base_vseq.sv b/hw/ip/csrng/dv/env/seq_lib/csrng_base_vseq.sv
index 853b8cf..ad46a3b 100644
--- a/hw/ip/csrng/dv/env/seq_lib/csrng_base_vseq.sv
+++ b/hw/ip/csrng/dv/env/seq_lib/csrng_base_vseq.sv
@@ -100,5 +100,150 @@
wait_cmd_req_done();
end
end
- endtask
+ endtask // send_cmd_req
+
+ task force_path(string path1, string path2, bit value1, bit value2);
+ if (!uvm_hdl_check_path(path1)) begin
+ `uvm_fatal(`gfn, "\n\t ----| PATH NOT FOUND")
+ end else begin
+ `DV_CHECK(uvm_hdl_force(path1, value1));
+ end
+ if (!uvm_hdl_check_path(path2)) begin
+ `uvm_fatal(`gfn, "\n\t ----| PATH NOT FOUND")
+ end else begin
+ `DV_CHECK(uvm_hdl_force(path2, value2));
+ end
+ endtask // force_path
+
+ task force_fifo_err(string path1, string path2, bit value1, bit value2,
+ uvm_reg_field reg_field, bit exp_data);
+ force_path(path1, path2, value1, value2);
+ // Check register value
+ csr_spinwait(.ptr(reg_field), .exp_data(exp_data));
+ `DV_CHECK(uvm_hdl_release(path1));
+ `DV_CHECK(uvm_hdl_release(path2));
+ endtask // force_fifo_err
+
+ task force_fifo_err_exception(string path1, string path2, bit value1, bit value2,
+ bit value3, uvm_reg_field reg_field, bit exp_data);
+ force_path(path1, path2, value1, value2);
+ // Check register value
+ csr_spinwait(.ptr(reg_field), .exp_data(exp_data));
+ `DV_CHECK(uvm_hdl_force(path1, value3));
+ `DV_CHECK(uvm_hdl_release(path2));
+ endtask // force_fifo_err_exception
+
+ task force_all_fifo_errs(string paths [4], bit values [4], string path_exts [4],
+ uvm_reg_field reg_field, bit exp_data, int case_state);
+ int index1 [$], index2 [$];
+ string path_push, path_full, path_pop, path_not_empty;
+ bit val_push, val_full, val_pop, val_not_empty;
+ case (case_state)
+ fifo_write: begin // fifo write err
+ index1 = path_exts.find_index(x) with (x == "push");
+ index2 = path_exts.find_index(x) with (x == "full");
+ path_push = paths[index1[0]];
+ path_full = paths[index2[0]];
+ val_push = values[index1[0]];
+ val_full = values[index2[0]];
+ force_fifo_err(path_push, path_full, 1'b1, 1'b1, reg_field, exp_data);
+ end
+ fifo_read: begin // fifo read err
+ index1 = path_exts.find_index(x) with (x == "pop");
+ index2 = path_exts.find_index(x) with (x == "not_empty");
+ path_pop = paths[index1[0]];
+ path_not_empty = paths[index2[0]];
+ val_pop = values[index1[0]];
+ val_not_empty = values[index2[0]];
+ force_fifo_err(path_pop, path_not_empty, 1'b1, 1'b0, reg_field, exp_data);
+ end
+ fifo_state: begin // fifo state err
+ index1 = path_exts.find_index(x) with (x == "pop");
+ index2 = path_exts.find_index(x) with (x == "not_empty");
+ path_pop = paths[index1[0]];
+ path_not_empty = paths[index2[0]];
+ val_pop = values[index1[0]];
+ val_not_empty = values[index2[0]];
+ force_fifo_err(path_full, path_not_empty, 1'b1, 1'b0, reg_field, exp_data);
+ end
+ default: begin
+ `uvm_fatal(`gfn, "Invalid case! (bug in environment)")
+ end
+ endcase // case (case_state)
+ endtask // force_all_fifo_errs
+
+ task force_all_fifo_errs_exception(string paths [4], bit values [4],string path_exts [4],
+ uvm_reg_field reg_field, bit exp_data, int case_state);
+ int index1 [$], index2 [$];
+ string path_push, path_full, path_pop, path_not_empty;
+ bit val_push, val_full, val_pop, val_not_empty;
+ case (case_state)
+ fifo_write: begin // fifo write err
+ index1 = path_exts.find_index(x) with (x == "push");
+ index2 = path_exts.find_index(x) with (x == "full");
+ path_push = paths[index1[0]];
+ path_full = paths[index2[0]];
+ val_push = values[index1[0]];
+ val_full = values[index2[0]];
+ force_fifo_err(path_push, path_full, val_push, val_full, reg_field, exp_data);
+ end
+ fifo_read: begin // fifo read err
+ index1 = path_exts.find_index(x) with (x == "pop");
+ index2 = path_exts.find_index(x) with (x == "not_empty");
+ path_pop = paths[index1[0]];
+ path_not_empty = paths[index2[0]];
+ val_pop = values[index1[0]];
+ val_not_empty = values[index2[0]];
+ force_fifo_err_exception(path_pop, path_not_empty, val_pop, val_not_empty, 1'b0,
+ reg_field, exp_data);
+ end
+ fifo_state: begin // fifo state err
+ index1 = path_exts.find_index(x) with (x == "full");
+ index2 = path_exts.find_index(x) with (x == "not_empty");
+ path_full = paths[index1[0]];
+ path_not_empty = paths[index2[0]];
+ val_full = values[index1[0]];
+ val_not_empty = values[index2[0]];
+ force_fifo_err(path_full, path_not_empty, val_full, val_not_empty, reg_field, exp_data);
+ end
+ default: begin
+ `uvm_fatal(`gfn, "Invalid case! (bug in environment)")
+ end
+ endcase // case (case_state)
+ endtask // force_all_fifo_errs_exception
+
+ task force_path_err(string path, bit [7:0] value, uvm_reg_field reg_field,
+ bit exp_data);
+ if (!uvm_hdl_check_path(path)) begin
+ `uvm_fatal(`gfn, $sformatf("\n\t ----| PATH NOT FOUND"))
+ end else begin
+ `DV_CHECK(uvm_hdl_force(path, value));
+ cfg.clk_rst_vif.wait_clks(50);
+ `DV_CHECK(uvm_hdl_release(path));
+ cfg.clk_rst_vif.wait_clks(50);
+ // Check register value
+ csr_rd_check(.ptr(reg_field), .compare_value(exp_data));
+ end
+ endtask // force_path_err
+
+ // Find the first or last index in the original string that the target character appears
+ function automatic int find_index (string target, string original_str, string which_index);
+ int index;
+ case (which_index)
+ "first": begin
+ for (int i = original_str.len(); i > 0; i--) begin
+ if (original_str[i] == target) index = i;
+ end
+ end
+ "last": begin
+ for (int i = 0; i < original_str.len(); i++) begin
+ if (original_str[i] == target) index = i;
+ end
+ end
+ default: begin
+ `uvm_fatal(`gfn, "Invalid index!")
+ end
+ endcase // case (which_index)
+ return index;
+ endfunction // find_index
endclass : csrng_base_vseq
diff --git a/hw/ip/csrng/dv/env/seq_lib/csrng_err_vseq.sv b/hw/ip/csrng/dv/env/seq_lib/csrng_err_vseq.sv
new file mode 100644
index 0000000..a5c0731
--- /dev/null
+++ b/hw/ip/csrng/dv/env/seq_lib/csrng_err_vseq.sv
@@ -0,0 +1,181 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// Test ERR_CODE fields fired as expected, as well as ERR_CODE_TEST register
+
+class csrng_err_vseq extends csrng_base_vseq;
+ `uvm_object_utils(csrng_err_vseq)
+
+ `uvm_object_new
+
+ csrng_item cs_item;
+
+ task body();
+ bit [2:0] SP2V_LOGIC_HIGH = '{1'b0,1'b1,1'b1};
+ bit [5:0] err_code_test_bit;
+ string path, path1, path2;
+ bit value1, value2;
+ string fifo_name;
+ int first_index, last_index;
+ string fifo_base_path;
+ string path_exts [4] = {"push", "full", "pop", "not_empty"};
+ string fifo_forced_paths [4];
+ bit fifo_forced_values [4] = {1'b1, 1'b1, 1'b1, 1'b0};
+ string fifo_err_path [2][string];
+ bit fifo_err_value [2][string];
+ string path_key;
+ string reg_name, fld_name;
+ uvm_reg csr;
+ uvm_reg_field fld;
+
+ fifo_err_path[0] = '{"write": "push", "read": "pop", "state": "full"};
+ fifo_err_path[1] = '{"write": "full", "read": "not_empty", "state": "not_empty"};
+ fifo_err_value[0] = '{"write": 1'b1, "read": 1'b1, "state": 1'b1};
+ fifo_err_value[1] = '{"write": 1'b1, "read": 1'b0, "state": 1'b0};
+
+ // Turn off fatal alert check
+ expect_fatal_alerts = 1'b1;
+
+ // Turn off assertions
+ $assertoff(0, "tb.entropy_src_if.ReqHighUntilAck_A");
+ $assertoff(0, "tb.entropy_src_if.AckAssertedOnlyWhenReqAsserted_A");
+ $assertoff(0, "tb.dut.u_csrng_core.u_prim_arbiter_ppc_updblk_arb.LockArbDecision_A");
+ $assertoff(0, "tb.dut.u_csrng_core.u_prim_arbiter_ppc_benblk_arb.ReqStaysHighUntilGranted0_M");
+ $assertoff(0, "tb.dut.u_csrng_core.u_prim_arbiter_ppc_updblk_arb.ReqStaysHighUntilGranted0_M");
+ cfg.csrng_assert_vif.assert_off();
+
+ cs_item = csrng_item::type_id::create("cs_item");
+
+ // Write CSRNG Cmd_Req - Instantiate Command
+ cs_item.acmd = csrng_pkg::INS;
+ cs_item.clen = 'h0;
+ cs_item.flags = 'h1;
+ cs_item.glen = 'h0;
+ `uvm_info(`gfn, $sformatf("%s", cs_item.convert2string()), UVM_DEBUG)
+ send_cmd_req(SW_APP, cs_item);
+
+ // Write CSRNG Cmd_Req Register - Generate Command
+ cs_item.acmd = csrng_pkg::GEN;
+ cs_item.clen = 'h0;
+ cs_item.flags = 'h1;
+ cs_item.glen = 'h1;
+ `uvm_info(`gfn, $sformatf("%s", cs_item.convert2string()), UVM_DEBUG)
+ send_cmd_req(SW_APP, cs_item);
+
+ reg_name = "err_code";
+ csr = ral.get_reg_by_name(reg_name);
+ fld_name = cfg.which_err_code.name();
+
+ first_index = find_index("_", fld_name, "first");
+ last_index = find_index("_", fld_name, "last");
+
+ case (cfg.which_err_code) inside
+ sfifo_cmd_err, sfifo_genbits_err, sfifo_cmdreq_err, sfifo_rcstage_err, sfifo_keyvrc_err,
+ sfifo_bencreq_err, sfifo_final_err, sfifo_gbencack_err, sfifo_grcstage_err,
+ sfifo_gadstage_err, sfifo_ggenbits_err, sfifo_blkenc_err, sfifo_updreq_err,
+ sfifo_bencack_err, sfifo_pdata_err, sfifo_ggenreq_err: begin
+ fld = csr.get_field_by_name(fld_name);
+ fifo_base_path = fld_name.substr(0, last_index-1);
+
+ foreach (path_exts[i]) begin
+ fifo_forced_paths[i] = cfg.csrng_path_vif.fifo_err_path(cfg.NHwApps, fifo_base_path,
+ path_exts[i]);
+ end
+
+ if (cfg.which_err_code == sfifo_updreq_err || cfg.which_err_code == sfifo_bencack_err ||
+ cfg.which_err_code == sfifo_pdata_err || cfg.which_err_code == sfifo_ggenreq_err) begin
+ force_all_fifo_errs_exception(fifo_forced_paths, fifo_forced_values, path_exts, fld,
+ 1'b1, cfg.which_fifo_err);
+ end else begin
+ force_all_fifo_errs(fifo_forced_paths, fifo_forced_values, path_exts, fld,
+ 1'b1, cfg.which_fifo_err);
+ end
+ end
+ cmd_stage_sm_err, main_sm_err, drbg_gen_sm_err, drbg_updbe_sm_err, drbg_updob_sm_err: begin
+ fld = csr.get_field_by_name(fld_name);
+ path = cfg.csrng_path_vif.sm_err_path(fld_name.substr(0, last_index-1), cfg.NHwApps);
+ force_path_err(path, 8'b0, fld, 1'b1);
+ end
+ aes_cipher_sm_err: begin
+ fld = csr.get_field_by_name(fld_name);
+ if (SP2V_LOGIC_HIGH[cfg.which_sp2v] == 1'b1) begin
+ path = cfg.csrng_path_vif.aes_cipher_sm_err_path(cfg.which_sp2v, "p");
+ force_path_err(path, 8'b0, fld, 1'b1);
+ end else begin
+ path = cfg.csrng_path_vif.aes_cipher_sm_err_path(cfg.which_sp2v, "n");
+ force_path_err(path, 8'b0, fld, 1'b1);
+ end
+ end
+ cmd_gen_cnt_err: begin
+ fld = csr.get_field_by_name(fld_name);
+ path = cfg.csrng_path_vif.cmd_gen_cnt_err_path(cfg.NHwApps);
+ force_path_err(path, 8'h01, fld, 1'b1);
+ end
+ fifo_write_err, fifo_read_err, fifo_state_err: begin
+ fld = csr.get_field_by_name(fld_name);
+ fifo_name = cfg.which_fifo.name();
+ path_key = fld_name.substr(first_index+1, last_index-1);
+
+ path1 = cfg.csrng_path_vif.fifo_err_path(cfg.NHwApps, fifo_name,
+ fifo_err_path[0][path_key]);
+ path2 = cfg.csrng_path_vif.fifo_err_path(cfg.NHwApps, fifo_name,
+ fifo_err_path[1][path_key]);
+ value1 = fifo_err_value[0][path_key];
+ value2 = fifo_err_value[1][path_key];
+
+ if (cfg.which_err_code == fifo_read_error &&
+ ((cfg.which_fifo == sfifo_ggenreq) || (cfg.which_fifo == sfifo_pdata) ||
+ (cfg.which_fifo == sfifo_bencack) || (cfg.which_fifo == sfifo_updreq)))
+ begin
+ force_fifo_err_exception(path1, path2, 1'b1, 1'b0, 1'b0, fld, 1'b1);
+ end else begin
+ force_fifo_err(path1, path2, value1, value2, fld, 1'b1);
+ end
+ end
+ sfifo_cmd_err_test, sfifo_genbits_err_test, sfifo_cmdreq_err_test, sfifo_rcstage_err_test,
+ sfifo_keyvrc_err_test, sfifo_updreq_err_test, sfifo_bencreq_err_test, sfifo_bencack_err_test,
+ sfifo_pdata_err_test, sfifo_final_err_test, sfifo_gbencack_err_test, sfifo_grcstage_err_test,
+ sfifo_ggenreq_err_test, sfifo_gadstage_err_test, sfifo_ggenbits_err_test,
+ sfifo_blkenc_err_test, cmd_stage_sm_err_test, main_sm_err_test, drbg_gen_sm_err_test,
+ drbg_updbe_sm_err_test, drbg_updob_sm_err_test, aes_cipher_sm_err_test, cmd_gen_cnt_err_test,
+ fifo_write_err_test, fifo_read_err_test, fifo_state_err_test: begin
+ fld = csr.get_field_by_name(fld_name.substr(0, last_index-1));
+ err_code_test_bit = fld.get_lsb_pos();
+ csr_wr(.ptr(ral.err_code_test.err_code_test), .value(err_code_test_bit));
+ cfg.clk_rst_vif.wait_clks(50);
+ csr_rd_check(.ptr(fld), .compare_value(1'b1));
+ // Clear interrupt_enable
+ csr_wr(.ptr(ral.intr_enable), .value(32'd0));
+ ral.ctrl.enable.set(prim_mubi_pkg::MuBi4False);
+ ral.ctrl.sw_app_enable.set(prim_mubi_pkg::MuBi4True);
+ csr_update(.csr(ral.ctrl));
+ // Expect/Clear interrupt bit
+ check_interrupts(.interrupts((1 << FifoErr)), .check_set(1'b1));
+ end
+ default: begin
+ `uvm_fatal(`gfn, "Invalid case! (bug in environment)")
+ end
+ endcase // case (cfg.which_err_code)
+
+ cfg.clk_rst_vif.wait_clks(50);
+ // Clear intr_enable
+ csr_wr(.ptr(ral.intr_enable), .value(32'h0));
+ ral.ctrl.enable.set(prim_mubi_pkg::MuBi4False);
+ csr_update(.csr(ral.ctrl));
+ // Clear intr_state
+ csr_wr(.ptr(ral.intr_state), .value(32'd15));
+ cfg.clk_rst_vif.wait_clks(100);
+ csr_rd_check(.ptr(ral.intr_state), .compare_value(4'b0));
+
+ // Turn assertions back on
+ $asserton(0, "tb.entropy_src_if.ReqHighUntilAck_A");
+ $asserton(0, "tb.entropy_src_if.AckAssertedOnlyWhenReqAsserted_A");
+ $asserton(0, "tb.dut.u_csrng_core.u_prim_arbiter_ppc_updblk_arb.LockArbDecision_A");
+ $asserton(0, "tb.dut.u_csrng_core.u_prim_arbiter_ppc_benblk_arb.ReqStaysHighUntilGranted0_M");
+ $asserton(0, "tb.dut.u_csrng_core.u_prim_arbiter_ppc_updblk_arb.ReqStaysHighUntilGranted0_M");
+ cfg.csrng_assert_vif.assert_on();
+
+ endtask : body
+
+endclass : csrng_err_vseq
diff --git a/hw/ip/csrng/dv/env/seq_lib/csrng_intr_vseq.sv b/hw/ip/csrng/dv/env/seq_lib/csrng_intr_vseq.sv
new file mode 100644
index 0000000..5fa976b
--- /dev/null
+++ b/hw/ip/csrng/dv/env/seq_lib/csrng_intr_vseq.sv
@@ -0,0 +1,226 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// Test cs_cmd_req_done, cs_entropy_req, cs_hw_inst_exc and cs_fatal_err interrupts
+// fired as expected
+
+class csrng_intr_vseq extends csrng_base_vseq;
+ `uvm_object_utils(csrng_intr_vseq)
+
+ `uvm_object_new
+
+ csrng_item cs_item;
+ string path1, path2, path_push, path_full, path_pop, path_not_empty, path;
+ int Sp2VWidth = 3;
+ bit [2:0] SP2V_LOGIC_HIGH = '{1'b0,1'b1,1'b1};
+
+ task test_cs_cmd_req_done();
+ cs_item = csrng_item::type_id::create("cs_item");
+
+ // Write CSRNG Cmd_Req - Instantiate Command
+ cs_item.acmd = csrng_pkg::INS;
+ cs_item.clen = 'h0;
+ cs_item.flags = 'h1;
+ cs_item.glen = 'h0;
+ `uvm_info(`gfn, $sformatf("%s", cs_item.convert2string()), UVM_DEBUG)
+ send_cmd_req(SW_APP, cs_item);
+
+ // Write CSRNG Cmd_Req Register - Generate Command
+ cs_item.acmd = csrng_pkg::GEN;
+ cs_item.clen = 'h0;
+ cs_item.flags = 'h1;
+ cs_item.glen = 'h1;
+ `uvm_info(`gfn, $sformatf("%s", cs_item.convert2string()), UVM_DEBUG)
+ send_cmd_req(SW_APP, cs_item);
+ endtask // test_cs_cmd_req_done
+
+ task test_cs_entropy_req();
+ cs_item = csrng_item::type_id::create("cs_item");
+
+ // Write CSRNG Cmd_Req - Instantiate Command
+ cs_item.acmd = csrng_pkg::INS;
+ cs_item.clen = 'h0;
+ cs_item.flags = 'h0;
+ cs_item.glen = 'h0;
+ `uvm_info(`gfn, $sformatf("%s", cs_item.convert2string()), UVM_DEBUG)
+ send_cmd_req(SW_APP, cs_item);
+
+ // Write CSRNG Cmd_Req Register - Generate Command
+ cs_item.acmd = csrng_pkg::GEN;
+ cs_item.clen = 'h0;
+ cs_item.flags = 'h0;
+ cs_item.glen = 'h1;
+ `uvm_info(`gfn, $sformatf("%s", cs_item.convert2string()), UVM_DEBUG)
+ send_cmd_req(SW_APP, cs_item);
+
+ // Expect/Clear interrupt bit
+ csr_rd_check(.ptr(ral.intr_state.cs_entropy_req), .compare_value(1'b1));
+ check_interrupts(.interrupts((1 << EntropyReq)), .check_set(1'b1));
+ cfg.clk_rst_vif.wait_clks(100);
+ // Make sure the interrupt bit is cleared
+ csr_rd_check(.ptr(ral.intr_state.cs_entropy_req), .compare_value(1'b0));
+ endtask // test_cs_entropy_req
+
+ task test_cs_hw_inst_exc();
+ path1 = cfg.csrng_path_vif.cs_hw_inst_exc_path("ack", cfg.which_hw_inst_exc);
+ path2 = cfg.csrng_path_vif.cs_hw_inst_exc_path("ack_sts", cfg.which_hw_inst_exc);
+
+ force_path(path1, path2, 1'b1, 1'b0);
+ // Wait for cs_hw_inst_exc interrupt
+ csr_spinwait(.ptr(ral.intr_state.cs_hw_inst_exc), .exp_data(1'b1));
+
+ `DV_CHECK(uvm_hdl_release(path1));
+ `DV_CHECK(uvm_hdl_release(path2));
+
+ // Expect/Clear interrupt bit
+ check_interrupts(.interrupts((1 << HwInstExc)), .check_set(1'b1));
+ cfg.clk_rst_vif.wait_clks(100);
+ // Make sure the interrupt bit is cleared
+ csr_rd_check(.ptr(ral.intr_state.cs_hw_inst_exc), .compare_value(1'b0));
+ endtask // test_cs_hw_inst_exc
+
+ task test_cs_fatal_err();
+ string path, path1, path2;
+ bit value1, value2;
+ string fifo_name, fld_name;
+ int first_index, last_index;
+ string fifo_base_path;
+ string path_exts [4] = {"push", "full", "pop", "not_empty"};
+ string fifo_forced_paths [4];
+ bit fifo_forced_values [4] = {1'b1, 1'b1, 1'b1, 1'b0};
+ string fifo_err_path [2][string];
+ bit fifo_err_value [2][string];
+ string path_key;
+
+ fifo_err_path[0] = '{"write": "push", "read": "pop", "state": "full"};
+ fifo_err_path[1] = '{"write": "full", "read": "not_empty", "state": "not_empty"};
+ fifo_err_value[0] = '{"write": 1'b1, "read": 1'b1, "state": 1'b1};
+ fifo_err_value[1] = '{"write": 1'b1, "read": 1'b0, "state": 1'b0};
+
+ // Enable CSRNG
+ ral.ctrl.enable.set(prim_mubi_pkg::MuBi4True);
+ csr_update(.csr(ral.ctrl));
+ // Enable intr_state
+ csr_wr(.ptr(ral.intr_enable), .value(32'd15));
+
+ fld_name = cfg.which_fatal_err.name();
+
+ first_index = find_index("_", fld_name, "first");
+ last_index = find_index("_", fld_name, "last");
+
+ case (cfg.which_fatal_err) inside
+ sfifo_cmd_error, sfifo_genbits_error, sfifo_cmdreq_error, sfifo_rcstage_error,
+ sfifo_keyvrc_error, sfifo_bencreq_error, sfifo_final_error, sfifo_gbencack_error,
+ sfifo_grcstage_error, sfifo_gadstage_error, sfifo_ggenbits_error,
+ sfifo_blkenc_error, sfifo_updreq_error, sfifo_bencack_error, sfifo_pdata_error,
+ sfifo_ggenreq_error: begin
+ fifo_base_path = fld_name.substr(0, last_index-1);
+
+ foreach (path_exts[i]) begin
+ fifo_forced_paths[i] = cfg.csrng_path_vif.fifo_err_path(cfg.NHwApps, fifo_base_path,
+ path_exts[i]);
+ end
+ if (cfg.which_fatal_err == sfifo_updreq_error ||
+ cfg.which_fatal_err == sfifo_bencack_error ||
+ cfg.which_fatal_err == sfifo_pdata_error ||
+ cfg.which_fatal_err == sfifo_ggenreq_error) begin
+ force_all_fifo_errs_exception(fifo_forced_paths, fifo_forced_values, path_exts,
+ ral.intr_state.cs_fatal_err, 1'b1, cfg.which_fifo_err);
+ end else begin
+ force_all_fifo_errs(fifo_forced_paths, fifo_forced_values, path_exts,
+ ral.intr_state.cs_fatal_err, 1'b1, cfg.which_fifo_err);
+ end
+ end
+ cmd_stage_sm_error, main_sm_error, drbg_gen_sm_error, drbg_updbe_sm_error,
+ drbg_updob_sm_error: begin
+ path = cfg.csrng_path_vif.sm_err_path(fld_name.substr(0, last_index-1), cfg.NHwApps);
+ force_path_err(path, 8'b0, ral.intr_state.cs_fatal_err, 1'b1);
+ end
+ aes_cipher_sm_error: begin
+ if (SP2V_LOGIC_HIGH[cfg.which_sp2v] == 1'b1) begin
+ path = cfg.csrng_path_vif.aes_cipher_sm_err_path(cfg.which_sp2v, "p");
+ force_path_err(path, 8'b0, ral.intr_state.cs_fatal_err, 1'b1);
+ end else begin
+ path = cfg.csrng_path_vif.aes_cipher_sm_err_path(cfg.which_sp2v, "n");
+ force_path_err(path, 8'b0, ral.intr_state.cs_fatal_err, 1'b1);
+ end
+ end
+ cmd_gen_cnt_error: begin
+ path = cfg.csrng_path_vif.cmd_gen_cnt_err_path(cfg.NHwApps);
+ force_path_err(path, 8'h01, ral.intr_state.cs_fatal_err, 1'b1);
+ end
+ fifo_write_error, fifo_read_error, fifo_state_error: begin
+ fifo_name = cfg.which_fifo.name();
+ path_key = fld_name.substr(first_index+1, last_index-1);
+
+ path1 = cfg.csrng_path_vif.fifo_err_path(cfg.NHwApps, fifo_name,
+ fifo_err_path[0][path_key]);
+ path2 = cfg.csrng_path_vif.fifo_err_path(cfg.NHwApps, fifo_name,
+ fifo_err_path[1][path_key]);
+ value1 = fifo_err_value[0][path_key];
+ value2 = fifo_err_value[1][path_key];
+
+ if (cfg.which_fatal_err == fifo_read_error &&
+ ((cfg.which_fifo == sfifo_ggenreq) || (cfg.which_fifo == sfifo_pdata) ||
+ (cfg.which_fifo == sfifo_bencack) || (cfg.which_fifo == sfifo_updreq)))
+ begin
+ force_fifo_err_exception(path1, path2, 1'b1, 1'b0, 1'b0, ral.intr_state.cs_fatal_err,
+ 1'b1);
+ end else begin
+ force_fifo_err(path1, path2, value1, value2, ral.intr_state.cs_fatal_err, 1'b1);
+ end
+ end
+ default: begin
+ `uvm_fatal(`gfn, "Invalid case! (bug in environment)")
+ end
+ endcase // case (cfg.which_fatal_err)
+ endtask // test_cs_fatal_err
+
+ task body();
+ // Turn off fatal alert check
+ expect_fatal_alerts = 1'b1;
+
+ // Turn off assertions
+ $assertoff(0, "tb.entropy_src_if.ReqHighUntilAck_A");
+ $assertoff(0, "tb.entropy_src_if.AckAssertedOnlyWhenReqAsserted_A");
+ $assertoff(0, "tb.dut.u_csrng_core.u_prim_arbiter_ppc_updblk_arb.LockArbDecision_A");
+ $assertoff(0, "tb.dut.u_csrng_core.u_prim_arbiter_ppc_benblk_arb.ReqStaysHighUntilGranted0_M");
+ $assertoff(0, "tb.dut.u_csrng_core.u_prim_arbiter_ppc_updblk_arb.ReqStaysHighUntilGranted0_M");
+ cfg.csrng_assert_vif.assert_off();
+
+ // Test cs_cmd_req_done interrupt
+ // cs_cmd_req_done interrupt is checked in the send_cmd_req()
+ test_cs_cmd_req_done();
+
+ // Test cs_entropy_req interrupt
+ test_cs_entropy_req();
+
+ // Test cs_hw_inst_exc interrupt
+ test_cs_hw_inst_exc();
+
+ // Test cs_fatal_err interrupt
+ test_cs_fatal_err();
+
+ cfg.clk_rst_vif.wait_clks(50);
+ // Clear intr_enable
+ csr_wr(.ptr(ral.intr_enable), .value(32'h0));
+ ral.ctrl.enable.set(prim_mubi_pkg::MuBi4False);
+ ral.ctrl.sw_app_enable.set(prim_mubi_pkg::MuBi4True);
+ csr_update(.csr(ral.ctrl));
+ // Clear intr_state
+ csr_wr(.ptr(ral.intr_state), .value(32'd15));
+ cfg.clk_rst_vif.wait_clks(100);
+ csr_rd_check(.ptr(ral.intr_state), .compare_value(4'b0));
+
+ // Turn assertions back on
+ $asserton(0, "tb.entropy_src_if.ReqHighUntilAck_A");
+ $asserton(0, "tb.entropy_src_if.AckAssertedOnlyWhenReqAsserted_A");
+ $asserton(0, "tb.dut.u_csrng_core.u_prim_arbiter_ppc_updblk_arb.LockArbDecision_A");
+ $asserton(0, "tb.dut.u_csrng_core.u_prim_arbiter_ppc_benblk_arb.ReqStaysHighUntilGranted0_M");
+ $asserton(0, "tb.dut.u_csrng_core.u_prim_arbiter_ppc_updblk_arb.ReqStaysHighUntilGranted0_M");
+ cfg.csrng_assert_vif.assert_on();
+
+ endtask : body
+
+endclass : csrng_intr_vseq
diff --git a/hw/ip/csrng/dv/env/seq_lib/csrng_vseq_list.sv b/hw/ip/csrng/dv/env/seq_lib/csrng_vseq_list.sv
index 26d617f..6542bb7 100644
--- a/hw/ip/csrng/dv/env/seq_lib/csrng_vseq_list.sv
+++ b/hw/ip/csrng/dv/env/seq_lib/csrng_vseq_list.sv
@@ -7,3 +7,6 @@
`include "csrng_common_vseq.sv"
`include "csrng_cmds_vseq.sv"
`include "csrng_stress_all_vseq.sv"
+`include "csrng_intr_vseq.sv"
+`include "csrng_alert_vseq.sv"
+`include "csrng_err_vseq.sv"
diff --git a/hw/ip/csrng/dv/sva/csrng_assert_if.sv b/hw/ip/csrng/dv/sva/csrng_assert_if.sv
new file mode 100644
index 0000000..75c8e58
--- /dev/null
+++ b/hw/ip/csrng/dv/sva/csrng_assert_if.sv
@@ -0,0 +1,73 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// Interface: csrng_assert_if
+// Description: Asserts interface to turn off assertions that have long paths
+
+`define PATH1 \
+ tb.dut.u_csrng_core.gen_cmd_stage[2].u_csrng_cmd_stage.u_prim_count_cmd_gen_cntr
+`define PATH2 \
+ tb.dut.u_csrng_core.u_csrng_block_encrypt.u_aes_cipher_core.u_aes_cipher_control
+`define PATH2_1 \
+ gen_fsm[0].gen_fsm_p.u_aes_cipher_control_fsm_i.u_aes_cipher_control_fsm
+`define PATH2_2 \
+ gen_fsm[1].gen_fsm_p.u_aes_cipher_control_fsm_i.u_aes_cipher_control_fsm
+`define PATH2_3 \
+ gen_fsm[2].gen_fsm_n.u_aes_cipher_control_fsm_i.u_aes_cipher_control_fsm
+`define PATH3 \
+ tb.dut.u_csrng_core.u_prim_mubi4_sync_cs_enable
+`define PATH4 \
+ tb.dut.u_csrng_core.u_prim_mubi4_sync_sw_app_enable
+`define PATH5 \
+ tb.dut.u_csrng_core.u_prim_mubi4_sync_read_int_state
+
+interface csrng_assert_if
+(
+ input csrng_cmd_i
+);
+
+ task automatic assert_off ();
+ $assertoff(0, `PATH1.MaxUpCntStable_A);
+ $assertoff(0, `PATH1.gen_cross_cnt_hardening.CrossCntErrBackward_A);
+ $assertoff(0, `PATH2.`PATH2_1.AesCipherControlStateValid);
+ $assertoff(0, `PATH2.`PATH2_2.AesCipherControlStateValid);
+ $assertoff(0, `PATH2.`PATH2_3.AesCipherControlStateValid);
+ endtask // assert_off
+
+ task automatic assert_on ();
+ $asserton(0, `PATH1.MaxUpCntStable_A);
+ $asserton(0, `PATH1.gen_cross_cnt_hardening.CrossCntErrBackward_A);
+ $asserton(0, `PATH2.`PATH2_1.AesCipherControlStateValid);
+ $asserton(0, `PATH2.`PATH2_2.AesCipherControlStateValid);
+ $asserton(0, `PATH2.`PATH2_3.AesCipherControlStateValid);
+ endtask // assert_on
+
+ task automatic assert_off_alert ();
+ $assertoff(0, `PATH3.PrimMubi4SyncCheckTransients_A);
+ $assertoff(0, `PATH3.PrimMubi4SyncCheckTransients0_A);
+ $assertoff(0, `PATH3.PrimMubi4SyncCheckTransients1_A);
+
+ $assertoff(0, `PATH4.PrimMubi4SyncCheckTransients_A);
+ $assertoff(0, `PATH4.PrimMubi4SyncCheckTransients0_A);
+ $assertoff(0, `PATH4.PrimMubi4SyncCheckTransients1_A);
+
+ $assertoff(0, `PATH5.PrimMubi4SyncCheckTransients_A);
+ $assertoff(0, `PATH5.PrimMubi4SyncCheckTransients0_A);
+ $assertoff(0, `PATH5.PrimMubi4SyncCheckTransients1_A);
+ endtask // assert_off_alert
+
+ task automatic assert_on_alert ();
+ $asserton(0, `PATH3.PrimMubi4SyncCheckTransients_A);
+ $asserton(0, `PATH3.PrimMubi4SyncCheckTransients0_A);
+ $asserton(0, `PATH3.PrimMubi4SyncCheckTransients1_A);
+
+ $asserton(0, `PATH4.PrimMubi4SyncCheckTransients_A);
+ $asserton(0, `PATH4.PrimMubi4SyncCheckTransients0_A);
+ $asserton(0, `PATH4.PrimMubi4SyncCheckTransients1_A);
+
+ $asserton(0, `PATH5.PrimMubi4SyncCheckTransients_A);
+ $asserton(0, `PATH5.PrimMubi4SyncCheckTransients0_A);
+ $asserton(0, `PATH5.PrimMubi4SyncCheckTransients1_A);
+ endtask // assert_on_alert
+endinterface
diff --git a/hw/ip/csrng/dv/sva/csrng_sva.core b/hw/ip/csrng/dv/sva/csrng_sva.core
index 0a5e15f..5461bdd 100644
--- a/hw/ip/csrng/dv/sva/csrng_sva.core
+++ b/hw/ip/csrng/dv/sva/csrng_sva.core
@@ -11,6 +11,7 @@
- lowrisc:fpv:csr_assert_gen
files:
- csrng_bind.sv
+ - csrng_assert_if.sv
file_type: systemVerilogSource
files_formal:
diff --git a/hw/ip/csrng/dv/tb.sv b/hw/ip/csrng/dv/tb.sv
index 9c5bc03..77ac7f5 100644
--- a/hw/ip/csrng/dv/tb.sv
+++ b/hw/ip/csrng/dv/tb.sv
@@ -36,6 +36,8 @@
push_pull_if#(.HostDataWidth(entropy_src_pkg::FIPS_CSRNG_BUS_WIDTH))
entropy_src_if(.clk(clk), .rst_n(rst_n));
push_pull_if#(.HostDataWidth(1)) aes_halt_if(.clk(clk), .rst_n(rst_n));
+ csrng_path_if csrng_path_if (.csrng_cmd_i(csrng_cmd_i));
+ csrng_assert_if csrng_assert_if (.csrng_cmd_i(csrng_cmd_i));
`DV_ALERT_IF_CONNECT
@@ -102,10 +104,13 @@
lc_hw_debug_en_if);
uvm_config_db#(virtual tl_if)::set(null, "*.env.m_tl_agent*", "vif", tl_if);
uvm_config_db#(virtual push_pull_if#(.HostDataWidth(entropy_src_pkg::FIPS_CSRNG_BUS_WIDTH)))::
- set(null, "*.env.m_entropy_src_agent*", "vif", entropy_src_if);
+ set(null, "*.env.m_entropy_src_agent*", "vif", entropy_src_if);
uvm_config_db#(virtual push_pull_if#(.HostDataWidth(1)))::set
(null, "*.env.m_aes_halt_agent*", "vif", aes_halt_if);
- uvm_config_db#(virtual csrng_cov_if)::set(null, "*.env", "csrng_cov_if", dut.u_csrng_cov_if );
+ uvm_config_db#(virtual csrng_cov_if)::set(null, "*.env", "csrng_cov_if", dut.u_csrng_cov_if);
+ uvm_config_db#(virtual csrng_assert_if)::set(null, "*.env", "csrng_assert_vif",
+ csrng_assert_if);
+ uvm_config_db#(virtual csrng_path_if)::set(null, "*.env", "csrng_path_vif", csrng_path_if);
$timeformat(-12, 0, " ps", 12);
run_test();
end
diff --git a/hw/ip/csrng/dv/tests/csrng_alert_test.sv b/hw/ip/csrng/dv/tests/csrng_alert_test.sv
new file mode 100644
index 0000000..a52692d
--- /dev/null
+++ b/hw/ip/csrng/dv/tests/csrng_alert_test.sv
@@ -0,0 +1,22 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class csrng_alert_test extends csrng_base_test;
+
+ `uvm_component_utils(csrng_alert_test)
+ `uvm_component_new
+
+ function void configure_env();
+ super.configure_env();
+
+ cfg.en_scb = 0;
+ cfg.otp_en_cs_sw_app_read_pct = 100;
+ cfg.sw_app_enable_pct = 100;
+ cfg.use_invalid_mubi = 1;
+
+ `DV_CHECK_RANDOMIZE_FATAL(cfg)
+
+ `uvm_info("csrng_intr_dbg", $sformatf("%s", cfg.convert2string()), UVM_LOW)
+ endfunction
+endclass : csrng_alert_test
diff --git a/hw/ip/csrng/dv/tests/csrng_intr_test.sv b/hw/ip/csrng/dv/tests/csrng_intr_test.sv
new file mode 100644
index 0000000..d609040
--- /dev/null
+++ b/hw/ip/csrng/dv/tests/csrng_intr_test.sv
@@ -0,0 +1,22 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class csrng_intr_test extends csrng_base_test;
+
+ `uvm_component_utils(csrng_intr_test)
+ `uvm_component_new
+
+ function void configure_env();
+ super.configure_env();
+
+ cfg.en_scb = 0;
+ cfg.otp_en_cs_sw_app_read_pct = 100;
+ cfg.sw_app_enable_pct = 100;
+ cfg.use_invalid_mubi = 0;
+
+ `DV_CHECK_RANDOMIZE_FATAL(cfg)
+
+ `uvm_info("csrng_intr_dbg", $sformatf("%s", cfg.convert2string()), UVM_LOW)
+ endfunction
+endclass : csrng_intr_test
diff --git a/hw/ip/csrng/dv/tests/csrng_smoke_test.sv b/hw/ip/csrng/dv/tests/csrng_smoke_test.sv
index c388206..eeaf387 100644
--- a/hw/ip/csrng/dv/tests/csrng_smoke_test.sv
+++ b/hw/ip/csrng/dv/tests/csrng_smoke_test.sv
@@ -10,7 +10,10 @@
function void configure_env();
super.configure_env();
+ cfg.use_invalid_mubi = 0;
+
`DV_CHECK_RANDOMIZE_FATAL(cfg)
+
`uvm_info(`gfn, $sformatf("%s", cfg.convert2string()), UVM_LOW)
endfunction
endclass : csrng_smoke_test
diff --git a/hw/ip/csrng/dv/tests/csrng_test.core b/hw/ip/csrng/dv/tests/csrng_test.core
index 48b8fd9..75db35a 100644
--- a/hw/ip/csrng/dv/tests/csrng_test.core
+++ b/hw/ip/csrng/dv/tests/csrng_test.core
@@ -14,6 +14,8 @@
- csrng_smoke_test.sv: {is_include_file: true}
- csrng_cmds_test.sv: {is_include_file: true}
- csrng_stress_all_test.sv: {is_include_file: true}
+ - csrng_intr_test.sv: {is_include_file: true}
+ - csrng_alert_test.sv: {is_include_file: true}
file_type: systemVerilogSource
targets:
diff --git a/hw/ip/csrng/dv/tests/csrng_test_pkg.sv b/hw/ip/csrng/dv/tests/csrng_test_pkg.sv
index 2f2b83c..baeba09 100644
--- a/hw/ip/csrng/dv/tests/csrng_test_pkg.sv
+++ b/hw/ip/csrng/dv/tests/csrng_test_pkg.sv
@@ -17,5 +17,7 @@
`include "csrng_smoke_test.sv"
`include "csrng_cmds_test.sv"
`include "csrng_stress_all_test.sv"
+ `include "csrng_intr_test.sv"
+ `include "csrng_alert_test.sv"
endpackage