Engine Choice and Run Management
Pick the engine by the question (bug, proof, datapath), run several at once, set limits that end runs on purpose, and know what each status lets you claim.
- Lesson
- F4.7
- Time
- 20 min
- Runs on
- SymbiYosys
- Check
- 5 questions
A nightly regression ran one engine on every property. Half the proofs came back UNKNOWN every night for a month. With PDR running next to induction most of them closed in seconds, while the multiplier proofs did better on the old engine. No single engine had been the right choice.
One Question, One First Engine
Read the diagram as text
- cover: `smtbmc`, mode cover: is the bench alive?
- bug hunt: `smtbmc`, mode bmc, depth from the depth argument
- prove: k-induction and `abc pdr` side by side
- PASS: proven under the assumptions shown
- UNKNOWN: read the induction trace, add a helper
- TIMEOUT: no claim: abstract, cut, split, or bound it
- cover → bug hunt
- bug hunt → prove: no failure
- prove → PASS
- prove → UNKNOWN
- prove → TIMEOUT
- UNKNOWN → prove: helper
UNKNOWN goes to F4.6; TIMEOUT goes to F4.1 to F4.5. Liveness has its own engine, aiger suprove, in mode live.
Bugs come out of bmc: it is complete up to its depth and each step is a plain satisfiability query. Proofs need prove: k-induction is quick when the property is inductive, PDR when it is not. Wide arithmetic favours word-level SMT; long control favours bit-level PDR.
The Spine Under Five Engines
| fifo4sb (F3.4), prove depth 20 | Measured result |
|---|---|
smtbmc yices | time limit (20 s), no verdict |
smtbmc boolector | time limit (20 s), no verdict |
smtbmc bitwuzla | time limit (20 s), no verdict |
smtbmc z3 | time limit (20 s), no verdict |
abc pdr | Prove PASS, 1.8 s |
One design, one engine line changed per run.
Every SMT solver ends without a proof; PDR proves the same properties in 1.8 s with no invariant written by hand, because it builds its own (F2.5). With F4.6’s invariants, k-induction closes it too.
Measured: A Different Winner Each Time
| Property | smtbmc yices | smtbmc boolector | smtbmc bitwuzla | abc pdr | Fastest answer |
|---|---|---|---|---|---|
fifo16 empty |-> wr_ptr == rd_ptr, prove (depth 12) | UNKNOWN at depth 12, 0.5 s | UNKNOWN at depth 12, 0.6 s | UNKNOWN at depth 12, 0.6 s | Prove PASS, 1.4 s | abc pdr |
mul_sa, 6 bits, done |-> p == a_q * b_q, prove (depth 10) | Prove PASS, 0.8 s | Prove PASS, 0.9 s | Prove PASS, 0.8 s | time limit (20 s), no verdict | smtbmc bitwuzla |
mul_sa, 8 bits, same rule, bmc depth 12 | BMC PASS to depth 12, 10.7 s | BMC PASS to depth 12, 3.8 s | BMC PASS to depth 12, 8.6 s | not run | smtbmc boolector |
mul_sa, 8 bits, faulty, bmc depth 14 | FAIL at step 11, 0.5 s | FAIL at step 11, 0.6 s | FAIL at step 11, 0.6 s | FAIL at step 12, 0.8 s | smtbmc yices |
All through the site’s runner (20 s limit). "Fastest answer" is the quickest PASS or FAIL.
The control proof is not inductive, so every SMT solver stops at UNKNOWN and PDR proves it. The 6-bit multiplier proof is the reverse: induction closes it and PDR runs out of time. On the 8-bit bounded check the slowest SMT solver takes 2.8 times as long as the fastest.
The shallow bug is found by every engine within a second; PDR’s trace is one step longer (12 against 11). For bugs, the depth matters more than the engine.
Several Engines in One Task
[engines] and a time limit. SBY starts both and stops when one gives a definite answer.[options]
mode prove
depth 12
timeout 60
[engines]
smtbmc yices
abc pdr
[script]
read_verilog -formal -sv design.sv
prep -top fifo16
[files]
design.sv
engine_0 (smtbmc yices) returned pass for basecase
engine_0 (smtbmc yices) returned FAIL for induction
failed assertion fifo16._witness_.check_design_sv_20_assert_30 at design.sv:20.16-20.40
engine_1 (abc pdr) returned PASS
engine_1 did not produce any traces
DONE (PASS, rc=0)smtbmc yices, abc pdr, smtbmc bitwuzla), SBY directly: PASS in 1.5 s.engine_0 (smtbmc yices) returned FAIL for induction
failed assertion fifo4sb._witness_.check_design_sv_40_assert_50 at design.sv:40.24-40.44
engine_1 (abc pdr) returned PASS
engine_1 did not produce any traces
engine_2 (smtbmc bitwuzla) did not return a status
failed assertion fifo4sb._witness_.check_design_sv_40_assert_50 at design.sv:40.24-40.44
DONE (PASS, rc=0)An UNKNOWN from one engine does not end the task; a definite answer from any engine does. timeout ends a run on purpose and reports TIMEOUT, which claims nothing. expect names the status you want, so a regression fails loudly when it changes.
[tasks] splits one file into separate jobs, one per property group or engine, each with its own timeout and expect. The site’s 20-second budget is such a timeout line. A TIMEOUT from bmc asks for the depth argument (F4.1) or an abstraction; one from PDR asks for asserted invariants (F4.6) or a decomposition (F4.3).
| Run, SBY directly | Result |
|---|---|
expect fail on the faulty multiplier | DONE (FAIL, rc=0): the expected status gives exit code 0 |
timeout 5 on the 8-bit multiplier with smtbmc z3 | DONE (TIMEOUT, rc=8) |
bug hunt, fifo4sb with BUG_RD_ORDER, bmc 10, smtbmc yices | FAIL at step 3, 0.2 s |
the same with abc bmc3 | FAIL at step 3, 0.3 s |
sby --autotune on fifo16 | 24 solver configurations UNKNOWN; finished: abc pdr (1 seconds, status=PASS); aiger suprove (0 seconds, status=PASS) |
--autotune tries many engine settings in parallel and ranks the ones that answered.
What Each Status Lets You Claim
| Status | Claim | Next step |
|---|---|---|
| Prove PASS | true in every reachable state, under the assumptions | check the covers still reach (F3.2) |
| BMC PASS to depth N | no failure in N steps | compare N with the required depth (F4.1) |
| FAIL at step n | a trace from reset breaks the rule | triage: bug, missing assumption, wrong property |
| UNKNOWN | base case passed, induction step failed | read step 0, add a helper, or run PDR |
| TIMEOUT, time limit, ERROR | nothing at all | another engine, an abstraction, a split, or a bounded claim |
The words a report may use, and the only ones.
A sign-off table lists the engine, the status and the depth for every property. A TIMEOUT in it is an open item, never a pass.
Asked in Interviews
| Question | Answer |
|---|---|
| Which engine should I pick? | By the question: bmc for bugs, k-induction or PDR for proofs (PDR when no helper is known), word-level SMT for wide arithmetic, aiger suprove for liveness. Measure, because the winner changes per property. |
| Why do commercial tools run several engines at once? | No engine dominates, and a race costs only CPU. SBY does the same with several lines under [engines]: the first definite answer decides. |
| What do you do with an UNKNOWN or a TIMEOUT? | UNKNOWN: read the induction trace and strengthen. TIMEOUT: claim nothing; reduce the cone (cuts, abstraction, case split) or report a bounded result against the required depth. |
Try It
The lab is fifo16 from F2.4 under abc pdr. Measured: Prove PASS, 1.4 s.
assert property (@(posedge clk) disable iff (rst)
empty |-> wr_ptr == rd_ptr);
assert property (@(posedge clk) disable iff (rst)
done |-> p == a_q * b_q);Swap the engine
Run the same design with
smtbmc yicesin prove mode at depth 12 and read the verdict.Swap the design
Paste the 6-bit multiplier from F2.2 and run it under
smtbmc bitwuzla, prove depth 10, then underabc pdr.Hunt the bug
Make the multiplier test the wrong bit and run
bmcat depth 14 with two different solvers. Compare the reported steps.
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
bmcfor bugs; k-induction or PDR for proofs; SMT for wide arithmetic;aiger suprovefor liveness.- The winner changes per property: measure, or race several engines in one task.
timeoutandexpectmake regressions end and fail on purpose.- UNKNOWN and TIMEOUT are open items, never passes.