[prim_mubi] Fix sampling issue in MUBI sync assertions
Fix #15234
Signed-off-by: Michael Schaffner <msf@google.com>
diff --git a/hw/ip/prim/rtl/prim_lc_sync.sv b/hw/ip/prim/rtl/prim_lc_sync.sv
index ccfd748..7293135 100644
--- a/hw/ip/prim/rtl/prim_lc_sync.sv
+++ b/hw/ip/prim/rtl/prim_lc_sync.sv
@@ -46,13 +46,29 @@
.d_i(lc_en_i),
.q_o(lc_en)
);
- // Without the sampled rst_ni pre-condition, this may cause false assertion failures
- // right after a reset release, since the "iff disable" condition with the rst_ni is
- // sampled in the "observed" SV scheduler region after all assignments have been
- // evaluated. This is a simulation artifact due to reset synchronization in RTL, which
- // releases rst_ni on the active clock edge. This causes the assertion to evaluate
- // although the reset was actually 0 when entering this simulation cycle.
- `ASSERT(OutputDelay_A, rst_ni |-> ##2 lc_en_o == {NumCopies{$past(lc_en_i, 2)}})
+
+// Note regarding SVA below:
+//
+// 1) Without the sampled rst_ni pre-condition, this may cause false assertion failures right after
+// a reset release, since the "disable iff" condition with the rst_ni is sampled in the "observed"
+// SV scheduler region after all assignments have been evaluated (see also LRM section 16.12, page
+// 423). This is a simulation artifact due to reset synchronization in RTL, which releases rst_ni
+// on the active clock edge. This causes the assertion to evaluate although the reset was actually
+// 0 when entering this simulation cycle.
+//
+// 2) Similarly to 1) there can be sampling mismatches of the lc_en_i signal since that signal may
+// originate from a different clock domain. I.e., in cases where the lc_en_i signal changes exactly
+// at the same time that the clk_i signal rises, the SVA will not pick up that change in that clock
+// cycle, whereas RTL will because SVAs sample values in the "preponed" region. To that end we make
+// use of an RTL helper variable to sample the lc_en_i signal, hence ensuring that there are no
+// sampling mismatches.
+`ifdef INC_ASSERT
+ lc_ctrl_pkg::lc_tx_t lc_en_in_sva_q;
+ always_ff @(posedge clk_i) begin
+ lc_en_in_sva_q <= lc_en_i;
+ end
+ `ASSERT(OutputDelay_A, rst_ni |-> ##2 lc_en_o == {NumCopies{$past(lc_en_in_sva_q, 1)}})
+`endif
end else begin : gen_no_flops
// This unused companion logic helps remove lint errors
// for modules where clock and reset are used for assertions only
diff --git a/hw/ip/prim/rtl/prim_mubi12_sync.sv b/hw/ip/prim/rtl/prim_mubi12_sync.sv
index a48b3ed..19605fe 100644
--- a/hw/ip/prim/rtl/prim_mubi12_sync.sv
+++ b/hw/ip/prim/rtl/prim_mubi12_sync.sv
@@ -101,17 +101,39 @@
);
end
+// Note regarding SVAs below:
+//
+// 1) Without the sampled rst_ni pre-condition, this may cause false assertion failures right after
+// a reset release, since the "disable iff" condition with the rst_ni is sampled in the "observed"
+// SV scheduler region after all assignments have been evaluated (see also LRM section 16.12, page
+// 423). This is a simulation artifact due to reset synchronization in RTL, which releases rst_ni
+// on the active clock edge. This causes the assertion to evaluate although the reset was actually
+// 0 when entering this simulation cycle.
+//
+// 2) Similarly to 1) there can be sampling mismatches of the lc_en_i signal since that signal may
+// originate from a different clock domain. I.e., in cases where the lc_en_i signal changes exactly
+// at the same time that the clk_i signal rises, the SVA will not pick up that change in that clock
+// cycle, whereas RTL will because SVAs sample values in the "preponed" region. To that end we make
+// use of an RTL helper variable to sample the lc_en_i signal, hence ensuring that there are no
+// sampling mismatches.
+`ifdef INC_ASSERT
+ mubi12_t mubi_in_sva_q;
+ always_ff @(posedge clk_i) begin
+ mubi_in_sva_q <= mubi_i;
+ end
`ASSERT(OutputIfUnstable_A, sig_unstable |-> mubi_o == {NumCopies{reset_value}})
- `ASSERT(OutputDelay_A, ##3 !sig_unstable |-> mubi_o == {NumCopies{$past(mubi_i, 3)}})
+ `ASSERT(OutputDelay_A, rst_ni |-> ##3 sig_unstable ||
+ mubi_o == {NumCopies{$past(mubi_in_sva_q, 2)}})
+`endif
end else begin : gen_no_stable_chks
assign mubi = mubi_sync;
- // Without the sampled rst_ni pre-condition, this may cause false assertion failures
- // right after a reset release, since the "iff disable" condition with the rst_ni is
- // sampled in the "observed" SV scheduler region after all assignments have been
- // evaluated. This is a simulation artifact due to reset synchronization in RTL, which
- // releases rst_ni on the active clock edge. This causes the assertion to evaluate
- // although the reset was actually 0 when entering this simulation cycle.
- `ASSERT(OutputDelay_A, rst_ni |-> ##2 mubi_o == {NumCopies{$past(mubi_i, 2)}})
+`ifdef INC_ASSERT
+ mubi12_t mubi_in_sva_q;
+ always_ff @(posedge clk_i) begin
+ mubi_in_sva_q <= mubi_i;
+ end
+ `ASSERT(OutputDelay_A, rst_ni |-> ##2 mubi_o == {NumCopies{$past(mubi_in_sva_q, 1)}})
+`endif
end
end else begin : gen_no_flops
diff --git a/hw/ip/prim/rtl/prim_mubi16_sync.sv b/hw/ip/prim/rtl/prim_mubi16_sync.sv
index c510f10..24b400e 100644
--- a/hw/ip/prim/rtl/prim_mubi16_sync.sv
+++ b/hw/ip/prim/rtl/prim_mubi16_sync.sv
@@ -101,17 +101,39 @@
);
end
+// Note regarding SVAs below:
+//
+// 1) Without the sampled rst_ni pre-condition, this may cause false assertion failures right after
+// a reset release, since the "disable iff" condition with the rst_ni is sampled in the "observed"
+// SV scheduler region after all assignments have been evaluated (see also LRM section 16.12, page
+// 423). This is a simulation artifact due to reset synchronization in RTL, which releases rst_ni
+// on the active clock edge. This causes the assertion to evaluate although the reset was actually
+// 0 when entering this simulation cycle.
+//
+// 2) Similarly to 1) there can be sampling mismatches of the lc_en_i signal since that signal may
+// originate from a different clock domain. I.e., in cases where the lc_en_i signal changes exactly
+// at the same time that the clk_i signal rises, the SVA will not pick up that change in that clock
+// cycle, whereas RTL will because SVAs sample values in the "preponed" region. To that end we make
+// use of an RTL helper variable to sample the lc_en_i signal, hence ensuring that there are no
+// sampling mismatches.
+`ifdef INC_ASSERT
+ mubi16_t mubi_in_sva_q;
+ always_ff @(posedge clk_i) begin
+ mubi_in_sva_q <= mubi_i;
+ end
`ASSERT(OutputIfUnstable_A, sig_unstable |-> mubi_o == {NumCopies{reset_value}})
- `ASSERT(OutputDelay_A, ##3 !sig_unstable |-> mubi_o == {NumCopies{$past(mubi_i, 3)}})
+ `ASSERT(OutputDelay_A, rst_ni |-> ##3 sig_unstable ||
+ mubi_o == {NumCopies{$past(mubi_in_sva_q, 2)}})
+`endif
end else begin : gen_no_stable_chks
assign mubi = mubi_sync;
- // Without the sampled rst_ni pre-condition, this may cause false assertion failures
- // right after a reset release, since the "iff disable" condition with the rst_ni is
- // sampled in the "observed" SV scheduler region after all assignments have been
- // evaluated. This is a simulation artifact due to reset synchronization in RTL, which
- // releases rst_ni on the active clock edge. This causes the assertion to evaluate
- // although the reset was actually 0 when entering this simulation cycle.
- `ASSERT(OutputDelay_A, rst_ni |-> ##2 mubi_o == {NumCopies{$past(mubi_i, 2)}})
+`ifdef INC_ASSERT
+ mubi16_t mubi_in_sva_q;
+ always_ff @(posedge clk_i) begin
+ mubi_in_sva_q <= mubi_i;
+ end
+ `ASSERT(OutputDelay_A, rst_ni |-> ##2 mubi_o == {NumCopies{$past(mubi_in_sva_q, 1)}})
+`endif
end
end else begin : gen_no_flops
diff --git a/hw/ip/prim/rtl/prim_mubi4_sync.sv b/hw/ip/prim/rtl/prim_mubi4_sync.sv
index 3834395..584c357 100644
--- a/hw/ip/prim/rtl/prim_mubi4_sync.sv
+++ b/hw/ip/prim/rtl/prim_mubi4_sync.sv
@@ -101,17 +101,39 @@
);
end
+// Note regarding SVAs below:
+//
+// 1) Without the sampled rst_ni pre-condition, this may cause false assertion failures right after
+// a reset release, since the "disable iff" condition with the rst_ni is sampled in the "observed"
+// SV scheduler region after all assignments have been evaluated (see also LRM section 16.12, page
+// 423). This is a simulation artifact due to reset synchronization in RTL, which releases rst_ni
+// on the active clock edge. This causes the assertion to evaluate although the reset was actually
+// 0 when entering this simulation cycle.
+//
+// 2) Similarly to 1) there can be sampling mismatches of the lc_en_i signal since that signal may
+// originate from a different clock domain. I.e., in cases where the lc_en_i signal changes exactly
+// at the same time that the clk_i signal rises, the SVA will not pick up that change in that clock
+// cycle, whereas RTL will because SVAs sample values in the "preponed" region. To that end we make
+// use of an RTL helper variable to sample the lc_en_i signal, hence ensuring that there are no
+// sampling mismatches.
+`ifdef INC_ASSERT
+ mubi4_t mubi_in_sva_q;
+ always_ff @(posedge clk_i) begin
+ mubi_in_sva_q <= mubi_i;
+ end
`ASSERT(OutputIfUnstable_A, sig_unstable |-> mubi_o == {NumCopies{reset_value}})
- `ASSERT(OutputDelay_A, ##3 !sig_unstable |-> mubi_o == {NumCopies{$past(mubi_i, 3)}})
+ `ASSERT(OutputDelay_A, rst_ni |-> ##3 sig_unstable ||
+ mubi_o == {NumCopies{$past(mubi_in_sva_q, 2)}})
+`endif
end else begin : gen_no_stable_chks
assign mubi = mubi_sync;
- // Without the sampled rst_ni pre-condition, this may cause false assertion failures
- // right after a reset release, since the "iff disable" condition with the rst_ni is
- // sampled in the "observed" SV scheduler region after all assignments have been
- // evaluated. This is a simulation artifact due to reset synchronization in RTL, which
- // releases rst_ni on the active clock edge. This causes the assertion to evaluate
- // although the reset was actually 0 when entering this simulation cycle.
- `ASSERT(OutputDelay_A, rst_ni |-> ##2 mubi_o == {NumCopies{$past(mubi_i, 2)}})
+`ifdef INC_ASSERT
+ mubi4_t mubi_in_sva_q;
+ always_ff @(posedge clk_i) begin
+ mubi_in_sva_q <= mubi_i;
+ end
+ `ASSERT(OutputDelay_A, rst_ni |-> ##2 mubi_o == {NumCopies{$past(mubi_in_sva_q, 1)}})
+`endif
end
end else begin : gen_no_flops
diff --git a/hw/ip/prim/rtl/prim_mubi8_sync.sv b/hw/ip/prim/rtl/prim_mubi8_sync.sv
index c626dd1..c0a4ffb 100644
--- a/hw/ip/prim/rtl/prim_mubi8_sync.sv
+++ b/hw/ip/prim/rtl/prim_mubi8_sync.sv
@@ -101,17 +101,39 @@
);
end
+// Note regarding SVAs below:
+//
+// 1) Without the sampled rst_ni pre-condition, this may cause false assertion failures right after
+// a reset release, since the "disable iff" condition with the rst_ni is sampled in the "observed"
+// SV scheduler region after all assignments have been evaluated (see also LRM section 16.12, page
+// 423). This is a simulation artifact due to reset synchronization in RTL, which releases rst_ni
+// on the active clock edge. This causes the assertion to evaluate although the reset was actually
+// 0 when entering this simulation cycle.
+//
+// 2) Similarly to 1) there can be sampling mismatches of the lc_en_i signal since that signal may
+// originate from a different clock domain. I.e., in cases where the lc_en_i signal changes exactly
+// at the same time that the clk_i signal rises, the SVA will not pick up that change in that clock
+// cycle, whereas RTL will because SVAs sample values in the "preponed" region. To that end we make
+// use of an RTL helper variable to sample the lc_en_i signal, hence ensuring that there are no
+// sampling mismatches.
+`ifdef INC_ASSERT
+ mubi8_t mubi_in_sva_q;
+ always_ff @(posedge clk_i) begin
+ mubi_in_sva_q <= mubi_i;
+ end
`ASSERT(OutputIfUnstable_A, sig_unstable |-> mubi_o == {NumCopies{reset_value}})
- `ASSERT(OutputDelay_A, ##3 !sig_unstable |-> mubi_o == {NumCopies{$past(mubi_i, 3)}})
+ `ASSERT(OutputDelay_A, rst_ni |-> ##3 sig_unstable ||
+ mubi_o == {NumCopies{$past(mubi_in_sva_q, 2)}})
+`endif
end else begin : gen_no_stable_chks
assign mubi = mubi_sync;
- // Without the sampled rst_ni pre-condition, this may cause false assertion failures
- // right after a reset release, since the "iff disable" condition with the rst_ni is
- // sampled in the "observed" SV scheduler region after all assignments have been
- // evaluated. This is a simulation artifact due to reset synchronization in RTL, which
- // releases rst_ni on the active clock edge. This causes the assertion to evaluate
- // although the reset was actually 0 when entering this simulation cycle.
- `ASSERT(OutputDelay_A, rst_ni |-> ##2 mubi_o == {NumCopies{$past(mubi_i, 2)}})
+`ifdef INC_ASSERT
+ mubi8_t mubi_in_sva_q;
+ always_ff @(posedge clk_i) begin
+ mubi_in_sva_q <= mubi_i;
+ end
+ `ASSERT(OutputDelay_A, rst_ni |-> ##2 mubi_o == {NumCopies{$past(mubi_in_sva_q, 1)}})
+`endif
end
end else begin : gen_no_flops
diff --git a/util/design/data/prim_mubi_sync.sv.tpl b/util/design/data/prim_mubi_sync.sv.tpl
index e5f8d52..3148c13 100644
--- a/util/design/data/prim_mubi_sync.sv.tpl
+++ b/util/design/data/prim_mubi_sync.sv.tpl
@@ -101,17 +101,39 @@
);
end
+// Note regarding SVAs below:
+//
+// 1) Without the sampled rst_ni pre-condition, this may cause false assertion failures right after
+// a reset release, since the "disable iff" condition with the rst_ni is sampled in the "observed"
+// SV scheduler region after all assignments have been evaluated (see also LRM section 16.12, page
+// 423). This is a simulation artifact due to reset synchronization in RTL, which releases rst_ni
+// on the active clock edge. This causes the assertion to evaluate although the reset was actually
+// 0 when entering this simulation cycle.
+//
+// 2) Similarly to 1) there can be sampling mismatches of the lc_en_i signal since that signal may
+// originate from a different clock domain. I.e., in cases where the lc_en_i signal changes exactly
+// at the same time that the clk_i signal rises, the SVA will not pick up that change in that clock
+// cycle, whereas RTL will because SVAs sample values in the "preponed" region. To that end we make
+// use of an RTL helper variable to sample the lc_en_i signal, hence ensuring that there are no
+// sampling mismatches.
+`ifdef INC_ASSERT
+ mubi${n_bits}_t mubi_in_sva_q;
+ always_ff @(posedge clk_i) begin
+ mubi_in_sva_q <= mubi_i;
+ end
`ASSERT(OutputIfUnstable_A, sig_unstable |-> mubi_o == {NumCopies{reset_value}})
- `ASSERT(OutputDelay_A, ##3 !sig_unstable |-> mubi_o == {NumCopies{$past(mubi_i, 3)}})
+ `ASSERT(OutputDelay_A, rst_ni |-> ##3 sig_unstable ||
+ mubi_o == {NumCopies{$past(mubi_in_sva_q, 2)}})
+`endif
end else begin : gen_no_stable_chks
assign mubi = mubi_sync;
- // Without the sampled rst_ni pre-condition, this may cause false assertion failures
- // right after a reset release, since the "iff disable" condition with the rst_ni is
- // sampled in the "observed" SV scheduler region after all assignments have been
- // evaluated. This is a simulation artifact due to reset synchronization in RTL, which
- // releases rst_ni on the active clock edge. This causes the assertion to evaluate
- // although the reset was actually 0 when entering this simulation cycle.
- `ASSERT(OutputDelay_A, rst_ni |-> ##2 mubi_o == {NumCopies{$past(mubi_i, 2)}})
+`ifdef INC_ASSERT
+ mubi${n_bits}_t mubi_in_sva_q;
+ always_ff @(posedge clk_i) begin
+ mubi_in_sva_q <= mubi_i;
+ end
+ `ASSERT(OutputDelay_A, rst_ni |-> ##2 mubi_o == {NumCopies{$past(mubi_in_sva_q, 1)}})
+`endif
end
end else begin : gen_no_flops