<!-- DESCRIPTION: Verilator: Repository-wide guidelines for AI coding agents
     SPDX-FileCopyrightText: 2026-2026 Wilson Snyder
     SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -->

# 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](src/AGENTS.md) -- compiler C++ sources: AST, visitors, passes, parser, style
- [include/AGENTS.md](include/AGENTS.md) -- runtime library (`verilated*`): C++14, MT-safety, fixed-width types
- [test_regress/AGENTS.md](test_regress/AGENTS.md) -- regression tests: harness, drivers, golden files
- [docs/AGENTS.md](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-ccwarn` so 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`, and `make 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.
- [ ] Did not edit `docs/CONTRIBUTORS` (humans only) or `Changes` (maintainer
  updates it near release).

## 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`/`v3warn` needs a test in `test_regress/t/` -- enforced by the
  warn-coverage distribution test. `v3fatalSrc` is 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. Update `docs/guide/warnings.rst`
  when 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-timing` builds must work);
  C++20 only in timing code paths.
- [ ] In `include/` public headers, prefix public classes with `Verilated`/`Vl`
  and 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.
