In simulation, every register starts as X and a testbench applies a reset before anything else. A formal tool starts differently: every register may hold any value in the first cycle, and the reset is just another input that can be high or low in any cycle. This article explains how a formal run starts, why a reset assumption is needed, why initial values in the RTL can mislead you, and how a missing reset on one register shows up as a counterexample.

9 min read | Beginner to Intermediate

What You'll Learn

  • Describe the start state of a formal run and how the reset assumption shapes it
  • Explain how formal treats registers without a reset and registers with an initial value
  • Find a register that is missing from the reset with a property
  • Explain why the reset should stay free after the first cycle

Any Value in the First Cycle

A formal tool does not know what the flip-flops of a chip contain when the power comes on, and neither does anybody else. So in step 0 every register is free: the tool may choose any value for it, just as it chooses inputs. Properties that hold only from a clean state would fail at once.

The fix is the reset assumption you have used in every example so far:


initial m_rst: assume (rst);       // SVA: reset in the first cycle

In the lab form it is the init register and if (init) assume (rst);, or initial assume (rst == 1'b1); as in the lab template. After the reset cycle, every register that the reset clears has its reset value, and the check starts from the same state as a real chip after reset.

Registers Without a Reset

Not every register needs a reset. Data registers in a pipeline usually have none, because their content is only used when a valid bit says so, and leaving out the reset saves area and power. In formal, such a register keeps an arbitrary value after the reset cycle, exactly as in silicon. That is correct, and the properties must cope with it: a data register without a reset can hold anything until the first valid word arrives.

The danger is a control register that should be reset and is not. Then the arbitrary value leaks into the behavior after reset, and the formal tool finds it, because it is free to choose the worst start value.

Quick Check

Q: After the reset cycle, a data register without a reset holds 8'hA5 in the counterexample. Is that a bug?

Show Answer

Not by itself. A register without a reset may hold any value until it is written. It is a bug only if that value is used, for example if it reaches an output while the output is marked valid.

The Design: a Valid Pipeline With a Missing Reset

This two-stage pipeline carries a data word and a valid bit. The data registers have no reset, which is fine. But the designer reset only the first valid bit:


module valid_pipe (input clk, input rst, input in_valid, input [7:0] in_data,
                   output out_valid, output [7:0] out_data);
  reg       v1, v2;
  reg [7:0] d1, d2;
  always @(posedge clk) begin
    if (rst) v1 <= 1'b0;                       // bug: v2 is not reset
    else     v1 <= in_valid;
    v2 <= v1;
    d1 <= in_data;
    d2 <= d1;
  end
  assign out_valid = v2;
  assign out_data  = d2;
endmodule

Two rules: every valid output word entered two cycles earlier, and nothing comes out in the cycle after a reset.


a_from_input: assert property (@(posedge clk) disable iff (rst) out_valid |-> $past(in_valid, 2));
a_after_rst:  assert property (@(posedge clk) $fell(rst) |-> !out_valid);

Running It in ChipVerify Lab


`ifdef FORMAL
  reg init = 1'b1;
  always @(posedge clk) init <= 1'b0;
  always @(*) if (init) assume (rst);
  // an output word is always one that came in two cycles earlier
  always @(posedge clk)
    if (!init && !$past(rst) && !$past(rst, 2) && out_valid) assert ($past(in_valid, 2));
  // no output in the cycle after reset
  always @(posedge clk) if (!init && $past(rst)) assert (!out_valid);
`endif

The run fails at step 2:

The tool started v1 at 1. The reset in step 0 clears v1, but v2 copies the old value of v1 at the same clock edge, so out_valid is high in step 1. A word that never went in comes out of the pipeline right after reset, carrying whatever the data registers held. Add v2 to the reset and the run passes.

Initial Values Can Hide a Missing Reset

Verilog allows an initial value in a declaration, such as reg v2 = 1'b0;. The formal tool honors it: the register starts at that value instead of an arbitrary one. FPGAs honor it too, because the configuration loads every flip-flop. An ASIC does not. Its flip-flops come up with unknown values, and synthesis for ASICs ignores initial values.

So an initial value can make a formal check pass on a design that fails in silicon. A counter without a reset and with initial q = 0 passes a range check, while the same counter without the initial value fails in step 1, starting from 14. For ASIC designs, keep initial values out of the RTL, or make sure the formal setup does not rely on them.

Keep the Reset Free After the First Cycle

The reset assumption only forces the reset in the first cycle. After that, rst is a free input like any other, and the tool may raise it at any time. This is deliberate. A real chip can be reset in the middle of operation, by a watchdog or by software, and the design must recover cleanly from a reset in any state, not just from power-up.

The exercise shows a bug that only a reset in the middle of traffic reveals.

Quick Check

Q: Why not assume the reset is low after the first cycle, to keep the traces simpler?

Show Answer

Because the design must handle a reset at any time. Forbidding later resets removes every sequence with a mid-operation reset, and reset bugs that only show up in a busy state are never found.

Common Mistakes

Mistake #1: Running without a reset assumption

Without it, the tool starts every register at its worst value and reports failures from states the chip never reaches after reset. Assume the reset in the first cycle.

Mistake #2: Using initial values as a substitute for reset

Formal and FPGA flows honor initial values, ASIC silicon does not, and a reset in the middle of operation ignores them anyway. A control register that must start clean needs a reset.

Mistake #3: Forbidding the reset after the first cycle

An assumption such as "rst is low after step 0" hides every bug that appears when the design is reset in a busy state. Leave the reset free.

Practice Exercise

Challenge: Initial Values Are Not a Fix

Open the example and run it. Instead of adding v2 to the reset, try a shortcut: give both valid bits an initial value, reg v1 = 1'b0; and reg v2 = 1'b0;. Run again. Does the check pass? Read the counterexample and explain it.

Hint

Look at the reset input in the counterexample. Is it only high in step 0?

Solution

The check still fails, now at step 4. The tool sends a valid word in step 1, so v1 is 1 in step 2, and raises the reset in step 2. The reset clears v1 but not v2, which copies the 1 and shows a valid output in step 3, the cycle after the reset. The initial values only help at power-up. The real fix is to reset v2:


if (rst) begin v1 <= 1'b0; v2 <= 1'b0; end
else     begin v1 <= in_valid; v2 <= v1; end

With it the run passes, with or without initial values.

Open the ready-made example in the lab and run the formal check from the formal panel. The free tier allows a depth of up to 10 cycles, and PRO allows up to 100.

Summary

  • In step 0 of a formal run, every register may hold any value. A reset assumption in the first cycle gives the clean start of a real chip.
  • Registers without a reset stay arbitrary after reset, in formal and in silicon. That is fine for data, and a bug for control.
  • A valid bit missing from the reset was found at step 2: a word came out of the pipeline right after reset.
  • Initial values in the RTL are honored by formal tools and FPGAs but not by ASICs, so they can hide a missing reset.
  • Keep the reset free after the first cycle, so that resets in the middle of operation are checked too.
Did you find what you were looking for?

Quiz

No quiz questions available for this article.