Parser Module API
The parsers module handles conversion of Verilog netlists and text formats to structured JSON data.
Module: verilog_parser.py
Parses gate-level Verilog netlists from synthesis tools (Cadence Genus, Synopsys Design Compiler).
Functions
parse(input_filename, output_filename)
Parse a Verilog netlist and convert to internal format.
Parameters:
input_filename(str): Name of input Verilog file indata/input/output_filename(str): Name of output parsed file indata/parsed/
Returns:
str: Full path of the generated parsed file
Raises:
FileNotFoundError: If input file doesn’t exist
Output Files: Creates both text and JSON formats:
<output_filename>- Text format with comments<output_filename>.json- JSON format with structured data
Example:
from opentestability.parsers.verilog_parser import parse
# Parse and create both .txt and .json
output_path = parse("serial_ALU.v", "serial_alu.txt")
# Creates:
# data/parsed/serial_alu.txt
# data/parsed/serial_alu.json
CLI Usage:
python3 -m opentestability.parsers.verilog_parser circuit.v
parse_verilog_netlist(file_path)
Parse Verilog netlist using pyverilog library.
Parameters:
file_path(str): Full path to the Verilog netlist file
Returns:
dict: Dictionary containing parsed module information
Structure:
{
"module_name": {
"pi": ["input1", "input2", "bus[7:0]"],
"po": ["output1", "result[3:0]"],
"wires": ["n1", "n2", "n3"],
"instances": [
("AND2X1", "gate1", {"A": "input1", "B": "input2", "Y": "n1"}),
("INVX1", "gate2", {"A": "n1", "Y": "output1"})
]
}
}
Example:
from opentestability.parsers.verilog_parser import parse_verilog_netlist
modules = parse_verilog_netlist("path/to/circuit.v")
for module_name, module_data in modules.items():
print(f"Module: {module_name}")
print(f" Inputs: {module_data['pi']}")
print(f" Outputs: {module_data['po']}")
print(f" Gates: {len(module_data['instances'])}")
format_port(port)
Format port with width information if available.
Parameters:
port(object): Port AST node from pyverilog
Returns:
str: Formatted port string (e.g.,"data[7:0]"or"clk")
Example:
# Internal usage during parsing
formatted = format_port(port_node)
# Returns: "data[7:0]" for buses, "clk" for single bits
get_argname_name(arg)
Extract argument name from AST node.
Parameters:
arg(object): Argument AST node from pyverilog
Returns:
str: Argument name, possibly with array indexing
Example:
# Internal usage during parsing
arg_name = get_argname_name(arg_node)
# Returns: "signal_name" or "bus[3]"
Supported Verilog Constructs
Module Definitions
module my_circuit(
input clk, reset,
input [3:0] data_in,
output [7:0] result,
output valid
);
Port Declarations
- Single-bit:
input clk - Multi-bit bus:
input [7:0] data - Bidirectional parsing (input/output/wire)
Standard Cell Instances
AND2X1 gate1(.A(in1), .B(in2), .Y(out1));
NAND3X1 gate2(.A(a), .B(b), .C(c), .Y(result));
DFFRX1 reg1(.D(d), .CK(clk), .Q(q), .QN(qn));
Wire Declarations
wire n1, n2, n3;
wire [7:0] bus_signal;
Output Port Detection
The parser recognizes standard output port names:
Z,ZN- Inverted/non-inverted outputsQ,QN- Flip-flop outputsY- General outputsS,CO- Sum and carry outputs (adders)
Configuration:
OUTPUT_PORT_NAMES = {'Z', 'ZN', 'Q', 'QN', 'Y', 'S', 'CO'}
Module: json_converter.py
Converts text-based parsed netlists to JSON format.
Functions
convert_txt_to_json(input_filename)
Convert a parsed text netlist to JSON format.
Parameters:
input_filename(str): Name of text file indata/parsed/(must end with.txt)
Returns:
str: Path to the generated JSON file
Raises:
ValueError: If input file doesn’t have.txtextensionFileNotFoundError: If file doesn’t exist
Example:
from opentestability.parsers.json_converter import convert_txt_to_json
json_path = convert_txt_to_json("circuit.txt")
# Creates: data/parsed/circuit.json
CLI Usage:
python3 -m opentestability.parsers.json_converter circuit.txt
parse_netlist_txt(txt_path)
Parse a text-based netlist file and extract components.
Parameters:
txt_path(Path): Path to the text netlist file
Returns:
dict: Dictionary containing parsed netlist data
Structure:
{
"primary_inputs": ["clk", "reset", "A[3:0]", "B[3:0]"],
"primary_outputs": ["result[3:0]", "zero", "carry"],
"gates": [
{
"type": "AND2X1",
"output": "n1",
"inputs": ["a", "b"]
},
{
"type": "INVX1",
"output": "z",
"inputs": ["n1"]
}
]
}
Example:
from opentestability.parsers.json_converter import parse_netlist_txt
from pathlib import Path
data = parse_netlist_txt(Path("data/parsed/circuit.txt"))
print(f"Found {len(data['gates'])} gates")
Text Format Specification
The text format uses a simple, human-readable structure:
# Primary Inputs
clk reset A[3:0] B[3:0] opcode[1:0]
# Primary Outputs
result[3:0] zero carry
# Complete Paths
AND2X1 out(n1) in(a b)
OR2X1 out(n2) in(n1 c)
INVX1 out(z) in(n2)
INPUT clk reset A[3:0] B[3:0] opcode[1:0]
OUTPUT result[3:0] zero carry
Format Rules:
- Lines starting with
#are comments (ignored) - Empty lines are ignored
INPUTlines define primary inputs (space-separated)OUTPUTlines define primary outputs (space-separated)- Gate lines follow format:
<TYPE> out(<output>) in(<input1> <input2> ...)
Integration Examples
Complete Parsing Workflow
from opentestability.parsers.verilog_parser import parse
from opentestability.parsers.json_converter import convert_txt_to_json
import json
# Method 1: Direct parse (creates both formats automatically)
parse("circuit.v", "circuit.txt")
# Method 2: Parse to text, then convert to JSON
# (if you have old text files without JSON)
json_path = convert_txt_to_json("old_circuit.txt")
# Load and use the JSON data
with open("data/parsed/circuit.json", 'r') as f:
netlist = json.load(f)
print(f"Circuit has {len(netlist['gates'])} gates")
print(f"Inputs: {netlist['primary_inputs']}")
print(f"Outputs: {netlist['primary_outputs']}")
Custom Parsing
from opentestability.parsers.verilog_parser import parse_verilog_netlist
# Parse with full control
modules = parse_verilog_netlist("/custom/path/circuit.v")
# Process specific module
module_name = "serial_alu"
if module_name in modules:
mod_data = modules[module_name]
# Extract gate types
gate_types = set(inst[0] for inst in mod_data['instances'])
print(f"Gate types used: {gate_types}")
# Count flip-flops
ff_count = sum(1 for inst in mod_data['instances']
if 'DFF' in inst[0])
print(f"Flip-flops: {ff_count}")
Batch Processing
from pathlib import Path
from opentestability.parsers.verilog_parser import parse
input_dir = Path("data/input")
verilog_files = input_dir.glob("*.v")
for vfile in verilog_files:
output_name = f"{vfile.stem}.txt"
try:
parse(vfile.name, output_name)
print(f"✓ Parsed {vfile.name}")
except Exception as e:
print(f"✗ Error parsing {vfile.name}: {e}")
Error Handling
Common Errors
FileNotFoundError:
try:
parse("nonexistent.v", "output.txt")
except FileNotFoundError as e:
print(f"File not found: {e}")
Syntax Errors in Verilog:
# pyverilog will raise ParseError for invalid Verilog
from pyverilog.vparser.parser import ParseError
try:
modules = parse_verilog_netlist("bad_syntax.v")
except ParseError as e:
print(f"Verilog syntax error: {e}")
Invalid Text Format:
try:
data = parse_netlist_txt(Path("malformed.txt"))
except Exception as e:
print(f"Parse error: {e}")
Performance Considerations
Large Netlists
For circuits with 10,000+ gates:
- Parsing time: ~1-5 seconds
- Memory usage: ~50-200 MB
- Output file size: ~1-10 MB (JSON)
Optimization Tips
- Use JSON format for repeated access (faster than reparsing Verilog)
- Parse once, analyze multiple times
- Consider batching for multiple files
# Good: Parse once, analyze many times
parse("large_circuit.v", "large_circuit.txt")
# Now use large_circuit.json for all subsequent analysis
# Not optimal: Reparsing for each analysis
# parse() → analyze() → parse() → analyze() ...
Dependencies
Required Packages
- pyverilog: Verilog AST parsing
pip install pyverilog
System Requirements
- Python 3.7+
- No additional system dependencies for parsing
Future Enhancements
Planned features:
- SystemVerilog support
- Hierarchical module parsing
- SPICE netlist support
- Custom cell library definitions
- Incremental parsing for large files