원클릭으로
nc-api
The API of Netlist Carpentry with all relevant classes, properties, functions and methods.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
The API of Netlist Carpentry with all relevant classes, properties, functions and methods.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| name | nc-api |
| description | The API of Netlist Carpentry with all relevant classes, properties, functions and methods. |
| # | Section | Description |
|---|---|---|
| 1 | Loading & Writing Circuits | ReadConfig, read(), read_json(), write(), generate_json() |
| 2 | Circuit | Root container — all modules, top-level, navigation |
| 3 | Module | Design unit — instances, ports, wires, connections |
| 4 | Instance | Gate or submodule instantiation |
| 5 | Port | Module or instance I/O |
| 6 | Wire | Internal net connection |
| 7 | PortSegment / WireSegment | Per-bit elements |
| 8 | Element Paths | Hierarchical navigation types |
| 9 | ModuleGraph | NetworkX integration |
| 10 | Pattern Matching | Pattern, Match, Constraint |
| 11 | VCD Waveform Processing | VCDWaveform, VCDScope, VCDVar, parsing functions |
| 12 | Signal Model | Signal enum, SignalArray |
| 13 | Direction Enum | Port directions |
| 14 | EType Enum | Element type classification |
| 15 | Configuration | CFG global settings |
| 16 | Built-in Routines | Optimization, checking |
| 17 | Gate Library | Primitive gates, mixins, parameters |
| 18 | Equivalence Checking | run_eqy, run_equiv, run_equiv_miter |
| 19 | Base Classes | NetlistElement — base for all elements |
| 20 | Custom Collections | CustomDict, CustomList |
| 21 | Metadata Types | METADATA_DICT, NESTED_DICT |
| 22 | Type Aliases & Protocols | Signal types, gate protocols |
| 23 | Constants & Utilities | Wire constants, exports, logging |
ReadConfig — Yosys Read ConfigurationA Pydantic model that configures the entire Yosys synthesis flow for reading RTL into a Circuit. It generates the Yosys script from its properties.
Constructor Fields:
| Field | Type | Default | Description |
|---|---|---|---|
files | List[Path] | (required) | Input RTL files (Verilog .v, SystemVerilog .sv, JSON .json, VHDL .vhd/.vhdl). May also be directories (recursively scanned). |
output | Optional[Path] | None | Output file path for the final netlist. Suffix determines format: .v → Verilog, .sv → SystemVerilog, .json → JSON. If None, no output file is written (but json_path still applies). |
top | Optional[str] | None | Top module name. If None, auto-selected via hierarchy -auto-top (unless no_hierarchy=True). |
json_path | Optional[Path] | None | Path to save the intermediate JSON netlist. If None, stored in a temp directory and deleted after reading. |
techmaps | Optional[List[Path]] | None | Techmap files (.v or .json) to apply for gate-level mapping. Applied in order. |
share | Literal['off', 'fast', 'aggressive'] | 'off' | Resource sharing strategy. 'off' = disabled, 'fast' = quick sharing, 'aggressive' = thorough sharing (may hurt timing). |
environments | Optional[List[Path]] | None | Shell environment files to source before Yosys runs (e.g., source /opt/cad/sourceme.sh). On Windows uses . instead of source. |
yosys_plugins | Optional[List[str]] | None | Yosys plugin module names to load via -m. Common: ["ghdl"] for VHDL, ["slang"] for improved SystemVerilog parsing. |
no_hierarchy | bool | False | Skip the hierarchy pass entirely. Only relevant when top=None. |
keep_memory_cells | bool | False | If True, Yosys emits mem_v2 cells for inferred memories. If False, memories are mapped to FFs + MUX trees via memory pass. |
insbuf | bool | True | Insert buffer cells for directly connected wires via insbuf; proc pass. |
Computed Properties (generate Yosys commands):
| Property | Yosys Command(s) Generated |
|---|---|
read_pass | read_verilog [-sv] file.v / read_json file.json / ghdl -read file.vhd (auto-selected by file extension; uses read_slang if slang plugin loaded) |
hierarchy_pass | hierarchy -top <name> or hierarchy -auto-top or empty |
memory_pass | memory or memory -nomap |
techmap_pass | techmap -map <path> for each techmap file |
share_pass | share -fast / share -aggressive or empty |
insbuf_pass | insbuf; proc or empty |
write_pass | write_verilog [-sv] out.v / write_json out.json (plus intermediate write_json if json_path set) |
environment_activation | source <path> or . (Windows) for each environment file |
yosys_plugin_str | -m ghdl -m slang etc. |
Yosys Script Template (generated by yosys_commands()):
{read_pass}
{hierarchy_pass}
proc; opt
{memory_pass}
{techmap_pass}
{share_pass}
opt; clean
{insbuf_pass}
{write_pass}
Methods:
yosys_commands() -> strFormats the Yosys script template with all computed properties. Returns the complete Yosys -p argument string.
shell_script(path: Path | None = None) -> List[str]Generates a shell command list (or writes to file if path given).
['bash', '-c', 'set -e\nsource ...\nyosys -m ... -p "...script..."']['powershell.exe', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', script]yosys_executable -> strReturns CFG.yosys_executable (default: 'yosys', fallback: 'yowasp-yosys').
Usage:
from netlist_carpentry import ReadConfig
cfg = ReadConfig(
files=[Path("design.v")],
top="my_design",
json_path=Path("out.json"),
techmaps=None,
share='off', # 'off' | 'fast' | 'aggressive'
environments=None,
yosys_plugins=None, # e.g., ["ghdl", "slang"]
no_hierarchy=False,
keep_memory_cells=False,
insbuf=True,
)
# Inspect generated Yosys commands
print(cfg.yosys_commands())
# Generate shell script
cmd = cfg.shell_script() # Returns ['bash', '-c', '...']
read() — Load from Verilog/VHDL/JSONfrom netlist_carpentry import read
circuit = read("design.v") # Load single file
circuit = read(["design.v", "sub.v"]) # Load multiple files
circuit = read(ReadConfig(files=["design.v"], top="my_top")) # With config
Parameters:
cfg_or_files (ReadConfig | str | Path | List[str | Path]): Either a ReadConfig object or file path(s).top (str, optional): Top module name (only when cfg_or_files is not a ReadConfig).circuit_name (str, optional): Name for the resulting circuit.verbose (bool): Print Yosys output.out (str | Path, optional): Directory for generated JSON file. Defaults to temp dir.source_paths (List[str], optional): Environment files to source before Yosys.no_hierarchy (bool): Skip hierarchy pass.Returns: Circuit — fully parsed circuit object.
read_json() — Load from JSON netlistfrom netlist_carpentry import read_json
circuit = read_json("netlist.json")
Parameters:
json_path (str | Path): Path to the JSON file.circuit_name (str, optional): Name for the resulting circuit.Returns: Circuit
read_via_cfg() — Load with ReadConfigfrom netlist_carpentry import read_via_cfg, ReadConfig
cfg = ReadConfig(files=["design.v"], top="my_top", json_path=Path("out.json"))
circuit = read_via_cfg(cfg)
Parameters:
cfg (ReadConfig): Configuration for Yosys-based reading.circuit_name (str, optional): Name for the resulting circuit.verbose (bool): Print Yosys output.Returns: Circuit
write() — Export to Verilogfrom netlist_carpentry import write
write(circuit, "output.v", overwrite=True)
Parameters:
circuit (Circuit): The circuit to export.output_file_path (str | Path): Destination file path.overwrite (bool): Overwrite if exists.generate_json() — Generate JSON via Yosysfrom netlist_carpentry import generate_json
result = generate_json(["design.v"]) # Returns CompletedProcess
result = generate_json(ReadConfig(files=["design.v"])) # With config
Parameters:
cfg_or_files (List[Path] | ReadConfig): Input files or config.yosys_script_path (Path, optional): Custom Yosys script path.verbose (bool): Print Yosys output.overwrite (bool): Overwrite existing JSON.Returns: subprocess.CompletedProcess[str] — Yosys execution result.
generate_json_netlist() — Generate JSON Netlist ⚠️ DEPRECATEDfrom netlist_carpentry import generate_json_netlist
result = generate_json_netlist("design.v", Path("out.json"), top="my_top")
⚠️ Deprecated: This function is deprecated and will be removed in v1.0.0. Use
generate_json()with aReadConfigobject instead.
Parameters:
input_file_path (str | Path): Path to the input Verilog file.output_file_path (str | Path): Path where the output JSON netlist should be saved.top_module_name (str, optional): The name of the top module. Defaults to ''.verbose (bool, optional): Whether to print Yosys log. Defaults to False.yosys_script_path (str | Path, optional): Path to a custom Yosys script. Defaults to ''.no_hierarchy (bool, optional): Skip the hierarchy pass. Defaults to False.Returns: subprocess.CompletedProcess[str] — Yosys execution result.
Replacement:
from netlist_carpentry import generate_json, ReadConfig
cfg = ReadConfig(files=["design.v"], output=Path("out.json"), top="my_top")
result = generate_json(cfg)
The root container holding all modules and the top-level module.
| Property | Type | Description |
|---|---|---|
name | str | Circuit name |
modules | CustomDict[str, Module] | All modules by name |
module_count | NonNegativeInt | Number of modules |
top_name | str | Name of top-level module |
top | Module | Top-level module (raises if no top) |
has_top | bool | True if top module is set |
creator | str | Circuit creator name |
instances | DefaultDict[str, List[InstancePath]] | All instances by type across circuit |
__getitem__(key: str) -> ModuleGet a module by name.
module = circuit["my_module"]
__contains__(key: str | Module) -> boolCheck if module exists.
if "my_module" in circuit:
...
__len__() -> intNumber of modules.
__iter__() -> Iterator[Module]Iterate over all modules.
first -> ModuleGet the first module (raises IndexError if empty).
add_module(module: Module, fetch_existing: bool = False) -> ModuleAdd a module to the circuit.
new_mod = circuit.add_module(Module(name="new"))
remove_module(module: str | Module) -> NoneRemove a module from the circuit.
circuit.remove_module("unused_module")
create_module(name: str) -> ModuleCreate and add a new module.
mod = circuit.create_module("my_new_module")
copy_module(old_module: str | Module, new_name: str) -> ModuleDuplicate a module with a new name.
copied = circuit.copy_module("original", "original_copy")
get_module(module_name: str) -> Optional[Module]Get a module by name, returns None if not found.
get_module_at_idx(index: NonNegativeInt) -> Optional[Module]Get module by dictionary index order.
set_top(module: str | Module | None) -> NoneSet the top-level module. Pass None to clear.
circuit.set_top("my_design")
add_from_circuit(other_circuit: str | Circuit) -> Dict[str, Module]Import all modules from another circuit or file path.
imported = circuit.add_from_circuit("other_design.v")
get_from_path(path: str | ElementPath) -> NetlistElementResolve a hierarchical path to a circuit element. See Element Paths for full type resolution details.
get_path_from_str(path_str: str, sep: str = '.') -> ElementPathConvert a path string to the appropriate ElementPath type. See Element Paths for auto-detection details.
sync_instances() -> NoneRebuild the instances dictionary from all modules. O(N*M) complexity.
update_instance(instance: Instance | InstancePath, old_type: str | None = None) -> NoneUpdate the circuit's instance registry for a single instance.
uniquify(module: str | Module | None = None, keep_original_module: bool = False) -> Dict[InstancePath, str]Create unique copies of each module instance.
mapping = circuit.uniquify("shared_module")
# Returns {InstancePath: "shared_module_0", ...}
flatten(skip_modules: List[str] | None = None) -> NoneFlatten all submodule instances into their parent modules.
circuit.flatten(skip_modules=["blackbox"])
create_blackbox_modules() -> NoneCreate empty module definitions for all blackbox cells.
set_signal(path: str, signal_value: LogicLevel | Signal) -> NoneSet signal on a port/wire/segment by path string.
circuit.set_signal("top.clk", Signal.HIGH)
circuit.set_signal("top.data_in.0", '0')
optimize() -> boolOptimize all modules and remove unused ones. Returns True if changes were made.
check() -> CheckReportValidate the circuit. Returns a report with issues (combinational loops, fanout).
evaluate() -> NoneEvaluate signals across the entire circuit hierarchy (top-down).
write(output_file_path: str | Path, overwrite: bool = False) -> NoneWrite circuit to Verilog file.
prove_equivalence(gold_design: List[str] | Circuit, out_dir: str | Path, eqy_script_path: str | Path = '', gold_top_module: str = '', quiet: bool = False) -> subprocess.Popen[str]Formal equivalence check against a gold design using Yosys EQY.
result = circuit.prove_equivalence(gold_design, out_dir=Path("eqy_out"))
export_metadata(path: str | Path, include_empty: bool = False, sort_by: Literal['path', 'category'] = 'path', filter: Callable[[str, NESTED_DICT], bool] = ...) -> NoneExport all metadata to a JSON file.
A single design unit containing instances, ports, and wires.
| Property | Type | Description |
|---|---|---|
name | str | Module name |
instances | CustomDict[str, Instance] | All instances by name |
ports | CustomDict[str, Port[Module]] | All ports by name |
wires | CustomDict[str, Wire] | All internal wires |
parameters | Parameters | Module parameters |
metadata | MetadataMixin | User/Yosys metadata |
submodules | List[Instance] | Submodule instances |
primitives | List[Instance] | Primitive gate instances |
instances_by_types | DefaultDict[str, List[Instance]] | Instances grouped by type |
locked | bool | Structural immutability flag |
has_circuit | bool | Whether attached to a Circuit |
circuit | Circuit | Parent circuit |
path | ModulePath | Hierarchical path |
raw_path | str | Raw path string |
create_instance(interface_definition: Module | Type[Instance], name: str | None = None, params: Dict[str, object] | Parameters | None = None) -> InstanceCreate a submodule or primitive gate instance.
from netlist_carpentry.utils.gate_lib import AndGate
# Submodule instance
sub = module.create_instance(circuit["sub_module"], "u_sub")
# Primitive gate
and_gate = module.create_instance(AndGate, "u_and")
add_instance(instance: Instance) -> InstanceAdd an existing instance to the module.
remove_instance(instance: str | Instance) -> NoneRemove an instance and its connections.
copy_instance(instance: str | Instance, new_name: str, keep_inputs: bool = False) -> InstanceCopy an instance within the module.
refine_instance(old_instance: str | Instance, new_type_definition: Module | Type[Instance]) -> NoneReplace an instance with a different type, preserving connections.
module.refine_instance("u_old", AndGate)
substitute_instance(old_instance: str | Instance, new_instance: Instance) -> NoneReplace an instance with a pre-built instance object.
create_port(name: str, direction: str | Direction = Direction.UNKNOWN, width: PositiveInt = 1, offset: NonNegativeInt = 0, is_locked: bool = False) -> Port[Module]Create a new port.
clk_port = module.create_port("clk", Direction.IN, width=1)
data_port = module.create_port("data_in", Direction.IN, width=8)
add_port(port: Port[Module]) -> Port[Module]Add an existing port.
remove_port(port: str | Port[Module]) -> NoneRemove a port and its connections.
get_port(name: str) -> Port[Module] | NoneGet a port by name (returns None if not found).
get_ports(name: str | None = None, direction: Direction | None = None, fuzzy: bool = False) -> List[Port[Module]]Search for ports by name or direction.
inputs = module.get_ports(direction=Direction.IN)
all_ports = module.get_ports(name="data", fuzzy=True)
create_wire(name: str | None = None, width: PositiveInt = 1, is_locked: bool = False, offset: NonNegativeInt = 0) -> WireCreate a new wire. If name is None, generates _ncgen_{i}_.
bus = module.create_wire("data_bus", width=16)
auto_wire = module.create_wire() # Name: "_ncgen_0_"
add_wire(wire: Wire) -> WireAdd an existing wire.
remove_wire(wire: str | Wire) -> NoneRemove a wire and disconnect its port segments.
get_wire(name: str) -> Wire | NoneGet a wire by name.
get_wires(name: str | None = None, fuzzy: bool = False) -> List[Wire]Search for wires by name.
name_occupied(name: str) -> boolCheck if a name is already used by any instance, port, or wire.
connect(source: ANY_SIGNAL_SOURCE, target: ANY_SIGNAL_TARGET, new_wire_name: str | None = None) -> NoneConnect source to target. Auto-creates wires if needed.
# Connect wire segment to port segment
module.connect(wire[0], port[1])
# Connect two ports (auto-creates wire)
module.connect(port_a, port_b)
# Using path strings
module.connect("top.wire.0", "top.inst.port.1")
disconnect(port_like: PortSegmentPath | PortPath | PortSegment | Port) -> NoneDisconnect a port segment from its wire.
reconnect(source: PortPath | Port, target: PortPath | Port) -> NoneMove all wire connections from source port to target port.
get_edges(instance: str | Instance) -> Dict[str, Dict[int, WireSegment]]Get all connections for an instance.
get_outgoing_edges(instance_name: str) -> Dict[str, Dict[int, WireSegment]]Get only output port connections.
get_incoming_edges(instance_name: str) -> Dict[str, Dict[int, WireSegment]]Get only input port connections.
get_wire_ports(ws_path: WireSegmentPath) -> List[PortSegment]Get all port segments connected to a wire segment.
get_neighbors(instance_name: str) -> Dict[str, Dict[int, List[PortSegment]]]Get neighboring port segments of an instance.
get_succeeding_instances(instance_name: str) -> Dict[str, Dict[int, List[Instance | Port[Module]]]]Get instances connected to output ports.
get_preceeding_instances(instance_name: str) -> Dict[str, Dict[int, List[Instance | Port[Module]]]]Get instances connected to input ports.
split(instance: str | Instance) -> Dict[NonNegativeInt, Instance]Split an n-bit instance into n 1-bit instances.
split_all(type: str = '', fuzzy: bool = True, recursive: bool = False) -> intSplit all matching instances. Returns count of split instances.
count = module.split_all("§and", fuzzy=True)
make_chain(instances: List[Instance], input_port: str, output_port: str) -> Tuple[Port[Instance], Port[Instance]]Chain instances together. Returns the unconnected ends.
flatten(skip_name: List[str] | None = None, skip_type: List[str] | None = None, recursive: bool = False) -> NoneFlatten submodule instances into this module.
flatten_instance(instance: str | Instance) -> NoneFlatten a single instance (non-recursive).
get_instances(name: str | None = None, type: str | None = None, fuzzy: bool = False, recursive: bool = False) -> List[Instance]Search for instances by name or type.
and_gates = module.get_instances(type="§and")
all_dffs = module.get_instances(type="dff", fuzzy=True, recursive=True)
graph() -> ModuleGraphGet the NetworkX MultiDiGraph for this module. Must call as method.
G = module.graph()
import networkx as nx
paths = nx.all_simple_paths(G, "input_port", "output_port")
optimize() -> boolRun constant propagation, remove driverless/loadless elements.
check() -> CheckReportCheck for combinational loops and fanout issues.
show(interactive: bool = False, figpath: str | None = None, **fwd_params) -> Dash | NoneVisualize the module graph. Interactive mode returns a Dash app.
normalize_metadata(include_empty: bool = False, sort_by: Literal['path', 'category'] = 'path', filter: Callable[[str, NESTED_DICT], bool] = ...) -> METADATA_DICTNormalize metadata from all elements in the module.
export_metadata(path: str | Path, include_empty: bool = False, sort_by: Literal['path', 'category'] = 'path', filter: Callable[[str, NESTED_DICT], bool] = ...) -> NoneExport metadata to JSON.
update_module_instances() -> NoneUpdate all instance interfaces in the circuit when this module's ports change.
pre_py2v_hook() / post_py2v_hook()Hooks called before/after Verilog export.
A gate or submodule instantiation within a module.
| Property | Type | Description |
|---|---|---|
name | str | Instance name |
instance_type | str | Module name or primitive type (e.g., "§and") |
ports | CustomDict[str, Port[Instance]] | All ports |
parameters | InstanceParams | Instance parameters |
connections | Dict[str, Dict[int, WireSegmentPath]] | Port → wire mappings |
connection_str_paths | Dict[str, Dict[int, str]] | Connections as string paths |
input_ports | Tuple[Port[Instance], ...] | Input ports only |
output_ports | Tuple[Port[Instance], ...] | Output ports only |
module | Module | Parent module |
module_definition | `Module | None` |
path | InstancePath | Hierarchical path |
raw_path | str | Raw path string |
is_blackbox | bool | True if neither primitive nor module instance |
is_module_instance | bool | True if references a module |
is_primitive | bool | True if from built-in gate library |
splittable | bool | True if can be split into 1-bit instances |
has_unconnected_port_segments | bool | True if any port segment is unconnected |
signals | Dict[str, SignalArray] | All port signals |
verilog | str | Generated Verilog instantiation string |
verilog_template | str | Template: {inst_type} {inst_name} {parameters}({ports}); |
all_connections(include_unconnected: bool) -> Dict[str, Dict[int, WireSegmentPath]]Get all connections including unconnected ports.
connect(port_name: str, ws_path: WireSegmentPath | None, direction: Direction = Direction.UNKNOWN, index: NonNegativeInt = 0, width: PositiveInt = 1) -> NoneAdd connections to a port.
inst.connect("A", wire_seg_path, direction=Direction.IN, index=0, width=8)
disconnect(port_name: str, index: int | None = None) -> NoneRemove connections from a port. Index=None disconnects all bits.
modify_connection(port_name: str, ws_path: WireSegmentPath, index: NonNegativeInt = 0) -> NoneUpdate an existing connection.
connect_modify(port_name: str, ws_path: WireSegmentPath, direction: Direction = Direction.UNKNOWN, index: NonNegativeInt = 0, width: PositiveInt = 1) -> NoneAdd or modify a connection (idempotent).
get_connection(port_name: str, index: int | None = None) -> WireSegmentPath | Dict[int, WireSegmentPath] | NoneGet connection path(s) for a port.
tie_port(name: str, index: NonNegativeInt, sig_value: LogicLevel) -> NoneTie a port segment to a constant value.
has_tied_ports() / has_tied_inputs() / has_tied_outputs() -> boolCheck if any ports are tied to constants.
split() -> Dict[NonNegativeInt, Instance]Split n-bit instance into n 1-bit instances (if splittable).
copy_object(new_name: str) -> InstanceCreate a copy with a new name (unconnected ports).
update_signedness(port_name: str) -> NoneUpdate signedness parameter from port metadata.
change_mutability(is_now_locked: bool, recursive: bool = False) -> InstanceLock/unlock the instance and optionally its ports.
normalize_metadata(...) -> METADATA_DICTNormalize metadata from all ports.
I/O of a module or instance. Generic: Port[Module] or Port[Instance].
| Property | Type | Description |
|---|---|---|
name | str | Port name |
direction | Direction | IN, OUT, IN_OUT, UNKNOWN |
segments | CustomDict[int, PortSegment] | Per-bit segments |
width | int | Number of bits |
offset | `int | None` |
msb_first | bool | MSB-first ordering |
lsb_first | bool | LSB-first (inverse of msb_first) |
signed | bool | Whether port is signed |
unsigned | bool | Whether port is unsigned |
signal | Signal | Signal value (1-bit only, warns otherwise) |
signal_array | SignalArray | Full multi-bit signal array |
signal_str | str | Signal as binary string (MSB first) |
signal_int | `int | None` |
is_input | bool | True if direction is IN or IN_OUT |
is_output | bool | True if direction is OUT or IN_OUT |
is_driver | bool | True if driving a signal (instance OUT or module IN) |
is_load | bool | True if being driven (instance IN or module OUT) |
is_connected | bool | All segments connected |
is_connected_partly | bool | At least one segment connected |
is_unconnected | bool | No segments connected |
is_unconnected_partly | bool | At least one segment unconnected |
is_tied | bool | All segments tied to constant |
is_tied_partly | bool | At least one segment tied |
is_tied_defined | bool | All tied to 0 or 1 |
is_tied_defined_partly | bool | At least one tied to 0 or 1 |
is_tied_undefined | bool | All tied to x or z |
is_tied_undefined_partly | bool | At least one tied to x or z |
is_floating | bool | All segments floating |
is_floating_partly | bool | At least one segment floating |
has_undefined_signals | bool | Any segment is x or z |
is_instance_port | bool | True if instance port |
is_module_port | bool | True if module port |
is_connected_1to1 | bool | Connected as assign port = wire; |
connected_wire_segments | Dict[int, WireSegmentPath] | Connected wire paths |
connected_wires | Set[WirePath] | Connected wire paths (unique) |
path | PortPath | Hierarchical path |
raw_path | str | Raw path string |
set_signal(signal: LogicLevel | Signal, index: NonNegativeInt = 0) -> NoneSet signal on a specific bit.
port.set_signal(Signal.HIGH, index=0)
port.set_signal('0', index=1)
set_signals(signal: int | str | SignalDict) -> NoneSet all bits at once.
port.set_signals(0b1010) # From integer (LSB=bit 0)
port.set_signals("1010") # From binary string (MSB first)
port.set_signals({0: '1', 2: '1'}) # From dict
tie_signal(signal: LogicLevel | Signal, index: NonNegativeInt = 0) -> NoneTie a port segment to a constant value permanently.
count_signals(target_signal: Signal) -> NonNegativeIntCount occurrences of a signal value.
high_count = port.count_signals(Signal.HIGH)
driver(single: bool = False) -> Port | Dict[int, PortSegment | None]Get the driving port (for load ports only).
driving_port = port.driver(single=True) # Single port if all segments driven by same
drivers = port.driver() # Dict of segment → driver segment
loads() -> Dict[int, List[PortSegment]]Get all load port segments (for driver ports).
set_signed(signed: bool) -> boolChange signedness. Returns True if changed.
change_connection(new_wire_segment_path: WireSegmentPath, index: int | None = 0) -> NoneChange which wire a segment connects to.
create_port_segment(index: NonNegativeInt) -> PortSegmentCreate and add a new segment.
create_port_segments(count: PositiveInt, offset: NonNegativeInt = 0) -> Dict[int, PortSegment]Create multiple segments.
remove_port_segment(index: NonNegativeInt) -> NoneRemove a segment.
get_port_segment(index: NonNegativeInt) -> PortSegment | NoneGet a segment by index.
__getitem__(index: int) -> PortSegmentSubscript access: port[0].
__len__() -> intPort width.
__iter__() -> Iterator[Tuple[int, PortSegment]]Iterate over (index, segment) pairs.
Internal net connection between ports.
| Property | Type | Description |
|---|---|---|
name | str | Wire name |
segments | CustomDict[int, WireSegment] | Per-bit segments |
width | int | Number of bits |
offset | `int | None` |
msb_first | bool | MSB-first ordering |
lsb_first | bool | LSB-first |
signed | bool | Whether wire is signed |
unsigned | bool | Whether wire is unsigned |
signal | Signal | Signal value (1-bit only) |
signal_array | SignalArray | Full multi-bit signal array |
signal_str | str | Signal as binary string |
signal_int | `int | None` |
connected_port_segments | Dict[int, List[PortSegment]] | Connected port segments |
path | WirePath | Hierarchical path |
raw_path | str | Raw path string |
set_signal(signal: LogicLevel | Signal, index: NonNegativeInt = 0) -> NoneSet signal on a specific bit.
set_signals(signal: int | str | SignalDict) -> NoneSet all bits at once.
set_signed(signed: bool) -> NoneChange signedness.
driver() -> Dict[int, PortSegment | None]Get driving port segments for each bit.
loads() -> Dict[int, List[PortSegment]]Get load port segments for each bit.
has_no_driver(get_mapping: bool = False) -> bool | Dict[int, bool]Check if wire has no driver.
has_multiple_drivers(get_mapping: bool = False) -> bool | Dict[int, bool]Check for multiple drivers (error condition).
has_no_loads(get_mapping: bool = False) -> bool | Dict[int, bool]Check if wire has no loads (dangling).
is_dangling(get_mapping: bool = False) -> bool | Dict[int, bool]Check if any segment is dangling.
has_problems(get_mapping: bool = False) -> bool | Dict[int, bool]Check for any problems (no driver, multiple drivers, no loads).
create_wire_segment(index: NonNegativeInt) -> WireSegmentCreate and add a new segment.
create_wire_segments(count: PositiveInt, offset: NonNegativeInt = 0) -> Dict[int, WireSegment]Create multiple segments.
remove_wire_segment(index: NonNegativeInt) -> NoneRemove a segment.
get_wire_segment(index: NonNegativeInt) -> WireSegment | NoneGet a segment by index.
get_wire_segments(name: str = '', fuzzy: bool = False) -> Dict[int, WireSegment]Search segments by name.
__getitem__(index: int) -> WireSegmentSubscript access: wire[0].
__len__() -> intWire width.
__iter__() -> Iterator[Tuple[int, WireSegment]]Iterate over (index, segment) pairs.
The smallest addressable unit — individual bits of ports and wires.
| Property | Type | Description |
|---|---|---|
signal | Signal | Current signal value |
signal_int | `int | None` |
is_connected | bool | Connected to a wire segment |
is_unconnected | bool | Not connected |
is_tied | bool | Tied to constant (0, 1, x, z) |
is_tied_defined | bool | Tied to 0 or 1 |
is_tied_undefined | bool | Tied to x or z |
is_floating | bool | Floating (z) |
is_undefined | bool | Undefined (x) |
ws_path | WireSegmentPath | Connected wire segment path |
ws | WireSegment | Connected wire segment object |
wire_name | str | Name of connected wire |
raw_ws_path | str | Raw wire segment path string |
index | int | Bit index in parent port |
parent | Port[Module] | Port[Instance] | Parent port |
grandparent | Module | Instance | Parent of parent |
path | PortSegmentPath | Hierarchical path |
type | EType | Element type (PORT_SEGMENT) |
set_ws_path(ws_path: str | WireSegmentPath) -> SelfSet or update the wire segment path. Returns self for chaining.
| Property | Type | Description |
|---|---|---|
signal | Signal | Current signal value |
is_constant | bool | True if constant (0, 1, x, z) |
is_defined_constant | bool | True if defined constant (0 or 1) |
has_defined_signal | bool | True if signal is defined (0 or 1) |
port_segments | CustomList[PortSegment] | Connected port segments |
nr_connected_ports | int | Number of connected ports |
index | int | Bit index in parent wire |
parent | Wire | Parent wire |
grandparent | Module | Parent module |
path | WireSegmentPath | Hierarchical path |
type | EType | Element type (WIRE_SEGMENT) |
add_port_segment(port_segment: PortSegment) -> PortSegmentAdd a port segment to this wire segment. Returns the added PortSegment.
add_port_segments(port_segments: Iterable[PortSegment]) -> List[PortSegment]Add multiple port segments. Returns list of added segments.
remove_port_segment(port_segment: PortSegment) -> NoneRemove a port segment from this wire segment.
has_no_driver() -> boolCheck if no driver.
has_multiple_drivers() -> boolCheck for multiple drivers.
has_no_loads() -> boolCheck if no loads.
is_dangling() -> boolCheck if segment is dangling (no connections).
has_problems() -> boolCheck for any problems (no driver, multiple drivers, no loads).
evaluate() -> NoneEvaluate signal propagation to/from this segment.
Note: Both PortSegment and WireSegment share these common methods (also documented on Wire/Port):
set_signal(signal: LogicLevel | Signal) — The only way to write signalsdriver() / loads() — Get driving/load port segmentshas_no_driver() / has_multiple_drivers() / has_no_loads() — Problem detectionTyped path objects for hierarchical navigation. All use dot-separated notation with numeric segment indices. Each type carries semantic meaning that determines how it resolves to actual objects via get_from_path().
The key insight: the path type determines the return type of get_from_path(). A type checker can infer the exact object type from the path argument.
| Path Class | Example | Resolves To | Where Used |
|---|---|---|---|
ModulePath | "top" | Module | Circuit.get_from_path(ModulePath) — must be single component |
InstancePath | "top.u_adder" | Instance | Circuit.get_from_path(InstancePath), Module.get_from_path(InstancePath) |
PortPath | "top.data_in" | Port[Module] | Module-level: resolves to module port |
PortPath | "top.u_adder.clk" | Port[Instance] | Instance-level: resolves to instance port |
PortSegmentPath | "top.data_in.3" | PortSegment (module port segment) | Module-level |
PortSegmentPath | "top.u_adder.clk.0" | PortSegment (instance port segment) | Instance-level |
WirePath | "top.addr_bus" | Wire | Always module-level (wires live in modules) |
WireSegmentPath | "top.addr_bus.7" | WireSegment | Always module-level |
"top" — no sub-components allowed."top.sub.u_inst" → traverses top module → finds instance u_inst of type sub.Port[Module]; if parent is an Instance → Port[Instance].You can pass either a raw string or a typed path object to get_from_path(). The typed version enables type inference:
from netlist_carpentry import Circuit
from netlist_carpentry.core.netlist_elements.element_path import (
ModulePath, InstancePath, PortPath, PortSegmentPath, WirePath, WireSegmentPath
)
circuit = read("design.v")
# String form — returns NetlistElement (no type inference)
inst = circuit.get_from_path("top.u_adder") # type: NetlistElement
port = circuit.get_from_path("top.data_in") # type: NetlistElement
seg = circuit.get_from_path("top.data_in.3") # type: NetlistElement
# Typed form — type checker knows the exact return type
inst = circuit.get_from_path(InstancePath(raw="top.u_adder")) # type: Instance
port = circuit.get_from_path(PortPath(raw="top.data_in")) # type: Port[Module]
port = circuit.get_from_path(PortPath(raw="top.u_adder.clk")) # type: Port[Instance]
seg = circuit.get_from_path(PortSegmentPath(raw="top.data_in.3")) # type: PortSegment
wire = circuit.get_from_path(WirePath(raw="top.addr_bus")) # type: Wire
wseg = circuit.get_from_path(WireSegmentPath(raw="top.addr_bus.7")) # type: WireSegment
.path PropertyEach element returns its own typed path — use this to navigate up the hierarchy:
inst = circuit.get_from_path(InstancePath(raw="top.u_adder"))
assert isinstance(inst.path, InstancePath) # inst.path → InstancePath("top.u_adder")
port = inst.ports["A"]
assert isinstance(port.path, PortPath) # port.path → PortPath("top.u_adder.A")
seg = port[0]
assert isinstance(seg.path, PortSegmentPath) # seg.path → PortSegmentPath("top.u_adder.A.0")
# Navigate up the hierarchy
assert seg.path.parent == port.path # PortSegmentPath → PortPath
assert port.path.parent == inst.path # PortPath → InstancePath
assert inst.path.parent.hierarchy_level == 0 # InstancePath → ModulePath (hierarchy_level 0 = top-level module)
| Property/Method | Type | Description |
|---|---|---|
raw | str | Raw path string (e.g., "top.u_adder.A.0") |
sep | str | Separator character (default '.') |
type | EType | Element type enum (MODULE, INSTANCE, PORT, PORT_SEGMENT, WIRE, WIRE_SEGMENT) |
parts | List[str] | Split path components: "top.u_adder.A.0" → ["top", "u_adder", "A", "0"] |
name | str | Last component (element name): "0" or "A" or "u_adder" |
parent | ElementPath | Parent path (returns appropriate subclass: InstancePath.parent → Union[ModulePath, InstancePath], PortPath.parent → InstancePath, etc.) |
hierarchy_level | int | Number of hierarchy levels: top-level instance = 1, submodule instance = 2 |
is_empty | bool | True if raw path is empty string |
type_mapping | List[Tuple[str, EType]] | Heuristic mapping of each component to its element type |
get(index: int) -> strGet component at index (returns '' instead of raising).
path = PortSegmentPath(raw="top.u_adder.A.0")
path.get(0) # "top"
path.get(-1) # "0" (last component)
path.get(-99) # "" (out of bounds → empty string)
nth_parent(index: NonNegativeInt) -> ElementPathGet nth ancestor (0=self, 1=parent, 2=grandparent).
seg_path = PortSegmentPath(raw="top.u_adder.A.0")
seg_path.nth_parent(0) # PortSegmentPath("top.u_adder.A.0") — self
seg_path.nth_parent(1) # PortPath("top.u_adder.A") — parent
seg_path.nth_parent(2) # InstancePath("top.u_adder") — grandparent
seg_path.nth_parent(3) # ModulePath("top") — great-grandparent
has_parent(index: NonNegativeInt = 1) -> boolCheck if nth parent exists.
seg_path.has_parent(1) # True (has parent)
seg_path.has_parent(10) # False (no such ancestor)
replace(old: str, new: str) -> SelfReplace a path component in-place.
path = InstancePath(raw="top.u_adder")
path.replace("u_adder", "u_sub")
# path.raw is now "top.u_sub"
is_type(type: EType) -> boolCheck if path type matches.
PortPath(raw="top.clk").is_type(EType.PORT) # True
PortPath(raw="top.clk").is_type(EType.WIRE) # False
get_subseq(lower_idx: int | None, upper_idx: int | None) -> List[str]Slice path components.
path = InstancePath(raw="top.sub.u_inst")
path.get_subseq(0, 2) # ["top", "sub"]
path.get_subseq(None, 1) # ["top"]
path.get_subseq(1, None) # ["sub", "u_inst"]
__getitem__(index: int) -> strSubscript access: path[0].
__len__() -> intNumber of components.
__eq__(other: object) -> boolEquality comparison.
__hash__() -> intHash for use in dicts/sets.
__str__() -> strString representation (same as raw).
__repr__() -> strDeveloper representation.
get_path_from_str() — Auto-Detect Path TypeCircuit.get_path_from_str() inspects the path string against the circuit's modules/instances/ports/wires to infer the correct path type:
path = circuit.get_path_from_str("top.u_adder.A.0")
# Returns PortSegmentPath (auto-detected)
path = circuit.get_path_from_str("top.data_in")
# Returns PortPath (auto-detected)
path = circuit.get_path_from_str("top.wire_a")
# Returns WirePath (auto-detected)
type_mapping)Each path type builds a heuristic mapping of components to element types:
path = PortSegmentPath(raw="top.sub.u_inst.port.3")
# type_mapping → [
# ("top", EType.MODULE),
# ("sub", EType.INSTANCE),
# ("u_inst", EType.INSTANCE),
# ("port", EType.PORT), # second-to-last for segment paths
# ("3", EType.PORT_SEGMENT) # last element
# ]
| Name | Type | Description |
|---|---|---|
T_PATH_TYPES | Union[...] | Union of all path types |
TYPES2PATHS | Dict[EType, Type[ElementPath]] | Maps EType → path class (used internally for path resolution) |
A networkx.MultiDiGraph wrapper for module-level graph algorithms.
| Property | Type | Description |
|---|---|---|
nodes | NodeView | NetworkX node view |
edges | EdgeView | NetworkX edge view |
node_type(node_name: str) -> Literal['INSTANCE', 'PORT']Get node type.
node_subtype(node_name: str) -> strGet node subtype (port direction or instance type).
all_edges(node_name: str) -> Set[Tuple[str, str, str]]Get all edges connected to a node. Each tuple: (source, target, edge_key).
get_data(node_name: str, key: str) -> objectGet node attribute data. Keys: 'ntype', 'nsubtype', 'ndata'.
set_data(node_name: str, val: object, key: str) -> NoneSet node attribute data.
G = module.graph()
import networkx as nx
# All simple paths
paths = nx.all_simple_paths(G, "input_port", "output_port")
# Cycles
cycles = nx.simple_cycles(G)
# Successors/predecessors
successors = list(G.successors("u_and"))
predecessors = list(G.predecessors("u_adder"))
Pattern — Find and Replace Subgraphs (Namespace Class)Important: Pattern is a namespace class with only classmethods — it has no __init__ and cannot be instantiated.
from netlist_carpentry import Pattern, ModuleGraph
# Use classmethods directly
mapping = Pattern.get_mapping(pattern_module, replacement_module)
Pattern._add_node_metadata(graph: ModuleGraph) -> None (classmethod, private)Adds metadata to graph nodes: n_input_inst and n_output_inst booleans.
Pattern._remove_ports_from_pattern_graphs(graph: ModuleGraph) -> None (classmethod, private)Removes PORT nodes from a pattern graph.
Pattern.get_mapping(pattern_module: Module, replacement_module: Module) -> Dict[Tuple[str, str, int], Tuple[str, str, int]] (classmethod)Generate port mapping between pattern and replacement modules.
Pattern.find_matches(pattern_graph: ModuleGraph, circuit_graph: ModuleGraph, max_match_count: int | None = None) -> MatchFind all occurrences of the pattern in a circuit graph.
match_result = Pattern.find_matches(module.graph(), module.graph())
print(f"Found {match_result.count} matches")
Returns: Match object containing found matches.
Pattern.count_matches(pattern_graph: ModuleGraph, circuit_graph: ModuleGraph) -> intCount matches without returning details.
Pattern.replace(pattern_module: Module, target_module: Module) -> NoneReplace all matched patterns in a module (if replacement graph is set).
Match — Pattern Match ResultsReturned by Pattern.find_matches().
from netlist_carpentry import Match
| Property | Type | Description |
|---|---|---|
pattern_graph | ModuleGraph | The pattern graph (deep copy) |
matches | List[ModuleGraph] | List of matched subgraphs found in the original circuit (each is a deep copy) |
count | int | Number of matches |
pairings | Dict[str, Dict[int, str]] | Mapping of pattern graph nodes to matched node IDs across all matches. Format: {pattern_node_id: {match_index: matched_node_id}} |
get_interfaces(circuit_graph: ModuleGraph) -> Dict[int, Dict[Tuple[str, str, int], Set[Tuple[str, str, int]]]]Get interface mappings for each match.
Constraint — Pattern Matching ConstraintsFilter which matches are accepted.
from netlist_carpentry import Constraint, CascadingGateConstraint
Constraint — Base Class| Method | Signature | Description |
|---|---|---|
check() | check(potential_match_graph: ModuleGraph, circuit_graph: ModuleGraph) -> bool | Check if constraint is satisfied |
CascadingGateConstraint — Gate Type Constraintconstraint = CascadingGateConstraint("§and")
| Property | Type | Description |
|---|---|---|
instance_type | str | Required instance type |
| Method | Signature | Description |
|---|---|---|
check() | check(potential_match_graph: ModuleGraph, circuit_graph: ModuleGraph) -> bool | Check if all instances match type |
from netlist_carpentry import CASCADING_OR_CONSTRAINT, CASCADING_AND_CONSTRAINT
| Constant | Type | Description |
|---|---|---|
CASCADING_OR_CONSTRAINT | CascadingGateConstraint | Checks if subgraph forms a cascading OR structure |
CASCADING_AND_CONSTRAINT | CascadingGateConstraint | Checks if subgraph forms a cascading AND structure |
VCD (Value Change Dump) processing requires the optional pywellen dependency. Install via pip install netlist-carpentry[vcd].
Availability Check:
from netlist_carpentry import HAS_VCD
if HAS_VCD:
from netlist_carpentry.io.vcd import VCDWaveform, ...
VCDWaveform — VCD Waveform Containerfrom netlist_carpentry.io.vcd import VCDWaveform
wf = VCDWaveform("simulation.vcd") # From file path (str or Path)
wf = VCDWaveform(waveform_object) # From pywellen Waveform object
| Property | Type | Description |
|---|---|---|
top_scopes | List[VCDScope] | Top-level scopes in the waveform |
all_vars | Dict[str, VCDVar] | All variables keyed by full name |
VCDScope — VCD Scope Representationfrom netlist_carpentry.io.vcd import VCDScope
| Property | Type | Description |
|---|---|---|
name | str | Scope name |
full_name | str | Full hierarchical scope name |
scope_type | SCOPE_TYPES | Scope type (module, program, etc.) |
scopes | List[VCDScope] | Sub-scopes |
vars | List[VCDVar] | Variables in this scope |
VCDVar — VCD Variable Representationfrom netlist_carpentry.io.vcd import VCDVar
| Property | Type | Description |
|---|---|---|
name | str | Variable name |
full_name | str | Full hierarchical variable name |
bitwidth | Optional[int] | Variable bitwidth |
var_type | VAR_TYPES | Variable type (wire, reg, etc.) |
enum_type | Optional[Tuple[str, List[Tuple[str, str]]]] | Enum type info |
direction | Literal[...] | Direction (Unknown, Input, Output, InOut, Buffer, Linkage) |
length | Optional[int] | Variable length |
is_real | bool | Whether variable is real type |
is_string | bool | Whether variable is string type |
is_bit_vector | bool | Whether variable is bit vector |
is_1bit | bool | Whether variable is 1-bit |
all_changes | List[Tuple[NonNegativeInt, Union[NonNegativeInt, str]]] | All signal changes (time, value) |
change_times | List[NonNegativeInt] | Timestamps when the variable changed |
| Method | Signature | Description |
|---|---|---|
value_at_time() | value_at_time(time: NonNegativeInt) -> Union[int, str] | Get signal value at timestamp |
value_at_idx() | value_at_idx(idx: int) -> Union[int, str] | Get signal value at index |
get_hierarchy_dict(wf: VCDWaveform) -> STR_DICTReturns a nested dictionary of all scopes and subscopes.
from netlist_carpentry.io.vcd import get_hierarchy_dict
hierarchy = get_hierarchy_dict(wf)
# {"top": {"sub1": {"sub2": {}}}}
get_scope(wf: VCDWaveform, scope_name: str) -> VCDScopeReturns the scope with the given name. Raises VcdLoadingError if not found.
map_names_to_circuit(c: Circuit, wf: VCDWaveform, top_vcd_scope: str) -> VCD_MAPPINGMaps all scope names to corresponding circuit modules.
from netlist_carpentry.io.vcd import map_names_to_circuit
mapping = map_names_to_circuit(circuit, wf, "top_tb")
# Returns {"top_tb": Module, "top_tb.sub": Module, ...}
apply_vcd_data(c: Circuit, wf: VCDWaveform, top_scope: str, scope: VCDScope = None) -> NoneApplies VCD data to circuit wires. Stores value traces in Wire.metadata.vcd.
from netlist_carpentry.io.vcd import apply_vcd_data
apply_vcd_data(circuit, wf, "top_tb")
# After this, wire.metadata.vcd contains {"var.full.name": [(time, value), ...]}
equal_toggles(wf: VCDWaveform, scope: VCDScope = None, vcd_vars: List[str | VCDVar] = None) -> SIGNAL_TOGGLE_DICTReturns a dictionary of timestamps → list of VCD vars that toggle at those timestamps.
from netlist_carpentry.io.vcd import equal_toggles
toggles = equal_toggles(wf)
# { (10, 20, 30): [VCDVar(...), VCDVar(...)], ... }
filter_signals(wf: VCDWaveform, scope: VCDScope = None, vcd_vars: List[str | VCDVar] = None, min_occurences: PositiveInt = 1, min_changes: NonNegativeInt = 0) -> SIGNAL_TOGGLE_DICTFilters signals based on toggle frequency and co-toggling behavior.
from netlist_carpentry.io.vcd import filter_signals
filtered = filter_signals(wf, min_occurences=2, min_changes=1)
# Only includes signals that toggle together at least 2 times and change at least once
filter_signals_per_scope(wf: VCDWaveform, scope: VCDScope, signal_dict: Dict[str, SIGNAL_TOGGLE_DICT], ...) -> NoneFilters signals per scope and populates the given dictionary. Updates signal_dict in-place.
find_matching_signals(vcd_filepaths: List[Path | str]) -> SIGNAL_GROUPSFinds signals across multiple VCD files that always have the same value and groups them.
from netlist_carpentry.io.vcd import find_matching_signals
groups = find_matching_signals(["sim1.vcd", "sim2.vcd"])
# [["top_tb.sig_a", "top_tb.sig_b"], ["top_tb.sig_c"], ...]
get_hierarchy_dict(wf: VCDWaveform) -> STR_DICTReturns a nested dictionary of all scopes and subscopes.
Signal — 4-Value Logic Enumfrom netlist_carpentry import Signal
Signal.LOW # '0' — logical zero
Signal.HIGH # '1' — logical one
Signal.UNDEFINED # 'x' — unknown
Signal.FLOATING # 'z' — high-impedance
| Property | Type | Description |
|---|---|---|
is_defined | bool | True if 0 or 1 |
is_undefined | bool | True if x or z |
Signal.get(sval: str | int | bool | Signal) -> SignalConvert various types to Signal.
Signal.get('0') # Signal.LOW
Signal.get(1) # Signal.HIGH
Signal.get(True) # Signal.HIGH
Signal.get('z') # Signal.FLOATING
Signal.parsable(signal_like: object) -> boolCheck if value can be converted to Signal.
~signal (invert operator)Invert a signal: ~Signal.LOW → Signal.HIGH.
signal & other (AND operator)Bitwise AND: Signal.HIGH & Signal.LOW → Signal.LOW.
signal | other (OR operator)Bitwise OR: Signal.HIGH | Signal.LOW → Signal.HIGH.
signal ^ other (XOR operator)Bitwise XOR: Signal.HIGH ^ Signal.LOW → Signal.HIGH.
int(signal) — Convert to int (only if defined).SignalArray — Multi-Bit Signal Containerfrom netlist_carpentry import SignalArray
# From integer (LSB = index 0)
arr = SignalArray.from_int(0b1010, fixed_width=4)
# From binary string (MSB first by default)
arr = SignalArray.from_bin("1010")
# From list
arr = SignalArray.create([Signal.HIGH, Signal.LOW, Signal.UNDEFINED])
# From dict
arr = SignalArray.create({0: '1', 2: '1'})
| Property | Type | Description |
|---|---|---|
signals | Dict[int, Signal] | Index → Signal mapping |
is_defined | bool | All bits defined (0 or 1) |
is_undefined | bool | All bits undefined (x or z) |
signed | bool | Whether signed |
msb_first | bool | MSB-first ordering |
default_fill | Signal | Default fill signal for undefined bits |
SignalArray.from_int(value: int, msb_first: bool = True, fixed_width: int | None = None) -> SignalArrayCreate from integer.
SignalArray.from_bin(bin_str: str, msb_first: bool = True, fixed_width: int | None = None) -> SignalArrayCreate from binary string.
SignalArray.create(data: list | dict | int | str, ...) -> SignalArrayCreate from various sources.
int(signal_array) — Convert to integer (only if all defined).str(signal_array) — Convert to binary string (MSB first).from netlist_carpentry import Direction
Direction.IN # 'input'
Direction.OUT # 'output'
Direction.IN_OUT # 'inout'
Direction.UNKNOWN # 'unknown'
| Property | Type | Description |
|---|---|---|
is_input | bool | True for IN or IN_OUT |
is_output | bool | True for OUT or IN_OUT |
is_defined | bool | True if not UNKNOWN |
Direction.get(value: str) -> DirectionConvert string to Direction (case-insensitive).
Direction.get('input') # Direction.IN
Direction.get('OUT') # Direction.OUT
Direction.get('InOut') # Direction.IN_OUT
Direction.get('invalid') # Direction.UNKNOWN
An enumeration of all possible netlist element types. Used throughout the codebase to classify elements, drive path resolution, and determine behavior (e.g., whether an element can carry signals).
| Value | String | Corresponding Class | Can Carry Signal | Is Segment |
|---|---|---|---|---|
EType.UNSPECIFIED | 'unspecified' | NetlistElement (base) | No | No |
EType.MODULE | 'module' | Module | No | No |
EType.INSTANCE | 'instance' | Instance | No | No |
EType.PORT | 'port' | Port | Yes | No |
EType.PORT_SEGMENT | 'port_segment' | PortSegment | Yes | Yes |
EType.WIRE | 'wire' | Wire | Yes | No |
EType.WIRE_SEGMENT | 'wire_segment' | WireSegment | Yes | Yes |
| Property | Type | Description |
|---|---|---|
can_carry_signal | bool | True for PORT, PORT_SEGMENT, WIRE, WIRE_SEGMENT. False for MODULE, INSTANCE, UNSPECIFIED. |
is_segment | bool | True for PORT_SEGMENT, WIRE_SEGMENT. False for all others. |
EType is used in three key places:
Path type discrimination — Each ElementPath subclass returns its corresponding EType from .type. Used to route path resolution:
from netlist_carpentry.core.enums.element_type import EType
if path.type == EType.PORT_SEGMENT:
# resolve to PortSegment
Class lookup — The get_class() function maps EType → Python class:
from netlist_carpentry.core.enums.element_type import get_class
cls = get_class(EType.PORT) # returns Port
cls = get_class(EType.WIRE) # returns Wire
cls = get_class("instance") # returns Instance (string lookup)
Path type registry — TYPES2PATHS maps EType → path class for internal resolution:
from netlist_carpentry.core.netlist_elements.element_path import TYPES2PATHS
path_cls = TYPES2PATHS[EType.PORT] # returns PortPath
path_cls = TYPES2PATHS[EType.WIRE] # returns WirePath
CFG — Global Settingsfrom netlist_carpentry import CFG
CFG.log_level # 3 (default: warnings and above)
CFG.print_source_module # False
CFG.id_external # '__' (external naming prefix)
CFG.id_internal # '§' (internal/primitive prefix)
CFG.allow_detached_segments # False
CFG.yosys_executable # 'yosys' (or 'yowasp-yosys')
from netlist_carpentry.routines.opt import (
clean_circuit, # Remove unused modules
opt_constant, # Constant propagation & mux optimization
opt_driverless, # Remove instances with no driver
opt_loadless, # Remove wires with no load
opt_chains, # Floodfill chain optimization
)
opt_constant(module: Module) -> boolPropagate constants through the module. Returns True if changes made.
opt_driverless(module: Module) -> boolRemove instances with no driver (all inputs tied or undriven).
opt_loadless(module: Module) -> boolRemove wires with no load (dangling nets).
clean_circuit(circuit: Circuit) -> boolRemove unused modules from the circuit.
opt_chains(circuit: Circuit, input_path: str | None = None, top_module: str | None = None, gates: list[str] | None = None, output_path: str | None = None, skip_modules: set[str] | None = None) -> CircuitOptimizationResultOptimize chain structures (e.g., shift registers).
Parameters:
circuit (Circuit): Circuit object to optimize.input_path (str | None): Verilog file path (alternative to circuit object).top_module (str | None): Top module name (required with input_path).gates (list[str] | None): Gate types to optimize.output_path (str | None): Output file path.skip_modules (set[str] | None): Modules to skip.Returns: CircuitOptimizationResult — Statistics about optimization.
from netlist_carpentry.routines.opt.floodfill.chain_metrics import CircuitOptimizationResult
| Property | Type | Description |
|---|---|---|
modules_processed | int | Number of modules processed |
modules_with_chains | int | Modules containing chains |
total_chains_detected | int | Total chains found |
total_chains_replaced | int | Chains successfully replaced |
total_chains_skipped | int | Chains skipped |
total_chains_failed | int | Chains that failed |
module_results | Dict[str, ReplacementResult] | Per-module results |
module_reports | Dict[str, ModuleReport] | Per-module reports |
| Method | Signature | Description |
|---|---|---|
summary() | summary() -> str | Human-readable summary |
all_chain_details() | all_chain_details() -> List[Tuple[str, ChainInfo]] | All chain details |
all_skipped() | all_skipped() -> List[Tuple[str, ChainInfo]] | Skipped chains |
all_degenerate() | all_degenerate() -> List[Tuple[str, ChainInfo]] | Degenerate chains (constant inputs) |
all_problematic() | all_problematic() -> List[Tuple[str, ChainInfo]] | Problematic skips |
all_failed() | all_failed() -> List[Tuple[str, ChainInfo]] | Failed chains |
all_with_constants() | all_with_constants() -> List[Tuple[str, ChainInfo]] | Chains with constants |
from netlist_carpentry.routines.check import fanout, find_comb_loops, has_comb_loops
has_comb_loops(module: Module) -> boolCheck for combinational loops.
find_comb_loops(module: Module) -> List[List[str]]Find all combinational loop chains.
fanout(module: Module, sort_by: str = 'number') -> Dict[str, int]Calculate fanout counts for all instances.
All primitive gates are in netlist_carpentry.utils.gate_lib, prefixed with §.
from netlist_carpentry.utils.gate_lib import get, AndGate, OrGate, DFF
gate_class = get("§and") # Returns AndGate class
| Class | Instance Type | Ports | Description |
|---|---|---|---|
Buffer | §buf | I, O | Buffer |
NotGate | §not | I, O | Inverter |
AndGate | §and | A, B, Y | AND |
OrGate | §or | A, B, Y | OR |
XorGate | §xor | A, B, Y | XOR |
XnorGate | §xnor | A, B, Y | XNOR |
NorGate | §nor | A, B, Y | NOR |
NandGate | §nand | A, B, Y | NAND |
LogicAnd | §logic_and | A, B, Y | Logic AND (two-input, non-zero check) |
LogicOr | §logic_or | A, B, Y | Logic OR (two-input, non-zero check) |
LogicNot | §logic_not | I, O | Logic NOT (!wire_vector) |
BitwiseCaseEquality | §bweqx | A, B, Y | Bitwise case equality (===) |
| Class | Instance Type | Ports | Description |
|---|---|---|---|
Adder | §add | A, B, S, C_OUT | Adder |
Subtractor | §sub | A, B, D, B_OUT | Subtractor |
Multiplier | §mul | A, B, Y | Multiplication |
Divider | §div | A, B, Y | Truncated division |
Modulo | §mod | A, B, Y | Modulo (remainder) |
Exponentiator | §pow | A, B, Y | Power/exponentiation |
PosGate | §pos | A, Y | Arithmetic plus (sign extend) |
NegGate | §neg | A, Y | Arithmetic negator (two's complement) |
| Class | Instance Type | Ports | Description |
|---|---|---|---|
LessThan | §lt | A, B, Y | Less than |
LessEqual | §le | A, B, Y | Less than or equal (<=) |
Equal | §eq | A, B, Y | Equality |
CaseEqual | §eqx | A, B, Y | Case equal (===) |
NotEqual | §ne | A, B, Y | Not equal (!=) |
CaseNotEqual | §nex | A, B, Y | Case not equal (!==) |
GreaterThan | §gt | A, B, Y | Greater than |
GreaterEqual | §ge | A, B, Y | Greater than or equal (>=) |
| Class | Instance Type | Ports | Description |
|---|---|---|---|
ShiftLeft | §shl | A, B, Y | Shift left logical |
ShiftRight | §shr | A, B, Y | Shift right logical |
ShiftSigned | §shift | A, B, Y | Signed shift (conditional left/right) |
ArithmeticShiftLeft | §sshl | A, B, Y | Arithmetic shift left (<<<) |
ArithmeticShiftRight | §sshr | A, B, Y | Arithmetic shift right (>>>) |
ShiftX | §shiftx | A, B, Y | Shift with indexed part-select ([+:]) |
| Class | Instance Type | Ports | Description |
|---|---|---|---|
ReduceAnd | §reduce_and | A, Y | AND reduction |
ReduceOr | §reduce_or | A, Y | OR reduction |
ReduceXor | §reduce_xor | A, Y | XOR reduction |
ReduceBool | §reduce_bool | A, Y | Reduction OR with double negation |
ReduceXnor | §reduce_xnor | A, Y | Reduction XNOR |
| Class | Instance Type | Ports | Description |
|---|---|---|---|
Multiplexer | §mux | D0..Dn, S, Y | MUX (bit_width param) |
Demultiplexer | §demux | D, S, Y0..Yn | DEMUX (bit_width param) |
| Class | Instance Type | Ports | Description |
|---|---|---|---|
DFF | §dff | CLK, D, Q | D flip-flop |
ADFF | §adff | CLK, D, RST, Q | Async reset DFF |
DFFE | §dffe | CLK, EN, D, Q | Enable DFF |
ADFFE | §adffe | CLK, EN, D, RST, Q | Async reset DFF with enable |
SDFF | §sdff | CLK, D, RST, Q | Synchronous reset DFF |
SDFFE | §sdffe | CLK, EN, D, RST, Q | Sync reset DFF (rst precedence) |
SDFFCE | §sdffce | CLK, EN, D, RST, Q | Sync reset DFF with enable (en precedence) |
ALDFF | §aldff | CLK, AL, AD, D, Q | Async load DFF |
ALDFFE | §aldffe | CLK, AL, EN, AD, D, Q | Async load DFF with enable |
DFFSR | §dffsr | CLK, CLR, SET, D, Q | SR DFF |
DFFSRE | §dffsre | CLK, CLR, SET, EN, D, Q | SR DFF with enable |
| Class | Instance Type | Ports | Description |
|---|---|---|---|
ScanDFF | §scan_dff | CLK, D, S, Q | Scan DFF |
ScanADFF | §scan_adff | CLK, SE, SI, D, SO, Q | Scan async reset DFF |
ScanDFFE | §scan_dffe | CLK, SE, SI, EN, D, SO, Q | Scan enable DFF |
ScanADFFE | §scan_adffe | CLK, SE, SI, EN, D, RST, SO, Q | Scan async reset enable DFF |
| Class | Instance Type | Ports | Description |
|---|---|---|---|
DLatch | §dlatch | EN, D, Q | D latch |
Combine with gate classes for extended functionality. Full method details are in the Base Classes section below.
from netlist_carpentry.utils.gate_mixins import ClkMixin, RstMixin, EnMixin, ScanMixin, SRMixin, LoadMixin
from netlist_carpentry.utils.gate_lib import DFF
class MyDFF(ClkMixin, RstMixin, DFF):
pass
inst = module.create_instance(MyDFF, "u_ff")
run_eqy() — Formal Equivalence Checkfrom netlist_carpentry import run_eqy
result = run_eqy(
gold_files=["gold.v"],
gate_files=["gate.v"],
gold_top="gold_top",
gate_top="gate_top",
script_path=Path("script.eqy"),
output_path=Path("out"),
overwrite=True,
quiet=False,
)
Parameters:
gold_files (List[str]): Gold design Verilog files.gate_files (List[str]): Gate-level design Verilog files.gold_top (str): Top module of gold design.gate_top (str): Top module of gate design.script_path (Path): Output EQY script path.output_path (Path): Output directory.overwrite (bool): Overwrite existing files.quiet (bool): Suppress Yosys output.Returns: subprocess.Popen[str] — Yosys process handle.
run_equiv() — Run Equivalence Check via Yosysfrom netlist_carpentry import run_equiv
# With circuit objects
result = run_equiv(circuit_a, circuit_b, quiet=False, out_dir=Path("miter_out"))
# With file paths
result = run_equiv(["gold.v"], ["gate.v"], gold_top="gold_top", gate_top="gate_top")
Parameters:
gold_design (Circuit | str | Path | List[str]): Gold design.gate_design (Circuit | str | Path | List[str]): Gate-level design.gold_top (str): Top module of gold design (required when using file paths).gate_top (str): Top module of gate design (required when using file paths).quiet (bool): Suppress Yosys output.out_dir (str | Path | None): Output directory.no_name_matching (bool): Disable name matching.Returns: subprocess.Popen[str] — Yosys process handle.
run_equiv_miter() — Run Equivalence Check with Miter/SAT Approachfrom netlist_carpentry import run_equiv_miter
# With circuit objects
result = run_equiv_miter(circuit_a, circuit_b, gold_top="top", gate_top="top")
# With file paths + bounded model checking
result = run_equiv_miter(["gold.v"], ["gate.v"], gold_top="gold_top", gate_top="gate_top", cycles=5)
Parameters:
gold_design (Circuit | str | Path | List[str]): Gold design.gate_design (Circuit | str | Path | List[str]): Gate-level design.gold_top (str): Top module of gold design.gate_top (str): Top module of gate design.quiet (bool): Suppress Yosys output.out_dir (str | Path | None): Output directory (creates temp dir if None).cycles (PositiveInt | None): Number of cycles for Bounded Model Checking. None = temporal induction.Returns: subprocess.Popen[str] — Yosys process handle.
| Type | Definition | Description |
|---|---|---|
LogicLevelInt | Literal[0, 1] | Integer logic level |
LogicLevel | Union[Literal['0', '1', 'Z', 'X'], LogicLevelInt] | Single-bit signal value |
SignalOrLogicLevel | Union[Signal, LogicLevel] | Signal or raw logic level |
SignalDict | Dict[int, Signal] | Index → Signal mapping |
SIGNAL_LIKE | Union[bool, int, str, Signal] | Parseable signal value (from signal_array.py) |
class CarriesSignal(Protocol):
@property
def signal(self) -> Signal: ...
@property
def signal_int(self) -> Optional[int]: ...
Used to type elements that can carry signals (Port, Wire, PortSegment, WireSegment).
| Protocol | Purpose |
|---|---|
GateProtocol | Base protocol for all gates |
ClockMixinProtocol | Clock port access |
EnableMixinProtocol | Enable port access |
ResetMixinProtocol | Reset port access |
LoadMixinProtocol | Load port access (for ALDFF) |
SRMixinProtocol | Set/Reset port access |
ScanMixinProtocol | Scan port access |
CustomDict[K, V](Dict[K, V])Extended dict with add() and remove() methods that support locking.
d = CustomDict[str, Instance]()
d.add("u_and", and_inst) # Add with lock=False (default)
d.add("u_or", or_inst, locked=True) # Add with lock=True
d.remove("u_and") # Remove by key
| Method | Signature | Description |
|---|---|---|
add() | add(key: K, element: V, locked: bool = False) -> V | Add element with optional lock |
remove() | remove(key: K, locked: bool = False) -> None | Remove element by key |
CustomList[V](List[V])Extended list with add(), extend(), and remove() methods that support locking and duplicate control.
l = CustomList[PortSegment]()
l.add(seg) # Add single element
l.extend([seg1, seg2]) # Add multiple elements
l.flatten() # Flatten nested lists
l.remove(seg) # Remove by value
| Method | Signature | Description |
|---|---|---|
add() | add(object: V, locked: bool = False, allow_duplicates: bool = False) -> V | Add element |
extend() | extend(iterable: Iterable[V], locked: bool = False, allow_duplicates: bool = False, skip_duplicates: bool = False) -> None | Add multiple elements |
remove() | remove(object: V, locked: bool = False) -> None | Remove by value |
flatten() | flatten() -> List[V] | Flatten nested iterables |
from netlist_carpentry.core.netlist_elements.mixins.metadata import METADATA_DICT, NESTED_DICT
# Type definitions
NESTED_DICT = Union[BASIC_LEAF, Dict[str, 'NESTED_DICT'], List['NESTED_DICT']]
METADATA_DICT: TypeAlias = Dict[str, Dict[str, NESTED_DICT]]
Used for user-defined and Yosys-generated metadata on netlist elements.
NetlistElement — Base Class for All ElementsAll netlist elements inherit from NetlistElement. Key properties and methods:
| Property/Method | Type | Description |
|---|---|---|
path | ElementPath | Hierarchical path |
raw_path | str | Raw path string |
type | EType | Element type enum |
hierarchy_level | int | Hierarchy depth |
parent | NetlistElement | Parent element |
has_parent | bool | Whether has parent |
circuit | Circuit | Parent circuit (raises if not attached) |
has_circuit | bool | Whether attached to a Circuit |
locked | bool | Structural immutability flag |
is_placeholder_instance | bool | Whether placeholder instance |
can_carry_signal | bool | Whether element can carry signals |
| Method | Signature | Description |
|---|---|---|
__eq__() | __eq__(value: object) -> bool | Equality comparison |
_link_parent() | _link_parent() -> Self | Link to parent element |
set_name() | set_name(new_name: str) -> None | Change element name |
_set_name_recursively() | _set_name_recursively(old_name: str, new_name: str) -> None | Rename recursively |
change_mutability() | change_mutability(is_now_locked: bool) -> Self | Lock/unlock element |
copy_object() | copy_object(new_name: str) -> NetlistElement | Create a copy |
evaluate() | evaluate() -> None | Evaluate signal propagation |
normalize_metadata() | normalize_metadata(include_empty: bool = False, sort_by: Literal['path', 'category'] = 'path', filter: Callable[[str, NESTED_DICT], bool] = ...) -> METADATA_DICT | Normalize metadata |
__str__() | __str__() -> str | String representation |
__repr__() | __repr__() -> str | Developer representation |
All primitive gates inherit from these base classes:
| Class | Inherits From | Description |
|---|---|---|
PrimitiveGate | Instance, BaseModel | Base for all primitive gates |
UnaryGate | PrimitiveGate, BaseModel | Single-input gates |
BinaryGate | PrimitiveGate, BaseModel | Two-input gates |
ShiftGate | BinaryGate, BaseModel | Shift operations |
ArithmeticGate | BinaryGate, BaseModel | Arithmetic operations |
BinaryNto1Gate | _Out1BitMixin, BinaryGate, BaseModel | N-input to 1-output gates |
StorageGate | PrimitiveGate, BaseModel | Storage elements (FFs, latches) |
ReduceGate | _Out1BitMixin, UnaryGate | Reduction gates |
| Property | Type | Description |
|---|---|---|
y_width | PositiveInt | Output width |
a_width | PositiveInt | First input width |
b_width | PositiveInt | Second input width (if applicable) |
is_combinational | bool | Whether combinational |
is_sequential | bool | Whether sequential |
output_port | Port[Instance] | Output port |
is_primitive | bool | Always True |
data_width | int | Data width |
verilog_template | str | Verilog instantiation template |
verilog_net_map | Dict[str, str] | Port name mapping for Verilog |
| Method | Signature | Description |
|---|---|---|
_try_update_parameters() | _try_update_parameters() -> None | Try to update parameters from ports |
update_parameters() | update_parameters() -> None | Update parameters from ports |
sync_parameters() | sync_parameters(warn: bool = True) -> Parameters | Sync parameters with port widths |
p2v() | `p2v(port: ANY_PORT, exclude_indices: List[int] | None = None, include_indices: List[int] |
set() | set(port_name: str, new_signal: SignalOrLogicLevel, idx: Union[int, List[int]] = 0) -> None | Set signal on port |
evaluate() | evaluate() -> None | Evaluate gate output |
_calc_output() | _calc_output(idx: NonNegativeInt = 0) -> Dict[int, Signal] | Calculate output signals |
_set_output() | _set_output(new_signals: Dict[int, Signal]) -> None | Set output signals |
_split() | _split() -> Dict[NonNegativeInt, Self] | Split into 1-bit instances |
_split_sync_params() | _split_sync_params(slices: Iterable[Self]) -> None | Sync params after split |
Full method details for gate mixins are in the Gate Library section above.
| Mixin | Purpose | Key Properties/Methods |
|---|---|---|
ClkMixin | Clock port | clk_port, clk_polarity, set_clk() |
EnMixin | Enable port | en_port, en_polarity, en_signal, set_en() |
RstMixin | Reset port | rst_port, rst_polarity, rst_val, set_rst() |
LoadMixin | Load port (ALDFF) | al_port, ad_port, load_val, set_al() |
SRMixin | Set/Reset ports | clr_port, set_port, set_clr(), set_set() |
ScanMixin | Scan ports | se_port, si_port, so_port, scan_ff_equivalent, set_se() |
All gate parameters are defined as Pydantic models:
| Class | Inherits From | Description |
|---|---|---|
TypedParams | TypedDict | Base TypedDict for params |
Parameters | BaseModel | Base parameter model |
PortParams | Parameters | Port parameters |
InstanceParams | Parameters | Instance parameters |
GateParams | InstanceParams | Gate-specific parameters |
ClockParams | ClockParamsMixin, GateParams | Clock parameters |
EnableParams | EnableParamsMixin, GateParams | Enable parameters |
ResetParams | ResetParamsMixin, GateParams | Reset parameters |
LoadParams | LoadParamsMixin, GateParams | Load parameters |
SRParams | SRParamsMixin, GateParams | Set/Reset parameters |
WireParams | Parameters | Wire parameters |
UnaryParams | GateParams | Unary gate parameters |
BinaryParams | GateParams | Binary gate parameters |
MuxParams | GateParams | MUX parameters |