Official code implementation for the paper "SANGAM: SystemVerilog Assertion Generation via Monte Carlo Tree Self-Refine".
Recent advancements in the field of reasoning using Large Language Models (LLMs) have created new possibilities for more complex and automatic Hardware Assertion Generation techniques. This paper introduces SANGAM, a SystemVerilog Assertion Generation framework using LLM-guided Monte Carlo Tree Search for the automatic generation of SVAs from industry-level specifications. The proposed framework utilizes a three-stage approach:
- Stage 1 — Multimodal Specification Processing: Signal Mapper, SPEC Analyzer, and Waveform Analyzer LLM Agents parse the design specification PDF and extract per-signal information.
- Stage 2 — Monte Carlo Tree Self-Refine (MCTSr): An MCTS-based reasoning loop that iteratively generates, critiques, and refines SVA candidates for each signal, guided by formal verification feedback from JasperGold.
- Stage 3 — Assertion Combination & Post-Processing: MCTSr-generated reasoning traces are combined, syntax-corrected via JasperGold, and deduplicated to produce the final assertion set.
Our framework generates robust sets of SVAs, outperforming recent methods in evaluation.
- Architecture Overview
- Repository Structure
- Prerequisites
- Installation
- Configuration
- Preparing a Design
- Running the Pipeline
- Output Files
- Analysis
- Supported Designs
- Troubleshooting
┌──────────────────────────────────────────────────────────────┐
│ SANGAM Pipeline │
│ │
│ ┌──────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ Stage 1 │ │ Stage 2 │ │ Stage 3 │ │
│ │ Spec │──▶│ MCTSr Loop │──▶│ Combine & │ │
│ │ Processing │ │ (4 iters) │ │ Post-Process │ │
│ └──────────────┘ └───────┬────────┘ └────────────────┘ │
│ │ │ │ │
│ PDF → OCR text ┌─────▼──────┐ Final SVAs │
│ CSV signal info │ Per iter: │ per signal │
│ RAG book index │ Generate │ │
│ │ Critique │ │
│ │ JG Check │ │
│ │ Refine │ │
│ └────────────┘ │
│ │
│ LLM: DeepSeek-R1 (via Nebius AI Studio) │
│ Formal Verifier: Cadence JasperGold (remote via SSH) │
│ RAG: FAISS + OpenAI Embeddings │
└──────────────────────────────────────────────────────────────┘
Per-signal MCTSr loop (Stage 2):
- Generate Weak Answer — LLM produces initial SVA set
- Sample Reward — JasperGold verifies SVAs; LLM critic scores them (−100 to +100)
- Node Selection — UCB1 (C=1.4) selects the best node to expand
- Node Expansion — Critic provides feedback; generator refines SVAs using JG logs + RAG context
- Evaluation & Backpropagation — Updated rewards propagate up the tree
- Repeat for
max_iter=4iterations (early exit if all assertions pass JG)
SANGAM/
├── MAIN(i2c).ipynb # Main pipeline notebook for I2C Master design
├── MAIN(rv).ipynb # Main pipeline notebook for RV Timer design
├── Anaysis(i2c).ipynb # Post-run analysis for I2C results
├── Anaysis(rv).ipynb # Post-run analysis for RV Timer results
├── main.py # Standalone script version of the pipeline
├── config.py # Model name, system prompts, SV module templates
├── utils.py # PDF OCR, JasperGold SSH runner, assertion extraction
├── commands.txt # Git clone command
├── .env # API keys & SSH credentials (create from template below)
│
├── datasets/
│ ├── info/ # Per-design CSVs (signal names + spec excerpts)
│ │ ├── i2c.csv
│ │ ├── rv.csv
│ │ └── hpdmc.csv
│ ├── spec/ # Design specification PDFs
│ │ ├── i2c.pdf
│ │ ├── rv.pdf
│ │ └── hpdmc.pdf
│ └── rtl/ # RTL source files (Verilog) per design
│ ├── i2c/ # i2c_master_top.v, i2c_master_bit_ctrl.v, ...
│ ├── hpdmc/ # hpdmc.v, hpdmc_busif.v, ...
│ └── ... # 20 design directories total
│
├── books/ # Reference books for RAG
│ ├── faiss_index/ # Pre-built FAISS vector index
│ │ └── index.faiss
│ └── documents.pkl # Serialized document chunks
│
├── LLMOutput/ # Raw LLM outputs per signal per MCTS iteration
│ ├── i2c/
│ └── rv/
│
├── TempOutput/ # Intermediate CSVs during pipeline execution
│ ├── i2c/
│ └── rv/
│
├── FinalOutputs/ # Final assertion files per signal
│ ├── i2c/
│ │ ├── {signal}_Duplicates.txt # All syntax-valid assertions (pre-dedup)
│ │ └── {signal}_NoDuplicatesLLM.txt # Final deduplicated assertions
│ └── rv/
│
├── JasperGold_Logs/ # JasperGold verification logs
│ ├── i2c/
│ └── rv/
│
├── output/ # MCTS trace JSONs and result CSVs
│ └── json/
│
├── i2c/ # Per-signal output text files + analysis CSVs for I2C
│ ├── {signal}.txt
│ ├── i2cAnalysis.csv
│ └── i2cFinal.csv
│
└── rv/ # Per-signal output text files + analysis CSVs for RV
├── {signal}.txt
├── rvAnalysis.csv
└── rvFinal.csv
| Requirement | Details |
|---|---|
| Python | 3.9+ |
| Tesseract OCR | Required for PDF specification extraction. Install guide |
| JasperGold | Cadence JasperGold formal verification tool, accessible over SSH on a remote server |
| LLM API Access | Nebius AI Studio API keys (for DeepSeek-R1) |
| OpenAI API Key | Required for RAG embeddings (FAISS index building) and the optional combiner step |
| SSH Access | Credentials for a remote server with JasperGold + design TCL scripts set up |
-
Clone the repository:
git clone git@github.com:CoolSunflower/SANGAM.git cd SANGAM -
Create and activate a virtual environment (recommended):
python -m venv venv # Windows venv\Scripts\activate # Linux/Mac source venv/bin/activate
-
Install Python dependencies:
pip install numpy pandas openai python-dotenv retry paramiko PyMuPDF pytesseract Pillow langchain langchain-openai langchain-community faiss-cpu tabulate unstructured pickle5 ipykernel
-
Install Tesseract OCR:
- Windows: Download the installer from UB Mannheim and note the install path.
- Linux:
sudo apt install tesseract-ocr - macOS:
brew install tesseract
Update the Tesseract path in the notebook if needed:
pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
Create a .env file in the SANGAM/ directory:
# LLM API Keys (Nebius AI Studio - supports up to 24 keys for round-robin)
NEBIUS_API_KEY1=your_nebius_api_key_1
NEBIUS_API_KEY2=your_nebius_api_key_2
# ... add more keys if needed (NEBIUS_API_KEY3 through NEBIUS_API_KEY24)
# OpenAI API Key (used for RAG embeddings and combiner step)
API_KEY=your_openai_api_key
# JasperGold Remote Server SSH Credentials
HOST_NAME=your_jaspergold_server_hostname
USERNAME=your_ssh_username
PASSWORD=your_ssh_passwordNote: Multiple Nebius API keys enable round-robin rotation to avoid rate limits. At minimum, provide
NEBIUS_API_KEY1.
The pipeline SSH-es into a remote server to run JasperGold. You need to:
- Ensure the remote server has Cadence JasperGold installed and licensed.
- Place the RTL files and JasperGold TCL scripts on the remote server. The default root path is:
/storage/ckarfa/hpdmc/ - For each design, create a
.tclscript (e.g.,i2c.tcl,rv.tcl) that configures JasperGold to:- Load the RTL files
- Bind the SVA module
- Run formal property checking
- The SVA file is uploaded to
sva/{design_name}/{design_name}.svon the remote server.
To adapt for your server, modify the run_jg() function in utils.py:
- Update
ROOTto your remote directory path - Update the
JG_COMMANDshell commands (CAD tool sourcing, paths, etc.)
Edit config.py to change the LLM model:
MODEL_NAME = "deepseek-ai/DeepSeek-R1" # Default: DeepSeek-R1 via NebiusTo add a new design to the framework:
-
Add the specification PDF to
datasets/spec/{design_name}.pdf -
Add the RTL files to
datasets/rtl/{design_name}/ -
Create a signal CSV at
datasets/info/{design_name}.csvwith columns:Column Description spec_nameDesign name (e.g., i2c)signal_nameSignal name ( NAfor row 0, then one signal per row)informationRow 0: full architecture overview + signal mapping. Rows 1+: per-signal specification excerpt -
Add an SV template in
config.py— define the module wrapper with all signal ports and a{properties}placeholder:module {design}_sva ( input logic clk, // ... all signals ... ); {properties} endmodule
-
Set up JasperGold on the remote server with a corresponding
.tclscript and updaterun_jg()inutils.pywith the new design's paths and commands.
- Open
MAIN({design_name}).ipynbin Jupyter Notebook / VS Code. - Set
SPEC_NAMEin the first code cell:SPEC_NAME = 'i2c' # or 'rv', 'hpdmc'
- Run cells sequentially. The pipeline will:
- Extract text from the specification PDF via OCR
- Load the signal information CSV
- For each signal, run the full MCTSr pipeline (Stage 2)
- Combine traces and post-process (Stage 3)
- Save results to
FinalOutputs/{design_name}/
Execution time: Each signal takes ~15–30 minutes depending on LLM response times and JasperGold verification. A full design with 20+ signals can take several hours.
Please note some parts of main.py are not-updated to recent version, please use the notebook for proper output.
| Path | Description |
|---|---|
LLMOutput/{design}/ |
Raw LLM outputs: {spec}_{signal}_{iter}_{step}.txt where step ∈ {WeakAnswer, SampleReward, GetHints, GetBetterAnswer, EvaluateNewNode, ...} |
output/json/{spec}_{signal}.json |
Full MCTS tree trace (answers, rewards, UCB values, parent/child relationships) |
JasperGold_Logs/{design}/ |
Pickled JasperGold result dictionaries per signal |
TempOutput/{design}/ |
Intermediate CSVs saved during the pipeline run |
FinalOutputs/{design}/{signal}_Duplicates.txt |
All syntax-valid assertions before deduplication |
FinalOutputs/{design}/{signal}_NoDuplicatesLLM.txt |
Final deduplicated assertions for each signal |
{design}/{design}Final.csv |
Summary CSV with per-signal assertion outputs |
{design}/{design}Analysis.csv |
JasperGold verification results summary |
After running the pipeline, use the analysis notebooks to evaluate results:
- Open
Anaysis({design_name}).ipynb - It reads the final output files, runs each assertion through JasperGold, and classifies them:
- Complete Correct — passes JG with no counterexamples
- Syntax Correct, Semantics Wrong — valid SVA syntax but JG finds a counterexample
- Syntax Wrong — JG reports syntax/compilation errors
- Results are saved to
{design}/{design}Analysis.csv
| Design | Spec PDF | Signals | Description |
|---|---|---|---|
| i2c | i2c.pdf |
23 | I2C Master Core (Wishbone bus interface) |
| rv | rv.pdf |
10 | RISC-V Timer Module |
| hpdmc | hpdmc.pdf |
~25 | High Performance DDR SDRAM Memory Controller |
RTL for 20 additional designs is included in datasets/rtl/ (AES, Ethernet MAC, SHA3, UART, etc.) but CSV/spec preparation is required before running.
| Issue | Solution |
|---|---|
TesseractNotFoundError |
Install Tesseract OCR and set the correct path in the notebook |
Connection refused (SSH) |
Verify HOST_NAME, USERNAME, PASSWORD in .env; check server firewall |
API key exhausted / rate limit |
Add more Nebius API keys to .env (up to NEBIUS_API_KEY24) |
| JasperGold timeout or stall | Check the remote server's JG license and TCL script paths |
No assertions found |
Verify the signal CSV has correct information content for the signal |
| FAISS index missing | Run the RAG setup cells in the notebook to rebuild from books in books/ |
If you use this code in your research, please cite:
@inproceedings{gupta2025sangam,
title={SANGAM: SystemVerilog Assertion Generation via Monte Carlo Tree Self-Refine},
author={Gupta, Adarsh and Mali, Bhabesh and Karfa, Chandan},
booktitle={2025 IEEE International Conference on LLM-Aided Design (ICLAD)},
year={2025},
month={June},
doi={10.1109/ICLAD65226.2025.00024}
}