The Sign-Off Argument

Compute the depth a bounded proof must reach, expose a hidden over-constraint with a cover, and write the one-page argument a lead can accept or reject.

Lesson
F7.3
Time
25 min
Runs on
SymbiYosys
Check
5 questions

Two blocks reached review with the same line: "bounded proof, depth 12, no failures". The lead asked how deep a trace must be to show the worst bug. One block needed depth 11 and was accepted; the other needed depth 17 and was sent back.

A Bounded PASS Needs a Second Number

TMO = 6: the bound reaches the bug

Depth 12 against the required depth 11 of the TMO = 6 block with the late-error bug.

Linear scale. 0 to 20 steps.

Checked bound
12
Required bound
11
First reported failure
10
Claim
Counterexample found

Measured: depth 12 gives FAIL at reported step 10. The bound covers the bug.

TMO = 12: the bound stops short

Depth 12 against the required depth 17 of the TMO = 12 block with the late-error bug.

Linear scale. 0 to 20 steps.

Checked bound
12
Required bound
17
First reported failure
16
Claim
Counterexample found

Measured: depth 12 gives BMC PASS to depth 12; depth 20 gives FAIL at reported step 16. The bound stopped short.

A bounded PASS means nothing on its own. It becomes an argument next to the required depth: the shortest trace from reset that could show a violation. Reached above required is a bounded sign-off. Reached below it is a PASS and nothing more.

The Required-Depth Worksheet

Line of the worksheetTMO = 6TMO = 12
Reset step11
Request accepted11
Deepest counter in the cone: the timeout612
Longest tail of the transaction: the late cycle11
The property's own window: |=>11
SBY: depth N checks samples up to N − 211
Required depth1117
Measured: smallest failing bmc depth11 (depth 10 passes)17 (depth 16 passes)

Filled before running, then checked against a depth sweep on the buggy block. The counter comes from the cone map (F7.1), not from the whole design.

Three lines carry the design: the deepest counter the property depends on, the longest transaction, and the property's own window (A2.1). The rest is bookkeeping. The engine agreed with the worksheet to the step.

Same Depth, Two Verdicts

Run on tmo_blkMeasured result
TMO = 6, bug, bmc depth 12FAIL at reported step 10
TMO = 12, bug, bmc depth 12BMC PASS to depth 12
TMO = 12, bug, bmc depth 20FAIL at reported step 16
TMO = 12, bug, k-induction depth 12UNKNOWN at k = 12 (base case passed, induction step failed)
TMO = 12, bug, abc pdrFAIL at reported step 17
TMO = 12, fixed, abc pdrProve PASS (abc pdr)

Reset assumed in step 0, smtbmc yices unless named.

The request lost after a timeout
012345678910111213141516clkfreereqfreegrant_inpendingcnt01234567891011latereq_qcnt = TMO - 1: timeoutlate: req droppedcheck failsreported step 16

Measured, TMO = 12, bmc depth 20: FAIL at reported step 16. The request in the late cycle is dropped, so pending stays low.

When prove closes, the depth argument is unnecessary: the proof holds for all time. When it does not close, the report says "bounded, depth D, required R". A report that says only PASS has left the argument out.

k-induction at depth 12 returns UNKNOWN on the buggy block: no proof and no failure. PDR finds the counterexample, and on the fixed block it closes the proof, which needs no worksheet at all.

The Hidden Over-Constraint

Grant assumed within four cycles

assume property (@(posedge clk) pending && cnt >= 3 |-> grant_in);
cover property (@(posedge clk) !rst && pending && cnt == TMO - 1 && !grant_in);

Buggy block: Prove PASS (abc pdr). Timeout cover: Cover unreached within depth 20.

No extra assumption

cover property (@(posedge clk) !rst && pending && cnt == TMO - 1 && !grant_in);

Timeout cover: Cover reached, reported step 14. The buggy block fails.

One innocent-looking assumption made the timeout unreachable, and the proof of a buggy block passed. The cover caught it. Every assumption in a sign-off needs a reason from the spec and a cover that stays reachable under it.

The Four Cs

The Four Lists a Lead ReviewsConstraints, checkers, complexity and coverage: each list has an open-tool result under it.
The four lists a lead reviewsConstraints, checkers, complexity and coverage: each list has an open-tool result under it. list Constraints every assumption, itsreason, and a coverreached under it list Checkers the spec checklistand a mutation scorewith its sample(F7.2) list Complexity per property: fullproof, or boundedwith its worksheet;each abstraction withits soundness note list Coverage the cone map, whitelogic named (F7.1);cover depths result One-pagesign-off the four lists, thedepth bar perproperty, suiteversion, date
Read the diagram as text
  • Constraints: every assumption, its reason, and a cover reached under it
  • Checkers: the spec checklist and a mutation score with its sample (F7.2)
  • Complexity: per property: full proof, or bounded with its worksheet; each abstraction with its soundness note
  • Coverage: the cone map, white logic named (F7.1); cover depths
  • One-page sign-off: the four lists, the depth bar per property, suite version, date
  • Constraints → One-page sign-off
  • Checkers → One-page sign-off
  • Complexity → One-page sign-off
  • Coverage → One-page sign-off

A gap in any list is a reason to reject, however green the runs are.

Sign-off lineAccepted?
Proven: abc pdr, SBY v0.70-9-g79fc9ed, 2026-11-08yes
Bounded, depth 20, required 17, worksheet attachedyes
Bounded, depth 12, required 17no: prove, or run deeper
All properties PASSno: mode and depth missing

The verdict words of this track, with the numbers that make them reviewable.

Each card is a list a reviewer can check line by line. Constraints come first, because one bad assumption voids every result after it, as the grant assumption just showed.

Required depth is the floor. A common margin is twice the deepest cover, so that two operations back to back fit inside the bound.

Asked in Interviews

QuestionAnswer
When can a block be signed off with formal alone?When every property is proven or bounded above its required depth, the assumptions are listed and justified with covers reachable under them, the cone map is dispositioned, and the mutation score is quoted with its sample.
What is a bounded-proof argument?The required depth from the deepest counter in the cone, the longest transaction and the property window, set against the depth reached. Here 12 covers TMO = 6 (needs 11) and not TMO = 12 (needs 17).
What are the four Cs of formal sign-off?Constraints, checkers, complexity and coverage: the four lists a reviewer reads before accepting a block.

Try It

The lab is tmo_blk with TMO = 6 and the late-error bug, bmc at depth 12: FAIL at reported step 10 in 0.5 s. The rule in concurrent SVA; the design runs it as req_q and an immediate assertion.

No request is lost: a request seen while idle is pending one cycle later.
assert property (@(posedge clk) disable iff (rst) req && !pending |=> pending);
  1. Fill the worksheet first

    Before running, compute the required depth for TMO = 6 and TMO = 12. Then run and compare the failing step.

  2. Accept or reject?

    Set localparam TMO = 12; and run at depth 12. Write the sign-off line for that PASS, then rerun at the depth your worksheet asks for.

  3. Find the over-constraint

    Add the assumption that the grant comes within four cycles, switch to abc pdr, then turn the check into the timeout cover. Read both.

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 outputtmo_blk, TMO = 12, late-error bug on, mode bmc, depth 12, smtbmc yices, reset assumed in step 0. The verdict is:
module tmo_blk(input clk, rst, req, grant_in, output reg pending = 0, output reg err = 0);
  localparam TMO = 12;
  reg [3:0] cnt = 0;      // waiting cycles
  reg late = 0;           // the cycle after a timeout
  always @(posedge clk)
    if (rst) begin pending <= 0; cnt <= 0; err <= 0; late <= 0; end
    else begin
      err <= late;
      late <= 0;
      if (!pending) begin
        if (req && !late) begin pending <= 1; cnt <= 0; end   // bug: a req in the late cycle is dropped
      end else if (grant_in) pending <= 0;
      else if (cnt == TMO - 1) begin pending <= 0; late <= 1; end
      else cnt <= cnt + 4'd1;
    end
`ifdef FORMAL
  always @(posedge clk) begin
    if ($initstate) begin assume(rst); end else begin assume(!rst); end
  end
  reg req_q = 0;           // registered copy: a request seen while idle
  always @(posedge clk) begin
    req_q <= !rst && req && !pending;
    if (!rst && req_q) assert(pending);
  end
`endif
endmodule
Predict the outputThe same block with TMO = 6, mode bmc, depth 12, smtbmc yices, reset assumed in step 0. At which step does SBY report the failure?
module tmo_blk(input clk, rst, req, grant_in, output reg pending = 0, output reg err = 0);
  localparam TMO = 6;
  reg [3:0] cnt = 0;      // waiting cycles
  reg late = 0;           // the cycle after a timeout
  always @(posedge clk)
    if (rst) begin pending <= 0; cnt <= 0; err <= 0; late <= 0; end
    else begin
      err <= late;
      late <= 0;
      if (!pending) begin
        if (req && !late) begin pending <= 1; cnt <= 0; end   // bug: a req in the late cycle is dropped
      end else if (grant_in) pending <= 0;
      else if (cnt == TMO - 1) begin pending <= 0; late <= 1; end
      else cnt <= cnt + 4'd1;
    end
`ifdef FORMAL
  always @(posedge clk) begin
    if ($initstate) begin assume(rst); end else begin assume(!rst); end
  end
  reg req_q = 0;           // registered copy: a request seen while idle
  always @(posedge clk) begin
    req_q <= !rst && req && !pending;
    if (!rst && req_q) assert(pending);
  end
`endif
endmodule
ConceptWhat goes into the required depth of a bounded proof?
ConceptWhich sign-off line does a reviewer reject on form alone?
Read the waveformIn the measured TMO = 12 trace, at which step does the counter reach TMO − 1, and when is the dropped request sampled?
The request lost after a timeout
012345678910111213141516clkfreereqfreegrant_inpendingcnt01234567891011latereq_qcnt = TMO - 1: timeoutlate: req droppedcheck failsreported step 16

Measured, TMO = 12, bmc depth 20: FAIL at reported step 16. The request in the late cycle is dropped, so pending stays low.

Remember

  • A bounded PASS is an argument only next to its required depth.
  • Required depth: the deepest counter in the cone, the longest transaction, the property window, plus the engine offset; check it with a depth sweep.
  • Every assumption needs a reason and a cover reachable under it; one over-constraint can make a buggy block prove.
  • The four Cs: constraints, checkers, complexity, coverage. A sign-off line names mode, depth, required depth, tool version and date.