Skip to content

Commit bb2d383

Browse files
thomasahleclaude
andcommitted
Add 12 new SVA lessons from Mehta book
Tier 1 — core language gaps: - sva/nonconsec-eq: [=m] non-consecutive equal repetition - sva/throughout: throughout operator for signal stability - sva/sequence-ops: intersect, within, and, or composition - sva/isunknown: $isunknown() X/Z detection (with testbench) - sva/changed: $changed() and $sampled() Tier 2 — formal/temporal operators: - sva/always-eventually: s_eventually and always (LTL operators) - sva/until: s_until, until_with temporal "hold" operators - sva/abort: reject_on / accept_on property preemption Tier 3 — structural/reusable: - sva/triggered: .triggered sequence endpoint detection - sva/checker: checker construct for reusable assertion bundles - sva/recursive: recursive properties for "hold until" patterns Curriculum updated: new chapters "Sequence Operators" and expanded "Formal Verification"; abort added to Properties & Implication; isunknown/changed added to Sampled Value Functions; triggered/checker/recursive added to Advanced Properties. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent e18720f commit bb2d383

46 files changed

Lines changed: 465 additions & 5 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/lessons/index.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,13 @@ export const parts = [
7373
title: 'SystemVerilog Assertions',
7474
chapters: [
7575
{ title: 'Your First Assertion', lessons: [L('sva/immediate-assert'), L('sva/sequence-basics')] },
76-
{ title: 'Clock Delay & Sequences', lessons: [L('sva/clock-delay'), L('sva/consecutive-rep'), L('sva/nonconsec-rep')] },
77-
{ title: 'Properties & Implication', lessons: [L('sva/implication'), L('sva/req-ack'), L('sva/disable-iff'), L('sva/vacuous-pass')] },
78-
{ title: 'Sampled Value Functions', lessons: [L('sva/rose-fell'), L('sva/stable-past')] },
76+
{ title: 'Clock Delay & Sequences', lessons: [L('sva/clock-delay'), L('sva/consecutive-rep'), L('sva/nonconsec-rep'), L('sva/nonconsec-eq')] },
77+
{ title: 'Sequence Operators', lessons: [L('sva/throughout'), L('sva/sequence-ops')] },
78+
{ title: 'Properties & Implication', lessons: [L('sva/implication'), L('sva/req-ack'), L('sva/disable-iff'), L('sva/vacuous-pass'), L('sva/abort')] },
79+
{ title: 'Sampled Value Functions', lessons: [L('sva/rose-fell'), L('sva/stable-past'), L('sva/isunknown'), L('sva/changed')] },
7980
{ title: 'Coverage', lessons: [L('sva/cover-property')] },
80-
{ title: 'Advanced Properties', lessons: [L('sva/local-vars'), L('sva/onehot')] },
81-
{ title: 'Formal Verification', lessons: [L('sva/formal-intro'), L('sva/formal-assume'), L('sva/lec')] },
81+
{ title: 'Advanced Properties', lessons: [L('sva/local-vars'), L('sva/onehot'), L('sva/triggered'), L('sva/checker'), L('sva/recursive')] },
82+
{ title: 'Formal Verification', lessons: [L('sva/formal-intro'), L('sva/formal-assume'), L('sva/always-eventually'), L('sva/until'), L('sva/lec')] },
8283
],
8384
},
8485
{
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module abort_check(input logic clk, start, ack, err);
2+
3+
property p_burst_ok;
4+
@(posedge clk) start |=> reject_on(err) (##[1:4] ack);
5+
endproperty
6+
7+
burst_ok_a: assert property (p_burst_ok);
8+
9+
endmodule
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module abort_check(input logic clk, start, ack, err);
2+
3+
// Spec: after start, ack must arrive within 4 cycles.
4+
// If err fires mid-transfer, fail immediately.
5+
property p_burst_ok;
6+
@(posedge clk)
7+
// TODO: start |=> reject_on(err) (##[1:4] ack);
8+
;
9+
endproperty
10+
11+
burst_ok_a: assert property (p_burst_ok);
12+
13+
endmodule
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<p>Sometimes an in-progress property should be terminated early — either because an abort condition renders the check irrelevant, or because its occurrence should itself be flagged as a failure. SVA provides two operators for this:</p>
2+
<ul>
3+
<li><code>reject_on(cond) prop</code> — if <code>cond</code> becomes true while <code>prop</code> is being evaluated, <strong>fail</strong> immediately.</li>
4+
<li><code>accept_on(cond) prop</code> — if <code>cond</code> becomes true, <strong>pass</strong> immediately (abort without failure).</li>
5+
</ul>
6+
<p>Both have synchronous variants — <code>sync_reject_on</code> and <code>sync_accept_on</code> — that only sample <code>cond</code> at the property's clock edge instead of asynchronously.</p>
7+
<p>Example: a burst transfer should normally complete with <code>ack</code> within 4 cycles, but if an error fires mid-burst the property should immediately fail:</p>
8+
<pre>start |=> reject_on(err) (##[1:4] ack)</pre>
9+
<p>Open <code>abort_check.sv</code> and complete the property body using <code>reject_on</code>.</p>
10+
<blockquote><p><code>reject_on(cond) seq</code> is equivalent to <code>(!cond) throughout seq</code> — both fail when <code>cond</code> goes true during the sequence window. <code>reject_on</code> is more expressive because it also applies to composite properties, not just sequences.</p></blockquote>

src/lessons/sva/abort/meta.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"title": "Aborting Properties: reject_on and accept_on",
3+
"focus": "/src/abort_check.sv"
4+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<p>SVA provides two operators for reasoning about entire future traces rather than bounded windows:</p>
2+
<ul>
3+
<li><code>s_eventually prop</code><strong>strong eventually</strong>: <code>prop</code> must become true at some future clock tick. Fails if the trace ends without it occurring.</li>
4+
<li><code>always prop</code><code>prop</code> must hold at <em>every</em> clock tick from now on.</li>
5+
</ul>
6+
<p>The <em>strong</em> vs <em>weak</em> distinction matters for formal tools: a weak property (<code>eventually</code>) is satisfied vacuously by a finite trace that never reaches the condition, while a strong property (<code>s_eventually</code>) demands the condition eventually occurs:</p>
7+
<pre>// After POR, the lock signal must eventually assert
8+
property p_lock_live;
9+
@(posedge clk) $rose(rst_n) |-> s_eventually lock;
10+
endproperty
11+
12+
// Once locked, it stays locked
13+
property p_lock_stable;
14+
@(posedge clk) lock |-> always lock;
15+
endproperty</pre>
16+
<p>Open <code>liveness.sv</code> and fill in both property bodies.</p>
17+
<blockquote><p><code>s_eventually</code> and <code>always</code> used as property operators are <strong>IEEE 1800-2012</strong> features. They express Linear Temporal Logic (LTL) properties and require a formal tool that supports unbounded reasoning. Bounded model checking can only falsify them within its bound, not fully prove them.</p></blockquote>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module liveness(input logic clk, rst_n, lock);
2+
3+
property p_lock_live;
4+
@(posedge clk) $rose(rst_n) |-> s_eventually lock;
5+
endproperty
6+
7+
property p_lock_stable;
8+
@(posedge clk) lock |-> always lock;
9+
endproperty
10+
11+
lock_live_a: assert property (p_lock_live);
12+
lock_stable_a: assert property (p_lock_stable);
13+
14+
endmodule
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module liveness(input logic clk, rst_n, lock);
2+
3+
// After POR, the lock signal must eventually assert (liveness)
4+
property p_lock_live;
5+
@(posedge clk)
6+
// TODO: $rose(rst_n) |-> s_eventually lock;
7+
;
8+
endproperty
9+
10+
// Once lock asserts it never de-asserts (safety)
11+
property p_lock_stable;
12+
@(posedge clk)
13+
// TODO: lock |-> always lock;
14+
;
15+
endproperty
16+
17+
lock_live_a: assert property (p_lock_live);
18+
lock_stable_a: assert property (p_lock_stable);
19+
20+
endmodule
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"title": "always and s_eventually",
3+
"focus": "/src/liveness.sv"
4+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<p><code>$changed(sig)</code> returns true when a signal's sampled value differs from its value at the previous clock edge — a concise way to write <code>sig !== $past(sig)</code>:</p>
2+
<pre>update |=> $changed(data)</pre>
3+
<p>The companion function <code>$sampled(expr)</code> returns the value of an expression as sampled in the preponed region (the settled value at the clock edge). It is most useful inside action blocks to print what the checker actually saw:</p>
4+
<pre>else $error("data unchanged: 0x%0h", $sampled(data));</pre>
5+
<p>Open <code>toggle_check.sv</code> and complete the property body: while <code>update</code> is high, <code>data</code> must change every cycle.</p>
6+
<blockquote><p><code>$changed</code> uses four-state inequality (<code>!==</code>) so it is also true when a signal transitions to or from X. To ignore X transitions use <code>data != $past(data)</code> (two-state inequality) instead.</p></blockquote>

0 commit comments

Comments
 (0)