Skip to content

netlist_carpentry.core.netlist_elements.port

Module for handling of ports (both instance and module ports) inside a circuit module.

Classes:

  • Port

    Represents a port in the netlist.

Port

Bases: NetlistElement, BaseModel, Generic[T_PARENT]

Represents a port in the netlist.

This class is generic to sensibly differentiate between module and instance ports. The value of the generic is derived from module_or_instance and is used mainly for type annotation. If this port belongs to a module, use Port[Module] otherwise use Port[Instance].

Attributes:

  • direction (Direction) –

    The direction of this port.

  • msb_first (bool) –

    Whether the index order of this port is MSB first. Defaults to True.

  • module_or_instance(Optional[Module, (Instance]) –

    The parent object (module or instance) to which this port belongs. Can also be None, in which case the port does not belong to any object initially, but should be assigned to an instance or module later.

Methods:

  • __getitem__

    Allows subscripting of a Port object to access its port segments directly.

  • __len__

    Returns the number of port segments in this port.

  • __iter__

    Iterates over the port segments in this port.

  • __eq__

    Compares this port to another object for equality.

  • set_name

    Renames this port to a new name.

  • create_port_segment

    Creates a port segment and adds it to this port.

  • create_port_segments

    Creates a port segment and adds it to this port.

  • remove_port_segment

    Removes a port segment from this port.

  • get_port_segment

    Returns a PortSegment with the given index from this port.

  • tie_signal

    Ties a signal to a constant value on the specified port segment.

  • set_signal

    Sets the signal of the port segment at the given index to the given new signal.

  • set_signals

    Sets the signals of all port segments at once.

  • count_signals

    Counts the number of occurrences of a given signal in this port's signal array.

  • driver

    Returns the driver of this port if it has one, otherwise None.

  • loads

    Returns the loads of this port as a dictionary of indices with associated port segment lists.

  • set_signed

    Modifies the signedness of this port and returns whether the signedness has changed.

  • change_connection

    Changes the connection of a port segment to the given wire segment path.

  • copy_object

    Creates a copy of this port with a new name.

  • __str__

    Returns a string representation of the port.

  • __repr__

    Returns a concise string representation of the port.

  • evaluate

    Evaluate the element depending on the incoming signals.

direction instance-attribute

direction: Direction

The direction of this port, indicating whether it's an input, output, or bidirectional connection.

msb_first class-attribute instance-attribute

msb_first: bool = True

Whether this port is MSB (most significant bit) first or not

path property

path: PortPath

Returns the PortPath of the netlist element.

The PortPath object is constructed using the element's type and its raw hierarchical path.

Returns:

  • PortPath ( PortPath ) –

    The hierarchical path of the netlist element.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('addr', 'input', width=8)
>>> p.path.raw
'm.addr'

type property

type: EType

The type of the element, which is a port.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('clk', 'input')
>>> p.type is EType.PORT
True

module property

module: 'Module'

The parent module of this port.

For a module port, this returns the immediate parent. For an instance port, it returns the module to which the instance belongs (i.e. the parent of the instance, or the grandparent of this port).

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='top')
>>> p = m.create_port('data', 'input', width=8)
>>> p.module.name
'top'

segments property

Returns the port segments of this port, where the key is the bit index.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=4)
>>> list(p.segments.keys())
[0, 1, 2, 3]

signal property

signal: Signal

Returns the signal associated with this port.

Does only work for 1-bit wide ports, as a convenient alternative for Port.signal_array.

If there's only one segment in the port (i.e. the port is exactly 1 bit wide), returns the signal of that segment. Otherwise, returns Signal.UNDEFINED to indicate ambiguity. This is meant as a shortcut of signal_array[0], since many ports commonly are only 1 bit wide. Thus, this property should only be used for 1-bit wide ports!

Returns:

  • Signal ( Signal ) –

    The signal associated with this port, if this port is 1 bit wide, otherwise returns Signal.UNDEFINED.

Example
>>> from netlist_carpentry import Module, Signal
>>> m = Module(name='m')
>>> p = m.create_port('clk', 'input')
>>> p.signal
UNDEFINED
>>> p.set_signal(Signal.HIGH)
>>> p.signal
HIGH

signal_int property

signal_int: Optional[int]

The signal currently applied to this port as an integer, if possible.

If Port.signed is False, the value is treated as an unsigned signal. If Port.signed is True, the value is treated as a signed signal, using the two's complement, if the sign bit is 1.

Offset is ignored when calculating this property. If a 4 bit port has an offset of 3, the returned integer is built form the actually present segments (i.e. the integer value is between 0 and 15). If segments are missing in between, they will be filled with undefined values. If a port has a segment with index 0 and with index 2, but a segment for index 1 is missing (not to be confused with an unconnected segment), the returned string will have the values of the segments 2 and 0 (in descending order), and Signal.UNDEFINED at index 1. In such case, no integer can be deduced, because of the undefined value at index 1, and None is returned.

If the signal string for a 4 bit port is '1001', then this property will return 9. If the string contains 'x' or 'z', the signal does not form an integer and this property returns None.

Example
>>> from netlist_carpentry import Module, Signal
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=4)
>>> p.set_signals(SignalArray.from_int(5, msb_first=True, fixed_width=4))
>>> p.signal_int
5
>>> p.set_signal(Signal.UNDEFINED, index=2)
>>> p.signal_int  # Contains undefined value

signal_array property

signal_array: SignalArray

Returns an array of signals associated with this port, ordered by bit index.

If the port is empty (i.e., no segments), returns an empty list. Otherwise, returns a list of signals corresponding to each segment in the port, where the index of the list corresponds to the bit index of the segment.

Returns:

  • SignalArray ( SignalArray ) –

    The array of signals associated with each segment of this port.

Example
>>> from netlist_carpentry import Module, Signal
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=4)
>>> p.set_signal(Signal.HIGH, index=0)
>>> p.set_signal(Signal.LOW, index=1)
>>> p.set_signal(Signal.HIGH, index=2)
>>> p.set_signal(Signal.LOW, index=3)
>>> str(p.signal_array)
'0101'

signal_str property

signal_str: str

The signal currently applied to this port as a string (MSB first).

The length of the string corresponds to the width of this port. Offset is ignored by this property. If a 4 bit port has an offset of 3, the returned string only consists of the actually present segments (i.e. the string consists of the signals at the 4 present segments). If segments are missing in between, they will be filled with undefined values. If a port has a segment with index 0 and with index 2, but a segment for index 1 is missing (not to be confused with an unconnected segment), the returned string will have the values of the segments 2 and 0 (in descending order), and Signal.UNDEFINED at index 1.

If the signal string for a 4 bit port is '1010', then the segments with indices 3 and 1 (plus offset) are currently 1 and the other two segments are 0. If the string contains 'x', the corresponding segment has an undefined value, and if the string contains 'z', the corresponding segment is floating.

Example
>>> from netlist_carpentry import Module, Signal
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=4)
>>> p.set_signal(Signal.HIGH, index=0)
>>> p.set_signal(Signal.LOW, index=1)
>>> p.set_signal(Signal.HIGH, index=2)
>>> p.set_signal(Signal.LOW, index=3)
>>> p.signal_str
'0101'

has_undefined_signals property

has_undefined_signals: bool

Whether any of the port's signals are undefined (e.g. "X" or "Z").

False, if the signals on all port segments are either "0" or "1". Otherwise, returns True.

Example
>>> from netlist_carpentry import Module, Signal
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=2)
>>> p.has_undefined_signals
True
>>> p.set_signal(Signal.HIGH, index=0)
>>> p.set_signal(Signal.LOW, index=1)
>>> p.has_undefined_signals
False

is_tied property

is_tied: bool

True if all of the port's segments are tied to a constant (e.g. "0" or "1"). Unconnected ("X") or floating port segments ("Z") are also considered tied in this context. To check if all port segments are tied to "0" or "1", use Port.is_tied_defined.

False, if any segments are connected to a wire.

Example
>>> from netlist_carpentry import Module, Signal
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=2)
>>> p.is_tied  # Unconnected segments are considered tied
True
>>> p.set_signal(Signal.HIGH, index=0)
>>> p.set_signal(Signal.LOW, index=1)
>>> p.is_tied
True

is_tied_partly property

is_tied_partly: bool

True if any of the port's segments are tied to a constant (e.g. "0" or "1"). Unconnected ("X") or floating port segments ("Z") are also considered tied in this context. To check if all port segments are tied to "0" or "1", use Port.is_tied_defined.

False, if all segments are connected to a wire.

Example
>>> from netlist_carpentry import Module, Signal
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input')
>>> w = m.create_wire('w')
>>> p.is_tied_partly  # All unconnected segments are tied
True
>>> m.connect(w, p)
>>> p.is_tied_partly
False

is_connected_partly property

is_connected_partly: bool

Determines whether the port is partly connected.

A port is considered partly connected if at least one of its segments is connected to a wire.

Returns:

  • bool ( bool ) –

    True if at least one segment is connected, False otherwise.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=4)
>>> p.is_connected_partly
False
>>> wire = m.create_wire('w', width=4)
>>> m.connect(wire, p, new_wire_name='w')
>>> p.is_connected_partly
True

is_connected property

is_connected: bool

Determines whether the port is fully connected.

A port is considered fully connected if all of its segments are connected to a wire.

Returns:

  • bool ( bool ) –

    True if all segments are connected, False otherwise.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=4)
>>> p.is_connected
False
>>> wire = m.create_wire('w', width=4)
>>> m.connect(wire, p, new_wire_name='w')
>>> p.is_connected
True

is_unconnected property

is_unconnected: bool

Determines whether the port is completely unconnected.

A port is considered completely unconnected if none of its segments are connected to a wire.

Returns:

  • bool ( bool ) –

    True if no segments are connected, False otherwise.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=4)
>>> p.is_unconnected
True
>>> wire = m.create_wire('w', width=4)
>>> m.connect(wire, p, new_wire_name='w')
>>> p.is_unconnected
False

is_unconnected_partly property

is_unconnected_partly: bool

Determines whether the port is partly unconnected.

A port is considered partly unconnected if at least one of its segments is unconnected.

Returns:

  • bool ( bool ) –

    True if at least one segment is unconnected, False otherwise.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=4)
>>> p.is_unconnected_partly  # All segments unconnected
True
>>> wire = m.create_wire('w', width=4)
>>> m.connect(wire, p, new_wire_name='w')
>>> p.is_unconnected_partly  # All segments now connected
False

is_floating property

is_floating: bool

Determines whether the port is completely floating.

A port is considered completely floating if all of its segments are floating.

Returns:

  • bool ( bool ) –

    True if all segments are floating, False otherwise.

Example
>>> from netlist_carpentry import Module, Signal
>>> m = Module(name='m')
>>> p = m.create_port('data', 'output', width=2)
>>> p.is_floating  # Unconnected segments are not floating (by default signal is X, not Z)
False
>>> p.tie_signal(Signal.FLOATING, index=0)
>>> p.tie_signal(Signal.FLOATING, index=1)
>>> p.is_floating  # Both segments are floating
True
>>> w = m.create_wire('w', width=2)
>>> m.connect(w, p)
>>> p.is_floating  # Connected to wire, not floating
False

is_floating_partly property

is_floating_partly: bool

Determines whether the port is partly floating.

A port is considered partly floating if at least one of its segments is floating.

Returns:

  • bool ( bool ) –

    True if at least one segment is floating, False otherwise.

Example
>>> from netlist_carpentry import Module, Signal
>>> m = Module(name='m')
>>> p = m.create_port('data', 'output', width=4)
>>> p.is_floating_partly  # Unconnected segments are not floating (by default signal is X, not Z)
False
>>> p.tie_signal(Signal.FLOATING, index=0)
>>> p.is_floating_partly  # One segment is floating
True

is_tied_defined property

is_tied_defined: bool

True if all segments are tied to a defined value (0 or 1), False otherwise.

Example
>>> from netlist_carpentry import Module, Signal
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=2)
>>> p.is_tied_defined  # Unconnected segments are not defined
False
>>> w = m.create_wire('w', width=2)
>>> m.connect(w, p)
>>> p.is_tied_defined  # Connected to wire, not tied to constant
False

is_tied_defined_partly property

is_tied_defined_partly: bool

True if at least one segment is tied to a defined value (0 or 1), False otherwise.

Example
>>> from netlist_carpentry import Module, Signal
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=4)
>>> p.is_tied_defined_partly  # All unconnected
False
>>> w = m.create_wire('w', width=4)
>>> m.connect(w, p)
>>> p.is_tied_defined_partly  # Connected to wire, not tied to constant
False

is_tied_undefined property

is_tied_undefined: bool

True if all segments are tied to an undefined value (X or Z), False otherwise.

If True, every segment is either unconnected or floating. Can also be mixed. If False, at least one segment is either connected or tied to 0 or 1.

Example
>>> from netlist_carpentry import Module, Signal
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=2)
>>> p.is_tied_undefined  # Unconnected segments are undefined
True
>>> w = m.create_wire('w', width=2)
>>> m.connect(w, p, new_wire_name='w')
>>> p.is_tied_undefined  # Connected to wire, not tied to undefined
False

is_tied_undefined_partly property

is_tied_undefined_partly: bool

True if at least one segment is tied to an undefined value (X or Z), False otherwise.

If True, at least one segment is either unconnected or floating. If False, all segments are either connected or tied to 0 or 1.

Example
>>> from netlist_carpentry import Module, Signal
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=4)
>>> p.is_tied_undefined_partly  # All unconnected
True
>>> w = m.create_wire('w', width=4)
>>> m.connect(w, p, new_wire_name='w')
>>> p.is_tied_undefined_partly  # All connected to wire
False

width property

width: int

The width of the port in bits, which is simply the number of port segments in the port.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p1 = m.create_port('clk', 'input')
>>> p1.width
1
>>> p2 = m.create_port('data', 'input', width=8)
>>> p2.width
8

offset property

offset: Optional[int]

The minimum segment index of this port, or None if the port has no segments.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=4)
>>> p.offset
0

lsb_first property

lsb_first: bool

Whether the LSB (least significant bit) comes first.

This property is coupled with Port.msb_first. To change this value, change Port.msb_first, and this property is updated accordingly.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=4)
>>> p.lsb_first  # Default is MSB first
False
>>> p.msb_first = False
>>> p.lsb_first
True

signed property

signed: bool

Whether this port is signed.

Normally, signed should only be either 0 or 1, but treat non-zero cases as signed (e.g. '1'/'0' or True/False).

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=8)
>>> p.signed
False
>>> p.set_signed(True)
True
>>> p.signed
True

unsigned property

unsigned: bool

Whether this port is unsigned (i.e., not signed).

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=8)
>>> p.unsigned
True
>>> p.set_signed(True)
True
>>> p.unsigned
False

is_instance_port property

is_instance_port: bool

Whether this port is an instance port.

True, if this port is an instance port. False, if this port is a module port.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('clk', 'input')
>>> p.is_instance_port
False

is_module_port property

is_module_port: bool

Whether this port is a module port.

True, if this port is a module port. False, if this port is an instance port.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('clk', 'input')
>>> p.is_module_port
True

is_input property

is_input: bool

Whether this port is an input port.

Returns:

  • bool ( bool ) –

    True if this port is an input port, False otherwise.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p_in = m.create_port('a', 'input')
>>> p_in.is_input
True
>>> p_out = m.create_port('b', 'output')
>>> p_out.is_input
False

is_output property

is_output: bool

Whether this port is an output port.

Returns:

  • bool ( bool ) –

    True if this port is an output port, False otherwise.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p_out = m.create_port('b', 'output')
>>> p_out.is_output
True
>>> p_in = m.create_port('a', 'input')
>>> p_in.is_output
False

is_driver property

is_driver: bool

Whether this port is a driver port, i.e. a port driving a signal.

A driver port is an input port of a module, or an output port of an instance.

Returns:

  • bool ( bool ) –

    True if this port is a driver port, False otherwise.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p_in = m.create_port('a', 'input')
>>> p_in.is_driver  # Module input is a driver
True
>>> p_out = m.create_port('b', 'output')
>>> p_out.is_driver  # Module output is a load
False

is_load property

is_load: bool

Whether this port is a load port, i.e. a port being driven by a signal.

A load port is an output port of a module, or an input port of an instance.

Returns:

  • bool ( bool ) –

    True if this port is a load port, False otherwise.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p_out = m.create_port('b', 'output')
>>> p_out.is_load  # Module output is a load
True
>>> p_in = m.create_port('a', 'input')
>>> p_in.is_load  # Module input is a driver
False

connected_wire_segments property

connected_wire_segments: Dict[NonNegativeInt, WireSegmentPath]

Returns a dictionary of paths of wire segments connected to this port.

A port is considered connected to a wire segment if at least one of its segments is connected to that wire segment.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=2)
>>> p.connected_wire_segments  # Unconnected segments show empty path
{0: WireSegmentPath X, 1: WireSegmentPath X}
>>> wire = m.create_wire('w', width=2)
>>> m.connect(wire, p, new_wire_name='w')
>>> p.connected_wire_segments
{0: WireSegmentPath m.w.0, 1: WireSegmentPath m.w.1}

connected_wires property

connected_wires: Set[WirePath]

Returns a set of paths of wires connected to this port.

A port is considered connected to a wire if at least one of its segments is connected to that wire.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=2)
>>> len(p.connected_wires)
0
>>> wire = m.create_wire('w', width=2)
>>> m.connect(wire, p, new_wire_name='w')
>>> len(p.connected_wires)
1

is_connected_1to1 property

is_connected_1to1: bool

True if this port is connected completely to a certain wire.

True if this conforms to the Verilog expression assign port = wire;. False, if this conforms to other cases including bit slicing or concatenation, e.g. assign port[1:0] = {wire1, wire2}

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=4)
>>> p.is_connected_1to1  # Not connected yet
False
>>> wire = m.create_wire('w', width=4)
>>> m.connect(wire, p, new_wire_name='w')
>>> p.is_connected_1to1  # Connected 1-to-1
True

name instance-attribute

name: str

The name of the element.

!!! Do not modify this variable after instantiating it. Use NetlistElement.set_name() instead. Modifying this variable might lead to inconsistencies later on.

metadata class-attribute instance-attribute

Metadata of a netlist element.

Can be user-defined, or e. g. by Yosys (such as src for the HDL source). Is also grouped by categories, i.e. all metadata from Yosys can be accessed via Module.metadata["yosys"], or via Module.metadata.yosys, which both return a dictionary of all metadata. Read the documentation of MetaDataMixin for more information.

hierarchy_level property

hierarchy_level: int

The level of hierarchy of the element in the design.

The hierarchy level is the number of separators in the element's raw path. For example, a top-level instance has a hierarchy level of 0, while a direct submodule instance has a hierarchy level of 1.

Returns:

  • int ( int ) –

    The hierarchy level of the element.

has_parent property

has_parent: bool

Whether this object has a parent.

circuit property

circuit: 'Circuit'

The circuit object to which this netlist element belongs to.

  • For a module, returns the circuit to which the module belongs.
  • For any other netlist element, recursively returns the circuit of the parent, which ultimately leads to a module, to which the netlist element belongs.

Raises:

  • ParentNotFoundError

    If a parent cannot be resolved somewhere in the hierarchical chain.

  • ObjectNotFoundError

    If for a module no circuit is set.

has_circuit property

has_circuit: bool

Whether this netlist element has a defined circuit it belongs to.

Tries to access self.circuit and returns whether the call was successful. Can be used instead of a try-except clause around the call to NetlistElement.circuit.

locked property

locked: bool

True if this NetlistElement instance is locked (i.e. it is currently structurally unchangeable), False if it is mutable.

Can be changed via NetlistElement.change_mutability(bool).

Immutability is used to prevent accidental changes to the design.

is_placeholder_instance property

is_placeholder_instance: bool

A placeholder represents an element that does not have a specific path.

True if this NetlistElement instance represents a placeholder, False otherwise.

can_carry_signal property

can_carry_signal: bool

Whether this exact object is able to receive, pass or hold signal values.

True for ports (as they drive or receive values) and wires (as they pass the signals from driver to load ports) as well as their respective segments. False for instances and modules.

__getitem__

__getitem__(index: int) -> PortSegment

Allows subscripting of a Port object to access its port segments directly.

This is mainly for convenience, to use Port[i] instead of Port.segments[i].

Parameters:

  • index

    (int) –

    The index of the desired port segment.

Returns:

  • PortSegment ( PortSegment ) –

    The port segment at the specified index.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('p', 'input', width=4)
>>> p[0]
PortSegment(m.p.0, Signal:x)
>>> p[3]
PortSegment(m.p.3, Signal:x)

__len__

__len__() -> int

Returns the number of port segments in this port.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=8)
>>> len(p)
8

__iter__

__iter__() -> Generator[Tuple[int, PortSegment], None, None]

Iterates over the port segments in this port.

Yields:

  • Tuple[int, PortSegment]

    Tuple[int, PortSegment]: A tuple of (index, PortSegment) for each segment.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=3)
>>> list(p)
[(0, PortSegment(m.data.0, Signal:x)), (1, PortSegment(m.data.1, Signal:x)), (2, PortSegment(m.data.2, Signal:x))]

__eq__

__eq__(value: object) -> bool

Compares this port to another object for equality.

Two ports are considered equal if they have the same name and the same parent.

Parameters:

  • value

    (object) –

    The object to compare with this port.

Returns:

  • bool ( bool ) –

    True if the other object is a port with the same name and parent, False otherwise.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p1 = m.create_port('clk', 'input')
>>> p1 == p1  # Same object
True
>>> p1 == "not a port"
False

set_name

set_name(new_name: str) -> None

Renames this port to a new name.

For module ports, the associated wire is also renamed if it exists.

Parameters:

  • new_name

    (str) –

    The new name for this port.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('old_name', 'input')
>>> p.name
'old_name'
>>> p.set_name('new_name')
>>> p.name
'new_name'

create_port_segment

create_port_segment(index: NonNegativeInt) -> PortSegment

Creates a port segment and adds it to this port.

Parameters:

  • index

    (NonNegativeInt) –

    The index for which a PortSegment should be created and added to this port.

Returns:

  • PortSegment ( PortSegment ) –

    The PortSegment that was created and added to this port.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=2)
>>> len(p.segments)
2
>>> p.create_port_segment(index=2)
PortSegment(m.data.2, Signal:x)
>>> len(p.segments)
3

create_port_segments

create_port_segments(
    count: PositiveInt, offset: NonNegativeInt = 0
) -> Dict[int, PortSegment]

Creates a port segment and adds it to this port.

The number of port segments can be specified via count, which will create and add exactly this much port segments (in ascending order) to this port. With offset, the start index can be set

Parameters:

  • count

    (PositiveInt) –

    The amount of PortSegments to be created and added to this port.

  • offset

    (NonNegativeInt, default: 0 ) –

    The index from which the generated port segments start.

Returns:

  • Dict[int, PortSegment]

    List[PortSegment]: A list of PortSegment objects created and added to this port.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=2)
>>> segs = p.create_port_segments(3, offset=10)
>>> sorted(segs.keys())
[10, 11, 12]

remove_port_segment

remove_port_segment(index: NonNegativeInt) -> None

Removes a port segment from this port.

Parameters:

  • index

    (NonNegativeInt) –

    The index of the PortSegment to remove from this port.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=3)
>>> len(p.segments)
3
>>> p.remove_port_segment(1)
>>> len(p.segments)
2

get_port_segment

get_port_segment(index: NonNegativeInt) -> Optional[PortSegment]

Returns a PortSegment with the given index from this port.

Parameters:

  • index

    (NonNegativeInt) –

    The index of the PortSegment to retrieve from this port.

Returns:

  • Optional[PortSegment]

    Optional[PortSegment]: The PortSegment with the given index, or None if no port segment with that index exists.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=4)
>>> p.get_port_segment(2)
PortSegment(m.data.2, Signal:x)
>>> p.get_port_segment(10) is None
True

tie_signal

tie_signal(signal: LogicLevel, index: Optional[NonNegativeInt] = None) -> None
tie_signal(signal: Signal, index: Optional[NonNegativeInt] = None) -> None
tie_signal(
    signal: SignalOrLogicLevel, index: Optional[NonNegativeInt] = None
) -> None

Ties a signal to a constant value on the specified port segment.

If index is None, the whole port gets tied to the given signal. If the specified index corresponds to an existing port segment, ties its constant signal value and returns True. Otherwise it raises an ObjectNotFoundError.

If signal is X, which is interpreted as UNDEFINED, the port segment is unconnected to achieve this.

Does not work for instance output ports, as they are always driven by their parent instances.

Parameters:

  • signal

    (SignalOrLogicLevel) –

    The new constant signal value. 'X' unconnects the port.

  • index

    (NonNegativeInt, default: None ) –

    The bit index of the port segment. Defaults to None, in which case the whole port is tied to the given signal.

Raises:

  • ObjectNotFoundError

    If no segment with the given index exists.

  • AlreadyConnectedError

    (raised by: PortSegment.tie_signal) If this segment is belongs to a load port and is already connected to a wire, from which it receives its value.

  • InvalidDirectionError

    (raised by: PortSegment.tie_signal) If this port segment belongs to an instance output port, which is driven by the instance inputs and the instance's internal logic.

  • InvalidSignalError

    (raised by: PortSegment.tie_signal) If an invalid value is provided.

Example
>>> from netlist_carpentry import Module, Signal
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=2)
>>> p.tie_signal(Signal.HIGH, index=0)
>>> p[0].is_tied
True
>>> p.tie_signal(Signal.LOW, index=1)
>>> p[1].is_tied
True

set_signal

set_signal(signal: LogicLevel, index: Optional[NonNegativeInt] = None) -> None
set_signal(signal: Signal, index: Optional[NonNegativeInt] = None) -> None
set_signal(
    signal: SignalOrLogicLevel, index: Optional[NonNegativeInt] = None
) -> None

Sets the signal of the port segment at the given index to the given new signal.

If index is None, the whole port gets tied to the given signal.

Does only work for NON-CONSTANT port segments! This method is intended to be used in the signal evaluation process, where constant signals should be treated accordingly. Accordingly, it should be avoided that constant inputs are accidentally modified during signal evaluation. To change the signal of a port segment to be a constant value, use the tie_signal method instead.

Parameters:

  • signal

    (SignalOrLogicLevel) –

    The new signal to set on the port segment.

  • index

    (NonNegativeInt, default: None ) –

    The index of the port segment to set the signal on. Defaults to None, in which case the whole port is set to the given signal.

Raises:

  • IndexError

    If the index is out of range of the port's segments.

Example
>>> from netlist_carpentry import Module, Signal
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=4)
>>> p.set_signal(Signal.HIGH, index=0)
>>> p.set_signal(Signal.LOW, index=1)
>>> p.set_signal(Signal.HIGH, index=2)
>>> p.set_signal(Signal.LOW, index=3)
>>> p.signal_str
'0101'
>>> p.set_signal(Signal.HIGH)
>>> p.signal_str
'1111'

set_signals

set_signals(signal: int) -> None
set_signals(signal: str) -> None
set_signals(signal: SignalArray) -> None
set_signals(signal: Union[int, str, SignalArray]) -> None

Sets the signals of all port segments at once.

Accepts an integer (treated as unsigned), a binary string, or a SignalArray. The signals are applied to all segments of the port.

Parameters:

  • signal

    (Union[int, str, SignalArray]) –

    The signal value to set. An int is treated as an unsigned integer, a str as a binary string, and SignalArray is used directly.

Example
>>> from netlist_carpentry import Module, Signal
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=4)
>>> p.set_signals(10)  # decimal 10 in binary is 1010
>>> p.signal_str
'1010'
>>> p.set_signals('1100')
>>> p.signal_str
'1100'

count_signals

count_signals(target_signal: Signal) -> NonNegativeInt

Counts the number of occurrences of a given signal in this port's signal array.

Parameters:

  • target_signal

    (Signal) –

    The signal to count occurrences of.

Returns:

  • NonNegativeInt ( NonNegativeInt ) –

    The number of times the target signal appears in this port's signal array.

Example
>>> from netlist_carpentry import Module
>>> module = Module(name='m')
>>> port = module.create_port('p', direction='input', width=3)
>>> port.set_signal(Signal.HIGH, index=0)
>>> port.set_signal(Signal.HIGH, index=1)
>>> port.set_signal(Signal.LOW, index=2)
>>> port.count_signals(Signal.HIGH)
2
>>> port.count_signals(Signal.LOW)
1

driver

driver(single: Literal[True]) -> ANY_PORT
driver(single: Literal[False]) -> Dict[NonNegativeInt, Optional[PortSegment]]
driver() -> Dict[NonNegativeInt, Optional[PortSegment]]
driver(
    single: bool = False,
) -> Union[ANY_PORT, Dict[NonNegativeInt, Optional[PortSegment]]]

Returns the driver of this port if it has one, otherwise None.

Can only be retrieved if this port is a load port.

Parameters:

  • single

    (bool, default: False ) –

    Whether to return a single port, but this only works if each segment of this port is connected to the same port. Defaults to False.

Raises:

  • InvalidDirectionError

    If this port is a signal driving port.

  • WidthMismatchError

    Only if single is True: May happen if at least one index is undriven, or if this port is driven by different ports for different segments.

Returns:

  • Union[ANY_PORT, Dict[NonNegativeInt, Optional[PortSegment]]]

    Union[ANY_PORT, Dict[NonNegativeInt, Optional[PortSegment]]]: Either a single port that drives this port (if single is True), or a dictionary containing the driver (which is the opposing port segment) for each segment of this port. If the entry is None, then the corresponding port segment is undriven.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p_in = m.create_port('a', 'input')
>>> p_out = m.create_port('b', 'output')
>>> m.connect(p_in, p_out)
>>> p_in.driver()  # Module input ports are drivers, cannot get their driver
Traceback (most recent call last):
...
netlist_carpentry.core.exceptions.InvalidDirectionError: Cannot get driving port of port m.a: This port is a driver and thus does not have a driver!
>>> p_out.driver()  # Module output ports are loads, can retrieve their driver
{0: PortSegment(m.a.0, Signal:x)}

loads

loads() -> Dict[NonNegativeInt, List[PortSegment]]

Returns the loads of this port as a dictionary of indices with associated port segment lists.

If this port itself is a load port, it is also included into the list of load for each segment.

Returns:

  • Dict[NonNegativeInt, List[PortSegment]]

    Dict[NonNegativeInt, List[PortSegment]]: A dict of all indices mapped to port segments that receive the same signal via the same wire. If this port itself is a load port, it is also included into the list of load for each segment.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p_in = m.create_port('a', 'input')
>>> p_out = m.create_port('b', 'output')
>>> m.connect(p_in, p_out)
>>> p_in.loads()
{0: [PortSegment(m.b.0, Signal:x)]}
>>> p_out.loads()  # Returns itself as part of the loads, since it is a load port itself
{0: [PortSegment(m.b.0, Signal:x)]}

set_signed

set_signed(signed: bool) -> bool

Modifies the signedness of this port and returns whether the signedness has changed.

Parameters:

  • signed

    (bool) –

    The new signedness of this port. If True, the port is now signed. If False, the port is now unsigned

Returns:

  • bool ( bool ) –

    True if the signedness was changed (i.e. the new value is different from the previous value), False otherwise.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=8)
>>> p.set_signed(True)  # Changed from unsigned to signed
True
>>> p.set_signed(True)  # Already signed, no change
False
>>> p.set_signed(False)  # Changed back to unsigned
True

change_connection

change_connection(
    new_wire_segment_path: WireSegmentPath, index: Optional[NonNegativeInt] = 0
) -> None

Changes the connection of a port segment to the given wire segment path.

Parameters:

  • new_wire_segment_path

    (WireSegmentPath) –

    The new wire segment path to connect the port segment to.

  • index

    (int, default: 0 ) –

    The index of the port segment to change the connection for. Defaults to 0.

Note

If index is None, changes the connections of all segments in this port to the same given wire segment.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=2)
>>> w1 = m.create_wire('w1', width=2)
>>> w2 = m.create_wire('w2', width=2)
>>> m.connect(w1, p, new_wire_name='w1')
>>> p.connected_wire_segments
{0: WireSegmentPath m.w1.0, 1: WireSegmentPath m.w1.1}

copy_object

copy_object(new_name: str) -> Port[T_PARENT]

Creates a copy of this port with a new name.

The copied port has the same direction, width, and offset as the original, but is initially unconnected. Raises an error if the new name is already in use.

Parameters:

  • new_name

    (str) –

    The name for the copied port.

Returns:

  • Port[T_PARENT]

    Port[T_PARENT]: A new Port object with the given name.

Raises:

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p1 = m.create_port('data', 'input', width=4)
>>> p2 = p1.copy_object('data_copy')
>>> p2.name
'data_copy'
>>> p2.width
4
>>> p2.is_unconnected
True

__str__

__str__() -> str

Returns a string representation of the port.

Returns:

  • str ( str ) –

    A string in the format 'Port "name" with path ( port)'.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=4)
>>> str(p)
'Port "data" with path m.data (input port)'

__repr__

__repr__() -> str

Returns a concise string representation of the port.

Returns:

  • str ( str ) –

    A string in the format 'Port( , bit)'.

Example
>>> from netlist_carpentry import Module
>>> m = Module(name='m')
>>> p = m.create_port('data', 'input', width=4)
>>> repr(p)
'Port(input data, 4 bit)'

evaluate

evaluate() -> None

Evaluate the element depending on the incoming signals.

This is used for instances, which have some sort of transfer function. The combination of input signals and the transfer function determine the output signal. For simple gate instances, such as AND and OR gates, this is trivial, as the transfer function is just a small truth table. Complex structures, like submodules, are comprised of other instances, which are evaluated recursively, down to the leaf instances, which in return are primitive gates. Thus, to evaluate a module, first all of its submodules and gates are evaluated, to calculate the output signals of the module.

Raises: