Merge branch 'dev' into characterizer_bug_fixes

This commit is contained in:
Hunter Nichols 2020-11-17 13:22:56 -08:00
commit ac425643a0
123 changed files with 789 additions and 2198 deletions

View File

@ -5,31 +5,92 @@
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
from globals import OPTS
class _cell:
def __init__(self, port_order, port_types, port_map=None, hard_cell=True, boundary_layer="boundary"):
# Specifies if this is a hard (i.e. GDS) cell
self._hard_cell = hard_cell
self._boundary_layer = boundary_layer
# Specifies the port directions
self._port_types_map = {x: y for (x, y) in zip(port_order, port_types)}
# Specifies a map from OpenRAM names to cell names
# by default it is 1:1
if not port_map:
self._port_map = {x: x for x in port_order}
# Update mapping of names
self._original_port_order = port_order
self._port_order = port_order
# Create an index array
self._port_indices = [self._port_order.index(x) for x in self._original_port_order]
# Update ordered name list
self._port_names = [self._port_map[x] for x in self._port_order]
# Update ordered type list
self._port_types = [self._port_types_map[x] for x in self._port_order]
@property
def hard_cell(self):
return self._hard_cell
@property
def port_names(self):
return self._port_names
@property
def port_order(self):
return self._port_order
@port_order.setter
def port_order(self, x):
self._port_order = x
# Update ordered name list in the new order
self._port_names = [self._port_map[x] for x in self._port_order]
# Update ordered type list in the new order
self._port_types = [self._port_types_map[x] for x in self._port_order]
# Update the index array
self._port_indices = [self._port_order.index(x) for x in self._original_port_order]
@property
def port_indices(self):
return self._port_indices
@property
def port_map(self):
return self._port_map
@port_map.setter
def port_map(self, x):
self._port_map = x
# Update ordered name list to use the new names
self._port_names = [self.port_map[x] for x in self._port_order]
@property
def port_types(self):
return self._port_types
@property
def boundary_layer(self):
return self._boundary_layer
@boundary_layer.setter
def boundary_layer(self, x):
self._boundary_layer = x
class _pins:
def __init__(self, pin_dict):
# make the pins elements of the class to allow "." access.
# For example: props.bitcell.cell_6t.pin.bl = "foobar"
# For example: props.bitcell.cell_1port.pin.bl = "foobar"
for k, v in pin_dict.items():
self.__dict__[k] = v
class _cell:
def __init__(self, pin_dict):
pin_dict.update(self._default_power_pins())
self._pins = _pins(pin_dict)
@property
def pin(self):
return self._pins
def _default_power_pins(self):
return {'vdd': 'vdd',
'gnd': 'gnd'}
class _mirror_axis:
def __init__(self, x, y):
self.x = x
@ -47,88 +108,20 @@ class _pgate:
self.add_implants = add_implants
class _bitcell:
def __init__(self, mirror, cell_s8_6t, cell_6t, cell_1rw1r, cell_1w1r):
self.mirror = mirror
self._s8_6t = cell_s8_6t
self._6t = cell_6t
self._1rw1r = cell_1rw1r
self._1w1r = cell_1w1r
class _bitcell(_cell):
def __init__(self, port_order, port_types, port_map=None, storage_nets=["Q", "Q_bar"], mirror=None, end_caps=False):
super().__init__(port_order, port_types, port_map)
def _default():
axis = _mirror_axis(True, False)
cell_s8_6t = _cell({'bl': 'bl',
'br': 'br',
'wl': 'wl'})
cell_6t = _cell({'bl': 'bl',
'br': 'br',
'wl': 'wl'})
cell_1rw1r = _cell({'bl0': 'bl0',
'br0': 'br0',
'bl1': 'bl1',
'br1': 'br1',
'wl0': 'wl0',
'wl1': 'wl1'})
cell_1w1r = _cell({'bl0': 'bl0',
'br0': 'br0',
'bl1': 'bl1',
'br1': 'br1',
'wl0': 'wl0',
'wl1': 'wl1'})
return _bitcell(cell_s8_6t=cell_s8_6t,
cell_6t=cell_6t,
cell_1rw1r=cell_1rw1r,
cell_1w1r=cell_1w1r,
mirror=axis)
@property
def cell_s8_6t(self):
return self._s8_6t
@property
def cell_6t(self):
return self._6t
@property
def cell_1rw1r(self):
return self._1rw1r
@property
def cell_1w1r(self):
return self._1w1r
class _dff:
def __init__(self, use_custom_ports, custom_port_list, custom_type_list, clk_pin):
self.use_custom_ports = use_custom_ports
self.custom_port_list = custom_port_list
self.custom_type_list = custom_type_list
self.clk_pin = clk_pin
class _dff_buff:
def __init__(self, use_custom_ports, custom_buff_ports, add_body_contacts):
self.use_custom_ports = use_custom_ports
self.buf_ports = custom_buff_ports
self.add_body_contacts = add_body_contacts
class _dff_buff_array:
def __init__(self, use_custom_ports, add_body_contacts):
self.use_custom_ports = use_custom_ports
self.add_body_contacts = add_body_contacts
class _bitcell_array:
def __init__(self, use_custom_cell_arrangement):
self.use_custom_cell_arrangement = use_custom_cell_arrangement
self.end_caps = end_caps
if not mirror:
self.mirror = _mirror_axis(True, False)
else:
self.mirror = mirror
self.storage_nets = storage_nets
class cell_properties():
"""
This contains meta information about the custom designed cells. For
@ -137,56 +130,55 @@ class cell_properties():
"""
def __init__(self):
self.names = {}
self.names["bitcell"] = "cell_6t"
self.names["bitcell_1rw_1r"] = "cell_1rw_1r"
self.names["bitcell_1w_1r"] = "cell_1w_1r"
self.names["dummy_bitcell"] = "dummy_cell_6t"
self.names["dummy_bitcell_1rw_1r"] = "dummy_cell_1rw_1r"
self.names["dummy_bitcell_1w_1r"] = "dummy_cell_1w_1r"
self.names["replica_bitcell"] = "replica_cell_6t"
self.names["replica_bitcell_1rw_1r"] = "replica_cell_1rw_1r"
self.names["replica_bitcell_1w_1r"] = "replica_cell_1w_1r"
self.names["col_cap_bitcell_6t"] = "col_cap_cell_6t"
self.names["col_cap_bitcell_1rw_1r"] = "col_cap_cell_1rw_1r"
self.names["col_cap_bitcell_1w_1r"] = "col_cap_cell_1w_1r"
self.names["row_cap_bitcell_6t"] = "row_cap_cell_6t"
self.names["row_cap_bitcell_1rw_1r"] = "row_cap_cell_1rw_1r"
self.names["row_cap_bitcell_1w_1r"] = "row_cap_cell_1w_1r"
self._bitcell = _bitcell._default()
self.names["bitcell_1port"] = "cell_1rw"
self.names["bitcell_2port"] = "cell_2rw"
self.names["dummy_bitcell_1port"] = "dummy_cell_1rw"
self.names["dummy_bitcell_2port"] = "dummy_cell_2rw"
self.names["replica_bitcell_1port"] = "replica_cell_1rw"
self.names["replica_bitcell_2port"] = "replica_cell_2rw"
self.names["col_cap_bitcell_1port"] = "col_cap_cell_1rw"
self.names["col_cap_bitcell_2port"] = "col_cap_cell_2rw"
self.names["row_cap_bitcell_1port"] = "row_cap_cell_1rw"
self.names["row_cap_bitcell_2port"] = "row_cap_cell_2rw"
self._ptx = _ptx(model_is_subckt=False,
bin_spice_models=False)
self._pgate = _pgate(add_implants=False)
self._dff = _dff(use_custom_ports=False,
custom_port_list=["D", "Q", "clk", "vdd", "gnd"],
custom_type_list=["INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"],
clk_pin="clk")
self._inv_dec = _cell(["A", "Z", "vdd", "gnd"],
["INPUT", "OUTPUT", "POWER", "GROUND"])
self._nand2_dec = _cell(["A", "B", "Z", "vdd", "gnd"],
["INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"])
self._nand3_dec = _cell(["A", "B", "C", "Z", "vdd", "gnd"],
["INPUT", "INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"])
self._nand4_dec = _cell(["A", "B", "C", "D", "Z", "vdd", "gnd"],
["INPUT", "INPUT", "INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"])
self._dff = _cell(["D", "Q", "clk", "vdd", "gnd"],
["INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"])
self._dff_buff = _dff_buff(use_custom_ports=False,
custom_buff_ports=["D", "qint", "clk", "vdd", "gnd"],
add_body_contacts=False)
self._write_driver = _cell(['din', 'bl', 'br', 'en', 'vdd', 'gnd'],
["INPUT", "OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"])
self._dff_buff_array = _dff_buff_array(use_custom_ports=False,
add_body_contacts=False)
self._sense_amp = _cell(['bl', 'br', 'dout', 'en', 'vdd', 'gnd'],
["INPUT", "INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"])
self._write_driver = _cell({'din': 'din',
'bl': 'bl',
'br': 'br',
'en': 'en'})
self._bitcell_1port = _bitcell(["bl", "br", "wl", "vdd", "gnd"],
["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"])
self._sense_amp = _cell({'bl': 'bl',
'br': 'br',
'dout': 'dout',
'en': 'en'})
self._bitcell_2port = _bitcell(["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"],
["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"])
self._bitcell_array = _bitcell_array(use_custom_cell_arrangement=[])
self._col_cap_2port = _bitcell(["bl0", "br0", "bl1", "br1", "vdd"],
["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT", "POWER"])
@property
def bitcell(self):
return self._bitcell
self._row_cap_2port = _bitcell(["wl0", "wl1", "gnd"],
["INPUT", "INPUT", "POWER", "GROUND"])
@property
def ptx(self):
@ -196,18 +188,26 @@ class cell_properties():
def pgate(self):
return self._pgate
@property
def inv_dec(self):
return self._inv_dec
@property
def nand2_dec(self):
return self._nand2_dec
@property
def nand3_dec(self):
return self._nand3_dec
@property
def nand4_dec(self):
return self._nand4_dec
@property
def dff(self):
return self._dff
@property
def dff_buff(self):
return self._dff_buff
@property
def dff_buff_array(self):
return self._dff_buff_array
@property
def write_driver(self):
return self._write_driver
@ -217,13 +217,18 @@ class cell_properties():
return self._sense_amp
@property
def bitcell_array(self):
return self._bitcell_array
def bitcell_1port(self):
return self._bitcell_1port
@property
def bitcell_2port(self):
return self._bitcell_2port
def compare_ports(self, port_list):
use_custom_arrangement = False
for ports in port_list:
if ports == "{}R_{}W_{}RW".format(OPTS.num_r_ports, OPTS.num_w_ports, OPTS.num_rw_ports):
use_custom_arrangement = True
break
return use_custom_arrangement
@property
def col_cap_2port(self):
return self._col_cap_2port
@property
def row_cap_2port(self):
return self._row_cap_2port

View File

@ -6,8 +6,9 @@
# All rights reserved.
#
from hierarchy_design import hierarchy_design
from utils import round_to_grid
import utils
import contact
from tech import GDS, layer
from tech import preferred_directions
from tech import cell_properties as props
from globals import OPTS
@ -21,7 +22,7 @@ class design(hierarchy_design):
some DRC/layer constants and analytical models for other modules to reuse.
"""
def __init__(self, name, cell_name=None):
def __init__(self, name, cell_name=None, prop=None):
# This allows us to use different GDS/spice circuits for hard cells instead of the default ones
# Except bitcell names are generated automatically by the globals.py setup_bitcells routines
# depending on the number of ports.
@ -31,6 +32,28 @@ class design(hierarchy_design):
cell_name = name
super().__init__(name, cell_name)
# This means it is a custom cell.
# It could have properties and not be a hard cell too (e.g. dff_buf)
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))
self.add_pin_indices(prop.port_indices)
self.add_pin_names(prop.port_map)
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(self.pins,
self.cell_name,
GDS["unit"])
self.width = width
self.height = height
self.setup_multiport_constants()
def check_pins(self):
@ -232,8 +255,7 @@ class design(hierarchy_design):
#print(contact1)
pitch = contact_width + layer_space
return round_to_grid(pitch)
return utils.round_to_grid(pitch)
def setup_multiport_constants(self):
"""

View File

@ -275,16 +275,16 @@ class instance(geometry):
def calculate_transform(self, node):
#set up the rotation matrix
angle = math.radians(float(node.rotate))
mRotate = np.array([[math.cos(angle),-math.sin(angle),0.0],
[math.sin(angle),math.cos(angle),0.0],
[0.0,0.0,1.0]])
mRotate = np.array([[math.cos(angle), -math.sin(angle), 0.0],
[math.sin(angle), math.cos(angle), 0.0],
[0.0, 0.0, 1.0]])
#set up translation matrix
translateX = float(node.offset[0])
translateY = float(node.offset[1])
mTranslate = np.array([[1.0,0.0,translateX],
[0.0,1.0,translateY],
[0.0,0.0,1.0]])
mTranslate = np.array([[1.0, 0.0, translateX],
[0.0, 1.0, translateY],
[0.0, 0.0, 1.0]])
#set up the scale matrix (handles mirror X)
scaleX = 1.0
@ -292,27 +292,27 @@ class instance(geometry):
scaleY = -1.0
else:
scaleY = 1.0
mScale = np.array([[scaleX,0.0,0.0],
[0.0,scaleY,0.0],
[0.0,0.0,1.0]])
mScale = np.array([[scaleX, 0.0, 0.0],
[0.0, scaleY, 0.0],
[0.0, 0.0, 1.0]])
return (mRotate, mScale, mTranslate)
def apply_transform(self, mtransforms, uVector, vVector, origin):
origin = np.dot(mtransforms[0], origin) #rotate
uVector = np.dot(mtransforms[0], uVector) #rotate
vVector = np.dot(mtransforms[0], vVector) #rotate
origin = np.dot(mtransforms[1], origin) #scale
uVector = np.dot(mtransforms[1], uVector) #scale
vVector = np.dot(mtransforms[1], vVector) #scale
origin = np.dot(mtransforms[0], origin) # rotate
uVector = np.dot(mtransforms[0], uVector) # rotate
vVector = np.dot(mtransforms[0], vVector) # rotate
origin = np.dot(mtransforms[1], origin) # scale
uVector = np.dot(mtransforms[1], uVector) # scale
vVector = np.dot(mtransforms[1], vVector) # scale
origin = np.dot(mtransforms[2], origin)
return(uVector, vVector, origin)
def apply_path_transform(self, path):
uVector = np.array([[1.0],[0.0],[0.0]])
vVector = np.array([[0.0],[1.0],[0.0]])
origin = np.array([[0.0],[0.0],[1.0]])
uVector = np.array([[1.0], [0.0], [0.0]])
vVector = np.array([[0.0], [1.0], [0.0]])
origin = np.array([[0.0], [0.0], [1.0]])
while(path):
instance = path.pop(-1)
@ -330,7 +330,7 @@ class instance(geometry):
bl_offsets = [] # bl to cell offset
br_offsets = [] # br to cell offset
bl_meta = [] # bl offset metadata (row,col,name)
br_meta = [] #br offset metadata (row,col,name)
br_meta = [] # br offset metadata (row,col,name)
def walk_subtree(node):
path.append(node)
@ -338,8 +338,6 @@ class instance(geometry):
if node.mod.name == cell_name:
cell_paths.append(copy.copy(path))
inst_name = path[-1].name
# get the row and col names from the path
row = int(path[-1].name.split('_')[-2][1:])
col = int(path[-1].name.split('_')[-1][1:])
@ -370,17 +368,15 @@ class instance(geometry):
for pair in range(len(normalized_bl_offsets)):
normalized_bl_offsets[pair] = (normalized_bl_offsets[pair][0],
-1 * normalized_bl_offsets[pair][1])
-1 * normalized_bl_offsets[pair][1])
for pair in range(len(normalized_br_offsets)):
normalized_br_offsets[pair] = (normalized_br_offsets[pair][0],
-1 * normalized_br_offsets[pair][1])
-1 * normalized_br_offsets[pair][1])
Q_offsets.append([Q_x, Q_y])
Q_bar_offsets.append([Q_bar_x, Q_bar_y])
bl_offsets.append(normalized_bl_offsets)
br_offsets.append(normalized_br_offsets)
@ -428,7 +424,7 @@ class path(geometry):
def gds_write_file(self, new_layout):
"""Writes the path to GDS"""
debug.info(4, "writing path (" + str(self.layerNumber) + "): " + self.coordinates)
debug.info(4, "writing path (" + str(self.layerNumber) + "): " + self.coordinates)
new_layout.addPath(layerNumber=self.layerNumber,
purposeNumber=self.layerPurpose,
coordinates=self.coordinates,

View File

@ -40,8 +40,6 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
self.drc_errors = "skipped"
self.lvs_errors = "skipped"
self.name = name
self.cell_name = cell_name
hierarchy_spice.spice.__init__(self, name, cell_name)
hierarchy_layout.layout.__init__(self, name, cell_name)
self.init_graph_params()
@ -73,11 +71,11 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
elif (OPTS.inline_lvsdrc or force_check or final_verification):
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name)
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
self.lvs_write(tempspice)
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
self.gds_write(tempgds)
# Final verification option does not allow nets to be connected by label.
self.drc_errors = verify.run_drc(self.cell_name, tempgds, extract=True, final_verification=final_verification)
self.drc_errors = verify.run_drc(self.cell_name, tempgds, tempspice, extract=True, final_verification=final_verification)
self.lvs_errors = verify.run_lvs(self.cell_name, tempgds, tempspice, final_verification=final_verification)
# force_check is used to determine decoder height and other things, so we shouldn't fail
@ -105,9 +103,11 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
if OPTS.netlist_only:
return
elif (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.cell_name)
tempspice = "{0}{1}.sp".format(OPTS.openram_temp, self.name)
self.lvs_write(tempspice)
tempgds = "{0}{1}.gds".format(OPTS.openram_temp, self.cell_name)
self.gds_write(tempgds)
num_errors = verify.run_drc(self.cell_name, tempgds, final_verification=final_verification)
num_errors = verify.run_drc(self.cell_name, tempgds, tempspice, final_verification=final_verification)
debug.check(num_errors == 0,
"DRC failed for {0} with {1} error(s)".format(self.cell_name,
num_errors))
@ -126,9 +126,9 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
if OPTS.netlist_only:
return
elif (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.cell_name)
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
tempspice = "{0}{1}.sp".format(OPTS.openram_temp, self.cell_name)
self.lvs_write(tempspice)
tempgds = "{0}{1}.gds".format(OPTS.openram_temp, self.name)
self.gds_write(tempgds)
num_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification)
debug.check(num_errors == 0,

View File

@ -32,17 +32,29 @@ class layout():
"""
def __init__(self, name, cell_name):
# This gets set in both spice and layout so either can be called first.
self.name = name
self.cell_name = cell_name
self.width = None
self.height = None
self.bounding_box = None
self.insts = [] # Holds module/cell layout instances
self.inst_names = set() # Set of names to check for duplicates
self.objs = [] # Holds all other objects (labels, geometries, etc)
self.pin_map = {} # Holds name->pin_layout map for all pins
self.visited = [] # List of modules we have already visited
self.is_library_cell = False # Flag for library cells
# Holds module/cell layout instances
self.insts = []
# Set of names to check for duplicates
self.inst_names = set()
# Holds all other objects (labels, geometries, etc)
self.objs = []
# This is a mapping of internal pin names to cell pin names
# If the key is not found, the internal pin names is assumed
self.pin_names = {}
# Holds name->pin_layout map for all pins
self.pin_map = {}
# List of modules we have already visited
self.visited = []
# Flag for library cells
self.is_library_cell = False
self.gds_read()
try:
@ -50,9 +62,7 @@ class layout():
self.pwr_grid_layer = power_grid[0]
except ImportError:
self.pwr_grid_layer = "m3"
############################################################
# GDS layout
############################################################
@ -308,26 +318,59 @@ class layout():
"""
Return the pin or list of pins
"""
name = self.get_pin_name(text)
try:
if len(self.pin_map[text]) > 1:
if len(self.pin_map[name]) > 1:
debug.error("Should use a pin iterator since more than one pin {}".format(text), -1)
# If we have one pin, return it and not the list.
# Otherwise, should use get_pins()
any_pin = next(iter(self.pin_map[text]))
any_pin = next(iter(self.pin_map[name]))
return any_pin
except Exception:
self.gds_write("missing_pin.gds")
debug.error("No pin found with name {0} on {1}. Saved as missing_pin.gds.".format(text, self.cell_name), -1)
debug.error("No pin found with name {0} on {1}. Saved as missing_pin.gds.".format(name, self.cell_name), -1)
def get_pins(self, text):
"""
Return a pin list (instead of a single pin)
"""
if text in self.pin_map.keys():
return self.pin_map[text]
name = self.get_pin_name(text)
if name in self.pin_map.keys():
return self.pin_map[name]
else:
return set()
def add_pin_names(self, pin_dict):
"""
Create a mapping from internal pin names to external pin names.
"""
self.pin_names = pin_dict
self.original_pin_names = {y: x for (x, y) in self.pin_names.items()}
def get_pin_name(self, text):
""" Return the custom cell pin name """
if text in self.pin_names:
return self.pin_names[text]
else:
return text
def get_original_pin_names(self):
""" Return the internal cell pin name """
# This uses the hierarchy_spice pins (in order)
return [self.get_original_pin_name(x) for x in self.pins]
def get_original_pin_name(self, text):
""" Return the internal cell pin names in custom port order """
if text in self.original_pin_names:
return self.original_pin_names[text]
else:
return text
def get_pin_names(self):
"""
Return a pin list of all pins
@ -346,7 +389,7 @@ class layout():
for pin in pins:
if new_name == "":
new_name = pin.name
new_name = pin_name
self.add_layout_pin(new_name,
pin.layer,
pin.ll(),

View File

@ -28,17 +28,20 @@ class spice():
"""
def __init__(self, name, cell_name):
# This gets set in both spice and layout so either can be called first.
self.name = name
self.cell_name = cell_name
self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
# Holds subckts/mods for this module
self.mods = []
# Holds the pins for this module
# Holds the pins for this module (in order)
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)
self.conns = []
@ -94,19 +97,34 @@ class spice():
else:
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.
"""
self.pin_indices = index_list
def get_ordered_inputs(self, input_list):
"""
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 add_pin_types(self, type_list):
"""
Add pin types for all the cell's pins.
Typically, should only be used for handmade cells.
"""
# This only works if self.pins == bitcell.pin_names
if self.pin_names != self.pins:
debug.error("{} spice subcircuit port names do not match 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.pin_names, self.pins), 1)
self.pin_type = {pin: type for pin, type in zip(self.pin_names, type_list)}
".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_type = self.pin_type[name]
@ -158,19 +176,26 @@ class spice():
self.mods.append(mod)
def connect_inst(self, args, check=True):
"""Connects the pins of the last instance added
"""
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."""
group of modules are generated.
"""
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 (check and num_pins != num_args):
if num_pins < num_args:
mod_pins = self.insts[-1].mod.pins + [""] * (num_args - num_pins)
arg_pins = args
arg_pins = ordered_args
else:
arg_pins = args + [""] * (num_pins - num_args)
arg_pins = ordered_args + [""] * (num_pins - num_args)
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)])
@ -179,8 +204,9 @@ class spice():
modpins_string),
1)
self.conns.append(args)
self.conns.append(ordered_args)
# 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)
@ -238,7 +264,8 @@ 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, "LVS and spice file pin mismatch.")
debug.check(lvs_pins == self.pins,
"Spice netlists for LVS and simulation have port mismatches: {0} (LVS) vs {1} (sim)".format(lvs_pins, self.pins))
def check_net_in_spice(self, net_name):
"""Checks if a net name exists in the current. Intended to be check nets in hand-made cells."""
@ -296,6 +323,18 @@ class spice():
sp.write("\n.SUBCKT {0} {1}\n".format(self.cell_name,
" ".join(self.pins)))
# write a PININFO line
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, self.pin_type[pin]))

View File

@ -32,7 +32,7 @@ class pin_layout:
debug.check(self.height() > 0, "Zero height pin.")
# These are the valid pin layers
valid_layers = { x: layer[x] for x in layer_indices.keys()}
valid_layers = {x: layer[x] for x in layer_indices.keys()}
# if it's a string, use the name
if type(layer_name_pp) == str:
@ -46,7 +46,7 @@ class pin_layout:
self._layer = layer_name
break
else:
debug.error("Couldn't find layer {}".format(layer_name_pp), -1)
debug.error("Layer {} is not a valid routing layer in the tech file.".format(layer_name_pp), -1)
self.lpp = layer[self.layer]
self._recompute_hash()

View File

@ -5,9 +5,9 @@
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import debug
import math
class verilog:
"""
Create a behavioral Verilog file for simulation.
@ -16,7 +16,7 @@ class verilog:
def __init__(self):
pass
def verilog_write(self,verilog_name):
def verilog_write(self, verilog_name):
""" Write a behavioral Verilog model. """
self.vf = open(verilog_name, "w")
@ -220,6 +220,9 @@ class verilog:
self.vf.write(" dout{0} <= #(DELAY) mem[addr{0}_reg];\n".format(port))
self.vf.write(" end\n")
self.vf.write(" always @(csb{0})\n".format(port))
self.vf.write(" dout{0} = 0)\n".format(port))
def add_address_check(self, wport, rport):
""" Output a warning if the two addresses match """
# If the rport is actually reading... and addresses match.

View File

@ -10,7 +10,7 @@ from tech import cell_properties as props
import bitcell_base
class bitcell(bitcell_base.bitcell_base):
class bitcell_1port(bitcell_base.bitcell_base):
"""
A single bit cell (6T, 8T, etc.) This module implements the
single memory cell used in the design. It is a hand-made cell, so
@ -18,53 +18,41 @@ class bitcell(bitcell_base.bitcell_base):
library.
"""
pin_names = [props.bitcell.cell_6t.pin.bl,
props.bitcell.cell_6t.pin.br,
props.bitcell.cell_6t.pin.wl,
props.bitcell.cell_6t.pin.vdd,
props.bitcell.cell_6t.pin.gnd]
type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
storage_nets = ['Q', 'Q_bar']
def __init__(self, name):
super().__init__(name)
super().__init__(name, prop=props.bitcell_1port)
debug.info(2, "Create bitcell")
self.nets_match = self.do_nets_exist(self.storage_nets)
def get_all_wl_names(self):
""" Creates a list of all wordline pin names """
row_pins = [props.bitcell.cell_6t.pin.wl]
row_pins = ["wl"]
return row_pins
def get_all_bitline_names(self):
""" Creates a list of all bitline pin names (both bl and br) """
pin = props.bitcell.cell_6t.pin
column_pins = [pin.bl, pin.br]
return column_pins
return ["bl", "br"]
def get_all_bl_names(self):
""" Creates a list of all bl pins names """
return [props.bitcell.cell_6t.pin.bl]
return ["bl"]
def get_all_br_names(self):
""" Creates a list of all br pins names """
return [props.bitcell.cell_6t.pin.br]
return ["br"]
def get_bl_name(self, port=0):
"""Get bl name"""
debug.check(port == 0, "One port for bitcell only.")
return props.bitcell.cell_6t.pin.bl
return "bl"
def get_br_name(self, port=0):
"""Get bl name"""
debug.check(port == 0, "One port for bitcell only.")
return props.bitcell.cell_6t.pin.br
return "br"
def get_wl_name(self, port=0):
"""Get wl name"""
debug.check(port == 0, "One port for bitcell only.")
return props.bitcell.cell_6t.pin.wl
return "wl"
def build_graph(self, graph, inst_name, port_nets):
"""

View File

@ -1,126 +0,0 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 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.
#
import debug
from tech import cell_properties as props
import bitcell_base
class bitcell_1rw_1r(bitcell_base.bitcell_base):
"""
A single bit cell (6T, 8T, etc.) This module implements the
single memory cell used in the design. It is a hand-made cell, so
the layout and netlist should be available in the technology
library.
"""
pin_names = [props.bitcell.cell_1rw1r.pin.bl0,
props.bitcell.cell_1rw1r.pin.br0,
props.bitcell.cell_1rw1r.pin.bl1,
props.bitcell.cell_1rw1r.pin.br1,
props.bitcell.cell_1rw1r.pin.wl0,
props.bitcell.cell_1rw1r.pin.wl1,
props.bitcell.cell_1rw1r.pin.vdd,
props.bitcell.cell_1rw1r.pin.gnd]
type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT",
"INPUT", "INPUT", "POWER", "GROUND"]
storage_nets = ['Q', 'Q_bar']
def __init__(self, name):
super().__init__(name)
debug.info(2, "Create bitcell with 1RW and 1R Port")
self.nets_match = self.do_nets_exist(self.storage_nets)
pin_names = self.pin_names
self.bl_names = [pin_names[0], pin_names[2]]
self.br_names = [pin_names[1], pin_names[3]]
self.wl_names = [pin_names[4], pin_names[5]]
def get_bitcell_pins(self, col, row):
"""
Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array
"""
pin_name = props.bitcell.cell_1rw1r.pin
bitcell_pins = ["{0}_{1}".format(pin_name.bl0, col),
"{0}_{1}".format(pin_name.br0, col),
"{0}_{1}".format(pin_name.bl1, col),
"{0}_{1}".format(pin_name.br1, col),
"{0}_{1}".format(pin_name.wl0, row),
"{0}_{1}".format(pin_name.wl1, row),
"vdd",
"gnd"]
return bitcell_pins
def get_all_wl_names(self):
""" Creates a list of all wordline pin names """
return [props.bitcell.cell_1rw1r.pin.wl0,
props.bitcell.cell_1rw1r.pin.wl1]
def get_all_bitline_names(self):
""" Creates a list of all bitline pin names (both bl and br) """
return [props.bitcell.cell_1rw1r.pin.bl0,
props.bitcell.cell_1rw1r.pin.br0,
props.bitcell.cell_1rw1r.pin.bl1,
props.bitcell.cell_1rw1r.pin.br1]
def get_all_bl_names(self):
""" Creates a list of all bl pins names """
return [props.bitcell.cell_1rw1r.pin.bl0,
props.bitcell.cell_1rw1r.pin.bl1]
def get_all_br_names(self):
""" Creates a list of all br pins names """
return [props.bitcell.cell_1rw1r.pin.br0,
props.bitcell.cell_1rw1r.pin.br1]
def get_read_bl_names(self):
""" Creates a list of bl pin names associated with read ports """
return [props.bitcell.cell_1rw1r.pin.bl0,
props.bitcell.cell_1rw1r.pin.bl1]
def get_read_br_names(self):
""" Creates a list of br pin names associated with read ports """
return [props.bitcell.cell_1rw1r.pin.br0,
props.bitcell.cell_1rw1r.pin.br1]
def get_write_bl_names(self):
""" Creates a list of bl pin names associated with write ports """
return [props.bitcell.cell_1rw1r.pin.bl0]
def get_write_br_names(self):
""" Creates a list of br pin names asscociated with write ports"""
return [props.bitcell.cell_1rw1r.pin.br1]
def get_bl_name(self, port=0):
"""Get bl name by port"""
debug.check(port < 2, "Two ports for bitcell_1rw_1r only.")
return self.bl_names[port]
def get_br_name(self, port=0):
"""Get bl name by port"""
debug.check(port < 2, "Two ports for bitcell_1rw_1r only.")
return self.br_names[port]
def get_wl_name(self, port=0):
"""Get wl name by port"""
debug.check(port < 2, "Two ports for bitcell_1rw_1r only.")
return self.wl_names[port]
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function."""
pin_dict = {pin: port for pin, port in zip(self.pins, port_nets)}
# Edges hardcoded here. Essentially wl->bl/br for both ports.
# Port 0 edges
pins = props.bitcell.cell_1rw1r.pin
graph.add_edge(pin_dict[pins.wl0], pin_dict[pins.bl0], self)
graph.add_edge(pin_dict[pins.wl0], pin_dict[pins.br0], self)
# Port 1 edges
graph.add_edge(pin_dict[pins.wl1], pin_dict[pins.bl1], self)
graph.add_edge(pin_dict[pins.wl1], pin_dict[pins.br1], self)

View File

@ -1,122 +0,0 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 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.
#
import debug
from tech import cell_properties as props
import bitcell_base
class bitcell_1w_1r(bitcell_base.bitcell_base):
"""
A single bit cell (6T, 8T, etc.) This module implements the
single memory cell used in the design. It is a hand-made cell, so
the layout and netlist should be available in the technology
library.
"""
pin_names = [props.bitcell.cell_1w1r.pin.bl0,
props.bitcell.cell_1w1r.pin.br0,
props.bitcell.cell_1w1r.pin.bl1,
props.bitcell.cell_1w1r.pin.br1,
props.bitcell.cell_1w1r.pin.wl0,
props.bitcell.cell_1w1r.pin.wl1,
props.bitcell.cell_1w1r.pin.vdd,
props.bitcell.cell_1w1r.pin.gnd]
type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT",
"INPUT", "INPUT", "POWER", "GROUND"]
storage_nets = ['Q', 'Q_bar']
def __init__(self, name):
super().__init__(name)
debug.info(2, "Create bitcell with 1W and 1R Port")
self.nets_match = self.do_nets_exist(self.storage_nets)
pin_names = self.pin_names
self.bl_names = [pin_names[0], pin_names[2]]
self.br_names = [pin_names[1], pin_names[3]]
self.wl_names = [pin_names[4], pin_names[5]]
def get_bitcell_pins(self, col, row):
"""
Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array
"""
pin_name = props.bitcell.cell_1w1r.pin
bitcell_pins = ["{0}_{1}".format(pin_name.bl0, col),
"{0}_{1}".format(pin_name.br0, col),
"{0}_{1}".format(pin_name.bl1, col),
"{0}_{1}".format(pin_name.br1, col),
"{0}_{1}".format(pin_name.wl0, row),
"{0}_{1}".format(pin_name.wl1, row),
"vdd",
"gnd"]
return bitcell_pins
def get_all_wl_names(self):
""" Creates a list of all wordline pin names """
return [props.bitcell.cell_1w1r.pin.wl0,
props.bitcell.cell_1w1r.pin.wl1]
def get_all_bitline_names(self):
""" Creates a list of all bitline pin names (both bl and br) """
return [props.bitcell.cell_1w1r.pin.bl0,
props.bitcell.cell_1w1r.pin.br0,
props.bitcell.cell_1w1r.pin.bl1,
props.bitcell.cell_1w1r.pin.br1]
def get_all_bl_names(self):
""" Creates a list of all bl pins names """
return [props.bitcell.cell_1w1r.pin.bl0,
props.bitcell.cell_1w1r.pin.bl1]
def get_all_br_names(self):
""" Creates a list of all br pins names """
return [props.bitcell.cell_1w1r.pin.br0,
props.bitcell.cell_1w1r.pin.br1]
def get_read_bl_names(self):
""" Creates a list of bl pin names associated with read ports """
return [props.bitcell.cell_1w1r.pin.bl0,
props.bitcell.cell_1w1r.pin.bl1]
def get_read_br_names(self):
""" Creates a list of br pin names associated with read ports """
return [props.bitcell.cell_1w1r.pin.br0,
props.bitcell.cell_1w1r.pin.br1]
def get_write_bl_names(self):
""" Creates a list of bl pin names associated with write ports """
return [props.bitcell.cell_1w1r.pin.bl0]
def get_write_br_names(self):
""" Creates a list of br pin names asscociated with write ports"""
return [props.bitcell.cell_1w1r.pin.br1]
def get_bl_name(self, port=0):
"""Get bl name by port"""
return self.bl_names[port]
def get_br_name(self, port=0):
"""Get bl name by port"""
return self.br_names[port]
def get_wl_name(self, port=0):
"""Get wl name by port"""
debug.check(port < 2, "Two ports for bitcell_1rw_1r only.")
return self.wl_names[port]
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function."""
pin_dict = {pin: port for pin, port in zip(self.pins, port_nets)}
pins = props.bitcell.cell_1w1r.pin
# Edges hardcoded here. Essentially wl->bl/br for both ports.
# Port 0 edges
graph.add_edge(pin_dict[pins.wl1], pin_dict[pins.bl1], self)
graph.add_edge(pin_dict[pins.wl1], pin_dict[pins.br1], self)
# Port 1 is a write port, so its timing is not considered here.

View File

@ -0,0 +1,101 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 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.
#
import debug
from tech import cell_properties as props
import bitcell_base
class bitcell_2port(bitcell_base.bitcell_base):
"""
A single bit cell (6T, 8T, etc.) This module implements the
single memory cell used in the design. It is a hand-made cell, so
the layout and netlist should be available in the technology
library.
"""
def __init__(self, name):
super().__init__(name, prop=props.bitcell_2port)
debug.info(2, "Create bitcell with 2 ports")
self.bl_names = ["bl0", "bl1"]
self.br_names = ["br0", "br1"]
self.wl_names = ["wl0", "wl1"]
def get_bitcell_pins(self, col, row):
"""
Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array
"""
bitcell_pins = ["bl0_{0}".format(col),
"br0_{0}".format(col),
"bl1_{0}".format(col),
"br1_{0}".format(col),
"wl0_{0}".format(row),
"wl1_{0}".format(row),
"vdd",
"gnd"]
return bitcell_pins
def get_all_wl_names(self):
""" Creates a list of all wordline pin names """
return self.wl_names
def get_all_bitline_names(self):
""" Creates a list of all bitline pin names (both bl and br) """
return ["bl0", "br0", "bl1", "br1"]
def get_all_bl_names(self):
""" Creates a list of all bl pins names """
return ["bl0", "bl1"]
def get_all_br_names(self):
""" Creates a list of all br pins names """
return ["br0", "br1"]
def get_read_bl_names(self):
""" Creates a list of bl pin names associated with read ports """
return ["bl0", "bl1"]
def get_read_br_names(self):
""" Creates a list of br pin names associated with read ports """
return ["br0", "br1"]
def get_write_bl_names(self):
""" Creates a list of bl pin names associated with write ports """
return ["bl0"]
def get_write_br_names(self):
""" Creates a list of br pin names asscociated with write ports"""
return ["br1"]
def get_bl_name(self, port=0):
"""Get bl name by port"""
debug.check(port < 2, "Two ports for bitcell_2port only.")
return self.bl_names[port]
def get_br_name(self, port=0):
"""Get bl name by port"""
debug.check(port < 2, "Two ports for bitcell_2port only.")
return self.br_names[port]
def get_wl_name(self, port=0):
"""Get wl name by port"""
debug.check(port < 2, "Two ports for bitcell_2port only.")
return self.wl_names[port]
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function."""
pin_dict = {pin: port for pin, port in zip(self.pin_names, port_nets)}
# Edges hardcoded here. Essentially wl->bl/br for both ports.
# Port 0 edges
graph.add_edge(pin_dict["wl0"], pin_dict["bl0"], self)
graph.add_edge(pin_dict["wl0"], pin_dict["br0"], self)
# Port 1 edges
graph.add_edge(pin_dict["wl1"], pin_dict["bl1"], self)
graph.add_edge(pin_dict["wl1"], pin_dict["br1"], self)

View File

@ -8,30 +8,27 @@
import debug
import design
import utils
from globals import OPTS
import logical_effort
from tech import GDS, parameter, drc, layer
from tech import parameter, drc, layer
class bitcell_base(design.design):
"""
Base bitcell parameters to be over-riden.
"""
cell_size_layer = "boundary"
def __init__(self, name, cell_name=None, prop=None):
design.design.__init__(self, name, cell_name, prop)
def __init__(self, name, hard_cell=True):
design.design.__init__(self, name)
if hard_cell:
(self.width, self.height) = utils.get_libcell_size(self.cell_name,
GDS["unit"],
layer[self.cell_size_layer])
self.pin_map = utils.get_libcell_pins(self.pin_names,
self.cell_name,
GDS["unit"])
self.add_pin_types(self.type_list)
# Set the bitcell specific properties
if prop:
self.storage_nets = prop.storage_nets
self.nets_match = self.do_nets_exist(prop.storage_nets)
self.mirror = prop.mirror
self.end_caps = prop.end_caps
self.supplies = ["vdd", "gnd"]
def get_stage_effort(self, load):
parasitic_delay = 1
# This accounts for bitline being drained

View File

@ -1,30 +0,0 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 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.
#
import debug
from tech import cell_properties as props
import bitcell_base
class col_cap_bitcell_1rw_1r(bitcell_base.bitcell_base):
"""
Column end cap cell.
"""
pin_names = [props.bitcell.cell_1rw1r.pin.bl0,
props.bitcell.cell_1rw1r.pin.br0,
props.bitcell.cell_1rw1r.pin.bl1,
props.bitcell.cell_1rw1r.pin.br1,
props.bitcell.cell_1rw1r.pin.vdd]
type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT",
"POWER", "GROUND"]
def __init__(self, name="col_cap_cell_1rw_1r"):
bitcell_base.bitcell_base.__init__(self, name)
debug.info(2, "Create col_cap bitcell 1rw+1r object")
self.no_instances = True

View File

@ -0,0 +1,22 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 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.
#
import debug
from tech import cell_properties as props
import bitcell_base
class col_cap_bitcell_2port(bitcell_base.bitcell_base):
"""
Column end cap cell.
"""
def __init__(self, name="col_cap_bitcell_2port"):
bitcell_base.bitcell_base.__init__(self, name, prop=props.col_cap_2port)
debug.info(2, "Create col_cap bitcell 2 port object")
self.no_instances = True

View File

@ -10,22 +10,15 @@ from tech import cell_properties as props
import bitcell_base
class dummy_bitcell(bitcell_base.bitcell_base):
class dummy_bitcell_1port(bitcell_base.bitcell_base):
"""
A single bit cell (6T, 8T, etc.) This module implements the
single memory cell used in the design. It is a hand-made cell, so
the layout and netlist should be available in the technology
library.
"""
pin_names = [props.bitcell.cell_6t.pin.bl,
props.bitcell.cell_6t.pin.br,
props.bitcell.cell_6t.pin.wl,
props.bitcell.cell_6t.pin.vdd,
props.bitcell.cell_6t.pin.gnd]
type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
def __init__(self, name):
super().__init__(name)
super().__init__(name, prop=props.bitcell_1port)
debug.info(2, "Create dummy bitcell")

View File

@ -1,35 +0,0 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 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.
#
import debug
from tech import cell_properties as props
import bitcell_base
class dummy_bitcell_1rw_1r(bitcell_base.bitcell_base):
"""
A single bit cell which is forced to store a 0.
This module implements the single memory cell used in the design. It
is a hand-made cell, so the layout and netlist should be available in
the technology library. """
pin_names = [props.bitcell.cell_1rw1r.pin.bl0,
props.bitcell.cell_1rw1r.pin.br0,
props.bitcell.cell_1rw1r.pin.bl1,
props.bitcell.cell_1rw1r.pin.br1,
props.bitcell.cell_1rw1r.pin.wl0,
props.bitcell.cell_1rw1r.pin.wl1,
props.bitcell.cell_1rw1r.pin.vdd,
props.bitcell.cell_1rw1r.pin.gnd]
type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT",
"INPUT", "INPUT", "POWER", "GROUND"]
def __init__(self, name):
super().__init__(name)
debug.info(2, "Create dummy bitcell 1rw+1r object")

View File

@ -1,37 +0,0 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 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.
#
import debug
from tech import cell_properties as props
import bitcell_base
class dummy_bitcell_1w_1r(bitcell_base.bitcell_base):
"""
A single bit cell which is forced to store a 0.
This module implements the single memory cell used in the design. It
is a hand-made cell, so the layout and netlist should be available in
the technology library. """
pin_names = [props.bitcell.cell_1w1r.pin.bl0,
props.bitcell.cell_1w1r.pin.br0,
props.bitcell.cell_1w1r.pin.bl1,
props.bitcell.cell_1w1r.pin.br1,
props.bitcell.cell_1w1r.pin.wl0,
props.bitcell.cell_1w1r.pin.wl1,
props.bitcell.cell_1w1r.pin.vdd,
props.bitcell.cell_1w1r.pin.gnd]
type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT",
"INPUT", "INPUT", "POWER", "GROUND"]
def __init__(self, name):
super().__init__(name)
debug.info(2, "Create dummy bitcell 1w+1r object")

View File

@ -0,0 +1,24 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 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.
#
import debug
from tech import cell_properties as props
import bitcell_base
class dummy_bitcell_2port(bitcell_base.bitcell_base):
"""
A single bit cell which is forced to store a 0.
This module implements the single memory cell used in the design. It
is a hand-made cell, so the layout and netlist should be available in
the technology library. """
def __init__(self, name):
super().__init__(name, prop=props.bitcell_2port)
debug.info(2, "Create dummy bitcell 2 port object")

View File

@ -8,6 +8,7 @@
import contact
import debug
from tech import drc, parameter, layer
from tech import cell_properties as props
from vector import vector
from ptx import ptx
from globals import OPTS
@ -29,8 +30,10 @@ class pbitcell(bitcell_base.bitcell_base):
self.replica_bitcell = replica_bitcell
self.dummy_bitcell = dummy_bitcell
self.mirror = props.bitcell_1port.mirror
self.end_caps = props.bitcell_1port.end_caps
bitcell_base.bitcell_base.__init__(self, name, hard_cell=False)
bitcell_base.bitcell_base.__init__(self, name)
fmt_str = "{0} rw ports, {1} w ports and {2} r ports"
info_string = fmt_str.format(self.num_rw_ports,
self.num_w_ports,

View File

@ -12,22 +12,15 @@ from tech import parameter, drc
import logical_effort
class replica_bitcell(bitcell_base.bitcell_base):
class replica_bitcell_1port(bitcell_base.bitcell_base):
"""
A single bit cell (6T, 8T, etc.)
This module implements the single memory cell used in the design. It
is a hand-made cell, so the layout and netlist should be available in
the technology library. """
pin_names = [props.bitcell.cell_6t.pin.bl,
props.bitcell.cell_6t.pin.br,
props.bitcell.cell_6t.pin.wl,
props.bitcell.cell_6t.pin.vdd,
props.bitcell.cell_6t.pin.gnd]
type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
def __init__(self, name):
super().__init__(name)
super().__init__(name, prop=props.bitcell_1port)
debug.info(2, "Create replica bitcell object")
def get_stage_effort(self, load):

View File

@ -1,61 +0,0 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 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.
#
import debug
import bitcell_base
from tech import cell_properties as props
from tech import parameter, drc
import logical_effort
class replica_bitcell_1w_1r(bitcell_base.bitcell_base):
"""
A single bit cell which is forced to store a 0.
This module implements the single memory cell used in the design. It
is a hand-made cell, so the layout and netlist should be available in
the technology library. """
pin_names = [props.bitcell.cell_1w1r.pin.bl0,
props.bitcell.cell_1w1r.pin.br0,
props.bitcell.cell_1w1r.pin.bl1,
props.bitcell.cell_1w1r.pin.br1,
props.bitcell.cell_1w1r.pin.wl0,
props.bitcell.cell_1w1r.pin.wl1,
props.bitcell.cell_1w1r.pin.vdd,
props.bitcell.cell_1w1r.pin.gnd]
type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", "INPUT", "INPUT", "POWER", "GROUND"]
def __init__(self, name):
super().__init__(name)
debug.info(2, "Create replica bitcell 1w+1r object")
def get_stage_effort(self, load):
parasitic_delay = 1
size = 0.5 # This accounts for bitline being drained thought the access TX and internal node
cin = 3 # Assumes always a minimum sizes inverter. Could be specified in the tech.py file.
read_port_load = 0.5 # min size NMOS gate load
return logical_effort.logical_effort('bitline', size, cin, load + read_port_load, parasitic_delay, False)
def input_load(self):
"""Return the relative capacitance of the access transistor gates"""
# FIXME: This applies to bitline capacitances as well.
# FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
access_tx_cin = parameter["6T_access_size"] / drc["minwidth_tx"]
return 2 * access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function."""
debug.info(1, 'Adding edges for {}'.format(inst_name))
pin_dict = {pin: port for pin, port in zip(self.pins, port_nets)}
pins = props.bitcell.cell_1w1r.pin
# Edges hardcoded here. Essentially wl->bl/br for the read port.
# Port 1 edges
graph.add_edge(pin_dict[pins.wl1], pin_dict[pins.bl1], self)
graph.add_edge(pin_dict[pins.wl1], pin_dict[pins.br1], self)
# Port 0 is a write port, so its timing is not considered here.

View File

@ -12,26 +12,16 @@ from tech import parameter, drc
import logical_effort
class replica_bitcell_1rw_1r(bitcell_base.bitcell_base):
class replica_bitcell_2port(bitcell_base.bitcell_base):
"""
A single bit cell which is forced to store a 0.
This module implements the single memory cell used in the design. It
is a hand-made cell, so the layout and netlist should be available in
the technology library. """
pin_names = [props.bitcell.cell_1rw1r.pin.bl0,
props.bitcell.cell_1rw1r.pin.br0,
props.bitcell.cell_1rw1r.pin.bl1,
props.bitcell.cell_1rw1r.pin.br1,
props.bitcell.cell_1rw1r.pin.wl0,
props.bitcell.cell_1rw1r.pin.wl1,
props.bitcell.cell_1rw1r.pin.vdd,
props.bitcell.cell_1rw1r.pin.gnd]
type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"]
def __init__(self, name):
super().__init__(name)
debug.info(2, "Create replica bitcell 1rw+1r object")
super().__init__(name, prop=props.bitcell_2port)
debug.info(2, "Create replica bitcell 2 port object")
def get_stage_effort(self, load):
parasitic_delay = 1
@ -51,12 +41,11 @@ class replica_bitcell_1rw_1r(bitcell_base.bitcell_base):
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function."""
pin_dict = {pin: port for pin, port in zip(self.pins, port_nets)}
pins = props.bitcell.cell_1rw1r.pin
pin_dict = {pin: port for pin, port in zip(self.pin_names, port_nets)}
# Edges hardcoded here. Essentially wl->bl/br for both ports.
# Port 0 edges
graph.add_edge(pin_dict[pins.wl0], pin_dict[pins.bl0], self)
graph.add_edge(pin_dict[pins.wl0], pin_dict[pins.br0], self)
graph.add_edge(pin_dict["wl0"], pin_dict["bl0"], self)
graph.add_edge(pin_dict["wl0"], pin_dict["br0"], self)
# Port 1 edges
graph.add_edge(pin_dict[pins.wl1], pin_dict[pins.bl1], self)
graph.add_edge(pin_dict[pins.wl1], pin_dict[pins.br1], self)
graph.add_edge(pin_dict["wl1"], pin_dict["bl1"], self)
graph.add_edge(pin_dict["wl1"], pin_dict["br1"], self)

View File

@ -1,27 +0,0 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 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.
#
import debug
from tech import cell_properties as props
import bitcell_base
class row_cap_bitcell_1rw_1r(bitcell_base.bitcell_base):
"""
Row end cap cell.
"""
pin_names = [props.bitcell.cell_1rw1r.pin.wl0,
props.bitcell.cell_1rw1r.pin.wl1,
props.bitcell.cell_1rw1r.pin.gnd]
type_list = ["INPUT", "INPUT", "GROUND"]
def __init__(self, name="row_cap_cell_1rw_1r"):
bitcell_base.bitcell_base.__init__(self, name)
debug.info(2, "Create row_cap bitcell 1rw+1r object")
self.no_instances = True

View File

@ -0,0 +1,22 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 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.
#
import debug
from tech import cell_properties as props
import bitcell_base
class row_cap_bitcell_2port(bitcell_base.bitcell_base):
"""
Row end cap cell.
"""
def __init__(self, name="row_cap_bitcell_2port"):
bitcell_base.bitcell_base.__init__(self, name, prop=props.row_cap_2port)
debug.info(2, "Create row_cap bitcell 2 port object")
self.no_instances = True

View File

@ -5,13 +5,12 @@
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import sys
import tech
from .stimuli import *
import debug
from .charutils import *
import dff
from globals import OPTS
from sram_factory import factory
class setup_hold():
@ -22,9 +21,8 @@ class setup_hold():
def __init__(self, corner):
# This must match the spice model order
self.pins = ["data", "dout", "clk", "vdd", "gnd"]
self.model_name = "dff"
self.model_location = OPTS.openram_tech + "sp_lib/dff.sp"
self.dff = factory.create(module_type=OPTS.dff)
self.period = tech.spice["feasible_period"]
debug.info(2, "Feasible period from technology file: {0} ".format(self.period))
@ -50,8 +48,8 @@ class setup_hold():
# instantiate the master-slave d-flip-flop
self.sf.write("\n* Instantiation of the Master-Slave D-flip-flop\n")
self.stim.inst_model(pins=self.pins,
model_name=self.model_name)
self.stim.inst_model(pins=self.dff.get_original_pin_names(),
model_name=self.dff.cell_name)
self.write_data(mode=mode,
target_time=target_time,
@ -71,7 +69,7 @@ class setup_hold():
self.sf.write("\n* Stimulus for setup/hold: data {0} period {1}n\n".format(correct_value, self.period))
# include files in stimulus file
self.stim.write_include(self.model_location)
self.stim.write_include(self.dff.sp_file)
# add vdd/gnd statements
self.sf.write("\n* Global Power Supplies\n")
@ -94,7 +92,7 @@ class setup_hold():
start_value = incorrect_value
end_value = correct_value
self.stim.gen_pwl(sig_name="data",
self.stim.gen_pwl(sig_name="D",
clk_times=[0, self.period, target_time],
data_values=[init_value, start_value, end_value],
period=target_time,
@ -136,7 +134,7 @@ class setup_hold():
self.sf.write("\n* Measure statements for pass/fail verification\n")
trig_name = "clk"
targ_name = "dout"
targ_name = "Q"
trig_val = targ_val = 0.5 * self.vdd_voltage
# Start triggers right before the clock edge at 2*period
self.stim.gen_meas_delay(meas_name="clk2q_delay",
@ -149,7 +147,7 @@ class setup_hold():
trig_td=1.9 * self.period,
targ_td=1.9 * self.period)
targ_name = "data"
targ_name = "D"
# Start triggers right after initialize value is returned to normal
# at one period
self.stim.gen_meas_delay(meas_name="setup_hold_time",

View File

@ -6,40 +6,17 @@
# All rights reserved.
#
import design
from tech import GDS, layer, spice
from tech import cell_properties as props
import utils
from tech import spice
class dff(design.design):
"""
Memory address flip-flop
"""
if not props.dff.use_custom_ports:
pin_names = ["D", "Q", "clk", "vdd", "gnd"]
type_list = ["INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
clk_pin = "clk"
else:
pin_names = props.dff.custom_port_list
type_list = props.dff.custom_type_list
clk_pin = props.dff.clk_pin
cell_size_layer = "boundary"
def __init__(self, name="dff"):
super().__init__(name)
(width, height) = utils.get_libcell_size(self.cell_name,
GDS["unit"],
layer[self.cell_size_layer])
pin_map = utils.get_libcell_pins(self.pin_names,
self.cell_name,
GDS["unit"])
self.width = width
self.height = height
self.pin_map = pin_map
self.add_pin_types(self.type_list)
super().__init__(name, prop=props.dff)
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
@ -54,9 +31,9 @@ class dff(design.design):
def calculate_effective_capacitance(self, load):
"""Computes effective capacitance. Results in fF"""
c_load = load
c_para = spice["dff_out_cap"]#ff
c_para = spice["dff_out_cap"] # ff
transition_prob = 0.5
return transition_prob*(c_load + c_para)
return transition_prob * (c_load + c_para)
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function."""

View File

@ -6,9 +6,9 @@
# All rights reserved.
#
import design
from tech import GDS, layer, spice, parameter
import logical_effort
import utils
from tech import cell_properties as props
from tech import spice, parameter
class inv_dec(design.design):
@ -16,25 +16,8 @@ class inv_dec(design.design):
INV for address decoders.
"""
pin_names = ["A", "Z", "vdd", "gnd"]
type_list = ["INPUT", "OUTPUT", "POWER", "GROUND"]
cell_size_layer = "boundary"
def __init__(self, name="inv_dec", height=None):
super().__init__(name)
(width, height) = utils.get_libcell_size(self.cell_name,
GDS["unit"],
layer[self.cell_size_layer])
pin_map = utils.get_libcell_pins(self.pin_names,
self.cell_name,
GDS["unit"])
self.width = width
self.height = height
self.pin_map = pin_map
self.add_pin_types(self.type_list)
super().__init__(name, prop=props.inv_dec)
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
@ -52,7 +35,7 @@ class inv_dec(design.design):
# In fF
c_para = spice["min_tx_drain_c"] * (self.nmos_size / parameter["min_tx_size"])
return transition_prob * (c_load + c_para)
return 0.5 * (c_load + c_para)
def input_load(self):
"""

View File

@ -6,9 +6,9 @@
# All rights reserved.
#
import design
from tech import GDS, layer, spice, parameter, drc
from tech import spice, parameter, drc
from tech import cell_properties as props
import logical_effort
import utils
class nand2_dec(design.design):
@ -16,25 +16,8 @@ class nand2_dec(design.design):
2-input NAND decoder for address decoders.
"""
pin_names = ["A", "B", "Z", "vdd", "gnd"]
type_list = ["INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
cell_size_layer = "boundary"
def __init__(self, name="nand2_dec", height=None):
super().__init__(name)
(width, height) = utils.get_libcell_size(self.cell_name,
GDS["unit"],
layer[self.cell_size_layer])
pin_map = utils.get_libcell_pins(self.pin_names,
self.cell_name,
GDS["unit"])
self.width = width
self.height = height
self.pin_map = pin_map
self.add_pin_types(self.type_list)
super().__init__(name, prop=props.nand2_dec)
# FIXME: For now...
size = 1

View File

@ -6,9 +6,9 @@
# All rights reserved.
#
import design
from tech import GDS, layer, spice, parameter, drc
from tech import spice, parameter, drc
from tech import cell_properties as props
import logical_effort
import utils
class nand3_dec(design.design):
@ -16,25 +16,8 @@ class nand3_dec(design.design):
3-input NAND decoder for address decoders.
"""
pin_names = ["A", "B", "C", "Z", "vdd", "gnd"]
type_list = ["INPUT", "INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
cell_size_layer = "boundary"
def __init__(self, name="nand3_dec", height=None):
super().__init__(name)
(width, height) = utils.get_libcell_size(self.cell_name,
GDS["unit"],
layer[self.cell_size_layer])
pin_map = utils.get_libcell_pins(self.pin_names,
self.cell_name,
GDS["unit"])
self.width = width
self.height = height
self.pin_map = pin_map
self.add_pin_types(self.type_list)
super().__init__(name, prop=props.nand3_dec)
# FIXME: For now...
size = 1

View File

@ -6,35 +6,18 @@
# All rights reserved.
#
import design
from tech import GDS, layer, spice, parameter, drc
from tech import spice, parameter, drc
from tech import cell_properties as props
import logical_effort
import utils
class nand4_dec(design.design):
"""
2-input NAND decoder for address decoders.
4-input NAND decoder for address decoders.
"""
pin_names = ["A", "B", "C", "D", "Z", "vdd", "gnd"]
type_list = ["INPUT", "INPUT", "INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
cell_size_layer = "boundary"
def __init__(self, name="nand4_dec", height=None):
super().__init__(name)
(width, height) = utils.get_libcell_size(self.cell_name,
GDS["unit"],
layer[self.cell_size_layer])
pin_map = utils.get_libcell_pins(self.pin_names,
self.cell_name,
GDS["unit"])
self.width = width
self.height = height
self.pin_map = pin_map
self.add_pin_types(self.type_list)
super().__init__(name, prop=props.nand4_dec)
# FIXME: For now...
size = 1

View File

@ -7,8 +7,7 @@
#
import design
import debug
import utils
from tech import GDS, layer, parameter, drc
from tech import parameter, drc
from tech import cell_properties as props
import logical_effort
@ -20,45 +19,24 @@ class sense_amp(design.design):
the technology library.
Sense amplifier to read a pair of bit-lines.
"""
pin_names = [props.sense_amp.pin.bl,
props.sense_amp.pin.br,
props.sense_amp.pin.dout,
props.sense_amp.pin.en,
props.sense_amp.pin.vdd,
props.sense_amp.pin.gnd]
type_list = ["INPUT", "INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
cell_size_layer = "boundary"
def __init__(self, name="sense_amp"):
super().__init__(name)
super().__init__(name, prop=props.sense_amp)
debug.info(2, "Create sense_amp")
(width, height) = utils.get_libcell_size(self.cell_name,
GDS["unit"],
layer[self.cell_size_layer])
pin_map = utils.get_libcell_pins(self.pin_names,
self.cell_name,
GDS["unit"])
self.width = width
self.height = height
self.pin_map = pin_map
self.add_pin_types(self.type_list)
def get_bl_names(self):
return props.sense_amp.pin.bl
return "bl"
def get_br_names(self):
return props.sense_amp.pin.br
return "br"
@property
def dout_name(self):
return props.sense_amp.pin.dout
return "dout"
@property
def en_name(self):
return props.sense_amp.pin.en
return "en"
def get_cin(self):

View File

@ -7,8 +7,7 @@
#
import debug
import design
import utils
from tech import GDS, layer
from tech import spice
class tri_gate(design.design):
@ -18,10 +17,6 @@ class tri_gate(design.design):
netlist should be available in the technology library.
"""
pin_names = ["in", "out", "en", "en_bar", "vdd", "gnd"]
type_list = ["INPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"]
cell_size_layer = "boundary"
unique_id = 1
def __init__(self, name=""):
@ -31,19 +26,6 @@ class tri_gate(design.design):
super().__init__(self, name)
debug.info(2, "Create tri_gate")
(width, height) = utils.get_libcell_size(self.cell_name,
GDS["unit"],
layer[self.cell_size_layer])
pin_map = utils.get_libcell_pins(self.pin_names,
self.cell_name,
GDS["unit"])
self.width = width
self.height = height
self.pin_map = pin_map
self.add_pin_types(self.type_list)
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
#Power in this module currently not defined. Returns 0 nW (leakage and dynamic).
@ -51,7 +33,7 @@ class tri_gate(design.design):
return total_power
def get_cin(self):
return 9*spice["min_tx_gate_c"]
return 9 * spice["min_tx_gate_c"]
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function."""

View File

@ -7,8 +7,6 @@
#
import debug
import design
import utils
from tech import GDS, layer
from tech import cell_properties as props
@ -20,51 +18,28 @@ class write_driver(design.design):
the technology library.
"""
pin_names = [props.write_driver.pin.din,
props.write_driver.pin.bl,
props.write_driver.pin.br,
props.write_driver.pin.en,
props.write_driver.pin.vdd,
props.write_driver.pin.gnd]
type_list = ["INPUT", "OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
cell_size_layer = "boundary"
def __init__(self, name):
super().__init__(name)
super().__init__(name, prop=props.write_driver)
debug.info(2, "Create write_driver")
(width, height) = utils.get_libcell_size(self.cell_name,
GDS["unit"],
layer[self.cell_size_layer])
pin_map = utils.get_libcell_pins(self.pin_names,
self.cell_name,
GDS["unit"])
self.width = width
self.height = height
self.pin_map = pin_map
self.add_pin_types(self.type_list)
def get_bl_names(self):
return props.write_driver.pin.bl
return "bl"
def get_br_names(self):
return props.write_driver.pin.br
return "br"
@property
def din_name(self):
return props.write_driver.pin.din
return "din"
@property
def en_name(self):
return props.write_driver.pin.en
return "en"
def get_w_en_cin(self):
"""Get the relative capacitance of a single input"""
# This is approximated from SCMOS. It has roughly 5 3x transistor gates.
return 5*3
return 5 * 3
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function."""

View File

@ -213,28 +213,15 @@ def setup_bitcell():
# If we have non-1rw ports,
# and the user didn't over-ride the bitcell manually,
# figure out the right bitcell to use
if OPTS.bitcell == "bitcell":
if (OPTS.num_rw_ports == 1 and OPTS.num_w_ports == 0 and OPTS.num_r_ports == 0):
OPTS.bitcell = "bitcell"
else:
ports = ""
if OPTS.num_rw_ports > 0:
ports += "{}rw_".format(OPTS.num_rw_ports)
if OPTS.num_w_ports > 0:
ports += "{}w_".format(OPTS.num_w_ports)
if OPTS.num_r_ports > 0:
ports += "{}r".format(OPTS.num_r_ports)
if ports != "":
OPTS.bitcell_suffix = "_" + ports
OPTS.bitcell = "bitcell" + OPTS.bitcell_suffix
OPTS.dummy_bitcell = "dummy_" + OPTS.bitcell
OPTS.replica_bitcell = "replica_" + OPTS.bitcell
elif OPTS.bitcell == "pbitcell":
if OPTS.bitcell == "pbitcell":
OPTS.bitcell = "pbitcell"
OPTS.dummy_bitcell = "dummy_pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
else:
num_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
OPTS.bitcell = "bitcell_{}port".format(num_ports)
OPTS.dummy_bitcell = "dummy_" + OPTS.bitcell
OPTS.replica_bitcell = "replica_" + OPTS.bitcell
# See if bitcell exists
try:
@ -247,7 +234,8 @@ def setup_bitcell():
OPTS.dummy_bitcell = "dummy_pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
if not OPTS.is_unit_test:
debug.warning("Using the parameterized bitcell which may have suboptimal density.")
msg = "Didn't find {0}rw {1}w {2}r port bitcell. ".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports)
debug.warning("{} Using the parameterized bitcell which may have suboptimal density.".format(msg))
debug.info(1, "Using bitcell: {}".format(OPTS.bitcell))

View File

@ -62,7 +62,7 @@ class bitcell_array(bitcell_base_array):
for row in range(self.row_size):
name = "bit_r{0}_c{1}".format(row, col)
self.cell_inst[row, col]=self.add_inst(name=name,
mod=self.cell)
mod=self.cell)
self.connect_inst(self.get_bitcell_pins(row, col))
def analytical_power(self, corner, load):

View File

@ -7,7 +7,6 @@
#
import debug
import design
from tech import cell_properties
from sram_factory import factory
from globals import OPTS
@ -36,10 +35,10 @@ class bitcell_base_array(design.design):
self.rbl_wordline_names = [[] for port in self.all_ports]
self.all_rbl_wordline_names = []
# The supply pin namesn
self.bitcell_supplies = ["vdd", "gnd"]
# The supply pin names
self.bitcell_supplies = self.cell.supplies
# If the technology needs renaming of the supplies
self.supplies = self.bitcell_supplies
self.supplies = ["vdd", "gnd"]
def create_all_bitline_names(self):
for col in range(self.column_size):
@ -174,7 +173,7 @@ class bitcell_base_array(design.design):
tempx = xoffset
dir_y = False
# If we mirror the current cell on the y axis adjust the x position
if cell_properties.bitcell.mirror.y and (col + col_offset) % 2:
if self.cell.mirror.y and (col + col_offset) % 2:
tempx = xoffset + self.cell.width
dir_y = True
return (tempx, dir_y)
@ -183,7 +182,7 @@ class bitcell_base_array(design.design):
tempy = yoffset
dir_x = False
# If we mirror the current cell on the x axis adjust the y position
if cell_properties.bitcell.mirror.x and (row + row_offset) % 2:
if self.cell.mirror.x and (row + row_offset) % 2:
tempy = yoffset + self.cell.height
dir_x = True
return (tempy, dir_x)

View File

@ -6,7 +6,6 @@
from bitcell_base_array import bitcell_base_array
from sram_factory import factory
from globals import OPTS
from tech import cell_properties
class col_cap_array(bitcell_base_array):
@ -26,12 +25,9 @@ class col_cap_array(bitcell_base_array):
def create_netlist(self):
""" Create and connect the netlist """
# This will create a default set of bitline/wordline names
try:
end_caps_enabled = cell_properties.bitcell.end_caps
except AttributeError:
end_caps_enabled = False
self.cell = factory.create(module_type=OPTS.bitcell)
if not end_caps_enabled:
if not self.cell.end_caps:
self.create_all_wordline_names()
self.create_all_bitline_names()
@ -51,8 +47,6 @@ class col_cap_array(bitcell_base_array):
self.dummy_cell = factory.create(module_type="col_cap_{}".format(OPTS.bitcell))
self.add_mod(self.dummy_cell)
self.cell = factory.create(module_type=OPTS.bitcell)
def create_instances(self):
""" Create the module instances used in this design """
self.cell_inst = {}
@ -70,16 +64,14 @@ class col_cap_array(bitcell_base_array):
"""
if len(self.all_ports) == 1:
pin_name = cell_properties.bitcell.cell_6t.pin
bitcell_pins = ["{0}_{1}".format(pin_name.bl0, col),
"{0}_{1}".format(pin_name.br0, col),
bitcell_pins = ["bl0_{0}".format(col),
"br0_{0}".format(col),
"vdd"]
else:
pin_name = cell_properties.bitcell.cell_1rw1r.pin
bitcell_pins = ["{0}_{1}".format(pin_name.bl0, col),
"{0}_{1}".format(pin_name.br0, col),
"{0}_{1}".format(pin_name.bl1, col),
"{0}_{1}".format(pin_name.br1, col),
bitcell_pins = ["bl0_{0}".format(col),
"br0_{0}".format(col),
"bl1_{0}".format(col),
"br1_{0}".format(col),
"vdd"]
return bitcell_pins

View File

@ -11,7 +11,6 @@ from tech import layer, preferred_directions
from vector import vector
from sram_factory import factory
from globals import OPTS
from tech import cell_properties as cell_props
from tech import layer_properties as layer_props
@ -99,6 +98,8 @@ class column_mux_array(design.design):
bitcell_br=self.bitcell_br)
self.add_mod(self.mux)
self.cell = factory.create(module_type=OPTS.bitcell)
def setup_layout_constants(self):
self.column_addr_size = int(self.words_per_row / 2)
self.width = self.columns * self.mux.width
@ -128,7 +129,7 @@ class column_mux_array(design.design):
# For every column, add a pass gate
for col_num, xoffset in enumerate(self.offsets[0:self.columns]):
if cell_props.bitcell.mirror.y and (col_num + self.column_offset) % 2:
if self.cell.mirror.y and (col_num + self.column_offset) % 2:
mirror = "MY"
xoffset = xoffset + self.mux.width
else:

View File

@ -6,7 +6,6 @@
# All rights reserved.
#
import design
from tech import cell_properties as props
import debug
from sram_factory import factory
import math
@ -662,9 +661,6 @@ class control_logic(design.design):
self.ctrl_dff_inst=self.add_inst(name="ctrl_dffs",
mod=self.ctrl_dff_array)
inst_pins = self.input_list + self.dff_output_list + ["clk_buf"] + self.supply_list
if props.dff_buff_array.add_body_contacts:
inst_pins.append("vpb")
inst_pins.append("vnb")
self.connect_inst(inst_pins)
def place_dffs(self):

View File

@ -70,7 +70,7 @@ class dff_array(design.design):
mod=self.dff)
instance_ports = [self.get_din_name(row, col),
self.get_dout_name(row, col)]
for port in self.dff.pin_names:
for port in self.dff.pins:
if port != 'D' and port != 'Q':
instance_ports.append(port)
self.connect_inst(instance_ports)
@ -137,7 +137,7 @@ class dff_array(design.design):
height=dout_pin.height())
# Create vertical spines to a single horizontal rail
clk_pin = self.dff_insts[0, 0].get_pin(self.dff.clk_pin)
clk_pin = self.dff_insts[0, 0].get_pin("clk")
clk_ypos = 2 * self.m3_pitch + self.m3_width
debug.check(clk_pin.layer == "m2", "DFF clk pin not on metal2")
self.add_layout_pin_segment_center(text="clk",
@ -145,7 +145,7 @@ class dff_array(design.design):
start=vector(0, clk_ypos),
end=vector(self.width, clk_ypos))
for col in range(self.columns):
clk_pin = self.dff_insts[0, col].get_pin(self.dff.clk_pin)
clk_pin = self.dff_insts[0, col].get_pin("clk")
# Make a vertical strip for each column
self.add_rect(layer="m2",
offset=clk_pin.ll().scale(1, 0),

View File

@ -8,7 +8,6 @@
import debug
import design
from tech import layer
from tech import cell_properties as props
from vector import vector
from globals import OPTS
from sram_factory import factory
@ -72,16 +71,8 @@ class dff_buf(design.design):
self.add_mod(self.inv2)
def add_pins(self):
self.add_pin("D", "INPUT")
self.add_pin("Q", "OUTPUT")
self.add_pin("Qb", "OUTPUT")
self.add_pin("clk", "INPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
if props.dff_buff.add_body_contacts:
self.add_pin("vpb", "INPUT")
self.add_pin("vpn", "INPUT")
self.add_pin_list(["D", "Q", "Qb", "clk", "vdd", "gnd"],
["INPUT", "OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"])
def create_instances(self):
self.dff_inst=self.add_inst(name="dff_buf_dff",

View File

@ -7,7 +7,6 @@
#
import debug
import design
from tech import cell_properties as props
from vector import vector
from globals import OPTS
from sram_factory import factory
@ -65,10 +64,6 @@ class dff_buf_array(design.design):
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
if props.dff_buff_array.add_body_contacts:
self.add_pin("vpb", "INPUT")
self.add_pin("vnb", "INPUT")
def add_modules(self):
self.dff = factory.create(module_type="dff_buf",
inv1_size=self.inv1_size,
@ -88,9 +83,6 @@ class dff_buf_array(design.design):
"clk",
"vdd",
"gnd"]
if props.dff_buff_array.add_body_contacts:
inst_ports.append("vpb")
inst_ports.append("vnb")
self.connect_inst(inst_ports)
def place_dff_array(self):

View File

@ -5,7 +5,6 @@
#
from bitcell_base_array import bitcell_base_array
from sram_factory import factory
from tech import cell_properties as props
from globals import OPTS
@ -77,15 +76,17 @@ class dummy_array(bitcell_base_array):
for col in range(self.column_size):
for port in self.all_ports:
bl_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port])
self.add_rect(layer=bl_pin.layer,
offset=bl_pin.ll().scale(1, 0),
width=bl_pin.width(),
height=self.height)
self.add_layout_pin(text="bl_{0}_{1}".format(port, col),
layer=bl_pin.layer,
offset=bl_pin.ll().scale(1, 0),
width=bl_pin.width(),
height=self.height)
br_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port + 1])
self.add_rect(layer=br_pin.layer,
offset=br_pin.ll().scale(1, 0),
width=br_pin.width(),
height=self.height)
self.add_layout_pin(text="br_{0}_{1}".format(port, col),
layer=br_pin.layer,
offset=br_pin.ll().scale(1, 0),
width=br_pin.width(),
height=self.height)
wl_names = self.cell.get_all_wl_names()
for row in range(self.row_size):

View File

@ -10,7 +10,6 @@ import debug
from vector import vector
from sram_factory import factory
from globals import OPTS
from tech import cell_properties
class precharge_array(design.design):
@ -79,6 +78,8 @@ class precharge_array(design.design):
bitcell_br=self.bitcell_br)
self.add_mod(self.pc_cell)
self.cell = factory.create(module_type=OPTS.bitcell)
def add_layout_pins(self):
en_pin = self.pc_cell.get_pin("en_bar")
@ -120,7 +121,7 @@ class precharge_array(design.design):
self.offsets = [n * self.pc_cell.width for n in range(self.columns)]
for i, xoffset in enumerate(self.offsets):
if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2:
if self.cell.mirror.y and (i + self.column_offset) % 2:
mirror = "MY"
tempx = xoffset + self.pc_cell.width
else:

View File

@ -63,13 +63,8 @@ class replica_bitcell_array(bitcell_base_array):
# Two dummy cols plus replica if we add the column
self.extra_cols = len(self.left_rbl) + len(self.right_rbl)
try:
end_caps_enabled = cell_properties.bitcell.end_caps
except AttributeError:
end_caps_enabled = False
# If we aren't using row/col caps, then we need to use the bitcell
if not end_caps_enabled:
if not self.cell.end_caps:
self.extra_rows += 2
self.extra_cols += 2
@ -144,10 +139,6 @@ class replica_bitcell_array(bitcell_base_array):
column_offset=column_offset,
replica_bit=replica_bit)
self.add_mod(self.replica_columns[port])
try:
end_caps_enabled = cell_properties.bitcell.end_caps
except AttributeError:
end_caps_enabled = False
# Dummy row
self.dummy_row = factory.create(module_type="dummy_array",
@ -159,7 +150,7 @@ class replica_bitcell_array(bitcell_base_array):
self.add_mod(self.dummy_row)
# Dummy Row or Col Cap, depending on bitcell array properties
col_cap_module_type = ("col_cap_array" if end_caps_enabled else "dummy_array")
col_cap_module_type = ("col_cap_array" if self.cell.end_caps else "dummy_array")
self.col_cap_top = factory.create(module_type=col_cap_module_type,
cols=self.column_size,
rows=1,
@ -179,7 +170,7 @@ class replica_bitcell_array(bitcell_base_array):
self.add_mod(self.col_cap_bottom)
# Dummy Col or Row Cap, depending on bitcell array properties
row_cap_module_type = ("row_cap_array" if end_caps_enabled else "dummy_array")
row_cap_module_type = ("row_cap_array" if self.cell.end_caps else "dummy_array")
self.row_cap_left = factory.create(module_type=row_cap_module_type,
cols=1,
@ -240,11 +231,6 @@ class replica_bitcell_array(bitcell_base_array):
self.add_pin_list(self.rbl_bitline_names[port], "INOUT")
def add_wordline_pins(self):
try:
end_caps_enabled = cell_properties.bitcell.end_caps
except AttributeError:
end_caps_enabled = False
# Wordlines to ground
self.gnd_wordline_names = []
@ -385,14 +371,10 @@ class replica_bitcell_array(bitcell_base_array):
def add_replica_columns(self):
""" Add replica columns on left and right of array """
try:
end_caps_enabled = cell_properties.bitcell.end_caps
except AttributeError:
end_caps_enabled = False
# Grow from left to right, toward the array
for bit, port in enumerate(self.left_rbl):
if not end_caps_enabled:
if not self.cell.end_caps:
offset = self.bitcell_offset.scale(-len(self.left_rbl) + bit, -self.rbl[0] - 1) + self.strap_offset.scale(-len(self.left_rbl) + bit, 0) + self.unused_offset
else:
offset = self.bitcell_offset.scale(-len(self.left_rbl) + bit, -self.rbl[0] - (self.col_end_offset.y/self.cell.height)) + self.strap_offset.scale(-len(self.left_rbl) + bit, 0) + self.unused_offset
@ -400,7 +382,7 @@ class replica_bitcell_array(bitcell_base_array):
self.replica_col_insts[bit].place(offset)
# Grow to the right of the bitcell array, array outward
for bit, port in enumerate(self.right_rbl):
if not end_caps_enabled:
if not self.cell.end_caps:
offset = self.bitcell_array_inst.lr() + self.bitcell_offset.scale(bit, -self.rbl[0] - 1) + self.strap_offset.scale(bit, -self.rbl[0] - 1)
else:
offset = self.bitcell_array_inst.lr() + self.bitcell_offset.scale(bit, -self.rbl[0] - (self.col_end_offset.y/self.cell.height)) + self.strap_offset.scale(bit, -self.rbl[0] - 1)
@ -422,15 +404,11 @@ class replica_bitcell_array(bitcell_base_array):
def add_end_caps(self):
""" Add dummy cells or end caps around the array """
try:
end_caps_enabled = cell_properties.bitcell.end_caps
except AttributeError:
end_caps_enabled = False
# FIXME: These depend on the array size itself
# Far top dummy row (first row above array is NOT flipped)
flip_dummy = self.rbl[1] % 2
if not end_caps_enabled:
if not self.cell.end_caps:
dummy_row_offset = self.bitcell_offset.scale(0, self.rbl[1] + flip_dummy) + self.bitcell_array_inst.ul()
else:
dummy_row_offset = self.bitcell_offset.scale(0, self.rbl[1] + flip_dummy) + self.bitcell_array_inst.ul()
@ -440,7 +418,7 @@ class replica_bitcell_array(bitcell_base_array):
# FIXME: These depend on the array size itself
# Far bottom dummy row (first row below array IS flipped)
flip_dummy = (self.rbl[0] + 1) % 2
if not end_caps_enabled:
if not self.cell.end_caps:
dummy_row_offset = self.bitcell_offset.scale(0, -self.rbl[0] - 1 + flip_dummy) + self.unused_offset
else:
dummy_row_offset = self.bitcell_offset.scale(0, -self.rbl[0] - (self.col_end_offset.y/self.cell.height) + flip_dummy) + self.unused_offset
@ -448,7 +426,7 @@ class replica_bitcell_array(bitcell_base_array):
mirror="MX" if flip_dummy else "R0")
# Far left dummy col
# Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array
if not end_caps_enabled:
if not self.cell.end_caps:
dummy_col_offset = self.bitcell_offset.scale(-len(self.left_rbl) - 1, -self.rbl[0] - 1) + self.unused_offset
else:
dummy_col_offset = self.bitcell_offset.scale(-(len(self.left_rbl)*(1+self.strap_offset.x/self.cell.width)) - (self.row_end_offset.x/self.cell.width), -len(self.left_rbl) - (self.col_end_offset.y/self.cell.height))
@ -456,7 +434,7 @@ class replica_bitcell_array(bitcell_base_array):
self.dummy_col_insts[0].place(offset=dummy_col_offset)
# Far right dummy col
# Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array
if not end_caps_enabled:
if not self.cell.end_caps:
dummy_col_offset = self.bitcell_offset.scale(len(self.right_rbl), -self.rbl[0] - 1) + self.bitcell_array_inst.lr()
else:
dummy_col_offset = self.bitcell_offset.scale(len(self.right_rbl)*(1+self.strap_offset.x/self.cell.width), -self.rbl[0] - (self.col_end_offset.y/self.cell.height)) + self.bitcell_array_inst.lr()

View File

@ -5,7 +5,6 @@
#
import debug
from bitcell_base_array import bitcell_base_array
from tech import cell_properties
from sram_factory import factory
from vector import vector
from globals import OPTS
@ -30,8 +29,13 @@ class replica_column(bitcell_base_array):
self.replica_bit = replica_bit
# left, right, regular rows plus top/bottom dummy cells
self.total_size = self.left_rbl + rows + self.right_rbl
# Used for pin names and properties
self.cell = factory.create(module_type=OPTS.bitcell)
# For end caps
try:
if not cell_properties.bitcell.end_caps:
if not self.cell.end_caps:
self.total_size += 2
except AttributeError:
self.total_size += 2
@ -82,20 +86,14 @@ class replica_column(bitcell_base_array):
self.dummy_cell = factory.create(module_type=OPTS.dummy_bitcell)
self.add_mod(self.dummy_cell)
try:
edge_module_type = ("col_cap" if cell_properties.bitcell.end_caps else "dummy")
edge_module_type = ("col_cap" if self.cell.end_caps else "dummy")
except AttributeError:
edge_module_type = "dummy"
self.edge_cell = factory.create(module_type=edge_module_type + "_" + OPTS.bitcell)
self.add_mod(self.edge_cell)
# Used for pin names only
self.cell = factory.create(module_type=OPTS.bitcell)
def create_instances(self):
self.cell_inst = {}
try:
end_caps_enabled = cell_properties.bitcell.end_caps
except AttributeError:
end_caps_enabled = False
for row in range(self.total_size):
name="rbc_{0}".format(row)
@ -113,7 +111,7 @@ class replica_column(bitcell_base_array):
elif (row == 0 or row == self.total_size - 1):
self.cell_inst[row]=self.add_inst(name=name,
mod=self.edge_cell)
if end_caps_enabled:
if self.cell.end_caps:
self.connect_inst(self.get_bitcell_pins_col_cap(row, 0))
else:
self.connect_inst(self.get_bitcell_pins(row, 0))
@ -131,13 +129,13 @@ class replica_column(bitcell_base_array):
# column that needs to be flipped.
dir_y = False
xoffset = 0
if cell_properties.bitcell.mirror.y and self.column_offset % 2:
if self.cell.mirror.y and self.column_offset % 2:
dir_y = True
xoffset = self.replica_cell.width
for row in range(self.total_size):
# name = "bit_r{0}_{1}".format(row, "rbl")
dir_x = cell_properties.bitcell.mirror.x and (row + rbl_offset) % 2
dir_x = self.cell.mirror.x and (row + rbl_offset) % 2
offset = vector(xoffset, self.cell.height * (row + (row + rbl_offset) % 2))
@ -169,12 +167,7 @@ class replica_column(bitcell_base_array):
width=bl_pin.width(),
height=self.height)
try:
end_caps_enabled = cell_properties.bitcell.end_caps
except AttributeError:
end_caps_enabled = False
if end_caps_enabled:
if self.cell.end_caps:
row_range_max = self.total_size - 1
row_range_min = 1
else:

View File

@ -6,7 +6,6 @@
from bitcell_base_array import bitcell_base_array
from sram_factory import factory
from globals import OPTS
from tech import cell_properties
class row_cap_array(bitcell_base_array):
@ -61,9 +60,8 @@ class row_cap_array(bitcell_base_array):
indexed by column and row, for instance use in bitcell_array
"""
pin_name = cell_properties.bitcell.cell_1rw1r.pin
bitcell_pins = ["{0}_{1}".format(pin_name.wl0, row),
"{0}_{1}".format(pin_name.wl1, row),
bitcell_pins = ["wl0_{0}".format(row),
"wl1_{0}".format(row),
"gnd"]
return bitcell_pins

View File

@ -10,7 +10,6 @@ from vector import vector
from sram_factory import factory
import debug
from globals import OPTS
from tech import cell_properties
class sense_amp_array(design.design):
@ -92,7 +91,6 @@ class sense_amp_array(design.design):
def add_modules(self):
self.amp = factory.create(module_type="sense_amp")
self.add_mod(self.amp)
# This is just used for measurements,
@ -122,7 +120,7 @@ class sense_amp_array(design.design):
self.offsets.append(i * self.bitcell.width)
for i, xoffset in enumerate(self.offsets[0:self.num_cols:self.words_per_row]):
if cell_properties.bitcell.mirror.y and (i * self.words_per_row + self.column_offset) % 2:
if self.bitcell.mirror.y and (i * self.words_per_row + self.column_offset) % 2:
mirror = "MY"
xoffset = xoffset + self.amp_spacing
else:
@ -134,7 +132,7 @@ class sense_amp_array(design.design):
# place spare sense amps (will share the same enable as regular sense amps)
for i, xoffset in enumerate(self.offsets[self.num_cols:]):
index = self.word_size + i
if cell_properties.bitcell.mirror.y and (index + self.column_offset) % 2:
if self.bitcell.mirror.y and (index + self.column_offset) % 2:
mirror = "MY"
xoffset = xoffset + self.amp_width
else:

View File

@ -12,7 +12,6 @@ from tech import drc
from sram_factory import factory
from vector import vector
from globals import OPTS
from tech import cell_properties
class write_driver_array(design.design):
@ -161,7 +160,7 @@ class write_driver_array(design.design):
self.offsets.append(i * self.driver_spacing)
for i, xoffset in enumerate(self.offsets[0:self.columns:self.words_per_row]):
if cell_properties.bitcell.mirror.y and (i * self.words_per_row + self.column_offset) % 2:
if self.bitcell.mirror.y and (i * self.words_per_row + self.column_offset) % 2:
mirror = "MY"
xoffset = xoffset + self.driver.width
else:
@ -174,7 +173,7 @@ class write_driver_array(design.design):
for i, xoffset in enumerate(self.offsets[self.columns:]):
index = self.word_size + i
if cell_properties.bitcell.mirror.y and (index + self.column_offset) % 2:
if self.bitcell.mirror.y and (index + self.column_offset) % 2:
mirror = "MY"
xoffset = xoffset + self.driver.width
else:

View File

@ -144,7 +144,6 @@ class options(optparse.Values):
# These are the default modules that can be over-riden
bitcell_suffix = ""
bank_select = "bank_select"
bitcell_array = "bitcell_array"
bitcell = "bitcell"

View File

@ -1,69 +0,0 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 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.
#
import unittest
from testutils import *
import sys, os,re
#sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
import debug
class library_drc_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
import verify
(gds_dir, allnames) = setup_files()
drc_errors = 0
debug.info(1, "\nPerforming DRC on: " + ", ".join(allnames))
for f in allnames:
gds_name = "{0}/{1}.gds".format(gds_dir, f)
if not os.path.isfile(gds_name):
drc_errors += 1
debug.error("Missing GDS file: {}".format(gds_name))
drc_errors += verify.run_drc(f, gds_name)
# fails if there are any DRC errors on any cells
self.assertEqual(drc_errors, 0)
globals.end_openram()
def setup_files():
gds_dir = OPTS.openram_tech + "/gds_lib"
files = os.listdir(gds_dir)
nametest = re.compile("\.gds$", re.IGNORECASE)
gds_files = list(filter(nametest.search, files))
tempnames = gds_files
# remove the .gds and .sp suffixes
for i in range(len(tempnames)):
gds_files[i] = re.sub('\.gds$', '', tempnames[i])
try:
from tech import blackbox_cells
nameset = list(set(tempnames) - set(blackbox_cells))
except ImportError:
# remove duplicate base names
nameset = set(tempnames)
allnames = list(nameset)
return (gds_dir, allnames)
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -36,13 +36,14 @@ class library_lvs_test(openram_test):
if not os.path.isfile(sp_name):
lvs_errors += 1
debug.error("Missing SPICE file {}".format(sp_name))
drc_errors += verify.run_drc(name, gds_name)
drc_errors += verify.run_drc(name, gds_name, sp_name)
lvs_errors += verify.run_lvs(f, gds_name, sp_name)
# fail if the error count is not zero
self.assertEqual(drc_errors+lvs_errors, 0)
self.assertEqual(drc_errors + lvs_errors, 0)
globals.end_openram()
def setup_files():
gds_dir = OPTS.openram_tech + "/gds_lib"
sp_dir = OPTS.openram_tech + "/lvs_lib"

View File

@ -8,14 +8,14 @@
#
import unittest
from testutils import *
import sys, os,re,shutil
import sys, os, re, shutil
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
import getpass
class openram_back_end_test(openram_test):
def runTest(self):
@ -25,12 +25,12 @@ class openram_back_end_test(openram_test):
debug.info(1, "Testing top-level back-end openram.py with 2-bit, 16 word SRAM.")
out_file = "testsram"
out_path = "/tmp/testsram_{0}_{1}_{2}/".format(OPTS.tech_name,getpass.getuser(),os.getpid())
out_path = "/tmp/testsram_{0}_{1}_{2}/".format(OPTS.tech_name, getpass.getuser(), os.getpid())
# make sure we start without the files existing
if os.path.exists(out_path):
shutil.rmtree(out_path, ignore_errors=True)
self.assertEqual(os.path.exists(out_path),False)
self.assertEqual(os.path.exists(out_path), False)
try:
os.makedirs(out_path, 0o0750)

View File

@ -8,14 +8,14 @@
#
import unittest
from testutils import *
import sys, os,re,shutil
import sys, os, re, shutil
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
import getpass
class openram_front_end_test(openram_test):
def runTest(self):
@ -25,12 +25,12 @@ class openram_front_end_test(openram_test):
debug.info(1, "Testing top-level front-end openram.py with 2-bit, 16 word SRAM.")
out_file = "testsram"
out_path = "/tmp/testsram_{0}_{1}_{2}".format(OPTS.tech_name,getpass.getuser(),os.getpid())
out_path = "/tmp/testsram_{0}_{1}_{2}".format(OPTS.tech_name, getpass.getuser(), os.getpid())
# make sure we start without the files existing
if os.path.exists(out_path):
shutil.rmtree(out_path, ignore_errors=True)
self.assertEqual(os.path.exists(out_path),False)
self.assertEqual(os.path.exists(out_path), False)
try:
os.makedirs(out_path, 0o0750)

View File

@ -16,7 +16,7 @@ from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 50_riscv_phys_test")
@unittest.skip("SKIPPING 50_riscv_phys_test")
class riscv_phys_test(openram_test):
def runTest(self):

View File

@ -25,7 +25,7 @@ class openram_test(unittest.TestCase):
w.gds_write(tempgds)
import verify
result=verify.run_drc(w.name, tempgds)
result=verify.run_drc(w.name, tempgds, None)
if result != 0:
self.fail("DRC failed: {}".format(w.name))
@ -48,7 +48,7 @@ class openram_test(unittest.TestCase):
# Run both DRC and LVS even if DRC might fail
# Magic can still extract despite DRC failing, so it might be ok in some techs
# if we ignore things like minimum metal area of pins
drc_result=verify.run_drc(a.name, tempgds, extract=True, final_verification=final_verification)
drc_result=verify.run_drc(a.name, tempgds, tempspice, extract=True, final_verification=final_verification)
# We can still run LVS even if DRC fails in Magic OR Calibre
lvs_result=verify.run_lvs(a.name, tempgds, tempspice, final_verification=final_verification)

View File

@ -30,9 +30,13 @@ num_lvs_runs = 0
num_pex_runs = 0
def write_drc_script(cell_name, gds_name, extract, final_verification, output_path):
def write_drc_script(cell_name, gds_name, extract, final_verification=False, output_path=None):
""" Write a Calibre runset file and script to run DRC """
# the runset file contains all the options to run calibre
if not output_path:
output_path = OPTS.openram_temp
from tech import drc
drc_rules = drc["drc_rules"]
@ -68,9 +72,12 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa
return drc_runset
def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_path):
def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, output_path=None):
""" Write a Calibre runset file and script to run LVS """
if not output_path:
output_path = OPTS.openram_temp
from tech import drc
lvs_rules = drc["lvs_rules"]
lvs_runset = {
@ -132,8 +139,12 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_pa
return lvs_runset
def write_pex_script(cell_name, extract, output, final_verification, output_path):
def write_pex_script(cell_name, extract, output, final_verification=False, output_path=None):
""" Write a pex script that can either just extract the netlist or the netlist+parasitics """
if not output_path:
output_path = OPTS.openram_temp
if output == None:
output = cell_name + ".pex.sp"
@ -142,7 +153,7 @@ def write_pex_script(cell_name, extract, output, final_verification, output_path
if not os.path.isfile(output_path + cell_name + ".lvs.report"):
gds_name = output_path +"/"+ cell_name + ".gds"
sp_name = output_path +"/"+ cell_name + ".sp"
run_drc(cell_name, gds_name)
run_drc(cell_name, gds_name, sp_name)
run_lvs(cell_name, gds_name, sp_name)
from tech import drc
@ -181,7 +192,7 @@ def write_pex_script(cell_name, extract, output, final_verification, output_path
return pex_runset
def run_drc(cell_name, gds_name, extract=False, final_verification=False):
def run_drc(cell_name, gds_name, sp_name, extract=False, final_verification=False):
"""Run DRC check on a given top-level name which is
implemented in gds_name."""

View File

@ -66,7 +66,7 @@ num_pex_runs = 0
# (outfile, errfile, resultsfile) = run_script(cell_name, "filter")
def write_drc_script(cell_name, gds_name, extract, final_verification, output_path):
def write_drc_script(cell_name, gds_name, extract, final_verification, output_path, sp_name=None):
""" Write a magic script to perform DRC and optionally extraction. """
global OPTS
@ -102,35 +102,38 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa
f.write("drc catchup\n")
f.write("drc count total\n")
f.write("drc count\n")
f.write("port makeall\n")
if not sp_name:
f.write("port makeall\n")
else:
f.write("readspice {}\n".format(sp_name))
if not extract:
pre = "#"
else:
pre = ""
if final_verification and OPTS.route_supplies:
f.write(pre + "extract unique all\n".format(cell_name))
f.write(pre + "extract unique all\n")
# Hack to work around unit scales in SkyWater
if OPTS.tech_name=="sky130":
f.write(pre + "extract style ngspice(si)\n")
f.write(pre + "extract\n".format(cell_name))
f.write(pre + "extract\n")
# f.write(pre + "ext2spice hierarchy on\n")
# f.write(pre + "ext2spice scale off\n")
# lvs exists in 8.2.79, but be backword compatible for now
#f.write(pre+"ext2spice lvs\n")
f.write(pre+"ext2spice hierarchy on\n")
f.write(pre+"ext2spice format ngspice\n")
f.write(pre+"ext2spice cthresh infinite\n")
f.write(pre+"ext2spice rthresh infinite\n")
f.write(pre+"ext2spice renumber off\n")
f.write(pre+"ext2spice scale off\n")
f.write(pre+"ext2spice blackbox on\n")
f.write(pre+"ext2spice subcircuit top on\n")
f.write(pre+"ext2spice global off\n")
# f.write(pre + "ext2spice lvs\n")
f.write(pre + "ext2spice hierarchy on\n")
f.write(pre + "ext2spice format ngspice\n")
f.write(pre + "ext2spice cthresh infinite\n")
f.write(pre + "ext2spice rthresh infinite\n")
f.write(pre + "ext2spice renumber off\n")
f.write(pre + "ext2spice scale off\n")
f.write(pre + "ext2spice blackbox on\n")
f.write(pre + "ext2spice subcircuit top on\n")
f.write(pre + "ext2spice global off\n")
# Can choose hspice, ngspice, or spice3,
# but they all seem compatible enough.
f.write(pre+"ext2spice format ngspice\n")
f.write(pre+"ext2spice {}\n".format(cell_name))
f.write(pre + "ext2spice format ngspice\n")
f.write(pre + "ext2spice {}\n".format(cell_name))
f.write("quit -noprompt\n")
f.write("EOF\n")
@ -138,7 +141,7 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa
os.system("chmod u+x {}".format(run_file))
def run_drc(cell_name, gds_name, extract=True, final_verification=False):
def run_drc(cell_name, gds_name, sp_name=None, extract=True, final_verification=False):
"""Run DRC check on a cell which is implemented in gds_name."""
global num_drc_runs
@ -148,7 +151,7 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False):
if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'):
shutil.copy(gds_name, OPTS.openram_temp)
write_drc_script(cell_name, gds_name, extract, final_verification, OPTS.openram_temp)
write_drc_script(cell_name, gds_name, extract, final_verification, OPTS.openram_temp, sp_name=sp_name)
(outfile, errfile, resultsfile) = run_script(cell_name, "drc")
@ -161,7 +164,7 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False):
try:
f = open(outfile, "r")
except FileNotFoundError:
debug.error("Unable to load DRC results file from {}. Is magic set up?".format(outfile),1)
debug.error("Unable to load DRC results file from {}. Is magic set up?".format(outfile), 1)
results = f.readlines()
f.close()
@ -172,7 +175,7 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False):
errors = int(re.split(": ", line)[1])
break
else:
debug.error("Unable to find the total error line in Magic output.",1)
debug.error("Unable to find the total error line in Magic output.", 1)
# always display this summary
@ -180,7 +183,7 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False):
if errors > 0:
for line in results:
if "error tiles" in line:
debug.info(1,line.rstrip("\n"))
debug.info(1, line.rstrip("\n"))
debug.warning(result_str)
else:
debug.info(1, result_str)
@ -188,11 +191,14 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False):
return errors
def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_path):
def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, output_path=None):
""" Write a netgen script to perform LVS. """
global OPTS
if not output_path:
output_path = OPTS.openram_temp
setup_file = "setup.tcl"
full_setup_file = OPTS.openram_tech + "tech/" + setup_file
if os.path.exists(full_setup_file):
@ -207,14 +213,14 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_pa
f.write("{} -noconsole << EOF\n".format(OPTS.lvs_exe[1]))
# f.write("readnet spice {0}.spice\n".format(cell_name))
# f.write("readnet spice {0}\n".format(sp_name))
f.write("lvs {{{0}.spice {0}}} {{{1} {0}}} {2} {0}.lvs.report -json\n".format(cell_name, sp_name, setup_file))
f.write("lvs {{{0}.spice {0}}} {{{1} {0}}} {2} {0}.lvs.report -full -json\n".format(cell_name, sp_name, setup_file))
f.write("quit\n")
f.write("EOF\n")
f.close()
os.system("chmod u+x {}".format(run_file))
def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
def run_lvs(cell_name, gds_name, sp_name, final_verification=False, output_path=None):
"""Run LVS check on a given top-level name which is
implemented in gds_name and sp_name. Final verification will
ensure that there are no remaining virtual conections. """
@ -222,13 +228,16 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
global num_lvs_runs
num_lvs_runs += 1
if not output_path:
output_path = OPTS.openram_temp
# Copy file to local dir if it isn't already
if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'):
shutil.copy(gds_name, OPTS.openram_temp)
if os.path.dirname(sp_name)!=OPTS.openram_temp.rstrip('/'):
shutil.copy(sp_name, OPTS.openram_temp)
if os.path.dirname(gds_name) != output_path.rstrip('/'):
shutil.copy(gds_name, output_path)
if os.path.dirname(sp_name) != output_path.rstrip('/'):
shutil.copy(sp_name, output_path)
write_lvs_script(cell_name, gds_name, sp_name, final_verification, OPTS.openram_temp)
write_lvs_script(cell_name, gds_name, sp_name, final_verification)
(outfile, errfile, resultsfile) = run_script(cell_name, "lvs")
@ -289,13 +298,20 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
return total_errors
def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
def run_pex(name, gds_name, sp_name, output=None, final_verification=False, output_path=None):
"""Run pex on a given top-level name which is
implemented in gds_name and sp_name. """
global num_pex_runs
num_pex_runs += 1
os.chdir(OPTS.openram_temp)
if not output_path:
output_path = OPTS.openram_temp
os.chdir(output_path)
if not output_path:
output_path = OPTS.openram_temp
if output == None:
output = name + ".pex.netlist"
@ -309,10 +325,10 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
# pex_fix did run the pex using a script while dev orignial method
# use batch mode.
# the dev old code using batch mode does not run and is split into functions
pex_runset = write_script_pex_rule(gds_name, name, output)
pex_runset = write_script_pex_rule(gds_name, name, sp_name, output)
errfile = "{0}{1}.pex.err".format(OPTS.openram_temp, name)
outfile = "{0}{1}.pex.out".format(OPTS.openram_temp, name)
errfile = "{0}{1}.pex.err".format(output_path, name)
outfile = "{0}{1}.pex.out".format(output_path, name)
script_cmd = "{0} 2> {1} 1> {2}".format(pex_runset,
errfile,
@ -387,7 +403,7 @@ def write_batch_pex_rule(gds_name, name, sp_name, output):
return file
def write_script_pex_rule(gds_name, cell_name, output):
def write_script_pex_rule(gds_name, cell_name, sp_name, output):
global OPTS
run_file = OPTS.openram_temp + "run_pex.sh"
f = open(run_file, "w")
@ -399,26 +415,24 @@ def write_script_pex_rule(gds_name, cell_name, output):
f.write("load {}\n".format(cell_name))
f.write("select top cell\n")
f.write("expand\n")
f.write("port makeall\n")
extract = True
if not extract:
pre = "#"
if not sp_name:
f.write("port makeall\n")
else:
pre = ""
f.write(pre + "extract\n")
f.write(pre + "ext2sim labels on\n")
f.write(pre + "ext2sim\n")
f.write(pre + "extresist simplify off\n")
f.write(pre + "extresist all\n")
f.write(pre + "ext2spice hierarchy off\n")
f.write(pre + "ext2spice format ngspice\n")
f.write(pre + "ext2spice renumber off\n")
f.write(pre + "ext2spice scale off\n")
f.write(pre + "ext2spice blackbox on\n")
f.write(pre + "ext2spice subcircuit top on\n")
f.write(pre + "ext2spice global off\n")
f.write(pre + "ext2spice extresist on\n")
f.write(pre + "ext2spice {}\n".format(cell_name))
f.write("readspice {}\n".format(sp_name))
f.write("extract\n")
f.write("ext2sim labels on\n")
f.write("ext2sim\n")
f.write("extresist simplify off\n")
f.write("extresist all\n")
f.write("ext2spice hierarchy off\n")
f.write("ext2spice format ngspice\n")
f.write("ext2spice renumber off\n")
f.write("ext2spice scale off\n")
f.write("ext2spice blackbox on\n")
f.write("ext2spice subcircuit top on\n")
f.write("ext2spice global off\n")
f.write("ext2spice extresist on\n")
f.write("ext2spice {}\n".format(cell_name))
f.write("quit -noprompt\n")
f.write("eof\n")
f.write("mv {0}.spice {1}\n".format(cell_name, output))

View File

@ -17,11 +17,11 @@ lvs_warned = False
pex_warned = False
def write_drc_script(cell_name, gds_name, extract, final_verification, output_path):
def write_drc_script(cell_name, gds_name, extract, final_verification=False, output_path=None):
pass
def run_drc(cell_name, gds_name, extract=False, final_verification=False):
def run_drc(cell_name, gds_name, sp_name, extract=False, final_verification=False, output_path=None):
global drc_warned
if not drc_warned:
debug.error("DRC unable to run.", -1)
@ -30,11 +30,11 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False):
return 1
def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_path):
def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, output_path=None):
pass
def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
def run_lvs(cell_name, gds_name, sp_name, final_verification=False, output_path=None):
global lvs_warned
if not lvs_warned:
debug.error("LVS unable to run.", -1)
@ -43,7 +43,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
return 1
def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
def run_pex(name, gds_name, sp_name, output=None, final_verification=False, output_path=None):
global pex_warned
if not pex_warned:
debug.error("PEX unable to run.", -1)

View File

@ -1,5 +1,5 @@
.SUBCKT cell_6t bl br wl vdd gnd
.SUBCKT cell_1rw bl br wl vdd gnd
* Inverter 1
MM0 Q_bar Q gnd gnd NMOS_VTG W=205.00n L=50n
MM4 Q_bar Q vdd vdd PMOS_VTG W=90n L=50n
@ -11,5 +11,5 @@ MM5 Q Q_bar vdd vdd PMOS_VTG W=90n L=50n
* Access transistors
MM3 bl wl Q gnd NMOS_VTG W=135.00n L=50n
MM2 br wl Q_bar gnd NMOS_VTG W=135.00n L=50n
.ENDS cell_6t
.ENDS cell_1rw

View File

@ -1,14 +0,0 @@
.SUBCKT cell_1rw_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
MM9 RA_to_R_right wl1 br1 gnd NMOS_VTG W=180.0n L=50n m=1
MM8 RA_to_R_right Q gnd gnd NMOS_VTG W=180.0n L=50n m=1
MM7 RA_to_R_left Q_bar gnd gnd NMOS_VTG W=180.0n L=50n m=1
MM6 RA_to_R_left wl1 bl1 gnd NMOS_VTG W=180.0n L=50n m=1
MM5 Q wl0 bl0 gnd NMOS_VTG W=135.00n L=50n m=1
MM4 Q_bar wl0 br0 gnd NMOS_VTG W=135.00n L=50n m=1
MM1 Q Q_bar gnd gnd NMOS_VTG W=205.0n L=50n m=1
MM0 Q_bar Q gnd gnd NMOS_VTG W=205.0n L=50n m=1
MM3 Q Q_bar vdd vdd PMOS_VTG W=90n L=50n m=1
MM2 Q_bar Q vdd vdd PMOS_VTG W=90n L=50n m=1
.ENDS

View File

@ -1,5 +1,5 @@
.SUBCKT cell_1w_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
.SUBCKT cell_2rw bl0 br0 bl1 br1 wl0 wl1 vdd gnd
MM9 RA_to_R_right wl1 br1 gnd NMOS_VTG W=180.0n L=50n m=1
MM8 RA_to_R_right Q gnd gnd NMOS_VTG W=180.0n L=50n m=1
MM7 RA_to_R_left Q_bar gnd gnd NMOS_VTG W=180.0n L=50n m=1

View File

@ -1,5 +1,5 @@
.SUBCKT dummy_cell_6t bl br wl vdd gnd
.SUBCKT dummy_cell_1rw bl br wl vdd gnd
* Inverter 1
MM0 Q_bar Q gnd gnd NMOS_VTG W=205.00n L=50n
MM4 Q_bar Q vdd vdd PMOS_VTG W=90n L=50n
@ -11,5 +11,5 @@ MM5 Q Q_bar vdd vdd PMOS_VTG W=90n L=50n
* Access transistors
MM3 bl_noconn wl Q gnd NMOS_VTG W=135.00n L=50n
MM2 br_noconn wl Q_bar gnd NMOS_VTG W=135.00n L=50n
.ENDS cell_6t
.ENDS cell_1rw

View File

@ -1,14 +0,0 @@
.SUBCKT dummy_cell_1rw_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
MM9 RA_to_R_right wl1 br1_noconn gnd NMOS_VTG W=180.0n L=50n m=1
MM8 RA_to_R_right Q gnd gnd NMOS_VTG W=180.0n L=50n m=1
MM7 RA_to_R_left Q_bar gnd gnd NMOS_VTG W=180.0n L=50n m=1
MM6 RA_to_R_left wl1 bl1_noconn gnd NMOS_VTG W=180.0n L=50n m=1
MM5 Q wl0 bl0_noconn gnd NMOS_VTG W=135.00n L=50n m=1
MM4 Q_bar wl0 br0_noconn gnd NMOS_VTG W=135.00n L=50n m=1
MM1 Q Q_bar gnd gnd NMOS_VTG W=205.0n L=50n m=1
MM0 Q_bar Q gnd gnd NMOS_VTG W=205.0n L=50n m=1
MM3 Q Q_bar vdd vdd PMOS_VTG W=90n L=50n m=1
MM2 Q_bar Q vdd vdd PMOS_VTG W=90n L=50n m=1
.ENDS

View File

@ -1,5 +1,5 @@
.SUBCKT dummy_cell_1w_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
.SUBCKT dummy_cell_2rw bl0 br0 bl1 br1 wl0 wl1 vdd gnd
MM9 RA_to_R_right wl1 br1_noconn gnd NMOS_VTG W=180.0n L=50n m=1
MM8 RA_to_R_right Q gnd gnd NMOS_VTG W=180.0n L=50n m=1
MM7 RA_to_R_left Q_bar gnd gnd NMOS_VTG W=180.0n L=50n m=1

View File

@ -1,5 +1,5 @@
.SUBCKT replica_cell_6t bl br wl vdd gnd
.SUBCKT replica_cell_1rw bl br wl vdd gnd
* Inverter 1
MM0 vdd Q gnd gnd NMOS_VTG W=205.00n L=50n
MM4 vdd Q vdd vdd PMOS_VTG W=90n L=50n
@ -11,5 +11,5 @@ MM5 Q vdd vdd vdd PMOS_VTG W=90n L=50n
* Access transistors
MM3 bl wl Q gnd NMOS_VTG W=135.00n L=50n
MM2 br wl vdd gnd NMOS_VTG W=135.00n L=50n
.ENDS cell_6t
.ENDS cell_1rw

View File

@ -1,14 +0,0 @@
.SUBCKT replica_cell_1rw_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
MM9 RA_to_R_right wl1 br1 gnd NMOS_VTG W=180.0n L=50n m=1
MM8 RA_to_R_right Q gnd gnd NMOS_VTG W=180.0n L=50n m=1
MM7 RA_to_R_left vdd gnd gnd NMOS_VTG W=180.0n L=50n m=1
MM6 RA_to_R_left wl1 bl1 gnd NMOS_VTG W=180.0n L=50n m=1
MM5 Q wl0 bl0 gnd NMOS_VTG W=135.00n L=50n m=1
MM4 vdd wl0 br0 gnd NMOS_VTG W=135.00n L=50n m=1
MM1 Q vdd gnd gnd NMOS_VTG W=205.0n L=50n m=1
MM0 vdd Q gnd gnd NMOS_VTG W=205.0n L=50n m=1
MM3 Q vdd vdd vdd PMOS_VTG W=90n L=50n m=1
MM2 vdd Q vdd vdd PMOS_VTG W=90n L=50n m=1
.ENDS

View File

@ -1,5 +1,5 @@
.SUBCKT replica_cell_1w_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
.SUBCKT replica_cell_2rw bl0 br0 bl1 br1 wl0 wl1 vdd gnd
MM9 RA_to_R_right wl1 br1 gnd NMOS_VTG W=180.0n L=50n m=1
MM8 RA_to_R_right Q gnd gnd NMOS_VTG W=180.0n L=50n m=1
MM7 RA_to_R_left vdd gnd gnd NMOS_VTG W=180.0n L=50n m=1

View File

@ -31,8 +31,6 @@ tech_modules = module_type()
# Custom cell properties
###################################################
cell_properties = cell_properties()
cell_properties.bitcell.mirror.x = True
cell_properties.bitcell.mirror.y = False
cell_properties.bitcell_power_pin_directions = ("V", "V")
###################################################
@ -438,22 +436,23 @@ spice["bitcell_leakage"] = 1 # Leakage power of a single bitcell in nW
spice["inv_leakage"] = 1 # Leakage power of inverter in nW
spice["nand2_leakage"] = 1 # Leakage power of 2-input nand in nW
spice["nand3_leakage"] = 1 # Leakage power of 3-input nand in nW
spice["nand4_leakage"] = 1 # Leakage power of 4-input nand in nW
spice["nor2_leakage"] = 1 # Leakage power of 2-input nor in nW
spice["dff_leakage"] = 1 # Leakage power of flop in nW
spice["default_event_frequency"] = 100 # Default event activity of every gate. MHz
#Parameters related to sense amp enable timing and delay chain/RBL sizing
parameter["le_tau"] = 2.25 #In pico-seconds.
parameter["cap_relative_per_ff"] = 7.5 #Units of Relative Capacitance/ Femto-Farad
parameter["dff_clk_cin"] = 30.6 #relative capacitance
parameter["6tcell_wl_cin"] = 3 #relative capacitance
parameter["min_inv_para_delay"] = 2.4 #Tau delay units
parameter["sa_en_pmos_size"] = 0.72 #micro-meters
parameter["sa_en_nmos_size"] = 0.27 #micro-meters
parameter["sa_inv_pmos_size"] = 0.54 #micro-meters
parameter["sa_inv_nmos_size"] = 0.27 #micro-meters
parameter["bitcell_drain_cap"] = 0.1 #In Femto-Farad, approximation of drain capacitance
# Parameters related to sense amp enable timing and delay chain/RBL sizing
parameter["le_tau"] = 2.25 # In pico-seconds.
parameter["cap_relative_per_ff"] = 7.5 # Units of Relative Capacitance/ Femto-Farad
parameter["dff_clk_cin"] = 30.6 # relative capacitance
parameter["6tcell_wl_cin"] = 3 # relative capacitance
parameter["min_inv_para_delay"] = 2.4 # Tau delay units
parameter["sa_en_pmos_size"] = 0.72 # micro-meters
parameter["sa_en_nmos_size"] = 0.27 # micro-meters
parameter["sa_inv_pmos_size"] = 0.54 # micro-meters
parameter["sa_inv_nmos_size"] = 0.27 # micro-meters
parameter["bitcell_drain_cap"] = 0.1 # In Femto-Farad, approximation of drain capacitance
###################################################
# Technology Tool Preferences

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,146 +0,0 @@
magic
tech scmos
timestamp 1577067400
<< nwell >>
rect 0 46 54 75
<< pwell >>
rect 0 0 54 46
<< ntransistor >>
rect 14 33 16 37
rect 22 29 24 37
rect 30 29 32 37
rect 38 33 40 37
rect 14 17 16 23
rect 22 17 24 23
rect 30 17 32 23
rect 38 17 40 23
<< ptransistor >>
rect 22 54 24 57
rect 30 54 32 57
<< ndiffusion >>
rect 13 33 14 37
rect 16 33 17 37
rect 21 33 22 37
rect 17 29 22 33
rect 24 29 25 37
rect 29 29 30 37
rect 32 33 33 37
rect 37 33 38 37
rect 40 33 41 37
rect 32 29 37 33
rect 9 21 14 23
rect 13 17 14 21
rect 16 17 22 23
rect 24 17 25 23
rect 29 17 30 23
rect 32 17 38 23
rect 40 21 45 23
rect 40 17 41 21
<< pdiffusion >>
rect 21 54 22 57
rect 24 54 25 57
rect 29 54 30 57
rect 32 54 33 57
<< ndcontact >>
rect 9 33 13 37
rect 17 33 21 37
rect 25 29 29 37
rect 33 33 37 37
rect 41 33 45 37
rect 9 17 13 21
rect 25 17 29 23
rect 41 17 45 21
<< pdcontact >>
rect 17 54 21 58
rect 25 54 29 58
rect 33 54 37 58
<< psubstratepcontact >>
rect 25 9 29 13
<< nsubstratencontact >>
rect 25 68 29 72
<< polysilicon >>
rect 22 57 24 60
rect 30 57 32 60
rect 22 44 24 54
rect 30 51 32 54
rect 31 47 32 51
rect 14 37 16 44
rect 22 40 23 44
rect 22 37 24 40
rect 30 37 32 47
rect 38 37 40 44
rect 14 31 16 33
rect 38 31 40 33
rect 14 23 16 24
rect 22 23 24 29
rect 30 23 32 29
rect 38 23 40 24
rect 14 15 16 17
rect 22 15 24 17
rect 30 15 32 17
rect 38 15 40 17
<< polycontact >>
rect 27 47 31 51
rect 10 40 14 44
rect 23 40 27 44
rect 40 40 44 44
rect 12 24 16 28
rect 38 24 42 28
<< metal1 >>
rect 0 68 25 72
rect 29 68 54 72
rect 0 61 54 65
rect 10 44 14 61
rect 17 51 20 54
rect 17 47 27 51
rect 17 37 20 47
rect 34 44 37 54
rect 27 40 37 44
rect 40 44 44 61
rect 34 37 37 40
rect 6 33 9 37
rect 45 33 48 37
rect 25 23 29 29
rect 25 13 29 17
rect 0 9 25 13
rect 29 9 54 13
rect 0 2 16 6
rect 20 2 34 6
rect 38 2 54 6
<< m2contact >>
rect 25 68 29 72
rect 25 54 29 58
rect 2 33 6 37
rect 48 33 52 37
rect 16 24 20 28
rect 34 24 38 28
rect 9 17 13 21
rect 41 17 45 21
rect 16 2 20 6
rect 34 2 38 6
<< metal2 >>
rect 2 37 6 72
rect 2 0 6 33
rect 9 21 13 72
rect 25 58 29 68
rect 9 0 13 17
rect 16 6 20 24
rect 34 6 38 24
rect 41 21 45 72
rect 41 0 45 17
rect 48 37 52 72
rect 48 0 52 33
<< comment >>
rect 0 0 54 70
<< labels >>
rlabel metal1 19 63 19 63 1 wl0
rlabel metal1 19 70 19 70 5 vdd
rlabel metal1 27 4 27 4 1 wl1
rlabel psubstratepcontact 27 11 27 11 1 gnd
rlabel metal2 4 7 4 7 2 bl0
rlabel metal2 11 7 11 7 1 bl1
rlabel metal2 43 7 43 7 1 br1
rlabel metal2 50 7 50 7 8 br0
rlabel polycontact 29 49 29 49 1 Q
rlabel polycontact 25 42 25 42 1 Q_bar
<< end >>

View File

@ -1,41 +0,0 @@
timestamp 1536091415
version 8.2
tech scmos
style TSMC0.35um(tsmc35)from:t11c
scale 1000 1 5
resistclasses 3700 2800 1018000 1018000 1 6000 6000 80 70 80 40
node "comment_0_0#" 0 0 0 0 bb 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
node "br" 6 -1.43219e-14 96 -8 ndc 320 72 0 0 0 0 0 0 0 0 0 0 0 0 512 96 3456 464 0 0 0 0
node "bl" 6 -8.88178e-16 40 -8 ndc 320 72 0 0 0 0 0 0 0 0 0 0 0 0 512 96 3200 432 0 0 0 0
node "wl" 115 -2.89546e-13 -8 12 p 0 0 0 0 0 0 0 0 0 0 1536 360 0 0 2496 344 0 0 0 0 0 0
node "a_36_40#" 140 -3.51719e-13 36 40 ndif 960 144 304 72 0 0 0 0 0 0 1984 424 0 0 2048 288 0 0 0 0 0 0
node "a_28_32#" 160 -8.06466e-13 28 32 p 960 144 304 72 0 0 0 0 0 0 2000 456 0 0 1920 272 0 0 0 0 0 0
node "gnd" 41 -27.888 -32 -32 pw 1792 240 512 128 0 0 0 0 29600 696 0 0 0 0 2688 400 6400 864 0 0 0 0
equiv "gnd" "gnd"
node "vdd" 2340 2596 -32 116 nw 256 64 800 176 17600 576 0 0 0 0 0 0 0 0 3456 464 256 64 0 0 0 0
cap "wl" "bl" 189.768
cap "a_36_40#" "br" 17.59
cap "wl" "br" 189.768
cap "vdd" "bl" 135.015
cap "bl" "br" 27.492
cap "vdd" "br" 117.084
cap "gnd" "a_28_32#" 880.405
cap "gnd" "a_36_40#" 401.284
cap "a_28_32#" "a_36_40#" 272.793
cap "gnd" "wl" 1198.41
cap "gnd" "bl" 712.11
cap "a_28_32#" "wl" 108.364
cap "vdd" "gnd" 510.12
cap "gnd" "br" 698.471
cap "a_36_40#" "wl" 108.364
cap "a_28_32#" "bl" 104.205
cap "vdd" "a_28_32#" 430.812
cap "a_36_40#" "bl" 29.396
cap "a_28_32#" "br" 308.488
cap "vdd" "a_36_40#" 709.108
fet nfet 96 12 97 13 128 48 "gnd" "wl" 16 0 "br" 16 0 "a_28_32#" 16 0
fet nfet 40 12 41 13 128 48 "gnd" "wl" 16 0 "bl" 16 0 "a_36_40#" 16 0
fet nfet 116 40 117 41 256 80 "gnd" "a_36_40#" 16 0 "a_28_32#" 32 0 "gnd" 32 0
fet nfet 28 40 29 41 256 80 "gnd" "a_28_32#" 16 0 "gnd" 32 0 "a_36_40#" 32 0
fet pfet 108 148 109 149 192 56 "vdd" "a_36_40#" 32 0 "a_28_32#" 12 0 "vdd" 12 0
fet pfet 28 148 29 149 192 56 "vdd" "a_28_32#" 32 0 "vdd" 12 0 "a_36_40#" 12 0

View File

@ -1,15 +0,0 @@
* SPICE3 file created from cell_6t.ext - technology: scmos
M1000 a_36_40# a_28_32# vdd vdd pfet w=0.6u l=0.8u
+ ad=0.76p pd=3.6u as=2p ps=8.8u
M1001 vdd a_36_40# a_28_32# vdd pfet w=0.6u l=0.8u
+ ad=0p pd=0u as=0.76p ps=3.6u
M1002 a_36_40# a_28_32# gnd gnd nfet w=1.6u l=0.4u
+ ad=2.4p pd=7.2u as=4.48p ps=12u
M1003 gnd a_36_40# a_28_32# gnd nfet w=1.6u l=0.4u
+ ad=0p pd=0u as=2.4p ps=7.2u
M1004 a_36_40# wl bl gnd nfet w=0.8u l=0.4u
+ ad=0p pd=0u as=0.8p ps=3.6u
M1005 a_28_32# wl br gnd nfet w=0.8u l=0.4u
+ ad=0p pd=0u as=0.8p ps=3.6u
C0 vdd 0 2.60fF

Some files were not shown because too many files have changed in this diff Show More