[dv/rstmgr] Drive por_n_i[1] and bind SVA to chip
Set por_n_i[1] to non-zero values in unit tests.
If por_n_i[1] is always 0, a number of assertion failures are masked.
Full chip sets por_n_i[1] to non-zero values, which exposed failures.
Add missing assertions for some resets_o members.
Tighten some assertions.
Signed-off-by: Guillermo Maturana <maturana@google.com>
diff --git a/hw/ip/rstmgr/dv/env/rstmgr_if.sv b/hw/ip/rstmgr/dv/env/rstmgr_if.sv
index df298d3..a929a37 100644
--- a/hw/ip/rstmgr/dv/env/rstmgr_if.sv
+++ b/hw/ip/rstmgr/dv/env/rstmgr_if.sv
@@ -11,7 +11,7 @@
);
import rstmgr_env_pkg::*;
- import rstmgr_pkg::*;
+ import rstmgr_pkg::PowerDomains;
logic [PowerDomains-1:0] por_n;
diff --git a/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_base_vseq.sv b/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_base_vseq.sv
index 8fa2150..33e0d3b 100644
--- a/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_base_vseq.sv
+++ b/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_base_vseq.sv
@@ -246,9 +246,9 @@
endtask
task por_reset();
- cfg.rstmgr_vif.por_n = 1'b0;
+ cfg.rstmgr_vif.por_n = '0;
cfg.aon_clk_rst_vif.wait_clks(POR_CLK_CYCLES);
- cfg.rstmgr_vif.por_n = 1'b1;
+ cfg.rstmgr_vif.por_n = '1;
@(posedge cfg.rstmgr_vif.resets_o.rst_por_io_div4_n[0]);
endtask
diff --git a/hw/ip/rstmgr/dv/sva/rstmgr_bind.sv b/hw/ip/rstmgr/dv/sva/rstmgr_bind.sv
index 1c78438..b6b70cc 100644
--- a/hw/ip/rstmgr/dv/sva/rstmgr_bind.sv
+++ b/hw/ip/rstmgr/dv/sva/rstmgr_bind.sv
@@ -33,6 +33,8 @@
.clk_usb_i,
.por_n_i,
.resets_o,
+ .rst_lc_req(pwr_i.rst_lc_req),
+ .rst_sys_req(pwr_i.rst_sys_req),
.rst_lc_src_n(pwr_o.rst_lc_src_n),
.rst_sys_src_n(pwr_o.rst_sys_src_n),
.scan_rst_ni,
diff --git a/hw/ip/rstmgr/dv/sva/rstmgr_cascading_sva_if.sv b/hw/ip/rstmgr/dv/sva/rstmgr_cascading_sva_if.sv
index 18a844c..87d624f 100644
--- a/hw/ip/rstmgr/dv/sva/rstmgr_cascading_sva_if.sv
+++ b/hw/ip/rstmgr/dv/sva/rstmgr_cascading_sva_if.sv
@@ -9,6 +9,9 @@
// In addition, a scan reset is at the same level as por.
//
// Local terminology: A cascading relationship is between an "above" and a "below" reset.
+//
+// Some individual reset outputs will always be off. Allowing for this in general would
+// weaken the property that some resets MUST rise following other rise.
interface rstmgr_cascading_sva_if (
input logic clk_i,
input logic clk_aon_i,
@@ -19,6 +22,8 @@
input logic clk_usb_i,
input [rstmgr_pkg::PowerDomains-1:0] por_n_i,
input rstmgr_pkg::rstmgr_out_t resets_o,
+ input [rstmgr_pkg::PowerDomains-1:0] rst_lc_req,
+ input [rstmgr_pkg::PowerDomains-1:0] rst_sys_req,
input [rstmgr_pkg::PowerDomains-1:0] rst_lc_src_n,
input [rstmgr_pkg::PowerDomains-1:0] rst_sys_src_n,
input logic scan_rst_ni,
@@ -48,7 +53,7 @@
// Cycles are counted from the output rst_por_aon_n or scan reset edges. The rise times can be
// higher since in the chip the aon reset goes through the pwrmgr slow fsm where it causes an
// lc rise request and there may be multiple synchronizers in the path.
- localparam edge_bounds_t LcCycles = '{fall: '{min: 0, max: 4}, rise: '{min: 2, max: 10}};
+ localparam edge_bounds_t LcCycles = '{fall: '{min: 0, max: 4}, rise: '{min: 1, max: 4}};
// In the real system the rise of rst_lc_src_n is triggered by the pwr_i.rst_lc_req input,
// which can take a few cycles since it comes from the pwrmgr after it gets reset,
@@ -56,7 +61,7 @@
// a rise in rst_lc_src_n. There is an SVA for the rise in pwrmgr_rstmgr_sva_if.
// The cycles are counted from Lc edges.
- localparam edge_bounds_t SysCycles = '{fall: '{min: 0, max: 4}, rise: '{min: 0, max: 8}};
+ localparam edge_bounds_t SysCycles = '{fall: '{min: 0, max: 2}, rise: '{min: 1, max: 5}};
// The different peripheral edges are synchronized to their respective clocks,
// so these counts assume synchronization and are triggered on the correct clock.
@@ -65,43 +70,37 @@
bit disable_sva;
// Macros to avoid excessive boiler-plate code below.
- `define FALL_ASSERT(name, from, to, cycles, clk) \
- `ASSERT(name``AboveFallBelowHigh_A, \
- $fell(from) && to |-> ##[cycles.fall.min:cycles.fall.max] $fell(to), clk, disable_sva)
+ `define FALL_ASSERT(_name, _from, _to, _cycles, _clk) \
+ `ASSERT(_name``AboveFallBelowHigh_A, \
+ $fell(_from) && _to |-> ##[_cycles.fall.min:_cycles.fall.max] $fell(_to), _clk, \
+ disable_sva)
- `define RISE_ASSERTS(name, from, to, cycles, clk) \
- `ASSERT(name``AboveRise_A, \
- $rose(from) |-> ##[cycles.rise.min:cycles.rise.max] $rose(to), clk, disable_sva) \
- `ASSERT(name``BelowRise_A, \
- $rose(to) |-> from == 1'b1, clk, disable_sva)
+ `define RISE_ASSERTS(_name, _from, _to, _cycles, _clk) \
+ `ASSERT(_name``AboveRise_A, \
+ $rose(_from) |-> ##[_cycles.rise.min:_cycles.rise.max] (!_from || $rose(_to)), _clk, \
+ disable_sva) \
+ `ASSERT(_name``BelowRise_A, $rose(_to) |-> _from == 1'b1, _clk, disable_sva)
- `define CASCADED_ASSERTS(name, from, to, cycles, clk) \
- `FALL_ASSERT(name, from, to, cycles, clk) \
- `RISE_ASSERTS(name, from, to, cycles, clk)
+ `define CASCADED_ASSERTS(_name, _from, _to, _cycles, _clk) \
+ `FALL_ASSERT(_name, _from, _to, _cycles, _clk) \
+ `RISE_ASSERTS(_name, _from, _to, _cycles, _clk)
// A fall in por_n_i leads to a fall in rst_por_aon_n[0].
- `FALL_ASSERT(CascadePorToAon, por_n_i[rstmgr_pkg::DomainAonSel], resets_o.rst_por_aon_n[0],
- PorCycles, clk_aon_i)
+ `FALL_ASSERT(CascadePorToAon, por_n_i[rstmgr_pkg::DomainAonSel],
+ resets_o.rst_por_aon_n[rstmgr_pkg::DomainAonSel], PorCycles, clk_aon_i)
// A number of consecutive cycles with por_n_i inactive (high) should cause the aon resets to
// become inactive. This checks POR stretching.
- // The antecedent: por_n_i rising and being stably high for a minimum number of cycles.
+ // The antecedent: por_n_i rising and being active for enough cycles.
sequence PorStable_S;
$rose(
por_n_i[rstmgr_pkg::DomainAonSel]
- ) ##1 por_n_i[rstmgr_pkg::DomainAonSel] [* PorCycles.rise.min];
- endsequence
-
- // The consequence: reset will rise after some cycles.
- sequence EventualAonRstRise_S;
- ##[0:PorCycles.rise.max-PorCycles.rise.min] $rose(
- resets_o.rst_por_aon_n[0]
- );
+ ) ##1 (por_n_i[rstmgr_pkg::DomainAonSel] [* PorCycles.rise.max]);
endsequence
// The reset stretching assertion.
- `ASSERT(StablePorToAonRise_A, PorStable_S |-> EventualAonRstRise_S, clk_aon_i, disable_sva)
+ `ASSERT(StablePorToAonRise_A, PorStable_S |-> resets_o.rst_por_aon_n[0], clk_aon_i, disable_sva)
logic scan_reset_n;
always_comb scan_reset_n = scan_rst_ni || (scanmode_i != lc_ctrl_pkg::On);
@@ -111,53 +110,82 @@
// The internal reset is triggered by one of the generated reset outputs.
logic [rstmgr_pkg::PowerDomains-1:0] local_rst_n;
- always_comb local_rst_n = {rstmgr_pkg::PowerDomains{resets_o.rst_por_io_div4_n[0]}};
+ always_comb
+ local_rst_n = {rstmgr_pkg::PowerDomains{resets_o.rst_por_io_div4_n[rstmgr_pkg::DomainAonSel]}};
- for (genvar pd = 0; pd < rstmgr_pkg::PowerDomains; ++pd) begin : power_domains
- // The AON reset triggers the various por reset for the different clock domains through
- // syncronizers.
- `CASCADED_ASSERTS(CascadeEffAonToRstPor, effective_aon_rst[pd], resets_o.rst_por_n[pd],
- SyncCycles, clk_main_i)
- `CASCADED_ASSERTS(CascadeEffAonToRstPorIo, effective_aon_rst[pd], resets_o.rst_por_io_n[pd],
- SyncCycles, clk_io_i)
- `CASCADED_ASSERTS(CascadeEffAonToRstPorIoDiv2, effective_aon_rst[pd],
- resets_o.rst_por_io_div2_n[pd], SyncCycles, clk_io_div2_i)
+ for (genvar pd = 0; pd < rstmgr_pkg::PowerDomains; ++pd) begin : g_power_domains
+ // The AON reset triggers the various POR reset for the different clock domains through
+ // synchronizers.
`CASCADED_ASSERTS(CascadeEffAonToRstPorIoDiv4, effective_aon_rst[pd],
resets_o.rst_por_io_div4_n[pd], SyncCycles, clk_io_div4_i)
- `CASCADED_ASSERTS(CascadeEffAonToRstPorUcb, effective_aon_rst[pd], resets_o.rst_por_usb_n[pd],
- SyncCycles, clk_usb_i)
// The root lc reset is triggered either by the internal reset, or by the pwr_i.rst_lc_req
// input. The latter is checked independently in pwrmgr_rstmgr_sva_if.
- `CASCADED_ASSERTS(CascadeLocalRstToLc, local_rst_n[pd], rst_lc_src_n[pd], LcCycles, clk_i)
+ `CASCADED_ASSERTS(CascadeLocalRstToLc, local_rst_n[pd] && !rst_lc_req[pd], rst_lc_src_n[pd],
+ LcCycles, clk_i)
// The root sys reset is triggered by the lc reset, or independently by external requests.
// The latter is checked independently in pwrmgr_rstmgr_sva_if.
- `CASCADED_ASSERTS(CascadeLcToSys, rst_lc_src_n[pd], rst_sys_src_n[pd], SysCycles, clk_i)
+ `CASCADED_ASSERTS(CascadeLcToSys, rst_lc_src_n[pd] && !rst_sys_req[pd], rst_sys_src_n[pd],
+ SysCycles, clk_i)
+
+ // Controlled by rst_lc_src_n.
+ `CASCADED_ASSERTS(CascadeLcToLcIoDiv4, rst_lc_src_n[pd], resets_o.rst_lc_io_div4_n[pd],
+ SysCycles, clk_io_div4_i)
+ `CASCADED_ASSERTS(CascadeLcToLcIoDiv4Shadowed, rst_lc_src_n[pd],
+ resets_o.rst_lc_io_div4_shadowed_n[pd], SysCycles, clk_io_div4_i)
+
+ // Controlled by rst_sys_src_n.
+ `CASCADED_ASSERTS(CascadeSysToSysAon, rst_sys_src_n[pd], resets_o.rst_sys_aon_n[pd], SysCycles,
+ clk_aon_i)
+ `CASCADED_ASSERTS(CascadeSysToSysIoDiv4, rst_sys_src_n[pd], resets_o.rst_sys_io_div4_n[pd],
+ SysCycles, clk_io_div4_i)
end
+ // Aon to POR
+ `CASCADED_ASSERTS(CascadeEffAonToRstPor, effective_aon_rst[rstmgr_pkg::DomainAonSel],
+ resets_o.rst_por_n[rstmgr_pkg::DomainAonSel], SyncCycles, clk_main_i)
+ `CASCADED_ASSERTS(CascadeEffAonToRstPorIo, effective_aon_rst[rstmgr_pkg::DomainAonSel],
+ resets_o.rst_por_io_n[rstmgr_pkg::DomainAonSel], SyncCycles, clk_io_i)
+ `CASCADED_ASSERTS(CascadeEffAonToRstPorIoDiv2, effective_aon_rst[rstmgr_pkg::DomainAonSel],
+ resets_o.rst_por_io_div2_n[rstmgr_pkg::DomainAonSel], SyncCycles, clk_io_div2_i)
+ `CASCADED_ASSERTS(CascadeEffAonToRstPorUcb, effective_aon_rst[rstmgr_pkg::DomainAonSel],
+ resets_o.rst_por_usb_n[rstmgr_pkg::DomainAonSel], SyncCycles, clk_usb_i)
+
+ // Controlled by rst_lc_src_n.
+ `CASCADED_ASSERTS(CascadeLcToLcAon, rst_lc_src_n[rstmgr_pkg::DomainAonSel],
+ resets_o.rst_lc_aon_n[rstmgr_pkg::DomainAonSel], SysCycles, clk_aon_i)
+ `CASCADED_ASSERTS(CascadeLcToLc, rst_lc_src_n[rstmgr_pkg::Domain0Sel],
+ resets_o.rst_lc_n[rstmgr_pkg::Domain0Sel], SysCycles, clk_main_i)
+
+ // Controlled by rst_sys_src_n.
+ `CASCADED_ASSERTS(CascadeSysToSys, rst_sys_src_n[rstmgr_pkg::Domain0Sel],
+ resets_o.rst_sys_n[rstmgr_pkg::Domain0Sel], PeriCycles, clk_main_i)
+ `CASCADED_ASSERTS(CascadeSysToSysShadowed, rst_sys_src_n[rstmgr_pkg::Domain0Sel],
+ resets_o.rst_sys_shadowed_n[rstmgr_pkg::Domain0Sel], SysCycles, clk_main_i)
+
// Peripheral resets cascade from sys.
// We only care for power domain 1 for peripherals.
- `CASCADED_ASSERTS(CascadeSysToSpiDevice, rst_sys_src_n[1], resets_o.rst_spi_device_n[1],
- PeriCycles, clk_io_div4_i)
- `CASCADED_ASSERTS(CascadeSysToSpiHost0, rst_sys_src_n[1], resets_o.rst_spi_host0_n[1], PeriCycles,
- clk_io_div4_i)
- `CASCADED_ASSERTS(CascadeSysToSpiHost0Core, rst_sys_src_n[1], resets_o.rst_spi_host0_core_n[1],
- PeriCycles, clk_io_i)
- `CASCADED_ASSERTS(CascadeSysToSpiHost1, rst_sys_src_n[1], resets_o.rst_spi_host1_n[1], PeriCycles,
- clk_io_div4_i)
- `CASCADED_ASSERTS(CascadeSysToSpiHost1Core, rst_sys_src_n[1], resets_o.rst_spi_host1_core_n[1],
- PeriCycles, clk_io_i)
- `CASCADED_ASSERTS(CascadeSysToUsb, rst_sys_src_n[1], resets_o.rst_usb_n[1], PeriCycles,
- clk_io_div4_i)
- `CASCADED_ASSERTS(CascadeSysToUsbIf, rst_sys_src_n[1], resets_o.rst_usbif_n[1], PeriCycles,
- clk_usb_i)
- `CASCADED_ASSERTS(CascadeSysToI2C0, rst_sys_src_n[1], resets_o.rst_i2c0_n[1], PeriCycles,
- clk_io_div4_i)
- `CASCADED_ASSERTS(CascadeSysToI2C1, rst_sys_src_n[1], resets_o.rst_i2c1_n[1], PeriCycles,
- clk_io_div4_i)
- `CASCADED_ASSERTS(CascadeSysToI2C2, rst_sys_src_n[1], resets_o.rst_i2c2_n[1], PeriCycles,
- clk_io_div4_i)
+ `CASCADED_ASSERTS(CascadeSysToSpiDevice, rst_sys_src_n[rstmgr_pkg::Domain0Sel],
+ resets_o.rst_spi_device_n[rstmgr_pkg::Domain0Sel], PeriCycles, clk_io_div4_i)
+ `CASCADED_ASSERTS(CascadeSysToSpiHost0, rst_sys_src_n[rstmgr_pkg::Domain0Sel],
+ resets_o.rst_spi_host0_n[rstmgr_pkg::Domain0Sel], PeriCycles, clk_io_div4_i)
+ `CASCADED_ASSERTS(CascadeSysToSpiHost0Core, rst_sys_src_n[rstmgr_pkg::Domain0Sel],
+ resets_o.rst_spi_host0_core_n[rstmgr_pkg::Domain0Sel], PeriCycles, clk_io_i)
+ `CASCADED_ASSERTS(CascadeSysToSpiHost1, rst_sys_src_n[rstmgr_pkg::Domain0Sel],
+ resets_o.rst_spi_host1_n[rstmgr_pkg::Domain0Sel], PeriCycles, clk_io_div4_i)
+ `CASCADED_ASSERTS(CascadeSysToSpiHost1Core, rst_sys_src_n[rstmgr_pkg::Domain0Sel],
+ resets_o.rst_spi_host1_core_n[rstmgr_pkg::Domain0Sel], PeriCycles, clk_io_i)
+ `CASCADED_ASSERTS(CascadeSysToUsb, rst_sys_src_n[rstmgr_pkg::Domain0Sel],
+ resets_o.rst_usb_n[rstmgr_pkg::Domain0Sel], PeriCycles, clk_io_div4_i)
+ `CASCADED_ASSERTS(CascadeSysToUsbIf, rst_sys_src_n[rstmgr_pkg::Domain0Sel],
+ resets_o.rst_usbif_n[rstmgr_pkg::Domain0Sel], PeriCycles, clk_usb_i)
+ `CASCADED_ASSERTS(CascadeSysToI2C0, rst_sys_src_n[rstmgr_pkg::Domain0Sel],
+ resets_o.rst_i2c0_n[rstmgr_pkg::Domain0Sel], PeriCycles, clk_io_div4_i)
+ `CASCADED_ASSERTS(CascadeSysToI2C1, rst_sys_src_n[rstmgr_pkg::Domain0Sel],
+ resets_o.rst_i2c1_n[rstmgr_pkg::Domain0Sel], PeriCycles, clk_io_div4_i)
+ `CASCADED_ASSERTS(CascadeSysToI2C2, rst_sys_src_n[rstmgr_pkg::Domain0Sel],
+ resets_o.rst_i2c2_n[rstmgr_pkg::Domain0Sel], PeriCycles, clk_io_div4_i)
`undef FALL_ASSERT
`undef RISE_ASSERTS
`undef CASCADED_ASSERTS
diff --git a/hw/top_earlgrey/dv/chip_sim.core b/hw/top_earlgrey/dv/chip_sim.core
index f8ff6c4..ab30c17 100644
--- a/hw/top_earlgrey/dv/chip_sim.core
+++ b/hw/top_earlgrey/dv/chip_sim.core
@@ -15,6 +15,7 @@
- lowrisc:ip:tlul
- lowrisc:dv:chip_test
- lowrisc:dv:pwrmgr_sva
+ - lowrisc:dv:rstmgr_sva
- lowrisc:dv:xbar_main_bind
- lowrisc:dv:xbar_peri_bind
- lowrisc:dv:xbar_test
diff --git a/hw/top_earlgrey/dv/chip_sim_cfg.hjson b/hw/top_earlgrey/dv/chip_sim_cfg.hjson
index 09995e6..37044bc 100644
--- a/hw/top_earlgrey/dv/chip_sim_cfg.hjson
+++ b/hw/top_earlgrey/dv/chip_sim_cfg.hjson
@@ -25,6 +25,7 @@
// Add additional tops for simulation.
sim_tops: ["pwrmgr_bind",
+ "rstmgr_bind",
"xbar_main_bind",
"xbar_peri_bind"]