Cutpoints and Blackboxes
Free an internal signal to shrink the cone, see why that can only add failures, and tell a real counterexample from one the cut invented.
- Lesson
- F4.2
- Time
- 20 min
- Runs on
- SymbiYosys
- Check
- 5 questions
The packet buffer’s pointer proof ran out of time every night for a week. Its cone held a memory of sixteen 64-bit words and a CRC check, though the assertions only talked about pointers. One line, a free input in place of the CRC result, made it finish in 1.7 s.
A Cut Adds Behaviour
Read the diagram as text
- wdata, wr: 64-bit words: CRC in the top 16 bits
- memory, 16 × 64: cut B: blackbox, every output free
- CRC-16 check: cut A: bad becomes a free input
- full flag: cut C: control, gives a false failure
- wr_ptr, rd_ptr, count: a corrupt head word is dropped
- assertions: empty |-> pointers equal; count <= 16
- wdata, wr → memory, 16 × 64
- memory, 16 × 64 → CRC-16 check: head word
- CRC-16 check → wr_ptr, rd_ptr, count: drop
- full flag → wr_ptr, rd_ptr, count: write enable
- wr_ptr, rd_ptr, count → full flag: count == 16
- wr_ptr, rd_ptr, count → assertions
Cuts A and B remove the datapath from the cone. Cut C removes a fact the assertions depend on.
A cut point replaces a signal with a free input, and the logic that drove it leaves the cone. The cut model can do everything the real design does, and more. So a PASS on the cut model holds for the real design; a FAIL may be one the real design cannot produce.
| On the cut design | PASS | FAIL or reached |
|---|---|---|
| assertion | holds for the real design | triage: could the real logic drive the cut signal that way? |
| cover | unreached: unreachable in the real design too | reached: proves nothing if the trace uses the cut signal |
A cut flips which results you can trust: for assertions, PASS; for covers, unreached.
A blackbox does the same to a whole module: every output becomes a cut point. Yosys has a cutpoint pass for both. The site’s runner fixes its own script, so the lab writes the free value into the RTL with $anyseq.
Cut the Datapath
Real CRC check
wire bad = crc16(head[47:0]) != head[63:48];
abc pdr: time limit (20 s), no verdict.
Cut point
wire bad = $anyseq;
abc pdr: Prove PASS, 1.7 s.
| Run | Measured result |
|---|---|
real design, abc pdr, the site’s runner (limit 20 s) | time limit (20 s), no verdict |
real design, abc pdr, SBY directly (limit 180 s) | Prove PASS, 14.0 s |
cut A: CRC result free, abc pdr | Prove PASS, 1.7 s |
cut B: memory blackboxed, abc pdr | Prove PASS, 2.0 s |
faulty read pointer, cut A, abc pdr | FAIL at step 23, 0.9 s |
faulty read pointer, real design, bmc 24 | FAIL at step 19, 2.9 s |
The faulty twin wraps the read pointer at 16 while the write pointer wraps at 32. With the cut it still fails. Flop bits after prep: 15 real, 15 with cut A, 15 with cut B.
The pointers never care why a word is dropped, only that a drop moves rd_ptr like a read. Cutting bad keeps that and takes the CRC and the memory out of the cone, since nothing else reads the head word. The blackbox reaches the same cone from the other side.
Run the faulty twin after every cut. If it still fails, the cut kept the logic the bug lives in. If it passes, you cut too much, or the bug was in the logic you cut, and that logic needs its own proof.
Cut the Control: A False Failure
Measured counterexample with the full flag cut (bmc, depth 24): FAIL at step 19, 2.7 s. The free full is shaded like an input.
Cut the full flag instead and bmc fails at step 19. Step 17 shows count = 16 with full = 0, a pair the real flag never produces, and the write takes count to 17. The cut removed the very fact the assertion depends on.
Triage a cut-model failure like any counterexample: find the cut signal in the trace and ask whether the real logic could drive that value there. Here it could not. Do not undo the cut: constrain the free value with what the removed logic guaranteed, and prove that guarantee on the real logic.
| Run | Measured result |
|---|---|
cuts A and C plus assume(count != 16 || full), abc pdr | Prove PASS, 2.2 s |
| the guarantee asserted on the real flag, prove 2 | Prove PASS, 0.5 s |
cuts A and C plus the assumption, faulty read pointer, bmc 24 | FAIL at step 19, 2.6 s |
cover of count == 17, full cut, depth 24 | cover reached at step 19, 0.8 s |
cover of count == 17, real design, depth 24 | cover unreached within depth 24, 0.8 s |
The assumption states only what the real flag guarantees, and a separate run proves it. The reached cover on the cut design is the invented overflow.
This is assume-guarantee on a single wire (F4.3). The cover rows show the other half of the verdict table: the cut design reaches a count of 17, and the real one never does.
Asked in Interviews
| Question | Answer |
|---|---|
| What is a cutpoint? Is it sound? | An internal signal made a free input, so its fan-in leaves the cone. It is sound: the cut model has every real behaviour, so a PASS carries over. It can add false failures, never hide a real one. |
| What is blackboxing? | Replacing a module by free outputs. Typical targets: memories, arithmetic, analog models, IP verified elsewhere. The logic inside is then not verified by this run. |
| How do you know a cut-model failure is real? | Look at the cut signal in the trace. If the real logic could produce that value at that step, the failure is real; if not, refine the cut or add a proven assumption. |
Try It
The lab is the buffer with the CRC result cut, prove with abc pdr. Measured: Prove PASS, 1.7 s. Without the cut: time limit (20 s), no verdict in the runner; Prove PASS, 14.0 s with SBY directly.
assert property (@(posedge clk) disable iff (rst) empty |-> wr_ptr == rd_ptr);
assert property (@(posedge clk) disable iff (rst) count <= 16);Move the cut
Put the CRC check back and blackbox the memory instead: give
pbuf_memthe single lineassign rd = $anyseq;. Compare the time.Check soundness
Make the read pointer wrap at 15 (
rd_ptr == 5'd15 ? 5'd0 : rd_ptr + 5'd1) and run again with the cut.Cut the control
Restore the design and cut
fullinstead. Runbmcat depth 24 and find the step wherecountandfulldisagree.
design.sv
props.sv
Use assert property (@(posedge clk) ...);. Leave blank for immediate assertions in the design.
Inputs are free unless constrained. Run to find a counterexample or check a proof.
Model: one positive-edge clock, binary data. Sampled history requires declaration-initialized variables; primary-input history is unsupported.
SBY summary and log
Check Yourself
Remember
- A cut point or blackbox frees signals and shrinks the cone; it over-approximates the design.
- PASS on the cut model is a real PASS; FAIL must be checked at the cut signal.
- Cut datapath that the property does not read; never cut the control it depends on.
- Run the faulty twin after every cut.