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

Which Engine for Which QuestionCovers and bug hunting first, then a proof with two engines side by side. Every status sends you somewhere definite.
Which engine for which questionCovers and bug hunting first, then a proof with two engines side by side. Every status sends you somewhere definite. step cover `smtbmc`, mode cover:is the bench alive? step bug hunt `smtbmc`, mode bmc,depth from the depthargument step prove k-induction and `abcpdr` side by side result PASS proven under theassumptions shown result UNKNOWN read the inductiontrace, add a helper result TIMEOUT no claim: abstract,cut, split, or bound it no failurehelper
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 20Measured result
smtbmc yicestime limit (20 s), no verdict
smtbmc boolectortime limit (20 s), no verdict
smtbmc bitwuzlatime limit (20 s), no verdict
smtbmc z3time limit (20 s), no verdict
abc pdrProve 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

Propertysmtbmc yicessmtbmc boolectorsmtbmc bitwuzlaabc pdrFastest answer
fifo16 empty |-> wr_ptr == rd_ptr, prove (depth 12)UNKNOWN at depth 12, 0.5 sUNKNOWN at depth 12, 0.6 sUNKNOWN at depth 12, 0.6 sProve PASS, 1.4 sabc pdr
mul_sa, 6 bits, done |-> p == a_q * b_q, prove (depth 10)Prove PASS, 0.8 sProve PASS, 0.9 sProve PASS, 0.8 stime limit (20 s), no verdictsmtbmc bitwuzla
mul_sa, 8 bits, same rule, bmc depth 12BMC PASS to depth 12, 10.7 sBMC PASS to depth 12, 3.8 sBMC PASS to depth 12, 8.6 snot runsmtbmc boolector
mul_sa, 8 bits, faulty, bmc depth 14FAIL at step 11, 0.5 sFAIL at step 11, 0.6 sFAIL at step 11, 0.6 sFAIL at step 12, 0.8 ssmtbmc 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

Two engines under [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
fifo16 with two engines, SBY directly, 1.4 s. Induction gave up on the step; PDR proved it, so the task is PASS.
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)
fifo4sb with three engines (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 directlyResult
expect fail on the faulty multiplierDONE (FAIL, rc=0): the expected status gives exit code 0
timeout 5 on the 8-bit multiplier with smtbmc z3DONE (TIMEOUT, rc=8)
bug hunt, fifo4sb with BUG_RD_ORDER, bmc 10, smtbmc yicesFAIL at step 3, 0.2 s
the same with abc bmc3FAIL at step 3, 0.3 s
sby --autotune on fifo1624 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

StatusClaimNext step
Prove PASStrue in every reachable state, under the assumptionscheck the covers still reach (F3.2)
BMC PASS to depth Nno failure in N stepscompare N with the required depth (F4.1)
FAIL at step na trace from reset breaks the ruletriage: bug, missing assumption, wrong property
UNKNOWNbase case passed, induction step failedread step 0, add a helper, or run PDR
TIMEOUT, time limit, ERRORnothing at allanother 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

QuestionAnswer
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.

The two rules in concurrent SVA.
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);
  1. Swap the engine

    Run the same design with smtbmc yices in prove mode at depth 12 and read the verdict.

  2. Swap the design

    Paste the 6-bit multiplier from F2.2 and run it under smtbmc bitwuzla, prove depth 10, then under abc pdr.

  3. Hunt the bug

    Make the multiplier test the wrong bit and run bmc at 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

Predict the outputfifo16 with no helpers, mode prove, abc pdr, reset assumed in step 0. The verdict is:
module fifo16(input clk, rst, wr, rd, input [7:0] wdata,
  output [7:0] rdata, output empty, full);
  reg [7:0] mem [0:15];
  reg [4:0] wr_ptr=0, rd_ptr=0, count=0;
  assign empty = count == 5'd0;
  assign full  = count == 5'd16;
  wire do_wr = wr && !full, do_rd = rd && !empty;
  assign rdata = mem[rd_ptr[3:0]];
  always @(posedge clk)
    if (rst) begin wr_ptr <= 0; rd_ptr <= 0; count <= 0; end
    else begin
      if (do_wr) begin mem[wr_ptr[3:0]] <= wdata; wr_ptr <= wr_ptr + 5'd1; end
      if (do_rd) rd_ptr <= rd_ptr + 5'd1;
      count <= count + do_wr - do_rd;
    end
  always @(posedge clk) begin
    if ($initstate) begin assume(rst); end else begin assume(!rst); end
  end
  always @(posedge clk) if (!rst) begin
    if (empty) assert(wr_ptr == rd_ptr);
  end
endmodule
Predict the outputThe 6-bit shift-add multiplier, mode prove, depth 10, smtbmc bitwuzla, reset assumed in step 0. The verdict is:
module mul_sa(input clk, rst, start, input [5:0] a, b,
  output reg done=0, output reg [11:0] p=0);
  reg [11:0] mcand=0;
  reg [5:0] mplier=0;
  reg [2:0] n=0;
  reg busy=0;
  always @(posedge clk) begin
    done <= 0;
    if (rst) begin busy <= 0; p <= 0; n <= 0; end
    else if (start && !busy) begin
      busy <= 1; p <= 0; mcand <= a; mplier <= b; n <= 3'd6;
    end else if (busy) begin
      if (mplier[0]) p <= p + mcand;
      mcand <= mcand << 1;
      mplier <= mplier >> 1;
      n <= n - 3'd1;
      if (n == 3'd1) begin busy <= 0; done <= 1; end
    end
  end
  always @(posedge clk) begin
    if ($initstate) begin assume(rst); end else begin assume(!rst); end
  end
  // Modelling flops: the operands captured at start
  reg [5:0] a_q=0, b_q=0;
  always @(posedge clk) if (!rst && start && !busy) begin a_q <= a; b_q <= b; end
  always @(posedge clk) if (!rst && done) assert(p == a_q * b_q);
endmodule
ConceptA task lists smtbmc yices and abc pdr. Induction returns FAIL for the step, PDR returns PASS. The task status is:
ConceptWhat does expect fail change?
ConceptA proof hits its time limit after 20 s. What can the report say?

Remember

  • bmc for bugs; k-induction or PDR for proofs; SMT for wide arithmetic; aiger suprove for liveness.
  • The winner changes per property: measure, or race several engines in one task.
  • timeout and expect make regressions end and fail on purpose.
  • UNKNOWN and TIMEOUT are open items, never passes.