[dv/rstmgr] Add dv environment for rstmgr_cnsty_chk
Enable better testability of this V2S module.
Signed-off-by: Guillermo Maturana <maturana@google.com>
diff --git a/hw/ip/rstmgr/dv/rstmgr_cnsty_chk/data/rstmgr_cnsty_chk_testplan.hjson b/hw/ip/rstmgr/dv/rstmgr_cnsty_chk/data/rstmgr_cnsty_chk_testplan.hjson
new file mode 100644
index 0000000..e3413ec
--- /dev/null
+++ b/hw/ip/rstmgr/dv/rstmgr_cnsty_chk/data/rstmgr_cnsty_chk_testplan.hjson
@@ -0,0 +1,43 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+{
+ name: "rstmgr_cnsty_chk"
+ testpoints: [
+ {
+ name: unexpected_child_reset_activity
+ desc: '''Verify unexpected child_reset activity flags an error.
+ '''
+ milestone: V2S
+ tests: ["rstmgr_cnsty_chk_smoke"]
+ }
+ {
+ name: child_reset_asserts_late
+ desc: '''Verify error triggered if child reset asserts late.
+ '''
+ milestone: V2S
+ tests: []
+ }
+ {
+ name: child_reset_releases_late
+ desc: '''Verify error triggered if child reset releases late.
+ '''
+ milestone: V2S
+ tests: []
+ }
+ {
+ name: parent_reset_asserts_late
+ desc: '''Verify error triggered if parent reset asserts late.
+ '''
+ milestone: V2S
+ tests: []
+ }
+ {
+ name: parent_reset_releases_late
+ desc: '''Verify error triggered if parent reset releases late.
+ '''
+ milestone: V2S
+ tests: []
+ }
+ ]
+}
diff --git a/hw/ip/rstmgr/dv/rstmgr_cnsty_chk/rstmgr_cnsty_chk_sim.core b/hw/ip/rstmgr/dv/rstmgr_cnsty_chk/rstmgr_cnsty_chk_sim.core
new file mode 100644
index 0000000..da8d642
--- /dev/null
+++ b/hw/ip/rstmgr/dv/rstmgr_cnsty_chk/rstmgr_cnsty_chk_sim.core
@@ -0,0 +1,32 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:dv:rstmgr_cnsty_chk_sim:0.1"
+description: "Rstmgr_cnsty_chk DV sim target"
+filesets:
+ files_rtl:
+ depend:
+ - lowrisc:ip:rstmgr_cnsty_chk
+ file_type: systemVerilogSource
+
+ files_dv:
+ depend:
+ - lowrisc:dv:dv_utils
+ - lowrisc:dv:dv_test_status
+ - lowrisc:dv:common_ifs
+ files:
+ - tb.sv
+ file_type: systemVerilogSource
+
+targets:
+ sim: &sim_target
+ toplevel: tb
+ filesets:
+ - files_rtl
+ - files_dv
+ default_tool: vcs
+
+ lint:
+ <<: *sim_target
+
diff --git a/hw/ip/rstmgr/dv/rstmgr_cnsty_chk/rstmgr_cnsty_chk_sim_cfg.hjson b/hw/ip/rstmgr/dv/rstmgr_cnsty_chk/rstmgr_cnsty_chk_sim_cfg.hjson
new file mode 100644
index 0000000..eecf954
--- /dev/null
+++ b/hw/ip/rstmgr/dv/rstmgr_cnsty_chk/rstmgr_cnsty_chk_sim_cfg.hjson
@@ -0,0 +1,49 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+{
+ // Name of the sim cfg - typically same as the name of the DUT.
+ name: rstmgr_cnsty_chk
+
+ // Top level dut name (sv module).
+ dut: rstmgr_cnsty_chk
+
+ // Top level testbench name (sv module).
+ tb: tb
+
+ // Simulator used to sign off this block
+ tool: vcs
+
+ // Fusesoc core file used for building the file list.
+ fusesoc_core: lowrisc:dv:rstmgr_cnsty_chk_sim:0.1
+
+ // Testplan hjson file.
+ testplan: "{proj_root}/hw/ip/rstmgr/dv/rstmgr_cnsty_chk/data/rstmgr_cnsty_chk_testplan.hjson"
+
+ // Import additional common sim cfg files.
+ import_cfgs: ["{proj_root}/hw/dv/tools/dvsim/common_sim_cfg.hjson"]
+
+ // Default iterations for all tests - each test entry can override this.
+ reseed: 10
+
+ // List of test specifications.
+ tests: [
+ {
+ name: rstmgr_cnsty_chk_test
+ }
+ ]
+ // List of regressions.
+ regressions: [
+ {
+ name: smoke
+ tests: ["rstmgr_cnsty_chk_test"]
+ }
+ ]
+ overrides: [
+ // This override is in order to pick the autogen rstmgr packages.
+ {
+ name: design_level
+ value: "top"
+ }
+ ]
+}
diff --git a/hw/ip/rstmgr/dv/rstmgr_cnsty_chk/tb.sv b/hw/ip/rstmgr/dv/rstmgr_cnsty_chk/tb.sv
new file mode 100644
index 0000000..a76a404
--- /dev/null
+++ b/hw/ip/rstmgr/dv/rstmgr_cnsty_chk/tb.sv
@@ -0,0 +1,250 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Testbench module for rstmgr_cnsty_chk.
+//
+// Checks that errors are flagged for the following cases.
+// - Child reset going active with inactive reset requests.
+// - Child reset going inactive with active reset requests.
+//
+// NB: The checks are triggered by the reference clock.
+interface rstmgr_cnsty_chk_if;
+ logic child_rst_ni;
+ logic parent_rst_ni;
+ logic sw_rst_req_i;
+ logic sw_rst_req_clr_o;
+ logic err_o;
+ logic fsm_err_o;
+endinterface
+
+class reset_class;
+
+ parameter time ClkPeriod = 10_000;
+ parameter time ChildFastClkPeriod = 6_000;
+ parameter time ChildSlowClkPeriod = 25_000;
+
+ import uvm_pkg::*;
+
+ typedef enum int {
+ OrderChildLags,
+ OrderChildLeads
+ } order_e;
+
+ typedef enum int {
+ TimingOkay,
+ TimingSlow
+ } timing_e;
+
+ typedef enum int {
+ ChildClkFaster,
+ ChildClkSlower
+ } child_clk_e;
+
+ typedef struct packed {
+ order_e order;
+ timing_e timing;
+ } reset_op_t;
+
+ virtual clk_rst_if clk_rst_vif;
+ virtual clk_rst_if child_clk_rst_vif;
+ virtual rstmgr_cnsty_chk_if reset_vif;
+
+ logic error = 0;
+ int cycles_to_check = 7;
+
+ rand int cycles_reset_width;
+ rand int cycles_child_reset_width;
+ rand int cycles_in_apply_resets;
+ rand int cycles_to_child_reset;
+ rand int cycles_to_child_release;
+ rand int cycles_to_parent_reset;
+ rand int cycles_to_parent_release;
+ rand int cycles_to_sw_reset;
+ rand int cycles_to_sw_release;
+
+ constraint cycles_reset_width_c {cycles_reset_width inside {[2 : 10]};}
+ constraint cycles_child_reset_width_c {cycles_child_reset_width inside {[2 : 10]};}
+ constraint cycles_in_apply_resets_c {cycles_in_apply_resets inside {[5 : 25]};}
+ constraint cycles_to_child_reset_c {cycles_to_child_reset inside {[3 : 8]};}
+ constraint cycles_to_child_release_c {cycles_to_child_release inside {[3 : 6]};}
+ constraint cycles_to_parent_reset_c {cycles_to_parent_reset inside {[2 : 8]};}
+ constraint cycles_to_parent_release_c {cycles_to_parent_release inside {[3 : 6]};}
+ constraint cycles_to_sw_reset_c {cycles_to_sw_reset inside {[2 : 8]};}
+ constraint cycles_to_sw_release_c {cycles_to_sw_release inside {[3 : 6]};}
+
+ function new(virtual clk_rst_if clk_vif, virtual clk_rst_if child_clk_vif,
+ virtual rstmgr_cnsty_chk_if rst_vif);
+ clk_rst_vif = clk_vif;
+ child_clk_rst_vif = child_clk_vif;
+ reset_vif = rst_vif;
+ endfunction
+
+ function string get_full_name();
+ return "reset_class";
+ endfunction
+
+ task set_child_period(child_clk_e child_clk);
+ if (child_clk == ChildClkFaster) begin
+ `uvm_info(`gfn, $sformatf(
+ "Setting child clk (%0d ps) faster than reference (%0d ps)",
+ ChildFastClkPeriod,
+ ClkPeriod
+ ), UVM_LOW)
+ child_clk_rst_vif.set_period_ps(ChildFastClkPeriod);
+ end else begin
+ `uvm_info(`gfn, $sformatf(
+ "Setting child clk (%0d ps) slower than reference (%0d ps)",
+ ChildSlowClkPeriod,
+ ClkPeriod
+ ), UVM_LOW)
+ child_clk_rst_vif.set_period_ps(ChildSlowClkPeriod);
+ end
+ endtask
+
+ task apply_resets();
+ fork
+ clk_rst_vif.apply_reset(.reset_width_clks(cycles_reset_width));
+ child_clk_rst_vif.apply_reset(.reset_width_clks(cycles_child_reset_width));
+ begin
+ reset_vif.parent_rst_ni = 1'b0;
+ clk_rst_vif.wait_clks(cycles_in_apply_resets);
+ reset_vif.parent_rst_ni = 1'b1;
+ end
+ join
+ clk_rst_vif.wait_clks(4);
+ endtask
+
+ task set_quiescent();
+ `uvm_info(`gfn, "Setting quiescent inputs", UVM_MEDIUM)
+ reset_vif.parent_rst_ni = 1'b1;
+ reset_vif.sw_rst_req_i = 1'b0;
+ reset_vif.child_rst_ni = 1'b1;
+ endtask
+
+ task set_parent_reset(logic value, int cycles);
+ clk_rst_vif.wait_clks(cycles_to_parent_reset);
+ `uvm_info(`gfn, $sformatf("Setting parent_rst_ni=%b", value), UVM_MEDIUM)
+ reset_vif.parent_rst_ni = value;
+ endtask
+
+ task set_sw_reset(logic value, int cycles);
+ clk_rst_vif.wait_clks(cycles_to_sw_reset);
+ `uvm_info(`gfn, $sformatf("Setting sw_rst_req_i=%b", value), UVM_MEDIUM)
+ reset_vif.sw_rst_req_i = value;
+ endtask
+
+ task set_child_reset(logic value, int cycles);
+ clk_rst_vif.wait_clks(cycles);
+ `uvm_info(`gfn, $sformatf("Setting child_rst_ni=%b", value), UVM_MEDIUM)
+ reset_vif.child_rst_ni = value;
+ endtask
+
+ task send_unexpected_child_resets();
+ `uvm_info(`gfn, "check unexpected active child reset", UVM_MEDIUM)
+ set_child_reset(.value(0), .cycles(cycles_to_child_reset));
+ clk_rst_vif.wait_clks(cycles_to_check);
+ `DV_CHECK_EQ(reset_vif.err_o, 1'b1, "expected error for unexpected active child reset")
+ clk_rst_vif.wait_clks(cycles_to_child_release);
+ reset_vif.child_rst_ni = 1'b1;
+ endtask
+
+ task send_unexpected_child_release();
+ `uvm_info(`gfn, "check unexpected inactive child reset", UVM_MEDIUM)
+ fork
+ set_parent_reset(.value(0), .cycles(cycles_to_parent_reset));
+ set_sw_reset(.value(1), .cycles(cycles_to_sw_reset));
+ set_child_reset(.value(0), .cycles(cycles_to_child_reset));
+ join
+ clk_rst_vif.wait_clks(cycles_to_child_release);
+ reset_vif.child_rst_ni = 1'b1;
+ clk_rst_vif.wait_clks(cycles_to_check);
+ `uvm_info(`gfn, "Checking err_o output", UVM_MEDIUM)
+ `DV_CHECK_EQ(reset_vif.err_o, 1'b1, "expected error for unexpected inactive child reset")
+ endtask
+
+ task unexpected_child_activity();
+ `uvm_info(`gfn, "checking unexpected child activity", UVM_LOW)
+ for (int i = 0; i < 20; ++i) begin
+ set_quiescent();
+ `DV_CHECK_RANDOMIZE_FATAL(this);
+
+ send_unexpected_child_resets();
+ // Expect an error, so reset the dut.
+ apply_resets();
+
+ send_unexpected_child_release();
+ apply_resets();
+ end
+ endtask
+
+ task body();
+ clk_rst_vif.set_period_ps(ClkPeriod);
+ clk_rst_vif.set_active();
+ child_clk_rst_vif.set_period_ps(ChildFastClkPeriod);
+ child_clk_rst_vif.set_active();
+ `DV_CHECK_RANDOMIZE_FATAL(this);
+
+ apply_resets();
+ set_quiescent();
+
+ // Run with child clock faster than reference.
+ set_child_period(ChildClkFaster);
+ clk_rst_vif.wait_clks(20);
+
+ unexpected_child_activity();
+
+ // Run with child clock slower than reference.
+ set_child_period(ChildClkSlower);
+ clk_rst_vif.wait_clks(20);
+
+ unexpected_child_activity();
+ endtask
+endclass
+
+module tb;
+
+ import uvm_pkg::*;
+
+ reset_class reset_cl;
+
+ wire clk_i;
+ wire rst_ni;
+ wire child_clk_i;
+ wire unused_child_rst_ni;
+
+ clk_rst_if clk_rst_if (
+ .clk (clk_i),
+ .rst_n(rst_ni)
+ );
+ clk_rst_if child_clk_rst_if (
+ .clk (child_clk_i),
+ .rst_n(unused_child_rst_ni)
+ );
+ rstmgr_cnsty_chk_if rstmgr_cnsty_chk_if ();
+
+ logic error = 0;
+
+ rstmgr_cnsty_chk dut (
+ .clk_i(clk_i),
+ .rst_ni(rst_ni),
+ .child_clk_i(child_clk_i),
+ .child_rst_ni(rstmgr_cnsty_chk_if.child_rst_ni),
+ .parent_rst_ni(rstmgr_cnsty_chk_if.parent_rst_ni),
+ .sw_rst_req_i(rstmgr_cnsty_chk_if.sw_rst_req_i),
+ .sw_rst_req_clr_o(rstmgr_cnsty_chk_if.sw_rst_req_clr_o),
+ .err_o(rstmgr_cnsty_chk_if.err_o),
+ .fsm_err_o(rstmgr_cnsty_chk_if.fsm_err_o)
+ );
+
+ initial begin
+ automatic dv_utils_pkg::dv_report_server dv_report_server = new();
+ $timeformat(-12, 0, " ps", 12);
+ uvm_report_server::set_server(dv_report_server);
+ reset_cl = new(clk_rst_if, child_clk_rst_if, rstmgr_cnsty_chk_if);
+ reset_cl.body();
+ dv_report_server.report_summarize();
+ $finish();
+ end
+
+endmodule : tb
diff --git a/hw/ip/rstmgr/rstmgr.core b/hw/ip/rstmgr/rstmgr.core
index 2bfcf46..7339482 100644
--- a/hw/ip/rstmgr/rstmgr.core
+++ b/hw/ip/rstmgr/rstmgr.core
@@ -18,12 +18,12 @@
- lowrisc:prim:sparse_fsm
- "fileset_ip ? (lowrisc:ip:rstmgr_pkg)"
- "fileset_top ? (lowrisc:systems:rstmgr_pkg)"
+ - lowrisc:ip:rstmgr_cnsty_chk
- "fileset_top ? (lowrisc:systems:rstmgr)"
- "fileset_topgen ? (lowrisc:systems:topgen)"
files:
- rtl/rstmgr_ctrl.sv
- rtl/rstmgr_por.sv
- - rtl/rstmgr_cnsty_chk.sv
- rtl/rstmgr_crash_info.sv
- rtl/rstmgr_leaf_rst.sv
- "fileset_ip ? (rtl/rstmgr.sv)"
diff --git a/hw/ip/rstmgr/rstmgr_cnsty_chk.core b/hw/ip/rstmgr/rstmgr_cnsty_chk.core
new file mode 100644
index 0000000..de70135
--- /dev/null
+++ b/hw/ip/rstmgr/rstmgr_cnsty_chk.core
@@ -0,0 +1,43 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+name: "lowrisc:ip:rstmgr_cnsty_chk"
+description: "Rstmgr consistency checker"
+filesets:
+ files_rtl:
+ depend:
+ - lowrisc:prim:assert
+ - lowrisc:prim:sparse_fsm
+ - lowrisc:ip:rv_core_ibex_pkg
+ - "fileset_ip ? (lowrisc:ip:rstmgr_pkg)"
+ - "fileset_top ? (lowrisc:systems:rstmgr_pkg)"
+ - "fileset_top ? (lowrisc:systems:rstmgr)"
+ - "fileset_topgen ? (lowrisc:systems:topgen)"
+ files:
+ - rtl/rstmgr_cnsty_chk.sv
+ file_type: systemVerilogSource
+
+ files_verilator_waiver:
+ depend:
+ # common waivers
+ - lowrisc:lint:common
+
+ files_ascentlint_waiver:
+ depend:
+ # common waivers
+ - lowrisc:lint:common
+
+ files_veriblelint_waiver:
+ depend:
+ # common waivers
+ - lowrisc:lint:common
+
+targets:
+ default:
+ filesets:
+ - tool_verilator ? (files_verilator_waiver)
+ - tool_ascentlint ? (files_ascentlint_waiver)
+ - tool_veriblelint ? (files_veriblelint_waiver)
+ - files_rtl
diff --git a/hw/ip/rstmgr/rtl/rstmgr_cnsty_chk.sv b/hw/ip/rstmgr/rtl/rstmgr_cnsty_chk.sv
index d178786..d439d7f 100644
--- a/hw/ip/rstmgr/rtl/rstmgr_cnsty_chk.sv
+++ b/hw/ip/rstmgr/rtl/rstmgr_cnsty_chk.sv
@@ -114,7 +114,8 @@
prim_sparse_fsm_flop #(
.StateEnumT(state_e),
.Width(StateWidth),
- .ResetValue(StateWidth'(Reset))
+ .ResetValue(StateWidth'(Reset)),
+ .EnableAlertTriggerSVA(0)
) u_state_regs (
.clk_i,
.rst_ni,
@@ -148,6 +149,7 @@
logic sync_child_ack;
+ // TODO - make this a sparse fsm
always_comb begin
state_d = state_q;
err_o = '0;
diff --git a/hw/top_earlgrey/dv/top_earlgrey_sim_cfgs.hjson b/hw/top_earlgrey/dv/top_earlgrey_sim_cfgs.hjson
index 4d6fbc1..ff99dc8 100644
--- a/hw/top_earlgrey/dv/top_earlgrey_sim_cfgs.hjson
+++ b/hw/top_earlgrey/dv/top_earlgrey_sim_cfgs.hjson
@@ -44,6 +44,7 @@
"{proj_root}/hw/ip/pwm/dv/pwm_sim_cfg.hjson",
"{proj_root}/hw/ip/pwrmgr/dv/pwrmgr_sim_cfg.hjson",
"{proj_root}/hw/ip/rom_ctrl/dv/rom_ctrl_sim_cfg.hjson",
+ "{proj_root}/hw/ip/rstmgr/dv/rstmgr_cnsty_chk/rstmgr_cnsty_chk_sim_cfg.hjson",
"{proj_root}/hw/ip/rstmgr/dv/rstmgr_sim_cfg.hjson",
"{proj_root}/hw/ip/rv_timer/dv/rv_timer_sim_cfg.hjson",
"{proj_root}/hw/ip/spi_host/dv/spi_host_sim_cfg.hjson",