change pins to OrderedDict

This commit is contained in:
Sam Crow 2023-07-17 14:32:39 -07:00
parent c8c43f75d9
commit 7581df2255
3 changed files with 45 additions and 57 deletions

View File

@ -41,8 +41,8 @@ class design(hierarchy_design):
if prop and prop.hard_cell: if prop and prop.hard_cell:
# The pins get added from the spice file, so just check # The pins get added from the spice file, so just check
# that they matched here # that they matched here
debug.check(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, 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_indices(prop.port_indices)
self.add_pin_names(prop.port_map) self.add_pin_names(prop.port_map)
self.update_pin_types(prop.port_types) self.update_pin_types(prop.port_types)
@ -51,7 +51,7 @@ class design(hierarchy_design):
(width, height) = utils.get_libcell_size(self.cell_name, (width, height) = utils.get_libcell_size(self.cell_name,
GDS["unit"], GDS["unit"],
layer[prop.boundary_layer]) 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, self.cell_name,
GDS["unit"]) GDS["unit"])

View File

@ -135,9 +135,9 @@ class hierarchy_design(spice, layout):
# Translate port names to external nets # Translate port names to external nets
if len(port_nets) != len(self.pins): if len(port_nets) != len(self.pins):
debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets, debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,
self.pins), list(self.pins)),
1) 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)) debug.info(3, "Instance name={}".format(inst_name))
for subinst, conns in zip(self.insts, self.conns): for subinst, conns in zip(self.insts, self.conns):
if subinst in self.graph_inst_exclude: if subinst in self.graph_inst_exclude:
@ -153,9 +153,9 @@ class hierarchy_design(spice, layout):
# Translate port names to external nets # Translate port names to external nets
if len(port_nets) != len(self.pins): if len(port_nets) != len(self.pins):
debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets, debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,
self.pins), list(self.pins)),
1) 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)) debug.info(3, "Instance name={}".format(inst_name))
for subinst, conns in zip(self.insts, self.conns): for subinst, conns in zip(self.insts, self.conns):
subinst_name = inst_name + "{}x".format(OPTS.hier_seperator) + subinst.name 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 # The final pin names will depend on the spice hierarchy, so
# they are passed as an input. # 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() input_pins = self.get_inputs()
output_pins = self.get_outputs() output_pins = self.get_outputs()
inout_pins = self.get_inouts() inout_pins = self.get_inouts()
@ -197,7 +197,7 @@ class hierarchy_design(spice, layout):
def __str__(self): def __str__(self):
""" override print function output """ """ override print function output """
pins = ",".join(self.pins) pins = ",".join(list(self.pins))
insts = [" {}".format(x) for x in self.insts] insts = [" {}".format(x) for x in self.insts]
objs = [" {}".format(x) for x in self.objs] objs = [" {}".format(x) for x in self.objs]
s = "********** design {0} **********".format(self.cell_name) s = "********** design {0} **********".format(self.cell_name)
@ -208,7 +208,7 @@ class hierarchy_design(spice, layout):
def __repr__(self): def __repr__(self):
""" override print function output """ """ 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: for i in self.objs:
text+=str(i) + ",\n" text+=str(i) + ",\n"
for i in self.insts: for i in self.insts:

View File

@ -13,13 +13,13 @@ from pprint import pformat
from openram import debug from openram import debug
from openram import tech from openram import tech
from openram import OPTS from openram import OPTS
from collections import OrderedDict
from compiler.base.net_spice import net_spice
from .delay_data import delay_data from .delay_data import delay_data
from .wire_spice_model import wire_spice_model from .wire_spice_model import wire_spice_model
from .power_data import power_data from .power_data import power_data
from .logical_effort import convert_relative_c_to_farad, convert_farad_to_relative_c from .logical_effort import convert_relative_c_to_farad, convert_farad_to_relative_c
from .pin_spice import pin_spice from .pin_spice import pin_spice
from .net_spice import net_spice
class spice(): class spice():
@ -55,14 +55,15 @@ class spice():
# Holds subckts/mods for this module # Holds subckts/mods for this module
self.mods = set() self.mods = set()
# Holds the pins for this module (in order) # 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. # An (optional) list of indices to reorder the pins to match the spice.
self.pin_indices = [] self.pin_indices = []
# THE CONNECTIONS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the # THE CONNECTIONS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the
# Spice format) # Spice format)
# internal nets, which may or may not be connected to pins of the same name # internal nets, which may or may not be connected to pins of the same name
self.nets = [] self.nets = {}
# If this is set, it will out output subckt or isntances of this (for row/col caps etc.) # If this is set, it will not output subckt or instances of this (for row/col caps etc.)
self.no_instances = False self.no_instances = False
# If we are doing a trimmed netlist, these are the instance that will be filtered # If we are doing a trimmed netlist, these are the instance that will be filtered
self.trim_insts = set() self.trim_insts = set()
@ -90,9 +91,8 @@ class spice():
def add_pin(self, name, pin_type="INOUT"): def add_pin(self, name, pin_type="INOUT"):
""" Adds a pin to the pins list. Default type is INOUT signal. """ """ Adds a pin to the pins list. Default type is INOUT signal. """
new_pin = pin_spice(name, pin_type) debug.check(name not in self.pins, "cannot add duplicate spice pin {}".format(name))
debug.check(new_pin not in self.pins, "cannot add duplicate spice pin") self.pins[name] = pin_spice(name, pin_type)
self.pins.append(new_pin)
def add_pin_list(self, pin_list, pin_type="INOUT"): def add_pin_list(self, pin_list, pin_type="INOUT"):
""" Adds a pin_list to the pins list """ """ Adds a pin_list to the pins list """
@ -122,20 +122,17 @@ class spice():
def update_pin_types(self, type_list): def update_pin_types(self, type_list):
""" Change pin types for all the cell's pins. """ """ Change pin types for all the cell's pins. """
if len(type_list) != len(self.pins): debug.check(len(type_list) == len(self.pins),
debug.error("{} spice subcircuit number of port types does not match number of pins\ "{} spice subcircuit number of port types does not match number of pins\
\n SPICE names={}\ \n pin names={}\n port types={}".format(self.name, list(self.pins), type_list))
\n Module names={}\ for pin, type in zip(self.pins.values(), type_list):
".format(self.name, self.pins, type_list), 1)
for pin, type in zip(self.pins, type_list):
pin.set_pin_type(type) pin.set_pin_type(type)
def get_pin_type(self, name): def get_pin_type(self, name):
""" Returns the type of the signal pin. """ """ Returns the type of the signal pin. """
for pin in self.pins: pin = self.pins.get(name)
if pin.name == name: debug.check(pin is not None, "Spice pin {} not found".format(name))
return pin.type return pin.type
debug.error("Spice pin {} not found".format(name))
def get_pin_dir(self, name): def get_pin_dir(self, name):
""" Returns the direction of the pin. (Supply/ground are INOUT). """ """ Returns the direction of the pin. (Supply/ground are INOUT). """
@ -148,10 +145,10 @@ class spice():
def get_inputs(self): def get_inputs(self):
""" """
These use pin types to determine pin lists. These use pin types to determine pin lists.
Returns names only to maintain historical interface. Returns names only, to maintain historical interface.
""" """
input_list = [] input_list = []
for pin in self.pins: for pin in self.pins.values():
if pin.type == "INPUT": if pin.type == "INPUT":
input_list.append(pin.name) input_list.append(pin.name)
return input_list return input_list
@ -159,26 +156,28 @@ class spice():
def get_outputs(self): def get_outputs(self):
""" """
These use pin types to determine pin lists. These use pin types to determine pin lists.
Returns names only to maintain historical interface. Returns names only, to maintain historical interface.
""" """
output_list = [] output_list = []
for pin in self.pins: for pin in self.pins.values():
if pin.type == "OUTPUT": if pin.type == "OUTPUT":
output_list.append(pin.name) output_list.append(pin.name)
return output_list return output_list
def get_inouts(self): 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 = [] inout_list = []
for pin in self.pins: for pin in self.pins.values():
if pin.type == "INOUT": if pin.type == "INOUT":
inout_list.append(pin.name) inout_list.append(pin.name)
return inout_list return inout_list
def copy_pins(self, other_module, suffix=""): def copy_pins(self, other_module, suffix=""):
""" This will copy all of the pins from the other module and add an optional 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) self.add_pin(pin.name + suffix, pin.type)
def connect_inst(self, args): def connect_inst(self, args):
@ -186,7 +185,7 @@ class spice():
Connects the pins of the last instance added 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_pins = len(spice_pins)
num_args = len(args) num_args = len(args)
@ -241,8 +240,7 @@ class spice():
subckt = re.compile("^.subckt {}".format(self.cell_name), re.IGNORECASE) subckt = re.compile("^.subckt {}".format(self.cell_name), re.IGNORECASE)
subckt_line = list(filter(subckt.search, self.spice))[0] subckt_line = list(filter(subckt.search, self.spice))[0]
# parses line into ports and remove subckt # parses line into ports and remove subckt
# FIXME: needs to use new pins interface self.add_pin_list(subckt_line.split(" ")[2:])
self.pins = subckt_line.split(" ")[2:]
else: else:
debug.info(4, "no spfile {0}".format(self.sp_file)) debug.info(4, "no spfile {0}".format(self.sp_file))
self.spice = [] self.spice = []
@ -263,10 +261,10 @@ class spice():
subckt_line = list(filter(subckt.search, self.lvs))[0] subckt_line = list(filter(subckt.search, self.lvs))[0]
# parses line into ports and remove subckt # parses line into ports and remove subckt
lvs_pins = subckt_line.split(" ")[2:] 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, "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.lvs_file,
self.pins, list(self.pins),
self.sp_file)) self.sp_file))
def check_net_in_spice(self, net_name): def check_net_in_spice(self, net_name):
@ -299,6 +297,8 @@ class spice():
return False return False
def sp_write_file(self, sp, usedMODS, lvs=False, trim=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; Recursive spice subcircuit write;
Writes the spice subcircuit from the library or the dynamically generated one. Writes the spice subcircuit from the library or the dynamically generated one.
@ -319,29 +319,17 @@ class spice():
if len(self.insts) == 0: if len(self.insts) == 0:
return return
if self.pins == []: if len(self.pins) == 0:
return return
# write out the first spice line (the subcircuit) # 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, sp.write("\n.SUBCKT {0}\n+ {1}\n".format(self.cell_name,
wrapped_pins)) 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 # Also write pins as comments
for pin in self.pins: for pin in self.pins.values():
sp.write("* {1:6}: {0} \n".format(pin, pin.type)) sp.write("* {1:6}: {0} \n".format(pin.name, pin.type))
for line in self.comments: for line in self.comments:
sp.write("* {}\n".format(line)) sp.write("* {}\n".format(line))