Chapter 3 ran lint with every option left at its default, which is all this tutorial's design needs. The Lint tab has four more settings underneath that default view — this article covers what each one does and the situations where you'd actually reach for it.
7 min read | Beginner Level
What You'll Learn
- When to override Top Module, and what
--no-topis for - How Defines/Macros change what lint actually checks
- How to control strictness with Error Limit and Warnings as Errors
- When to reach for raw Verilator flags via Additional Args
Top Module & --no-top
Left blank, ChipVerify Lab auto-detects your design's top module the same way synthesis does — the one module nothing else instantiates. That's correct for a normal design like this series' shift register. You'd fill in Top Module by hand if your project has more than one plausible top and auto-detection picks the wrong one. You'd check --no-top instead if your project genuinely doesn't have a single top at all — for example, a folder of independent, unrelated modules you're linting together as a batch rather than a single connected design.
Defines / Macros
This field sets preprocessor defines — entering SIM=1, WIDTH=8, SYNTH passes -DSIM=1 -DWIDTH=8 -DSYNTH to Verilator, exactly like `define would in the source. It matters whenever your RTL uses `ifdef blocks to include or exclude code conditionally — simulation-only assertions guarded by `ifdef SIM, for instance. Leave a macro undefined here and lint checks whichever branch applies when it's not defined (the `else branch, or nothing at all) — so code inside an `ifdef SIM block is silently skipped by lint unless you actually define SIM in this field.
Strictness: Error Limit & Warnings as Errors
Error limit caps how many errors Verilator reports before it stops early — raise it on a large or unfamiliar file where the default cutoff stops you from seeing the full picture in one run. Warnings as errors does the opposite kind of job: it promotes specific warning categories (entered by name, like WIDTH, UNUSED) from advisory to blocking, so a run with one of those warnings fails outright instead of just printing a note. Teams use this to enforce a style rule nobody can accidentally ignore — leave it blank while you're still iterating on a design, and consider using it once you want a specific class of issue to be a hard gate.
Additional Args
Anything typed here is appended to the Verilator command verbatim, for cases the other fields don't cover. Two common uses: suppressing one specific, known-and-intentional warning with a flag like -Wno-EOFNEWLINE, or asking for a more thorough pass than the default with -Wall. This is an escape hatch for one-off cases — if you find yourself using the same flag on every run, it likely belongs in a more permanent project setting instead.
Common Mistakes
Mistake #1: Not checking --no-top when a project has no single top
Leaving Top Module blank on a project that's genuinely a batch of independent modules gets you a confusing auto-detect guess instead of a clean lint pass across all of them. Check --no-top for that case instead of fighting the auto-detection.
Mistake #2: Forgetting a define set for lint doesn't carry over to simulation
Defines/Macros only apply to the lint run you set them on. If you want the same `ifdef-guarded code checked in both lint and simulation, you need to set the matching define in each tool's own config — setting it once in the Lint tab doesn't affect Chapter 2's Simulate tab.
Mistake #3: Turning on Warnings as Errors before the design is clean
Promoting a warning category to a hard error on a design that still has that warning turns a routine lint pass into a blocking failure with no new information — clear the warnings first, then consider locking them down with Warnings as Errors so they can't silently come back.
Where Is This Used?
Promoting specific warning categories to hard errors is a common team-wide lint policy in real RTL projects — it turns "please don't do this" into something CI can actually enforce. Conditional compilation via `ifdef is equally common, most often for simulation-only assertions or debug logic that should never reach a synthesizable build.
Practice Exercise
Challenge: Make Lint See a Guarded Block
Add this to shift_register_4bit.v, anywhere inside the module:
`ifdef SIM
initial $display("Simulation build");
`endif
Run lint with Defines/Macros left blank, then run it again with SIM entered in that field. Compare whether anything about the run changes.
Hint
You're checking whether lint even looks at the code inside the `ifdef block in each case — not necessarily expecting a new warning.
Solution
With SIM undefined, lint doesn't process the $display line at all — as far as lint is concerned, that code doesn't exist. Once you add SIM to Defines/Macros, lint processes the block for real, which is how you'd catch an issue inside simulation-only code before it ever reaches simulation.
Summary
In this tutorial, you learned:
- When to override Top Module or use --no-top instead of relying on auto-detection
- How Defines/Macros determine which `ifdef`-guarded code lint actually checks
- How Error Limit and Warnings as Errors control how strict a lint run is
- When Additional Args is the right tool versus a more permanent setting