This document provides guidance for AI assistants working on the STG-Rust codebase.
STG (Structured Testbench Generation) is a Rust tool that automatically generates comprehensive testbenches for Verilog/SystemVerilog designs. It compares a Design Under Test (DUT) against a golden reference model.
- Parse Verilog/SystemVerilog modules and extract port information
- Classify signals into control vs. data, and inputs vs. outputs
- Generate semi-exhaustive test patterns with intelligent coverage
- Support multiple testbench modes: SystemVerilog, C++, and SystemC
- Compare DUT outputs against golden reference and report statistics
- Type Safety: Leverage Rust's type system to prevent entire classes of bugs
- Performance: Native binary with no runtime interpreter overhead
- Flexibility: Support multiple modes (SV, CC, SC) and design types
- Portability: Single binary that can be shipped anywhere
stg-rust/
├── src/
│ ├── main.rs # Entry point, CLI parsing
│ ├── lib.rs # Library exports
│ ├── cli.rs # CLI argument definitions (using clap)
│ ├── python_runtime.rs # Python environment management for LM features
│ ├── commands/ # Command implementations
│ │ ├── generate.rs # Main testbench generation logic
│ │ ├── generate_fsm.rs # FSM-based coverage-enhanced generation
│ │ ├── compile.rs # Testbench compilation
│ │ ├── identify.rs # Signal classification
│ │ └── parse.rs # Module parsing and priority sorting
│ └── tools/ # Core functionality modules
│ ├── verilog_parser.rs # Verilog parsing (sv-parser + iverilog)
│ ├── signal_classification.rs # Signal type identification
│ ├── generator.rs # Testbench template generation
│ ├── compiler.rs # iverilog/Verilator compilation
│ ├── emplace_verilog.rs # Module emplacement (SV mode)
│ ├── fsm_extractor.rs # FSM extraction for coverage
│ ├── fsm_analysis.rs # FSM analysis and DFS engine
│ └── file_utils.rs # File I/O utilities
├── examples/ # Test cases and examples
│ ├── ALU/ # Combinational logic example
│ ├── ALU_cc/ # C++ testbench example
│ ├── pingpong/ # Sequential clocked example
│ ├── seq_detector/ # FSM coverage example
│ └── traffic_light/ # Traffic light FSM example
├── tests/ # Rust integration tests
└── docs/ # Sphinx documentation
- Hybrid approach: Uses sv-parser for Rust-based parsing, falls back to iverilog for port information
- Module priority sorting: Analyzes instantiation hierarchy and submodule counts
- Port extraction: Identifies inputs, outputs, widths, and signal types
- Identifies control signals (opcodes, enables, modes) vs. data signals (values, addresses)
- Detects special signals: clock, reset, done/valid
- Uses heuristics: signal width, naming patterns, module context
- Generates testbench templates from Tera templating engine
- Three modes: SystemVerilog (SV), C++ (CC), SystemC (SC)
- Test pattern generation strategy:
- Control signals: Exhaustive enumeration (up to 2^26 combinations)
- Data signals: Random sampling (default: 1024 samples per control vector)
- iverilog: Traditional SystemVerilog compilation
- Verilator: High-performance C++ conversion with optional MPI support
- Coverage analysis support (generates .dat files)
- Multi-DUT support with unique prefixes (V0_, V1_, V2_...)
- Extract FSM state machines from Verilog (deterministic or LM-assisted)
- Generate state transition graphs
- DFS-based test generation for complete state coverage
- Hierarchical signal access for internal state monitoring
STG supports three fundamental design types:
- Pure combinational logic (no clock, no state)
- Test approach: Enumerate control signals, random data signals
- Examples: ALU, multiplexers, decoders
- Golden model: Implements
eval()function
- Clocked sequential design with continuous operation
- Requires clock and usually reset signals
- Test approach: Apply random control/data patterns over multiple clock cycles
- Examples: Counters, shift registers, timers
- Golden model: Implements
posedge_clk()function
- Sequential design with transaction-based operation
- Requires clock, reset, and done/valid signal
- Test approach: Start transaction, wait for done signal, check results
- Examples: GCD, dividers, state machines with completion signals
- Golden model: Implements
posedge_clk()and tracks completion
- Both DUT and golden are Verilog modules
- Uses iverilog or Verilator for compilation
- Single-stage workflow
- Good for: Simple designs, standard workflow
- DUT is Verilog, golden is C++ header file
- Two-stage workflow:
- Generate template with
--out-header golden_model.h - Implement golden model, then compile with
--golden golden_model.h
- Generate template with
- Uses Verilator for DUT compilation
- Good for: Complex golden models, custom logic, performance
- Similar to CC but uses SystemC types (
sc_uint<N>) - Two-stage workflow like CC
- Good for: SystemC ecosystem integration, bit-accurate types
STG can test multiple DUT implementations simultaneously against one golden reference.
- Compare multiple implementations in one run
- Individual statistics for each DUT in
test_stats.json - Automatic unique prefixes (V0_, V1_, V2_...)
- In SV mode: Use
--emplace-moduleto avoid module name conflicts - In CC/SC mode: Verilator handles renaming automatically
- Single name:
--module alu(used for all DUTs) - Comma-separated:
--module alu1,alu2,alu3 - Interleaved:
--verilog dut1.v --module alu1 --verilog dut2.v --module alu2
- Clock signals:
clk,clock - Reset signals:
rst,rst_n,reset,reset_n - Done/Valid signals:
done,valid,ready - Control signals: Usually narrow (1-4 bits), named like
op,mode,cmd - Data signals: Usually wider (8+ bits), named like
a,b,data,addr
- Error handling: Use
Result<T, String>for recoverable errors - File paths: Always use
PathBufand handle path operations carefully - Template rendering: Use Tera for all code generation
- External tools: Shell out to iverilog, verilator using
std::process::Command
- Examples in
examples/serve as integration tests - Each example has a README.md and Makefile
- Run
cargo testfor unit tests - Test examples with their Makefiles:
make -C examples/ALU
-
Update CLI (
cli.rs):#[arg(long, help = "Your new feature")] pub new_feature: bool,
-
Modify Generator (
tools/generator.rs):- Add template variables in the generation context
- Update Tera template rendering
-
Update Templates (embedded in code or separate files):
- Add new template sections
- Use Tera syntax:
{% if new_feature %}...{% endif %}
-
Test:
- Create example in
examples/new_feature/ - Add README.md and test files
- Run and verify output
- Create example in
-
Update Classification (
tools/signal_classification.rs):- Add detection logic in signal classification algorithm
- Update
SignalInfostruct if needed
-
Update Generator (
tools/generator.rs):- Add handling for new signal type in testbench templates
- Update test pattern generation
-
Update Documentation:
- Add to USAGE.md with examples
- Update CLI help text
- Enable debug output:
--debugflag - Check parser fallback: sv-parser fails gracefully, iverilog provides backup
- Verify module names: Use
stg parseto see what modules are detected - Check port extraction: Use
stg identifyto see classified signals
New feature for achieving higher coverage in sequential designs by extracting FSM structure.
Documentation: See docs/source/user_guide/fsm_coverage.md for the generate-fsm command guide.
- Uses language models (OpenAI, Gemini) to identify FSMs
- Python-based, managed through
python_runtime.rs - Environment setup with
uvpackage manager - API keys from
.envfile (e.g.,GOOGLE_API_KEY)
- Parser/AST-based approach using iverilog or sv-parser
- Extract state variables, state transitions
- More reliable but less flexible than LM approach
- Uses extracted state transition graph
- Performs depth-first search to cover all states
- Generates targeted input sequences
- Key advantage: Achieves states that random testing misses
- Verilator supports accessing internal signals:
dut->module->signal - Condition monitoring: Wait for internal states (e.g., counters reaching values)
- Enables state-aware testing beyond just input/output
examples/seq_detector/: Sequence detector FSMexamples/traffic_light/: Traffic light controller FSM- Compare coverage: traditional vs. FSM-enhanced
Problem: Multiple Verilog files with same module names cause compilation errors Solution:
- SV mode: Use
--emplace-moduleto add prefixes - CC/SC mode: Verilator handles automatically with unique prefixes
Problem: Important control signals classified as data (or vice versa)
Solution: Explicitly specify with --control-signals or --data-signals
Problem: Relative paths may break in different contexts
Solution: Convert to absolute paths early using std::fs::canonicalize()
Problem: Users forget two-stage workflow in CC/SC mode Solution: Clear error messages mentioning stage 1 and stage 2
Problem: Older Verilator versions may not support required features Solution: Recommend Verilator v5.020+ in documentation and error messages
Problem: MPI processes write to same coverage.dat file Solution: In CC/SC mode, use rank-specific filenames; SV mode doesn't support MPI coverage
Problem: Non-deterministic test results make debugging hard
Solution: Use fixed seed for reproducibility (consider adding --seed flag)
- Located in
tests/directory - Test individual components: parser, classifier, generator
- Run with
cargo test
- Examples serve as integration tests
- Each example has Makefile with test target
- Verify generated testbench compiles and runs without errors
- Keep
test_stats.jsonoutputs for examples - Compare statistics after changes to detect regressions
- Golden references should maintain 100% score
- FSM examples test coverage enhancement features
- Compare deterministic vs. LM-based vs. traditional coverage
- Look for state coverage gaps in
.datfiles
| File | Purpose | When to Modify |
|---|---|---|
cli.rs |
Command-line interface | Adding new flags/options |
commands/generate.rs |
Main testbench generation | Changing generation logic |
tools/verilog_parser.rs |
Verilog parsing | Parser improvements |
tools/signal_classification.rs |
Signal type detection | Classification algorithm changes |
tools/generator.rs |
Template generation | Testbench template updates |
tools/compiler.rs |
Compilation backend | Compiler flag changes |
tools/fsm_analysis.rs |
FSM coverage | DFS engine improvements |
python_runtime.rs |
Python environment | LM integration changes |
- iverilog: SystemVerilog simulation (v11+ recommended)
- Verilator: C++ conversion and high-performance simulation (v5.020+ required)
- Python: For LM-based FSM extraction (managed through
uv)
clap: CLI parsingserde: Serialization (YAML, JSON)tera: Template enginesv-parser: Verilog parsingregex: Pattern matching
- Run
cargo fmtto format code - Run
cargo clippyto check for warnings - Run
cargo testto verify unit tests - Test relevant examples:
make -C examples/ALU - Update USAGE.md if adding user-facing features
- Update AGENTS.md if adding significant architectural changes
- Create directory under
examples/ - Add DUT Verilog file(s)
- Add golden reference (Verilog or C++ header)
- Create README.md explaining the example
- Add Makefile with targets:
all,clean,test - Document command-line usage in example README
- Be specific: Include file names, line numbers, signal names
- Be helpful: Suggest fixes or next steps
- Be consistent: Follow existing error message patterns
- Example: "Module 'alu' not found in dut.v. Available modules: [add, sub]. Use --module to specify."
- Coverage analysis: Integrate Verilator coverage more deeply
- Smart test generation: ML-guided test pattern selection
- Assertion support: Generate SVA properties from golden model
- Waveform comparison: VCD-based debugging for mismatches
- Parallel DUT compilation: Speed up multi-DUT builds
- Interactive mode: REPL for exploring designs
- Automatic state variable identification
- Better LM prompt engineering for complex FSMs
- Support for hierarchical/nested FSMs
- Visualization of state transition graphs
- README.md: Quick start and installation
- docs/source/getting_started.md: Installation and quick start guide
- docs/source/user_guide/: Mode guides (SV, CC/SC), multi-DUT, FSM coverage, advanced features
- docs/source/reference/cli.md: Complete CLI reference for all commands
- docs/source/examples.md: Examples by design type
- docs/source/troubleshooting.md: Common issues and solutions
- examples/*/README.md: Specific example guides
- Read before modifying: Always read relevant source files before suggesting changes
- Test your changes: Verify with examples before claiming success
- Follow Rust conventions: Use
Result,Option, proper error handling - Preserve existing behavior: Don't break working examples
- Document decisions: Update this file when architecture changes
- Be explicit: Don't guess module names or file paths - verify them
- Check dependencies: Ensure external tools (iverilog, verilator) are available
- Understand modes: SV vs. CC/SC have different workflows and constraints
- Multi-DUT awareness: Many features must handle multiple DUTs correctly
- FSM features are new: The FSM coverage enhancement is actively being developed
# Build and install
cargo build --release
cargo install --path .
# Run tests
cargo test
make -C examples/ALU test
# Generate testbench (SV mode)
stg generate --verilog dut.v --golden golden.v --type combinational --out tb.sv
# Generate testbench (CC mode, two-stage)
stg generate --verilog dut.v --type combinational --out tb.cpp --out-header golden.h --cc
# ... implement golden.h ...
stg generate --verilog dut.v --golden golden.h --type combinational --out tb.cpp --out-exe tb_exe --cc
# Multi-DUT
stg generate --verilog dut1.v --verilog dut2.v --golden golden.h --type combinational --out tb.cpp --out-exe tb_exe --cc
# Parse and identify
stg parse --verilog design.v --out modules.yaml
stg identify --verilog design.v --module top --type seq_clocked --out signals.yaml
# FSM-enhanced coverage (future)
stg generate --verilog dut.v --golden golden.v --type seq_clocked --out tb.cpp --fsm-coverageLast updated: 2026-02-09 Maintained for AI assistants working on STG-Rust