mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev' into characterizer_bug_fixes
This commit is contained in:
commit
ac425643a0
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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]))
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
@ -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)
|
||||
|
|
@ -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.
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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")
|
||||
|
||||
|
||||
|
|
@ -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")
|
||||
|
||||
|
||||
|
|
@ -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")
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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")
|
||||
|
||||
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
@ -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.
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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."""
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
||||
|
|
|
|||
|
|
@ -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."""
|
||||
|
|
|
|||
|
|
@ -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."""
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
||||
|
|
@ -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"
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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."""
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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 >>
|
||||
|
|
@ -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
|
||||
|
|
@ -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
Loading…
Reference in New Issue