[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