From 7581df22557bffe6997a4d87da770bc2093aa496 Mon Sep 17 00:00:00 2001 From: Sam Crow Date: Mon, 17 Jul 2023 14:32:39 -0700 Subject: [PATCH] change pins to OrderedDict --- compiler/base/design.py | 6 +-- compiler/base/hierarchy_design.py | 14 +++--- compiler/base/hierarchy_spice.py | 82 +++++++++++++------------------ 3 files changed, 45 insertions(+), 57 deletions(-) diff --git a/compiler/base/design.py b/compiler/base/design.py index 329883c0..fe9b5495 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -41,8 +41,8 @@ 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 == self.pins, - "Custom cell pin names do not match spice file:\n{0} vs {1}".format(prop.port_names, self.pins)) + 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))) self.add_pin_indices(prop.port_indices) self.add_pin_names(prop.port_map) self.update_pin_types(prop.port_types) @@ -51,7 +51,7 @@ class design(hierarchy_design): (width, height) = utils.get_libcell_size(self.cell_name, GDS["unit"], layer[prop.boundary_layer]) - self.pin_map = utils.get_libcell_pins(self.pins, + self.pin_map = utils.get_libcell_pins(list(self.pins), self.cell_name, GDS["unit"]) diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py index 42c0543d..c34bc5f5 100644 --- a/compiler/base/hierarchy_design.py +++ b/compiler/base/hierarchy_design.py @@ -135,9 +135,9 @@ 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, - self.pins), + list(self.pins)), 1) - port_dict = {pin: port for pin, port in zip(self.pins, port_nets)} + port_dict = {pin: port for pin, port in zip(list(self.pins), port_nets)} debug.info(3, "Instance name={}".format(inst_name)) for subinst, conns in zip(self.insts, self.conns): if subinst in self.graph_inst_exclude: @@ -153,9 +153,9 @@ 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, - self.pins), + list(self.pins)), 1) - port_dict = {pin: port for pin, port in zip(self.pins, port_nets)} + port_dict = {pin: port for pin, port in zip(list(self.pins), port_nets)} debug.info(3, "Instance name={}".format(inst_name)) for subinst, conns in zip(self.insts, self.conns): subinst_name = inst_name + "{}x".format(OPTS.hier_seperator) + subinst.name @@ -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(self.pins, port_nets)} + pin_dict = {pin: port for pin, port in zip(list(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(self.pins) + pins = ",".join(list(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(self.pins) + " " + str(self.width) + "x" + str(self.height) + " )\n" + text="( design: " + self.name + " pins=" + str(list(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_spice.py b/compiler/base/hierarchy_spice.py index 3bf2af7f..914ee2f0 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -13,13 +13,13 @@ from pprint import pformat from openram import debug from openram import tech from openram import OPTS - -from compiler.base.net_spice import net_spice +from collections import OrderedDict from .delay_data import delay_data from .wire_spice_model import wire_spice_model from .power_data import power_data from .logical_effort import convert_relative_c_to_farad, convert_farad_to_relative_c from .pin_spice import pin_spice +from .net_spice import net_spice class spice(): @@ -55,14 +55,15 @@ class spice(): # Holds subckts/mods for this module self.mods = set() # Holds the pins for this module (in order) - self.pins = [] + # on Python3.7+ regular dictionaries guarantee order too, but we allow use of v3.5+ + self.pins = OrderedDict() # 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 out output subckt or isntances of this (for row/col caps etc.) + self.nets = {} + # If this is set, it will not output subckt or instances 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() @@ -90,9 +91,8 @@ class spice(): def add_pin(self, name, pin_type="INOUT"): """ Adds a pin to the pins list. Default type is INOUT signal. """ - new_pin = pin_spice(name, pin_type) - debug.check(new_pin not in self.pins, "cannot add duplicate spice pin") - self.pins.append(new_pin) + debug.check(name not in self.pins, "cannot add duplicate spice pin {}".format(name)) + self.pins[name] = pin_spice(name, pin_type) def add_pin_list(self, pin_list, pin_type="INOUT"): """ Adds a pin_list to the pins list """ @@ -122,20 +122,17 @@ class spice(): def update_pin_types(self, type_list): """ Change pin types for all the cell's pins. """ - 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) - for pin, type in zip(self.pins, type_list): + 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_pin_type(type) def get_pin_type(self, name): """ Returns the type of the signal pin. """ - for pin in self.pins: - if pin.name == name: - return pin.type - debug.error("Spice pin {} not found".format(name)) + pin = self.pins.get(name) + debug.check(pin is not None, "Spice pin {} not found".format(name)) + return pin.type def get_pin_dir(self, name): """ Returns the direction of the pin. (Supply/ground are INOUT). """ @@ -148,10 +145,10 @@ class spice(): def get_inputs(self): """ These use pin types to determine pin lists. - Returns names only to maintain historical interface. + Returns names only, to maintain historical interface. """ input_list = [] - for pin in self.pins: + for pin in self.pins.values(): if pin.type == "INPUT": input_list.append(pin.name) return input_list @@ -159,26 +156,28 @@ class spice(): def get_outputs(self): """ These use pin types to determine pin lists. - Returns names only to maintain historical interface. + Returns names only, to maintain historical interface. """ output_list = [] - for pin in self.pins: + for pin in self.pins.values(): if pin.type == "OUTPUT": output_list.append(pin.name) return output_list 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.""" + """ + These use pin types to determine pin lists. + Returns names only, to maintain historical interface. + """ inout_list = [] - for pin in self.pins: + 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: + for pin in other_module.pins.values(): self.add_pin(pin.name + suffix, pin.type) def connect_inst(self, args): @@ -186,7 +185,7 @@ class spice(): Connects the pins of the last instance added """ - spice_pins = self.insts[-1].spice_pins + spice_pins = list(self.insts[-1].spice_pins) num_pins = len(spice_pins) num_args = len(args) @@ -241,8 +240,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 - # FIXME: needs to use new pins interface - self.pins = subckt_line.split(" ")[2:] + self.add_pin_list(subckt_line.split(" ")[2:]) else: debug.info(4, "no spfile {0}".format(self.sp_file)) self.spice = [] @@ -263,10 +261,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 == self.pins, + debug.check(lvs_pins == list(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, - self.pins, + list(self.pins), self.sp_file)) def check_net_in_spice(self, net_name): @@ -299,6 +297,8 @@ class spice(): return False def sp_write_file(self, sp, usedMODS, lvs=False, trim=False): + # FIXME: this function refers to conns for connections but that no longer exists. + # it should be possible to just query the instances themselves for their connections. """ Recursive spice subcircuit write; Writes the spice subcircuit from the library or the dynamically generated one. @@ -319,29 +319,17 @@ class spice(): if len(self.insts) == 0: return - if self.pins == []: + if len(self.pins) == 0: return # write out the first spice line (the subcircuit) - wrapped_pins = "\n+ ".join(tr.wrap(" ".join(self.pins))) + wrapped_pins = "\n+ ".join(tr.wrap(" ".join(list(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: - sp.write("* {1:6}: {0} \n".format(pin, pin.type)) + for pin in self.pins.values(): + sp.write("* {1:6}: {0} \n".format(pin.name, pin.type)) for line in self.comments: sp.write("* {}\n".format(line))