SAT and SMT in One Lesson

Learn the one question a SAT solver answers, why UNSAT is the good news, and what an SMT solver adds for datapaths.

Lesson
F2.2
Time
15 min
Runs on
SymbiYosys
Check
4 questions

A formal run on a 32-bit datapath was killed after a weekend, and the engineer decided the design was too big for formal. The task had used a bit-level engine. The same property on a word-level SMT solver came back before lunch.

One Question

Decide, Propagate, LearnClauses: (a ∨ b), (¬a ∨ c), (¬b ∨ c), (¬c ∨ d), (¬a ∨ ¬d). A CDCL solver guesses, follows the consequences, and learns from the conflict.
Decide, propagate, learnClauses: (a ∨ b), (¬a ∨ c), (¬b ∨ c), (¬c ∨ d), (¬a ∨ ¬d). A CDCL solver guesses, follows the consequences, and learns from the conflict. decide Decide a = 1 a guess, level 1 propagate Propagate c = 1,d = 1 from (¬a ∨ c), then(¬c ∨ d) conflict Conflict (¬a ∨ ¬d) is false learn Learn (¬a) a = 1 always leadshere backjump Backjump: a = 0 forced by the learnedclause result Model: a=0 b=1c=1 d=1 every clause true:SAT b, c, d follow
  1. Decide

    No clause forces anything yet, so the solver guesses a = 1.

  2. Propagate

    (¬a ∨ c) now needs c = 1, and (¬c ∨ d) then needs d = 1. No guessing: unit propagation.

  3. Conflict and learn

    (¬a ∨ ¬d) is false. Tracing the implications back shows the guess a = 1 caused it, so the solver adds the clause (¬a). That conflict can never be explored again.

  4. Backjump and finish

    (¬a) forces a = 0. Then (a ∨ b) gives b = 1, which gives c = 1 and d = 1. Every clause holds: SAT, and this assignment is the model.

Read the diagram as text
  • Decide a = 1: a guess, level 1
  • Propagate c = 1, d = 1: from (¬a ∨ c), then (¬c ∨ d)
  • Conflict: (¬a ∨ ¬d) is false
  • Learn (¬a): a = 1 always leads here
  • Backjump: a = 0: forced by the learned clause
  • Model: a=0 b=1 c=1 d=1: every clause true: SAT
  • Decide a = 1 → Propagate c = 1, d = 1
  • Propagate c = 1, d = 1 → Conflict
  • Conflict → Learn (¬a)
  • Learn (¬a) → Backjump: a = 0
  • Backjump: a = 0 → Model: a=0 b=1 c=1 d=1: b, c, d follow

Add a sixth clause (¬b ∨ ¬d) and the same steps end in a conflict with no guess left to undo: UNSAT. Drawn by hand, not measured.

A SAT solver answers one question: is there a 0/1 assignment that makes every clause true? SAT means yes, and here it is: the model. UNSAT means no such assignment exists.

Modern solvers (CDCL) decide, propagate, hit a conflict, learn a clause that forbids it, and jump back. DPLL (1962) had the decide-propagate-backtrack loop; GRASP (1999) added clause learning; Chaff (2001) made propagation cheap.

Every BMC Query Is This Question

Measured smtbmc log for a failing seq3 run (F2.3). One query per step; the last one was satisfiable.
Checking assumptions in step 0..
Checking assertions in step 0..
Checking assumptions in step 1..
Checking assertions in step 1..
Checking assumptions in step 2..
Checking assertions in step 2..
Checking assumptions in step 3..
Checking assertions in step 3..
Checking assumptions in step 4..
Checking assertions in step 4..
BMC failed!
Assert failed in seq3: design.sv:12.35-12.47 (_witness_.check_design_sv_12_assert_16)
Status: failed

Each query asks: is there an input sequence of length k that reaches a bad state? A satisfiable answer is a counterexample, and its model is the trace. An unsatisfiable answer says no failure exists at that step. In formal, UNSAT is the good news.

Words and Gates

Measured sweepThe Same Multiplier, Wider Each TimeBMC of mul_sa at depth W + 4, which covers one full multiplication. Whole-task time with SBY on this machine.
  • smtbmc yices
  • smtbmc boolector
  • smtbmc z3
  • abc bmc3
100 ms1 s10 s100 sTime4.04.55.05.56.06.57.07.58.0Operand width100 ms1 s10 s100 sTime45678Operand width
Read the plot as a table
Operand widthsmtbmc yicessmtbmc boolectorsmtbmc z3abc bmc3
4189 ms189 ms205 ms176 ms
4.5256.8 ms246.3 ms338 ms280.3 ms
5324.5 ms303.5 ms471 ms384.5 ms
5.5392.3 ms360.8 ms604 ms488.7 ms
6460 ms418 ms737 ms593 ms
6.51.293 s703.5 ms1.794 s1.445 s
72.127 s989 ms2.852 s2.297 s
7.56.319 s2.285 s9.634 s10.75 s
810.51 s3.582 s16.42 s19.2 s

Measured once per point. Single runs on one machine are not a ranking.

Wsmtbmc yicessmtbmc boolectorsmtbmc bitwuzlasmtbmc z3abc bmc3
40.2 s0.2 s0.2 s0.2 s0.2 s
60.5 s0.4 s0.4 s0.7 s0.6 s
72.1 s1.0 s0.9 s2.9 s2.3 s
810.5 s3.6 s9.8 s16.4 s19.2 s

Measured, PASS everywhere. At W = 8 the fastest was smtbmc boolector (3.6 s) and the slowest abc bmc3 (19.2 s).

An SMT solver is SAT plus theories. The bit-vector theory knows that a + b is an addition, rewrites x + 0 to x, and turns words into gates only when it must. smtbmc writes SMT-LIB2 with bit-vectors and arrays; abc works on the AIGER, where everything is already gates.

Multiplication is hard for every engine: here each extra bit multiplies the time by two to eight. The four SMT solvers differ in rewriting and in their SAT core, by design. On control logic a bit-level engine often wins; F4.7 measures that habit across engines.

Same Verdict, Different Time

mul_sa, W = 6, depth 10EngineMeasured resultTime
correctsmtbmc yicesPASS0.8 s
correctsmtbmc boolectorPASS0.7 s
bug: wrong multiplier bitsmtbmc yicesFAIL at step 90.5 s
bug: wrong multiplier bitsmtbmc boolectorFAIL at step 90.5 s
bug: wrong multiplier bitabc bmc3FAIL at step 90.3 s

The first four through the lab runner, the last with SBY directly. The failing step does not depend on the engine.

The rule in concurrent SVA

assert property (@(posedge clk) disable iff (rst)
  done |-> p == a_q * b_q);

When done, the product equals the operands captured at start.

What the engine runs

  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);

Two modelling flops hold the operands.

Asked in Interviews

QuestionAnswer
What is SAT, and why is UNSAT the good news?The question whether some assignment makes a formula true. An UNSAT BMC query means no counterexample of that length exists.
SAT or SMT: what does bit-vector reasoning buy?Word-level structure, rewriting and smaller formulas on datapaths. Bit-level engines often win on control logic and have IC3.
Name a SAT algorithm.DPLL; CDCL with clause learning (GRASP, Chaff).

Try It

The lab runs the 6-bit multiplier in bmc mode at depth 10 with smtbmc yices. Measured: PASS in 0.8 s.

  1. Change the solver

    Switch the engine to Boolector, Bitwuzla and Z3 in turn. The verdict stays; read the times.

  2. Plant the bug

    Change mplier[0] to mplier[1] and run two solvers. Both report the same step.

  3. Count the queries

    Open the SBY log: one "Checking assertions in step" line per step, each one a solver call.

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 outputmul_sa at W = 6 with the wrong multiplier bit, mode bmc, depth 10, smtbmc boolector, reset assumed in step 0. SBY reports the failure at step:
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[1]) p <= p + mcand;   // bug: wrong bit
      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
ConceptWhich statement is wrong?
ConceptWhat does bit-vector SMT add over plain SAT for a 32-bit adder?
ConceptIn the measured log, which line reports the satisfiable answer?

Remember

  • A SAT solver finds an assignment that makes every clause true, or proves none exists.
  • In BMC, SAT is a counterexample and UNSAT is the good news.
  • CDCL solvers learn a clause from each conflict.
  • SMT keeps words and arithmetic; bit-level engines see only gates. The verdict is the same, the time is not.