Liveness, Fairness, Deadlock

Read a liveness failure as a loop, add the fairness the environment really gives, run the bounded substitute, and find a deadlock as a safety failure.

Lesson
F3.7
Time
15 min
Runs on
SymbiYosys
Check
4 questions

An arbiter's "every request is eventually granted" passed in live mode on the first try. The job also held the block's safety assertions, and the liveness flow had quietly turned them into assumptions, one of which pruned the path where the third requester starved. Run alone, with fairness on ready and nothing else, the property failed with a loop of eleven states.

A liveness counterexample is a lasso

A prefix from reset to a request, then a loop the design can repeat forever. gnt is 0 in every state of the loop, so the promised grant never comes.

A liveness counterexample is a lassoA prefix from reset to a request, then a loop the design can repeat forever. `gnt` is 0 in every state of the loop, so the promised grant never comes.Reachable from resetresetDepth 0req seenDepth 1pending, ready 0Bad statepending, ready 0Bad statepending, ready 0Bad stategntUnreachable

Around the loop pending stays 1 and gnt stays 0. No finite step fails; the failure is the loop itself, and only a liveness engine can return it.

Read the states and transitions
  • reset: initial, depth 0.
  • req seen: reachable, depth 1.
  • pending, ready 0: bad, depth 2.
  • pending, ready 0: bad, depth 3.
  • pending, ready 0: bad, depth 4.
  • gnt: unreachable, depth 0.
  • reset → req seen.
  • req seen → pending, ready 0.
  • pending, ready 0 → pending, ready 0.
  • pending, ready 0 → pending, ready 0.
  • pending, ready 0 → pending, ready 0.

Illustration. A drawing, not an engine witness. The state labelled gnt is never entered on this path.

Fairness: The Stall Always Ends

Bounded response, no fairness: the solver never lets ready rise
012345678910clkfreerstfreereqfreereadypendinggntreqwindow openswindow closes, no gntSBY reports FAIL

Measured with smtbmc yices at depth 20. The window is steps 2 to 9; ready is low in all 8 of them, so no design could grant.

A liveness property (F1.5) fails on a loop, not at a step. Most such failures on a correct design are the environment's: the solver holds ready low forever, and no design can grant. A fairness constraint is a liveness assumption on the environment: assume property (@(posedge clk) s_eventually ready); says the stall always ends, without saying when.

Liveness without fairness fails on almost everything. Fairness that is never checked hides almost everything, which is why a live job needs a sanity run (below). The editor here runs the bounded forms; liveness itself is drawn, not run.

Bounded runMeasured resultTime
req |-> ##[1:8] gnt, no fairnessFAIL at reported step 10689 ms
plus !ready |-> ##[1:4] readyBMC PASS to depth 20730 ms
plus $fell(ready) |-> ##[1:4] ready insteadFAIL at reported step 10731 ms
Grant needs two ready cycles running, bounded fairnessFAIL at reported step 10733 ms
No fairness, clocked immediate formFAIL at reported step 10516 ms

hs_live; mode bmc, depth 20, smtbmc yices, reset assumed in step 0. The range comes from A2.1.

The $fell form fails because ready can be low from reset: it never falls, so the assumption never starts. The two-cycle bug fails under fair stalls too, because ready may rise for one cycle at a time. Bounded response is weaker than liveness, since it invents a deadline the spec may not state, and far cheaper.

Three Ways to Make No Progress

Deadlock, Livelock, StarvationThree ways to make no progress, and the property kind that finds each. Arrows mean "is found by".
Deadlock, livelock, starvationThree ways to make no progress, and the property kind that finds each. Arrows mean "is found by". component Deadlock one stuck state,repeated component Livelock a loop of legal states:retry, back off,retry component Starvation a loop in which onerequester is neverserved component Safety, in bmc !(sa == 1 && sb ==1): a finite trace component Liveness req |-> s_eventuallygnt: a lasso component Liveness plusfairness or a round-robin fix
Read the diagram as text
  • Deadlock: one stuck state, repeated
  • Livelock: a loop of legal states: retry, back off, retry
  • Starvation: a loop in which one requester is never served
  • Safety, in bmc: !(sa == 1 && sb == 1): a finite trace
  • Liveness: req |-> s_eventually gnt: a lasso
  • Liveness plus fairness: or a round-robin fix
  • Deadlock → Safety, in bmc
  • Livelock → Liveness
  • Starvation → Liveness plus fairness

Only deadlock is reached at a finite step. Livelock and starvation have no bad state, only a bad loop.

Deadlock found as a safety failure
0123clkfreego_afreego_bsasbown1own202both gosa 1, sb 1: stuckSBY reports FAIL

Measured at depth 20. own1 = 1 (A) and own2 = 2 (B) from step 2 on: a single state the pair can never leave. With both machines taking lock 1 first: BMC PASS to depth 20.

A deadlock is a safety property in disguise: one stuck state, reached at a finite step, so bmc finds it. Livelock and starvation have no bad state; every state on the loop is legal and only the loop is wrong (A3.1 Weak and strong).

Three Rules for a Live Job

RuleWhy
One s_eventually assertion per job, and no safety assertions in itSBY's live mode turns asserts into assumptions. Prove safety in its own task first, on the same design and environment.
One obligation per jobThe liveness engine reads only the first obligation. Two properties need two jobs.
A sanity job: assert property (@(posedge clk) s_eventually 1'b0); must FAILIf it passes, the fairness left no infinite path, and every liveness proof under it was about nothing.
Never put s_eventually in a bmc or prove taskPlain SBY drops liveness checks in those modes and passes.

The traps come from the pinned SBY flow; commercial tools have the same traps under other names.

Written out, the live job is assert property (@(posedge clk) req |-> s_eventually gnt); with assume property (@(posedge clk) s_eventually ready);, alone, plus the sanity job. When a liveness proof will not converge, the bounded form above is the common substitute; record the deadline you chose as a reviewed assumption.

Asked in Interviews

QuestionAnswer
How do you write "every request is eventually granted"?req |-> s_eventually gnt in a live job, alone, with the fairness the environment really gives and a sanity job showing a fair path exists.
What is a fairness constraint?A liveness assumption on the environment: a stall always ends.
Deadlock, livelock, starvation?A stuck state (safety, finite trace); a loop of legal states with no progress (liveness); a loop in which one party is never served (liveness, usually arbitration).

Try It

Liveness, as IEEE SVA writes it

assert property (@(posedge clk) req |-> s_eventually gnt);
assume property (@(posedge clk) s_eventually ready);
// sanity job, must FAIL:
assert property (@(posedge clk) s_eventually 1'b0);

A live job: no depth, a loop as the counterexample.

The bounded substitute this editor runs

assume property (@(posedge clk) disable iff (rst) !ready |-> ##[1:4] ready);
assert property (@(posedge clk) disable iff (rst) req |-> ##[1:8] gnt);

Safety: a finite window and a finite stall.

Mode bmc, default depth 20. A live task has no depth at all.
[options]
mode bmc
depth 20
[engines]
smtbmc yices
[script]
read_verilog -formal -sv design.sv props.sv
prep -top hs_live
[files]
design.sv
props.sv
  1. Run without fairness

    Run as it is: FAIL at reported step 10. Count the window steps with ready low.

  2. Add bounded fairness

    Add the !ready |-> ##[1:4] ready assumption as the first line of props.sv: BMC PASS to depth 20.

  3. Try the $fell form

    Write it as assume property (@(posedge clk) disable iff (rst) $fell(ready) |-> ##[1:4] ready); with the registered ready_q. Why does it not help?

  4. Ask the spec

    What deadline does the spec actually state for the grant? What did the bounded form add?

  5. Find the deadlock

    Run two_fsm as safety: FAIL at reported step 3. Then make both machines take lock 1 first.

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 outpuths_live, correct RTL, mode bmc, default depth 20, smtbmc yices, reset assumed in step 0, req |-> ##[1:8] gnt with no assumption on ready. SBY reports the failure at which step?
module hs_live(input clk, rst, req, ready, output reg gnt=0);
  reg pending=0;
  reg ready_q=0;   // last cycle's ready
  wire go = (pending || req) && ready;
  always @(posedge clk) begin
    ready_q <= ready;
    if (rst) begin pending <= 0; gnt <= 0; end
    else begin
      gnt <= go;
      if (go) pending <= 0;
      else if (req) pending <= 1;
    end
  end
`ifdef FORMAL
  always @(posedge clk) begin
    if ($initstate) begin assume(rst); end else begin assume(!rst); end
  end
`endif
endmodule
Read included file: props.sv
assert property (@(posedge clk) disable iff (rst) req |-> ##[1:8] gnt);
ConceptWhich live job layout is wrong?
ConceptDeadlock, livelock, starvation: which is a safety property?
Read the waveformIn the bounded trace without fairness, how many window steps after the request pass with ready low before the check fails?
Bounded response, no fairness: the solver never lets ready rise
012345678910clkfreerstfreereqfreereadypendinggntreqwindow openswindow closes, no gntSBY reports FAIL

Measured with smtbmc yices at depth 20. The window is steps 2 to 9; ready is low in all 8 of them, so no design could grant.

Remember

  • A liveness counterexample is a lasso: a prefix and a loop in which the promised event never comes.
  • Fairness is a liveness assumption on the environment; without it, liveness fails on almost everything.
  • A live job holds one obligation and no safety asserts, and a sanity job must show a fair path exists.
  • Deadlock is safety and bmc finds it; bounded response is the cheap substitute for liveness, with a deadline the spec may not state.