A test can only show that a design works for the inputs you tried. Formal verification asks a bigger question: is there any input, at any time, that makes the design break a rule? If there is one, the tool finds it and shows it to you. If there is none, you know the rule holds for every input, not just for the ones in your tests.

Formal verification is a way of checking a hardware design by reasoning about it mathematically instead of running tests. You write down rules that the design must always follow, called properties, and a formal tool searches through every possible input sequence to find one that breaks a rule. This article explains the idea in plain words, shows a first property, and introduces the tool that ChipVerify Lab uses.

10 min read | Beginner to Intermediate

What You'll Learn

  • Explain what formal verification checks and how it differs from running tests
  • Describe what a property, a pass and a counterexample are
  • Read a first property written in SystemVerilog Assertions
  • List the limitations of formal verification
  • Say what the formal engine in ChipVerify Lab can do

The Problem With Tests

When you verify a design by simulation, you write a testbench. It drives inputs into the design, cycle by cycle, and checks the outputs. If the outputs are wrong, the test fails and you have found a bug.

The weak point is the word "drives". The testbench only drives the inputs that you, or a random generator, chose. A design with a few inputs and a few registers can receive an enormous number of different input sequences. Even millions of test cycles try only a small part of them. If a bug hides behind an unusual sequence that no test produces, the simulation passes and the bug goes into the chip.

Formal verification turns the problem around. You do not choose the inputs at all. You only say what must always be true, and the tool looks for any input sequence that makes it false.

Properties: Rules the Design Must Follow

A property is a rule about the behavior of a design, written so that a tool can check it. Some examples, in words:

  • A counter that counts from 0 to 5 never shows a value larger than 5.
  • A FIFO never accepts data when it is full.
  • An arbiter never gives the grant to two requesters at the same time.
  • After a request, an acknowledge comes within 4 clock cycles.

These rules are written in a language that the tool understands. The standard language is SystemVerilog Assertions, SVA, which is part of SystemVerilog. Here is the first rule of the list as SVA, for a counter with the output q:


assert property (@(posedge clk) disable iff (rst) q <= 3'd5);

Read it from left to right:

  • assert property: this is a rule that must always hold.
  • @(posedge clk): check it at every rising edge of the clock.
  • disable iff (rst): do not check it while the reset is active.
  • q <= 3'd5: the rule itself, the counter value is at most 5.

That one line replaces a whole family of tests. It does not say which inputs to apply. It says what must be true for all of them.

Quick Check

Q: Does a property tell the formal tool which input values to try?

Show Answer

No. A property only says what must be true. The tool itself decides which inputs to try, and it considers all of them.

Two Possible Answers

A formal tool takes the design and the properties, and gives one of two answers for each property:

  • Pass. The tool found no input sequence that breaks the property. Depending on the method, this holds for every sequence up to a certain number of clock cycles, or for every sequence of any length. Chapter 5 and Chapter 6 explain the difference.
  • Fail, with a counterexample. The tool found an input sequence that breaks the property. It gives you that sequence as a waveform, cycle by cycle, which you can open like a simulation result. This waveform is called a counterexample, because it is an example that goes against your rule.

The counterexample is the most useful thing a formal tool produces. It is a short, exact recipe for the bug, often only a few cycles long, with no unrelated activity around it.

A First Example

Here is a small counter that is meant to count from 0 to 5 and then start again at 0, for example to count the tens of seconds of a clock:


module mod6 (input clk, input rst, input en, output reg [2:0] q);
  always @(posedge clk)
    if (rst)     q <= 3'd0;
    else if (en) q <= (q == 3'd6) ? 3'd0 : q + 3'd1;   // bug: should be 3'd5

  assert property (@(posedge clk) disable iff (rst) q <= 3'd5);
endmodule

The designer made a small mistake: the counter wraps at 6 instead of 5, so it shows the value 6 for one count. A simulation finds this only if a test runs long enough with en high and someone checks the value. The formal tool finds it by itself. On the lab engine it reports a failure at step 8 and gives this counterexample:

The tool chose the inputs: a reset in the first cycle, and then en high long enough for the counter to climb to 6. Nobody wrote those inputs. With the wrap value corrected to 5, the same run passes.

Quick Check

Q: In the counterexample, who decided that en is 1 for six cycles?

Show Answer

The formal tool. It searched for any input sequence that breaks the property and found this one. There is no testbench that drives en.

Why It Is Called Formal

The word formal comes from mathematics, where a formal proof follows exact rules. The tool turns the design and the property into a mathematical problem: is there a sequence of input values for which the property is false? A program called a solver answers that question. It does not try the sequences one by one, which would take forever. It reasons about all of them at once. The article about how a model checker works shows the idea.

Formal Verification in ChipVerify Lab

ChipVerify Lab has a formal engine built from open-source tools: SymbiYosys, which reads the design with Yosys, and three solvers, bitwuzla, boolector and z3. It runs bounded model checking. That means it checks every input sequence up to a number of clock cycles that you choose, called the depth. The depth limit is 10 cycles on the free tier and 100 cycles with PRO. When a property fails, the lab shows the counterexample as a waveform.

Limitations of Formal Verification

Formal verification is exhaustive, but only inside some clear limits. Knowing them is as important as knowing its strengths, because a pass outside these limits means nothing.

  • It checks only the properties you write. A rule that nobody wrote down is never checked. If the properties miss an important behavior, a design can pass every formal check and still be wrong. Formal is only as complete as its list of properties.
  • It checks only the inputs your assumptions allow. Assumptions tell the tool which inputs are legal. An assumption that is too strict removes real input sequences from the search, and a bug that needs those inputs is never found. In the worst case a wrong assumption makes every property pass without checking anything.
  • The design must fit in the tool. Every register doubles the number of possible states. Large blocks, wide arithmetic such as multipliers and floating-point units, big memories and long counters can make a formal run very slow or impossible to finish. Formal is used on blocks of moderate size, not on a whole chip.
  • A bounded check stops at its depth. Bounded model checking, which the lab uses, only looks at a fixed number of clock cycles. A bug that needs more cycles to appear is not found. A full proof for any number of cycles is possible, but it does not always finish, and then the result is inconclusive.
  • It works on the logic model only. Formal reasons about the 0 and 1 values of the RTL. It does not check analog behavior, the timing of real gates and wires (that is the job of static timing analysis), power, or clocks that drift against each other. It also cannot say whether the specification itself is what the customer wanted.
  • It takes skill. Writing good properties and assumptions, and reading counterexamples, is a skill of its own. A beginner can start in minutes, but proving a complex block can take an expert days or weeks.

These limits are why formal and simulation are used together, each where it is strongest. The article about formal verification vs simulation compares them in detail.

Running It in ChipVerify Lab

The open-source front end of the lab does not read the concurrent form assert property (@(posedge clk) ...). The lab example writes the same rule in a form that it accepts: an assert inside a clocked always block, placed in an `ifdef FORMAL section so that simulation tools ignore it.


`ifdef FORMAL
  reg init = 1'b1;                                // high only in the first cycle
  always @(posedge clk) init <= 1'b0;
  always @(*) if (init) assume (rst);             // start from a reset
  always @(posedge clk) if (!init) assert (q <= 3'd5);
`endif

The assume line tells the tool to start with a reset, and the assert is the rule. The meaning is the same as the one-line SVA property. Chapter 2 explains each line, and Chapter 3 compares the two forms of assertions in detail.

Common Mistakes

Mistake #1: Thinking a passing formal run means the design is correct

A pass means the properties you wrote hold. If an important rule was never written down, the tool never checks it. Formal is only as complete as its list of properties.

Mistake #2: Expecting formal to replace all simulation

Formal works best on blocks of moderate size and on rules that can be written precisely. Large systems, software running on a processor, and performance questions are still checked by simulation. The two methods are used together.

Practice Exercise

Challenge: Find and Fix the Counter Bug

Open the example below in ChipVerify Lab. It is the counter of this article with the wrong wrap value. Run the formal check with a depth of 10 and look at the counterexample. Find the line that causes it, fix it, and run again.

Hint

Look at the value of q in the last steps of the waveform. Which value should never appear, and which line of the RTL lets it appear?

Solution

The counterexample shows q reaching 6 after six counts. The wrap condition compares with 6, so the counter only goes back to 0 after it has shown 6. Change (q == 3'd6) to (q == 3'd5). The run then passes: no input sequence within the depth makes q larger than 5.

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

  • Formal verification checks a design against rules, called properties, for every possible input sequence instead of the inputs of a test.
  • A property says what must be true, not which inputs to apply. The standard language is SystemVerilog Assertions.
  • The tool answers with a pass, or with a counterexample: a short waveform that shows exactly how the rule is broken.
  • The tool reasons about all input sequences at once with a solver, instead of trying them one by one.
  • Formal checks only the properties you write, under the assumptions you give, on designs small enough for the tool, and only the logic model: no analog, timing or power.
  • ChipVerify Lab runs bounded model checking with SymbiYosys, up to 10 cycles on the free tier and 100 with PRO, and shows counterexamples as waveforms.
Did you find what you were looking for?

Quiz

No quiz questions available for this article.