Skip to content

Coverage Signoff on an ASIC Design

Reaching coverage signoff can be a long, repetitive part of ASIC verification: run the regression, read the coverage reports, work out which features the tests never exercise, write new stimulus, and run everything again. This tutorial shows how NEX can take on that loop. We will use an OpenCores CAN controller as our example: its regression passes but sits far below the signoff targets, and NEX will measure the baseline, diagnose which CAN features the tests never touch, extend the testbench, and deliver the signoff table, with the engineer steering through four prompts.

Note

Before you begin, ensure you have installed the NEX CLI and that Synopsys VCS and urg are available in your environment. NEX license and LLM configuration are covered in Settings Basics.

Follow along

The project files used in this tutorial are available in the ChipNexus tutorials repository.

The Challenge

The design under test is an OpenCores SJA1000-compatible CAN protocol controller: 6,600 lines of Verilog across 12 modules, including a bit-stream processor (can_bsp), bit-timing logic (can_btl), and an acceptance filter (can_acf). It needs coverage signoff.

The regression passes. Every check is green. But "the tests pass" and "the design is verified" are different claims: the regression only exercises basic-mode (11-bit ID) transmit/receive with one frame shape. The verification lead has set signoff targets:

Metric Target
Total urg SCORE >= 67%
can_bsp (bit stream processor) >= 72%
can_acf (acceptance filter) >= 55%
Every DUT module >= 50%

Setting Up the Workspace

The workspace is minimal: third-party RTL, a project-owned testbench, and a filelist:

Workspace layout
can-coverage-signoff/
├── NEX.md          # project rules (empty for now; NEX will write it)
├── can.f           # filelist: RTL + testbench + include dirs
├── rtl/            # 13 Verilog files (third-party, read-only)
└── tb/
    └── tb_can_basic.v   # the current regression: 2 CAN nodes on a wired-AND bus

The testbench models a real CAN topology: two can_top instances on a wired-AND bus, so node 2 provides the hardware ACK in the ACK slot exactly like a real transceiver would. It drives the 8051-style register interface (ALE/RD/WR) with write_reg/read_reg tasks and self-checks every stimulus: 6 checks, ending in TEST PASSED.

Launch the ASIC agent from the workspace:

cd can-coverage-signoff
REQUEST_LIMIT=200 nex --agent asic

Launching the ASIC agent with a raised autonomous-step budget

Why REQUEST_LIMIT=200?

A signoff loop (compile, simulate, report, patch, repeat) makes far more tool calls than a conversational session, so we raise NEX's autonomous step budget from its default of 20 up front. If the limit is ever reached anyway, NEX pauses safely and typing continue resumes.

Teaching NEX the Project Rules

NEX.md is the project memory: targets, flow, and conventions that persist across sessions. You can write it by hand, or, as we do here, ask NEX in the prompt to write it after reading the design. First prompt:

Prompt
We're kicking off a CAN controller coverage signoff. The design is an OpenCores
SJA1000-compatible core. Sources are in can.f, top is tb_can_basic. Our targets:
total urg SCORE >= 67%, can_bsp >= 72%, can_acf >= 55%, no DUT module below 50%.
Look at the RTL and testbench, then write a NEX.md for this workspace that
captures the signoff targets, the VCS+urg flow, and the project conventions
nex should follow.

Because the prompt explicitly asks for it, NEX inspects can.f and the testbench and then writes the file itself through its update_nex_md tool:

NEX authors the project's NEX.md and asks for approval before writing it

Two details in the generated NEX.md show it actually read the design rather than templating: it recorded that this is a plain Verilog project ("do not use -sverilog", because the RTL uses do as a port name, which SystemVerilog reserves), and it pre-registered the coverage flags and the urg text-report flow it would need later.

Running the Baseline

Prompt
Run the baseline regression with VCS coverage and report per-module scores
against the targets in NEX.md.

NEX delegates to its verification agent (agent_verification, flow="vcs"), which creates the VCS project from the filelist, compiles with -cm line+cond+fsm+tgl+branch, runs the simulation with coverage collection, generates the urg text report, and parses it.

The verification agent runs the whole VCS flow: project setup, coverage compile, simulation, and the urg report

The verdict:

Metric / Module Baseline Target Status
Total urg SCORE 58.69% >= 67% FAIL
can_bsp 59.49% >= 72% FAIL
can_acf 37.37% >= 55% FAIL
can_registers 49.77% >= 50% FAIL

Eight other modules already clear their 50% floor (can_crc at 99%, can_ibo at 100%; both are small, fully-exercised leaf modules). The failures are concentrated exactly where the regression's blind spots are.

Baseline scores versus targets: all four signoff metrics failing

A note on stderr

EDA tools print banners and warnings to stderr even on success: urg's Synopsys banner and a harmless Fsm shape not found warning (this design has no urg-recognizable FSMs) show up in NEX's dim "Diagnostics (stderr)" panel. The exit code, not stderr, is the truth.

A successful urg run: banner and warnings on stderr, exit code clean

Diagnosing the Holes

Prompt
Which modules are furthest from target and why? What test additions would
close the gap?

NEX pulls the per-module detail through vcs_parse_urg_report, one call per failing module, and maps unhit coverage bins to missing CAN features:

  • can_acf (37%): the acceptance code/mask registers are never toggled, and the extended-mode filter logic (single-filter and dual-filter compare paths) is completely unhit; the regression accepts every frame with a wildcard mask.
  • can_bsp (59%): the error-handling machinery is dark: stuff/form/ACK error detection, the error-frame state machine, the fault-confinement counters (error_passive at 128, bus_off at 256), and arbitration-loss tracking. The regression never makes anything go wrong on the bus.
  • can_registers (49.8%): the extended-mode (PeliCAN) register map, a whole second personality of the block, is never selected.

The diagnosis: unhit bins translated into missing CAN features, with the test plan to close each gap

This is the heart of coverage-driven verification: the numbers are only the symptom. The diagnosis translates them into design features the regression never exercises, and each one maps to a concrete stimulus.

Fixing and Verifying

Prompt
Apply the recommended fixes and re-run. Show me the before/after per-module table.

NEX reads the testbench, patches it (tool_patch_file), and re-runs the full flow through the verification agent. Its four additions:

  1. Register readback sweep: reads every configuration register in both basic and extended mode, covering the read-mux branches in can_registers.
  2. Acceptance filter tests: extended mode, single- and dual-filter configurations, with frames that match and frames that don't.
  3. Forced arbitration loss: both nodes transmit simultaneously (fork/join); node 1's dominant ID beats node 2's recessive ID, and node 2's arbitration-lost logic finally fires.
  4. NACK-induced bus-off: node 2 is held in reset so nobody ACKs; node 1 retries into escalating ACK errors, walking tx_err_cnt through the error-passive (128) and bus-off (256) thresholds. That is the entire CAN fault confinement loop.

NEX extends the testbench: the register readback sweep going in

The result:

Module Baseline After Target Status
Total urg SCORE 58.69% 72.81% >= 67% MET
can_bsp 59.49% 80.45% >= 72% MET
can_acf 37.37% 79.56% >= 55% MET
can_registers 49.77% 72.98% >= 50% MET

The signoff table: every metric from FAIL to MET

Every target met, and the regression is still self-checking: the new stimulus carries checks, not just activity.

What Did This Cost?

Ask for the accounting at the end of the run:

/session stats

Session stats for the full signoff

Prompts 4
Tool & agent calls 11 (all successful)
Wall time 17 min 25 s
Agents active 9 min 27 s
Input tokens 2.78 M (1.74 M served from cache)
Output tokens 21 K

Under ten minutes of agent-active time, most of it VCS compiling and simulating, the same work an engineer would wait on anyway; the rest of the wall clock is the engineer reading between prompts. What NEX compressed is the other part: reading urg reports, mapping unhit bins to design features, and writing protocol-correct stimulus for a two-node CAN bus.

Watching the Full Session

The following recording shows the entire signoff session from start to finish, with no edits or manual intervention.

Takeaways

  • A passing regression is not signoff. The baseline passed 6/6 checks and still left the acceptance filter 63% dark.
  • NEX.md is leverage. One prompt turned the signoff targets into persistent project rules that every later step consulted, including the plain-Verilog constraint that would otherwise cost a debugging round-trip.
  • The loop is repeatable. Signoff thresholds are project choices. If your requirements tighten, run the same diagnose-and-extend cycle again: each pass turns the next set of unhit bins into targeted stimulus, until the numbers meet your targets.