Assert, Assume, Cover: The Three Verbs

Run one line as assert, as assume and as cover, and read what each verdict does and does not say.

Lesson
F1.3
Time
15 min
Runs on
SymbiYosys
Check
4 questions

An engineer inherited a formal bench with a hundred green properties. Six of them were assume statements on outputs: someone had changed a failing assert to assume to get past it and never changed it back. The tool had been told to consider only the worlds where the bug did not happen. A cover on the symptom would have come back unreached in under a second and exposed the trick.

Assumptions as a DialLeft: no assumptions, the tool drives illegal inputs and reports false failures. Centre: the environment the spec describes. Right: assumptions on outputs or contradictory assumptions, and nothing is left to check. Arrows mean "produces".
Assumptions as a dialLeft: no assumptions, the tool drives illegal inputs and reports false failures. Centre: the environment the spec describes. Right: assumptions on outputs or contradictory assumptions, and nothing is left to check. Arrows mean "produces". component No assumptions every input value,every cycle component The legalenvironment assume what the specpromises component Assume onoutputs or assumptions thatcontradict component False failures traces the realmaster never sends component Real bugs only every FAIL isreachable component Nothing to check the proof is empty
Read the diagram as text
  • No assumptions: every input value, every cycle
  • The legal environment: assume what the spec promises
  • Assume on outputs: or assumptions that contradict
  • False failures: traces the real master never sends
  • Real bugs only: every FAIL is reachable
  • Nothing to check: the proof is empty
  • No assumptions → False failures
  • The legal environment → Real bugs only
  • Assume on outputs → Nothing to check

F3.2 and F3.3 turn the two wrong ends into a flow: catch over-constraint with covers, fix under-constraint with assumptions on inputs.

One Statement, Three Jobs

StatementWhat the tool doesWhat the result means
assert(p)Tries to break it and reports a counterexample if it can.FAIL: a bug, or a missing assumption (F1.4). PASS: no failure within the depth.
assume(p)Takes it as true and looks only at input sequences where it holds.The world shrinks. An assumption on an output hides design behaviour.
cover(p)Tries to reach it and reports the trace that does.Unreached: dead logic, or an assumption that rules it out.
restrict(p)An assumption that only formal honours.For formal-only case splits (F4.3). Simulators ignore it.

In simulation (A1.1 Why assertions) assume behaves as assert and cover counts hits. To a prover the three are different jobs.

The verb says who is responsible. Assume what the environment does. Assert what the design does. Cover what you expect to be possible. An assume on an output is the tool-side name for cheating: F3.1 makes this the master rule.

The Same Line, Four Runs

The cover trace: the shortest way to a double grant
012345clkfreerstfreereq000110011111000freeweight00A58000lockgnt000010011000A5 and 110gnt = 011, cover reachedSBY reports step 5

Measured with smtbmc yices. The cover is reached at sampled step 4 and reported at 5: the same steps as the assert's counterexample in F1.1.

Statements in the designModeMeasured resultTime
assert($onehot0(gnt))bmcFAIL at reported step 5520 ms
assume($onehot0(gnt)) in place of the assert (the cover line is dropped in this mode)bmcRefused: no assertion left to check169 ms
assume($onehot0(gnt)) alone, no cover linebmcRefused: no assertion, cover or live check148 ms
assume($onehot0(gnt)) and assert($onehot0(gnt))bmcBMC PASS to depth 20536 ms
cover(!$onehot0(gnt))coverCover reached, reported step 5515 ms
cover(!$onehot0(gnt)) under assume($onehot0(gnt))coverCover unreached within the depth535 ms
assert($onehot0(gnt)) under assume(weight != 8'hA5)bmcBMC PASS to depth 20536 ms

The buggy arb3 of F1.1 in every row; depth 20; smtbmc yices. The one thing that changes is the verb. Time is the wall time on this machine.

Row 2 is the trick from the hook. The assert became an assume and bmc drops the cover, so nothing is left to check. Plain SBY would print PASS anyway. This site refuses the job: a pass with no obligation means nothing. Row 3 is refused for the same reason.

Row 4 is what the inherited bench did, and no tool refuses it: the assert is "proven" because every world with two grants has been discarded. Row 6 is the sanity check that exposes it: the double grant became unreachable, and the design did not change.

Row 7 is the right shape of assumption, on an input. It also passes, and now the question is one for the spec, not the tool: does firmware ever write A5? In the F1.1 story it did. An assumption is a claim about the environment, and it goes into the sign-off list where someone must sign it (F7.3).

How the Engine Sees the Verbs

Concurrent SVA, as the industry writes it

assert property (@(posedge clk) disable iff (rst) $onehot0(gnt));
assume property (@(posedge clk) disable iff (rst) $onehot0(gnt));
cover property (@(posedge clk) !rst && !$onehot0(gnt));

Three verbs, one clock, the same expression.

Clocked immediate statements, as this engine runs them

always @(posedge clk) if (!rst) begin
  assert($onehot0(gnt));
  assume($onehot0(gnt));
  cover(!$onehot0(gnt));
end

Yosys turns them into $assert, $assume and $cover cells.

On this site a bmc or prove task keeps asserts and assumes and drops covers. A cover task drops asserts, keeps assumes and searches for the shortest trace to each cover. So one design file can carry all three verbs, and the mode selects the job. The reset is itself an assumption: rst high in the $initstate step and low afterwards (F1.6).

Asked in Interviews

QuestionAnswer
What are assert, assume and cover to a formal tool?Checked, believed, reached.
What happens if you assume a property on an output?The tool stops considering the behaviours where the design violates it. The proof is vacuous.
How do you detect an over-constraint?A cover on a behaviour you expect to be possible comes back unreached (F3.2).
What is restrict?An assumption that only formal honours; simulators ignore it. It is for formal-only case splits.

Try It

The task for the first run. For the cover runs change mode bmc to mode cover (the Mode selector below does the same).
[options]
mode bmc
depth 20
[engines]
smtbmc yices
[script]
read_verilog -formal -sv design.sv
prep -top arb3
[files]
design.sv
  1. Assert

    Run as it is: mode bmc. Read FAIL at reported step 5. The cover line is ignored in this mode.

  2. Assume

    Change assert( to assume( and run again: refused, because bmc drops the cover and no assertion is left. Add the assert line under the assume, run: PASS. Is the bug fixed?

  3. Cover

    Set the mode to cover and run. With the assume in place the double grant is unreached. Remove the assume: the cover is reached at reported step 5, and the trace is the F1.1 counterexample.

  4. The right assumption

    Back in mode bmc, delete the assume on gnt and add assume(weight != 8'hA5); beside the assert. PASS. Then decide: does the real firmware never write A5?

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 outputThe buggy arb3, mode bmc, default depth 20, reset assumed in step 0, with assume($onehot0(gnt)) added on the line above assert($onehot0(gnt)) (bmc drops the cover line). The summary verdict is:
module arb3(input clk, rst, input [2:0] req, input [7:0] weight, output reg [2:0] gnt=0);
  reg lock=0;
  reg [1:0] reload=0;
  wire [2:0] pri  = req[0] ? 3'b001 : req[1] ? 3'b010 : req[2] ? 3'b100 : 3'b000;
  wire       hold = lock && |(req & gnt);
  always @(posedge clk) begin
    if (rst) begin gnt<=0; lock<=0; reload<=0; end
    else begin
      lock   <= weight[7];
      reload <= (weight == 8'hA5 && req == 3'b110) ? 2'd1 : (reload == 2'd1 && req == 3'b011) ? 2'd2 : 2'd0;
      if (reload == 2'd2 && req == 3'b111) gnt <= gnt | pri;   // reload cycle: lock holds, encoder grants too
      else gnt <= hold ? gnt : pri;
    end
  end
  always @(posedge clk) begin
    if ($initstate) begin assume(rst); end else begin assume(!rst); end
  end
  always @(posedge clk) if (!rst) begin
    assume($onehot0(gnt));
    assert($onehot0(gnt));
    cover(!$onehot0(gnt));
  end
endmodule
ConceptWhich of these four lines is the wrong one to write?
ConceptA cover is unreached under your assumptions, at a depth beyond the longest trace you know. Which two causes must you consider?
Read the waveformIn the cover trace, which step reaches !$onehot0(gnt)?
The cover trace: the shortest way to a double grant
012345clkfreerstfreereq000110011111000freeweight00A58000lockgnt000010011000A5 and 110gnt = 011, cover reachedSBY reports step 5

Measured with smtbmc yices. The cover is reached at sampled step 4 and reported at 5: the same steps as the assert's counterexample in F1.1.

Remember

  • Assert: the tool tries to break it. Assume: the tool believes it and shrinks the world. Cover: the tool tries to reach it.
  • Assume what the environment does, assert what the design does, cover what should be possible.
  • An assume on an output makes the proof vacuous; a cover on the hidden behaviour comes back unreached.
  • restrict is an assume only formal honours. In simulation, assume checks like assert and cover counts.