diff --git a/compiler/base/geometry.py b/compiler/base/geometry.py index 9eedc7f5..d397f7a3 100644 --- a/compiler/base/geometry.py +++ b/compiler/base/geometry.py @@ -292,19 +292,25 @@ class instance(geometry): to both of their respective objects nets_list must be the same length as self.spice_pins """ + if len(nets_list) == 0 and len(self.spice_pins) == 0: + # this is the only valid case to skip the following debug check + # because this with no pins are often connected arbitrarily + self.connected = True + return debug.check(not self.connected, "instance {} has already been connected".format(self.name)) debug.check(len(self.spice_pins) == len(nets_list), "must provide list of nets the same length as pin list\ when connecting an instance") - for i in range(len(self.spice_pins)): - self.spice_pins[i].set_inst_net(nets_list[i]) - nets_list[i].connect_pin(self.spice_pins[i]) + for pin in self.spice_pins.values(): + net = nets_list.pop(0) + pin.set_inst_net(net) + net.connect_pin(pin) self.connected = True def get_connections(self): conns = [] - for pin in self.spice_pins: + for pin in self.spice_pins.values(): conns.append(pin.inst_net.name) return conns diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index d33d552d..f9d3e889 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -629,7 +629,7 @@ class layout(): """ Return a pin list of all pins """ - return self.pins + return list(self.pins) def copy_layout_pin(self, instance, pin_name, new_name="", relative_offset=vector(0, 0)): """ @@ -1523,6 +1523,7 @@ class layout(): """ Return the pin shapes as blockages for non-top-level blocks. """ # FIXME: We don't have a body contact in ptx, so just ignore it for now import copy + # FIXME: this may not work now that self.pins is a dict as defined in hierarchy_spice pin_names = copy.deepcopy(self.pins) if self.name.startswith("pmos") or self.name.startswith("nmos"): pin_names.remove("B") diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index 4803fb65..952fa080 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -90,13 +90,13 @@ class spice(): def add_pin(self, name, pin_type="INOUT"): """ Adds a pin to the pins list. Default type is INOUT signal. """ debug.check(name not in self.pins, "cannot add duplicate spice pin {}".format(name)) - self.pins[name] = pin_spice(name, pin_type) + self.pins[name] = pin_spice(name, pin_type, self) def add_pin_list(self, pin_list, pin_type="INOUT"): """ Adds a pin_list to the pins list """ # The pin type list can be a single type for all pins # or a list that is the same length as the pin list. - if type(pin_type) == str: + if isinstance(pin_type, str): for pin in pin_list: self.add_pin(pin, pin_type) @@ -124,7 +124,7 @@ class spice(): "{} spice subcircuit number of port types does not match number of pins\ \n pin names={}\n port types={}".format(self.name, list(self.pins), type_list)) for pin, type in zip(self.pins.values(), type_list): - pin.set_pin_type(type) + pin.set_type(type) def get_pin_type(self, name): """ Returns the type of the signal pin. """ @@ -212,7 +212,7 @@ class spice(): for name in names_list: # setdefault adds to the dict if it doesn't find the net in it already # then it returns the net it found or created, a net_spice object - net = self.nets.setdefault(name, net_spice(name)) + net = self.nets.setdefault(name, net_spice(name, self)) nets.append(net) return nets @@ -764,9 +764,10 @@ class pin_spice(): self.inst = inst def set_inst_net(self, net): - debug.check(self.inst_net is None, - "pin {} is already connected to net {} so it cannot also be connected to net {}\ - ".format(self.name, self.inst_net.name, net.name)) + if self.inst_net is not None: + debug.error("pin {} is already connected to net {}\ + so it cannot also be connected to net {}\ + ".format(self.name, self.inst_net.name, net.name), 1) debug.check(isinstance(net, net_spice), "net must be a net_spice object") self.inst_net = net @@ -789,6 +790,23 @@ class pin_spice(): """ return self._hash + def __deepcopy__(original, memo): + """ + This function is defined so that instances of modules can make deep + copies of their parent module's pins dictionary. It is only expected + to be called by the instance class __init__ function. Mod and mod_net + should not be deep copies but references to the existing mod and net + objects they refer to in the original. If inst is already defined this + function will throw an error because that means it was called on a pin + from an instance, which is not defined behavior. + """ + debug.check(original.inst is None, + "cannot make a deepcopy of a spice pin from an inst") + pin = pin_spice(original.name, original.type, original.mod) + if original.mod_net is not None: + pin.set_mod_net(original.mod_net) + return pin + class net_spice(): """ @@ -797,9 +815,10 @@ class net_spice(): inst is the instance this net is a part of, if any. """ - def __init__(self, name): + def __init__(self, name, mod): self.name = name self.pins = [] + self.mod = mod self.inst = None # TODO: evaluate if this makes sense... and works @@ -812,9 +831,12 @@ class net_spice(): else: self.pins.append(pin) + def set_inst(self, inst): + self.inst = inst + def __str__(self): """ override print function output """ - return "(pin_name={} type={})".format(self.name, self.type) + return "(net_name={} type={})".format(self.name, self.type) def __repr__(self): """ override repr function output """ @@ -830,3 +852,21 @@ class net_spice(): Provides a speedup if pin_spice is used as a key for dicts. """ return self._hash + + def __deepcopy__(original, memo): + """ + This function is defined so that instances of modules can make deep + copies of their parent module's nets dictionary. It is only expected + to be called by the instance class __init__ function. Mod and mod_net + should not be deep copies but references to the existing mod and net + objects they refer to in the original. If inst is already defined this + function will throw an error because that means it was called on a pin + from an instance, which is not defined behavior. + """ + debug.check(original.inst is None, + "cannot make a deepcopy of a spice net from an inst") + net = net_spice(original.name, original.mod) + if original.pins != []: + # TODO: honestly I'm not sure if this is right but we'll see... + net.pins = original.pins + return net