Drop redundant width sets, cover low-bound rejection, and add s_always per-cycle parity test

This commit is contained in:
Yilou Wang 2026-06-16 16:23:27 +02:00
parent 1bdf145f6f
commit 500d8cb725
2 changed files with 21 additions and 28 deletions

View File

@ -12,12 +12,6 @@ import vltest_bootstrap
test.scenarios('vlt')
test.compile(verilator_flags2=['--assert'])
# a is always 1 so there is no per-cycle safety failure: the ONLY failure source
# is the strong end-of-simulation liveness obligation of s_always[1:1] (its window
# is cut off by $finish), so the simulation must exit non-zero. If the in-window
# marking regresses (e.g. the offset-hi vertex stops being flagged), s_always[1:1]
# goes silent, the run succeeds, and this test fails -- catching the regression.
test.execute(fails=True)
test.passes()

View File

@ -4,36 +4,35 @@
// SPDX-FileCopyrightText: 2026 PlanV GmbH
// SPDX-License-Identifier: CC0-1.0
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
// verilog_format: on
module t (
input clk
);
int cyc = 0;
logic a = 1'b1;
logic rst = 1'b1;
logic a_high = 1'b1;
logic a_low = 1'b0;
int low_s_fail_q[$];
int low_w_fail_q[$];
as_liveness: assert property (@(posedge clk) s_always [2:5] a_high);
as_weak: assert property (@(posedge clk) always [2:5] a_high);
as_low_s: assert property (@(posedge clk) s_always [2:5] a_low)
; else low_s_fail_q.push_back(cyc);
as_low_w: assert property (@(posedge clk) always [2:5] a_low)
; else low_w_fail_q.push_back(cyc);
always @(posedge clk) begin
cyc <= cyc + 1;
if (cyc == 0) rst <= 1'b0;
end
// a is always 1, so there is no per-cycle safety failure. The ONLY way these
// can fail is the strong end-of-simulation liveness obligation: attempts whose
// [m:n] window is cut off by $finish must fail (IEEE 1800-2023 16.12.11).
// Single-tick window s_always[1:1]: its in-window state is ONE registered
// vertex, so a dropped end-of-trace obligation produces total silence (no
// shallower attempt can mask it). It is the most sensitive guard and shares
// the in-window marking with every s_always[m:n], so if it fires the deeper
// windows do too. $finish halts on the first liveness $error, so a single
// strong assertion keeps the failure attributable to this case.
as_mm: assert property (@(posedge clk) disable iff (rst) s_always [1:1] a);
// Weak twin imposes no end-of-trace obligation: never fails on this trace.
as_weak: assert property (@(posedge clk) disable iff (rst) always [1:4] a);
always @(posedge clk) begin
if (cyc == 10) begin
if (cyc == 4) begin
`checkd(low_s_fail_q.size(), 3);
`checkd(low_w_fail_q.size(), 3);
$write("*-* All Finished *-*\n");
$finish;
end