Interviews

Formal Verification Interview Questions

Practise the question, then the follow-ups an interviewer asks next.

Start with a Question TreeAI Mock Interview

25
Question trees
170
Follow-ups
92
Wrong answers explained
41
Runnable on a simulator
Question tree The interviewer asksA mode register has no reset, because firmware writes it before start. Simulation passes, but formal fails at step 3. Who is right? WhyWhy an Unreset Flop Is a Free ValueCompareX-Optimism, X-Pessimism and Free ValuesBreak ItWhy Random Initial Values Are Not EnoughWhat IfAn Explicit X in Formal + 2 more follow-ups · Open this tree

Browse by Track

Flagship Questions · With follow-ups

Question Trees

Each question opens into the follow-ups an interviewer asks next, the wrong answers people give, and what a fresher's and a senior's answer sound like.

Quick revision · One flat list

Question Bank

All 118 Formal Verification questions, main and follow-up. Open a track, then a topic. Answer out loud first, then open the short answer.

Jump to a Track
36 questions · 6 topicsFormal Basics
Formal Verification vs Simulation8
What is the difference between formal verification and simulation, and when would you pick each? L0L1

Simulation checks the paths your stimulus happens to drive, so a rare corner is found only if some test reaches it. Formal treats the inputs as free. It asks a solver whether any input sequence breaks a property, within a bound or for all time. Pick formal for control logic with deep corners such as arbiters, FIFOs, protocol rules and registers. Keep simulation for long end-to-end flows, performance and whole-chip behaviour.

QuestionPractise Formal Verification vs Simulation →
Why can a bug survive a million random cycles and then fall out of a formal run in seconds? L0L1

A simulation is one path. A million cycles visit at most a million states, out of up to 2 to the power of the flop count. BMC at depth k reasons about every input sequence of length k from reset in one solver query. The solver picks the inputs that break the property, so a rare three-cycle pattern costs it nothing extra.

Follow-upPractise Why Formal Finds What a Million Cycles Miss →
Which blocks are poor candidates for formal, and what do you do about them? L1L2

Formal struggles when a property's cone is deep or hard: long counters, wide multipliers, big memories and whole-chip flows. A bounded run then stops short of the behaviour and a proof may never finish. One option is to change the question with cut points, abstraction and smaller parameters. The other is to leave that part to simulation and prove the control logic around it.

Follow-upPractise Blocks That Resist Formal →
Why does a 16-bit timeout counter make a bounded proof hopeless, and what do you do instead? L1L2

Reaching expiry from reset takes as many steps as the count. BMC must unroll every one of them, so the required depth runs into the tens of thousands. Instead, abstract the counter to the few values that matter and prove the abstraction on the real counter in a side run. A one-transition property can also be proven by induction at full width without ever reaching expiry.

Follow-upPractise Why a Wide Counter Defeats BMC →
You replace the 16-bit timeout counter with an abstract one that may expire at any time. Why is that sound, and what can it break? L2L3

The abstract counter can do everything the real one does, plus more, such as expiring early. So a pass on the abstract model holds for the real design. The extra behaviour can cause false failures, for example an early timeout. Check each failure against the real counter, and prove the values you kept on the real design.

Follow-upPractise Is the Abstract Counter Sound →
A block passed full formal proofs and still had a bug in silicon. How can that happen? L2L3

The proof was true of what was written, not of what was meant. Common causes are a missing or weak property, or an assumption that removed legal inputs. Others are a bounded result read as a proof, or a bug outside every property's cone. The defences are a spec checklist, covers under the assumptions, a stated required depth and a cone map.

Follow-upPractise A Proven Block with a Silicon Bug →
You own verification of a new IP. How do you decide what formal covers and what simulation covers? L3

Split by question, not by team. Formal takes control logic whose rules fit in a few cycles: protocol compliance, arbitration, FIFO and credit invariants, registers, connectivity and deadlock. Simulation keeps data flows across many blocks, long scenarios, performance and firmware interaction. Every formal assumption is also bound into simulation as an assertion, so a wrong assumption is caught at system level.

Follow-upPractise Splitting an IP Between Formal and Simulation →
A refresh event happens only every few thousand cycles, far past any depth your proofs reach. Compare full formal with a semiformal search for bugs around that event. L2L3

Full formal searches every trace from reset, so a few thousand cycles of depth is out of reach. Semiformal starts the solver from a waypoint instead: a simulation or cover trace that has already run close to the event. It then searches exhaustively from there. It finds deep bugs that neither method finds alone. But it proves nothing about the states it skipped, so it counts as bug hunting, not sign-off.

Follow-upPractise Full Formal vs Semiformal Search →
Assert, Assume and Cover in Formal5
In a formal run, what do assert, assume and cover each tell the tool to do? L0L1

An assertion is a goal: the tool searches for any legal input sequence that breaks it. An assumption is taken as true, so it removes input sequences from the search. A cover asks the tool to reach a condition and return a trace that does. The working rule is to assume what the environment does, assert what the design does and cover what should be possible.

QuestionPractise Assert, Assume and Cover in Formal →
Why should the first run on a new formal bench be covers, not assertions? L1

A cover shows the design moving under your assumptions: reset releases, the FIFO fills, each state is entered. If the bench is over-constrained, the covers come back unreached before any assertion can mislead you with a pass. In this run the arbiter's output is assumed one-hot, and the cover of a double grant is unreached.

Follow-upPractise Why Covers Come Before Asserts →
The same SVA file is compiled into the simulation testbench. What happens to the assume and cover statements there? L1L2

A simulator checks an assume exactly like an assert. So the system testbench tells you when the real environment breaks a block-level assumption. Covers are counted as they are hit, and restrict is ignored. Binding block assumptions into system simulation is the cheapest way to validate them.

Follow-upPractise Formal Assumptions in Simulation →
What if a block assumption, bound into system simulation, fires on day 40? What does it tell you, and what do you do? L2

The real neighbour broke a rule that the block proof relied on. So the block proof does not cover that traffic. Decide from the spec which side is wrong. Either fix the neighbour, or relax the assumption and rerun the proof, which may now fail.

Follow-upPractise A Block Assumption Fires in System Simulation →
How does a formal cover differ from a covergroup bin that simulation hits? L1L2

A covergroup bin counts what your tests happened to do. A formal cover asks whether any legal input sequence can reach the condition and returns the shortest trace that does. An unreached formal cover within a bound only says the depth was too short or an assumption blocks it. A proof of the negation is what makes a bin truly unreachable.

Follow-upPractise A Formal Cover vs a Covergroup Bin →
What a Bounded Pass Promises5
The tool reports BMC PASS at depth 20 on an idle-timeout block. Your manager asks whether the block is verified. What do you say? L0L1

It means no input sequence breaks the property within the first 20 steps from reset, and nothing more. A bug that needs a longer run, such as a counter reaching its limit, is invisible at that depth. Either compute the depth the logic needs and show covers reach it, or run a prove mode for an unbounded answer.

QuestionPractise What a Bounded Pass Promises →
How do you work out the depth a bounded proof must reach before you trust it? L2L3

Start from the deepest counter in the property's cone, the longest transaction and the property's own window. Then add the tool's step offset. Check the number with covers: the deepest interesting behaviour must be reached inside the bound. The book's guideline is to prove assertions deeper than the longest cover trace, ideally about twice as deep.

Follow-upPractise Working Out the Required Depth →
You computed a required depth of 30 and proved to 30. How can the result still miss a bug? L2L3

The number is only as good as its inputs. A counter you missed in the cone, a longer transaction or a wrong step offset makes 30 too small. Covers check it: the deepest interesting state must be reached inside the bound. A depth sweep, where a planted bug fails near the predicted depth, also checks the arithmetic.

Follow-upPractise A Required Depth That Was Too Small →
What does a prove mode give you that BMC does not, and what does an UNKNOWN result mean? L1L2

Prove mode runs k-induction (an induction proof over k steps) or IC3/PDR (an engine that builds its own invariant). It can return a PASS that holds for all time. UNKNOWN means the base case passed but the induction step did not, so no proof has been found. It is an open item, never a pass, and it can sit on a real bug deeper than the base case. On the buggy idle timer here, prove at k = 2 reports UNKNOWN rather than FAIL.

Follow-upPractise BMC vs Prove Mode, and What UNKNOWN Means →
Your full proofs will not converge before tape-out. Can you sign off with bounded proofs instead? L3

Yes, if the bound is argued, not hoped. The page must show the required depth from the counters and transactions, and a run that reaches it. It must also show covers of the deepest behaviour inside the bound. The page reports the result as bounded, with the depth, the tool version and the date. It also states the risk of a deeper bug.

Follow-upPractise Bounded Proofs at Sign-Off →
Reading a Formal Counterexample6
A formal run fails at step 7 and hands you a trace. How do you read it, and how do you tell a real bug from a problem in your bench? L0L1

Start at the failing step and walk backwards to the first value that set the design on the wrong path. Then sort the cause into one of four: an RTL bug, a missing assumption, a wrong property, or reset not modelled. The state at step 0 and the inputs the solver chose usually decide it. An input sequence the real environment never produces calls for an assumption, not an RTL change.

QuestionPractise Reading a Formal Counterexample →
Why are formal counterexamples usually much shorter than the simulation failures for the same bug? L1

BMC checks depth 1, then 2, and so on, and stops at the first satisfiable depth, so no shorter failing trace exists. The solver also chooses every input directly instead of waiting for random stimulus to line up. An IC3/PDR counterexample (from the engine that builds its own invariant) starts at reset too but need not be the shortest.

Follow-upPractise Why Formal Traces Are Short →
Your counterexample fails at step 1, before any request has arrived. What do you check first? L1

Check how the design starts. A failure that early usually has one of two causes. Either reset was not assumed in the first step, or a flop with no reset started at a value the solver chose. Look at step 0. If a register holds a value reset would never give it, fix the bench or add the reset, not the logic.

Follow-upPractise A Failure One Step After Reset →
What if the unreset register is set by firmware at boot, so the hardware team refuses to add a reset? L1L2

Then the start value is an assumption, not a fact. Write it as an initial-state assumption that the register holds its boot value. Put it on the sign-off list, so someone checks it against the boot code. Add a cover that the block still runs, so the assumption did not empty the bench.

Follow-upPractise A Register That Firmware Initialises →
Compare debugging a formal counterexample with debugging a failing random simulation. L1L2

A simulation failure is one run, often thousands of cycles long, with the cause buried somewhere in the middle. A formal trace is short and stands for a whole family of failures. If it shows an illegal input, you add an assumption and re-solve. The tool then returns another trace or proves the case is gone, which new random seeds can never tell you.

Follow-upPractise Debugging a Counterexample vs a Simulation Failure →
Your team brings up formal on a new block and reports forty failures in one morning. How do you triage them? L3

Expect most early failures to be environment problems, not RTL bugs. Bucket them by cause from step 0 and the solver-chosen inputs, fix reset and missing assumptions first, and rerun; many failures collapse together. Each assumption added is written from a spec row, reviewed, and paired with a cover. Only the failures that survive go to the designer as bugs.

Follow-upPractise Triaging Forty Formal Failures →
Reset and the Initial State in Formal7
Your first formal run on a decade counter fails at step 1 with count = 12. The RTL has a synchronous reset. What went wrong? L0L1

Nothing told the tool how the design starts, so every state, including count = 12, was a legal initial state. Assume reset in the first step, for example if ($initstate) assume(rst), or declare initial values. A flop with no reset or initial value stays a free choice at step 0. The solver picks whichever value breaks the property.

QuestionPractise Reset and the Initial State in Formal →
Why does a formal tool treat an unreset flop as any value, instead of X as simulation does? L1

Formal models are two-valued, and silicon powers up to some real 0 or 1 in each flop. Leaving the start value free lets the solver try every possibility in one run. Four-state simulation instead carries an X that if statements can silently resolve, so it may never show the bad value.

Follow-upPractise Why an Unreset Flop Is a Free Value →
Compare assuming reset in the first step, declaring initial values and holding reset with a small counter. L1L2

All three make the decade counter pass at depth 20 in the lesson. Assuming reset at $initstate checks the real reset logic and is closest to silicon. Declared initial values skip the reset path, so a bug in it can hide. A reset counter models a multi-cycle reset sequence at the cost of a little depth.

Follow-upPractise Three Ways to Model Reset →
A mode register has no reset, because firmware writes it before start. Simulation passes, but formal fails at step 3. Who is right? L1L2

Both, about different things. In formal the unreset mode is free at step 0. So the solver picked the value that enables the block before firmware wrote anything. Simulation started mode at one value per run, and a default run never hit the bad one. Either reset the flop, or write the firmware promise as an initial-state assumption and put it on the sign-off list.

QuestionPractise Simulation Passes, Formal Fails on an Unreset Flop →
Compare X-optimism, X-pessimism and the way formal handles an unknown start value. L1L2

X-optimism is RTL simulation resolving an unknown too kindly, so a bug hides. For example, an if on X takes the else branch. X-pessimism is gate-level simulation spreading X further than real hardware would, which floods the run with false unknowns. Formal is two-valued and leaves the value free, so it checks both 0 and 1 and reports the one that breaks a property.

Follow-upPractise X-Optimism, X-Pessimism and Free Values →
A colleague says random initial values in simulation are as good as formal for unreset flops. Break that claim. L1L2

A random initial value is one draw per run. If only a few start values break the rule, most seeds pass. Formal treats the start value as free, so one run checks every value. The solver then picks a value that breaks the property, if one exists.

Follow-upPractise Why Random Initial Values Are Not Enough →
What does a formal tool do with the output below, which the RTL assigns as 1'bx? L2

In this flow an explicit x becomes a free value the solver may choose on every cycle. An assertion that the debug output stays low therefore fails, here at step 2. That is useful. A stray x default in a case statement shows up as a real failure, not a silent simulation quirk.

Follow-upPractise An Explicit X in Formal →
Safety and Liveness Properties5
What is the difference between a safety property and a liveness property, and how does each one fail? L1L2

A safety property says something bad never happens. So a finite trace that reaches the bad state breaks it at a definite step. A liveness property says something good eventually happens. So only an endless trace breaks it: a prefix and a loop where the event never comes. Liveness nearly always needs fairness assumptions, and many teams check a bounded response instead.

QuestionPractise Safety and Liveness Properties →
Why does almost every liveness property fail unless you add fairness assumptions? L2

With free inputs, the solver can let the environment stall forever, for example by never raising ready. That endless loop breaks the property. Fairness restricts the search to paths where the environment keeps its promise, such as ready returning infinitely often. Every fairness assumption needs a spec reason and a quick check that it is not vacuous.

Follow-upPractise Why Liveness Needs Fairness →
Compare deadlock, livelock and starvation. Which of them can a plain bmc run find? L2

Deadlock is a reachable state that nothing can leave, so asserting that state never occurs is safety and bmc finds it. Livelock is a loop of states that keeps moving without progress, and starvation is one requester never served while others are. Those two are liveness; to run them in bmc you bound them with a counter and accept the number you chose.

Follow-upPractise Deadlock, Livelock and Starvation →
Compare a liveness check with a bounded-response check such as "ack within 8 cycles of req". L2L3

Bounded response is a safety property: it has a failing step, runs in bmc or prove mode and gives readable traces. Its cost is a number the spec may not give, and picking it too large hides slow paths. Liveness needs no number but needs fairness and a liveness engine. Many sign-offs ship the bounded form with the deadline taken from a measured cover.

Follow-upPractise Liveness vs Bounded Response →
A fixed-priority arbiter passes every safety check you wrote. What is it hiding? L2

Starvation: a low-priority requester can wait forever while higher ones keep asking. Safety properties cannot see that, because no single cycle is wrong. You need a liveness property under fairness, or a bounded wait under a named stand-in assumption. Take the bound for the wait from a measured cover.

Follow-upPractise What a Fixed-Priority Arbiter Hides →
26 questions · 4 topicsProperties
Over-Constraint and Vacuous Proofs7
Your FIFO bench has the two lines below, and the proof passes. A colleague distrusts the assumption. What can it hide, and how would you show it? L1L2

An assumption deletes every input sequence that breaks it. So an assumption stronger than the real environment deletes legal behaviour along with the bug. The proof is then true of a world the chip never sees. Write assumptions only on ports, from the spec, and pair each with a cover of behaviour it should still allow. An unreached cover is the alarm.

QuestionPractise Over-Constraint and Vacuous Proofs →
Why should assumptions be written on the block's ports and never on its internal state? L1L2

The neighbouring block can only promise things it can see, which are the ports. A rule about internal state is a claim about the design itself, so it should be asserted and proven. Assumed instead, it can quietly delete the very states where the bug lives.

Follow-upPractise Why Assumptions Belong on Ports →
You keep the suspect assumption and replace the assertion with the covers below. What do you expect back, and what does it prove? L1L2

Keep the suspect assumption and replace the assertion with three covers. They are the FIFO full, a push while the count is 16, and a pop while empty. The full and pop-on-empty covers are reached, at steps 19 and 2. The push at a count of 16 is unreached, which is exactly the behaviour the assumption deleted.

Follow-upPractise A Cover That Exposes an Over-Constraint →
What happens if two of your assumptions contradict each other at some point in a trace? L2

From that point on no legal trace exists, so every assertion that needs to look past it passes for nothing. Some tools report a conflict when the assumptions are unsatisfiable from reset, but not every case is caught. Covers of normal behaviour after that point are the reliable check.

Follow-upPractise Two Assumptions That Contradict →
Prove it: how do you find which assumptions conflict when the tool does not report it? L2

Add covers of normal behaviour at growing depths, and find where they stop being reached. Then disable assumptions one at a time and rerun the covers. An assumption whose removal brings them back is part of the conflict. Fix it from the spec, and keep the covers as a standing check.

Follow-upPractise Finding the Conflicting Assumptions →
Compare under-constraint and over-constraint. Which one is more dangerous? L1L2

Under-constraint gives false failures: they cost debug time, but every one is visible in a trace. Over-constraint gives false passes, which look exactly like real ones. Over-constraint is the dangerous one, and covers under the full assumption set are the only routine defence against it.

Follow-upPractise Under-Constraint vs Over-Constraint →
How do you review the assumptions of a block-level formal sign-off? L3

List every assumption with its spec row and a cover showing legal behaviour survives it. Also list where it is checked at system level, usually a bound assertion in simulation. Anything without a spec row is either removed or escalated as a design requirement. The review signs off the list, not the proof.

Follow-upPractise Reviewing Assumptions at Sign-Off →
False Failures from Free Inputs4
A read slave that passes all its simulation tests fails formal at step 5. In the trace, the master changes araddr while arvalid is still waiting for arready. What is going on? L1L2

The inputs are free, so the solver drove a sequence no legal master sends: it changed the address during a stall. The failure is false; the bench is under-constrained. Add one assumption from the spec row and cite the row. It says arvalid stays high and the address stays stable until the handshake. Then cover the stall and the handshake so the assumption did not go too far.

QuestionPractise False Failures from Free Inputs →
Why start a formal bench with few assumptions instead of writing them all from the spec on day one? L1L2

A long list written up front is likely to include rules stronger than the real environment, and nothing tells you which. Starting loose means you add each assumption in answer to a trace that showed an illegal input. So every assumption has a reason and a spec row. The false failures are cheap; a silent over-constraint is not.

Follow-upPractise Why Start with Few Assumptions →
To silence the failure, someone adds the assumption below. The assertion now passes. What broke? L2

The address is now stuck at its starting value, so most legal reads never happen. The pass says nothing about other addresses. A cover of a handshake at address 8'hFF comes back unreached, which shows the assumption removed legal traffic.

Follow-upPractise An Assumption That Went Too Far →
What should the assumption have said instead, and how do you show it is not too strong as well? L2

Write the spec rule: while arvalid waits for arready, the address holds. In this bench that is arvalid && !arready |=> araddr == araddr_q. Between transfers the address is free again. Then rerun the covers: the stall, the handshake and the handshake at 8'hFF must all be reached.

Follow-upPractise The Assumption That Should Have Been Written →
End-to-End vs Glue Properties9
Your FIFO bench proves the four properties below. Is the FIFO verified? What would you write first? L2

Not yet: those are glue properties about the mechanism, and they miss bugs that leave the pointers and count intact. Write an end-to-end check at the ports first: every accepted word leaves once, in order and unchanged. In the lesson, this glue set passes depth 10 on a FIFO that reads the wrong slot. The end-to-end check fails at step 3. Keep the glue to localise failures and feed induction.

QuestionPractise End-to-End vs Glue Properties →
Why can every pointer and count property hold while the FIFO returns the wrong data? L2

Glue properties check the mechanism: pointers stay consistent with the count and full and empty agree with them. A bug in what is read, such as the wrong slot or stale data, leaves all of that intact. Only a property that compares what leaves with what entered, the purpose of the block, can see it.

Follow-upPractise Why Glue Properties Miss Data Bugs →
Write a formal check of data integrity and order through a FIFO, without modelling the whole queue. L2L3

Track one word whose value comes from $anyconst, so the solver picks it once, and let the cycle it enters be free. Count the words ahead of it, then assert that it is never dropped and that it leaves first in line, unchanged. The value and entry time are arbitrary. So a proof for this one word covers every word, as long as the design never inspects the data.

QuestionPractise The Formal Scoreboard with One Symbolic Word →
Why does the symbolic tracker proof need helper assertions before k-induction (an induction proof over k steps) can close it? L2L3

Without helpers the induction step may start with the tracker claiming a word is stored in a slot that holds something else. Helpers tie the tracker to the design. Its distance from the read pointer equals the count of words ahead. Memory at the tracked slot still holds the value. Without them the proof stays UNKNOWN even at k = 8; with them it closes at k = 2.

Follow-upPractise Why the Tracker Proof Needs Helpers →
What if you also want to check that two different words never swap order? L2

Track two writes chosen freely by the solver, the first accepted before the second. Assert that the first leaves before the second and both arrive unchanged. Because both choices are free, the check covers every pair of words, which catches reordering that a single tracker cannot see.

Follow-upPractise Two Tracked Words for Ordering →
Why does choosing both words freely cover every pair, when the proof only ever tracks two? L2L3

The solver may pick any two writes, at any times, as the tracked pair. A proof must hold for every choice it could make. So if any pair could swap, some choice of the two tracked words shows it. Two trackers then stand for all pairs, with only two sets of state.

Follow-upPractise Why Two Free Words Cover Every Pair →
Compare a symbolic tracker with a reference-model queue as the scoreboard of a formal bench. L2L3

A reference queue copies every word, so its state grows with depth times width. The solver must reason about all of it. The tracker holds one value, one slot and one count, yet covers every word through the free choice. The queue is closer to a simulation scoreboard and easier to read, so people pick it first. The tracker is what converges.

Follow-upPractise Symbolic Tracker vs Reference Queue →
How does the same idea scale to a two-by-two packet router with several flows? L3

Track one symbolic packet, tagged at the moment of acceptance. Count how many packets of its flow are owed ahead of it at its output. Assert that it leaves at its turn, on the right port, unchanged. Also assert that no output delivers a packet it does not owe. Fairness is a separate question: a fixed-priority arbiter passes every one of these safety checks.

Follow-upPractise Scaling the Tracker to a Packet Router →
Your end-to-end FIFO check passes at depth 10. What bug could still be there? L2L3

Anything that needs more than ten steps to reach a port. Examples are a pointer that wraps wrongly only after many writes, or a count that drifts and overflows later. The end-to-end check sees the effect only once the bad word is read. Glue invariants on the count and pointers catch such drift early and also help an induction proof close.

Follow-upPractise What a Bounded End-to-End Check Misses →
Writing a First Formal Testbench6
Write the formal bench for a one-entry register slice with valid/ready on both sides. What goes in it, and what is missing compared with a simulation testbench? L0L1

A formal bench has four parts: the DUT, assumptions on inputs, assertions on outputs and state, and covers. There is no driver, clock generator or scoreboard class, because the solver chooses every input. For the slice, assume upstream holds in_valid and its data until accepted. Assert the same rule on the output side. Cover a stall and a back-to-back transfer.

QuestionPractise Writing a First Formal Testbench →
Why does a formal bench need no stimulus, and what takes the place of a coverage model? L0L1

The solver treats every input as free and considers all legal values on every cycle. So writing stimulus would only narrow the search. Assumptions say what is legal. Covers replace the coverage model. Each one asks whether a behaviour is reachable under those assumptions, and returns a trace if it is.

Follow-upPractise Why a Formal Bench Needs No Stimulus →
What if you run the bench with no assumptions at all? What do you expect to see first? L1

Expect failures that no real neighbour could cause, because every input is free on every cycle. For example, the data changes while valid waits for ready. Triage each one: check the reset state, then each input against the spec. Add one assumption per spec rule, and cover the behaviour you still expect.

Follow-upPractise A Formal Bench with No Assumptions →
What if the slice adds one to the payload instead of passing it through? How does the check change? L1L2

Capture the accepted input in modelling code. When the word leaves, assert that the output equals the same function of it, here the captured value plus one. The modelling code only reads design signals; it never drives them.

Follow-upPractise Checking a Transformed Payload →
You have an APB property file written for the completer. How do you reuse it to verify the requester? L2L3

Write each rule once with its owner, and let a parameter choose assume or assert. Rules owned by the side under test are asserted, and the rest are assumed. A rule that flips from assertion to assumption is no longer checked on the new bench. So review it and cover what it might exclude. Watch for over-strict rules, such as forbidding PREADY high while PENABLE is low, which APB allows.

Follow-upPractise Reusing a Protocol Checker on the Other Side →
Compare the two ways of writing the output stall rule below: a concurrent property, and a clocked immediate assertion over registered copies. L1L2

They check the same rule. The |=> is one flop of delay, and $stable compares with last cycle's sample. So the immediate form registers the stall condition and the data, and asserts on them a cycle later. In the lesson both forms fail the buggy slice at step 4. The immediate form helps where an engine refuses history functions on primary inputs, as this one does.

Follow-upPractise Concurrent Property vs Clocked Immediate Form →
9 questions · 2 topicsProof Engines
When k-Induction Returns UNKNOWN5
Your prove run passes the base case but the induction step fails, so the tool reports UNKNOWN. Is there a bug, and what do you do next? L1L2

Not necessarily a bug. The induction step may start from any state where the property held for k cycles, including states reset never reaches. Read step 0 of the induction trace and name what is impossible about it. Assert that relation as a helper and rerun until the step passes. Raising k may never close the proof, while one good helper often does.

QuestionPractise When k-Induction Returns UNKNOWN →
Why can the induction step start in a state the design never reaches from reset? L1L2

The step only assumes the property held for k consecutive cycles; it says nothing about reachability. A state can satisfy the property but break a hidden invariant, such as two equal counters being unequal. Such a state is a legal start. The fix is to make the hidden invariant part of what is proven, so those states are ruled out.

Follow-upPractise Why the Induction Step Starts Anywhere →
What if you simply raise k instead of writing a helper? When does that work, and when does it never work? L2

Raising k makes the step assume the property held for more cycles. That works only when every bad start state reaches a failure within k cycles. Two counters that must stay equal can drift apart and stay apart for any number of cycles. Then no k closes the proof; only a helper that states the invariant does.

Follow-upPractise Raising k Instead of Writing a Helper →
Compare k-induction (an induction proof over k steps) with IC3/PDR on a FIFO proof that k-induction cannot close. L2

IC3/PDR does not unroll but keeps frames of clauses. It proves each clause relative to the previous frame until two frames match, giving an inductive invariant it built itself. On the lesson's 16-entry FIFO, PDR proves the property with no helpers while k-induction stays UNKNOWN at k = 12. Its counterexamples start at reset but need not be the shortest. No engine wins everywhere, so teams race several.

Follow-upPractise IC3/PDR vs k-Induction →
A large proof now has thirty helper assertions. How do you keep them from becoming a liability? L3

Every helper is asserted, so it is proven, never assumed. Keep only the helpers the final proof needs, by removing them one at a time and rerunning. After each change, rerun a faulty version of the design to show the set still catches the bug. Review helpers like RTL, because they become the next engineer's spec of the block.

Follow-upPractise Keeping Helper Invariants Honest →
How Bounded Model Checking Works4
How does bounded model checking work, and in its solver query, which answer is the good news? L0L1

BMC unrolls the design k times from the initial state. It asks a SAT or SMT solver whether some input assignment reaches a bad state at any step. Satisfiable means yes, and the assignment is the counterexample trace. Unsatisfiable means no trace of that length breaks the property, which is the good news. Depths are tried in order, so the first failure found is a shortest one.

QuestionPractise How Bounded Model Checking Works →
Why is the first counterexample BMC returns guaranteed to be a shortest one? L1

The checker asks about depth 1, then 2, then 3, and stops at the first depth the solver finds satisfiable. If a shorter failing trace existed, an earlier query would already have been satisfiable. That makes BMC traces short and easy to read, which is one reason engineers run bmc for bug hunting.

Follow-upPractise Why the First BMC Failure Is the Shortest →
When does a word-level SMT solver help over a bit-level SAT engine? L2

A SAT engine sees only gates, so a wide adder or multiplier becomes thousands of clauses. An SMT solver keeps words and arithmetic as theories and can simplify before it falls back to bits. The verdict is the same either way; only the time differs, and in the lesson the winner changed with the property.

Follow-upPractise SAT vs SMT Solvers for Datapaths →
What if you knew the design's diameter, the most steps any reachable state needs from reset? Would BMC then give a full proof? L2L3

Yes: if every reachable state can be reached within d steps, a BMC pass to that depth covers every reachable state. The problem is that nobody knows the diameter of a real design, and it grows with every counter. That is why full proofs use induction or IC3/PDR, an engine that builds its own invariant. Bounded results are argued from a required depth instead.

Follow-upPractise BMC and the Design Diameter →
12 questions · 3 topicsConvergence
A Proof That Will Not Converge4
An assertion on a watchdog block has run for hours with no answer. Walk me through what you do. L2L3

First work out which of three causes it is. The depth needed is huge, the cone holds hard logic such as a multiplier, or the property is not inductive. Read the cone and the engine log rather than guessing. Then change the question to match. Abstract the counter, cut datapath the property does not read, add helper invariants, split cases or switch engines. Every reduction gets a written reason and a rerun of a known-buggy version.

QuestionPractise A Proof That Will Not Converge →
Compare blackboxing a submodule with placing a cut point. L2

A blackbox turns every output of a module into a free input. That suits memories and arithmetic the property does not depend on. A cut point frees a single internal node. So you can remove one hard cone, such as a CRC check, without dropping the module around it. Both add behaviour, so a pass stays sound and a failure must be checked at the freed signal.

Follow-upPractise Blackbox vs Cut Point →
What if a property is hard only for some opcodes or address ranges? How do you split it safely? L2L3

Run the proof once per case, each with an assumption that pins the case variable. Prove separately that the cases together cover every value. Pin the case for the whole run, from a value fixed at the start. A split that lets the case change each cycle can hide interleavings between cases. The slow case then shows you where the hard logic is.

Follow-upPractise Case Splitting a Hard Proof →
As formal lead, how do you get designers to make their blocks cheaper to prove? L3L4

Agree on a few habits before RTL is written. These are right-sized state, control separated from data, parameterised timers and depths, one reset, and important state exposed or named. Show one measured before-and-after from your own project, because that persuades more than a rule. Designers who run formal on fresh RTL also find bugs while they still remember the code.

Follow-upPractise Getting Designers to Build for Formal →
Is a Cut Point Safe?4
In a packet buffer's bench you replace the CRC check with the cut below. Can that make a buggy design pass? Can it make a correct design fail? L2L3

Freeing a signal lets it take any value, so the cut model has every behaviour of the real design and more. A pass on the cut model is therefore a real pass, but a failure may be one the cut invented. Check each failure at the freed signal. If no real logic could produce that value there, add an assumption that restores the fact. Then prove that assumption on the uncut logic.

QuestionPractise Is a Cut Point Safe? →
An abstract model of a buffer passes, but its full-write cover is unreached. How did the abstraction remove a real bug? L2L3

The replacement was not a superset of the real logic. Something narrowed it. Typically that is an assumption added to silence a false failure, or a model that leaves out a legal case. A sound abstraction must keep every concrete behaviour. The unreached cover is the evidence; fix the abstraction, not the cover.

Follow-upPractise When an Abstraction Removes the Bug →
Why is an assumption placed on a cut signal more dangerous than the cut itself? L2L3

A cut only adds behaviour, so a pass on the cut model still holds for the real design. An assumption on the cut signal removes behaviour again. If it removes something the real logic can do, a real bug disappears. So prove each such assumption on the uncut logic in a side run.

Follow-upPractise Why an Assumption on a Cut Is Risky →
The cut model fails. How do you decide whether the failure is real? L2

Look at the freed signal in the trace. If the real logic could produce that value from the trace's inputs, the failure is real. Running the uncut design to the same step confirms it. If not, the cut invented it, and you either restore the missing fact with a proven assumption or choose a different cut.

Follow-upPractise Is the Cut Model's Failure Real? →
Assume-Guarantee Without Circular Logic4
Two blocks are too big to prove together, so you prove each one assuming the other behaves. When is that sound, and when does it prove a bug away? L3

Prove each block's guarantee while assuming the other's, then compose. For safety this is sound when each assumption is only needed for earlier cycles, not the current one. If each block assumes the other's guarantee in the same cycle, the proofs lean on each other. Both can then pass with a real bug. In the lesson's credit link the circular version passes; assuming only last cycle's guarantees finds the bug.

QuestionPractise Assume-Guarantee Without Circular Logic →
Why does assuming only the other block's guarantee from the previous cycle make the argument sound? L3

It turns the pair of proofs into induction over time. At reset both guarantees hold. Suppose both held up to cycle t minus one. Then each block's proof shows its own guarantee at cycle t, so both hold at t. A same-cycle assumption breaks that chain, because each guarantee at t would rest on the other at t.

Follow-upPractise Why Last Cycle's Guarantee Is Enough →
Break it: show how two same-cycle assumptions can let two wrong blocks both prove. L3

Block A assumes B sends good data this cycle, and B assumes the same of A. Suppose both send bad data in the same cycle. Each proof rules that case out by its own assumption, so both pass. The time shift breaks the circle, because cycle t then rests only on cycle t minus one.

Follow-upPractise Two Wrong Blocks That Both Prove →
How would you use interface contracts to verify a subsystem of six blocks formally? L4

Write one contract per boundary from the interface spec. Prove each block against the contracts of its neighbours, assumed with the time-shift rule. Each contract is asserted on its owner and bound into system simulation as a check. The end-to-end goals that cross several blocks then rest on proven contracts, and a contract change triggers a review of both sides.

Follow-upPractise Contracts for a Six-Block Subsystem →
11 questions · 2 topicsEquivalence
Combinational vs Sequential Equivalence5
What is the difference between combinational and sequential equivalence checking, and when do you need each? L1L2

Combinational equivalence pairs the flops of the two designs and compares the logic cone in front of each pair, with no unrolling. It suits RTL against a synthesised netlist, because synthesis mostly keeps the flops. Sequential equivalence lets the state differ and asks for equal outputs over time from reset. You need it after retiming, pipelining, state recoding or clock-gating changes.

QuestionPractise Combinational vs Sequential Equivalence →
Why does combinational LEC need the flops of both designs matched, and what goes wrong when the match is wrong? L2

Matching flops cuts both designs into small cones between key points, so each comparison is combinational and needs no unrolling. If two flops are paired wrongly, their cones compute different functions. The tool then reports a mismatch that is a mapping error, not a design bug. Debug starts at the smallest failing cone and the key points that feed it.

Follow-upPractise Why LEC Needs Matched Key Points →
What if synthesis retimed part of the design, so some flops moved and no longer match by name? L2L3

Then combinational LEC cannot pair those flops, because they now hold different functions. Their cones fail or stay unmapped. The retimed region needs sequential equivalence, which compares outputs over time from reset. That region then gets its own line in the sign-off.

Follow-upPractise Equivalence After Retiming →
The equivalence check of two differently built multipliers never finishes. What do you do? L2L3

Expect it. Equivalence of unlike multipliers grows exponentially with width on every solver. BDDs for the middle product bit are exponential for every variable order. Change the question instead of the machine. Compare at register boundaries, or split the proof into partial products and the adder tree, each of which is easy to check.

Follow-upPractise An Equivalence Check on a Multiplier →
LEC reports a mismatch whose counterexample sets two internal key points to values that can never occur together. Is it a real bug? L2

Probably not. Treating key points as free inputs throws away the relations between them. So the tool can pick combinations the real design never produces. A real difference has a consistent counterexample that is reachable from the inputs. Check that before calling it a bug. Otherwise, fix the mapping or add a constraint.

Follow-upPractise An LEC Mismatch on Impossible Inputs →
Proving a Late Fix Changed Only the Bug6
Two weeks before tape-out a designer fixes a WRAP-burst address bug. How do you show the fix changed nothing else? L3

Build a miter of the old and new RTL and check conditional equivalence. Outputs must match whenever the bug's condition is false. Inside that condition, the new design must meet the spec. Write the condition from the bug report, never from the diff, or a wrong fix defines its own condition. A counterexample on inputs the spec forbids means a missing assumption, not a bad fix.

QuestionPractise Proving a Late Fix Changed Only the Bug →
Why is writing the condition of a conditional equivalence check the same job as writing formal assumptions? L3

Both say where the check applies. A condition that is too wide hides real differences, exactly as an over-constraining assumption hides bugs. So it needs the same discipline. It needs a written source in the bug report or the spec. It also needs a review by someone who did not write the fix.

Follow-upPractise The Condition Is a Specification →
Break it: the fix touched one opcode, but the condition excludes a whole opcode group. What can escape? L3

Inside the excluded region the old and new designs may differ freely, and the check says nothing. So a second, accidental change to another opcode in that group passes. Write the condition from the bug report, so it covers only the failing case. Then check the new design inside it against the spec.

Follow-upPractise A Condition That Excludes Too Much →
Compare a conditional-equivalence miter with a full regression rerun as the check for a late fix. L3

The regression samples the input space at the points its tests reach, and it takes hours or days. The miter covers every input in the region where the old and new designs must agree. For a block-level fix, it usually takes minutes. The regression still matters for what the miter does not state. That is the behaviour inside the bug condition and the system around the block.

Follow-upPractise A Miter vs a Regression Rerun for an ECO →
With the correct fix, the check still fails, on a WRAP burst of length 3. The miter's environment is below, with the WRAP-length line still missing. What do you do? L2L3

AXI allows WRAP bursts of only 2, 4, 8 or 16 transfers, so length 3 cannot occur; add that rule as an assumption, citing the spec. Add only what a counterexample demands: in the lesson the alignment assumption turned out unnecessary, because the check passes without it.

Follow-upPractise An ECO Counterexample on an Illegal Burst →
How would you make formal ECO checks a standard step in a chip's tape-out flow? L4

Every late RTL change carries a miter against the last signed-off RTL. Its condition comes from its bug report, and a second engineer reviews it. The block's formal regression and RTL-to-netlist LEC rerun on the new netlist. The ECO is closed only when all three are clean and the condition is attached to the change record.

Follow-upPractise Formal ECO Checks in the Tape-Out Flow →
8 questions · 2 topicsApplications
Which Formal Apps to Run First5
You join an SoC project that has no formal yet. Which formal apps would you run first, and why those? L1L2

Start with apps that need no hand-written properties: connectivity from the integration table and register checks from the register map. Both find real wiring and access-type bugs within days, which earns trust for the harder work. Then add automatic checks and X-propagation, and use unreachability analysis to prune coverage holes for the simulation team. An app proves only the properties it generates, so design rules still need your own.

QuestionPractise Which Formal Apps to Run First →
Why must register checks be generated from the register map, and never from the RTL? L1L2

Checks generated from the RTL only prove that the RTL agrees with itself. A field built with the wrong access type then passes. The map is the independent statement of intent. Each access type in it implies a fixed set of checks. For example, a write of 1 clears a W1C bit and a write of 0 keeps it.

Follow-upPractise Why Register Checks Come from the Map →
What if the RTL and the checks both come from the same register map? One row of the map has the wrong access type. L2

Then the proof passes, because the RTL and the checks agree with the same wrong row. Formal shows that the RTL matches the map, not that the map is right. So the map needs its own review against the spec and the driver code. A firmware test of the field in system simulation catches what that review misses.

Follow-upPractise When the Register Map Itself Is Wrong →
An interrupt-status field should be write-one-to-clear but was built as the line below. Which generated check catches it, and what is the subtle part? L1L2

The W1C check that a written 0 keeps a set bit fails within a few cycles: plain read-write overwrites the bit with the 0. The subtle part is priority. A hardware event that arrives in the same cycle as the clearing write must still set its bit. The bus protocol is assumed and covered, and the register behaviour is asserted one cycle after the completing write.

Follow-upPractise A W1C Field Built as Read-Write →
Compare lint with formal automatic checks on the same RTL. L1L2

Lint reads the text and flags code that could be wrong, such as a width mismatch. It does not know whether the bad case can happen. Formal automatic checks generate covers and assertions from the RTL and show whether the bad state is reachable, with a trace. In the lesson lint warned only about a truncated index, while formal failed the index, a dropped carry and an X default.

Follow-upPractise Lint vs Formal Automatic Checks →
Using Formal to Close Coverage Holes3
Simulation never hits three coverage bins. Can formal let you waive them, and what evidence would you accept? L1L2

Formal can ask three things of a bin: is it reachable, proven unreachable forever, or merely unreached within N steps. Only the proof supports a waiver; a bounded unreached cover is a hint about depth. In the lesson one bin is unreached at depth 20 and reached at step 26 at depth 30. Run the proof with as few assumptions as possible, since an over-constraint makes a live bin look dead.

QuestionPractise Using Formal to Close Coverage Holes →
Why should an unreachability run use as few assumptions as possible? L2

Free inputs allow more behaviour than the real environment. So a bin that cannot be reached even with free inputs cannot be reached in the chip. Every assumption you add shrinks the search and can make a live bin look dead. Add an assumption only when a reached trace is clearly illegal, and list it on the waiver.

Follow-upPractise Why Unreachability Runs Use Few Assumptions →
Formal reaches a bin simulation never hit. What can you do with that trace? L2L3

Replay it as a directed test. SBY writes a small Verilog testbench for every trace. You can port the input values into the simulation environment as a sequence. The simulation team then has a test that hits the bin and keeps hitting it in regression. Every checker and scoreboard watches that test.

Follow-upPractise Turning a Cover Trace into a Test →
16 questions · 4 topicsSignoff
The Formal Sign-Off Argument5
You are asked to sign off a timeout block with formal. What has to be on the page before you put your name to it? L3L4

Each of four items needs evidence. Every assumption has a spec reason and a cover reachable under it. The properties map to spec rows, and a mutation sample shows they notice faults. Each result is a full proof, or a bounded pass next to the depth the counters and transactions require. A cone map names the logic no property reads, and every line carries the tool version and date.

QuestionPractise The Formal Sign-Off Argument →
What does a proof actually cover, and how do you show the logic it never looked at? L2L3

A proof covers its property's cone of influence, the logic that can affect it, and nothing else. Draw the union of all cones: logic outside it is unverified, not wrong, and belongs in the review. The proof core is the part of the cone the engine actually used, and cutting registers one at a time measures it. Cover depths add a time view: a bounded run below the deepest cover never saw that behaviour.

Follow-upPractise What a Proof Actually Covers →
How do you know your property set is complete enough? Compare a spec checklist with mutation analysis. L2L3

The checklist puts one spec rule per row with its property, so an empty cell is a visible hole. But it trusts that each property is strong enough. Mutation changes the design on purpose and asks whether some property fails; survivors grouped by behaviour name the missing properties. In the lesson's FIFO campaign, bookkeeping properties killed 24 of 39 mutations, and adding an order property raised it to 38.

Follow-upPractise Spec Checklist vs Mutation Analysis →
What if a mutated design passes every property? How do you decide whether it shows a hole or is harmless? L2L3

Run an equivalence check between the mutated design and the original. If they are equivalent, the mutation changed nothing visible, so it is harmless. If not, the check gives a trace where they differ. That trace names the behaviour no property watches, so write the missing property from it.

Follow-upPractise A Mutation That Survives Every Property →
What goes in a formal verification plan, and when do you write it? L3

Write it before the properties. It names scope, goal, spec rows, properties, assumptions, covers, abstractions, a depth budget and sign-off criteria. Every assumption names who checks it at system level, and every bounded result sits next to its required depth. One empty field can turn an honest open item into a false sign-off.

Follow-upPractise Writing the Formal Verification Plan →
Planning Formal Across a Subsystem3
You lead formal for a new subsystem of a dozen blocks, with two engineers and six months. How do you decide where formal goes and what "done" means? L3L4

Rank blocks by where formal pays: control-heavy logic with deep corners and clean interfaces. Examples are arbiters, credit logic, FIFOs, register blocks and protocol bridges. Give each block a goal, bug hunting or sign-off, because the exit criteria differ. Run the cheap apps across the subsystem early, plan abstractions and depth budgets per block, and bind every assumption into simulation. Track proofs, bounded results and open UNKNOWNs as a risk list.

QuestionPractise Planning Formal Across a Subsystem →
Why do bug hunting and sign-off need different exit criteria? L2L3

Bug hunting aims to find failures fast. So it accepts over-constraints, shallow bounds and partial property sets, and it ends when the bug rate drops. Sign-off claims the block is correct against its spec. So it needs complete properties, justified assumptions with covers, and proofs or argued bounds. Mixing the two leads to a bug-hunting bench presented as a sign-off.

Follow-upPractise Bug Hunting vs Sign-Off Goals →
Halfway through the schedule, two key proofs still do not converge. What is your fallback? L3L4

Decide per property, early. Try abstraction and decomposition first, within a time box. If that fails, ship a bounded result with its required depth and covers. Move the remaining risk to targeted simulation or emulation tests. Record the decision and its residual risk in the sign-off, so nobody reads the block as fully proven.

Follow-upPractise When Key Proofs Still Do Not Converge →
Formally Verifying a Round-Robin Arbiter3
What properties would you write to verify a four-requester round-robin arbiter formally? L1L2

Start with one-cycle safety: at most one grant, and no grant without a request. Then pin the rotation: after granting requester i, the pointer moves just past i. Finally fairness: assuming requests hold until granted, every request is granted within a bounded number of cycles. Cover each requester being granted and a full round of grants.

QuestionPractise Formally Verifying a Round-Robin Arbiter →
The safety properties of the fixed arbiter prove at k = 2, but fairness needs k = 6. Why? L2L3

Fairness is checked with bench counters that count how long each request has waited. In the induction step those counters may start at any value the property allows, including combinations no real run produces. A longer window, k = 6 here, rules those starts out, while PDR finds the needed invariant by itself.

Follow-upPractise Why the Fairness Proof Needs k = 6 →
How would simulation verify the same arbiter, and what would it be likely to miss? L1L2

A random-request bench with a reference model and grant-latency checks finds most bugs quickly. What it misses are skips and starvation that need a specific multi-cycle pattern of requests. Random stimulus rarely produces that exact pattern. Formal finds such patterns in a few steps, which is why arbiters are a classic first formal target.

Follow-upPractise The Same Arbiter in Simulation →
Defending a Formal Proof You Closed5
Walk me through a formal proof you closed on a real block. Cover the properties, the assumptions, the hard part, and how you knew you were done. L2L3

A strong answer names the block and its spec rows, then the property kinds: end-to-end checks, glue invariants and covers. It lists each assumption with its source and how the system checks it. It names the convergence problem and the technique that solved it. It ends with the evidence for done: full or bounded with the required depth, reached covers, and a fault-injection or mutation result.

QuestionPractise Defending a Formal Proof You Closed →
The interviewer hands you the counterexample shown with the answer, from an APB register block, and five minutes. What do they want to hear? L1L2

The failing step, the cause, and the fix, in that order, plus the causes you ruled out and how. Say whether it is an RTL bug, a missing assumption, a wrong property or an unmodelled reset. Point at the signal and step that decided it. Thinking aloud in that structure matters more than reaching the answer first.

Follow-upPractise Five Minutes with a Counterexample →
Tell me about an assumption in one of your formal benches that turned out to be wrong. How was it found? L2L3

A good story names the assumption, why it seemed right, and the evidence that broke it. That evidence might be an unreached cover, a bound assertion firing in system simulation, or a lab failure. It ends with what changed in the process, such as covers per assumption or binding assumptions into simulation from day one.

Follow-upPractise An Assumption That Turned Out Wrong →
What would you change in the flow so that the next wrong assumption is found in days, not in the lab? L2L3

Give every assumption a written reason from the spec and a cover that must stay reached. Bind every block assumption into system simulation as an assertion from day one. Review the list at each milestone with someone from the neighbouring block. Then a wrong assumption shows up early, as a firing check or an unreached cover.

Follow-upPractise Catching Wrong Assumptions Early →
What happens to your formal bench after tape-out? L3

Keep it alive. When the lab reports a symptom, write it as a cover and the lab observations as assumptions. The shortest trace is a hypothesis for the root cause. Never assume away what the lab did not observe, since it may be the cause. Then prove the fix under the same environment before the respin.

Follow-upPractise The Formal Bench After Tape-Out →

Your Review Queue

Saved review reminders are coming soon.