Simulation and formal verification both look for bugs, but they look in very different ways. Simulation runs the design on chosen inputs and watches what happens. Formal verification reasons about all inputs at once and looks for one that breaks a rule. This article compares the two side by side, shows a bug that simulation almost never finds and formal finds in three clock cycles, and explains why real projects use both.
8 min read | Beginner to Intermediate
What You'll Learn
- Describe how simulation and formal verification each look for bugs
- Explain why a rare input value can hide a bug from random simulation
- List the strengths and the limits of each method
- Decide which method fits a given verification question
How Simulation Looks for Bugs
A simulator runs the design like a real circuit, one clock cycle after another. A testbench supplies the inputs: some are written by hand, many are random. Checkers in the testbench compare the outputs with the expected values. Simulation answers the question: does the design do the right thing for these inputs?
Simulation is flexible. It can run a whole chip, with a processor executing a program, for millions of cycles. It checks the real function of the design, end to end. But it can only find a bug if the inputs happen to lead to it, and if a checker notices it.
How Formal Looks for Bugs
A formal tool does not run the design with chosen inputs. It treats every input as unknown and asks: is there any value of these inputs, in any cycle, that makes a property false? The solver answers that question for all input values together. Formal answers the question: is there any input that breaks this rule?
Formal is complete for the question it is asked. If a failing input sequence exists within the bound, the tool finds it. The price is that the question must be written as a property, and that the tool can only handle designs of limited size, because the problem grows quickly with every register.
Quick Check
Q: A random simulation runs for one million cycles without a failure. Does that prove the design correct?
Show Answer
No. It shows that the one million input combinations that were tried did not expose a failure. Other inputs, which were never tried, can still break the design.
A Bug That Simulation Almost Never Finds
Here is a small block that raises an alarm output. The alarm must never be raised in normal operation. But the designer left a piece of debug code in it, which sets the alarm when the 32-bit data input has one special value:
module alarm_unit (input clk, input rst, input [31:0] data, output reg alarm);
always @(posedge clk)
if (rst) alarm <= 1'b0;
else if (data == 32'hDEADBEEF) alarm <= 1'b1; // left-over debug code
assert property (@(posedge clk) disable iff (rst) !alarm);
endmodule
A 32-bit input has 2 to the power 32 values, about 4.3 billion. A random test that applies a new random value in every cycle hits the special value on average once in 4.3 billion cycles. A typical regression of a few million cycles almost certainly never sees it, and the bug ships in the chip.
The formal tool finds it at once. On the lab engine, the property fails at step 3, with this counterexample:
The tool did not get lucky. It asked the solver whether any value of data sets the alarm, and the solver worked out the only value that does, 32'hDEADBEEF. The size of the input space does not matter to it in the way it matters to random testing.
Side by Side
| Simulation | Formal verification | |
|---|---|---|
| Inputs | Chosen by tests and random generators | All values, chosen by the tool |
| Question | Does it work for these inputs? | Is there any input that breaks this rule? |
| Rare corner cases | Found only if a test reaches them | Found if they break a property |
| Design size | Whole chip | Blocks of limited size |
| Length in time | Millions of cycles | Tens to a few hundred cycles, or a proof for all lengths |
| What you write | Testbench and checkers | Properties and assumptions |
| Result of a failure | A long log of a test | A short counterexample, usually a few cycles |
Where Each One Wins
Formal is strongest for:
- Control logic with many corner cases: arbiters, FIFOs, state machines, handshakes.
- Rules that must hold always: no overflow, no deadlock, at most one grant, no data lost.
- Rare values and rare orderings, like the debug code above.
- Proving that two versions of a design are equivalent, for example before and after synthesis.
Simulation is strongest for:
- Large systems, where the formal problem would be too big.
- Long scenarios, such as booting a processor or sending a whole packet stream.
- Checking that the design does the right thing overall, not only that it follows a list of rules.
- Analog models, software, and performance measurements.
Quick Check
Q: You want to check that a round-robin arbiter never grants two masters at once. Which method fits best, and why?
Show Answer
Formal verification. The rule is short and must hold in every cycle, the arbiter is a small block, and the dangerous cases are rare orderings of requests that random tests can miss.
Using Both
Real projects do not choose one method. A common split is:
- The designer uses formal on a new block while writing it, to catch mistakes in minutes without a testbench.
- The verification team proves the key rules of the critical blocks with formal.
- Simulation, often with a UVM testbench, checks the complete function and the integration of the blocks.
- The same assertions are used in both: in formal as rules to prove, in simulation as checkers that fire when a test breaks them.
The last point matters. An SVA property written for formal also works in a simulator. Writing it once gives value twice.
Running It in ChipVerify Lab
The lab example writes the rule of the alarm unit in the form that the open-source engine accepts:
`ifdef FORMAL
reg init = 1'b1;
always @(posedge clk) init <= 1'b0;
always @(*) if (init) assume (rst);
always @(posedge clk) if (!init) assert (!alarm);
`endif
The counterexample is short, so it fits in the free depth of 10 cycles.
Common Mistakes
Mistake #1: Measuring formal by the number of cycles it runs
A formal run of 20 cycles is not "less" than a simulation of a million cycles. It covers every input sequence of 20 cycles, which is far more combinations than any simulation can try. What it does not cover is behavior that needs more than 20 cycles to appear.
Mistake #2: Writing properties that only repeat the RTL
A property such as "if data is DEADBEEF then alarm is set" restates the code and proves nothing useful. Write what the design must do from the outside, such as "alarm is never set in normal operation".
Practice Exercise
Challenge: Find the Magic Value
Open the alarm example in ChipVerify Lab and run the formal check. Read the value of data in the counterexample. Then change the debug value in the RTL to another 32-bit number of your choice and run again. Does the tool find the new value as quickly?
Hint
The solver does not search the values in order. Think about whether the size of the number makes any difference to it.
Solution
The first run shows data = 32'hDEADBEEF in step 1. With any other value, the counterexample shows that value instead, again within a few steps. The solver works out the value from the comparison in the logic. It does not count up through the 4.3 billion possibilities, so the choice of the value makes no practical difference.
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
- Simulation checks the inputs that tests choose. Formal checks whether any input breaks a property.
- A bug that needs one value out of 4.3 billion is almost never found by random simulation, and formal finds it in a few cycles.
- Formal suits control logic and rules that must always hold, in blocks of limited size.
- Simulation suits large systems, long scenarios and checking the overall function.
- Projects use both, and the same SVA assertions serve as proof targets in formal and as checkers in simulation.