Interviews
Functional Coverage Interview Questions
Practise the question, then the follow-ups an interviewer asks next.
Start with a Question TreeAI Mock Interview
- 20
- Question trees
- 97
- Follow-ups
- 145
- Wrong answers explained
- 36
- Runnable on a simulator
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.
-
Full Code Coverage and a Bug Escape
Your block reached 100% code coverage, yet a bug escaped to silicon. How is that possible, and what does functional coverage add? 6 follow-ups · 8 pitfalls · 1 runnable -
Cover Property vs Covergroup
When do you usecover propertyand when a covergroup? 5 follow-ups · 8 pitfalls -
Weight, Goal and Minimum Hits
What dooption.weight,option.goalandoption.at_leastchange? Which of them change the numberget_coverage()returns? 4 follow-ups · 7 pitfalls · 3 runnable -
Type Coverage vs Instance Coverage
Two instances of one covergroup watch two ports. Between them they hit all four bins. What does this print? 4 follow-ups · 7 pitfalls · 3 runnable -
Automatic Bins on an 8-Bit Value
This coverpoint has no bins of its own. How many bins does it get, and what coverage does it print? 5 follow-ups · 7 pitfalls · 2 runnable -
Ignore, Illegal and Default Bins
An opcode field has 8 values, and 6 and 7 are reserved. Do you useignore_bins,illegal_binsor adefaultbin? What does each one do? 4 follow-ups · 7 pitfalls · 2 runnable -
Wildcard Bins
What does this print? How would you change it so every odd value must be seen? 4 follow-ups · 6 pitfalls · 4 runnable -
Bins for a Wide Range of Lengths
A packet length runs from 1 to 1024 bytes. Write the coverpoint bins. What goes wrong with one big bin, or with one bin per value? 5 follow-ups · 6 pitfalls · 2 runnable -
Covering a Stall with Transition Bins
A sink can holdreadylow for one or two cycles. Write coverage that proves both stall lengths were seen, not just that a stall happened. 5 follow-ups · 8 pitfalls · 4 runnable -
Three Coverage Holes, Three Causes
Coverage has stayed at 70.83% across three seeds. Here is the report. What causes each hole, and what do you do about it? 5 follow-ups · 7 pitfalls · 2 runnable -
Closing the Last Eight Percent
Functional coverage has sat at 92% for two weeks. Tape-out is a month away. How do you close it? 4 follow-ups · 7 pitfalls -
Building a Coverage Plan from a Spec
Walk me through how you build a coverage plan from a spec. Use a FIFO with an APB register interface as the example. 6 follow-ups · 9 pitfalls · 1 runnable -
Merging Coverage and Ranking Tests
How do you merge coverage across a nightly regression of 3000 tests? What is test ranking for, and what is it not for? 4 follow-ups · 7 pitfalls -
Coverage Sign-Off for a Block
Walk me through your coverage sign-off review for a block. 5 follow-ups · 8 pitfalls -
A Cross That Can Never Close
Cross the command (READ, WRITE) with burst-length bins one, short and long. A READ is never longer than 4 beats. Write the cross so it can reach 100%. 5 follow-ups · 7 pitfalls · 3 runnable -
A Cross Stuck at 12 Percent
You cross address region (16 bins), burst length (8), size (4) and ID (16). Coverage has been stuck near 12% for weeks. What do you tell your manager? 5 follow-ups · 7 pitfalls · 3 runnable -
A Covergroup That Counted Idle Cycles
A covergroup on the packet kind is clocked with@(posedge clk). The trace shows only WRITE and CONFIG transfers, yet READ is covered. Why? 5 follow-ups · 6 pitfalls · 2 runnable -
A Covergroup Inside a Collector Class
This collector receives lengths 1, 2, 3 and 4. What coverage does it report, and why? 5 follow-ups · 8 pitfalls · 1 runnable -
Full Coverage, No Errors, and a Dropped Packet
Silicon drops CONFIG packets. Here is the end of the block regression log, which passed. What went wrong in the bench? 7 follow-ups · 9 pitfalls · 1 runnable -
Keeping Reset Out of Coverage
A clocked covergroup covers a FIFO's fill level, with bins for empty, partial and full. Write it so that reset cycles cannot cover any bin. 4 follow-ups · 6 pitfalls · 2 runnable
No question matches these filters.
Quick revision · One flat list
Question Bank
All 106 Functional Coverage questions, main and follow-up. Open a track, then a topic. Answer out loud first, then open the short answer.
Jump to a Track
106 questions · 20 topicsFunctional Coverage
Full Code Coverage and a Bug Escape6
Your block reached 100% code coverage, yet a bug escaped to silicon. How is that possible, and what does functional coverage add? L0L1L2
Code coverage measures which lines, branches and toggles of the RTL ran. It cannot see a check that was never written, or conditions that never happened together. Functional coverage measures the cases in the spec and the plan, such as "push while full". A missing feature then shows up as an empty bin. You need both: code coverage finds RTL nobody exercised, and functional coverage finds intent nobody tested.
QuestionPractise Full Code Coverage and a Bug Escape →Why can't code coverage find a feature that was never implemented? L0L1
A code coverage tool adds counters to the lines and branches that exist in the RTL. A check that was never written has no line, so there is nothing to count. The report can only ever say "this code ran" or "this code did not run". Functional coverage starts from the spec, so it can list cases the code does not handle.
Follow-upPractise Why Code Coverage Cannot See Missing Logic →Compare line, branch, expression, toggle and FSM coverage. Which one would have caught the missing full check? L1
Line coverage counts executed statements, and branch coverage counts each way through an if or case. Expression coverage checks that each term of a condition changed the result. Toggle coverage checks each bit went to 0 and 1, and FSM coverage counts states and arcs. None of them catches the missing check, because the condition count == 4 does not exist in the code.
Prove it: write the functional coverage that would have exposed the missing full check. L1
Cover the operation crossed with the fill state, sampled only outside reset. For example, push_full: coverpoint (push && count == 4) iff (!rst) { bins seen = {1}; }. A fuller model crosses push and pop with empty, partial and full. The empty bin forces someone to write the test, and that test finds the overflow.
Code coverage is 97%. The holes are in an error-recovery branch. What do you do with them? L2
Find out first whether the branch can be reached. If it can, the plan missed a feature: add it to the plan and write the test, often with error injection. If it cannot, because of a tie-off or a parameter, mark it unreachable with a reason the designer agrees to. Never waive a hole just because it is hard to hit.
Follow-upPractise Code Holes in an Error-Recovery Branch →At sign-off, hundreds of code coverage holes remain across a subsystem. How do you clear them without writing hundreds of tests? L3
Run a formal unreachability check on the holes first. It proves many of them dead, such as logic behind tied-off inputs or unused parameter values. Those can be excluded, with the proof as the reason. Review the rest with the designers, grouped by feature. Each group becomes a test, a plan update or a reviewed waiver.
Follow-upPractise Clearing Hundreds of Code Holes →Cover Property vs Covergroup6
When do you use cover property and when a covergroup? L1L2
Use cover property for a sequence of events on signals over time, such as "request, two stalled cycles, then a grant". It reuses the assertion language and counts each time the sequence completes. Use a covergroup for values and their combinations, such as packet length crossed with kind. Only a covergroup has bins, crosses and a percentage. cover property lives in modules, interfaces and checkers, not in classes.
Compare cover sequence (req ##[1:3] gnt) with cover property (req ##[1:3] gnt). Can their counts differ? L2
Yes. cover property counts at most one success per attempt. cover sequence counts every match, so one attempt can count several times. Suppose gnt is high in all three cycles after one req. The sequence cover counts three matches, and the property cover counts one. Use the property form to count scenarios, and the sequence form to see how often each ending happens.
What if your bench is all classes? Where does coverage of a timed sequence go? L2
Put the cover property in the interface or in a checker bound to the design; classes cannot hold it. Or let the monitor turn the timing into a value, such as a stall length per transfer. Then sample that value in a covergroup. The covergroup route gives bins and crosses with other transaction fields. The interface route stays closest to the signals.
Can a sequence in the interface feed a covergroup directly, so a timed event gets bins and crosses? L2L3
Yes. A sequence can call a function when it matches, for example (req ##[1:3] gnt, cg.sample(len)). With with function sample(...), the covergroup receives the values seen at that match, even local variables of the sequence. That gives a timed event, such as a grant latency, real bins and crosses.
In formal verification, what does a cover property tell you that a simulation count cannot? L2L3
Formal tries to reach the cover from reset under the assumptions. A reached cover comes with a trace, which proves the scenario can happen. An unreachable cover proves it cannot happen under those assumptions. That often means the assumptions are too tight, so covers are the main check against over-constraint.
Follow-upPractise What a Cover Means in Formal →How could a cover property report a hit that never happened in real traffic? L2
If the sequence can match on reset values, it is covered while the design is held in reset. For example, !valid ##1 !valid matches on any two reset cycles. Add disable iff (rst) to the cover, or include a real event such as valid && ready in the sequence.
Weight, Goal and Minimum Hits5
What do option.weight, option.goal and option.at_least change? Which of them change the number get_coverage() returns? L1L2
at_least sets how many hits a bin needs to count as covered; the default is 1. weight sets how much a coverpoint or cross counts in the covergroup average; the default is 1, and 0 takes it out. goal is a target that reports compare against, 100 by default. So at_least and weight change the number, and goal does not.
Why would you set at_least above 1? What does this coverpoint report? L1L2
It reports 50%, because b[1] has one hit and needs two. One hit shows a case happened once. It does not show the design handles it again, for example after it has already recovered once. Raise at_least for cases like error recovery or a full FIFO, where a second hit tests a different state. Don't raise it everywhere, or closure slows down for no gain.
The plan says error paths need at least 10 hits each, and normal traffic needs one. How do you express that in a large model? L2L3
Put error paths in their own coverpoints or covergroup, with option.at_least = 10 set on those coverpoints. Keep normal traffic at the default. Then each covergroup maps to a line of the plan, and the report shows each feature against its own target. Don't encode the difference in weights, which only blurs one total.
Compare setting option.weight = 0 on a coverpoint with deleting it. L1
With weight 0, the coverpoint still collects data and appears in the report, but it adds nothing to the covergroup number. That suits diagnostic coverpoints, and coverpoints that exist only to build a cross. Deleting it loses the data, and any cross that uses it no longer compiles.
Follow-upPractise Weight Zero vs Deleting the Coverpoint →How can weights make a coverage number misleading? L2L3
A large weight on an easy coverpoint pulls the total up early. The group then looks nearly done while a hard cross is empty. A zero weight on a hard cross hides it completely. Weights also behave differently between tools. Keep the default weights, and report hard items, such as key crosses, as their own numbers.
Follow-upPractise Weights That Make the Number Lie →Type Coverage vs Instance Coverage5
Two instances of one covergroup watch two ports. Between them they hit all four bins. What does this print? L2L3
It prints A=50.00 B=50.00 type=50.00. Each instance has its own coverage, and per_instance = 1 keeps it in the report. The type figure, get_coverage(), is by default the weighted average of the instances. It is not the union of their bins. With type_option.merge_instances = 1 the type becomes the union, so it reads 100%.
Why does the type figure read 50% when the instances together hit every bin? L2
With merging off, each instance is scored against its own bins, and the type is the weighted average of those scores. Port A scores 50 and port B scores 50, so the type is 50. The rule asks "how well was each instance covered", not "was each bin hit somewhere". One idle instance therefore pulls the type figure down.
Follow-upPractise Why the Type Figure Is an Average →Compare the merged view with the averaged view. When do you want each? L2L3
Merge when the instances are interchangeable and a case seen on any one of them is enough. Identical lanes behind one arbiter are an example. Average, and read per-instance numbers, when every instance must see every case, such as ports with their own logic. The choice belongs in the coverage plan, written next to the covergroup.
Follow-upPractise When to Merge Instances →Four ports share one covergroup type. Port 3 never sees traffic. What do the averaged and merged figures say? L2L3
The average reads 75%, and the union reads 100%. Merging asks whether any instance hit each bin, so three busy ports cover for the dead one. The averaged figure at least shows a gap. Only the per-instance report says which port is dead.
Follow-upPractise A Dead Port Behind a Merged 100 Percent →What if option.per_instance is left at 0? L2
Each instance still contributes to the type figure. But the per-instance data is not saved to the coverage database, so the report cannot show which port is weak. Set per_instance = 1 whenever instances watch different things. It can only be set on the covergroup, not on a coverpoint.
Automatic Bins on an 8-Bit Value5
This coverpoint has no bins of its own. How many bins does it get, and what coverage does it print? L0L1
It gets 64 automatic bins, not 256. When a coverpoint lists no bins, the tool makes at most auto_bin_max bins, and the default is 64. So each bin holds 4 values: 0 to 3, 4 to 7, and so on. The five samples land in only two bins, 0 to 3 and 100 to 103. It prints coverage=3.12, which is 2 of 64.
What if the coverpoint is on an enum with three named values, and auto_bin_max is set to 2? L1
An enum coverpoint gets one automatic bin per named value, and auto_bin_max does not apply. So there are three bins, and two samples give 66.67%. Values the enum type could hold but does not name get no bins.
Compare automatic bins with bins you write yourself. When is each the right choice? L1L2
Automatic bins are fine when there are few values and every one matters, such as an enum or a 3-bit field. Write explicit bins when the value is wide or when only some values matter. Explicit bins follow the spec: corners, ranges where the design behaves differently, and values that must never appear. They also give the report readable names.
Follow-upPractise Automatic vs Explicit Bins →A teammate puts a coverpoint with automatic bins on a 32-bit address and reports 100%. What does that number tell you? L2
Almost nothing. With 64 automatic bins, each bin spans 2 to the power 26 addresses, about 67 million. One access anywhere in each slice covers it. The model says nothing about alignment, region boundaries or the last address of a region. Replace it with bins for the address map. Cover each region, its first and last word, and unaligned accesses if the bus allows them.
Follow-upPractise Automatic Bins on a 32-Bit Address →Why does the language cap automatic bins at all, instead of one bin per value? L1
Without a cap, a 32-bit coverpoint would need over four billion bins. That costs memory, slows every sample and makes a report nobody can read. The cap keeps a forgotten coverpoint from exploding. You can change it per coverpoint or per covergroup with option.auto_bin_max.
Ignore, Illegal and Default Bins5
An opcode field has 8 values, and 6 and 7 are reserved. Do you use ignore_bins, illegal_bins or a default bin? What does each one do? L0L1
All three keep values out of the coverage total, but they act differently when a value arrives. ignore_bins drops the value silently. illegal_bins drops it and raises a run-time error when it is hit. A default bin collects every value no other bin names, and it never counts toward coverage. For reserved opcodes, use ignore_bins and a separate check in the monitor or an assertion.
Why do many teams avoid illegal_bins for protocol errors, even though it does raise an error? L1L2
Coverage is often switched off for speed in some regressions, and the check would vanish with it. An illegal bin also fires only when the covergroup samples. If sampling is gated, a bad value in an unsampled cycle passes unseen. The error text is short and has no transaction context. A checker or assertion runs in every regression and gives a useful message.
Follow-upPractise Why Teams Avoid Illegal Bins for Checking →The opcode coverpoint has iff (valid && ready). How can a reserved opcode still get past without the illegal bin firing? L2
The guard means the coverpoint only looks at accepted transfers. Suppose the design wrongly accepts a beat while ready is low. The coverpoint never sees that beat, so a reserved opcode on it goes unchecked. An assertion on the interface, such as valid |-> op inside {[0:5]}, checks every clock.
Compare an illegal bin with an assertion in the interface for the same reserved opcode. L1L2
The assertion is a check: it runs every clock, survives when coverage is off and reports with the time and signal values. The illegal bin is a side effect of a coverage model, and it runs only on samples. Use the assertion to catch the bug. Keep the reserved values in ignore_bins so they don't sit as permanent holes.
What if a later spec revision makes opcode 6 legal, and nobody touches the covergroup? L2L3
The new opcode stays in ignore_bins, so it never appears as a hole, and coverage still reads 100%. The new feature ships untested by any coverage measure. Keep every exclusion next to its spec reference and review them all when the spec changes. Treat a change to an exclusion like a design change.
Wildcard Bins5
What does this print? How would you change it so every odd value must be seen? L0L1
It prints coverage=100.00. With the wildcard keyword, each ? bit matches 0 or 1, so the bin collects all eight odd values. It is still one bin, and one hit on any odd value covers it. To need each odd value separately, write wildcard bins odd[] = {4'b???1};. That makes eight bins, and one sample covers 12.5%.
Compare these two ways to cover word-aligned addresses. What does the covergroup print? L1L2
It prints covergroup=75.00. The wildcard bin is one bin for every address ending in 00, so two aligned samples give 100%. The with filter keeps the aligned values in 0 to 15 and makes one bin each, so two of four are covered. The covergroup averages 100 and 50. Use the wildcard to ask "was any aligned access seen" and the filter when each aligned address matters.
Prove it: write bins that split an 8-bit opcode into four classes by its top two bits. L1
Write one wildcard bin per class, with the top two bits fixed and the rest as ?. For example, wildcard bins alu = {8'b00??????};. After an ALU, a load and a branch opcode, the run reports 75%, because no store was seen.
The instruction set has 200 opcodes in a dozen classes. How do you structure the opcode coverage? L2L3
Use two levels. A class coverpoint with wildcard bins shows broad progress early. A per-opcode coverpoint, generated from the same table the decoder uses, shows the long tail. Cross the class, not each opcode, with operand corners, or the cross explodes. Generate the bins from the spec table so a new opcode cannot be forgotten.
Follow-upPractise Opcode Coverage for a Whole Instruction Set →What if value 0 must be excluded, but it also matches the wildcard bin for even values? What does this print? L1L2
It prints after 0: 0.00, then after 6: 100.00. An ignored value is removed from every bin of the coverpoint, even a bin that also names it. So sampling 0 covers nothing, and the even bin needs some other even value.
Bins for a Wide Range of Lengths5
A packet length runs from 1 to 1024 bytes. Write the coverpoint bins. What goes wrong with one big bin, or with one bin per value? L0L1
Write bins for the corners and a few ranges: min = {1}, max = {1024}, a value next to each end, and mid[4] for the middle. One bin over [1:1024] is covered by the first packet, so it can never show a hole. One bin per value makes 1024 bins that a regression will not fill. Take the ranges from the spec, such as the sizes where the design changes behaviour.
Why might bins mid[4] = {[2:1023]} not give four equal bins? L1
The range holds 1022 values, which does not divide by 4. Each bin gets 255 values, and the last bin also takes the 2 left over, so it holds 257. If an edge matters, don't leave it to the division; give it a named bin.
Follow-upPractise Where the Leftover Values Go →Compare mid[4] = {[64:1022]} with ranges you name yourself, like small, medium and jumbo. L1L2
A fixed array splits the range by arithmetic, so a design threshold can fall in the middle of a bin. Named ranges follow the spec, so each bin means something and the report is readable. Use arrays for a quick spread across a range that has no special points. Use named ranges wherever the design changes behaviour.
Follow-upPractise Fixed Bin Arrays vs Named Ranges →The design stores packets in 256-byte buffers. Which lengths deserve their own bins, and why? L1L2
Give 255, 256 and 257 their own bins, and the same for 511 to 513 if two buffers chain. Off-by-one bugs live exactly there: the packet that just fits, and the one that spills into a second buffer by one byte. Write them as bins at_256[] = {255, 256, 257}; beside the wider ranges.
The same length coverpoint must work for designs built with different MAX_LEN values. How do you write it? L2
Pass the limit in as a covergroup argument, covergroup cg(int max_len);, and use it in the bins, such as bins max = {max_len};. Each instance then gets bins for its own design. The standard allows this, but check your tool. The coverage build used on this site rejects covergroup arguments inside bins.
Covering a Stall with Transition Bins5
A sink can hold ready low for one or two cycles. Write coverage that proves both stall lengths were seen, not just that a stall happened. L1L2
First reduce the handshake to one state per clock: IDLE when valid is 0, WAIT when ready is 0, and XFER when both are 1. Then write transition bins on that state. Use (IDLE, XFER => WAIT => XFER) for a one-cycle stall and (IDLE, XFER => WAIT => WAIT => XFER) for two. Anchoring the start stops a longer stall from also matching the shorter bin. A value bin on WAIT only says some stall happened.
Why convert valid and ready into one state before writing transitions? Why not cross them? L1
A transition bin follows one coverpoint's value from one sample to the next. A cross only pairs values within the same sample and has no memory of earlier ones. So valid crossed with ready shows that a stalled cycle happened, but not how long the stall lasted. One state per clock gives the transition something to follow.
Compare transition bins with a counter of stall cycles, sampled at each transfer. What does this print? L2
It prints three transfers, after 0, 1 and 5 stall cycles, then 75% coverage, because no two-cycle stall happened. A counter handles any stall length with one coverpoint, and a range bin like [3:16] covers long stalls. Transition bins grow one bin per length and get unreadable past three or four cycles. Use transitions for short, exact patterns and a counter for lengths.
An interconnect has 12 ports with the same handshake. How do you cover stalls on all of them without 12 copies of the code? L2L3
Write the covergroup once, in the interface or in a coverage class, and create one instance per port. Set option.per_instance = 1 so the report shows each port. Remember that the type total averages the instances. Eleven busy ports and one dead port still look like 92%, so review the per-port numbers, not just the total.
How could these transition bins still mislead you? Suppose the covergroup samples on a core clock twice as fast as the bus. L2
Every bus cycle is sampled twice, so each state appears twice in a row. A one-cycle stall then looks like WAIT => WAIT, and it covers the two-cycle bin instead. Transition bins count samples, not bus cycles. Sample on the bus clock, or call sample() once per bus cycle.
Three Coverage Holes, Three Causes5
Coverage has stayed at 70.83% across three seeds. Here is the report. What causes each hole, and what do you do about it? L2L3
Treat each hole on its own, because they have different causes. No length 16 in 1500 packets means the bench cannot make it, so read the constraints: they stop at 15 while the spec allows 16. No CRC errors means no test turns on error injection, so a test or a knob is missing. CONFIG with a long burst is forbidden by the spec, so exclude it with a reference. More seeds fix none of the three.
QuestionPractise Three Coverage Holes, Three Causes →Why does the same number across several seeds point to the bench, rather than bad luck? L1L2
Each seed takes a different path through the stimulus space. If a bin is reachable with a fair chance, some seed hits it. When thousands of samples over many seeds never touch it, the chance is probably zero. That usually means a constraint, a disabled knob, or a case the design cannot reach.
Follow-upPractise Why a Flat Line Points at the Bench →How could a future constraint edit quietly create a hole like this again? Write a check that would catch it early. L2
Add a short test that asks the solver for each corner the coverage model needs, with randomize() with { len == 16; }. If the constraints forbid the corner, randomize() returns 0 and the test fails at once. It runs in seconds, so it can run on every check-in, long before a regression plateaus.
Compare excluding the CONFIG/long cells with relaxing the CONFIG constraint so they get hit. L1L2
The spec says CONFIG is one beat, so a long CONFIG is illegal stimulus. Relaxing the constraint would make the bench send packets the design is allowed to reject or mishandle. The scoreboard would then raise false errors. Exclude the cells, cite the spec, and keep a check that the design never sees a long CONFIG from a real source.
Follow-upPractise Excluding a Cell vs Relaxing the Constraint →What if the bench can generate the case, but the design never enters the state the bin describes? L2L3
Then either the bin is wrong, or the design is missing a feature. Ask the designer which one, and settle it with evidence. A formal cover on the state either finds a trace or proves it unreachable. If the spec requires the state, an unreachable result is a design bug, not a waiver.
Follow-upPractise A Hole the Design Itself Cannot Reach →Closing the Last Eight Percent5
Functional coverage has sat at 92% for two weeks. Tape-out is a month away. How do you close it? L2L3
First list the holes and sort them by cause and by risk, not by count. Fix bench limits, such as wrong constraints or missing knobs, because one fix often clears many holes. Bias the constraints toward rare cases, and write directed tests only for cases random stimulus cannot reach in time. Prove unreachable holes with formal or a designer review, and exclude them with the reason. Report what remains as named risks.
QuestionPractise Closing the Last Eight Percent →Why does coverage rise fast at first and then crawl? L1L2
Early samples land on empty bins, so almost every sample adds coverage. Later, most samples land on bins already hit, and only the rare ones add anything. Bins with low probability under the constraints may take thousands of samples each. Holes that cannot be reached never close, so they look like a crawl that never ends.
Follow-upPractise Why the Last Few Percent Take the Longest →Your lead wants a weekly closure report for a subsystem. What goes in it besides one percentage? L3
Show coverage per plan feature, not one total, with its trend over the weeks. Show how many new bins each regression adds, because a flat line means you need new work, not more runs. Add the open holes grouped by cause and owner, and the bug rate. A falling bug rate with flat coverage is the pattern you want before sign-off.
Follow-upPractise Reporting Closure Progress →Compare biasing the constraints toward a hole with writing a directed test for it. L2
Biasing, for example with dist weights or a test-level constraint, keeps the other fields random. So the rare case also meets many neighbours. A directed test hits the case once, fast and repeatably. Bias first when the case is reachable but rare. Go directed when it needs a long exact sequence, such as an error during a full FIFO after reset.
What if tape-out is in a week and 3% is still open? What do you do? L3L4
Go through each remaining hole with the designers and the project lead. For each, state what feature it covers, how likely the case is in real use, and what a bug there would cost. Close the high-risk ones with targeted tests or formal. For the rest, record an accepted risk with an owner, plus a plan for post-silicon tests or a software workaround.
Follow-upPractise Tape-Out with Coverage Holes Left →Building a Coverage Plan from a Spec7
Walk me through how you build a coverage plan from a spec. Use a FIFO with an APB register interface as the example. L2L3
I start from the spec, not the RTL, and list each feature with its section number. For each one I decide what must be observed: values, sequences or combinations, and where to sample them, usually the monitor. Bins come from the spec's corners, and crosses only where the spec ties two fields together. Exclusions get a written reason. Then the designer and architect review the plan before any covergroup is coded.
QuestionPractise Building a Coverage Plan from a Spec →Why build the coverage plan from the spec and not from the RTL? L1L2
A plan read from the RTL only lists what was built, so it repeats the designer's understanding, mistakes included. A missing feature never appears in it. Code coverage already measures the RTL's structure. The spec is the independent source, so a plan built from it can find what the RTL left out.
Follow-upPractise Why the Plan Starts from the Spec →Compare a coverage plan with a test plan. Why keep both? L2
A test plan lists the stimulus: which tests exist and what each one drives. A coverage plan lists what must be observed before a feature counts as done. With random tests the mapping is many to many: one test fills bins from many features, and one feature needs many tests. The coverage plan measures whether the tests did their job.
Follow-upPractise Coverage Plan vs Test Plan →How can a plan item reach 100% coverage and still be unverified? L2L3
Coverage says the case happened; it does not say anyone checked the result. If the scoreboard ignores a field, or an assertion is missing, the case passes with any behaviour. So each plan row needs both a coverage item and a named checker. Review the checkers as carefully as the bins.
Follow-upPractise Covered but Never Checked →What if the spec is silent on one corner? For example, a push and a pop arrive in the same cycle while the FIFO is full. L2
Raise it as a spec question with the architect, in writing, and don't guess. Cover the case anyway, because unclear corners are where designers and verifiers disagree. Once the answer is agreed, update the spec, the checker and the plan together. Until then, mark the row as open.
Follow-upPractise A Corner the Spec Does Not Define →The FIFO now sits inside a subsystem with a DMA and an interconnect. How does the coverage plan change? L3L4
Don't re-close the FIFO's block corners; they were closed at block level. Keep the block covergroups running passively, so you can see which corners real traffic reaches. Add integration items: connections, the FIFO full while the DMA retries, and the interconnect stalling the APB side. Add system scenarios from the use cases too. Each level covers what only it can reach.
Follow-upPractise The FIFO Plan Inside a Subsystem →Prove it: turn the "overflow sticky bit" row into coverage. What does this print for the two tests? L1L2
It prints 100.00 for the first test and 66.67 for the second. The row says the bit is set by an overflow, stays set, and is cleared by a register write. Each of those is a transition, so each gets a transition bin. The second test never clears the bit, and the report names that hole.
Follow-upPractise From a Plan Row to a Coverpoint →Merging Coverage and Ranking Tests5
How do you merge coverage across a nightly regression of 3000 tests? What is test ranking for, and what is it not for? L3L4
Merge only runs that passed, built from the same RTL and the same coverage model, and take the union of bin hits. Coverage from a failing run is discarded, because the design misbehaved there. Ranking orders tests by how much new coverage each adds, so a small set reaches the same number. Use that set as a fast check-in regression. Don't delete the rest; random seeds still find bugs the model never named.
QuestionPractise Merging Coverage and Ranking Tests →Why is coverage from failing runs thrown away before merging? L2
A failing run shows the design did not behave as the spec says in that run. The bins it hit describe cases that ran, but were not shown to work. Counting them would mark features as verified while their bug is still open. Once the bug is fixed, rerun the test and count the new, passing coverage.
Follow-upPractise Why Failing Runs Don't Count →Compare running the ranked set with running the full regression. When do you use each? L3
The ranked set reaches the same coverage in a fraction of the time, so it suits every check-in and quick bug-fix checks. Its seeds are fixed, so it repeats the same stimulus every time. The full regression keeps exploring with new seeds and finds bugs the coverage model never described. Run the ranked set often and the full regression nightly or weekly.
Follow-upPractise A Ranked Test Set vs the Full Regression →What if one block's RTL changes after coverage has been merged? Do you keep the old data? L3
Look at the size of the change first. For a local fix, rerun the tests that touch the changed logic, and replace that block's coverage with the new runs. For a broad change, such as a new feature or changed timing, start that block's merge from scratch. Sign-off coverage must come from runs on the RTL that tapes out.
Follow-upPractise Merged Coverage After an RTL Change →An IP block is reused in three chips, each with a new release. How do you manage its coverage? L4
Sign off coverage per IP release, stored with the release, on the configurations each chip uses. A new chip reuses that result for unchanged logic, and closes coverage only for new configurations and changed code. At chip level, cover the integration, not the IP's internals again. Keep a list of which configurations were never verified, so nobody assumes they were.
Follow-upPractise Coverage Across IP Releases →Coverage Sign-Off for a Block6
Walk me through your coverage sign-off review for a block. L3L4
I start from the plan, showing that every item maps to a covergroup, a cover or a test, and to a checker. Then the numbers: functional coverage at goal, from passing regressions on the final RTL, with every exclusion reviewed. Every code coverage hole has an explanation. Next the trend: the bug rate has flattened, and new seeds add no coverage. Last, the open risks, each accepted by a named owner.
QuestionPractise Coverage Sign-Off for a Block →Why look at the bug rate when coverage is already at goal? L2L3
Coverage measures the cases you thought of. The bug rate measures what the design is still doing wrong. If bugs keep appearing at full coverage, the model is missing cases, and the new bugs show where. A flat, low bug rate alongside full coverage is much stronger evidence than either alone.
Follow-upPractise Why the Bug Rate Belongs in Sign-Off →How could a block pass this review and still fail in silicon? L3
The plan can miss a feature, so nothing measures it. A covergroup can sample the stimulus instead of what the design did. A checker can ignore a field, so covered cases pass with wrong results. The failure can also need traffic only the chip creates. Each of these is a review question: what is missing, where is it sampled, who checks it, and what needs the chip?
Follow-upPractise How a Bad Block Passes Sign-Off →Compare coverage sign-off for a block with sign-off for the whole chip. L3L4
Block sign-off closes the detailed corners of one design: every mode, boundary and error path. Chip sign-off assumes the blocks are done. It closes what only the chip has: connections, clocks and resets, shared buses, and end-to-end use cases. Its plan is smaller per block and wider across blocks. A chip review that re-checks block corners is wasting its time.
Follow-upPractise Block Sign-Off vs Chip Sign-Off →You lead verification for a chip with 40 blocks and several teams. How do you make every block's sign-off mean the same thing? L4
Write the criteria once, before the reviews start. They cover the plan and its checkers, coverage goals, exclusion rules and the bug-rate condition. Give every team the same report template, generated from the regression rather than typed by hand. Have someone from another team join each review. Track every block on one dashboard, so a weak block is visible early.
Follow-upPractise One Sign-Off Standard for Forty Blocks →What if a bug fix lands in the block a week after its coverage sign-off? What do you rerun? L3
Start with an impact review with the designer: which logic changed and which features touch it. Add a test that reproduces the bug and passes on the fix. Rerun the regression for that block on the new RTL, and replace its coverage with the new runs. Then check that nothing in the plan dropped below goal. Record the change and the evidence in the sign-off.
Follow-upPractise A Bug Fix After Sign-Off →A Cross That Can Never Close5
Cross the command (READ, WRITE) with burst-length bins one, short and long. A READ is never longer than 4 beats. Write the cross so it can reach 100%. L1L2
The plain cross has six cells, and READ with a long burst can never happen, so it stays below 100%. Exclude that cell: ignore_bins rd_long = binsof(c) intersect {READ} && binsof(l.long_);. Here binsof(c) intersect {READ} picks the READ bins of c, and binsof(l.long_) picks one bin of l. The && keeps only cells that match both. Put the spec reference next to the line.
Explain what binsof(c) intersect {READ} selects. Why not just name the bin? L1
binsof(c) means all the bins of coverpoint c. Adding intersect {READ} keeps only the bins whose values include READ. For an enum with automatic bins, you never wrote the bin names. Selecting by value is simpler, and it survives a bin rename. When you did name a bin, as with l.long_, binsof(l.long_) picks it directly.
Compare the cross with exclusions against two coverpoints guarded by the command. What does this version print? L1L2
It prints 83.33. The read coverpoint has only the legal read lengths, so it closes at 100%. The write coverpoint is missing long_, so it reads 66.67%, and the group averages the two. Splitting needs no exclusions, and each coverpoint reads clearly. A cross is better when many fields combine, because guarded coverpoints multiply quickly.
What if the design one day accepts a long READ? Who notices? L2
Nobody, if the only trace of the rule is the ignore_bins. The ignored cell takes the hit silently, and coverage stays at 100%. Every exclusion needs a matching check, such as an assertion on the interface or a scoreboard error. The exclusion keeps the number honest, and the check catches the bug.
How could the exclusion itself hide holes? Suppose someone writes || instead of &&. L2
With ||, the expression selects every READ cell and every long cell, so it removes four of the six cells. Only WRITE one and WRITE short remain, and short writes alone close the cross. Review exclusions by listing the cells they remove, not by reading the expression.
A Cross Stuck at 12 Percent5
You cross address region (16 bins), burst length (8), size (4) and ID (16). Coverage has been stuck near 12% for weeks. What do you tell your manager? L2L3
The cross has 16 × 8 × 4 × 16 = 8192 cells, and each needs its own hit. Most of them are not interesting, and many are impossible, so a low number says more about the model than the design. Cross only the pairs the spec ties together, such as length with size. Cover the ID on its own. Each cell should be a case someone would write a test for.
QuestionPractise A Cross Stuck at 12 Percent →What if every cell is legal and equally likely? Roughly how many random samples does a 512-cell cross need? Read the run. L2
Many more than 512. Random samples repeat cells, so the last few empty cells take the longest. After 512 samples this run has about 63% of the cells. It needs 3384 samples, more than six per cell, to fill them all. Uneven probabilities make it much worse, so rare cells need biased constraints or a directed test.
Follow-upPractise How Long Random Stimulus Takes to Fill a Cross →Compare one four-way cross with a set of two-way crosses over the same fields. L2L3
The four-way cross demands every combination, 8192 cells here. The pairs, such as length with size and region with size, need every combination of two fields. That is a few hundred cells in all. Most spec rules involve two fields at a time, so pairs cover them at a small cost. Keep a three-way cross only where the spec states a rule that names three fields.
Follow-upPractise One Big Cross vs Several Pairs →How can the covergroup total make a weak cross look fine? L2
By default the covergroup averages its coverpoints and crosses with equal weight. In the twin above, two closed coverpoints and a 12.5% cross average to 70.83%. With four closed coverpoints beside the cross, the total would pass 80% while the cross is nearly empty. Report each cross on its own.
Follow-upPractise A Cross Hidden in the Covergroup Total →Prove it: how do you get one number that is just the cross? What does this print? L2
It prints 25.00. The two coverpoints have weight 0, so they still collect data and show in the report, but they add nothing to the total. The cross is the only item left, and 4 of its 16 cells are hit. Put each key cross in a covergroup built this way, or read it from the report tool.
Follow-upPractise Reading a Cross as Its Own Number →A Covergroup That Counted Idle Cycles5
A covergroup on the packet kind is clocked with @(posedge clk). The trace shows only WRITE and CONFIG transfers, yet READ is covered. Why? L1L2
A clocked covergroup samples at every clock edge, including idle cycles. While valid is 0, the bus parks kind at 0, and 0 is READ. So the idle cycles cover READ, though no read ever moved. Sample only on a transfer instead. Call sample() when valid && ready is true, or add iff (valid && ready) to the coverpoint.
Compare a clocked covergroup with one you sample by calling sample(). When is a clocking event the right choice? L1
A clocking event fits values that matter every cycle, such as an FSM state or a FIFO level. Calling sample() fits events, such as transfers, packets and register writes. A class-based bench usually calls sample() from the code that sees each transaction. A clocked covergroup on event data counts idle cycles as if they were events.
What if the covergroup is clocked on the same edge that updates the flop it covers? What does this print? L2
It prints zero-bin coverage=100.00. The covergroup samples when the edge event fires. The flop's nonblocking update lands later in that time step, so the sample sees the value from before the edge. That is the same value the flop held during the previous cycle. Plan bins with that one-cycle view in mind.
Your regression got 30% slower after the coverage model was added. What do you look at first? L2L3
Look first for covergroups that sample every clock but only need events. Then look for large crosses and for coverage inside objects that are created by the thousand. Sample once per transaction, guard coverpoints with iff, and cut crosses down to the cells in the plan. Keep a switch that turns coverage off in soak tests that are not measuring it.
A teammate embeds the covergroup in the transaction class, and the test creates a million transactions. What happens? L2L3
Each transaction object builds its own covergroup instance in its constructor. That is a million covergroup instances, each sampled once or twice, and memory and run time grow with them. Put covergroups in components that live for the whole run, such as a coverage collector, and pass each transaction to them.
Follow-upPractise A Covergroup Inside the Transaction Class →A Covergroup Inside a Collector Class4
This collector receives lengths 1, 2, 3 and 4. What coverage does it report, and why? L1L2
It reports 75%. write() calls sample() before it updates len, so each sample sees the previous length. The first sample sees 0, which has no bin, and the length 4 is never sampled. Pass the value in instead: declare covergroup cg with function sample(int l); and call cg.sample(t). The constructor is also the right place for cg = new(), because an embedded covergroup must be built there.
Why do many teams prefer with function sample(...) over coverpoints that read class members? L1
The arguments say exactly what is sampled and when. There is no ordering rule between updating members and calling sample(). The same covergroup can be sampled from any place that has the values. A monitor callback or an assertion action block both work. It also keeps the covergroup independent of the class layout.
What if someone moves cg = new() into a configure() method, or forgets it entirely? L1L2
Moving it does not compile. The standard allows an embedded covergroup to be assigned only in its class's new method, and the coverage build says exactly that. Forgetting it does compile. Then the covergroup never exists, and the first sample() call stops the run with a null pointer error. A collector that never samples just reports nothing for that group.
Compare a covergroup embedded in a class with one declared in a package and created by the class. L1L2
An embedded covergroup can read the class's local and protected members directly, and it is one instance per object. A covergroup declared in a package takes its inputs as arguments. Several classes can then create it, and a class can hold an array of them. Use embedded for one collector class; use a package covergroup when several components share the model.
Follow-upPractise Embedded vs Standalone Covergroups →Full Coverage, No Errors, and a Dropped Packet7
Silicon drops CONFIG packets. Here is the end of the block regression log, which passed. What went wrong in the bench? L1L2L3
Two things. The covergroup was sampled in the generator, so it measured what was sent, not what the design produced. And the scoreboard compared only the packets that came out: 30 went in, 20 were compared, and nobody checked the count. Sample coverage at the output monitor, from what the design accepted or produced. Add an end-of-test check that every sent packet was compared.
QuestionPractise Full Coverage, No Errors, and a Dropped Packet →Why should coverage be sampled from what the design accepted, and not from what the generator produced? L1
Coverage claims that the design was exercised in a situation. A generated item proves only that the bench made it. The design may never have accepted it, because of back-pressure, a reset or a driver bug. Sampling at the monitor ties each bin to something the design actually did.
Follow-upPractise Why Coverage Belongs on What the Design Did →How could coverage sampled at the output monitor still mislead you? L2
It sees only what came out. A packet the design corrupts into another kind is counted under the wrong bin. A packet that comes out with the wrong data still covers its bin. Coverage says a case happened; only the checker says it was right. That is why coverage is only trusted from passing tests.
Follow-upPractise What Output-Side Coverage Still Misses →Prove it: write the end-of-test check that would have caught the 10 missing CONFIG packets. L1L2
At the end of the test, after the design has drained, compare the counts and the expected queue. Fail if compared != sent, or if any expected item is still waiting, and print what is left. In a UVM bench this goes in check_phase, after the run phase has ended. In the log above it would have reported 10 packets that never came out.
Compare input-side and output-side coverage. Is input-side coverage ever useful? L2L3
Input-side coverage, taken at the input monitor after the design accepted the item, shows which requests the design saw. Output-side coverage shows which results it produced, such as error responses or interrupts. You usually need both, and a cross of them, such as request kind against response status. Coverage taken in the generator is useful only to tune the generator, never for sign-off.
Follow-upPractise Stimulus Coverage vs Response Coverage →What if the design is fine, but the driver drops items? It gives up after a few cycles of back-pressure and moves on. L2
Generator-side coverage is just as blind to this; the item was generated, so its bin counts. The scoreboard may never expect it, so nothing fails. An input monitor, sampling what crossed the interface, shows the missing items. Treat a driver that silently discards items as a bench bug: it must report an error or retry.
Follow-upPractise A Driver That Drops Items Under Back-Pressure →You review other teams' coverage models. Which questions catch mistakes like this one before tape-out? L3
Ask where each covergroup samples, and from which monitor. Ask which plan row each coverpoint serves, and why each bin edge sits where it does. Ask which exclusions exist and what spec text supports them, and whether reset is guarded. Ask which checker verifies each covered case. A model that cannot answer these is not ready to count toward sign-off.
Follow-upPractise Questions for a Coverage Model Review →Keeping Reset Out of Coverage5
A clocked covergroup covers a FIFO's fill level, with bins for empty, partial and full. Write it so that reset cycles cannot cover any bin. L1L2
Add a guard to the coverpoint: coverpoint level iff (!rst). During reset the design holds known values, such as a level of 0, and a clocked covergroup counts them. The empty bin is then covered by reset alone, even if the FIFO never drains in the test. With the guard false, the coverpoint ignores that sample.
Compare the iff guard with calling cg.stop() during reset and cg.start() after it. L1L2
The guard is part of the coverage model and works the same in every test. stop() and start() are calls the test must remember to make, so a test that forgets them counts reset again. They are useful for switching a whole group off in a phase of the test. Check your tool before relying on them; this site's coverage build ignores stop().
What if the spec allows a reset in the middle of traffic? Is excluding reset still the right model? L2
No, a mid-test reset is a feature to cover, not noise. Keep the iff (!rst) guard on the normal coverpoints, and add a coverpoint sampled at the rising edge of reset. Its bins say what the design was doing when reset arrived: empty, partial, full, or in the middle of a transfer. Each bin is a recovery case the bench must check.
At chip level there are several reset sources and domains. Which reset scenarios go into the coverage plan? L3
List each reset source and what it resets: power-on, warm reset, watchdog, and per-domain or per-block resets. Cover each one while traffic is in flight, and cover one domain resetting while its neighbours keep running. Cross the reset with the state of the bus between the domains. Those crossings are where hangs and lost transactions appear.
Follow-upPractise Reset Coverage Across a Chip →Why put iff on each coverpoint instead of wrapping the whole sample() call in if (!rst)? L1
A per-coverpoint guard lets one covergroup mix rules. Normal coverpoints ignore reset, while a reset coverpoint in the same group samples only during reset. Wrapping the call is fine when every coverpoint shares one rule. With a clocked covergroup there is no call to wrap, so the guard is the only option.
Follow-upPractise Why Guard Each Coverpoint →Your Review Queue
Saved review reminders are coming soon.