mirror of https://github.com/VLSIDA/OpenRAM.git
implement pin_spice object
This commit is contained in:
parent
4e649aad6b
commit
146efc5070
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
Loading…
Reference in New Issue