Source code for spydrnet.ir.instance

from copy import deepcopy
from collections import OrderedDict
from spydrnet.ir import FirstClassElement
from spydrnet.ir import OuterPin
from spydrnet.ir.views.outerpinsview import OuterPinsView
from spydrnet.global_state import global_callback
from spydrnet.global_state.global_callback import _call_create_instance


class Instance(FirstClassElement):
    """Netlist instance of a netlist definition.

    Instances are literally instances of definitions and they reside inside other definitions.
    Function names have been set to prevent potential confusion that could arise because instances
    have both a parent definition and definitions which they reference.


    :ivar parent: the parent of the object. Parent is the definition that instances another
        definition.
    :ivar child: the instance itself is the child of the parent.
    :ivar reference: the item of the object. Reference is the definition of the instance.

    For example, when writing definition 1, we instance definition 2. Definition 1 is the parent,
    the instance is the child, and definition 2 is the instance's reference.

    """

    __slots__ = ["_parent", "_reference", "_pins", "_is_top_instance"]

[docs] def __init__(self, name=None, properties=None): """Creates an empty object of type instance. parameters ---------- name - (str) the name of this instance properties - (dict) the dictionary which holds the properties """ super().__init__() self._parent = None self._reference = None self._pins = OrderedDict() self._is_top_instance = False _call_create_instance(self) if name is not None: self.name = name if properties is not None: assert isinstance(properties, dict), "properties must be a dictionary" for key in properties: self[key] = properties[key]
@property def parent(self): """Get the definition that contains this instance""" return self._parent def test(self): return True @property def reference(self): """Get the definition that this instance is instantiating""" return self._reference @reference.setter def reference(self, value): """Change the definition that represents this instance. Port positioning and size must be taken into account when a new definition is being used. if they are different the connections cannot be done automatically with this function. parameters ---------- value - (Definition) the definition that this instance should be an instance of """ global_callback._call_instance_reference(self, value) if value is None: for pin in self.pins: wire = pin.wire if wire: wire.disconnect_pin(pin) if isinstance(pin, OuterPin): pin._instance = None pin._inner_pin = None self._pins.clear() if self._reference: self._reference._references.remove(self) else: if self._reference is not None: assert len(self.reference.ports) == len(value.ports) and all( len(x.pins) == len(y.pins) for x, y in zip(self.reference.ports, value.ports) ), "Reference reassignment only supported for definitions with matching \ port positions" self._reference._references.remove(self) for cur_port, new_port in zip(self.reference.ports, value.ports): for cur_pin, new_pin in zip(cur_port.pins, new_port.pins): outer_pin = self._pins.pop(cur_pin) outer_pin._inner_pin = new_pin self._pins[new_pin] = outer_pin else: for port in value.ports: for pin in port.pins: self._pins[pin] = OuterPin(self, pin) value._references.add(self) self._reference = value @reference.deleter def reference(self): self.reference = None
[docs] def get_ports(self, *args, **kwargs): from spydrnet.util.get_ports import get_ports return get_ports(self, *args, **kwargs)
@property def pins(self): """Get the pins on this instance. Can do instance.pins[<inner_pin>] to get the inner pin's associated outer pins. """ return OuterPinsView(self._pins) def _clone_rip_and_replace_in_definition(self, memo): """Slide the outerpins references into a new context. The instance still references something outside of what has been cloned. """ for op in self._pins.values(): op._clone_rip_and_replace(memo) def _clone_rip_and_replace_in_library(self, memo): """Move the instance into a new library/netlist. This will replace the reference if affected and replace the inner pins that will be affected as well. The instance should not be in the references list of the reference definition """ new_pins = OrderedDict() for ip, op in self._pins.items(): new_pins[memo[ip]] = op self._pins = new_pins def _clone_rip(self): """Remove the instance from its current environmnet. This will remove the instance from any wires but it will add it in to the references set on the definition which it instantiates. """ for op in self._pins.values(): op._wire = None self._reference._references.add(self) def _clone(self, memo): """Not api safe clone function clone the instance leaving all references in tact. The instance can then either be ripped or ripped and replaced """ assert ( self not in memo ), "the object should not have been copied twice in this pass" from spydrnet.ir import Instance as InstanceExtended c = InstanceExtended() memo[self] = c c._parent = None for inner_pin, outer_pin in self._pins.items(): new_outer_pin = outer_pin._clone(memo) new_outer_pin._instance = c c._pins[inner_pin] = new_outer_pin c._reference = self._reference c._data = deepcopy(self._data) return c
[docs] def clone(self): """ Clone the instance in an api safe way. This call will return a cloned instance that has the following properties: * the pins in the instance will all be disconnected from wires but they will maintain their references to inner pins * the instance references is the same as the cloned object * the reference's references list contains this instance * the instance is orphaned (no longer a child of the definition to which the cloned definition belonged """ c = self._clone(OrderedDict()) c._clone_rip() return c
def is_leaf(self): """Check to see if the definition that this instance contains represents a leaf cell. Leaf cells are cells with no children instances or no children cables. Blackbox cells are considered leaf cells as well as direct pass through cells with cables only """ if self._reference is None: return False elif len(self._reference._children) > 0 or len(self._reference._cables) > 0: return False return True def is_unique(self): """ Check to see if the instance is unique """ if len(self.reference.references) == 1 or self.reference.is_leaf(): return True else: return False def __str__(self): """Re-define the print function so it is easier to read""" rep = super().__str__() rep = rep[:-1] + "; " if self.parent is None: rep += "parent definition undefined" elif self.parent.name is None: rep += "parent definition.name undefined" else: rep += "parent definition.name '" + self.parent.name + "'" rep += "; " if self.reference is None: rep += "reference definition undefined" elif self.reference.name is None: rep += "reference definition.name undefined" else: rep += "reference definition.name '" + self.reference.name + "'" rep += ">" return rep def __lt__(self, other): return self.name < other.name @property def is_top_instance(self): return self._is_top_instance @is_top_instance.setter def is_top_instance(self, value): self._is_top_instance = value