7.4 KiB
Verilator Guidelines for AI Coding Agents
These files are the general layer an agent loads first -- nearest file wins, so
you read this repository-root file plus the one for the directory you are
editing. They stay deliberately high-level: where to start, how the tree is laid
out, and the conventions reviewers otherwise enforce by hand. They are an index,
not the architecture reference -- for depth (how a pass works internally, the
algorithms, node lifetime) they point you to docs/internals.rst. When the
guidance here is not enough, that is where to look next.
This file has two parts. Orientation gets you productive in the codebase from a cold start. Before you open a PR is the checklist of conventions reviewers otherwise have to enforce by hand -- read it before submitting any change.
Then read the directory guide for the area you are editing:
- src/AGENTS.md -- compiler C++ sources: AST, visitors, passes, parser, style
- include/AGENTS.md -- runtime library (
verilated*): C++14, MT-safety, fixed-width types - test_regress/AGENTS.md -- regression tests: harness, drivers, golden files
- docs/AGENTS.md -- documentation (
*.rst)
Orientation
What Verilator is
Verilator is a compiler, not an interpreter. It translates synthesizable (and much behavioral) SystemVerilog into a cycle-accurate C++ model that you then compile and run. Almost every decision is made at compile ("verilation") time; the generated C++ just advances state each evaluation. Optimize for verilation- time work over runtime work.
The pipeline is the spine
A run is an ordered sequence of passes over one shared AST (abstract syntax tree). In source order:
| Stage | What it does | Key files |
|---|---|---|
| Preprocess + parse | Lex and parse text into a raw AST -- builds nodes only, no semantic checks | verilog.l, verilog.y |
| Link / elaborate | Resolve names, scopes, parameters; instantiate the hierarchy | V3LinkParse, V3LinkDot, V3Param |
| Width / type | Assign and check data types and bit widths | V3Width |
| Transform / optimize / schedule | Constant fold, lower language features, schedule events | V3Const, V3Randomize, V3Assert*, V3Sched, V3Timing, V3Dfg |
| Emit | Lower the final AST to generated C++ | V3EmitC* |
| Runtime | Library the generated model links against | include/verilated* |
This table is the map; docs/internals.rst has the detail behind each stage.
Where to make a change
Map the symptom to the pass that owns it, then start by reading that pass's top-of-file comment.
| Symptom or feature area | Start in |
|---|---|
| Type/width error, "what type is this", implicit conversion | V3Width |
| Name/scope/parameter resolution ("Can't find...", hierarchy) | V3LinkDot, V3Param |
randomize / constraint / rand / randc |
V3Randomize |
assert / property / sequence / cover |
V3Assert, V3AssertPre, V3AssertNfa |
fork / timing / #delay / NBA / event scheduling |
V3Sched, V3Timing, V3Fork |
| Syntax wrongly accepted or rejected | verilog.y, verilog.l |
| Wrong generated C++ | V3EmitC* |
| Runtime model behavior | include/verilated* |
Build and run a test
- Build in the source tree:
autoconf && ./configure && make -j8. Configure with--enable-ccwarnso a new compiler warning stops the build. - Run one test from the repository root:
test_regress/t/t_<name>.py. - Run the full regression with
make test. The complete suite requires configuring with--enable-longtests(works on every OS, including macOS).
Before you open a PR
Scope and process
- Searched open PRs and issues -- duplicating in-flight work wastes review time.
- Fixed the general root cause, not just the reported case -- if it also affects other modules/classes/interfaces, cover them or expect rejection.
- PR is single-purpose. Refactors, drive-by fixes found along the way, and new features each go in separate PRs; land standalone cleanups first.
- Every bug fix has a test that fails without the fix; include the issue's own reproducer when possible.
- New code aims for 100% line coverage; branch coverage far below line coverage signals guards callers never violate -- justify or remove them.
- Ran
make format(clang-format),make cppcheck, andmake lint-py; self-reviewed the diff for leftover debug code, stale comments, and copy-paste errors. - Ran the full regression on at least one OS before submitting. Partial runs are fine during development, but the submitted PR is expected to pass every test.
- Validated the code changes against recommendations in the AGENTS.md files.
- Did not edit
docs/CONTRIBUTORS(humans only) orChanges(maintainer updates it near release).
Drafting a PR
- When creating a pull request message, omit itemized lists of changed files and changes, since reviewers already have access to the diff.
Pick the right diagnostic (and its required test)
The API you choose determines which test must accompany the change.
| API | Output | Meaning | Required test |
|---|---|---|---|
v3error("...") |
%Error: |
User wrote invalid SystemVerilog | t_*_bad*.v + .out golden |
v3error("Unsupported: ...") |
%Error-UNSUPPORTED: |
Legal SV that Verilator does not yet support | t_*_unsup*.v + .out golden |
v3warn(CODE, "...") |
%Warning-CODE: |
Legal but suspicious code | warning test + .out golden |
v3fatalSrc("...") |
%Error: Internal Error |
Should-never-happen internal assertion | none -- not user-triggerable |
- Every
v3error/v3warnneeds a test intest_regress/t/-- enforced by the warn-coverage distribution test.v3fatalSrcis exempt. - Reserve "Unsupported:" for not-yet-implemented features, never for user mistakes.
- When an error enforces a spec-defined restriction, cite the clause
(
IEEE 1800-2023 11.4.7) so it is verifiable. Updatedocs/guide/warnings.rstwhen adding or changing a warning. - On error paths, clean up or replace invalid AST (e.g.
AstConst::BitFalse) so later passes do not crash after the error.
Cross-cutting code rules
- No non-ASCII characters in C++ sources or headers: write
--(two ASCII hyphens) rather than a Unicode em-dash, and a plain'rather than a smart quote. At write time, not when CI complains. - Lists stay sorted: lexer/parser tokens, option declarations, enum values, configure feature lists, documented option lists.
bin/scripts are Python (distributed cross-platform);nodist/may use bash and platform-specific code (developer-only, not packaged).- Runtime code in
include/targets C++14 (--no-timingbuilds must work); C++20 only in timing code paths. - In
include/public headers, prefix public classes withVerilated/Vland document the API with///comments. - A new code pattern is applied globally or not at all -- no one-off convention in a single file.
Commits
- Subject line is short and imperative and conventionally ends with the PR number:
Support property case (#7721). A body is optional and common for non-trivial changes.