From cd1b0f973d6c60452734a2df1610498fa51f1b88 Mon Sep 17 00:00:00 2001 From: Sam Crow Date: Mon, 14 Aug 2023 18:30:40 -0700 Subject: [PATCH] Revert pin/net spice object work This reverts commits 01116 6e3e9 2ced8 c67fd 2b9e7 bfabe 09aa3 5907c aa717 478c7 45b88 d0339 e15fe 7581d c8c43 146ef --- compiler/base/contact.py | 2 + compiler/base/design.py | 8 +- compiler/base/geometry.py | 54 +--- compiler/base/hierarchy_design.py | 18 +- compiler/base/hierarchy_layout.py | 4 +- compiler/base/hierarchy_spice.py | 407 ++++++++++------------------- compiler/base/lef.py | 2 +- compiler/modules/column_decoder.py | 2 +- compiler/modules/pbitcell.py | 2 +- 9 files changed, 166 insertions(+), 333 deletions(-) diff --git a/compiler/base/contact.py b/compiler/base/contact.py index 84f60d0e..5fe59bcb 100644 --- a/compiler/base/contact.py +++ b/compiler/base/contact.py @@ -66,6 +66,8 @@ class contact(hierarchy_design): self.offset = vector(0, 0) self.implant_type = implant_type self.well_type = well_type + # Module does not have pins, but has empty pin list. + self.pins = [] self.create_layout() def create_layout(self): diff --git a/compiler/base/design.py b/compiler/base/design.py index 69d213d0..87030d4c 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -41,17 +41,17 @@ class design(hierarchy_design): if prop and prop.hard_cell: # The pins get added from the spice file, so just check # that they matched here - debug.check(prop.port_names == list(self.pins), - "Custom cell pin names do not match spice file:\n{0} vs {1}".format(prop.port_names, list(self.pins))) + debug.check(prop.port_names == self.pins, + "Custom cell pin names do not match spice file:\n{0} vs {1}".format(prop.port_names, self.pins)) self.add_pin_indices(prop.port_indices) self.add_pin_names(prop.port_map) - self.update_pin_types(prop.port_types) + self.add_pin_types(prop.port_types) (width, height) = utils.get_libcell_size(self.cell_name, GDS["unit"], layer[prop.boundary_layer]) - self.pin_map = utils.get_libcell_pins(list(self.pins), + self.pin_map = utils.get_libcell_pins(self.pins, self.cell_name, GDS["unit"]) diff --git a/compiler/base/geometry.py b/compiler/base/geometry.py index e8589266..9e7172bf 100644 --- a/compiler/base/geometry.py +++ b/compiler/base/geometry.py @@ -161,8 +161,8 @@ class geometry: class instance(geometry): """ - An instance of a module with a specified location, rotation, - spice pins, and spice nets + An instance of an instance/module with a specified location and + rotation """ def __init__(self, name, mod, offset=[0, 0], mirror="R0", rotate=0, is_bitcell=False): """Initializes an instance to represent a module""" @@ -177,18 +177,6 @@ class instance(geometry): self.offset = vector(offset).snap_to_grid() self.mirror = mirror self.is_bitcell = is_bitcell - # track if the instance's spice pin connections have been made - self.connected = False - - # deepcopy because this instance needs to - # change attributes in these spice objects - self.spice_pins = copy.deepcopy(self.mod.pins) - self.spice_nets = copy.deepcopy(self.mod.nets) - for pin in self.spice_pins.values(): - pin.set_inst(self) - for net in self.spice_nets.values(): - net.set_inst(self) - if OPTS.netlist_only: self.width = 0 self.height = 0 @@ -200,17 +188,9 @@ class instance(geometry): self.width = round_to_grid(mod.width) self.height = round_to_grid(mod.height) self.compute_boundary(offset, mirror, rotate) + debug.info(4, "creating instance: " + self.name) - def __deepcopy__(original, memo): - new_inst = instance(original.name+"_copy", original.mod) - new_inst.rotate = original.rotate - new_inst.offset = original.offset - new_inst.mirror = original.mirror - new_inst.is_bitcell = original.is_bitcell - return new_inst - - def get_blockages(self, lpp, top=False): """ Retrieve blockages of all modules in this instance. Apply the transform of the instance placement to give absolute blockages.""" @@ -295,34 +275,6 @@ class instance(geometry): new_pins.append(p) return new_pins - def connect_spice_pins(self, nets_list): - """ - add the connection between instance pins and module nets - 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 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.values(): - conns.append(pin.inst_net.name) - return conns - def calculate_transform(self, node): #set up the rotation matrix angle = math.radians(float(node.rotate)) diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py index 31a1e191..42c0543d 100644 --- a/compiler/base/hierarchy_design.py +++ b/compiler/base/hierarchy_design.py @@ -135,11 +135,11 @@ class hierarchy_design(spice, layout): # Translate port names to external nets if len(port_nets) != len(self.pins): debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets, - list(self.pins)), + self.pins), 1) - port_dict = {pin: port for pin, port in zip(list(self.pins), port_nets)} + port_dict = {pin: port for pin, port in zip(self.pins, port_nets)} debug.info(3, "Instance name={}".format(inst_name)) - for subinst, conns in zip(self.insts, self.get_instance_connections()): + for subinst, conns in zip(self.insts, self.conns): if subinst in self.graph_inst_exclude: continue subinst_name = inst_name + "{}x".format(OPTS.hier_seperator) + subinst.name @@ -153,11 +153,11 @@ class hierarchy_design(spice, layout): # Translate port names to external nets if len(port_nets) != len(self.pins): debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets, - list(self.pins)), + self.pins), 1) - port_dict = {pin: port for pin, port in zip(list(self.pins), port_nets)} + port_dict = {pin: port for pin, port in zip(self.pins, port_nets)} debug.info(3, "Instance name={}".format(inst_name)) - for subinst, conns in zip(self.insts, self.get_instance_connections()): + for subinst, conns in zip(self.insts, self.conns): subinst_name = inst_name + "{}x".format(OPTS.hier_seperator) + subinst.name subinst_ports = self.translate_nets(conns, port_dict, inst_name) for si_port, conn in zip(subinst_ports, conns): @@ -186,7 +186,7 @@ class hierarchy_design(spice, layout): """ # The final pin names will depend on the spice hierarchy, so # they are passed as an input. - pin_dict = {pin: port for pin, port in zip(list(self.pins), port_nets)} + pin_dict = {pin: port for pin, port in zip(self.pins, port_nets)} input_pins = self.get_inputs() output_pins = self.get_outputs() inout_pins = self.get_inouts() @@ -197,7 +197,7 @@ class hierarchy_design(spice, layout): def __str__(self): """ override print function output """ - pins = ",".join(list(self.pins)) + pins = ",".join(self.pins) insts = [" {}".format(x) for x in self.insts] objs = [" {}".format(x) for x in self.objs] s = "********** design {0} **********".format(self.cell_name) @@ -208,7 +208,7 @@ class hierarchy_design(spice, layout): def __repr__(self): """ override print function output """ - text="( design: " + self.name + " pins=" + str(list(self.pins)) + " " + str(self.width) + "x" + str(self.height) + " )\n" + text="( design: " + self.name + " pins=" + str(self.pins) + " " + str(self.width) + "x" + str(self.height) + " )\n" for i in self.objs: text+=str(i) + ",\n" for i in self.insts: diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 2b636d47..8c595254 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -479,6 +479,7 @@ class layout(): def add_existing_inst(self, inst, name): new_inst = deepcopy(inst) + new_inst.mod = inst.mod self.mods.add(new_inst.mod) if name: new_inst.name = name @@ -640,7 +641,7 @@ class layout(): """ Return a pin list of all pins """ - return list(self.pins) + return self.pins def copy_layout_pin(self, instance, pin_name, new_name="", relative_offset=vector(0, 0)): """ @@ -1534,7 +1535,6 @@ 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 2294208e..64dc0b2b 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -13,7 +13,6 @@ from pprint import pformat from openram import debug from openram import tech from openram import OPTS -from collections import OrderedDict from .delay_data import delay_data from .wire_spice_model import wire_spice_model from .power_data import power_data @@ -50,18 +49,20 @@ class spice(): if not os.path.exists(self.lvs_file): self.lvs_file = self.sp_file + self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "BIAS", "POWER", "GROUND"] # Holds subckts/mods for this module self.mods = set() # Holds the pins for this module (in order) - # on Python3.7+ regular dictionaries guarantee order too, but we allow use of v3.5+ - self.pins = OrderedDict() + self.pins = [] + # The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND + # for each instance, this is the set of nets/nodes that map to the pins for this instance + self.pin_type = {} # An (optional) list of indices to reorder the pins to match the spice. self.pin_indices = [] # THE CONNECTIONS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the # Spice format) - # internal nets, which may or may not be connected to pins of the same name - self.nets = {} - # If this is set, it will not output subckt or instances of this (for row/col caps etc.) + self.conns = [] + # If this is set, it will out output subckt or isntances of this (for row/col caps etc.) self.no_instances = False # If we are doing a trimmed netlist, these are the instance that will be filtered self.trim_insts = set() @@ -89,114 +90,128 @@ 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) + self.pins.append(name) + self.pin_type[name]=pin_type + debug.check(pin_type in self.valid_signal_types, + "Invalid signaltype for {0}: {1}".format(name, + pin_type)) 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 + # The type list can be a single type for all pins # or a list that is the same length as the pin list. - if isinstance(pin_type, str): + if type(pin_type)==str: for pin in pin_list: + debug.check(pin_type in self.valid_signal_types, + "Invalid signaltype for {0}: {1}".format(pin, + pin_type)) self.add_pin(pin, pin_type) elif len(pin_type)==len(pin_list): - for (pin, type) in zip(pin_list, pin_type): - self.add_pin(pin, type) + for (pin, ptype) in zip(pin_list, pin_type): + debug.check(ptype in self.valid_signal_types, + "Invalid signaltype for {0}: {1}".format(pin, + ptype)) + self.add_pin(pin, ptype) else: - debug.error("Pin type must be a string or list of strings the same length as pin_list", -1) + debug.error("Mismatch in type and pin list lengths.", -1) def add_pin_indices(self, index_list): - """ Add pin indices for all the cell's pins. """ + """ + Add pin indices for all the cell's pins. + """ self.pin_indices = index_list def get_ordered_inputs(self, input_list): - """ Return the inputs reordered to match the pins. """ + """ + Return the inputs reordered to match the pins. + """ if not self.pin_indices: return input_list new_list = [input_list[x] for x in self.pin_indices] return new_list - def update_pin_types(self, type_list): - """ Change pin types for all the cell's pins. """ - debug.check(len(type_list) == len(self.pins), - "{} 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_type(type) + def add_pin_types(self, type_list): + """ + Add pin types for all the cell's pins. + """ + # This only works if self.pins == bitcell.pin_names + if len(type_list) != len(self.pins): + debug.error("{} spice subcircuit number of port types does not match number of pins\ + \n SPICE names={}\ + \n Module names={}\ + ".format(self.name, self.pins, type_list), 1) + self.pin_type = {pin: type for pin, type in zip(self.pins, type_list)} def get_pin_type(self, name): """ Returns the type of the signal pin. """ - pin = self.pins.get(name) - debug.check(pin is not None, "Spice pin {} not found".format(name)) - return pin.type + pin_type = self.pin_type[name] + debug.check(pin_type in self.valid_signal_types, + "Invalid signaltype for {0}: {1}".format(name, pin_type)) + return pin_type def get_pin_dir(self, name): """ Returns the direction of the pin. (Supply/ground are INOUT). """ - pin_type = self.get_pin_type(name) - if pin_type in ["POWER", "GROUND"]: + if self.pin_type[name] in ["POWER", "GROUND"]: return "INOUT" else: - return pin_type + return self.pin_type[name] def get_inputs(self): - """ - These use pin types to determine pin lists. - Returns names only, to maintain historical interface. - """ + """ These use pin types to determine pin lists. These + may be over-ridden by submodules that didn't use pin directions yet.""" input_list = [] - for pin in self.pins.values(): - if pin.type == "INPUT": - input_list.append(pin.name) + for pin in self.pins: + if self.pin_type[pin]=="INPUT": + input_list.append(pin) return input_list def get_outputs(self): - """ - These use pin types to determine pin lists. - Returns names only, to maintain historical interface. - """ + """ These use pin types to determine pin lists. These + may be over-ridden by submodules that didn't use pin directions yet.""" output_list = [] - for pin in self.pins.values(): - if pin.type == "OUTPUT": - output_list.append(pin.name) + for pin in self.pins: + if self.pin_type[pin]=="OUTPUT": + output_list.append(pin) return output_list - def get_inouts(self): - """ - These use pin types to determine pin lists. - Returns names only, to maintain historical interface. - """ - inout_list = [] - for pin in self.pins.values(): - if pin.type == "INOUT": - inout_list.append(pin.name) - return inout_list - def copy_pins(self, other_module, suffix=""): """ This will copy all of the pins from the other module and add an optional suffix.""" - for pin in other_module.pins.values(): - self.add_pin(pin.name + suffix, pin.type) + for pin in other_module.pins: + self.add_pin(pin + suffix, other_module.get_pin_type(pin)) - def connect_inst(self, args): + def get_inouts(self): + """ These use pin types to determine pin lists. These + may be over-ridden by submodules that didn't use pin directions yet.""" + inout_list = [] + for pin in self.pins: + if self.pin_type[pin]=="INOUT": + inout_list.append(pin) + return inout_list + + def connect_inst(self, args, check=True): """ Connects the pins of the last instance added + It is preferred to use the function with the check to find if + there is a problem. The check option can be set to false + where we dynamically generate groups of connections after a + group of modules are generated. """ - spice_pins = list(self.insts[-1].spice_pins) - num_pins = len(spice_pins) + num_pins = len(self.insts[-1].mod.pins) num_args = len(args) # Order the arguments if the hard cell has a custom port order ordered_args = self.get_ordered_inputs(args) - if (num_pins != num_args): + if (check and num_pins != num_args): if num_pins < num_args: - mod_pins = spice_pins + [""] * (num_args - num_pins) + mod_pins = self.insts[-1].mod.pins + [""] * (num_args - num_pins) arg_pins = ordered_args else: arg_pins = ordered_args + [""] * (num_pins - num_args) - mod_pins = spice_pins + mod_pins = self.insts[-1].mod.pins modpins_string = "\n".join(["{0} -> {1}".format(arg, mod) for (arg, mod) in zip(arg_pins, mod_pins)]) debug.error("Connection mismatch:\nInst ({0}) -> Mod ({1})\n{2}".format(num_args, @@ -204,17 +219,27 @@ class spice(): modpins_string), 1) - ordered_nets = self.create_nets(ordered_args) - self.insts[-1].connect_spice_pins(ordered_nets) + self.conns.append(ordered_args) - def create_nets(self, names_list): - nets = [] - 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, self)) - nets.append(net) - return nets + # This checks if we don't have enough instance port connections for the number of insts + if check and (len(self.insts)!=len(self.conns)): + insts_string=pformat(self.insts) + conns_string=pformat(self.conns) + + debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name, + len(self.insts), + len(self.conns))) + debug.error("Instances: \n" + str(insts_string)) + debug.error("-----") + debug.error("Connections: \n" + str(conns_string), 1) + + def get_conns(self, inst): + """Returns the connections of a given instance.""" + for i in range(len(self.insts)): + if inst is self.insts[i]: + return self.conns[i] + # If not found, returns None + return None def sp_read(self): """ @@ -233,7 +258,7 @@ class spice(): subckt = re.compile("^.subckt {}".format(self.cell_name), re.IGNORECASE) subckt_line = list(filter(subckt.search, self.spice))[0] # parses line into ports and remove subckt - self.add_pin_list(subckt_line.split(" ")[2:]) + self.pins = subckt_line.split(" ")[2:] else: debug.info(4, "no spfile {0}".format(self.sp_file)) self.spice = [] @@ -254,10 +279,10 @@ class spice(): subckt_line = list(filter(subckt.search, self.lvs))[0] # parses line into ports and remove subckt lvs_pins = subckt_line.split(" ")[2:] - debug.check(lvs_pins == list(self.pins), + debug.check(lvs_pins == self.pins, "Spice netlists for LVS and simulation have port mismatches:\n{0} (LVS {1})\nvs\n{2} (sim {3})".format(lvs_pins, self.lvs_file, - list(self.pins), + self.pins, self.sp_file)) def check_net_in_spice(self, net_name): @@ -302,72 +327,78 @@ class spice(): # If spice isn't defined, we dynamically generate one. # recursively write the modules - for mod in self.mods: - if self.contains(mod, usedMODS): + for i in self.mods: + if self.contains(i, usedMODS): continue - usedMODS.append(mod) - mod.sp_write_file(sp, usedMODS, lvs, trim) + usedMODS.append(i) + i.sp_write_file(sp, usedMODS, lvs, trim) if len(self.insts) == 0: return - if len(self.pins) == 0: + if self.pins == []: return # write out the first spice line (the subcircuit) - wrapped_pins = "\n+ ".join(tr.wrap(" ".join(list(self.pins)))) + wrapped_pins = "\n+ ".join(tr.wrap(" ".join(self.pins))) sp.write("\n.SUBCKT {0}\n+ {1}\n".format(self.cell_name, wrapped_pins)) + # write a PININFO line + if False: + pin_info = "*.PININFO" + for pin in self.pins: + if self.pin_type[pin] == "INPUT": + pin_info += " {0}:I".format(pin) + elif self.pin_type[pin] == "OUTPUT": + pin_info += " {0}:O".format(pin) + else: + pin_info += " {0}:B".format(pin) + sp.write(pin_info + "\n") + # Also write pins as comments - for pin in self.pins.values(): - sp.write("* {1:6}: {0} \n".format(pin.name, pin.type)) + for pin in self.pins: + sp.write("* {1:6}: {0} \n".format(pin, self.pin_type[pin])) for line in self.comments: sp.write("* {}\n".format(line)) - # every instance must be connected with the connect_inst function - # TODO: may run into empty pin lists edge case, not sure yet - connected = True - for inst in self.insts: - if inst.connected: - continue - debug.error("Instance {} spice pins not connected".format(str(inst))) - connected = False - debug.check(connected, "{0} : Not all instance spice pins are connected.".format(self.cell_name)) + # every instance must have a set of connections, even if it is empty. + if len(self.insts) != len(self.conns): + debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.cell_name, + len(self.insts), + len(self.conns))) + debug.error("Instances: \n" + str(self.insts)) + debug.error("-----") + debug.error("Connections: \n" + str(self.conns), 1) - for inst in self.insts: + for i in range(len(self.insts)): # we don't need to output connections of empty instances. # these are wires and paths - if len(inst.spice_pins) == 0: + if self.conns[i] == []: continue # Instance with no devices in it needs no subckt/instance - if inst.mod.no_instances: + if self.insts[i].mod.no_instances: continue # If this is a trimmed netlist, skip it by adding comment char - if trim and inst.name in self.trim_insts: + if trim and self.insts[i].name in self.trim_insts: sp.write("* ") - if lvs and hasattr(inst.mod, "lvs_device"): - sp.write(inst.mod.lvs_device.format(inst.name, - " ".join(inst.get_connections()))) + if lvs and hasattr(self.insts[i].mod, "lvs_device"): + sp.write(self.insts[i].mod.lvs_device.format(self.insts[i].name, + " ".join(self.conns[i]))) sp.write("\n") - elif hasattr(inst.mod, "spice_device"): - sp.write(inst.mod.spice_device.format(inst.name, - " ".join(inst.get_connections()))) + elif hasattr(self.insts[i].mod, "spice_device"): + sp.write(self.insts[i].mod.spice_device.format(self.insts[i].name, + " ".join(self.conns[i]))) sp.write("\n") else: - if trim and inst.name in self.trim_insts: - wrapped_connections = "\n*+ ".join(tr.wrap(" ".join(inst.get_connections()))) - sp.write("X{0}\n*+ {1}\n*+ {2}\n".format(inst.name, - wrapped_connections, - inst.mod.cell_name)) - else: - wrapped_connections = "\n+ ".join(tr.wrap(" ".join(inst.get_connections()))) - sp.write("X{0}\n+ {1}\n+ {2}\n".format(inst.name, - wrapped_connections, - inst.mod.cell_name)) + wrapped_connections = "\n+ ".join(tr.wrap(" ".join(self.conns[i]))) + + sp.write("X{0}\n+ {1}\n+ {2}\n".format(self.insts[i].name, + wrapped_connections, + self.insts[i].mod.cell_name)) sp.write(".ENDS {0}\n".format(self.cell_name)) @@ -696,12 +727,6 @@ class spice(): aliases.append(net) return aliases - def get_instance_connections(self): - conns = [] - for inst in self.insts: - conns.append(inst.get_connections()) - return conns - def is_net_alias(self, known_net, net_alias, mod, exclusion_set): """ Checks if the alias_net in input mod is the same as the input net for this mod (self). @@ -714,7 +739,7 @@ class spice(): return True # Check connections of all other subinsts mod_set = set() - for subinst, inst_conns in zip(self.insts, self.get_instance_connections()): + for subinst, inst_conns in zip(self.insts, self.conns): for inst_conn, mod_pin in zip(inst_conns, subinst.mod.pins): if self.is_net_alias_name_check(known_net, inst_conn, net_alias, mod): return True @@ -731,149 +756,3 @@ class spice(): return self == mod and \ child_net.lower() == alias_net.lower() and \ parent_net.lower() == alias_net.lower() - - -class pin_spice(): - """ - A class to represent a spice netlist pin. - mod is the parent module that created this pin. - mod_net is the net object of this pin's parent module. It must have the same name as the pin. - inst is the instance this pin is a part of, if any. - inst_net is the net object from mod's nets which connects to this pin. - """ - - valid_pin_types = ["INOUT", "INPUT", "OUTPUT", "POWER", "GROUND", "BIAS"] - - def __init__(self, name, type, mod): - self.name = name - self.set_type(type) - self.mod = mod - self.mod_net = None - self.inst = None - self.inst_net = None - - # TODO: evaluate if this makes sense... and works - self._hash = hash(self.name) - - def set_type(self, type): - debug.check(type in pin_spice.valid_pin_types, - "Invalid pin type for {0}: {1}".format(self.name, type)) - self.type = type - - def set_mod_net(self, net): - debug.check(isinstance(net, net_spice), "net must be a net_spice object") - debug.check(net.name == self.name, "module spice net must have same name as spice pin") - self.mod_net = net - - def set_inst(self, inst): - self.inst = inst - - def set_inst_net(self, net): - 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 - - def __str__(self): - """ override print function output """ - return "(pin_name={} type={})".format(self.name, self.type) - - def __repr__(self): - """ override repr function output """ - return self.name - - def __eq__(self, name): - return (name == self.name) if isinstance(name, str) else super().__eq__(name) - - def __hash__(self): - """ - Implement the hash function for sets etc. - Only hash name since spice does not allow two pins to share a name. - 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 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(): - """ - A class to represent a spice net. - mod is the parent module that created this net. - pins are all the pins connected to this net. - inst is the instance this net is a part of, if any. - """ - - def __init__(self, name, mod): - self.name = name - self.pins = [] - self.mod = mod - self.inst = None - - # TODO: evaluate if this makes sense... and works - self._hash = hash(self.name) - - def connect_pin(self, pin): - debug.check(isinstance(pin, pin_spice), "pin must be a pin_spice object") - if pin in self.pins: - debug.warning("pin {} was already connected to net {} ... why was it connected again?".format(pin.name, self.name)) - else: - self.pins.append(pin) - - def set_inst(self, inst): - self.inst = inst - - def __str__(self): - """ override print function output """ - return "(net_name={} type={})".format(self.name, self.type) - - def __repr__(self): - """ override repr function output """ - return self.name - - def __eq__(self, name): - return (name == self.name) if isinstance(name, str) else super().__eq__(name) - - def __hash__(self): - """ - Implement the hash function for sets etc. - Only hash name since spice does not allow two nets to share a name - (on the same level of hierarchy, or rather they will be the same net). - Provides a speedup if net_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 - should not be a deep copy but a reference to the existing mod - object it refers to in the original. If inst is already defined this - function will throw an error because that means it was called on a net - 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 diff --git a/compiler/base/lef.py b/compiler/base/lef.py index e08f0efc..b138799b 100644 --- a/compiler/base/lef.py +++ b/compiler/base/lef.py @@ -18,7 +18,7 @@ class lef: """ SRAM LEF Class open GDS file, read pins information, obstruction and write them to LEF file. - This is inherited by the sram_1bank class. + This is inherited by the sram_base class. """ def __init__(self, layers): # LEF db units per micron diff --git a/compiler/modules/column_decoder.py b/compiler/modules/column_decoder.py index ab80b1c9..92149a71 100644 --- a/compiler/modules/column_decoder.py +++ b/compiler/modules/column_decoder.py @@ -42,7 +42,7 @@ class column_decoder(design): def create_instances(self): self.column_decoder_inst = self.add_inst(name="column_decoder", mod=self.column_decoder) - self.connect_inst(list(self.pins)) + self.connect_inst(self.pins) def create_layout(self): self.column_decoder_inst.place(vector(0,0)) diff --git a/compiler/modules/pbitcell.py b/compiler/modules/pbitcell.py index 9c1800bd..2eab6e28 100644 --- a/compiler/modules/pbitcell.py +++ b/compiler/modules/pbitcell.py @@ -1212,7 +1212,7 @@ class pbitcell(bitcell_base): if self.dummy_bitcell: return - pin_dict = {pin: port for pin, port in zip(list(self.pins), port_nets)} + pin_dict = {pin: port for pin, port in zip(self.pins, port_nets)} # Edges added wl->bl, wl->br for every port except write ports rw_pin_names = zip(self.r_wl_names, self.r_bl_names, self.r_br_names)