A controller must observe four completed transfers before releasing a result. Its up counter says four and its down counter says zero. Their sum is still four. Only three transfers actually occurred. A shared enable has advanced both counters together.
A relationship check has a narrow job
A student must submit four assignments. Two counters start at zero submitted and four remaining. Each real hand-in adds one to the first and subtracts one from the second, preserving a total of four: up and down. A mistaken paired update also preserves that total without receiving another assignment. A relationship check compares numbers; it does not independently inspect the drawer for completed work.
A cross-counter stores progress in opposite directions. Our three-bit registers start at up=0 and down=4. On each counted step, up increases and down decreases. The non-modular sum up+down must remain four. We use a widened sum to avoid hiding overflow through truncation.
An isolated change to up usually breaks the sum. A detector can block completion immediately and remember the error. However, a relation that remains true cannot reveal how the pair reached its values. A coordinated wrong update is invisible to this particular check.
OpenTitan publishes a cross-counter primitive. SYNFI discusses shared increment and clear signals as boundaries of counter protection. Our small schedule below illustrates that mechanism; we did not run SYNFI or reproduce its netlist experiments. Counter source, SYNFI section 4.4.1
Count completed work, not elapsed cycles
A real submission requires an assignment offered and a teacher ready to receive it: valid AND ready. Offering it to a busy teacher, or a ready teacher with nothing offered, does not increment the independent receipt ledger ref. Real hand-ins occur at edges 1, 3, and 4; edge 2 is idle. A fault nevertheless advances both desk counters after edge 2. The schedule exposes incorrect progress; elapsed time alone never counts completed work.
A genuine step means a transfer was accepted: valid and ready were both true at the agreed rising edge. Waiting through a stall does not complete work. The independent reference increments only on those genuine handshakes and remains outside the fault scope.
In the negative schedule, genuine handshakes occur at edges 1, 3 and 4. Edge 2 is idle. One false common enable after edge 2 advances up and down despite that idle cycle. After edge 4, the DUT pair is 4/0 while reference progress is three.
The result request arrives at edge 5. Sum-only completion permits it. The authorization reference requires four genuine transfers and therefore marks that commit as unauthorized. The checker correctly reports no sum error; it is blind to missing work, not broken arithmetic.
How a wrong enable counts work that never happened
After edge 4 the desk says four submitted and none remaining, but the independent ledger records three. At edge 5 the student requests completion evidence: sum permits it; progress sees up disagree with ref. The extra step after edge 2 is an abstract state update visible before the next bell. It neither creates a real earlier hand-in nor simulates electrical enable sampling. Truncating three-bit 6+6 to four is a separate width counterexample.
A handshake is an edge at which work actually transfers. Here only edges 1,3,4 have handshake=1; edge 2 is idle. The table lists pre-edge up,down,ref, then describes post-edge updates. Ref counts only real handshakes.
| edge | Before (up,down,ref) | Update after sampling |
|---|---|---|
| 1 | (0,4,0) | Real work produces (1,3,1) |
| 2 | (1,3,1) | No work; a wrong enable changes DUT to (2,2), while ref stays 1 |
| 3 | (2,2,1) | Real work produces (3,1,2) |
| 4 | (3,1,2) | Real work produces (4,0,3) |
| 5 | (4,0,3) | Result request arrives; sum=4 but only three jobs occurred |
Every row satisfies up+down=4. The sum checker answers a relationship question correctly; it does not count the source of work. Progress policy sees up=2 and ref=1 at edge 3 and retains the discrepancy, preventing acceptance at edge 5. This trusted ref is a testbench oracle. A product needs a justified source of progress evidence, not a testbench reference relabeled as hardware protection.
Width is part of the invariant. Three-bit values 6+6 produce four-bit 1100. Keeping only the low three bits gives 100 (4), making a wrong pair appear to satisfy sum=4. This arithmetic example explains truncation; it is not a value from the enable trace above. Zero-extend operands to four bits before comparing the complete sum.
The teaching model defines the enable fault as one extra up+1/down−1 state operation after edge 2 sampling and normal updating. It does not simulate an enable signal’s setup/hold. This operation cannot change values already sampled at edge 2; its result is first observed before edge 3. An RTL harness using a pre-edge enable pulse must separately verify its sampling and update order.
Give each target its own interpretation
Changing a position in submitted, substituting a whole pair, and advancing a shared receipt enable are different effects. After the normal update, pair substitution computes proposed_up = up XOR mask. Only values 0–4 are assigned as (proposed_up, 4−proposed_up); a proposal of five has no effect. This distinguishes submitted injection parameters from an actual changed state. The story's independent receipt ledger represents the harness reference, not a protection circuit automatically added to a product.
The main witness has one event at the common enable, no register XOR, and a fixed edge-0-to-5 window. Both counters stop at their intended endpoints. Clock/reset, workload, handshake observer, reference, sum checker and final consumer remain trusted.
The lab also offers an up-register XOR. Its mask is restricted to three bits. Another option substitutes the pair so down=4-up, only if the proposed up lies in 0..4. Out-of-range pair proposals have no effect. This is a constrained correlated substitution, not two independent bit flips. Record effective injection separately from a submitted parameter.
The progress variant additionally compares up with an independent progress input and remembers discrepancies. The executable model uses trusted reference progress to demonstrate the needed obligation. A product needs a separately justified work-completion observation; attaching a testbench oracle to grant is not a hardware solution.
Inspect the idle edge before the final request
Add one count at idle edge 2, then inspect completion acceptance at edge 5. Changing sum to progress leaves the three genuine hand-ins fixed, isolating the checking condition. Use four real submissions as a separate positive control. The 96 proposals include zero masks and ineffective pair substitutions. No acceptance can simply mean four assignments were never completed; it does not show 96 detected alterations.
Select enable, fault edge 2 and sum policy. Step through the table. At edge 3, the pair already reflects the false step while ref has not advanced. At edge 5, commit is true and reference is false. Switching to progress policy blocks this witness without changing its workload.
The 96 up/pair parameter runs never commit under progress policy on the three-handshake schedule. That alone does not prove fault detection: reference never reaches four. Separate assertions check the common-enable progress mismatch, an up XOR breaking the sum, and a coordinated pair substitution bypassing sum-only checking. The fault-free four-handshake control accepts at edge 5.
Try an injection after edge 5. No later request exists in this window. A missing unauthorized commit now proves only that the observation ended. Move the request later before claiming the corrupted progress is harmless. Also record whether the injection actually changes the pair.
The 96 parameter sets are two targets (up/pair) × six faultEdge values (0–5) × eight masks (0–7). Mask zero is a no-change control; out-of-range pair proposals also have no effect. Submitting 96 cases does not mean 96 effective injections.
Proposed RTL / SVA
Preserving the full arithmetic sum is like retaining all digits when adding submitted and remaining, rather than dropping the carry. Progress also compares against an independent receipt ledger, and acceptance checks reference_handshakes==4. That reference belongs to the trusted test harness. A product must establish and protect its own completion evidence; the classroom ledger is not ready-made hardware.
Read this lesson's property: Completed counts and real work
At the same edge as completion acceptance, the audit asks whether four real hand-ins occurred. Counting an offered request as completed loses the reference because an offer may not be received. This separates accepted_commit from reference_handshakes. Cover needs genuine four-step work rather than a controller that never releases. It does not verify every stall or clear priority.
SVA means SystemVerilog Assertions. An assertion checks a rule; it is not the permission gate. At each rising edge outside reset, if accepted_commit (csr_commit in Lesson 9) is one, |-> requires the right-hand condition on that same edge. With no acceptance, this implication raises no authorization failure; positive controls must still demonstrate useful work. disable iff (!rst_n) excludes active reset, without proving reset safety.
Cover seeks one matching path, rather than proving every transaction correct. Reference independently records the expected result in the testbench. The harness supplies inputs, fault budgets and this oracle; DUT means design under test. A two-state model uses only 0/1 logic, excluding X and intra-cycle delay; it does not mean a two-state FSM. Revisit Lesson 1 section 5 for syntax and wiring comparisons. These snippets have not been compiled, so listing a property does not establish a proof.
logic [3:0] sum; // widen three-bit operands
assign sum = {1'b0, up_q} + {1'b0, down_q};
assign count_bad = (sum != 4);
// work_count_i requires its own integrity/trust justification.
assign progress_bad = (up_q != work_count_i);
assign grant = (up_q == 4) && !count_bad && !progress_bad && !sticky_q;
assign accepted_commit = result_valid && result_ready && grant;
// Reset clears sticky; each edge sets it on count_bad or progress_bad.
assert property (@(posedge clk) disable iff (!rst_n)
accepted_commit |-> reference_handshakes == 4);
cover property (@(posedge clk) disable iff (!rst_n)
reference_handshakes == 4 && accepted_commit);The RTL sketch is uncompiled. A production counter needs legal set/clear behavior, arithmetic widths, saturation or wrap rules and a bound on outstanding work. Test the common enable before relying on duplicated registers. Lesson 7 asks which state substitutions an encoding can recognize.
Check your reasoning
For the questions, explain how both counters can advance during an idle edge, then whether four submitted with three receipts permits completion. The first concerns a common enable; the second concerns progress authorization. Changing a stall into a genuine hand-in is what should increment ref. A correct total cannot substitute for completed work.
1. Why does up+down=4 survive a false common enable?
Both directions change by opposite amounts.
2. Which event should increase the trusted work count?
A genuine valid/ready handshake.
3. What is the counterexample at edge 5?
DUT reports four steps; only three genuine transfers occurred.
4. Why run a four-handshake control?
It proves intended completion remains reachable.
5. Is the correlated pair substitution two independent bit flips?
No; state the substitution explicitly and restrict valid register values.
Engineering wrap-up
Keep the three-assignment receipt ledger beside the incorrect 4/0 pair in the handoff. Together they explain premature completion at edge 5 and ground the model, cause, and limits below. This wrap-up neither extends the observation window nor moves trusted ref into an implemented design.
- Threat and fault model
- One common-enable event after an idle edge, or separately bounded register effects, in edges 0..5. Three genuine handshakes precede the result request.
An extra shared-enable action after idle edge 2 can permit completion at edge 5. It is one enable event without an additional register flip.
- Root cause
- Opposite counters can remain consistent while jointly counting nonexistent work.
The desk's 4/0 pair has the right sum while receipts total three. Paired advances preserve the relation and count nonexistent work.
- Defense
- Bind progress to independently justified completion events; retain arithmetic integrity checks and immediate blocking.
Before completion, check genuine receipts and the full sum. Ref demonstrates the needed evidence; a product must justify its completion input separately.
- Validation
- Node reproduced early completion and checked 96 storage/substitution parameters; separate four-step positive and three-step negative controls ran.
Rerun premature completion after three receipts and normal completion after four; distinguish effective changes among 96 proposals. No acceptance does not automatically mean detection.
- Limits
- The pair option is a constrained abstract substitution. Out-of-range proposals have no effect. RTL, overflow implementation and physical shared-enable behavior are unverified.
An out-of-range pair proposal leaves the counters unchanged; that is not a detected wrong pair. Scope is constrained substitution, excluding physical enables and full overflow behavior.
- Transfer exercise
- Introduce stalls and simultaneous set/clear. Specify which operation wins and which events must leave progress unchanged.
An offered assignment not received is a stall, so counters should hold. If clear and receipt coincide, define priority first; the original schedule supplies no product rule.