Skip to content

netlist_carpentry.core.circuit

Base module for the Circuit class.

Classes:

  • Circuit

    Represents a circuit, which is a collection of modules.

Circuit

Bases: BaseModel

Represents a circuit, which is a collection of modules.

A circuit consists of one or more modules. All modules are uniquely identified by their names, which are stired as keys in a dictionary, where their values are the corresponding Module objects. Each module can be part of other modules in the form of instatiations as submodules within a module. Furthermore, each circuit can have an associated top-level module, indicating the hierarchical entry point of the circuit.

Methods:

  • __getitem__

    Returns a module from the circuit that has the given name.

  • __contains__

    Implements module_name in circuit.

  • __len__

    The size of the circuit, which is the number of modules in the circuit.

  • __iter__

    Iterator over the modules in the circuit.

  • add_module

    Adds a module to the circuit.

  • add_from_circuit

    Adds all modules from a given circuit to this circuit.

  • create_module

    Creates a new module with the given name and adds it to the circuit.

  • copy_module

    Duplicates the given module, and the new instance receives the given name.

  • remove_module

    Removes a module from the circuit.

  • get_module

    Gets a module from the circuit.

  • get_module_at_idx

    Returns the module with the given index.

  • set_top

    Sets the name of the top-level module in the circuit.

  • get_from_path

    Retrieves an element from the circuit based on a given ElementPath.

  • get_path_from_str

    Returns an appropriate ElementPath object for a given path.

  • sync_instances

    Synchronizes the instance registry by collecting instance paths from all modules.

  • update_instance

    Updates this Circuit's instance dictionary.

  • uniquify

    Ensure that every module instance in the circuit has its own unique definition.

  • create_blackbox_modules

    Implements empty modules for all blackbox cells.

  • set_signal

    Sets the signal of the port or wire (segment) at the given path to the given new signal.

  • write

    Writes a Verilog file for this circuit to the given location.

  • prove_equivalence

    Proves equivalence of the circuit against a set of gold Verilog files.

  • optimize

    Optimizes the circuit by applying optimizations to each module.

  • check

    Checks the circuit for issues.

  • evaluate

    Evaluates the circuit.

  • export_metadata

    Writes all metadata from this circuit to a JSON file at the given path.

Attributes:

  • name (str) –

    The name of the circuit.

  • modules (CustomDict[ModuleName, Module]) –

    Returns the dictionary of modules in the circuit.

  • module_count (NonNegativeInt) –

    The number of modules in the circuit.

  • top_name (ModuleName) –

    The name of the top-level module in the circuit.

  • top (Module) –

    The top-level module in the circuit.

  • has_top (bool) –

    True, if this circuit has a top-level module. False otherwise.

  • creator (str) –

    The name of the circuit's creator.

  • instances (DefaultDict[InstanceType, List[InstancePath]]) –

    A dictionary containing the names of all modules (and primitive gates) as keys,

  • first (Module) –

    Returns the first module in the circuit.

name instance-attribute

name: str

The name of the circuit.

modules property

modules: CustomDict[ModuleName, Module]

Returns the dictionary of modules in the circuit.

Returns:

  • CustomDict[ModuleName, Module]

    Dict[MODULE_NAME, Module]: The dictionary of modules, where the key is the module name and the value is a Module object.

module_count property

module_count: NonNegativeInt

The number of modules in the circuit.

top_name property

top_name: ModuleName

The name of the top-level module in the circuit.

top property

top: Module

The top-level module in the circuit.

has_top property

has_top: bool

True, if this circuit has a top-level module. False otherwise.

creator property writable

creator: str

The name of the circuit's creator.

instances property

instances: DefaultDict[InstanceType, List[InstancePath]]

A dictionary containing the names of all modules (and primitive gates) as keys, and a list of paths to corresponding module instances throughout the circuit.

This dictionary maps instance types to instance paths (i.e. to instances with the given type) throughout the circuit.

first property

first: Module

Returns the first module in the circuit.

Useful for circuits that only contain a single module.

Raises:

  • IndexError

    If the circuit does not have any modules, so no first module exists.

__getitem__

__getitem__(key: str) -> Module

Returns a module from the circuit that has the given name.

__contains__

__contains__(key: Union[str, Module]) -> bool

Implements module_name in circuit.

__len__

__len__() -> int

The size of the circuit, which is the number of modules in the circuit.

__iter__

__iter__() -> Iterator[Module]

Iterator over the modules in the circuit.

add_module

add_module(module: Module) -> Module

Adds a module to the circuit.

Parameters:

  • module

    (Module) –

    The module to add.

Returns:

  • Module ( Module ) –

    The module that was added.

add_from_circuit

add_from_circuit(
    other_circuit: Union[VerilogPath, Circuit],
) -> Dict[ModuleName, Module]

Adds all modules from a given circuit to this circuit.

The modules are not copied in the sense that new objects are created. The objects are added by reference, meaning that if a module in one circuit is changed, it will also change in the other circuit.

Parameters:

  • other_circuit

    (Union[VerilogPath, Circuit]) –

    The circuit of which the modules should be added. Can also be a path to a Verilog file containing the other circuit.

Returns:

  • Dict[ModuleName, Module]

    Dict[ModuleName, Module]: A dict of all module names and modules from the given circuit that were added to this circuit.

create_module

create_module(name: ModuleName) -> Module

Creates a new module with the given name and adds it to the circuit.

Parameters:

  • name

    (ModuleName) –

    The name of the module to create.

Returns:

  • Module ( Module ) –

    The module that was created and added to this circuit.

copy_module

copy_module(
    old_module: Union[ModuleName, Module], new_name: ModuleName
) -> Module

Duplicates the given module, and the new instance receives the given name.

If old_module is a string, a module with this name must exist in this circuit. This module is then copied, and receives the given name new_name to distinguish it from the original module.

Parameters:

  • old_module

    (Union[ModuleName, Module]) –

    The original module to copy. Can be a string, in which case a module with this exact name must exist within this circuit

  • new_name

    (ModuleName) –

    The new name of the freshly created module copy.

Raises:

  • ObjectNotFoundError

    If a string is given and no module with such name exists in this circuit.

Returns:

  • Module ( Module ) –

    The newly created module copy.

remove_module

remove_module(module: Union[ModuleName, Module]) -> None

Removes a module from the circuit.

Parameters:

  • module

    (Union[ModuleName, Module]) –

    The name of the module (or the module object) to remove.

Raises:

get_module

get_module(module_name: ModuleName) -> Optional[Module]

Gets a module from the circuit.

Parameters:

  • module_name

    (ModuleName) –

    The name of the module to get.

Returns:

  • Optional[Module]

    Optional[Module]: The module with the given name, if it exists.

get_module_at_idx

get_module_at_idx(index: NonNegativeInt) -> Optional[Module]

Returns the module with the given index.

Internally, the modules are stored in a dictionary, so there is no forced order. Therefore, this function enumerates the modules based on the order in the dictionary and returns the module at the given index. If there is no module at the given index (i.e. the index is out of bounds), returns None.

Parameters:

  • index

    (NonNegativeInt) –

    The index of the module to return.

Returns:

  • Optional[Module]

    Optional[Module]: The module at the given index, or None if the circuit has less modules than the given index.

set_top

set_top(module: Union[ModuleName, Module, None]) -> None

Sets the name of the top-level module in the circuit.

Set module=None to remove the current top module selection, and no module will be top module.

Parameters:

  • module

    (Union[ModuleName, Module, None]) –

    The name of the new top-level module in the circuit, or the Module object itself. Passing None will just remove the current top module selection, and no module will be top module.

Raises:

get_from_path

get_from_path(path: str) -> NetlistElement
get_from_path(path: InstancePath) -> Instance
get_from_path(path: PortPath) -> Port[Union[Module, Instance]]
get_from_path(path: PortSegmentPath) -> PortSegment
get_from_path(path: WirePath) -> Wire
get_from_path(path: WireSegmentPath) -> WireSegment
get_from_path(path: ElementPath) -> NetlistElement
get_from_path(
    path: Union[str, T_PATH_TYPES],
) -> Union[NetlistElement, T_MODULE_PARTS]

Retrieves an element from the circuit based on a given ElementPath.

The element can be of any type, including ports, wires or instances. This method tries to recursively break down the path to find the desired object. Given a path module.inst1.inst2, this method will return the instance inst2 of the instance inst1 inside the module module. Here, it is important that the type of the ElementPath is specified correctly. For the given example path, the type must be EType.INSTANCE, otherwise this method will be unable to find the instance.

Parameters:

  • path

    (ElementPath) –

    A certain ElementPath that points to an element within the circuit.

Returns:

  • NetlistElement ( Union[NetlistElement, T_MODULE_PARTS] ) –

    The object corresponding to the path.

Raises:

  • PathResolutionError

    If the given path could not be resolved to an object, either because the path is malformed, or no associated object exists.

get_path_from_str

get_path_from_str(path_str: str, sep: str = '.') -> ElementPath

Returns an appropriate ElementPath object for a given path.

Based on certain heuristics and the modules present in this circuit, the type of the path is assumed. The first element in the path is assumed to be a module, and any following element can only be an instance, port or wire. The actual type is retrieved by checking the instances, ports and wires of the module found in the first step for any matching instances. If it is a wire, it may only be followed by an integer indicating the corresponding segment. Analogously, if it is a port, and it is followed by an integer, the path points to a port segment. In case it is an instance, the path is further investigated, as an instance can be followed by a port in the path or another instance (if it is a submodule instance, and the path points to an instance within the submodule), which is then resolved recursively until the whole path is decoded. If no path can be retrieved, None is returned instead.

Parameters:

  • path_str

    (str) –

    The hierarchical path to an object of this circuit as a plain string.

  • sep

    (str, default: '.' ) –

    The character separating the individual hierarchical levels. Defaults to '.'. If the path uses a different separating character, it is replaced in the path by the '.'. Make sure, the '.' is not part of an element of the hierarchical path.

Returns:

  • ElementPath

    Optional[ElementPath]: An appropriate element path object from the given path based on certain heuristics. Is None, if no path object can be built.

sync_instances

sync_instances() -> None

Synchronizes the instance registry by collecting instance paths from all modules.

This method clears the current instances dictionary and rebuilds it by iterating through all modules. This is to ensure that an up-to-date mapping exists of instance types to their respective hierarchical paths.

The Circuit.instances dictionary is structured as:

```python
{
    'instance_type': ['path/to/inst1', 'path/to/inst2', ...],
    ...
}
```
Note

This method has a complexity of O(N * M) where N is the number of submodules and M is the number of instance types per submodule. For large circuits, this method might thus be rather slow and should therefore only be used if the instances dict somehow got corrupted. For "synchronization" of single instances, use Circuit.update_instance() instead.

update_instance

update_instance(
    instance: Union[Instance, InstancePath], old_type: Optional[str] = None
) -> None

Updates this Circuit's instance dictionary.

For a given Instance (or InstancePath), adds a reference to the instance's type definition. For an instance with path top.submodule.inst and type SomeModule, this method updates the Circuit's instance dictionary, such that Circuit.instances["SomeModule] now contains the path top.submodule.inst.

If old_type is not None, the corresponding instance path entry for Circuit.instances["old_type"] is removed as well. For this, a matching instance path must exist in Circuit.instances["old_type"]!

Parameters:

  • instance

    (Union[Instance, InstancePath]) –

    The instance (or path to an instance) to update in this Circuit.

  • old_type

    (Optional[str], default: None ) –

    A previous instance type, to delete the former reference from Circuit.instances, so that the previous reference does not point to an invalid path. If None, nothing is removed. Defaults to None.

uniquify

uniquify(
    module: Optional[Union[ModuleName, Module]] = None,
    *,
    keep_original_module: bool = False
) -> Dict[InstancePath, ModuleName]

Ensure that every module instance in the circuit has its own unique definition.

When a module is instantiated many times, all instances share the same definition. Any modification to that definition is reflected in every instance, which is often undesirable. This method creates a separate copy of the original module for each instance, updates the instance to refer to its copy, and removes the original definition if it is no longer used.

Each new module definition is named <orig_name>_<index>, where <index> starts at 0 and increments for each instance. The original module is removed from the circuit once it is no longer referenced by any instance. If module is a name that does not exist, ObjectNotFoundError is raised.

Parameters:

  • module

    (Optional[Union[ModuleName, Module]], default: None ) –

    The module to uniquify. If a string is supplied it is treated as the module name and looked up in the circuit. If None the method identifies all modules that appear more than once in self.instances and uniquifies them. Defaults to None.

  • keep_original_module

    (bool, default: False ) –

    Whether to keep the original module(s) that no longer are instantiated anywhere. If True, the original module is kept. If False, the original module and its references in Circuit.instances are removed. Defaults to False.

Returns:

  • Dict[InstancePath, ModuleName]

    Dict[InstancePath, ModuleName]: A dictionary mapping the module instance paths to the new module names. Each module name follows the schema <orig_name>_<index>.

create_blackbox_modules

create_blackbox_modules() -> None

Implements empty modules for all blackbox cells.

This method iterates through all instances of this circuit and checks whether the instance is a blackbox cell. If the instance is a blackbox, this method creates a module with the same interface as the blackbox cell, i.e. the same ports while assuming directions based on common output port names (e.g. Q, QN, Y are common output names). Every port with a name that is not a common output port name is automatically assumed to be an input port.

set_signal

set_signal(path: str, signal_value: LogicLevel) -> None
set_signal(path: str, signal_value: Signal) -> None
set_signal(path: str, signal_value: Union[LogicLevel, Signal]) -> None

Sets the signal of the port or wire (segment) at the given path to the given new signal.

Parameters:

  • path

    (str) –

    The path to the element, whose signal should be set. Must point to an element that supports signal assignment, e.g. a port, wire or a port/wire segment.

  • signal_value

    (Union[LogicLevel, Signal]) –

    A signal value. May be from the Signal enum, or the values 0 and 1 (integers), or the values '0', '1', 'x' or 'z' (strings).

Raises:

write

write(output_file_path: Union[str, Path], overwrite: bool = False) -> None

Writes a Verilog file for this circuit to the given location.

If the output file already exists and overwrite is False, it will raise an error.

Parameters:

  • output_file_path

    (Union[str, Path]) –

    The path to write the Verilog representation of the circuit to.

  • overwrite

    (bool, default: False ) –

    Whether to overwrite a file if it already exists. Defaults to False.

prove_equivalence

prove_equivalence(
    gold_design: List[str],
    out_dir: str,
    eqy_script_path: str = "",
    gold_top_module: str = "",
    quiet: bool = False,
) -> CompletedProcess[bytes]
prove_equivalence(
    gold_design: "Circuit",
    out_dir: str,
    eqy_script_path: str = "",
    gold_top_module: str = "",
    quiet: bool = False,
) -> CompletedProcess[bytes]
prove_equivalence(
    gold_design: Union[List[str], "Circuit"],
    out_dir: str,
    eqy_script_path: str = "",
    gold_top_module: str = "",
    quiet: bool = False,
) -> CompletedProcess[bytes]

Proves equivalence of the circuit against a set of gold Verilog files.

In the context of comparing two digital designs, gold is used to describe a reference design or implementation that is considered to be correct or the "golden reference". The complementary design (i.e. the optimized, modified or synthesized design) is refered to as gate design, as it is often a gate-level implementation of the previously designed circuit. This function compares the gate design with the gold Verilog files to ensure that they are equivalent using Yosys EQY.

Parameters:

  • gold_design

    (Union[List[str], Circuit]) –

    A list of paths to the gold Verilog files. Alternatively, another Circuit object can be provided, which is then used for comparison. In this case, the Circuit object is first converted back to Verilog and then the equivalence check is executed.

  • out_dir

    (str) –

    The directory to write the output files to.

  • eqy_script_path

    (str, default: '' ) –

    The path to the eqy script. If not provided, an eqy script will be generated. Defaults to ''.

  • gold_top_module

    (str, default: '' ) –

    The name of the top module in the gold Verilog files. Defaults to '', in which case the top module will be inferred from this circuit object.

  • quiet

    (bool, default: False ) –

    If True, pipes all Yosys output into the subprocess.CompletedProcess object. If False, prints all Yosys output to the console. Defaults to False.

Returns:

  • CompletedProcess[bytes]

    subprocess.CompletedProcess: The result of the execution plus some metadata.

optimize

optimize() -> bool

Optimizes the circuit by applying optimizations to each module.

Also removes modules that are never instantiated and thus considered unused.

Returns:

  • bool ( bool ) –

    True if at least one optimization was applied to at least one module. False otherwise.

check

check() -> CheckReport

Checks the circuit for issues.

Returns:

  • CheckReport ( CheckReport ) –

    A report with all found issues. bool(CheckReport) returns True if there are issues, and False otherwise.

evaluate

evaluate() -> None

Evaluates the circuit.

This method evaluates the top module in the circuit and all modules that are part of it, in a top-down manner.

export_metadata

export_metadata(
    path: Union[str, Path],
    include_empty: bool = False,
    sort_by: Literal["path", "category"] = "path",
    filter: Callable[[str, NESTED_DICT], bool] = lambda cat, md: True,
) -> None

Writes all metadata from this circuit to a JSON file at the given path.

Parameters:

  • path

    (Union[str, Path]) –

    The path to the JSON file to include the metadata.

  • include_empty

    (bool, default: False ) –

    Whether to include empty subdictionaries (e.g. if an instance does not have metadata). Defaults to False.

  • sort_by

    (Literal[&#39;path&#39;, &#39;category&#39;], default: 'path' ) –

    Whether to sort the metadata by the element's path or by category. Defaults to 'path'.

  • filter

    (Callable[[str, NESTED_DICT], bool], default: lambda cat, md: True ) –

    A filter function that is forwarded to Module.normalize_metadata for each module of this circuit. Defaults to a lambda that always returns True (i.e. no filtering).