[csrng/dv] Extend `csrng_cmds` test to randomly disable and re-enable CSRNG
Signed-off-by: Andreas Kurth <adk@lowrisc.org>
diff --git a/hw/ip/csrng/dv/env/csrng_env_cfg.sv b/hw/ip/csrng/dv/env/csrng_env_cfg.sv
index cd9983c..06da191 100644
--- a/hw/ip/csrng/dv/env/csrng_env_cfg.sv
+++ b/hw/ip/csrng/dv/env/csrng_env_cfg.sv
@@ -27,7 +27,14 @@
// Knobs & Weights
uint otp_en_cs_sw_app_read_pct, otp_en_cs_sw_app_read_inval_pct, lc_hw_debug_en_pct, regwen_pct,
enable_pct, sw_app_enable_pct, read_int_state_pct, force_state_pct, check_int_state_pct,
- num_cmds_min, num_cmds_max, aes_halt_pct, min_aes_halt_clks, max_aes_halt_clks;
+ num_cmds_min, num_cmds_max, aes_halt_pct, min_aes_halt_clks, max_aes_halt_clks,
+ min_num_disable_enable, max_num_disable_enable,
+ min_enable_clks, max_enable_clks,
+ min_disable_edn_before_csrng_clks, max_disable_edn_before_csrng_clks,
+ min_disable_csrng_before_entropy_src_clks, max_disable_csrng_before_entropy_src_clks,
+ min_disable_clks, max_disable_clks,
+ min_enable_entropy_src_before_csrng_clks, max_enable_entropy_src_before_csrng_clks,
+ min_enable_csrng_before_edn_clks, max_enable_csrng_before_edn_clks;
bit use_invalid_mubi;
@@ -116,6 +123,69 @@
[fifo_write_err : fifo_state_err_test] := 1
};}
+ // Number of times CSRNG gets disabled and re-enabled
+ rand uint num_disable_enable;
+ constraint num_disable_enable_c {
+ num_disable_enable >= min_num_disable_enable;
+ num_disable_enable <= max_num_disable_enable;
+ }
+
+ // In tests that disable CSRNG, how many cycles to keep all agents and CSRNG enabled
+ rand uint enable_clks;
+ constraint edn_enable_clks_c {
+ enable_clks >= min_enable_clks;
+ enable_clks <= max_enable_clks;
+ }
+
+ // In tests that disable CSRNG, how many cycles to wait to disable CSRNG after EDN agents have
+ // been disabled
+ rand uint disable_edn_before_csrng_clks;
+ constraint disable_edn_before_csrng_clks_c {
+ disable_edn_before_csrng_clks >= min_disable_edn_before_csrng_clks;
+ disable_edn_before_csrng_clks <= max_disable_edn_before_csrng_clks;
+ }
+
+ // In tests that disable CSRNG, how many cycles to wait to disable entropy_src after CSRNG has
+ // been disabled
+ rand uint disable_csrng_before_entropy_src_clks;
+ constraint disable_csrng_before_entropy_src_clks_c {
+ disable_csrng_before_entropy_src_clks >= min_disable_csrng_before_entropy_src_clks;
+ disable_csrng_before_entropy_src_clks <= max_disable_csrng_before_entropy_src_clks;
+ }
+
+ // In tests that disable CSRNG, how many cycles to keep all agents and CSRNG disabled
+ rand uint disable_clks;
+ constraint disable_clks_c {
+ disable_clks >= min_disable_clks;
+ disable_clks <= max_disable_clks;
+ }
+
+ // In tests that disable CSRNG, how many cycles to enable the entropy_src agent in advance of
+ // CSRNG
+ rand uint enable_entropy_src_before_csrng_clks;
+ constraint enable_entropy_src_before_csrng_clks_c {
+ enable_entropy_src_before_csrng_clks >= min_enable_entropy_src_before_csrng_clks;
+ enable_entropy_src_before_csrng_clks <= max_enable_entropy_src_before_csrng_clks;
+ }
+
+ // In tests that disable CSRNG, how many cycles to enable CSRNG in advance of enabling EDN agents
+ rand uint enable_csrng_before_edn_clks;
+ constraint enable_csrng_before_edn_clks_c {
+ enable_csrng_before_edn_clks >= min_enable_csrng_before_edn_clks;
+ enable_csrng_before_edn_clks <= max_enable_csrng_before_edn_clks;
+ }
+
+ // Re-randomize enable and disable delays. This is intended to be called between iterations in
+ // tests that disable and re-enable CSRNG (and the agents).
+ function automatic void randomize_disable_enable_clks();
+ `DV_CHECK_MEMBER_RANDOMIZE_FATAL(enable_clks)
+ `DV_CHECK_MEMBER_RANDOMIZE_FATAL(disable_edn_before_csrng_clks)
+ `DV_CHECK_MEMBER_RANDOMIZE_FATAL(disable_csrng_before_entropy_src_clks)
+ `DV_CHECK_MEMBER_RANDOMIZE_FATAL(disable_clks)
+ `DV_CHECK_MEMBER_RANDOMIZE_FATAL(enable_entropy_src_before_csrng_clks)
+ `DV_CHECK_MEMBER_RANDOMIZE_FATAL(enable_csrng_before_edn_clks)
+ endfunction
+
// Functions
function void post_randomize();
if (use_invalid_mubi) begin
diff --git a/hw/ip/csrng/dv/env/seq_lib/csrng_cmds_vseq.sv b/hw/ip/csrng/dv/env/seq_lib/csrng_cmds_vseq.sv
index a715a81..b01d5b0 100644
--- a/hw/ip/csrng/dv/env/seq_lib/csrng_cmds_vseq.sv
+++ b/hw/ip/csrng/dv/env/seq_lib/csrng_cmds_vseq.sv
@@ -82,6 +82,20 @@
end
endfunction
+ virtual task csrng_set_enable(bit enable);
+ mubi4_t mubi_en = prim_mubi_pkg::mubi4_bool_to_mubi(enable);
+
+ // Disabling CSRNG may drop an ongoing req to entropy_src. This is generally not allowed in
+ // push_pull_if, but in this case it is allowed because entropy_src is to be disabled and
+ // re-enabled shortly after.
+ `DV_ASSERT_CTRL_REQ("EntropySrcIf_ReqHighUntilAck_A_CTRL", enable)
+
+ // While CSRNG is disabled, entropy_src may ack a previous req that is no longer high.
+ `DV_ASSERT_CTRL_REQ("EntropySrcIf_AckAssertedOnlyWhenReqAsserted_A_CTRL", enable)
+
+ csr_wr(.ptr(ral.ctrl.enable), .value(mubi_en), .blocking(1));
+ endtask
+
task body();
super.body();
@@ -106,33 +120,88 @@
// Send commands
fork
- for (int i = 0; i < NUM_HW_APPS + 1; i++) begin
- automatic int j = i;
- fork
- begin
- foreach (cs_item_q[j][k]) begin
- send_cmd_req(.app(j), .cs_item(cs_item_q[j][k]));
+ fork
+ for (int i = 0; i < NUM_HW_APPS + 1; i++) begin
+ automatic int j = i;
+ fork
+ forever begin
+ automatic csrng_item item;
+ if (cs_item_q[j].size() == 0) begin
+ cfg.clk_rst_vif.wait_clks(1);
+ continue;
+ end
+ item = cs_item_q[j].pop_front();
+ send_cmd_req(.app(j), .cs_item(item));
cmds_sent += 1;
end
- end
- join_none;
- end
+ join_none;
+ end
- do begin
- `uvm_info(`gfn, $sformatf("aes_halt_clks = %0d, cmds_sent = %0d, cmds_gen = %0d",
- aes_halt_clks, cmds_sent, cmds_gen), UVM_DEBUG)
- if (cfg.aes_halt) begin
- `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(aes_halt_clks, aes_halt_clks inside
- { [cfg.min_aes_halt_clks:cfg.max_aes_halt_clks] };)
- cfg.clk_rst_vif.wait_clks(aes_halt_clks);
- m_aes_halt_pull_seq.start(p_sequencer.aes_halt_sequencer_h);
+ forever begin
+ `uvm_info(`gfn, $sformatf("aes_halt_clks = %0d, cmds_sent = %0d, cmds_gen = %0d",
+ aes_halt_clks, cmds_sent, cmds_gen), UVM_DEBUG)
+ if (cfg.aes_halt) begin
+ `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(aes_halt_clks, aes_halt_clks inside
+ { [cfg.min_aes_halt_clks:cfg.max_aes_halt_clks] };)
+ cfg.clk_rst_vif.wait_clks(aes_halt_clks);
+ m_aes_halt_pull_seq.start(p_sequencer.aes_halt_sequencer_h);
+ end
+ else begin
+ cfg.clk_rst_vif.wait_clks(500);
+ end
end
- else begin
- cfg.clk_rst_vif.wait_clks(500);
+ join
+
+ begin
+ // Disable and re-enable CSRNG (as well as EDN and entropy_src agents) at random instants.
+ while (cfg.num_disable_enable > 0) begin
+ cfg.clk_rst_vif.wait_clks(cfg.enable_clks);
+
+ `uvm_info(`gfn, "Disabling EDN.", UVM_LOW)
+ cfg.csrng_agents_vif.drive_edn_disable(1);
+
+ // Clear any items that may remain in the command queues.
+ for (int i = 0; i < NUM_HW_APPS + 1; i++) begin
+ cs_item_q[i].delete();
+ end
+
+ cfg.clk_rst_vif.wait_clks(cfg.disable_edn_before_csrng_clks);
+
+ `uvm_info(`gfn, "Disabling CSRNG.", UVM_LOW)
+ csrng_set_enable(0);
+
+ cfg.clk_rst_vif.wait_clks(cfg.disable_csrng_before_entropy_src_clks);
+
+ `uvm_info(`gfn, "Disabling entropy_src.", UVM_LOW)
+ cfg.csrng_agents_vif.drive_entropy_src_disable(1);
+
+ cfg.clk_rst_vif.wait_clks(cfg.disable_clks);
+
+ `uvm_info(`gfn, "Re-enabling entropy_src.", UVM_LOW)
+ cfg.csrng_agents_vif.drive_entropy_src_disable(0);
+
+ cfg.clk_rst_vif.wait_clks(cfg.enable_entropy_src_before_csrng_clks);
+
+ `uvm_info(`gfn, "Re-enabling CSRNG.", UVM_LOW)
+ csrng_set_enable(1);
+
+ cfg.clk_rst_vif.wait_clks(cfg.enable_csrng_before_edn_clks);
+
+ // Refill command queues.
+ create_cmds_all_apps();
+ print_cmds_all_apps();
+
+ `uvm_info(`gfn, "Re-enabling EDN.", UVM_LOW)
+ cfg.csrng_agents_vif.drive_edn_disable(0);
+
+ cfg.randomize_disable_enable_clks();
+ cfg.num_disable_enable -= 1;
end
+ `DV_WAIT(cmds_sent == cmds_gen)
+ `uvm_info(`gfn, "All commands sent, completing test.", UVM_LOW)
end
- while (cmds_sent < cmds_gen);
- join
+ join_any
+ disable fork;
// Check internal state, then uninstantiate if not already
if (cfg.check_int_state) begin
diff --git a/hw/ip/csrng/dv/tb.sv b/hw/ip/csrng/dv/tb.sv
index 23ecad4..1f0020a 100644
--- a/hw/ip/csrng/dv/tb.sv
+++ b/hw/ip/csrng/dv/tb.sv
@@ -162,4 +162,9 @@
[`CTR_DRBG_UPD.BlkEncAckFifoWidth-1 -: `CTR_DRBG_UPD.BlkLen]) !=
$past(`BLOCK_ENCRYPT_PATH.cipher_data_out, 2), clk, !rst_n)
+ // Assertion controls
+ `DV_ASSERT_CTRL("EntropySrcIf_ReqHighUntilAck_A_CTRL", entropy_src_if.ReqHighUntilAck_A)
+ `DV_ASSERT_CTRL("EntropySrcIf_AckAssertedOnlyWhenReqAsserted_A_CTRL",
+ entropy_src_if.AckAssertedOnlyWhenReqAsserted_A)
+
endmodule
diff --git a/hw/ip/csrng/dv/tests/csrng_cmds_test.sv b/hw/ip/csrng/dv/tests/csrng_cmds_test.sv
index 3d271aa..22c5c7d 100644
--- a/hw/ip/csrng/dv/tests/csrng_cmds_test.sv
+++ b/hw/ip/csrng/dv/tests/csrng_cmds_test.sv
@@ -16,6 +16,20 @@
cfg.min_aes_halt_clks = 400;
cfg.max_aes_halt_clks = 600;
cfg.force_state_pct = 100;
+ cfg.min_num_disable_enable = 0;
+ cfg.max_num_disable_enable = 10;
+ cfg.min_enable_clks = 1;
+ cfg.max_enable_clks = 10000;
+ cfg.min_disable_edn_before_csrng_clks = 10;
+ cfg.max_disable_edn_before_csrng_clks = 200;
+ cfg.min_disable_csrng_before_entropy_src_clks = 10;
+ cfg.max_disable_csrng_before_entropy_src_clks = 200;
+ cfg.min_disable_clks = 20;
+ cfg.max_disable_clks = 200;
+ cfg.min_enable_entropy_src_before_csrng_clks = 10;
+ cfg.max_enable_entropy_src_before_csrng_clks = 200;
+ cfg.min_enable_csrng_before_edn_clks = 10;
+ cfg.max_enable_csrng_before_edn_clks = 200;
for (int i = 0; i < NUM_HW_APPS; i++) begin
// CSRNG has a single AES primitive shared among the three application interfaces. To hit the