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.
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.
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__
¶
Returns a module from the circuit that has the given name.
add_module
¶
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:
create_module
¶
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
¶
Removes a module from the circuit.
Parameters:
Raises:
-
ObjectNotFoundError–If no such module exists in this circuit.
get_module
¶
get_module(module_name: ModuleName) -> Optional[Module]
get_module_at_idx
¶
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:
set_top
¶
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
Nonewill just remove the current top module selection, and no module will be top module.
Raises:
-
ObjectNotFoundError–If no module exists with the given name.
get_from_path
¶
get_from_path(path: str) -> NetlistElement
get_from_path(path: InstancePath) -> Instance
get_from_path(path: PortSegmentPath) -> PortSegment
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
¶
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
¶
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
Nonethe method identifies all modules that appear more than once inself.instancesand uniquifies them. Defaults toNone. -
(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.instancesare 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
¶
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
0and1(integers), or the values'0','1','x'or'z'(strings).
Raises:
-
SignalAssignmentError–If an object was provided that does not support signal assignment.
write
¶
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:
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
¶
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
¶
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['path', 'category'], 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_metadatafor each module of this circuit. Defaults to a lambda that always returns True (i.e. no filtering).