implement pin_spice object

This commit is contained in:
Sam Crow 2023-07-13 16:45:05 -07:00
parent 4e649aad6b
commit 146efc5070
4 changed files with 86 additions and 55 deletions

View File

@ -45,7 +45,7 @@ class design(hierarchy_design):
"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, 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.add_pin_types(prop.port_types) self.update_pin_types(prop.port_types)
(width, height) = utils.get_libcell_size(self.cell_name, (width, height) = utils.get_libcell_size(self.cell_name,

View File

@ -17,6 +17,7 @@ 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
class spice(): class spice():
@ -49,14 +50,10 @@ class spice():
if not os.path.exists(self.lvs_file): if not os.path.exists(self.lvs_file):
self.lvs_file = self.sp_file self.lvs_file = self.sp_file
self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "BIAS", "POWER", "GROUND"]
# 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 = [] 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. # 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
@ -90,106 +87,97 @@ 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. """
self.pins.append(name) new_pin = pin_spice(name, pin_type)
self.pin_type[name]=pin_type debug.check(new_pin not in self.pins, "cannot add duplicate spice pin")
debug.check(pin_type in self.valid_signal_types, self.pins.append(new_pin)
"Invalid signaltype for {0}: {1}".format(name,
pin_type))
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 """
# The type list can be a single type for all pins # The pin type list can be a single type for all pins
# or a list that is the same length as the pin list. # or a list that is the same length as the pin list.
if type(pin_type)==str: if type(pin_type) == str:
for pin in pin_list: 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) self.add_pin(pin, pin_type)
elif len(pin_type)==len(pin_list): elif len(pin_type)==len(pin_list):
for (pin, ptype) in zip(pin_list, pin_type): for (pin, type) in zip(pin_list, pin_type):
debug.check(ptype in self.valid_signal_types, self.add_pin(pin, type)
"Invalid signaltype for {0}: {1}".format(pin,
ptype))
self.add_pin(pin, ptype)
else: else:
debug.error("Mismatch in type and pin list lengths.", -1) debug.error("Pin type must be a string or list of strings the same length as pin_list", -1)
def add_pin_indices(self, index_list): 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 self.pin_indices = index_list
def get_ordered_inputs(self, input_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: if not self.pin_indices:
return input_list return input_list
new_list = [input_list[x] for x in self.pin_indices] new_list = [input_list[x] for x in self.pin_indices]
return new_list return new_list
def add_pin_types(self, type_list): def update_pin_types(self, type_list):
""" """ Change pin types for all the cell's pins. """
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): if len(type_list) != len(self.pins):
debug.error("{} spice subcircuit number of port types does not match number of pins\ debug.error("{} spice subcircuit number of port types does not match number of pins\
\n SPICE names={}\ \n SPICE names={}\
\n Module names={}\ \n Module names={}\
".format(self.name, self.pins, type_list), 1) ".format(self.name, self.pins, type_list), 1)
self.pin_type = {pin: type for pin, type in zip(self.pins, type_list)} for pin, type in zip(self.pins, type_list):
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. """
pin_type = self.pin_type[name] for pin in self.pins:
debug.check(pin_type in self.valid_signal_types, if pin.name == name:
"Invalid signaltype for {0}: {1}".format(name, pin_type)) 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). """
if self.pin_type[name] in ["POWER", "GROUND"]: pin_type = self.get_pin_type(name)
if pin_type in ["POWER", "GROUND"]:
return "INOUT" return "INOUT"
else: else:
return self.pin_type[name] return pin_type
def get_inputs(self): def get_inputs(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.
"""
input_list = [] input_list = []
for pin in self.pins: for pin in self.pins:
if self.pin_type[pin]=="INPUT": if pin.type == "INPUT":
input_list.append(pin) input_list.append(pin.name)
return input_list return input_list
def get_outputs(self): def get_outputs(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.
"""
output_list = [] output_list = []
for pin in self.pins: for pin in self.pins:
if self.pin_type[pin]=="OUTPUT": if pin.type == "OUTPUT":
output_list.append(pin) output_list.append(pin.name)
return output_list return output_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:
self.add_pin(pin + suffix, other_module.get_pin_type(pin))
def get_inouts(self): def get_inouts(self):
""" These use pin types to determine pin lists. These """ These use pin types to determine pin lists. These
may be over-ridden by submodules that didn't use pin directions yet.""" may be over-ridden by submodules that didn't use pin directions yet."""
inout_list = [] inout_list = []
for pin in self.pins: for pin in self.pins:
if self.pin_type[pin]=="INOUT": if pin.type == "INOUT":
inout_list.append(pin) inout_list.append(pin.name)
return inout_list 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:
self.add_pin(pin.name + suffix, pin.type)
def connect_inst(self, args, check=True): def connect_inst(self, args, check=True):
""" """
Connects the pins of the last instance added Connects the pins of the last instance added

View File

@ -18,7 +18,7 @@ class lef:
""" """
SRAM LEF Class open GDS file, read pins information, obstruction SRAM LEF Class open GDS file, read pins information, obstruction
and write them to LEF file. and write them to LEF file.
This is inherited by the sram_base class. This is inherited by the sram_1bank class.
""" """
def __init__(self, layers): def __init__(self, layers):
# LEF db units per micron # LEF db units per micron

View File

@ -0,0 +1,43 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
from openram import debug
class pin_spice:
"""
A class to represent a spice netlist pin.
"""
valid_pin_types = ["INOUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
def __init__(self, name, type):
self.name = name
self.set_type(type)
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 __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 __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