mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev' into bisr
This commit is contained in:
commit
2498ff07ea
|
|
@ -8,3 +8,5 @@
|
||||||
*.toc
|
*.toc
|
||||||
*.synctex.gz
|
*.synctex.gz
|
||||||
**/model_data
|
**/model_data
|
||||||
|
outputs
|
||||||
|
technology/freepdk45/ncsu_basekit
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
|
||||||
|
class drc_error(Exception):
|
||||||
|
"""Exception raised for DRC errors.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
expression -- input expression in which the error occurred
|
||||||
|
message -- explanation of the error
|
||||||
|
"""
|
||||||
|
|
||||||
|
# def __init__(self, expression, message):
|
||||||
|
# self.expression = expression
|
||||||
|
# self.message = message
|
||||||
|
def __init__(self, message):
|
||||||
|
self.message = message
|
||||||
|
|
@ -296,11 +296,11 @@ class path(geometry):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
""" override print function output """
|
""" override print function output """
|
||||||
return "path: layer=" + self.layerNumber + " w=" + self.width
|
return "path: layer=" + self.layerNumber + " purpose=" + str(self.layerPurpose) + " w=" + self.width
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
""" override print function output """
|
""" override print function output """
|
||||||
return "( path: layer=" + self.layerNumber + " w=" + self.width + " coords=" + str(self.coordinates) + " )"
|
return "( path: layer=" + self.layerNumber + " purpose=" + str(self.layerPurpose) + " w=" + self.width + " coords=" + str(self.coordinates) + " )"
|
||||||
|
|
||||||
|
|
||||||
class label(geometry):
|
class label(geometry):
|
||||||
|
|
@ -340,11 +340,11 @@ class label(geometry):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
""" override print function output """
|
""" override print function output """
|
||||||
return "label: " + self.text + " layer=" + str(self.layerNumber)
|
return "label: " + self.text + " layer=" + str(self.layerNumber) + " purpose=" + str(self.layerPurpose)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
""" override print function output """
|
""" override print function output """
|
||||||
return "( label: " + self.text + " @" + str(self.offset) + " layer=" + str(self.layerNumber) + " )"
|
return "( label: " + self.text + " @" + str(self.offset) + " layer=" + str(self.layerNumber) + " purpose=" + str(self.layerPurpose) + " )"
|
||||||
|
|
||||||
|
|
||||||
class rectangle(geometry):
|
class rectangle(geometry):
|
||||||
|
|
@ -391,4 +391,4 @@ class rectangle(geometry):
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
""" override print function output """
|
""" override print function output """
|
||||||
return "( rect: @" + str(self.offset) + " WxH=" + str(self.width) + "x" + str(self.height) + " layer=" + str(self.layerNumber) + " )"
|
return "( rect: @" + str(self.offset) + " WxH=" + str(self.width) + "x" + str(self.height) + " layer=" + str(self.layerNumber) + " purpose=" + str(self.layerPurpose) + " )"
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,11 @@
|
||||||
#
|
#
|
||||||
import hierarchy_layout
|
import hierarchy_layout
|
||||||
import hierarchy_spice
|
import hierarchy_spice
|
||||||
import globals
|
|
||||||
import verify
|
import verify
|
||||||
import debug
|
import debug
|
||||||
import os
|
import os
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
import graph_util
|
|
||||||
|
|
||||||
total_drc_errors = 0
|
|
||||||
total_lvs_errors = 0
|
|
||||||
|
|
||||||
class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
"""
|
"""
|
||||||
|
|
@ -28,6 +24,14 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds"
|
self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds"
|
||||||
self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp"
|
self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp"
|
||||||
|
|
||||||
|
# If we have a separate lvs directory, then all the lvs files
|
||||||
|
# should be in there (all or nothing!)
|
||||||
|
lvs_dir = OPTS.openram_tech + "lvs_lib/"
|
||||||
|
if os.path.exists(lvs_dir):
|
||||||
|
self.lvs_file = lvs_dir + name + ".sp"
|
||||||
|
else:
|
||||||
|
self.lvs_file = self.sp_file
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
hierarchy_spice.spice.__init__(self, name)
|
hierarchy_spice.spice.__init__(self, name)
|
||||||
hierarchy_layout.layout.__init__(self, name)
|
hierarchy_layout.layout.__init__(self, name)
|
||||||
|
|
@ -44,68 +48,93 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
inst_map = inst.mod.pin_map
|
inst_map = inst.mod.pin_map
|
||||||
return inst_map
|
return inst_map
|
||||||
|
|
||||||
|
def DRC_LVS(self, final_verification=False, force_check=False):
|
||||||
def DRC_LVS(self, final_verification=False, top_level=False):
|
|
||||||
"""Checks both DRC and LVS for a module"""
|
"""Checks both DRC and LVS for a module"""
|
||||||
|
|
||||||
# Final verification option does not allow nets to be connected by label.
|
# No layout to check
|
||||||
|
if OPTS.netlist_only:
|
||||||
|
return ("skipped", "skipped")
|
||||||
# Unit tests will check themselves.
|
# Unit tests will check themselves.
|
||||||
if OPTS.is_unit_test:
|
if not force_check and OPTS.is_unit_test:
|
||||||
return
|
return ("skipped", "skipped")
|
||||||
if not OPTS.check_lvsdrc:
|
if not force_check and not OPTS.check_lvsdrc:
|
||||||
return
|
return ("skipped", "skipped")
|
||||||
# Do not run if disabled in options.
|
# Do not run if disabled in options.
|
||||||
if (OPTS.inline_lvsdrc or top_level):
|
if (OPTS.inline_lvsdrc or force_check or final_verification):
|
||||||
|
|
||||||
global total_drc_errors
|
|
||||||
global total_lvs_errors
|
|
||||||
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name)
|
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name)
|
||||||
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
|
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
|
||||||
self.sp_write(tempspice)
|
self.lvs_write(tempspice)
|
||||||
self.gds_write(tempgds)
|
self.gds_write(tempgds)
|
||||||
|
# Final verification option does not allow nets to be connected by label.
|
||||||
num_drc_errors = verify.run_drc(self.name, tempgds, extract=True, final_verification=final_verification)
|
num_drc_errors = verify.run_drc(self.name, tempgds, extract=True, final_verification=final_verification)
|
||||||
num_lvs_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification)
|
num_lvs_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification)
|
||||||
debug.check(num_drc_errors == 0,"DRC failed for {0} with {1} error(s)".format(self.name,num_drc_errors))
|
|
||||||
debug.check(num_lvs_errors == 0,"LVS failed for {0} with {1} errors(s)".format(self.name,num_lvs_errors))
|
# force_check is used to determine decoder height and other things, so we shouldn't fail
|
||||||
total_drc_errors += num_drc_errors
|
# if that flag is set
|
||||||
total_lvs_errors += num_lvs_errors
|
if OPTS.inline_lvsdrc and not force_check:
|
||||||
|
debug.check(num_drc_errors == 0,
|
||||||
|
"DRC failed for {0} with {1} error(s)".format(self.name,
|
||||||
|
num_drc_errors))
|
||||||
|
debug.check(num_lvs_errors == 0,
|
||||||
|
"LVS failed for {0} with {1} errors(s)".format(self.name,
|
||||||
|
num_lvs_errors))
|
||||||
|
|
||||||
os.remove(tempspice)
|
os.remove(tempspice)
|
||||||
os.remove(tempgds)
|
os.remove(tempgds)
|
||||||
|
|
||||||
|
return (num_drc_errors, num_lvs_errors)
|
||||||
|
else:
|
||||||
|
return ("skipped", "skipped")
|
||||||
|
|
||||||
def DRC(self, final_verification=False):
|
def DRC(self, final_verification=False):
|
||||||
"""Checks DRC for a module"""
|
"""Checks DRC for a module"""
|
||||||
# Unit tests will check themselves.
|
# Unit tests will check themselves.
|
||||||
# Do not run if disabled in options.
|
# Do not run if disabled in options.
|
||||||
|
|
||||||
|
# No layout to check
|
||||||
|
if OPTS.netlist_only:
|
||||||
|
return "skipped"
|
||||||
|
|
||||||
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
|
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
|
||||||
global total_drc_errors
|
|
||||||
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
|
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
|
||||||
self.gds_write(tempgds)
|
self.gds_write(tempgds)
|
||||||
num_errors = verify.run_drc(self.name, tempgds, final_verification=final_verification)
|
num_errors = verify.run_drc(self.name, tempgds, final_verification=final_verification)
|
||||||
total_drc_errors += num_errors
|
debug.check(num_errors == 0,
|
||||||
debug.check(num_errors == 0,"DRC failed for {0} with {1} error(s)".format(self.name,num_error))
|
"DRC failed for {0} with {1} error(s)".format(self.name,
|
||||||
|
num_errors))
|
||||||
|
|
||||||
os.remove(tempgds)
|
os.remove(tempgds)
|
||||||
|
|
||||||
|
return num_errors
|
||||||
|
else:
|
||||||
|
return "skipped"
|
||||||
|
|
||||||
def LVS(self, final_verification=False):
|
def LVS(self, final_verification=False):
|
||||||
"""Checks LVS for a module"""
|
"""Checks LVS for a module"""
|
||||||
# Unit tests will check themselves.
|
# Unit tests will check themselves.
|
||||||
# Do not run if disabled in options.
|
# Do not run if disabled in options.
|
||||||
|
|
||||||
|
# No layout to check
|
||||||
|
if OPTS.netlist_only:
|
||||||
|
return "skipped"
|
||||||
|
|
||||||
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
|
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
|
||||||
global total_lvs_errors
|
|
||||||
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name)
|
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name)
|
||||||
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
|
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
|
||||||
self.sp_write(tempspice)
|
self.lvs_write(tempspice)
|
||||||
self.gds_write(tempgds)
|
self.gds_write(tempgds)
|
||||||
num_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification)
|
num_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification)
|
||||||
total_lvs_errors += num_errors
|
debug.check(num_errors == 0,
|
||||||
debug.check(num_errors == 0,"LVS failed for {0} with {1} error(s)".format(self.name,num_errors))
|
"LVS failed for {0} with {1} error(s)".format(self.name,
|
||||||
|
num_errors))
|
||||||
os.remove(tempspice)
|
os.remove(tempspice)
|
||||||
os.remove(tempgds)
|
os.remove(tempgds)
|
||||||
|
|
||||||
|
return num_errors
|
||||||
|
else:
|
||||||
|
return "skipped"
|
||||||
|
|
||||||
def init_graph_params(self):
|
def init_graph_params(self):
|
||||||
"""Initializes parameters relevant to the graph creation"""
|
"""Initializes parameters relevant to the graph creation"""
|
||||||
# Only initializes a set for checking instances which should not be added
|
# Only initializes a set for checking instances which should not be added
|
||||||
|
|
@ -116,7 +145,9 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
|
|
||||||
# Translate port names to external nets
|
# Translate port names to external nets
|
||||||
if len(port_nets) != len(self.pins):
|
if len(port_nets) != len(self.pins):
|
||||||
debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,self.pins),1)
|
debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,
|
||||||
|
self.pins),
|
||||||
|
1)
|
||||||
port_dict = {pin: port for pin, port in zip(self.pins, port_nets)}
|
port_dict = {pin: port for pin, port in zip(self.pins, port_nets)}
|
||||||
debug.info(3, "Instance name={}".format(inst_name))
|
debug.info(3, "Instance name={}".format(inst_name))
|
||||||
for subinst, conns in zip(self.insts, self.conns):
|
for subinst, conns in zip(self.insts, self.conns):
|
||||||
|
|
@ -130,7 +161,9 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
"""Collects all the nets and the parent inst of that net."""
|
"""Collects all the nets and the parent inst of that net."""
|
||||||
# Translate port names to external nets
|
# Translate port names to external nets
|
||||||
if len(port_nets) != len(self.pins):
|
if len(port_nets) != len(self.pins):
|
||||||
debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,self.pins),1)
|
debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,
|
||||||
|
self.pins),
|
||||||
|
1)
|
||||||
port_dict = {pin: port for pin, port in zip(self.pins, port_nets)}
|
port_dict = {pin: port for pin, port in zip(self.pins, port_nets)}
|
||||||
debug.info(3, "Instance name={}".format(inst_name))
|
debug.info(3, "Instance name={}".format(inst_name))
|
||||||
for subinst, conns in zip(self.insts, self.conns):
|
for subinst, conns in zip(self.insts, self.conns):
|
||||||
|
|
@ -190,8 +223,10 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
parent_net.lower() == alias_net.lower()
|
parent_net.lower() == alias_net.lower()
|
||||||
|
|
||||||
def get_mod_net(self, parent_net, child_inst, child_conns):
|
def get_mod_net(self, parent_net, child_inst, child_conns):
|
||||||
"""Given an instance and net, returns the internal net in the mod
|
"""
|
||||||
corresponding to input net."""
|
Given an instance and net, returns the internal net in the mod
|
||||||
|
corresponding to input net.
|
||||||
|
"""
|
||||||
for conn, pin in zip(child_conns, child_inst.mod.pins):
|
for conn, pin in zip(child_conns, child_inst.mod.pins):
|
||||||
if parent_net.lower() == conn.lower():
|
if parent_net.lower() == conn.lower():
|
||||||
return pin
|
return pin
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import collections
|
||||||
import geometry
|
import geometry
|
||||||
import gdsMill
|
import gdsMill
|
||||||
import debug
|
import debug
|
||||||
|
from math import sqrt
|
||||||
from tech import drc, GDS
|
from tech import drc, GDS
|
||||||
from tech import layer as techlayer
|
from tech import layer as techlayer
|
||||||
from tech import layer_stacks
|
from tech import layer_stacks
|
||||||
|
|
@ -16,6 +17,7 @@ import os
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from pin_layout import pin_layout
|
from pin_layout import pin_layout
|
||||||
|
from utils import round_to_grid
|
||||||
|
|
||||||
|
|
||||||
class layout():
|
class layout():
|
||||||
|
|
@ -45,7 +47,6 @@ class layout():
|
||||||
except ImportError:
|
except ImportError:
|
||||||
self.pwr_grid_layer = "m3"
|
self.pwr_grid_layer = "m3"
|
||||||
|
|
||||||
|
|
||||||
############################################################
|
############################################################
|
||||||
# GDS layout
|
# GDS layout
|
||||||
############################################################
|
############################################################
|
||||||
|
|
@ -213,12 +214,14 @@ class layout():
|
||||||
width = drc["minwidth_{}".format(layer)]
|
width = drc["minwidth_{}".format(layer)]
|
||||||
if not height:
|
if not height:
|
||||||
height = drc["minwidth_{}".format(layer)]
|
height = drc["minwidth_{}".format(layer)]
|
||||||
# negative layers indicate "unused" layers in a given technology
|
|
||||||
lpp = techlayer[layer]
|
lpp = techlayer[layer]
|
||||||
if lpp[0] >= 0:
|
if abs(offset[0]-5.16250)<0.01 and abs(offset[1]-8.70750)<0.01:
|
||||||
self.objs.append(geometry.rectangle(lpp, offset, width, height))
|
import pdb; pdb.set_trace()
|
||||||
|
self.objs.append(geometry.rectangle(lpp,
|
||||||
|
offset,
|
||||||
|
width,
|
||||||
|
height))
|
||||||
return self.objs[-1]
|
return self.objs[-1]
|
||||||
return None
|
|
||||||
|
|
||||||
def add_rect_center(self, layer, offset, width=None, height=None):
|
def add_rect_center(self, layer, offset, width=None, height=None):
|
||||||
"""
|
"""
|
||||||
|
|
@ -229,16 +232,13 @@ class layout():
|
||||||
width = drc["minwidth_{}".format(layer)]
|
width = drc["minwidth_{}".format(layer)]
|
||||||
if not height:
|
if not height:
|
||||||
height = drc["minwidth_{}".format(layer)]
|
height = drc["minwidth_{}".format(layer)]
|
||||||
# negative layers indicate "unused" layers in a given technology
|
|
||||||
lpp = techlayer[layer]
|
lpp = techlayer[layer]
|
||||||
corrected_offset = offset - vector(0.5 * width, 0.5 * height)
|
corrected_offset = offset - vector(0.5 * width, 0.5 * height)
|
||||||
if lpp[0] >= 0:
|
|
||||||
self.objs.append(geometry.rectangle(lpp,
|
self.objs.append(geometry.rectangle(lpp,
|
||||||
corrected_offset,
|
corrected_offset,
|
||||||
width,
|
width,
|
||||||
height))
|
height))
|
||||||
return self.objs[-1]
|
return self.objs[-1]
|
||||||
return None
|
|
||||||
|
|
||||||
def add_segment_center(self, layer, start, end):
|
def add_segment_center(self, layer, start, end):
|
||||||
"""
|
"""
|
||||||
|
|
@ -412,22 +412,17 @@ class layout():
|
||||||
|
|
||||||
def add_label(self, text, layer, offset=[0, 0], zoom=-1):
|
def add_label(self, text, layer, offset=[0, 0], zoom=-1):
|
||||||
"""Adds a text label on the given layer,offset, and zoom level"""
|
"""Adds a text label on the given layer,offset, and zoom level"""
|
||||||
# negative layers indicate "unused" layers in a given technology
|
|
||||||
debug.info(5, "add label " + str(text) + " " + layer + " " + str(offset))
|
debug.info(5, "add label " + str(text) + " " + layer + " " + str(offset))
|
||||||
lpp = techlayer[layer]
|
lpp = techlayer[layer]
|
||||||
if lpp[0] >= 0:
|
|
||||||
self.objs.append(geometry.label(text, lpp, offset, zoom))
|
self.objs.append(geometry.label(text, lpp, offset, zoom))
|
||||||
return self.objs[-1]
|
return self.objs[-1]
|
||||||
return None
|
|
||||||
|
|
||||||
def add_path(self, layer, coordinates, width=None):
|
def add_path(self, layer, coordinates, width=None):
|
||||||
"""Connects a routing path on given layer,coordinates,width."""
|
"""Connects a routing path on given layer,coordinates,width."""
|
||||||
debug.info(4, "add path " + str(layer) + " " + str(coordinates))
|
debug.info(4, "add path " + str(layer) + " " + str(coordinates))
|
||||||
import wire_path
|
import wire_path
|
||||||
# NOTE: (UNTESTED) add_path(...) is currently not used
|
# NOTE: (UNTESTED) add_path(...) is currently not used
|
||||||
# negative layers indicate "unused" layers in a given technology
|
|
||||||
# lpp = techlayer[layer]
|
# lpp = techlayer[layer]
|
||||||
# if lpp[0] >= 0:
|
|
||||||
# self.objs.append(geometry.path(lpp, coordinates, width))
|
# self.objs.append(geometry.path(lpp, coordinates, width))
|
||||||
|
|
||||||
wire_path.wire_path(obj=self,
|
wire_path.wire_path(obj=self,
|
||||||
|
|
@ -798,9 +793,7 @@ class layout():
|
||||||
self.add_rect(layer=layer,
|
self.add_rect(layer=layer,
|
||||||
offset=line_offset,
|
offset=line_offset,
|
||||||
height=length)
|
height=length)
|
||||||
# Make this the center of the rail
|
line_positions[names[i]] = line_offset + vector(half_minwidth, 0)
|
||||||
line_positions[names[i]] = line_offset + vector(half_minwidth,
|
|
||||||
0.5 * length)
|
|
||||||
else:
|
else:
|
||||||
for i in range(len(names)):
|
for i in range(len(names)):
|
||||||
line_offset = offset + vector(0,
|
line_offset = offset + vector(0,
|
||||||
|
|
@ -982,6 +975,7 @@ class layout():
|
||||||
def create_channel_route(self, netlist,
|
def create_channel_route(self, netlist,
|
||||||
offset,
|
offset,
|
||||||
layer_stack,
|
layer_stack,
|
||||||
|
layer_dirs=None,
|
||||||
vertical=False):
|
vertical=False):
|
||||||
"""
|
"""
|
||||||
The net list is a list of the nets. Each net is a list of pins
|
The net list is a list of the nets. Each net is a list of pins
|
||||||
|
|
@ -1020,6 +1014,7 @@ class layout():
|
||||||
|
|
||||||
def vcg_pin_overlap(pin1, pin2, vertical, pitch):
|
def vcg_pin_overlap(pin1, pin2, vertical, pitch):
|
||||||
""" Check for vertical or horizontal overlap of the two pins """
|
""" Check for vertical or horizontal overlap of the two pins """
|
||||||
|
|
||||||
# FIXME: If the pins are not in a row, this may break.
|
# FIXME: If the pins are not in a row, this may break.
|
||||||
# However, a top pin shouldn't overlap another top pin,
|
# However, a top pin shouldn't overlap another top pin,
|
||||||
# for example, so the
|
# for example, so the
|
||||||
|
|
@ -1033,12 +1028,24 @@ class layout():
|
||||||
overlaps = (not vertical and x_overlap) or (vertical and y_overlap)
|
overlaps = (not vertical and x_overlap) or (vertical and y_overlap)
|
||||||
return overlaps
|
return overlaps
|
||||||
|
|
||||||
|
if not layer_dirs:
|
||||||
|
# Use the preferred layer directions
|
||||||
if self.get_preferred_direction(layer_stack[0]) == "V":
|
if self.get_preferred_direction(layer_stack[0]) == "V":
|
||||||
self.vertical_layer = layer_stack[0]
|
self.vertical_layer = layer_stack[0]
|
||||||
self.horizontal_layer = layer_stack[2]
|
self.horizontal_layer = layer_stack[2]
|
||||||
else:
|
else:
|
||||||
self.vertical_layer = layer_stack[2]
|
self.vertical_layer = layer_stack[2]
|
||||||
self.horizontal_layer = layer_stack[0]
|
self.horizontal_layer = layer_stack[0]
|
||||||
|
else:
|
||||||
|
# Use the layer directions specified to the router rather than
|
||||||
|
# the preferred directions
|
||||||
|
debug.check(layer_dirs[0] != layer_dirs[1], "Must have unique layer directions.")
|
||||||
|
if layer_dirs[0] == "V":
|
||||||
|
self.vertical_layer = layer_stack[0]
|
||||||
|
self.horizontal_layer = layer_stack[2]
|
||||||
|
else:
|
||||||
|
self.horizontal_layer = layer_stack[0]
|
||||||
|
self.vertical_layer = layer_stack[2]
|
||||||
|
|
||||||
layer_stuff = self.get_layer_pitch(self.vertical_layer)
|
layer_stuff = self.get_layer_pitch(self.vertical_layer)
|
||||||
(self.vertical_pitch, self.vertical_width, self.vertical_space) = layer_stuff
|
(self.vertical_pitch, self.vertical_width, self.vertical_space) = layer_stuff
|
||||||
|
|
@ -1121,17 +1128,17 @@ class layout():
|
||||||
self.horizontal_pitch)
|
self.horizontal_pitch)
|
||||||
offset += vector(0, self.horizontal_pitch)
|
offset += vector(0, self.horizontal_pitch)
|
||||||
|
|
||||||
def create_vertical_channel_route(self, netlist, offset, layer_stack):
|
def create_vertical_channel_route(self, netlist, offset, layer_stack, layer_dirs=None):
|
||||||
"""
|
"""
|
||||||
Wrapper to create a vertical channel route
|
Wrapper to create a vertical channel route
|
||||||
"""
|
"""
|
||||||
self.create_channel_route(netlist, offset, layer_stack, vertical=True)
|
self.create_channel_route(netlist, offset, layer_stack, layer_dirs, vertical=True)
|
||||||
|
|
||||||
def create_horizontal_channel_route(self, netlist, offset, layer_stack):
|
def create_horizontal_channel_route(self, netlist, offset, layer_stack, layer_dirs=None):
|
||||||
"""
|
"""
|
||||||
Wrapper to create a horizontal channel route
|
Wrapper to create a horizontal channel route
|
||||||
"""
|
"""
|
||||||
self.create_channel_route(netlist, offset, layer_stack, vertical=False)
|
self.create_channel_route(netlist, offset, layer_stack, layer_dirs, vertical=False)
|
||||||
|
|
||||||
def add_boundary(self, ll=vector(0, 0), ur=None):
|
def add_boundary(self, ll=vector(0, 0), ur=None):
|
||||||
""" Add boundary for debugging dimensions """
|
""" Add boundary for debugging dimensions """
|
||||||
|
|
@ -1193,11 +1200,9 @@ class layout():
|
||||||
"supply router."
|
"supply router."
|
||||||
.format(name, inst.name, self.pwr_grid_layer))
|
.format(name, inst.name, self.pwr_grid_layer))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_power_pin(self, name, loc, size=[1, 1], vertical=False, start_layer="m1"):
|
def add_power_pin(self, name, loc, size=[1, 1], vertical=False, start_layer="m1"):
|
||||||
"""
|
"""
|
||||||
Add a single power pin from the lowest power_grid layer down to M1 at
|
Add a single power pin from the lowest power_grid layer down to M1 (or li) at
|
||||||
the given center location. The starting layer is specified to determine
|
the given center location. The starting layer is specified to determine
|
||||||
which vias are needed.
|
which vias are needed.
|
||||||
"""
|
"""
|
||||||
|
|
@ -1211,23 +1216,28 @@ class layout():
|
||||||
else:
|
else:
|
||||||
direction = None
|
direction = None
|
||||||
|
|
||||||
|
|
||||||
via = self.add_via_stack_center(from_layer=start_layer,
|
via = self.add_via_stack_center(from_layer=start_layer,
|
||||||
to_layer=self.pwr_grid_layer,
|
to_layer=self.pwr_grid_layer,
|
||||||
size=size,
|
size=size,
|
||||||
offset=loc,
|
offset=loc,
|
||||||
direction=direction)
|
direction=direction)
|
||||||
|
|
||||||
if start_layer == self.pwr_grid_layer:
|
if start_layer == self.pwr_grid_layer:
|
||||||
self.add_layout_pin_rect_center(text=name,
|
self.add_layout_pin_rect_center(text=name,
|
||||||
layer=self.pwr_grid_layer,
|
layer=self.pwr_grid_layer,
|
||||||
offset=loc)
|
offset=loc)
|
||||||
else:
|
else:
|
||||||
|
# Hack for min area
|
||||||
|
if OPTS.tech_name == "s8":
|
||||||
|
width = round_to_grid(sqrt(drc["minarea_m3"]))
|
||||||
|
height = round_to_grid(drc["minarea_m3"]/width)
|
||||||
|
else:
|
||||||
|
width = via.width
|
||||||
|
height = via.height
|
||||||
self.add_layout_pin_rect_center(text=name,
|
self.add_layout_pin_rect_center(text=name,
|
||||||
layer=self.pwr_grid_layer,
|
layer=self.pwr_grid_layer,
|
||||||
offset=loc,
|
offset=loc,
|
||||||
width=via.width,
|
width=width,
|
||||||
height=via.height)
|
height=height)
|
||||||
|
|
||||||
def add_power_ring(self, bbox):
|
def add_power_ring(self, bbox):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ from wire_spice_model import *
|
||||||
from power_data import *
|
from power_data import *
|
||||||
import logical_effort
|
import logical_effort
|
||||||
|
|
||||||
|
|
||||||
class spice():
|
class spice():
|
||||||
"""
|
"""
|
||||||
This provides a set of useful generic types for hierarchy
|
This provides a set of useful generic types for hierarchy
|
||||||
|
|
@ -42,7 +43,7 @@ class spice():
|
||||||
# Keep track of any comments to add the the spice
|
# Keep track of any comments to add the the spice
|
||||||
try:
|
try:
|
||||||
self.commments
|
self.commments
|
||||||
except:
|
except AttributeError:
|
||||||
self.comments = []
|
self.comments = []
|
||||||
|
|
||||||
self.sp_read()
|
self.sp_read()
|
||||||
|
|
@ -56,7 +57,7 @@ class spice():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.commments
|
self.commments
|
||||||
except:
|
except AttributeError:
|
||||||
self.comments = []
|
self.comments = []
|
||||||
|
|
||||||
self.comments.append(comment)
|
self.comments.append(comment)
|
||||||
|
|
@ -65,7 +66,9 @@ class spice():
|
||||||
""" Adds a pin to the pins list. Default type is INOUT signal. """
|
""" Adds a pin to the pins list. Default type is INOUT signal. """
|
||||||
self.pins.append(name)
|
self.pins.append(name)
|
||||||
self.pin_type[name]=pin_type
|
self.pin_type[name]=pin_type
|
||||||
debug.check(pin_type in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(name,pin_type))
|
debug.check(pin_type in self.valid_signal_types,
|
||||||
|
"Invalid signaltype for {0}: {1}".format(name,
|
||||||
|
pin_type))
|
||||||
|
|
||||||
def add_pin_list(self, pin_list, pin_type="INOUT"):
|
def add_pin_list(self, pin_list, pin_type="INOUT"):
|
||||||
""" Adds a pin_list to the pins list """
|
""" Adds a pin_list to the pins list """
|
||||||
|
|
@ -73,19 +76,25 @@ class spice():
|
||||||
# or a list that is the same length as the pin list.
|
# or a list that is the same length as the pin list.
|
||||||
if type(pin_type)==str:
|
if type(pin_type)==str:
|
||||||
for pin in pin_list:
|
for pin in pin_list:
|
||||||
debug.check(pin_type in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(pin,pin_type))
|
debug.check(pin_type in self.valid_signal_types,
|
||||||
|
"Invalid signaltype for {0}: {1}".format(pin,
|
||||||
|
pin_type))
|
||||||
self.add_pin(pin, pin_type)
|
self.add_pin(pin, pin_type)
|
||||||
|
|
||||||
elif len(pin_type)==len(pin_list):
|
elif len(pin_type)==len(pin_list):
|
||||||
for (pin, ptype) in zip(pin_list, pin_type):
|
for (pin, ptype) in zip(pin_list, pin_type):
|
||||||
debug.check(ptype in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(pin,ptype))
|
debug.check(ptype in self.valid_signal_types,
|
||||||
|
"Invalid signaltype for {0}: {1}".format(pin,
|
||||||
|
ptype))
|
||||||
self.add_pin(pin, ptype)
|
self.add_pin(pin, ptype)
|
||||||
else:
|
else:
|
||||||
debug.error("Mismatch in type and pin list lengths.", -1)
|
debug.error("Mismatch in type and pin list lengths.", -1)
|
||||||
|
|
||||||
def add_pin_types(self, type_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."""
|
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
|
# This only works if self.pins == bitcell.pin_names
|
||||||
if self.pin_names != self.pins:
|
if self.pin_names != self.pins:
|
||||||
debug.error("{} spice subcircuit port names do not match pin_names\
|
debug.error("{} spice subcircuit port names do not match pin_names\
|
||||||
|
|
@ -97,7 +106,8 @@ class spice():
|
||||||
def get_pin_type(self, name):
|
def get_pin_type(self, name):
|
||||||
""" Returns the type of the signal pin. """
|
""" Returns the type of the signal pin. """
|
||||||
pin_type = self.pin_type[name]
|
pin_type = self.pin_type[name]
|
||||||
debug.check(pin_type in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(name,pin_type))
|
debug.check(pin_type in self.valid_signal_types,
|
||||||
|
"Invalid signaltype for {0}: {1}".format(name, pin_type))
|
||||||
return pin_type
|
return pin_type
|
||||||
|
|
||||||
def get_pin_dir(self, name):
|
def get_pin_dir(self, name):
|
||||||
|
|
@ -125,7 +135,6 @@ class spice():
|
||||||
output_list.append(pin)
|
output_list.append(pin)
|
||||||
return output_list
|
return output_list
|
||||||
|
|
||||||
|
|
||||||
def copy_pins(self, other_module, suffix=""):
|
def copy_pins(self, other_module, suffix=""):
|
||||||
""" This will copy all of the pins from the other module and add an optional suffix."""
|
""" This will copy all of the pins from the other module and add an optional suffix."""
|
||||||
for pin in other_module.pins:
|
for pin in other_module.pins:
|
||||||
|
|
@ -144,7 +153,6 @@ class spice():
|
||||||
"""Adds a subckt/submodule to the subckt hierarchy"""
|
"""Adds a subckt/submodule to the subckt hierarchy"""
|
||||||
self.mods.append(mod)
|
self.mods.append(mod)
|
||||||
|
|
||||||
|
|
||||||
def connect_inst(self, args, check=True):
|
def connect_inst(self, args, check=True):
|
||||||
"""Connects the pins of the last instance added
|
"""Connects the pins of the last instance added
|
||||||
It is preferred to use the function with the check to find if
|
It is preferred to use the function with the check to find if
|
||||||
|
|
@ -182,8 +190,10 @@ class spice():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def sp_read(self):
|
def sp_read(self):
|
||||||
"""Reads the sp file (and parse the pins) from the library
|
"""
|
||||||
Otherwise, initialize it to null for dynamic generation"""
|
Reads the sp file (and parse the pins) from the library
|
||||||
|
Otherwise, initialize it to null for dynamic generation
|
||||||
|
"""
|
||||||
if self.sp_file and os.path.isfile(self.sp_file):
|
if self.sp_file and os.path.isfile(self.sp_file):
|
||||||
debug.info(3, "opening {0}".format(self.sp_file))
|
debug.info(3, "opening {0}".format(self.sp_file))
|
||||||
f = open(self.sp_file)
|
f = open(self.sp_file)
|
||||||
|
|
@ -200,9 +210,28 @@ class spice():
|
||||||
else:
|
else:
|
||||||
self.spice = []
|
self.spice = []
|
||||||
|
|
||||||
|
# We don't define self.lvs and will use self.spice if dynamically created
|
||||||
|
# or they are the same file
|
||||||
|
if self.lvs_file!=self.sp_file and os.path.isfile(self.lvs_file):
|
||||||
|
debug.info(3, "opening {0}".format(self.lvs_file))
|
||||||
|
f = open(self.lvs_file)
|
||||||
|
self.lvs = f.readlines()
|
||||||
|
for i in range(len(self.lvs)):
|
||||||
|
self.lvs[i] = self.lvs[i].rstrip(" \n")
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
# pins and subckt should be the same
|
||||||
|
# find the correct subckt line in the file
|
||||||
|
subckt = re.compile("^.subckt {}".format(self.name), re.IGNORECASE)
|
||||||
|
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.")
|
||||||
|
|
||||||
def check_net_in_spice(self, net_name):
|
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."""
|
"""Checks if a net name exists in the current. Intended to be check nets in hand-made cells."""
|
||||||
#Remove spaces and lower case then add spaces. Nets are separated by spaces.
|
# Remove spaces and lower case then add spaces.
|
||||||
|
# Nets are separated by spaces.
|
||||||
net_formatted = ' ' + net_name.lstrip().rstrip().lower() + ' '
|
net_formatted = ' ' + net_name.lstrip().rstrip().lower() + ' '
|
||||||
for line in self.spice:
|
for line in self.spice:
|
||||||
# Lowercase the line and remove any part of the line that is a comment.
|
# Lowercase the line and remove any part of the line that is a comment.
|
||||||
|
|
@ -228,23 +257,24 @@ class spice():
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def sp_write_file(self, sp, usedMODS):
|
def sp_write_file(self, sp, usedMODS, lvs_netlist=False):
|
||||||
""" Recursive spice subcircuit write;
|
"""
|
||||||
Writes the spice subcircuit from the library or the dynamically generated one"""
|
Recursive spice subcircuit write;
|
||||||
|
Writes the spice subcircuit from the library or the dynamically generated one
|
||||||
|
"""
|
||||||
if not self.spice:
|
if not self.spice:
|
||||||
# recursively write the modules
|
# recursively write the modules
|
||||||
for i in self.mods:
|
for i in self.mods:
|
||||||
if self.contains(i, usedMODS):
|
if self.contains(i, usedMODS):
|
||||||
continue
|
continue
|
||||||
usedMODS.append(i)
|
usedMODS.append(i)
|
||||||
i.sp_write_file(sp, usedMODS)
|
i.sp_write_file(sp, usedMODS, lvs_netlist)
|
||||||
|
|
||||||
if len(self.insts) == 0:
|
if len(self.insts) == 0:
|
||||||
return
|
return
|
||||||
if self.pins == []:
|
if self.pins == []:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
# write out the first spice line (the subcircuit)
|
# write out the first spice line (the subcircuit)
|
||||||
sp.write("\n.SUBCKT {0} {1}\n".format(self.name,
|
sp.write("\n.SUBCKT {0} {1}\n".format(self.name,
|
||||||
" ".join(self.pins)))
|
" ".join(self.pins)))
|
||||||
|
|
@ -264,18 +294,19 @@ class spice():
|
||||||
debug.error("-----")
|
debug.error("-----")
|
||||||
debug.error("Connections: \n" + str(self.conns), 1)
|
debug.error("Connections: \n" + str(self.conns), 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for i in range(len(self.insts)):
|
for i in range(len(self.insts)):
|
||||||
# we don't need to output connections of empty instances.
|
# we don't need to output connections of empty instances.
|
||||||
# these are wires and paths
|
# these are wires and paths
|
||||||
if self.conns[i] == []:
|
if self.conns[i] == []:
|
||||||
continue
|
continue
|
||||||
if hasattr(self.insts[i].mod,"spice_device"):
|
if lvs_netlist and hasattr(self.insts[i].mod, "lvs_device"):
|
||||||
|
sp.write(self.insts[i].mod.lvs_device.format(self.insts[i].name,
|
||||||
|
" ".join(self.conns[i])))
|
||||||
|
sp.write("\n")
|
||||||
|
elif hasattr(self.insts[i].mod, "spice_device"):
|
||||||
sp.write(self.insts[i].mod.spice_device.format(self.insts[i].name,
|
sp.write(self.insts[i].mod.spice_device.format(self.insts[i].name,
|
||||||
" ".join(self.conns[i])))
|
" ".join(self.conns[i])))
|
||||||
sp.write("\n")
|
sp.write("\n")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
sp.write("X{0} {1} {2}\n".format(self.insts[i].name,
|
sp.write("X{0} {1} {2}\n".format(self.insts[i].name,
|
||||||
" ".join(self.conns[i]),
|
" ".join(self.conns[i]),
|
||||||
|
|
@ -288,6 +319,9 @@ class spice():
|
||||||
# Including the file path makes the unit test fail for other users.
|
# Including the file path makes the unit test fail for other users.
|
||||||
# if os.path.isfile(self.sp_file):
|
# if os.path.isfile(self.sp_file):
|
||||||
# sp.write("\n* {0}\n".format(self.sp_file))
|
# sp.write("\n* {0}\n".format(self.sp_file))
|
||||||
|
if lvs_netlist and hasattr(self, "lvs"):
|
||||||
|
sp.write("\n".join(self.lvs))
|
||||||
|
else:
|
||||||
sp.write("\n".join(self.spice))
|
sp.write("\n".join(self.spice))
|
||||||
|
|
||||||
sp.write("\n")
|
sp.write("\n")
|
||||||
|
|
@ -302,10 +336,21 @@ class spice():
|
||||||
del usedMODS
|
del usedMODS
|
||||||
spfile.close()
|
spfile.close()
|
||||||
|
|
||||||
|
def lvs_write(self, spname):
|
||||||
|
"""Writes the lvs to files"""
|
||||||
|
debug.info(3, "Writing to {0}".format(spname))
|
||||||
|
spfile = open(spname, 'w')
|
||||||
|
spfile.write("*FIRST LINE IS A COMMENT\n")
|
||||||
|
usedMODS = list()
|
||||||
|
self.sp_write_file(spfile, usedMODS, True)
|
||||||
|
del usedMODS
|
||||||
|
spfile.close()
|
||||||
|
|
||||||
def analytical_delay(self, corner, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
"""Inform users undefined delay module while building new modules"""
|
"""Inform users undefined delay module while building new modules"""
|
||||||
|
|
||||||
# FIXME: Slew is not used in the model right now. Can be added heuristically as linear factor
|
# FIXME: Slew is not used in the model right now.
|
||||||
|
# Can be added heuristically as linear factor
|
||||||
relative_cap = logical_effort.convert_farad_to_relative_c(load)
|
relative_cap = logical_effort.convert_farad_to_relative_c(load)
|
||||||
stage_effort = self.get_stage_effort(relative_cap)
|
stage_effort = self.get_stage_effort(relative_cap)
|
||||||
|
|
||||||
|
|
@ -403,7 +448,9 @@ class spice():
|
||||||
thermal_voltage_nom = 0.008625 * tech.spice["nom_temperature"]
|
thermal_voltage_nom = 0.008625 * tech.spice["nom_temperature"]
|
||||||
thermal_voltage = 0.008625 * temp
|
thermal_voltage = 0.008625 * temp
|
||||||
vthresh = (tech.spice["nom_threshold"] + 2 * (thermal_voltage - thermal_voltage_nom))
|
vthresh = (tech.spice["nom_threshold"] + 2 * (thermal_voltage - thermal_voltage_nom))
|
||||||
#Calculate effect on Vdd-Vth. The current vdd is not used here. A separate vdd factor is calculated.
|
# Calculate effect on Vdd-Vth.
|
||||||
|
# The current vdd is not used here.
|
||||||
|
# A separate vdd factor is calculated.
|
||||||
return (tech.spice["nom_supply_voltage"] - tech.spice["nom_threshold"]) / (tech.spice["nom_supply_voltage"] - vthresh)
|
return (tech.spice["nom_supply_voltage"] - tech.spice["nom_threshold"]) / (tech.spice["nom_supply_voltage"] - vthresh)
|
||||||
|
|
||||||
def return_delay(self, delay, slew):
|
def return_delay(self, delay, slew):
|
||||||
|
|
@ -420,7 +467,8 @@ class spice():
|
||||||
net_vswing = vdd * swing
|
net_vswing = vdd * swing
|
||||||
power_dyn = c * vdd * net_vswing * freq
|
power_dyn = c * vdd * net_vswing * freq
|
||||||
|
|
||||||
#Apply process and temperature factors. Roughly, process and Vdd affect the delay which affects the power.
|
# A pply process and temperature factors.
|
||||||
|
# Roughly, process and Vdd affect the delay which affects the power.
|
||||||
# No other estimations are currently used. Increased delay->slower freq.->less power
|
# No other estimations are currently used. Increased delay->slower freq.->less power
|
||||||
proc_div = max(self.get_process_delay_factor(proc))
|
proc_div = max(self.get_process_delay_factor(proc))
|
||||||
temp_div = self.get_temp_delay_factor(temp)
|
temp_div = self.get_temp_delay_factor(temp)
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,11 @@
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
from tech import drc
|
from tech import drc
|
||||||
import debug
|
import contact
|
||||||
from wire_path import wire_path
|
from wire_path import wire_path
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
|
||||||
|
|
||||||
class wire(wire_path):
|
class wire(wire_path):
|
||||||
"""
|
"""
|
||||||
Object metal wire; given the layer type
|
Object metal wire; given the layer type
|
||||||
|
|
@ -36,6 +37,7 @@ class wire(wire_path):
|
||||||
# wires and wire_paths should not be offset to (0,0)
|
# wires and wire_paths should not be offset to (0,0)
|
||||||
|
|
||||||
def setup_layers(self):
|
def setup_layers(self):
|
||||||
|
|
||||||
(horiz_layer, via_layer, vert_layer) = self.layer_stack
|
(horiz_layer, via_layer, vert_layer) = self.layer_stack
|
||||||
self.via_layer_name = via_layer
|
self.via_layer_name = via_layer
|
||||||
|
|
||||||
|
|
@ -47,8 +49,39 @@ class wire(wire_path):
|
||||||
via_connect = factory.create(module_type="contact",
|
via_connect = factory.create(module_type="contact",
|
||||||
layer_stack=self.layer_stack,
|
layer_stack=self.layer_stack,
|
||||||
dimensions=(1, 1))
|
dimensions=(1, 1))
|
||||||
|
|
||||||
|
# This is used for short connections to avoid via-to-via spacing errors
|
||||||
|
self.vert_layer_contact_width = max(via_connect.second_layer_width,
|
||||||
|
via_connect.first_layer_width)
|
||||||
|
self.horiz_layer_contact_width = max(via_connect.second_layer_height,
|
||||||
|
via_connect.first_layer_height)
|
||||||
|
|
||||||
self.node_to_node = [drc("minwidth_" + str(self.horiz_layer_name)) + via_connect.width,
|
self.node_to_node = [drc("minwidth_" + str(self.horiz_layer_name)) + via_connect.width,
|
||||||
drc("minwidth_" + str(self.horiz_layer_name)) + via_connect.height]
|
drc("minwidth_" + str(self.horiz_layer_name)) + via_connect.height]
|
||||||
|
self.pitch = self.compute_pitch(self.layer_stack)
|
||||||
|
|
||||||
|
def compute_pitch(self, layer_stack):
|
||||||
|
|
||||||
|
"""
|
||||||
|
This is contact direction independent pitch,
|
||||||
|
i.e. we take the maximum contact dimension
|
||||||
|
"""
|
||||||
|
(layer1, via, layer2) = layer_stack
|
||||||
|
|
||||||
|
if layer1 == "poly" or layer1 == "active":
|
||||||
|
contact1 = getattr(contact, layer1 + "_contact")
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
contact1 = getattr(contact, layer1 + "_via")
|
||||||
|
except AttributeError:
|
||||||
|
contact1 = getattr(contact, layer2 + "_via")
|
||||||
|
max_contact = max(contact1.width, contact1.height)
|
||||||
|
|
||||||
|
layer1_space = drc("{0}_to_{0}".format(layer1))
|
||||||
|
layer2_space = drc("{0}_to_{0}".format(layer2))
|
||||||
|
pitch = max_contact + max(layer1_space, layer2_space)
|
||||||
|
|
||||||
|
return pitch
|
||||||
|
|
||||||
# create a 1x1 contact
|
# create a 1x1 contact
|
||||||
def create_vias(self):
|
def create_vias(self):
|
||||||
|
|
@ -56,9 +89,6 @@ class wire(wire_path):
|
||||||
self.c=factory.create(module_type="contact",
|
self.c=factory.create(module_type="contact",
|
||||||
layer_stack=self.layer_stack,
|
layer_stack=self.layer_stack,
|
||||||
dimensions=(1, 1))
|
dimensions=(1, 1))
|
||||||
c_width = self.c.width
|
|
||||||
c_height = self.c.height
|
|
||||||
|
|
||||||
from itertools import tee, islice
|
from itertools import tee, islice
|
||||||
nwise = lambda g, n=2: zip(*(islice(g, i, None) for i, g in enumerate(tee(g, n))))
|
nwise = lambda g, n=2: zip(*(islice(g, i, None) for i, g in enumerate(tee(g, n))))
|
||||||
threewise = nwise(self.position_list, 3)
|
threewise = nwise(self.position_list, 3)
|
||||||
|
|
@ -72,7 +102,6 @@ class wire(wire_path):
|
||||||
self.obj.add_via_center(layers=self.layer_stack,
|
self.obj.add_via_center(layers=self.layer_stack,
|
||||||
offset=offset)
|
offset=offset)
|
||||||
|
|
||||||
|
|
||||||
def create_rectangles(self):
|
def create_rectangles(self):
|
||||||
"""
|
"""
|
||||||
Create the actual rectangles on the appropriate layers
|
Create the actual rectangles on the appropriate layers
|
||||||
|
|
@ -80,10 +109,18 @@ class wire(wire_path):
|
||||||
"""
|
"""
|
||||||
pl = self.position_list # position list
|
pl = self.position_list # position list
|
||||||
for index in range(len(pl) - 1):
|
for index in range(len(pl) - 1):
|
||||||
|
# Horizontal wire segment
|
||||||
if pl[index][0] != pl[index + 1][0]:
|
if pl[index][0] != pl[index + 1][0]:
|
||||||
line_length = pl[index + 1][0] - pl[index][0]
|
line_length = pl[index + 1][0] - pl[index][0]
|
||||||
|
# Make the wire wider to avoid via-to-via spacing problems
|
||||||
|
# But don't make it wider if it is shorter than one via
|
||||||
|
if abs(line_length) < self.pitch and abs(line_length) > self.horiz_layer_contact_width:
|
||||||
|
width = self.horiz_layer_contact_width
|
||||||
|
else:
|
||||||
|
width = self.horiz_layer_width
|
||||||
temp_offset = [pl[index][0],
|
temp_offset = [pl[index][0],
|
||||||
pl[index][1] - 0.5*self.horiz_layer_width]
|
pl[index][1] - 0.5 * width]
|
||||||
|
# If we go in the negative direction, move the offset
|
||||||
if line_length < 0:
|
if line_length < 0:
|
||||||
temp_offset = [temp_offset[0] + line_length,
|
temp_offset = [temp_offset[0] + line_length,
|
||||||
temp_offset[1]]
|
temp_offset[1]]
|
||||||
|
|
@ -91,10 +128,17 @@ class wire(wire_path):
|
||||||
length=abs(line_length),
|
length=abs(line_length),
|
||||||
offset=temp_offset,
|
offset=temp_offset,
|
||||||
orientation="horizontal",
|
orientation="horizontal",
|
||||||
layer_width=self.horiz_layer_width)
|
layer_width=width)
|
||||||
|
# Vertical wire segment
|
||||||
elif pl[index][1] != pl[index + 1][1]:
|
elif pl[index][1] != pl[index + 1][1]:
|
||||||
line_length = pl[index + 1][1] - pl[index][1]
|
line_length = pl[index + 1][1] - pl[index][1]
|
||||||
temp_offset = [pl[index][0] - 0.5 * self.vert_layer_width,
|
# Make the wire wider to avoid via-to-via spacing problems
|
||||||
|
# But don't make it wider if it is shorter than one via
|
||||||
|
if abs(line_length) < self.pitch and abs(line_length) > self.vert_layer_contact_width:
|
||||||
|
width = self.vert_layer_contact_width
|
||||||
|
else:
|
||||||
|
width = self.vert_layer_width
|
||||||
|
temp_offset = [pl[index][0] - 0.5 * width,
|
||||||
pl[index][1]]
|
pl[index][1]]
|
||||||
if line_length < 0:
|
if line_length < 0:
|
||||||
temp_offset = [temp_offset[0],
|
temp_offset = [temp_offset[0],
|
||||||
|
|
@ -103,11 +147,13 @@ class wire(wire_path):
|
||||||
length=abs(line_length),
|
length=abs(line_length),
|
||||||
offset=temp_offset,
|
offset=temp_offset,
|
||||||
orientation="vertical",
|
orientation="vertical",
|
||||||
layer_width=self.vert_layer_width)
|
layer_width=width)
|
||||||
|
|
||||||
def assert_node(self, A, B):
|
def assert_node(self, A, B):
|
||||||
""" Check if the node movements are not big enough for the
|
"""
|
||||||
technology sizes."""
|
Check if the node movements are not big enough for the
|
||||||
|
technology sizes.
|
||||||
|
"""
|
||||||
X_diff = abs(A[0] - B[0])
|
X_diff = abs(A[0] - B[0])
|
||||||
Y_diff = abs(A[1] - B[1])
|
Y_diff = abs(A[1] - B[1])
|
||||||
[minX, minY] = self.node_to_node
|
[minX, minY] = self.node_to_node
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#
|
#
|
||||||
import contact
|
import contact
|
||||||
import debug
|
import debug
|
||||||
from tech import drc, parameter
|
from tech import drc, parameter, layer
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from ptx import ptx
|
from ptx import ptx
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
|
@ -975,6 +975,7 @@ class pbitcell(bitcell_base.bitcell_base):
|
||||||
"""
|
"""
|
||||||
Connects wells between ptx modules and places well contacts
|
Connects wells between ptx modules and places well contacts
|
||||||
"""
|
"""
|
||||||
|
if "pwell" in layer:
|
||||||
# extend pwell to encompass entire nmos region of the cell up to the
|
# extend pwell to encompass entire nmos region of the cell up to the
|
||||||
# height of the tallest nmos transistor
|
# height of the tallest nmos transistor
|
||||||
max_nmos_well_height = max(self.inverter_nmos.well_height,
|
max_nmos_well_height = max(self.inverter_nmos.well_height,
|
||||||
|
|
@ -993,6 +994,7 @@ class pbitcell(bitcell_base.bitcell_base):
|
||||||
|
|
||||||
# extend nwell to encompass inverter_pmos
|
# extend nwell to encompass inverter_pmos
|
||||||
# calculate offset of the left pmos well
|
# calculate offset of the left pmos well
|
||||||
|
if "nwell" in layer:
|
||||||
inverter_well_xpos = -(self.inverter_nmos.active_width + 0.5 * self.inverter_to_inverter_spacing) \
|
inverter_well_xpos = -(self.inverter_nmos.active_width + 0.5 * self.inverter_to_inverter_spacing) \
|
||||||
- self.nwell_enclose_active
|
- self.nwell_enclose_active
|
||||||
inverter_well_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height \
|
inverter_well_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height \
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,8 @@ class delay(simulation):
|
||||||
""" Create measurement names. The names themselves currently define the type of measurement """
|
""" Create measurement names. The names themselves currently define the type of measurement """
|
||||||
|
|
||||||
self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"]
|
self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"]
|
||||||
self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power"]
|
self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power",
|
||||||
|
"disabled_read0_power", "disabled_read1_power", "disabled_write0_power", "disabled_write1_power"]
|
||||||
# self.voltage_when_names = ["volt_bl", "volt_br"]
|
# self.voltage_when_names = ["volt_bl", "volt_br"]
|
||||||
# self.bitline_delay_names = ["delay_bl", "delay_br"]
|
# self.bitline_delay_names = ["delay_bl", "delay_br"]
|
||||||
|
|
||||||
|
|
@ -108,6 +109,11 @@ class delay(simulation):
|
||||||
self.read_lib_meas.append(power_measure("read0_power", "FALL", measure_scale=1e3))
|
self.read_lib_meas.append(power_measure("read0_power", "FALL", measure_scale=1e3))
|
||||||
self.read_lib_meas[-1].meta_str = sram_op.READ_ZERO
|
self.read_lib_meas[-1].meta_str = sram_op.READ_ZERO
|
||||||
|
|
||||||
|
self.read_lib_meas.append(power_measure("disabled_read1_power", "RISE", measure_scale=1e3))
|
||||||
|
self.read_lib_meas[-1].meta_str = "disabled_read1"
|
||||||
|
self.read_lib_meas.append(power_measure("disabled_read0_power", "FALL", measure_scale=1e3))
|
||||||
|
self.read_lib_meas[-1].meta_str = "disabled_read0"
|
||||||
|
|
||||||
# This will later add a half-period to the spice time delay. Only for reading 0.
|
# This will later add a half-period to the spice time delay. Only for reading 0.
|
||||||
for obj in self.read_lib_meas:
|
for obj in self.read_lib_meas:
|
||||||
if obj.meta_str is sram_op.READ_ZERO:
|
if obj.meta_str is sram_op.READ_ZERO:
|
||||||
|
|
@ -156,6 +162,11 @@ class delay(simulation):
|
||||||
self.write_lib_meas.append(power_measure("write0_power", "FALL", measure_scale=1e3))
|
self.write_lib_meas.append(power_measure("write0_power", "FALL", measure_scale=1e3))
|
||||||
self.write_lib_meas[-1].meta_str = sram_op.WRITE_ZERO
|
self.write_lib_meas[-1].meta_str = sram_op.WRITE_ZERO
|
||||||
|
|
||||||
|
self.write_lib_meas.append(power_measure("disabled_write1_power", "RISE", measure_scale=1e3))
|
||||||
|
self.write_lib_meas[-1].meta_str = "disabled_write1"
|
||||||
|
self.write_lib_meas.append(power_measure("disabled_write0_power", "FALL", measure_scale=1e3))
|
||||||
|
self.write_lib_meas[-1].meta_str = "disabled_write0"
|
||||||
|
|
||||||
write_measures = []
|
write_measures = []
|
||||||
write_measures.append(self.write_lib_meas)
|
write_measures.append(self.write_lib_meas)
|
||||||
write_measures.append(self.create_write_bit_measures())
|
write_measures.append(self.create_write_bit_measures())
|
||||||
|
|
@ -1199,6 +1210,9 @@ class delay(simulation):
|
||||||
write_port)
|
write_port)
|
||||||
self.measure_cycles[write_port][sram_op.WRITE_ZERO] = len(self.cycle_times)-1
|
self.measure_cycles[write_port][sram_op.WRITE_ZERO] = len(self.cycle_times)-1
|
||||||
|
|
||||||
|
self.add_noop_clock_one_port(write_port)
|
||||||
|
self.measure_cycles[write_port]["disabled_write0"] = len(self.cycle_times)-1
|
||||||
|
|
||||||
# This also ensures we will have a H->L transition on the next read
|
# This also ensures we will have a H->L transition on the next read
|
||||||
self.add_read("R data 1 address {} to set dout caps".format(inverse_address),
|
self.add_read("R data 1 address {} to set dout caps".format(inverse_address),
|
||||||
inverse_address,
|
inverse_address,
|
||||||
|
|
@ -1209,6 +1223,10 @@ class delay(simulation):
|
||||||
read_port)
|
read_port)
|
||||||
self.measure_cycles[read_port][sram_op.READ_ZERO] = len(self.cycle_times)-1
|
self.measure_cycles[read_port][sram_op.READ_ZERO] = len(self.cycle_times)-1
|
||||||
|
|
||||||
|
self.add_noop_clock_one_port(read_port)
|
||||||
|
self.measure_cycles[read_port]["disabled_read0"] = len(self.cycle_times) - 1
|
||||||
|
|
||||||
|
|
||||||
self.add_noop_all_ports("Idle cycle (if read takes >1 cycle)")
|
self.add_noop_all_ports("Idle cycle (if read takes >1 cycle)")
|
||||||
|
|
||||||
self.add_write("W data 1 address {} to write value".format(self.probe_address),
|
self.add_write("W data 1 address {} to write value".format(self.probe_address),
|
||||||
|
|
@ -1218,12 +1236,19 @@ class delay(simulation):
|
||||||
write_port)
|
write_port)
|
||||||
self.measure_cycles[write_port][sram_op.WRITE_ONE] = len(self.cycle_times)-1
|
self.measure_cycles[write_port][sram_op.WRITE_ONE] = len(self.cycle_times)-1
|
||||||
|
|
||||||
|
self.add_noop_clock_one_port(write_port)
|
||||||
|
self.measure_cycles[write_port]["disabled_write1"] = len(self.cycle_times)-1
|
||||||
|
|
||||||
self.add_write("W data 0 address {} to clear din caps".format(inverse_address),
|
self.add_write("W data 0 address {} to clear din caps".format(inverse_address),
|
||||||
inverse_address,
|
inverse_address,
|
||||||
data_zeros,
|
data_zeros,
|
||||||
wmask_ones,
|
wmask_ones,
|
||||||
write_port)
|
write_port)
|
||||||
|
|
||||||
|
self.add_noop_clock_one_port(read_port)
|
||||||
|
self.measure_cycles[read_port]["disabled_read1"] = len(self.cycle_times) - 1
|
||||||
|
|
||||||
|
|
||||||
# This also ensures we will have a L->H transition on the next read
|
# This also ensures we will have a L->H transition on the next read
|
||||||
self.add_read("R data 0 address {} to clear dout caps".format(inverse_address),
|
self.add_read("R data 0 address {} to clear dout caps".format(inverse_address),
|
||||||
inverse_address,
|
inverse_address,
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ class lib:
|
||||||
""" Determine the load/slews if they aren't specified in the config file. """
|
""" Determine the load/slews if they aren't specified in the config file. """
|
||||||
# These are the parameters to determine the table sizes
|
# These are the parameters to determine the table sizes
|
||||||
#self.load_scales = np.array([0.1, 0.25, 0.5, 1, 2, 4, 8])
|
#self.load_scales = np.array([0.1, 0.25, 0.5, 1, 2, 4, 8])
|
||||||
self.load_scales = np.array([0.25, 1, 8])
|
self.load_scales = np.array([0.25, 1, 4])
|
||||||
#self.load_scales = np.array([0.25, 1])
|
#self.load_scales = np.array([0.25, 1])
|
||||||
self.load = tech.spice["dff_in_cap"]
|
self.load = tech.spice["dff_in_cap"]
|
||||||
self.loads = self.load_scales*self.load
|
self.loads = self.load_scales*self.load
|
||||||
|
|
@ -181,6 +181,8 @@ class lib:
|
||||||
self.lib.write(" dont_touch : true;\n")
|
self.lib.write(" dont_touch : true;\n")
|
||||||
self.lib.write(" area : {};\n\n".format(self.sram.width * self.sram.height))
|
self.lib.write(" area : {};\n\n".format(self.sram.width * self.sram.height))
|
||||||
|
|
||||||
|
self.write_pg_pin()
|
||||||
|
|
||||||
#Build string of all control signals.
|
#Build string of all control signals.
|
||||||
control_str = 'csb0' #assume at least 1 port
|
control_str = 'csb0' #assume at least 1 port
|
||||||
for i in range(1, self.total_port_num):
|
for i in range(1, self.total_port_num):
|
||||||
|
|
@ -188,10 +190,11 @@ class lib:
|
||||||
|
|
||||||
# Leakage is included in dynamic when macro is enabled
|
# Leakage is included in dynamic when macro is enabled
|
||||||
self.lib.write(" leakage_power () {\n")
|
self.lib.write(" leakage_power () {\n")
|
||||||
self.lib.write(" when : \"{0}\";\n".format(control_str))
|
# 'when' condition unnecessary when cs pin does not turn power to devices
|
||||||
|
# self.lib.write(" when : \"{0}\";\n".format(control_str))
|
||||||
self.lib.write(" value : {};\n".format(self.char_sram_results["leakage_power"]))
|
self.lib.write(" value : {};\n".format(self.char_sram_results["leakage_power"]))
|
||||||
self.lib.write(" }\n")
|
self.lib.write(" }\n")
|
||||||
self.lib.write(" cell_leakage_power : {};\n".format(0))
|
self.lib.write(" cell_leakage_power : {};\n".format(self.char_sram_results["leakage_power"]))
|
||||||
|
|
||||||
|
|
||||||
def write_units(self):
|
def write_units(self):
|
||||||
|
|
@ -240,6 +243,9 @@ class lib:
|
||||||
self.lib.write(" default_max_fanout : 4.0 ;\n")
|
self.lib.write(" default_max_fanout : 4.0 ;\n")
|
||||||
self.lib.write(" default_connection_class : universal ;\n\n")
|
self.lib.write(" default_connection_class : universal ;\n\n")
|
||||||
|
|
||||||
|
self.lib.write(" voltage_map ( VDD, {} );\n".format(tech.spice["nom_supply_voltage"]))
|
||||||
|
self.lib.write(" voltage_map ( GND, 0 );\n\n")
|
||||||
|
|
||||||
def create_list(self,values):
|
def create_list(self,values):
|
||||||
""" Helper function to create quoted, line wrapped list """
|
""" Helper function to create quoted, line wrapped list """
|
||||||
list_values = ", ".join(str(v) for v in values)
|
list_values = ", ".join(str(v) for v in values)
|
||||||
|
|
@ -516,42 +522,69 @@ class lib:
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
if port in self.read_ports:
|
if port in self.read_ports:
|
||||||
web_name = " & !web{0}".format(port)
|
web_name = " & !web{0}".format(port)
|
||||||
avg_write_power = np.mean(self.char_port_results[port]["write1_power"] + self.char_port_results[port]["write0_power"])
|
write1_power = np.mean(self.char_port_results[port]["write1_power"])
|
||||||
|
write0_power = np.mean(self.char_port_results[port]["write0_power"])
|
||||||
self.lib.write(" internal_power(){\n")
|
self.lib.write(" internal_power(){\n")
|
||||||
self.lib.write(" when : \"!csb{0} & clk{0}{1}\"; \n".format(port, web_name))
|
self.lib.write(" when : \"!csb{0}{1}\"; \n".format(port, web_name))
|
||||||
self.lib.write(" rise_power(scalar){\n")
|
self.lib.write(" rise_power(scalar){\n")
|
||||||
self.lib.write(" values(\"{0}\");\n".format(avg_write_power/2.0))
|
self.lib.write(" values(\"{0:.6e}\");\n".format(write1_power))
|
||||||
self.lib.write(" }\n")
|
self.lib.write(" }\n")
|
||||||
self.lib.write(" fall_power(scalar){\n")
|
self.lib.write(" fall_power(scalar){\n")
|
||||||
self.lib.write(" values(\"{0}\");\n".format(avg_write_power/2.0))
|
self.lib.write(" values(\"{0:.6e}\");\n".format(write0_power))
|
||||||
|
self.lib.write(" }\n")
|
||||||
|
self.lib.write(" }\n")
|
||||||
|
|
||||||
|
# Disabled power.
|
||||||
|
disabled_write1_power = np.mean(self.char_port_results[port]["disabled_write1_power"])
|
||||||
|
disabled_write0_power = np.mean(self.char_port_results[port]["disabled_write0_power"])
|
||||||
|
self.lib.write(" internal_power(){\n")
|
||||||
|
self.lib.write(" when : \"csb{0}{1}\"; \n".format(port, web_name))
|
||||||
|
self.lib.write(" rise_power(scalar){\n")
|
||||||
|
self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_write1_power))
|
||||||
|
self.lib.write(" }\n")
|
||||||
|
self.lib.write(" fall_power(scalar){\n")
|
||||||
|
self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_write0_power))
|
||||||
self.lib.write(" }\n")
|
self.lib.write(" }\n")
|
||||||
self.lib.write(" }\n")
|
self.lib.write(" }\n")
|
||||||
|
|
||||||
if port in self.read_ports:
|
if port in self.read_ports:
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
web_name = " & web{0}".format(port)
|
web_name = " & web{0}".format(port)
|
||||||
avg_read_power = np.mean(self.char_port_results[port]["read1_power"] + self.char_port_results[port]["read0_power"])
|
read1_power = np.mean(self.char_port_results[port]["read1_power"])
|
||||||
|
read0_power = np.mean(self.char_port_results[port]["read0_power"])
|
||||||
self.lib.write(" internal_power(){\n")
|
self.lib.write(" internal_power(){\n")
|
||||||
self.lib.write(" when : \"!csb{0} & !clk{0}{1}\"; \n".format(port, web_name))
|
self.lib.write(" when : \"!csb{0}{1}\"; \n".format(port, web_name))
|
||||||
self.lib.write(" rise_power(scalar){\n")
|
self.lib.write(" rise_power(scalar){\n")
|
||||||
self.lib.write(" values(\"{0}\");\n".format(avg_read_power/2.0))
|
self.lib.write(" values(\"{0:.6e}\");\n".format(read1_power))
|
||||||
self.lib.write(" }\n")
|
self.lib.write(" }\n")
|
||||||
self.lib.write(" fall_power(scalar){\n")
|
self.lib.write(" fall_power(scalar){\n")
|
||||||
self.lib.write(" values(\"{0}\");\n".format(avg_read_power/2.0))
|
self.lib.write(" values(\"{0:.6e}\");\n".format(read0_power))
|
||||||
self.lib.write(" }\n")
|
self.lib.write(" }\n")
|
||||||
self.lib.write(" }\n")
|
self.lib.write(" }\n")
|
||||||
|
|
||||||
# Have 0 internal power when disabled, this will be represented as leakage power.
|
# Disabled power.
|
||||||
|
disabled_read1_power = np.mean(self.char_port_results[port]["disabled_read1_power"])
|
||||||
|
disabled_read0_power = np.mean(self.char_port_results[port]["disabled_read0_power"])
|
||||||
self.lib.write(" internal_power(){\n")
|
self.lib.write(" internal_power(){\n")
|
||||||
self.lib.write(" when : \"csb{0}\"; \n".format(port))
|
self.lib.write(" when : \"csb{0}{1}\"; \n".format(port, web_name))
|
||||||
self.lib.write(" rise_power(scalar){\n")
|
self.lib.write(" rise_power(scalar){\n")
|
||||||
self.lib.write(" values(\"0\");\n")
|
self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_read1_power))
|
||||||
self.lib.write(" }\n")
|
self.lib.write(" }\n")
|
||||||
self.lib.write(" fall_power(scalar){\n")
|
self.lib.write(" fall_power(scalar){\n")
|
||||||
self.lib.write(" values(\"0\");\n")
|
self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_read0_power))
|
||||||
self.lib.write(" }\n")
|
self.lib.write(" }\n")
|
||||||
self.lib.write(" }\n")
|
self.lib.write(" }\n")
|
||||||
|
|
||||||
|
def write_pg_pin(self):
|
||||||
|
self.lib.write(" pg_pin(vdd) {\n")
|
||||||
|
self.lib.write(" voltage_name : VDD;\n")
|
||||||
|
self.lib.write(" pg_type : primary_power;\n")
|
||||||
|
self.lib.write(" }\n\n")
|
||||||
|
self.lib.write(" pg_pin(gnd) {\n")
|
||||||
|
self.lib.write(" voltage_name : GND;\n")
|
||||||
|
self.lib.write(" pg_type : primary_ground;\n")
|
||||||
|
self.lib.write(" }\n\n")
|
||||||
|
|
||||||
def compute_delay(self):
|
def compute_delay(self):
|
||||||
"""Compute SRAM delays for current corner"""
|
"""Compute SRAM delays for current corner"""
|
||||||
self.d = delay(self.sram, self.sp_file, self.corner)
|
self.d = delay(self.sram, self.sp_file, self.corner)
|
||||||
|
|
@ -624,17 +657,12 @@ class lib:
|
||||||
))
|
))
|
||||||
|
|
||||||
# information of checks
|
# information of checks
|
||||||
from hierarchy_design import total_drc_errors
|
(drc_errors, lvs_errors) = self.sram.DRC_LVS(final_verification=True)
|
||||||
from hierarchy_design import total_lvs_errors
|
datasheet.write("{0},{1},".format(drc_errors, lvs_errors))
|
||||||
DRC = 'skipped'
|
|
||||||
LVS = 'skipped'
|
|
||||||
if OPTS.check_lvsdrc:
|
|
||||||
DRC = str(total_drc_errors)
|
|
||||||
LVS = str(total_lvs_errors)
|
|
||||||
|
|
||||||
datasheet.write("{0},{1},".format(DRC, LVS))
|
|
||||||
# write area
|
# write area
|
||||||
datasheet.write(str(self.sram.width * self.sram.height) + ',')
|
datasheet.write(str(self.sram.width * self.sram.height) + ',')
|
||||||
|
|
||||||
# write timing information for all ports
|
# write timing information for all ports
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
#din timings
|
#din timings
|
||||||
|
|
|
||||||
|
|
@ -284,6 +284,23 @@ class simulation():
|
||||||
except:
|
except:
|
||||||
self.add_wmask("0"*self.num_wmasks, port)
|
self.add_wmask("0"*self.num_wmasks, port)
|
||||||
|
|
||||||
|
def add_noop_clock_one_port(self, port):
|
||||||
|
""" Add the control values for a noop to a single port. Increments the period. """
|
||||||
|
debug.info(2, 'Clock only on port {}'.format(port))
|
||||||
|
self.fn_cycle_comments.append('Clock only on port {}'.format(port))
|
||||||
|
self.append_cycle_comment(port, 'Clock only on port {}'.format(port))
|
||||||
|
|
||||||
|
self.cycle_times.append(self.t_current)
|
||||||
|
self.t_current += self.period
|
||||||
|
|
||||||
|
self.add_noop_one_port(port)
|
||||||
|
|
||||||
|
#Add noops to all other ports.
|
||||||
|
for unselected_port in self.all_ports:
|
||||||
|
if unselected_port != port:
|
||||||
|
self.add_noop_one_port(unselected_port)
|
||||||
|
|
||||||
|
|
||||||
def append_cycle_comment(self, port, comment):
|
def append_cycle_comment(self, port, comment):
|
||||||
"""Add comment to list to be printed in stimulus file"""
|
"""Add comment to list to be printed in stimulus file"""
|
||||||
#Clean up time before appending. Make spacing dynamic as well.
|
#Clean up time before appending. Make spacing dynamic as well.
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,10 @@ class stimuli():
|
||||||
self.sf = stim_file
|
self.sf = stim_file
|
||||||
|
|
||||||
(self.process, self.voltage, self.temperature) = corner
|
(self.process, self.voltage, self.temperature) = corner
|
||||||
|
try:
|
||||||
|
self.device_libraries = tech.spice["fet_libraries"][self.process]
|
||||||
|
except:
|
||||||
|
debug.info(2, "Not using spice library")
|
||||||
self.device_models = tech.spice["fet_models"][self.process]
|
self.device_models = tech.spice["fet_models"][self.process]
|
||||||
|
|
||||||
self.sram_name = "Xsram"
|
self.sram_name = "Xsram"
|
||||||
|
|
@ -247,8 +251,17 @@ class stimuli():
|
||||||
|
|
||||||
def write_include(self, circuit):
|
def write_include(self, circuit):
|
||||||
"""Writes include statements, inputs are lists of model files"""
|
"""Writes include statements, inputs are lists of model files"""
|
||||||
|
|
||||||
includes = self.device_models + [circuit]
|
includes = self.device_models + [circuit]
|
||||||
self.sf.write("* {} process corner\n".format(self.process))
|
self.sf.write("* {} process corner\n".format(self.process))
|
||||||
|
if OPTS.tech_name == "s8":
|
||||||
|
libraries = self.device_libraries
|
||||||
|
for item in list(libraries):
|
||||||
|
if os.path.isfile(item[0]):
|
||||||
|
self.sf.write(".lib \"{0}\" {1}\n".format(item[0], item[1]))
|
||||||
|
else:
|
||||||
|
debug.error("Could not find spice library: {0}\nSet SPICE_MODEL_DIR to over-ride path.\n".format(item[0]))
|
||||||
|
|
||||||
for item in list(includes):
|
for item in list(includes):
|
||||||
if os.path.isfile(item):
|
if os.path.isfile(item):
|
||||||
self.sf.write(".include \"{0}\"\n".format(item))
|
self.sf.write(".include \"{0}\"\n".format(item))
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import debug
|
||||||
from drc_value import *
|
from drc_value import *
|
||||||
from drc_lut import *
|
from drc_lut import *
|
||||||
|
|
||||||
|
|
||||||
class design_rules(dict):
|
class design_rules(dict):
|
||||||
"""
|
"""
|
||||||
This is a class that implements the design rules structures.
|
This is a class that implements the design rules structures.
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#
|
#
|
||||||
import debug
|
import debug
|
||||||
|
|
||||||
|
|
||||||
class drc_lut():
|
class drc_lut():
|
||||||
"""
|
"""
|
||||||
Implement a lookup table of rules.
|
Implement a lookup table of rules.
|
||||||
|
|
@ -32,7 +33,6 @@ class drc_lut():
|
||||||
if self.match(key, table_key):
|
if self.match(key, table_key):
|
||||||
return self.table[table_key]
|
return self.table[table_key]
|
||||||
|
|
||||||
|
|
||||||
def match(self, key1, key2):
|
def match(self, key1, key2):
|
||||||
"""
|
"""
|
||||||
Determine if key1>=key2 for all tuple pairs.
|
Determine if key1>=key2 for all tuple pairs.
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class drc_value():
|
class drc_value():
|
||||||
"""
|
"""
|
||||||
A single DRC value.
|
A single DRC value.
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import re
|
||||||
import copy
|
import copy
|
||||||
import importlib
|
import importlib
|
||||||
|
|
||||||
VERSION = "1.1.4"
|
VERSION = "1.1.5"
|
||||||
NAME = "OpenRAM v{}".format(VERSION)
|
NAME = "OpenRAM v{}".format(VERSION)
|
||||||
USAGE = "openram.py [options] <config file>\nUse -h for help.\n"
|
USAGE = "openram.py [options] <config file>\nUse -h for help.\n"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,9 @@ class bank_select(design.design):
|
||||||
self.height = max([x.uy() for x in self.inv_inst]) + self.m1_width
|
self.height = max([x.uy() for x in self.inv_inst]) + self.m1_width
|
||||||
self.width = max([x.rx() for x in self.inv_inst])
|
self.width = max([x.rx() for x in self.inv_inst])
|
||||||
|
|
||||||
|
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
|
|
||||||
# Number of control lines in the bus
|
# Number of control lines in the bus
|
||||||
|
|
@ -75,9 +73,8 @@ class bank_select(design.design):
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
""" Create modules for later instantiation """
|
""" Create modules for later instantiation """
|
||||||
self.bitcell = factory.create(module_type="bitcell")
|
self.dff = factory.create(module_type="dff")
|
||||||
|
height = self.dff.height + drc("poly_to_active")
|
||||||
height = self.bitcell.height + drc("poly_to_active")
|
|
||||||
|
|
||||||
# 1x Inverter
|
# 1x Inverter
|
||||||
self.inv_sel = factory.create(module_type="pinv", height=height)
|
self.inv_sel = factory.create(module_type="pinv", height=height)
|
||||||
|
|
@ -98,14 +95,12 @@ class bank_select(design.design):
|
||||||
|
|
||||||
def calculate_module_offsets(self):
|
def calculate_module_offsets(self):
|
||||||
|
|
||||||
self.xoffset_nand = self.inv4x.width + 2*self.m2_pitch + drc("pwell_to_nwell")
|
self.xoffset_nand = self.inv4x.width + 3 * self.m2_pitch + drc("pwell_to_nwell")
|
||||||
self.xoffset_nor = self.inv4x.width + 2*self.m2_pitch + drc("pwell_to_nwell")
|
self.xoffset_nor = self.inv4x.width + 3 * self.m2_pitch + drc("pwell_to_nwell")
|
||||||
self.xoffset_bank_sel_inv = 0
|
self.xoffset_bank_sel_inv = 0
|
||||||
self.xoffset_inputs = 0
|
self.xoffset_inputs = 0
|
||||||
|
|
||||||
self.yoffset_maxpoint = self.num_control_lines * self.inv4x.height
|
self.yoffset_maxpoint = self.num_control_lines * self.inv4x.height
|
||||||
|
|
||||||
|
|
||||||
def create_instances(self):
|
def create_instances(self):
|
||||||
|
|
||||||
self.bank_sel_inv=self.add_inst(name="bank_sel_inv",
|
self.bank_sel_inv=self.add_inst(name="bank_sel_inv",
|
||||||
|
|
@ -201,7 +196,6 @@ class bank_select(design.design):
|
||||||
inv_inst.place(offset=[logic_inst.rx(), y_offset],
|
inv_inst.place(offset=[logic_inst.rx(), y_offset],
|
||||||
mirror=mirror)
|
mirror=mirror)
|
||||||
|
|
||||||
|
|
||||||
def route_instances(self):
|
def route_instances(self):
|
||||||
|
|
||||||
# bank_sel is vertical wire
|
# bank_sel is vertical wire
|
||||||
|
|
@ -234,7 +228,6 @@ class bank_select(design.design):
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=bank_sel_bar_pin.rc())
|
offset=bank_sel_bar_pin.rc())
|
||||||
|
|
||||||
|
|
||||||
for i in range(self.num_control_lines):
|
for i in range(self.num_control_lines):
|
||||||
|
|
||||||
logic_inst = self.logic_inst[i]
|
logic_inst = self.logic_inst[i]
|
||||||
|
|
@ -248,12 +241,13 @@ class bank_select(design.design):
|
||||||
xoffset_bank_signal = xoffset_bank_sel
|
xoffset_bank_signal = xoffset_bank_sel
|
||||||
|
|
||||||
# Connect the logic output to inverter input
|
# Connect the logic output to inverter input
|
||||||
pre = logic_inst.get_pin("Z").lc()
|
out_pin = logic_inst.get_pin("Z")
|
||||||
out_position = logic_inst.get_pin("Z").rc() + vector(0.5*self.m1_width,0)
|
out_pos = out_pin.rc()
|
||||||
in_position = inv_inst.get_pin("A").lc() + vector(0.5*self.m1_width,0)
|
in_pin = inv_inst.get_pin("A")
|
||||||
post = inv_inst.get_pin("A").rc()
|
in_pos = in_pin.lc()
|
||||||
self.add_path("m1", [pre, out_position, in_position, post])
|
mid1_pos = vector(0.5 * (out_pos.x + in_pos.x), out_pos.y)
|
||||||
|
mid2_pos = vector(0.5 * (out_pos.x + in_pos.x), in_pos.y)
|
||||||
|
self.add_path("m1", [out_pos, mid1_pos, mid2_pos, in_pos])
|
||||||
|
|
||||||
# Connect the logic B input to bank_sel / bank_sel_bar
|
# Connect the logic B input to bank_sel / bank_sel_bar
|
||||||
logic_pos = logic_inst.get_pin("B").lc() - vector(0.5 * contact.m1_via.height, 0)
|
logic_pos = logic_inst.get_pin("B").lc() - vector(0.5 * contact.m1_via.height, 0)
|
||||||
|
|
@ -263,7 +257,6 @@ class bank_select(design.design):
|
||||||
offset=logic_pos,
|
offset=logic_pos,
|
||||||
directions=("H", "H"))
|
directions=("H", "H"))
|
||||||
|
|
||||||
|
|
||||||
# Connect the logic A input to the input pin
|
# Connect the logic A input to the input pin
|
||||||
logic_pos = logic_inst.get_pin("A").lc()
|
logic_pos = logic_inst.get_pin("A").lc()
|
||||||
input_pos = vector(0, logic_pos.y)
|
input_pos = vector(0, logic_pos.y)
|
||||||
|
|
@ -286,7 +279,6 @@ class bank_select(design.design):
|
||||||
width=inv_inst.rx() - out_pin.lx(),
|
width=inv_inst.rx() - out_pin.lx(),
|
||||||
height=out_pin.height())
|
height=out_pin.height())
|
||||||
|
|
||||||
|
|
||||||
# Find the x offsets for where the vias/pins should be placed
|
# Find the x offsets for where the vias/pins should be placed
|
||||||
a_xoffset = self.logic_inst[0].lx()
|
a_xoffset = self.logic_inst[0].lx()
|
||||||
b_xoffset = self.inv_inst[0].lx()
|
b_xoffset = self.inv_inst[0].lx()
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ class bitcell_array(bitcell_base_array):
|
||||||
# the replica bitcell in the control logic
|
# the replica bitcell in the control logic
|
||||||
# self.offset_all_coordinates()
|
# self.offset_all_coordinates()
|
||||||
|
|
||||||
|
|
||||||
def create_netlist(self):
|
def create_netlist(self):
|
||||||
""" Create and connect the netlist """
|
""" Create and connect the netlist """
|
||||||
self.add_modules()
|
self.add_modules()
|
||||||
|
|
@ -62,7 +61,6 @@ class bitcell_array(bitcell_base_array):
|
||||||
|
|
||||||
def analytical_power(self, corner, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Power of Bitcell array and bitline in nW."""
|
"""Power of Bitcell array and bitline in nW."""
|
||||||
from tech import drc, parameter
|
|
||||||
|
|
||||||
# Dynamic Power from Bitline
|
# Dynamic Power from Bitline
|
||||||
bl_wire = self.gen_bl_wire()
|
bl_wire = self.gen_bl_wire()
|
||||||
|
|
|
||||||
|
|
@ -5,18 +5,16 @@
|
||||||
# (acting for and on behalf of Oklahoma State University)
|
# (acting for and on behalf of Oklahoma State University)
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
from math import log
|
|
||||||
import design
|
import design
|
||||||
from tech import drc, parameter
|
|
||||||
from tech import cell_properties as props
|
from tech import cell_properties as props
|
||||||
import debug
|
import debug
|
||||||
import contact
|
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
import math
|
import math
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
import logical_effort
|
import logical_effort
|
||||||
|
|
||||||
|
|
||||||
class control_logic(design.design):
|
class control_logic(design.design):
|
||||||
"""
|
"""
|
||||||
Dynamically generated Control logic for the total SRAM circuit.
|
Dynamically generated Control logic for the total SRAM circuit.
|
||||||
|
|
@ -44,6 +42,7 @@ class control_logic(design.design):
|
||||||
self.inv_parasitic_delay = logical_effort.logical_effort.pinv
|
self.inv_parasitic_delay = logical_effort.logical_effort.pinv
|
||||||
|
|
||||||
# Determines how much larger the sen delay should be. Accounts for possible error in model.
|
# Determines how much larger the sen delay should be. Accounts for possible error in model.
|
||||||
|
# FIXME: This should be made a parameter
|
||||||
self.wl_timing_tolerance = 1
|
self.wl_timing_tolerance = 1
|
||||||
self.wl_stage_efforts = None
|
self.wl_stage_efforts = None
|
||||||
self.sen_stage_efforts = None
|
self.sen_stage_efforts = None
|
||||||
|
|
@ -71,7 +70,6 @@ class control_logic(design.design):
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
""" Add the pins to the control logic module. """
|
""" Add the pins to the control logic module. """
|
||||||
self.add_pin_list(self.input_list + ["clk"] + self.rbl_list, "INPUT")
|
self.add_pin_list(self.input_list + ["clk"] + self.rbl_list, "INPUT")
|
||||||
|
|
@ -92,7 +90,7 @@ class control_logic(design.design):
|
||||||
self.add_mod(self.ctrl_dff_array)
|
self.add_mod(self.ctrl_dff_array)
|
||||||
|
|
||||||
self.and2 = factory.create(module_type="pand2",
|
self.and2 = factory.create(module_type="pand2",
|
||||||
size=4,
|
size=12,
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
self.add_mod(self.and2)
|
self.add_mod(self.and2)
|
||||||
|
|
||||||
|
|
@ -101,7 +99,6 @@ class control_logic(design.design):
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
self.add_mod(self.rbl_driver)
|
self.add_mod(self.rbl_driver)
|
||||||
|
|
||||||
|
|
||||||
# clk_buf drives a flop for every address
|
# clk_buf drives a flop for every address
|
||||||
addr_flops = math.log(self.num_words, 2) + math.log(self.words_per_row, 2)
|
addr_flops = math.log(self.num_words, 2) + math.log(self.words_per_row, 2)
|
||||||
# plus data flops and control flops
|
# plus data flops and control flops
|
||||||
|
|
@ -151,7 +148,6 @@ class control_logic(design.design):
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
self.add_mod(self.p_en_bar_driver)
|
self.add_mod(self.p_en_bar_driver)
|
||||||
|
|
||||||
|
|
||||||
self.nand2 = factory.create(module_type="pnand2",
|
self.nand2 = factory.create(module_type="pnand2",
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
self.add_mod(self.nand2)
|
self.add_mod(self.nand2)
|
||||||
|
|
@ -195,7 +191,8 @@ class control_logic(design.design):
|
||||||
# self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen() #get the new timing
|
# self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen() #get the new timing
|
||||||
# self.delay_chain_resized = True
|
# self.delay_chain_resized = True
|
||||||
|
|
||||||
debug.check(OPTS.delay_chain_stages%2, "Must use odd number of delay chain stages for inverting delay chain.")
|
debug.check(OPTS.delay_chain_stages % 2,
|
||||||
|
"Must use odd number of delay chain stages for inverting delay chain.")
|
||||||
self.delay_chain=factory.create(module_type="delay_chain",
|
self.delay_chain=factory.create(module_type="delay_chain",
|
||||||
fanout_list = OPTS.delay_chain_stages * [ OPTS.delay_chain_fanout_per_stage ])
|
fanout_list = OPTS.delay_chain_stages * [ OPTS.delay_chain_fanout_per_stage ])
|
||||||
self.add_mod(self.delay_chain)
|
self.add_mod(self.delay_chain)
|
||||||
|
|
@ -251,13 +248,16 @@ class control_logic(design.design):
|
||||||
previous_delay_chain_delay = (previous_fanout + 1 + self.inv_parasitic_delay) * previous_stages
|
previous_delay_chain_delay = (previous_fanout + 1 + self.inv_parasitic_delay) * previous_stages
|
||||||
debug.info(2, "Previous delay chain produced {} delay units".format(previous_delay_chain_delay))
|
debug.info(2, "Previous delay chain produced {} delay units".format(previous_delay_chain_delay))
|
||||||
|
|
||||||
delay_fanout = 3 # This can be anything >=2
|
# This can be anything >=2
|
||||||
|
delay_fanout = 3
|
||||||
# The delay chain uses minimum sized inverters. There are (fanout+1)*stages inverters and each
|
# The delay chain uses minimum sized inverters. There are (fanout+1)*stages inverters and each
|
||||||
# inverter adds 1 unit of delay (due to minimum size). This also depends on the pinv value
|
# inverter adds 1 unit of delay (due to minimum size). This also depends on the pinv value
|
||||||
required_delay = self.wl_delay * self.wl_timing_tolerance - (self.sen_delay - previous_delay_chain_delay)
|
required_delay = self.wl_delay * self.wl_timing_tolerance - (self.sen_delay - previous_delay_chain_delay)
|
||||||
debug.check(required_delay > 0, "Cannot size delay chain to have negative delay")
|
debug.check(required_delay > 0, "Cannot size delay chain to have negative delay")
|
||||||
delay_stages = ceil(required_delay/(delay_fanout+1+self.inv_parasitic_delay))
|
delay_per_stage = delay_fanout + 1 + self.inv_parasitic_delay
|
||||||
if delay_stages%2 == 1: #force an even number of stages.
|
delay_stages = ceil(required_delay / delay_per_stage)
|
||||||
|
# force an even number of stages.
|
||||||
|
if delay_stages % 2 == 1:
|
||||||
delay_stages += 1
|
delay_stages += 1
|
||||||
# Fanout can be varied as well but is a little more complicated but potentially optimal.
|
# Fanout can be varied as well but is a little more complicated but potentially optimal.
|
||||||
debug.info(1, "Setting delay chain to {} stages with {} fanout to match {} delay".format(delay_stages, delay_fanout, required_delay))
|
debug.info(1, "Setting delay chain to {} stages with {} fanout to match {} delay".format(delay_stages, delay_fanout, required_delay))
|
||||||
|
|
@ -266,24 +266,33 @@ class control_logic(design.design):
|
||||||
def get_dynamic_delay_fanout_list(self, previous_stages, previous_fanout):
|
def get_dynamic_delay_fanout_list(self, previous_stages, previous_fanout):
|
||||||
"""Determine the size of the delay chain used for the Sense Amp Enable using path delays"""
|
"""Determine the size of the delay chain used for the Sense Amp Enable using path delays"""
|
||||||
|
|
||||||
previous_delay_chain_delay = (previous_fanout+1+self.inv_parasitic_delay)*previous_stages
|
previous_delay_per_stage = previous_fanout + 1 + self.inv_parasitic_delay
|
||||||
|
previous_delay_chain_delay = previous_delay_per_stage * previous_stages
|
||||||
debug.info(2, "Previous delay chain produced {} delay units".format(previous_delay_chain_delay))
|
debug.info(2, "Previous delay chain produced {} delay units".format(previous_delay_chain_delay))
|
||||||
|
|
||||||
fanout_rise = fanout_fall = 2 # This can be anything >=2
|
fanout_rise = fanout_fall = 2 # This can be anything >=2
|
||||||
# The delay chain uses minimum sized inverters. There are (fanout+1)*stages inverters and each
|
# The delay chain uses minimum sized inverters. There are (fanout+1)*stages inverters and each
|
||||||
# inverter adds 1 unit of delay (due to minimum size). This also depends on the pinv value
|
# inverter adds 1 unit of delay (due to minimum size). This also depends on the pinv value
|
||||||
required_delay_fall = self.wl_delay_fall*self.wl_timing_tolerance - (self.sen_delay_fall-previous_delay_chain_delay/2)
|
required_delay_fall = self.wl_delay_fall * self.wl_timing_tolerance - \
|
||||||
required_delay_rise = self.wl_delay_rise*self.wl_timing_tolerance - (self.sen_delay_rise-previous_delay_chain_delay/2)
|
(self.sen_delay_fall - previous_delay_chain_delay / 2)
|
||||||
debug.info(2,"Required delays from chain: fall={}, rise={}".format(required_delay_fall,required_delay_rise))
|
required_delay_rise = self.wl_delay_rise * self.wl_timing_tolerance - \
|
||||||
|
(self.sen_delay_rise - previous_delay_chain_delay / 2)
|
||||||
|
debug.info(2,
|
||||||
|
"Required delays from chain: fall={}, rise={}".format(required_delay_fall,
|
||||||
|
required_delay_rise))
|
||||||
|
|
||||||
# If the fanout is different between rise/fall by this amount. Stage algorithm is made more pessimistic.
|
# If the fanout is different between rise/fall by this amount. Stage algorithm is made more pessimistic.
|
||||||
WARNING_FANOUT_DIFF = 5
|
WARNING_FANOUT_DIFF = 5
|
||||||
stages_close = False
|
stages_close = False
|
||||||
# The stages need to be equal (or at least a even number of stages with matching rise/fall delays)
|
# The stages need to be equal (or at least a even number of stages with matching rise/fall delays)
|
||||||
while True:
|
while True:
|
||||||
stages_fall = self.calculate_stages_with_fixed_fanout(required_delay_fall,fanout_fall)
|
stages_fall = self.calculate_stages_with_fixed_fanout(required_delay_fall,
|
||||||
stages_rise = self.calculate_stages_with_fixed_fanout(required_delay_rise,fanout_rise)
|
fanout_fall)
|
||||||
debug.info(1,"Fall stages={}, rise stages={}".format(stages_fall,stages_rise))
|
stages_rise = self.calculate_stages_with_fixed_fanout(required_delay_rise,
|
||||||
|
fanout_rise)
|
||||||
|
debug.info(1,
|
||||||
|
"Fall stages={}, rise stages={}".format(stages_fall,
|
||||||
|
stages_rise))
|
||||||
if abs(stages_fall - stages_rise) == 1 and not stages_close:
|
if abs(stages_fall - stages_rise) == 1 and not stages_close:
|
||||||
stages_close = True
|
stages_close = True
|
||||||
safe_fanout_rise = fanout_rise
|
safe_fanout_rise = fanout_rise
|
||||||
|
|
@ -313,13 +322,17 @@ class control_logic(design.design):
|
||||||
def calculate_stages_with_fixed_fanout(self, required_delay, fanout):
|
def calculate_stages_with_fixed_fanout(self, required_delay, fanout):
|
||||||
from math import ceil
|
from math import ceil
|
||||||
# Delay being negative is not an error. It implies that any amount of stages would have a negative effect on the overall delay
|
# Delay being negative is not an error. It implies that any amount of stages would have a negative effect on the overall delay
|
||||||
if required_delay <= 3+self.inv_parasitic_delay: #3 is the minimum delay per stage (with pinv=0).
|
# 3 is the minimum delay per stage (with pinv=0).
|
||||||
|
if required_delay <= 3 + self.inv_parasitic_delay:
|
||||||
return 1
|
return 1
|
||||||
delay_stages = ceil(required_delay/(fanout+1+self.inv_parasitic_delay))
|
delay_per_stage = fanout + 1 + self.inv_parasitic_delay
|
||||||
|
delay_stages = ceil(required_delay / delay_per_stage)
|
||||||
return delay_stages
|
return delay_stages
|
||||||
|
|
||||||
def calculate_stage_list(self, total_stages, fanout_rise, fanout_fall):
|
def calculate_stage_list(self, total_stages, fanout_rise, fanout_fall):
|
||||||
"""Produces a list of fanouts which determine the size of the delay chain. List length is the number of stages.
|
"""
|
||||||
|
Produces a list of fanouts which determine the size of the delay chain.
|
||||||
|
List length is the number of stages.
|
||||||
Assumes the first stage is falling.
|
Assumes the first stage is falling.
|
||||||
"""
|
"""
|
||||||
stage_list = []
|
stage_list = []
|
||||||
|
|
@ -366,7 +379,6 @@ class control_logic(design.design):
|
||||||
|
|
||||||
self.supply_list = ["vdd", "gnd"]
|
self.supply_list = ["vdd", "gnd"]
|
||||||
|
|
||||||
|
|
||||||
def route_rails(self):
|
def route_rails(self):
|
||||||
""" Add the input signal inverted tracks """
|
""" Add the input signal inverted tracks """
|
||||||
height = self.control_logic_center.y - self.m2_pitch
|
height = self.control_logic_center.y - self.m2_pitch
|
||||||
|
|
@ -374,7 +386,6 @@ class control_logic(design.design):
|
||||||
|
|
||||||
self.rail_offsets = self.create_vertical_bus("m2", self.m2_pitch, offset, self.internal_bus_list, height)
|
self.rail_offsets = self.create_vertical_bus("m2", self.m2_pitch, offset, self.internal_bus_list, height)
|
||||||
|
|
||||||
|
|
||||||
def create_instances(self):
|
def create_instances(self):
|
||||||
""" Create all the instances """
|
""" Create all the instances """
|
||||||
self.create_dffs()
|
self.create_dffs()
|
||||||
|
|
@ -390,8 +401,6 @@ class control_logic(design.design):
|
||||||
self.create_delay()
|
self.create_delay()
|
||||||
self.create_pen_row()
|
self.create_pen_row()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def place_instances(self):
|
def place_instances(self):
|
||||||
""" Place all the instances """
|
""" Place all the instances """
|
||||||
# Keep track of all right-most instances to determine row boundary
|
# Keep track of all right-most instances to determine row boundary
|
||||||
|
|
@ -459,7 +468,6 @@ class control_logic(design.design):
|
||||||
self.route_gated_clk_buf()
|
self.route_gated_clk_buf()
|
||||||
self.route_supply()
|
self.route_supply()
|
||||||
|
|
||||||
|
|
||||||
def create_delay(self):
|
def create_delay(self):
|
||||||
""" Create the replica bitline """
|
""" Create the replica bitline """
|
||||||
self.delay_inst=self.add_inst(name="delay_chain",
|
self.delay_inst=self.add_inst(name="delay_chain",
|
||||||
|
|
@ -488,11 +496,9 @@ class control_logic(design.design):
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=in_pos)
|
offset=in_pos)
|
||||||
|
|
||||||
|
|
||||||
# Input from RBL goes to the delay line for futher delay
|
# Input from RBL goes to the delay line for futher delay
|
||||||
self.copy_layout_pin(self.delay_inst, "in", "rbl_bl")
|
self.copy_layout_pin(self.delay_inst, "in", "rbl_bl")
|
||||||
|
|
||||||
|
|
||||||
def create_clk_buf_row(self):
|
def create_clk_buf_row(self):
|
||||||
""" Create the multistage and gated clock buffer """
|
""" Create the multistage and gated clock buffer """
|
||||||
self.clk_buf_inst = self.add_inst(name="clkbuf",
|
self.clk_buf_inst = self.add_inst(name="clkbuf",
|
||||||
|
|
@ -516,13 +522,12 @@ class control_logic(design.design):
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=clk_pos)
|
offset=clk_pos)
|
||||||
|
|
||||||
|
|
||||||
# Connect this at the bottom of the buffer
|
# Connect this at the bottom of the buffer
|
||||||
out_pos = self.clk_buf_inst.get_pin("Z").center()
|
out_pos = self.clk_buf_inst.get_pin("Z").center()
|
||||||
mid1 = vector(out_pos.x, 2 * self.m2_pitch)
|
mid1 = vector(out_pos.x, 2 * self.m2_pitch)
|
||||||
mid2 = vector(self.rail_offsets["clk_buf"].x, mid1.y)
|
mid2 = vector(self.rail_offsets["clk_buf"].x, mid1.y)
|
||||||
bus_pos = self.rail_offsets["clk_buf"]
|
bus_pos = self.rail_offsets["clk_buf"]
|
||||||
self.add_wire(("m3","via2","m2"),[out_pos, mid1, mid2, bus_pos])
|
self.add_wire(self.m2_stack[::-1], [out_pos, mid1, mid2, bus_pos])
|
||||||
# The pin is on M1, so we need another via as well
|
# The pin is on M1, so we need another via as well
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=self.clk_buf_inst.get_pin("Z").center())
|
offset=self.clk_buf_inst.get_pin("Z").center())
|
||||||
|
|
@ -557,15 +562,20 @@ class control_logic(design.design):
|
||||||
|
|
||||||
# This is the second gate over, so it needs to be on M3
|
# This is the second gate over, so it needs to be on M3
|
||||||
clkbuf_map = zip(["A"], ["cs"])
|
clkbuf_map = zip(["A"], ["cs"])
|
||||||
self.connect_vertical_bus(clkbuf_map, self.gated_clk_bar_inst, self.rail_offsets, ("m3", "via2", "m2"))
|
self.connect_vertical_bus(clkbuf_map,
|
||||||
|
self.gated_clk_bar_inst,
|
||||||
|
self.rail_offsets,
|
||||||
|
self.m2_stack[::-1])
|
||||||
# The pin is on M1, so we need another via as well
|
# The pin is on M1, so we need another via as well
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=self.gated_clk_bar_inst.get_pin("A").center())
|
offset=self.gated_clk_bar_inst.get_pin("A").center())
|
||||||
|
|
||||||
|
|
||||||
# This is the second gate over, so it needs to be on M3
|
# This is the second gate over, so it needs to be on M3
|
||||||
clkbuf_map = zip(["Z"], ["gated_clk_bar"])
|
clkbuf_map = zip(["Z"], ["gated_clk_bar"])
|
||||||
self.connect_vertical_bus(clkbuf_map, self.gated_clk_bar_inst, self.rail_offsets, ("m3", "via2", "m2"))
|
self.connect_vertical_bus(clkbuf_map,
|
||||||
|
self.gated_clk_bar_inst,
|
||||||
|
self.rail_offsets,
|
||||||
|
self.m2_stack[::-1])
|
||||||
# The pin is on M1, so we need another via as well
|
# The pin is on M1, so we need another via as well
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=self.gated_clk_bar_inst.get_pin("Z").center())
|
offset=self.gated_clk_bar_inst.get_pin("Z").center())
|
||||||
|
|
@ -586,9 +596,11 @@ class control_logic(design.design):
|
||||||
clkbuf_map = zip(["A", "B"], ["clk_buf", "cs"])
|
clkbuf_map = zip(["A", "B"], ["clk_buf", "cs"])
|
||||||
self.connect_vertical_bus(clkbuf_map, self.gated_clk_buf_inst, self.rail_offsets)
|
self.connect_vertical_bus(clkbuf_map, self.gated_clk_buf_inst, self.rail_offsets)
|
||||||
|
|
||||||
|
|
||||||
clkbuf_map = zip(["Z"], ["gated_clk_buf"])
|
clkbuf_map = zip(["Z"], ["gated_clk_buf"])
|
||||||
self.connect_vertical_bus(clkbuf_map, self.gated_clk_buf_inst, self.rail_offsets, ("m3", "via2", "m2"))
|
self.connect_vertical_bus(clkbuf_map,
|
||||||
|
self.gated_clk_buf_inst,
|
||||||
|
self.rail_offsets,
|
||||||
|
self.m2_stack[::-1])
|
||||||
# The pin is on M1, so we need another via as well
|
# The pin is on M1, so we need another via as well
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=self.gated_clk_buf_inst.get_pin("Z").center())
|
offset=self.gated_clk_buf_inst.get_pin("Z").center())
|
||||||
|
|
@ -656,7 +668,6 @@ class control_logic(design.design):
|
||||||
# hence we use rbl_bl_delay as well.
|
# hence we use rbl_bl_delay as well.
|
||||||
self.connect_inst(["rbl_bl_delay", "gated_clk_bar", input_name, "s_en", "vdd", "gnd"])
|
self.connect_inst(["rbl_bl_delay", "gated_clk_bar", input_name, "s_en", "vdd", "gnd"])
|
||||||
|
|
||||||
|
|
||||||
def place_sen_row(self, row):
|
def place_sen_row(self, row):
|
||||||
x_offset = self.control_x_offset
|
x_offset = self.control_x_offset
|
||||||
|
|
||||||
|
|
@ -664,7 +675,6 @@ class control_logic(design.design):
|
||||||
|
|
||||||
self.row_end_inst.append(self.s_en_gate_inst)
|
self.row_end_inst.append(self.s_en_gate_inst)
|
||||||
|
|
||||||
|
|
||||||
def route_sen(self):
|
def route_sen(self):
|
||||||
|
|
||||||
if self.port_type=="rw":
|
if self.port_type=="rw":
|
||||||
|
|
@ -700,11 +710,9 @@ class control_logic(design.design):
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=self.rbl_bl_delay_inv_inst.get_pin("Z").center())
|
offset=self.rbl_bl_delay_inv_inst.get_pin("Z").center())
|
||||||
|
|
||||||
|
|
||||||
rbl_map = zip(["A"], ["rbl_bl_delay"])
|
rbl_map = zip(["A"], ["rbl_bl_delay"])
|
||||||
self.connect_vertical_bus(rbl_map, self.rbl_bl_delay_inv_inst, self.rail_offsets)
|
self.connect_vertical_bus(rbl_map, self.rbl_bl_delay_inv_inst, self.rail_offsets)
|
||||||
|
|
||||||
|
|
||||||
def create_wen_row(self):
|
def create_wen_row(self):
|
||||||
|
|
||||||
# input: we (or cs) output: w_en
|
# input: we (or cs) output: w_en
|
||||||
|
|
@ -720,7 +728,6 @@ class control_logic(design.design):
|
||||||
# Only drive the writes in the second half of the clock cycle during a write operation.
|
# Only drive the writes in the second half of the clock cycle during a write operation.
|
||||||
self.connect_inst([input_name, "rbl_bl_delay_bar", "gated_clk_bar", "w_en", "vdd", "gnd"])
|
self.connect_inst([input_name, "rbl_bl_delay_bar", "gated_clk_bar", "w_en", "vdd", "gnd"])
|
||||||
|
|
||||||
|
|
||||||
def place_wen_row(self, row):
|
def place_wen_row(self, row):
|
||||||
x_offset = self.control_x_offset
|
x_offset = self.control_x_offset
|
||||||
|
|
||||||
|
|
@ -784,7 +791,6 @@ class control_logic(design.design):
|
||||||
|
|
||||||
return (y_off, mirror)
|
return (y_off, mirror)
|
||||||
|
|
||||||
|
|
||||||
def connect_output(self, inst, pin_name, out_name):
|
def connect_output(self, inst, pin_name, out_name):
|
||||||
""" Create an output pin on the right side from the pin of a given instance. """
|
""" Create an output pin on the right side from the pin of a given instance. """
|
||||||
|
|
||||||
|
|
@ -795,8 +801,6 @@ class control_logic(design.design):
|
||||||
start=out_pin.center(),
|
start=out_pin.center(),
|
||||||
end=right_pos)
|
end=right_pos)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def route_supply(self):
|
def route_supply(self):
|
||||||
""" Add vdd and gnd to the instance cells """
|
""" Add vdd and gnd to the instance cells """
|
||||||
|
|
||||||
|
|
@ -824,8 +828,6 @@ class control_logic(design.design):
|
||||||
self.copy_layout_pin(self.ctrl_dff_inst, "gnd")
|
self.copy_layout_pin(self.ctrl_dff_inst, "gnd")
|
||||||
self.copy_layout_pin(self.ctrl_dff_inst, "vdd")
|
self.copy_layout_pin(self.ctrl_dff_inst, "vdd")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_lvs_correspondence_points(self):
|
def add_lvs_correspondence_points(self):
|
||||||
""" This adds some points for easier debugging if LVS goes wrong.
|
""" This adds some points for easier debugging if LVS goes wrong.
|
||||||
These should probably be turned off by default though, since extraction
|
These should probably be turned off by default though, since extraction
|
||||||
|
|
@ -852,17 +854,18 @@ class control_logic(design.design):
|
||||||
height=pin.height(),
|
height=pin.height(),
|
||||||
width=pin.width())
|
width=pin.width())
|
||||||
|
|
||||||
|
|
||||||
def get_delays_to_wl(self):
|
def get_delays_to_wl(self):
|
||||||
"""Get the delay (in delay units) of the clk to a wordline in the bitcell array"""
|
"""Get the delay (in delay units) of the clk to a wordline in the bitcell array"""
|
||||||
debug.check(self.sram.all_mods_except_control_done, "Cannot calculate sense amp enable delay unless all module have been added.")
|
debug.check(self.sram.all_mods_except_control_done, "Cannot calculate sense amp enable delay unless all module have been added.")
|
||||||
self.wl_stage_efforts = self.get_wordline_stage_efforts()
|
self.wl_stage_efforts = self.get_wordline_stage_efforts()
|
||||||
clk_to_wl_rise, clk_to_wl_fall = logical_effort.calculate_relative_rise_fall_delays(self.wl_stage_efforts)
|
clk_to_wl_rise, clk_to_wl_fall = logical_effort.calculate_relative_rise_fall_delays(self.wl_stage_efforts)
|
||||||
total_delay = clk_to_wl_rise + clk_to_wl_fall
|
total_delay = clk_to_wl_rise + clk_to_wl_fall
|
||||||
debug.info(1, "Clock to wl delay is rise={:.3f}, fall={:.3f}, total={:.3f} in delay units".format(clk_to_wl_rise, clk_to_wl_fall,total_delay))
|
debug.info(1,
|
||||||
|
"Clock to wl delay is rise={:.3f}, fall={:.3f}, total={:.3f} in delay units".format(clk_to_wl_rise,
|
||||||
|
clk_to_wl_fall,
|
||||||
|
total_delay))
|
||||||
return clk_to_wl_rise, clk_to_wl_fall
|
return clk_to_wl_rise, clk_to_wl_fall
|
||||||
|
|
||||||
|
|
||||||
def get_wordline_stage_efforts(self):
|
def get_wordline_stage_efforts(self):
|
||||||
"""Follows the gated_clk_bar -> wl_en -> wordline signal for the total path efforts"""
|
"""Follows the gated_clk_bar -> wl_en -> wordline signal for the total path efforts"""
|
||||||
stage_effort_list = []
|
stage_effort_list = []
|
||||||
|
|
@ -882,14 +885,18 @@ class control_logic(design.design):
|
||||||
return stage_effort_list
|
return stage_effort_list
|
||||||
|
|
||||||
def get_delays_to_sen(self):
|
def get_delays_to_sen(self):
|
||||||
"""Get the delay (in delay units) of the clk to a sense amp enable.
|
"""
|
||||||
|
Get the delay (in delay units) of the clk to a sense amp enable.
|
||||||
This does not incorporate the delay of the replica bitline.
|
This does not incorporate the delay of the replica bitline.
|
||||||
"""
|
"""
|
||||||
debug.check(self.sram.all_mods_except_control_done, "Cannot calculate sense amp enable delay unless all module have been added.")
|
debug.check(self.sram.all_mods_except_control_done, "Cannot calculate sense amp enable delay unless all module have been added.")
|
||||||
self.sen_stage_efforts = self.get_sa_enable_stage_efforts()
|
self.sen_stage_efforts = self.get_sa_enable_stage_efforts()
|
||||||
clk_to_sen_rise, clk_to_sen_fall = logical_effort.calculate_relative_rise_fall_delays(self.sen_stage_efforts)
|
clk_to_sen_rise, clk_to_sen_fall = logical_effort.calculate_relative_rise_fall_delays(self.sen_stage_efforts)
|
||||||
total_delay = clk_to_sen_rise + clk_to_sen_fall
|
total_delay = clk_to_sen_rise + clk_to_sen_fall
|
||||||
debug.info(1, "Clock to s_en delay is rise={:.3f}, fall={:.3f}, total={:.3f} in delay units".format(clk_to_sen_rise, clk_to_sen_fall,total_delay))
|
debug.info(1,
|
||||||
|
"Clock to s_en delay is rise={:.3f}, fall={:.3f}, total={:.3f} in delay units".format(clk_to_sen_rise,
|
||||||
|
clk_to_sen_fall,
|
||||||
|
total_delay))
|
||||||
return clk_to_sen_rise, clk_to_sen_fall
|
return clk_to_sen_rise, clk_to_sen_fall
|
||||||
|
|
||||||
def get_sa_enable_stage_efforts(self):
|
def get_sa_enable_stage_efforts(self):
|
||||||
|
|
@ -931,7 +938,7 @@ class control_logic(design.design):
|
||||||
|
|
||||||
stage_effort_list = []
|
stage_effort_list = []
|
||||||
# Calculate the load on clk_buf_bar
|
# Calculate the load on clk_buf_bar
|
||||||
ext_clk_buf_cout = self.sram.get_clk_bar_cin()
|
# ext_clk_buf_cout = self.sram.get_clk_bar_cin()
|
||||||
|
|
||||||
# Operations logic starts on negative edge
|
# Operations logic starts on negative edge
|
||||||
last_stage_rise = False
|
last_stage_rise = False
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,11 @@
|
||||||
#
|
#
|
||||||
import debug
|
import debug
|
||||||
import design
|
import design
|
||||||
from tech import drc
|
|
||||||
from contact import contact
|
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
|
||||||
|
|
||||||
class delay_chain(design.design):
|
class delay_chain(design.design):
|
||||||
"""
|
"""
|
||||||
Generate a delay chain with the given number of stages and fanout.
|
Generate a delay chain with the given number of stages and fanout.
|
||||||
|
|
@ -37,7 +36,6 @@ class delay_chain(design.design):
|
||||||
if not OPTS.netlist_only:
|
if not OPTS.netlist_only:
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
|
|
||||||
|
|
||||||
def create_netlist(self):
|
def create_netlist(self):
|
||||||
self.add_modules()
|
self.add_modules()
|
||||||
self.add_pins()
|
self.add_pins()
|
||||||
|
|
@ -51,6 +49,7 @@ class delay_chain(design.design):
|
||||||
|
|
||||||
self.place_inverters()
|
self.place_inverters()
|
||||||
self.route_inverters()
|
self.route_inverters()
|
||||||
|
self.route_supplies()
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
@ -69,7 +68,6 @@ class delay_chain(design.design):
|
||||||
def create_inverters(self):
|
def create_inverters(self):
|
||||||
""" Create the inverters and connect them based on the stage list """
|
""" Create the inverters and connect them based on the stage list """
|
||||||
self.driver_inst_list = []
|
self.driver_inst_list = []
|
||||||
self.rightest_load_inst = {}
|
|
||||||
self.load_inst_map = {}
|
self.load_inst_map = {}
|
||||||
for stage_num, fanout_size in zip(range(len(self.fanout_list)), self.fanout_list):
|
for stage_num, fanout_size in zip(range(len(self.fanout_list)), self.fanout_list):
|
||||||
# Add the inverter
|
# Add the inverter
|
||||||
|
|
@ -100,9 +98,6 @@ class delay_chain(design.design):
|
||||||
|
|
||||||
# Keep track of all the loads to connect their inputs as a load
|
# Keep track of all the loads to connect their inputs as a load
|
||||||
self.load_inst_map[cur_driver].append(cur_load)
|
self.load_inst_map[cur_driver].append(cur_load)
|
||||||
else:
|
|
||||||
# Keep track of the last one so we can add the the wire later
|
|
||||||
self.rightest_load_inst[cur_driver]=cur_load
|
|
||||||
|
|
||||||
def place_inverters(self):
|
def place_inverters(self):
|
||||||
""" Place the inverters and connect them based on the stage list """
|
""" Place the inverters and connect them based on the stage list """
|
||||||
|
|
@ -126,7 +121,6 @@ class delay_chain(design.design):
|
||||||
load_list[i].place(offset=inv_offset,
|
load_list[i].place(offset=inv_offset,
|
||||||
mirror=inv_mirror)
|
mirror=inv_mirror)
|
||||||
|
|
||||||
|
|
||||||
def add_route(self, pin1, pin2):
|
def add_route(self, pin1, pin2):
|
||||||
""" This guarantees that we route from the top to bottom row correctly. """
|
""" This guarantees that we route from the top to bottom row correctly. """
|
||||||
pin1_pos = pin1.center()
|
pin1_pos = pin1.center()
|
||||||
|
|
@ -154,7 +148,7 @@ class delay_chain(design.design):
|
||||||
# Route an M3 horizontal wire to the furthest
|
# Route an M3 horizontal wire to the furthest
|
||||||
z_pin = inv.get_pin("Z")
|
z_pin = inv.get_pin("Z")
|
||||||
a_pin = inv.get_pin("A")
|
a_pin = inv.get_pin("A")
|
||||||
a_max = self.rightest_load_inst[inv].get_pin("A")
|
a_max = self.load_inst_map[inv][-1].get_pin("A")
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=a_pin.center())
|
offset=a_pin.center())
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
|
|
@ -163,7 +157,6 @@ class delay_chain(design.design):
|
||||||
offset=z_pin.center())
|
offset=z_pin.center())
|
||||||
self.add_path("m3", [z_pin.center(), a_max.center()])
|
self.add_path("m3", [z_pin.center(), a_max.center()])
|
||||||
|
|
||||||
|
|
||||||
# Route Z to the A of the next stage
|
# Route Z to the A of the next stage
|
||||||
if i + 1 < len(self.driver_inst_list):
|
if i + 1 < len(self.driver_inst_list):
|
||||||
z_pin = inv.get_pin("Z")
|
z_pin = inv.get_pin("Z")
|
||||||
|
|
@ -174,34 +167,23 @@ class delay_chain(design.design):
|
||||||
mid2_point = vector(next_a_pin.cx(), y_mid)
|
mid2_point = vector(next_a_pin.cx(), y_mid)
|
||||||
self.add_path("m2", [z_pin.center(), mid1_point, mid2_point, next_a_pin.center()])
|
self.add_path("m2", [z_pin.center(), mid1_point, mid2_point, next_a_pin.center()])
|
||||||
|
|
||||||
|
def route_supplies(self):
|
||||||
def add_layout_pins(self):
|
|
||||||
""" Add vdd and gnd rails and the input/output. Connect the gnd rails internally on
|
|
||||||
the top end with no input/output to obstruct. """
|
|
||||||
|
|
||||||
# Add power and ground to all the cells except:
|
# Add power and ground to all the cells except:
|
||||||
# the fanout driver, the right-most load
|
# the fanout driver, the right-most load
|
||||||
# The routing to connect the loads is over the first and last cells
|
# The routing to connect the loads is over the first and last cells
|
||||||
# We have an even number of drivers and must only do every other
|
# We have an even number of drivers and must only do every other
|
||||||
# supply rail
|
# supply rail
|
||||||
for i in range(0,len(self.driver_inst_list),2):
|
|
||||||
inv = self.driver_inst_list[i]
|
|
||||||
for load in self.load_inst_map[inv]:
|
|
||||||
if load==self.rightest_load_inst[inv]:
|
|
||||||
continue
|
|
||||||
for pin_name in ["vdd", "gnd"]:
|
|
||||||
pin = load.get_pin(pin_name)
|
|
||||||
self.add_power_pin(pin_name, pin.rc())
|
|
||||||
else:
|
|
||||||
# We have an even number of rows, so need to get the last gnd rail
|
|
||||||
inv = self.driver_inst_list[-1]
|
|
||||||
for load in self.load_inst_map[inv]:
|
|
||||||
if load==self.rightest_load_inst[inv]:
|
|
||||||
continue
|
|
||||||
pin_name = "gnd"
|
|
||||||
pin = load.get_pin(pin_name)
|
|
||||||
self.add_power_pin(pin_name, pin.rc())
|
|
||||||
|
|
||||||
|
for inst in self.driver_inst_list:
|
||||||
|
load_list = self.load_inst_map[inst]
|
||||||
|
for pin_name in ["vdd", "gnd"]:
|
||||||
|
pin = load_list[0].get_pin(pin_name)
|
||||||
|
self.add_power_pin(pin_name, pin.rc() - vector(self.m1_pitch, 0))
|
||||||
|
|
||||||
|
pin = load_list[-1].get_pin(pin_name)
|
||||||
|
self.add_power_pin(pin_name, pin.rc() - vector(0.5 * self.m1_pitch, 0))
|
||||||
|
|
||||||
|
def add_layout_pins(self):
|
||||||
|
|
||||||
# input is A pin of first inverter
|
# input is A pin of first inverter
|
||||||
a_pin = self.driver_inst_list[0].get_pin("A")
|
a_pin = self.driver_inst_list[0].get_pin("A")
|
||||||
|
|
@ -212,10 +194,9 @@ class delay_chain(design.design):
|
||||||
offset=a_pin.ll().scale(1, 0),
|
offset=a_pin.ll().scale(1, 0),
|
||||||
height=a_pin.cy())
|
height=a_pin.cy())
|
||||||
|
|
||||||
|
|
||||||
# output is A pin of last load inverter
|
# output is A pin of last load inverter
|
||||||
last_driver_inst = self.driver_inst_list[-1]
|
last_driver_inst = self.driver_inst_list[-1]
|
||||||
a_pin = self.rightest_load_inst[last_driver_inst].get_pin("A")
|
a_pin = self.load_inst_map[last_driver_inst][-1].get_pin("A")
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=a_pin.center())
|
offset=a_pin.center())
|
||||||
mid_point = vector(a_pin.cx() + 3 * self.m2_width, a_pin.cy())
|
mid_point = vector(a_pin.cx() + 3 * self.m2_width, a_pin.cy())
|
||||||
|
|
@ -234,11 +215,12 @@ class delay_chain(design.design):
|
||||||
def determine_delayed_en_stage_efforts(self, ext_delayed_en_cout, inp_is_rise=True):
|
def determine_delayed_en_stage_efforts(self, ext_delayed_en_cout, inp_is_rise=True):
|
||||||
"""Get the stage efforts from the en to s_en. Does not compute the delay for the bitline load."""
|
"""Get the stage efforts from the en to s_en. Does not compute the delay for the bitline load."""
|
||||||
stage_effort_list = []
|
stage_effort_list = []
|
||||||
#Add a stage to the list for every stage in delay chain. Stages only differ in fanout except the last which has an external cout.
|
# Add a stage to the list for every stage in delay chain.
|
||||||
|
# Stages only differ in fanout except the last which has an external cout.
|
||||||
last_stage_is_rise = inp_is_rise
|
last_stage_is_rise = inp_is_rise
|
||||||
for stage_fanout in self.fanout_list:
|
for stage_fanout in self.fanout_list:
|
||||||
stage_cout = self.inv.get_cin() * (stage_fanout + 1)
|
stage_cout = self.inv.get_cin() * (stage_fanout + 1)
|
||||||
if len(stage_effort_list) == len(self.fanout_list)-1: #last stage
|
if len(stage_effort_list) == len(self.fanout_list) - 1:
|
||||||
stage_cout+=ext_delayed_en_cout
|
stage_cout+=ext_delayed_en_cout
|
||||||
stage = self.inv.get_stage_effort(stage_cout, last_stage_is_rise)
|
stage = self.inv.get_stage_effort(stage_cout, last_stage_is_rise)
|
||||||
stage_effort_list.append(stage)
|
stage_effort_list.append(stage)
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,13 @@
|
||||||
#
|
#
|
||||||
import debug
|
import debug
|
||||||
import design
|
import design
|
||||||
from tech import drc,parameter
|
from tech import parameter
|
||||||
from tech import cell_properties as props
|
from tech import cell_properties as props
|
||||||
from math import log
|
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
|
||||||
|
|
||||||
class dff_buf(design.design):
|
class dff_buf(design.design):
|
||||||
"""
|
"""
|
||||||
This is a simple buffered DFF. The output is buffered
|
This is a simple buffered DFF. The output is buffered
|
||||||
|
|
@ -52,9 +52,8 @@ class dff_buf(design.design):
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
self.place_instances()
|
self.place_instances()
|
||||||
self.width = self.inv2_inst.rx()
|
self.width = self.inv2_inst.rx()
|
||||||
|
|
||||||
self.height = self.dff.height
|
self.height = self.dff.height
|
||||||
|
|
||||||
|
|
||||||
self.route_wires()
|
self.route_wires()
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
|
|
@ -74,8 +73,6 @@ class dff_buf(design.design):
|
||||||
height=self.dff.height)
|
height=self.dff.height)
|
||||||
self.add_mod(self.inv2)
|
self.add_mod(self.inv2)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
self.add_pin("D", "INPUT")
|
self.add_pin("D", "INPUT")
|
||||||
self.add_pin("Q", "OUTPUT")
|
self.add_pin("Q", "OUTPUT")
|
||||||
|
|
@ -91,8 +88,8 @@ class dff_buf(design.design):
|
||||||
def create_instances(self):
|
def create_instances(self):
|
||||||
self.dff_inst=self.add_inst(name="dff_buf_dff",
|
self.dff_inst=self.add_inst(name="dff_buf_dff",
|
||||||
mod=self.dff)
|
mod=self.dff)
|
||||||
self.connect_inst(props.dff_buff.buf_ports)
|
|
||||||
#self.connect_inst(["D", "qint", "clk", "vdd", "gnd"])
|
self.connect_inst(["D", "qint", "clk", "vdd", "gnd"])
|
||||||
|
|
||||||
self.inv1_inst=self.add_inst(name="dff_buf_inv1",
|
self.inv1_inst=self.add_inst(name="dff_buf_inv1",
|
||||||
mod=self.inv1)
|
mod=self.inv1)
|
||||||
|
|
@ -107,9 +104,21 @@ class dff_buf(design.design):
|
||||||
self.dff_inst.place(vector(0, 0))
|
self.dff_inst.place(vector(0, 0))
|
||||||
|
|
||||||
# Add INV1 to the right
|
# Add INV1 to the right
|
||||||
well_spacing = max(self.nwell_space,
|
# The INV needs well spacing because the DFF is likely from a library
|
||||||
self.pwell_space,
|
# with different well construction rules
|
||||||
self.pwell_to_nwell)
|
well_spacing = 0
|
||||||
|
try:
|
||||||
|
well_spacing = max(well_spacing, self.nwell_space)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
well_spacing = max(well_spacing, self.pwell_space)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
well_spacing = max(well_spacing, self.pwell_to_nwell)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
self.inv1_inst.place(vector(self.dff_inst.rx() + well_spacing + self.well_extend_active, 0))
|
self.inv1_inst.place(vector(self.dff_inst.rx() + well_spacing + self.well_extend_active, 0))
|
||||||
|
|
||||||
# Add INV2 to the right
|
# Add INV2 to the right
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,12 @@
|
||||||
#
|
#
|
||||||
import debug
|
import debug
|
||||||
import design
|
import design
|
||||||
from tech import drc
|
|
||||||
from tech import cell_properties as props
|
from tech import cell_properties as props
|
||||||
from math import log
|
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
|
||||||
|
|
||||||
class dff_buf_array(design.design):
|
class dff_buf_array(design.design):
|
||||||
"""
|
"""
|
||||||
This is a simple row (or multiple rows) of flops.
|
This is a simple row (or multiple rows) of flops.
|
||||||
|
|
@ -49,6 +48,7 @@ class dff_buf_array(design.design):
|
||||||
self.width = self.columns * self.dff.width
|
self.width = self.columns * self.dff.width
|
||||||
self.height = self.rows * self.dff.height
|
self.height = self.rows * self.dff.height
|
||||||
self.place_dff_array()
|
self.place_dff_array()
|
||||||
|
self.route_supplies()
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
@ -75,7 +75,6 @@ class dff_buf_array(design.design):
|
||||||
inv2_size=self.inv2_size)
|
inv2_size=self.inv2_size)
|
||||||
self.add_mod(self.dff)
|
self.add_mod(self.dff)
|
||||||
|
|
||||||
|
|
||||||
def create_dff_array(self):
|
def create_dff_array(self):
|
||||||
self.dff_insts={}
|
self.dff_insts={}
|
||||||
for row in range(self.rows):
|
for row in range(self.rows):
|
||||||
|
|
@ -96,15 +95,25 @@ class dff_buf_array(design.design):
|
||||||
|
|
||||||
def place_dff_array(self):
|
def place_dff_array(self):
|
||||||
|
|
||||||
well_spacing = max(self.nwell_space,
|
well_spacing = 0
|
||||||
self.pwell_space,
|
try:
|
||||||
self.pwell_to_nwell)
|
well_spacing = max(self.nwell_space, well_spacing)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
well_spacing = max(self.pwell_space, well_spacing)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
well_spacing = max(self.pwell_to_nwell, well_spacing)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
dff_pitch = self.dff.width + well_spacing + self.well_extend_active
|
dff_pitch = self.dff.width + well_spacing + self.well_extend_active
|
||||||
|
|
||||||
for row in range(self.rows):
|
for row in range(self.rows):
|
||||||
for col in range(self.columns):
|
for col in range(self.columns):
|
||||||
name = "Xdff_r{0}_c{1}".format(row,col)
|
# name = "Xdff_r{0}_c{1}".format(row, col)
|
||||||
if (row % 2 == 0):
|
if (row % 2 == 0):
|
||||||
base = vector(col * dff_pitch, row * self.dff.height)
|
base = vector(col * dff_pitch, row * self.dff.height)
|
||||||
mirror = "R0"
|
mirror = "R0"
|
||||||
|
|
@ -144,7 +153,16 @@ class dff_buf_array(design.design):
|
||||||
|
|
||||||
return dout_bar_name
|
return dout_bar_name
|
||||||
|
|
||||||
def add_layout_pins(self):
|
def route_supplies(self):
|
||||||
|
for row in range(self.rows):
|
||||||
|
vdd0_pin=self.dff_insts[row, 0].get_pin("vdd")
|
||||||
|
vddn_pin=self.dff_insts[row, self.columns - 1].get_pin("vdd")
|
||||||
|
self.add_path(vdd0_pin.layer, [vdd0_pin.lc(), vddn_pin.rc()], width=vdd0_pin.height())
|
||||||
|
|
||||||
|
gnd0_pin=self.dff_insts[row, 0].get_pin("gnd")
|
||||||
|
gndn_pin=self.dff_insts[row, self.columns - 1].get_pin("gnd")
|
||||||
|
self.add_path(gnd0_pin.layer, [gnd0_pin.lc(), gndn_pin.rc()], width=gnd0_pin.height())
|
||||||
|
|
||||||
for row in range(self.rows):
|
for row in range(self.rows):
|
||||||
for col in range(self.columns):
|
for col in range(self.columns):
|
||||||
# Continous vdd rail along with label.
|
# Continous vdd rail along with label.
|
||||||
|
|
@ -155,6 +173,7 @@ class dff_buf_array(design.design):
|
||||||
gnd_pin=self.dff_insts[row, col].get_pin("gnd")
|
gnd_pin=self.dff_insts[row, col].get_pin("gnd")
|
||||||
self.add_power_pin("gnd", gnd_pin.lc())
|
self.add_power_pin("gnd", gnd_pin.lc())
|
||||||
|
|
||||||
|
def add_layout_pins(self):
|
||||||
|
|
||||||
for row in range(self.rows):
|
for row in range(self.rows):
|
||||||
for col in range(self.columns):
|
for col in range(self.columns):
|
||||||
|
|
@ -182,7 +201,6 @@ class dff_buf_array(design.design):
|
||||||
width=dout_bar_pin.width(),
|
width=dout_bar_pin.width(),
|
||||||
height=dout_bar_pin.height())
|
height=dout_bar_pin.height())
|
||||||
|
|
||||||
|
|
||||||
# Create vertical spines to a single horizontal rail
|
# Create vertical spines to a single horizontal rail
|
||||||
clk_pin = self.dff_insts[0, 0].get_pin("clk")
|
clk_pin = self.dff_insts[0, 0].get_pin("clk")
|
||||||
clk_ypos = 2 * self.m3_pitch + self.m3_width
|
clk_ypos = 2 * self.m3_pitch + self.m3_width
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,15 @@ import math
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
from errors import drc_error
|
||||||
|
from tech import cell_properties
|
||||||
|
|
||||||
|
|
||||||
class hierarchical_decoder(design.design):
|
class hierarchical_decoder(design.design):
|
||||||
"""
|
"""
|
||||||
Dynamically generated hierarchical decoder.
|
Dynamically generated hierarchical decoder.
|
||||||
"""
|
"""
|
||||||
def __init__(self, name, rows):
|
def __init__(self, name, num_outputs):
|
||||||
design.design.__init__(self, name)
|
design.design.__init__(self, name)
|
||||||
|
|
||||||
self.AND_FORMAT = "DEC_AND_{0}"
|
self.AND_FORMAT = "DEC_AND_{0}"
|
||||||
|
|
@ -26,15 +28,55 @@ class hierarchical_decoder(design.design):
|
||||||
self.pre3x8_inst = []
|
self.pre3x8_inst = []
|
||||||
|
|
||||||
b = factory.create(module_type="bitcell")
|
b = factory.create(module_type="bitcell")
|
||||||
self.cell_height = b.height
|
try:
|
||||||
self.rows = rows
|
self.cell_multiple = cell_properties.bitcell.decoder_bitcell_multiple
|
||||||
self.num_inputs = math.ceil(math.log(self.rows, 2))
|
except AttributeError:
|
||||||
|
self.cell_multiple = 1
|
||||||
|
self.cell_height = self.cell_multiple * b.height
|
||||||
|
|
||||||
|
self.num_outputs = num_outputs
|
||||||
|
self.num_inputs = math.ceil(math.log(self.num_outputs, 2))
|
||||||
(self.no_of_pre2x4, self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs)
|
(self.no_of_pre2x4, self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs)
|
||||||
|
|
||||||
self.create_netlist()
|
self.create_netlist()
|
||||||
if not OPTS.netlist_only:
|
if not OPTS.netlist_only:
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
|
|
||||||
|
def find_decoder_height(self):
|
||||||
|
"""
|
||||||
|
Dead code. This would dynamically determine the bitcell multiple,
|
||||||
|
but I just decided to hard code it in the tech file if it is not 1
|
||||||
|
because a DRC tool would be required even to run in front-end mode.
|
||||||
|
"""
|
||||||
|
b = factory.create(module_type="bitcell")
|
||||||
|
|
||||||
|
# Old behavior
|
||||||
|
if OPTS.netlist_only:
|
||||||
|
return (b.height, 1)
|
||||||
|
|
||||||
|
# Search for the smallest multiple that works
|
||||||
|
cell_multiple = 1
|
||||||
|
while cell_multiple < 5:
|
||||||
|
cell_height = cell_multiple * b.height
|
||||||
|
# debug.info(2,"Trying mult = {0} height={1}".format(cell_multiple, cell_height))
|
||||||
|
try:
|
||||||
|
and3 = factory.create(module_type="pand3",
|
||||||
|
height=cell_height)
|
||||||
|
except drc_error:
|
||||||
|
# debug.info(1, "Incrementing decoder height by 1 bitcell height {}".format(b.height))
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
(drc_errors, lvs_errors) = and3.DRC_LVS(force_check=True)
|
||||||
|
total_errors = drc_errors + lvs_errors
|
||||||
|
if total_errors == 0:
|
||||||
|
debug.info(1, "Decoder height is multiple of {} bitcells.".format(cell_multiple))
|
||||||
|
return (cell_height, cell_multiple)
|
||||||
|
|
||||||
|
cell_multiple += 1
|
||||||
|
|
||||||
|
else:
|
||||||
|
debug.error("Couldn't find a valid decoder height multiple.", -1)
|
||||||
|
|
||||||
def create_netlist(self):
|
def create_netlist(self):
|
||||||
self.add_modules()
|
self.add_modules()
|
||||||
self.setup_netlist_constants()
|
self.setup_netlist_constants()
|
||||||
|
|
@ -46,8 +88,8 @@ class hierarchical_decoder(design.design):
|
||||||
self.setup_layout_constants()
|
self.setup_layout_constants()
|
||||||
self.place_pre_decoder()
|
self.place_pre_decoder()
|
||||||
self.place_row_decoder()
|
self.place_row_decoder()
|
||||||
self.route_input_rails()
|
self.route_inputs()
|
||||||
self.route_predecode_rails()
|
self.route_decoder_bus()
|
||||||
self.route_vdd_gnd()
|
self.route_vdd_gnd()
|
||||||
self.offset_all_coordinates()
|
self.offset_all_coordinates()
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
|
|
@ -101,7 +143,7 @@ class hierarchical_decoder(design.design):
|
||||||
def setup_netlist_constants(self):
|
def setup_netlist_constants(self):
|
||||||
self.predec_groups = [] # This array is a 2D array.
|
self.predec_groups = [] # This array is a 2D array.
|
||||||
|
|
||||||
# Distributing vertical rails to different groups. One group belongs to one pre-decoder.
|
# Distributing vertical bus to different groups. One group belongs to one pre-decoder.
|
||||||
# For example, for two 2:4 pre-decoder and one 3:8 pre-decoder, we will
|
# For example, for two 2:4 pre-decoder and one 3:8 pre-decoder, we will
|
||||||
# have total 16 output lines out of these 3 pre-decoders and they will
|
# have total 16 output lines out of these 3 pre-decoders and they will
|
||||||
# be distributed as [ [0,1,2,3] ,[4,5,6,7], [8,9,10,11,12,13,14,15] ]
|
# be distributed as [ [0,1,2,3] ,[4,5,6,7], [8,9,10,11,12,13,14,15] ]
|
||||||
|
|
@ -140,35 +182,42 @@ class hierarchical_decoder(design.design):
|
||||||
|
|
||||||
self.predecoder_height = self.pre2_4.height * self.no_of_pre2x4 + self.pre3_8.height * self.no_of_pre3x8
|
self.predecoder_height = self.pre2_4.height * self.no_of_pre2x4 + self.pre3_8.height * self.no_of_pre3x8
|
||||||
|
|
||||||
|
# We may have more than one bitcell per decoder row
|
||||||
|
self.num_rows = math.ceil(self.num_outputs / self.cell_multiple)
|
||||||
|
# We will place this many final decoders per row
|
||||||
|
self.decoders_per_row = math.ceil(self.num_outputs / self.num_rows)
|
||||||
|
|
||||||
# Calculates height and width of row-decoder
|
# Calculates height and width of row-decoder
|
||||||
if (self.num_inputs == 4 or self.num_inputs == 5):
|
if (self.num_inputs == 4 or self.num_inputs == 5):
|
||||||
nand_width = self.and2.width
|
nand_width = self.and2.width
|
||||||
else:
|
else:
|
||||||
nand_width = self.and3.width
|
nand_width = self.and3.width
|
||||||
self.internal_routing_width = self.m2_pitch * self.total_number_of_predecoder_outputs
|
self.internal_routing_width = self.m2_pitch * (self.total_number_of_predecoder_outputs + 1)
|
||||||
self.row_decoder_height = self.inv.height * self.rows
|
self.row_decoder_height = self.inv.height * self.num_rows
|
||||||
|
|
||||||
self.input_routing_width = (self.num_inputs + 1) * self.m2_pitch
|
self.input_routing_width = (self.num_inputs + 1) * self.m2_pitch
|
||||||
# Calculates height and width of hierarchical decoder
|
# Calculates height and width of hierarchical decoder
|
||||||
self.height = self.row_decoder_height
|
# Add extra pitch for good measure
|
||||||
|
self.height = max(self.predecoder_height, self.row_decoder_height) + self.m3_pitch
|
||||||
self.width = self.input_routing_width + self.predecoder_width \
|
self.width = self.input_routing_width + self.predecoder_width \
|
||||||
+ self.internal_routing_width + nand_width + self.inv.width
|
+ self.internal_routing_width \
|
||||||
|
+ self.decoders_per_row * nand_width + self.inv.width
|
||||||
|
|
||||||
def route_input_rails(self):
|
def route_inputs(self):
|
||||||
""" Create input rails for the predecoders """
|
""" Create input bus for the predecoders """
|
||||||
# inputs should be as high as the decoders
|
# inputs should be as high as the decoders
|
||||||
input_height = self.no_of_pre2x4 * self.pre2_4.height + self.no_of_pre3x8 * self.pre3_8.height
|
input_height = self.no_of_pre2x4 * self.pre2_4.height + self.no_of_pre3x8 * self.pre3_8.height
|
||||||
|
|
||||||
# Find the left-most predecoder
|
# Find the left-most predecoder
|
||||||
min_x = 0
|
min_x = 0
|
||||||
if self.no_of_pre2x4 > 0:
|
if self.no_of_pre2x4 > 0:
|
||||||
min_x = min(min_x, -self.pre2_4.width)
|
min_x = min(min_x, self.pre2x4_inst[0].lx())
|
||||||
if self.no_of_pre3x8 > 0:
|
if self.no_of_pre3x8 > 0:
|
||||||
min_x = min(min_x, -self.pre3_8.width)
|
min_x = min(min_x, self.pre3x8_inst[0].lx())
|
||||||
input_offset=vector(min_x - self.input_routing_width, 0)
|
input_offset=vector(min_x - self.input_routing_width, 0)
|
||||||
|
|
||||||
input_bus_names = ["addr_{0}".format(i) for i in range(self.num_inputs)]
|
input_bus_names = ["addr_{0}".format(i) for i in range(self.num_inputs)]
|
||||||
self.input_rails = self.create_vertical_pin_bus(layer="m2",
|
self.input_bus = self.create_vertical_pin_bus(layer="m2",
|
||||||
pitch=self.m2_pitch,
|
pitch=self.m2_pitch,
|
||||||
offset=input_offset,
|
offset=input_offset,
|
||||||
names=input_bus_names,
|
names=input_bus_names,
|
||||||
|
|
@ -182,7 +231,7 @@ class hierarchical_decoder(design.design):
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
index = pre_num * 2 + i
|
index = pre_num * 2 + i
|
||||||
|
|
||||||
input_pos = self.input_rails["addr_{}".format(index)]
|
input_pos = self.input_bus["addr_{}".format(index)]
|
||||||
|
|
||||||
in_name = "in_{}".format(i)
|
in_name = "in_{}".format(i)
|
||||||
decoder_pin = self.pre2x4_inst[pre_num].get_pin(in_name)
|
decoder_pin = self.pre2x4_inst[pre_num].get_pin(in_name)
|
||||||
|
|
@ -192,13 +241,13 @@ class hierarchical_decoder(design.design):
|
||||||
decoder_offset = decoder_pin.bc() + vector(0, (i + 1) * self.inv.height)
|
decoder_offset = decoder_pin.bc() + vector(0, (i + 1) * self.inv.height)
|
||||||
input_offset = input_pos.scale(1, 0) + decoder_offset.scale(0, 1)
|
input_offset = input_pos.scale(1, 0) + decoder_offset.scale(0, 1)
|
||||||
|
|
||||||
self.route_input_rail(decoder_offset, input_offset)
|
self.route_input_bus(decoder_offset, input_offset)
|
||||||
|
|
||||||
for pre_num in range(self.no_of_pre3x8):
|
for pre_num in range(self.no_of_pre3x8):
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
index = pre_num * 3 + i + self.no_of_pre2x4 * 2
|
index = pre_num * 3 + i + self.no_of_pre2x4 * 2
|
||||||
|
|
||||||
input_pos = self.input_rails["addr_{}".format(index)]
|
input_pos = self.input_bus["addr_{}".format(index)]
|
||||||
|
|
||||||
in_name = "in_{}".format(i)
|
in_name = "in_{}".format(i)
|
||||||
decoder_pin = self.pre3x8_inst[pre_num].get_pin(in_name)
|
decoder_pin = self.pre3x8_inst[pre_num].get_pin(in_name)
|
||||||
|
|
@ -208,10 +257,13 @@ class hierarchical_decoder(design.design):
|
||||||
decoder_offset = decoder_pin.bc() + vector(0, (i + 1) * self.inv.height)
|
decoder_offset = decoder_pin.bc() + vector(0, (i + 1) * self.inv.height)
|
||||||
input_offset = input_pos.scale(1, 0) + decoder_offset.scale(0, 1)
|
input_offset = input_pos.scale(1, 0) + decoder_offset.scale(0, 1)
|
||||||
|
|
||||||
self.route_input_rail(decoder_offset, input_offset)
|
self.route_input_bus(decoder_offset, input_offset)
|
||||||
|
|
||||||
def route_input_rail(self, input_offset, output_offset):
|
def route_input_bus(self, input_offset, output_offset):
|
||||||
""" Route a vertical M2 coordinate to another vertical M2 coordinate to the predecode inputs """
|
"""
|
||||||
|
Route a vertical M2 coordinate to another
|
||||||
|
vertical M2 coordinate to the predecode inputs
|
||||||
|
"""
|
||||||
|
|
||||||
self.add_via_center(layers=self.m2_stack,
|
self.add_via_center(layers=self.m2_stack,
|
||||||
offset=input_offset)
|
offset=input_offset)
|
||||||
|
|
@ -225,7 +277,7 @@ class hierarchical_decoder(design.design):
|
||||||
for i in range(self.num_inputs):
|
for i in range(self.num_inputs):
|
||||||
self.add_pin("addr_{0}".format(i), "INPUT")
|
self.add_pin("addr_{0}".format(i), "INPUT")
|
||||||
|
|
||||||
for j in range(self.rows):
|
for j in range(self.num_outputs):
|
||||||
self.add_pin("decode_{0}".format(j), "OUTPUT")
|
self.add_pin("decode_{0}".format(j), "OUTPUT")
|
||||||
self.add_pin("vdd", "POWER")
|
self.add_pin("vdd", "POWER")
|
||||||
self.add_pin("gnd", "GROUND")
|
self.add_pin("gnd", "GROUND")
|
||||||
|
|
@ -294,18 +346,17 @@ class hierarchical_decoder(design.design):
|
||||||
else:
|
else:
|
||||||
base= vector(-self.pre2_4.width, num * self.pre2_4.height)
|
base= vector(-self.pre2_4.width, num * self.pre2_4.height)
|
||||||
|
|
||||||
self.pre2x4_inst[num].place(base)
|
self.pre2x4_inst[num].place(base - vector(2 * self.m2_pitch, 0))
|
||||||
|
|
||||||
def place_pre3x8(self, num):
|
def place_pre3x8(self, num):
|
||||||
""" Place 3x8 predecoder to the left of the origin and above any 2x4 decoders """
|
""" Place 3x8 predecoder to the left of the origin and above any 2x4 decoders """
|
||||||
if (self.num_inputs == 3):
|
if (self.num_inputs == 3):
|
||||||
offset = vector(-self.pre_3_8.width, 0)
|
offset = vector(-self.pre_3_8.width, 0)
|
||||||
mirror = "R0"
|
|
||||||
else:
|
else:
|
||||||
height = self.no_of_pre2x4 * self.pre2_4.height + num * self.pre3_8.height
|
height = self.no_of_pre2x4 * self.pre2_4.height + num * self.pre3_8.height
|
||||||
offset = vector(-self.pre3_8.width, height)
|
offset = vector(-self.pre3_8.width, height)
|
||||||
|
|
||||||
self.pre3x8_inst[num].place(offset)
|
self.pre3x8_inst[num].place(offset - vector(2 * self.m2_pitch, 0))
|
||||||
|
|
||||||
def create_row_decoder(self):
|
def create_row_decoder(self):
|
||||||
""" Create the row-decoder by placing AND2/AND3 and Inverters
|
""" Create the row-decoder by placing AND2/AND3 and Inverters
|
||||||
|
|
@ -322,14 +373,14 @@ class hierarchical_decoder(design.design):
|
||||||
if (self.num_inputs == 4 or self.num_inputs == 5):
|
if (self.num_inputs == 4 or self.num_inputs == 5):
|
||||||
for i in range(len(self.predec_groups[0])):
|
for i in range(len(self.predec_groups[0])):
|
||||||
for j in range(len(self.predec_groups[1])):
|
for j in range(len(self.predec_groups[1])):
|
||||||
row = len(self.predec_groups[0]) * j + i
|
output = len(self.predec_groups[0]) * j + i
|
||||||
if (row < self.rows):
|
if (output < self.num_outputs):
|
||||||
name = self.AND_FORMAT.format(row)
|
name = self.AND_FORMAT.format(output)
|
||||||
self.and_inst.append(self.add_inst(name=name,
|
self.and_inst.append(self.add_inst(name=name,
|
||||||
mod=self.and2))
|
mod=self.and2))
|
||||||
pins =["out_{0}".format(i),
|
pins =["out_{0}".format(i),
|
||||||
"out_{0}".format(j + len(self.predec_groups[0])),
|
"out_{0}".format(j + len(self.predec_groups[0])),
|
||||||
"decode_{0}".format(row),
|
"decode_{0}".format(output),
|
||||||
"vdd", "gnd"]
|
"vdd", "gnd"]
|
||||||
self.connect_inst(pins)
|
self.connect_inst(pins)
|
||||||
|
|
||||||
|
|
@ -338,18 +389,18 @@ class hierarchical_decoder(design.design):
|
||||||
for i in range(len(self.predec_groups[0])):
|
for i in range(len(self.predec_groups[0])):
|
||||||
for j in range(len(self.predec_groups[1])):
|
for j in range(len(self.predec_groups[1])):
|
||||||
for k in range(len(self.predec_groups[2])):
|
for k in range(len(self.predec_groups[2])):
|
||||||
row = (len(self.predec_groups[0]) * len(self.predec_groups[1])) * k \
|
output = (len(self.predec_groups[0]) * len(self.predec_groups[1])) * k \
|
||||||
+ len(self.predec_groups[0]) * j + i
|
+ len(self.predec_groups[0]) * j + i
|
||||||
|
|
||||||
if (row < self.rows):
|
if (output < self.num_outputs):
|
||||||
name = self.AND_FORMAT.format(row)
|
name = self.AND_FORMAT.format(output)
|
||||||
self.and_inst.append(self.add_inst(name=name,
|
self.and_inst.append(self.add_inst(name=name,
|
||||||
mod=self.and3))
|
mod=self.and3))
|
||||||
|
|
||||||
pins = ["out_{0}".format(i),
|
pins = ["out_{0}".format(i),
|
||||||
"out_{0}".format(j + len(self.predec_groups[0])),
|
"out_{0}".format(j + len(self.predec_groups[0])),
|
||||||
"out_{0}".format(k + len(self.predec_groups[0]) + len(self.predec_groups[1])),
|
"out_{0}".format(k + len(self.predec_groups[0]) + len(self.predec_groups[1])),
|
||||||
"decode_{0}".format(row),
|
"decode_{0}".format(output),
|
||||||
"vdd", "gnd"]
|
"vdd", "gnd"]
|
||||||
self.connect_inst(pins)
|
self.connect_inst(pins)
|
||||||
|
|
||||||
|
|
@ -363,7 +414,10 @@ class hierarchical_decoder(design.design):
|
||||||
self.route_decoder()
|
self.route_decoder()
|
||||||
|
|
||||||
def place_decoder_and_array(self):
|
def place_decoder_and_array(self):
|
||||||
""" Add a column of AND gates for final decode """
|
"""
|
||||||
|
Add a column of AND gates for final decode.
|
||||||
|
This may have more than one decoder per row to match the bitcell height.
|
||||||
|
"""
|
||||||
|
|
||||||
# Row Decoder AND GATE array for address inputs <5.
|
# Row Decoder AND GATE array for address inputs <5.
|
||||||
if (self.num_inputs == 4 or self.num_inputs == 5):
|
if (self.num_inputs == 4 or self.num_inputs == 5):
|
||||||
|
|
@ -375,9 +429,13 @@ class hierarchical_decoder(design.design):
|
||||||
self.place_and_array(and_mod=self.and3)
|
self.place_and_array(and_mod=self.and3)
|
||||||
|
|
||||||
def place_and_array(self, and_mod):
|
def place_and_array(self, and_mod):
|
||||||
""" Add a column of AND gates for the decoder above the predecoders."""
|
"""
|
||||||
|
Add a column of AND gates for the decoder above the predecoders.
|
||||||
|
"""
|
||||||
|
|
||||||
for row in range(self.rows):
|
for inst_index in range(self.num_outputs):
|
||||||
|
row = math.floor(inst_index / self.decoders_per_row)
|
||||||
|
dec = inst_index % self.decoders_per_row
|
||||||
if ((row % 2) == 0):
|
if ((row % 2) == 0):
|
||||||
y_off = and_mod.height * row
|
y_off = and_mod.height * row
|
||||||
mirror = "R0"
|
mirror = "R0"
|
||||||
|
|
@ -385,46 +443,52 @@ class hierarchical_decoder(design.design):
|
||||||
y_off = and_mod.height * (row + 1)
|
y_off = and_mod.height * (row + 1)
|
||||||
mirror = "MX"
|
mirror = "MX"
|
||||||
|
|
||||||
self.and_inst[row].place(offset=[self.internal_routing_width, y_off],
|
x_off = self.internal_routing_width + dec * and_mod.width
|
||||||
|
self.and_inst[inst_index].place(offset=vector(x_off, y_off),
|
||||||
mirror=mirror)
|
mirror=mirror)
|
||||||
|
|
||||||
def route_decoder(self):
|
def route_decoder(self):
|
||||||
""" Add the pins. """
|
""" Add the pins. """
|
||||||
|
|
||||||
for row in range(self.rows):
|
for output in range(self.num_outputs):
|
||||||
z_pin = self.and_inst[row].get_pin("Z")
|
z_pin = self.and_inst[output].get_pin("Z")
|
||||||
self.add_layout_pin(text="decode_{0}".format(row),
|
self.add_layout_pin(text="decode_{0}".format(output),
|
||||||
layer="m1",
|
layer="m1",
|
||||||
offset=z_pin.ll(),
|
offset=z_pin.ll(),
|
||||||
width=z_pin.width(),
|
width=z_pin.width(),
|
||||||
height=z_pin.height())
|
height=z_pin.height())
|
||||||
|
|
||||||
def route_predecode_rails(self):
|
def route_decoder_bus(self):
|
||||||
""" Creates vertical metal 2 rails to connect predecoder and decoder stages."""
|
"""
|
||||||
|
Creates vertical metal 2 bus to connect predecoder and decoder stages.
|
||||||
|
"""
|
||||||
|
|
||||||
# This is not needed for inputs <4 since they have no pre/decode stages.
|
# This is not needed for inputs <4 since they have no pre/decode stages.
|
||||||
if (self.num_inputs >= 4):
|
if (self.num_inputs >= 4):
|
||||||
input_offset = vector(0.5 * self.m2_width, 0)
|
# This leaves an offset for the predecoder output jogs
|
||||||
input_bus_names = ["predecode_{0}".format(i) for i in range(self.total_number_of_predecoder_outputs)]
|
input_bus_names = ["predecode_{0}".format(i) for i in range(self.total_number_of_predecoder_outputs)]
|
||||||
self.predecode_rails = self.create_vertical_pin_bus(layer="m2",
|
self.predecode_bus = self.create_vertical_pin_bus(layer="m2",
|
||||||
pitch=self.m2_pitch,
|
pitch=self.m2_pitch,
|
||||||
offset=input_offset,
|
offset=vector(0, 0),
|
||||||
names=input_bus_names,
|
names=input_bus_names,
|
||||||
length=self.height)
|
length=self.height)
|
||||||
|
|
||||||
self.route_rails_to_predecodes()
|
self.route_predecodes_to_bus()
|
||||||
self.route_rails_to_decoder()
|
self.route_bus_to_decoder()
|
||||||
|
|
||||||
def route_rails_to_predecodes(self):
|
|
||||||
""" Iterates through all of the predecodes and connects to the rails including the offsets """
|
|
||||||
|
|
||||||
|
def route_predecodes_to_bus(self):
|
||||||
|
"""
|
||||||
|
Iterates through all of the predecodes
|
||||||
|
and connects to the rails including the offsets
|
||||||
|
"""
|
||||||
# FIXME: convert to connect_bus
|
# FIXME: convert to connect_bus
|
||||||
for pre_num in range(self.no_of_pre2x4):
|
for pre_num in range(self.no_of_pre2x4):
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
predecode_name = "predecode_{}".format(pre_num * 4 + i)
|
predecode_name = "predecode_{}".format(pre_num * 4 + i)
|
||||||
out_name = "out_{}".format(i)
|
out_name = "out_{}".format(i)
|
||||||
pin = self.pre2x4_inst[pre_num].get_pin(out_name)
|
pin = self.pre2x4_inst[pre_num].get_pin(out_name)
|
||||||
self.route_predecode_rail_m3(predecode_name, pin)
|
x_offset = self.pre2x4_inst[pre_num].rx() + self.m2_pitch
|
||||||
|
self.route_predecode_bus_inputs(predecode_name, pin, x_offset)
|
||||||
|
|
||||||
# FIXME: convert to connect_bus
|
# FIXME: convert to connect_bus
|
||||||
for pre_num in range(self.no_of_pre3x8):
|
for pre_num in range(self.no_of_pre3x8):
|
||||||
|
|
@ -432,52 +496,82 @@ class hierarchical_decoder(design.design):
|
||||||
predecode_name = "predecode_{}".format(pre_num * 8 + i + self.no_of_pre2x4 * 4)
|
predecode_name = "predecode_{}".format(pre_num * 8 + i + self.no_of_pre2x4 * 4)
|
||||||
out_name = "out_{}".format(i)
|
out_name = "out_{}".format(i)
|
||||||
pin = self.pre3x8_inst[pre_num].get_pin(out_name)
|
pin = self.pre3x8_inst[pre_num].get_pin(out_name)
|
||||||
self.route_predecode_rail_m3(predecode_name, pin)
|
x_offset = self.pre3x8_inst[pre_num].rx() + self.m2_pitch
|
||||||
|
self.route_predecode_bus_inputs(predecode_name, pin, x_offset)
|
||||||
|
|
||||||
def route_rails_to_decoder(self):
|
def route_bus_to_decoder(self):
|
||||||
""" Use the self.predec_groups to determine the connections to the decoder AND gates.
|
|
||||||
Inputs of AND2/AND3 gates come from different groups.
|
|
||||||
For example for these groups [ [0,1,2,3] ,[4,5,6,7],
|
|
||||||
[8,9,10,11,12,13,14,15] ] the first AND3 inputs are connected to
|
|
||||||
[0,4,8] and second AND3 is connected to [0,4,9] ........... and the
|
|
||||||
128th AND3 is connected to [3,7,15]
|
|
||||||
"""
|
"""
|
||||||
row_index = 0
|
Use the self.predec_groups to determine the connections to the decoder AND gates.
|
||||||
|
Inputs of AND2/AND3 gates come from different groups.
|
||||||
|
For example for these groups
|
||||||
|
[ [0,1,2,3] ,[4,5,6,7], [8,9,10,11,12,13,14,15] ]
|
||||||
|
the first AND3 inputs are connected to [0,4,8],
|
||||||
|
second AND3 is connected to [0,4,9],
|
||||||
|
...
|
||||||
|
and the 128th AND3 is connected to [3,7,15]
|
||||||
|
"""
|
||||||
|
output_index = 0
|
||||||
|
|
||||||
if (self.num_inputs == 4 or self.num_inputs == 5):
|
if (self.num_inputs == 4 or self.num_inputs == 5):
|
||||||
for index_B in self.predec_groups[1]:
|
for index_B in self.predec_groups[1]:
|
||||||
for index_A in self.predec_groups[0]:
|
for index_A in self.predec_groups[0]:
|
||||||
# FIXME: convert to connect_bus?
|
# FIXME: convert to connect_bus?
|
||||||
if (row_index < self.rows):
|
if (output_index < self.num_outputs):
|
||||||
|
row_index = math.floor(output_index / self.decoders_per_row)
|
||||||
|
row_remainder = (output_index % self.decoders_per_row)
|
||||||
|
row_offset = row_index * self.and_inst[0].height + (2 * row_remainder + 1) * self.m3_pitch
|
||||||
predecode_name = "predecode_{}".format(index_A)
|
predecode_name = "predecode_{}".format(index_A)
|
||||||
self.route_predecode_rail(predecode_name, self.and_inst[row_index].get_pin("A"))
|
self.route_predecode_bus_outputs(predecode_name,
|
||||||
|
self.and_inst[output_index].get_pin("A"),
|
||||||
|
row_offset)
|
||||||
predecode_name = "predecode_{}".format(index_B)
|
predecode_name = "predecode_{}".format(index_B)
|
||||||
self.route_predecode_rail(predecode_name, self.and_inst[row_index].get_pin("B"))
|
self.route_predecode_bus_outputs(predecode_name,
|
||||||
row_index = row_index + 1
|
self.and_inst[output_index].get_pin("B"),
|
||||||
|
row_offset + self.m3_pitch)
|
||||||
|
output_index = output_index + 1
|
||||||
|
|
||||||
elif (self.num_inputs > 5):
|
elif (self.num_inputs > 5):
|
||||||
for index_C in self.predec_groups[2]:
|
for index_C in self.predec_groups[2]:
|
||||||
for index_B in self.predec_groups[1]:
|
for index_B in self.predec_groups[1]:
|
||||||
for index_A in self.predec_groups[0]:
|
for index_A in self.predec_groups[0]:
|
||||||
# FIXME: convert to connect_bus?
|
# FIXME: convert to connect_bus?
|
||||||
if (row_index < self.rows):
|
if (output_index < self.num_outputs):
|
||||||
|
row_index = math.floor(output_index / self.decoders_per_row)
|
||||||
|
row_remainder = (output_index % self.decoders_per_row)
|
||||||
|
row_offset = row_index * self.and_inst[0].height + (3 * row_remainder + 1) * self.m3_pitch
|
||||||
predecode_name = "predecode_{}".format(index_A)
|
predecode_name = "predecode_{}".format(index_A)
|
||||||
self.route_predecode_rail(predecode_name, self.and_inst[row_index].get_pin("A"))
|
self.route_predecode_bus_outputs(predecode_name,
|
||||||
|
self.and_inst[output_index].get_pin("A"),
|
||||||
|
row_offset)
|
||||||
predecode_name = "predecode_{}".format(index_B)
|
predecode_name = "predecode_{}".format(index_B)
|
||||||
self.route_predecode_rail(predecode_name, self.and_inst[row_index].get_pin("B"))
|
self.route_predecode_bus_outputs(predecode_name,
|
||||||
|
self.and_inst[output_index].get_pin("B"),
|
||||||
|
row_offset + self.m3_pitch)
|
||||||
predecode_name = "predecode_{}".format(index_C)
|
predecode_name = "predecode_{}".format(index_C)
|
||||||
self.route_predecode_rail(predecode_name, self.and_inst[row_index].get_pin("C"))
|
self.route_predecode_bus_outputs(predecode_name,
|
||||||
row_index = row_index + 1
|
self.and_inst[output_index].get_pin("C"),
|
||||||
|
row_offset + 2 * self.m3_pitch)
|
||||||
|
output_index = output_index + 1
|
||||||
|
|
||||||
def route_vdd_gnd(self):
|
def route_vdd_gnd(self):
|
||||||
""" Add a pin for each row of vdd/gnd which are must-connects next level up. """
|
"""
|
||||||
|
Add a pin for each row of vdd/gnd which are
|
||||||
|
must-connects next level up.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# The vias will be placed at the right of the cells.
|
||||||
|
xoffset = max(x.rx() for x in self.and_inst)
|
||||||
|
for num in range(0, self.num_outputs):
|
||||||
|
# Only add the power pin for the 1st in each row
|
||||||
|
if num % self.decoders_per_row:
|
||||||
|
continue
|
||||||
|
|
||||||
# The vias will be placed in the center and right of the cells, respectively.
|
|
||||||
xoffset = self.and_inst[0].rx()
|
|
||||||
for num in range(0, self.rows):
|
|
||||||
for pin_name in ["vdd", "gnd"]:
|
for pin_name in ["vdd", "gnd"]:
|
||||||
# The nand and inv are the same height rows...
|
# The nand and inv are the same height rows...
|
||||||
supply_pin = self.and_inst[num].get_pin(pin_name)
|
supply_pin = self.and_inst[num].get_pin(pin_name)
|
||||||
pin_pos = vector(xoffset, supply_pin.cy())
|
pin_pos = vector(xoffset, supply_pin.cy())
|
||||||
|
self.add_path("m1",
|
||||||
|
[supply_pin.lc(), vector(xoffset, supply_pin.cy())])
|
||||||
self.add_power_pin(name=pin_name,
|
self.add_power_pin(name=pin_name,
|
||||||
loc=pin_pos)
|
loc=pin_pos)
|
||||||
|
|
||||||
|
|
@ -486,23 +580,42 @@ class hierarchical_decoder(design.design):
|
||||||
self.copy_layout_pin(pre, "vdd")
|
self.copy_layout_pin(pre, "vdd")
|
||||||
self.copy_layout_pin(pre, "gnd")
|
self.copy_layout_pin(pre, "gnd")
|
||||||
|
|
||||||
def route_predecode_rail(self, rail_name, pin):
|
def route_predecode_bus_outputs(self, rail_name, pin, y_offset):
|
||||||
""" Connect the routing rail to the given metal1 pin """
|
"""
|
||||||
rail_pos = vector(self.predecode_rails[rail_name].x, pin.lc().y)
|
Connect the routing rail to the given metal1 pin
|
||||||
self.add_path("m1", [rail_pos, pin.lc()])
|
using a routing track at the given y_offset
|
||||||
|
|
||||||
|
"""
|
||||||
|
pin_pos = pin.center()
|
||||||
|
# If we have a single decoder per row, we can route on M1
|
||||||
|
if self.decoders_per_row == 1:
|
||||||
|
rail_pos = vector(self.predecode_bus[rail_name].x, pin_pos.y)
|
||||||
|
self.add_path("m1", [rail_pos, pin_pos])
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=rail_pos)
|
offset=rail_pos)
|
||||||
|
# If not, we must route over the decoder cells on M3
|
||||||
|
else:
|
||||||
|
rail_pos = vector(self.predecode_bus[rail_name].x, y_offset)
|
||||||
|
mid_pos = vector(pin_pos.x, rail_pos.y)
|
||||||
|
self.add_wire(self.m2_stack[::-1], [rail_pos, mid_pos, pin_pos])
|
||||||
|
self.add_via_center(layers=self.m2_stack,
|
||||||
|
offset=rail_pos)
|
||||||
|
self.add_via_center(layers=self.m1_stack,
|
||||||
|
offset=pin_pos)
|
||||||
|
|
||||||
def route_predecode_rail_m3(self, rail_name, pin):
|
def route_predecode_bus_inputs(self, rail_name, pin, x_offset):
|
||||||
""" Connect the routing rail to the given metal1 pin """
|
"""
|
||||||
|
Connect the routing rail to the given metal1 pin using a jog
|
||||||
|
to the right of the cell at the given x_offset.
|
||||||
|
"""
|
||||||
# This routes the pin up to the rail, basically, to avoid conflicts.
|
# This routes the pin up to the rail, basically, to avoid conflicts.
|
||||||
# It would be fixed with a channel router.
|
# It would be fixed with a channel router.
|
||||||
mid_point = vector(pin.cx(), pin.cy() + self.inv.height / 2)
|
pin_pos = pin.center()
|
||||||
rail_pos = vector(self.predecode_rails[rail_name].x, mid_point.y)
|
mid_point1 = vector(x_offset, pin_pos.y)
|
||||||
|
mid_point2 = vector(x_offset, pin_pos.y + self.inv.height / 2)
|
||||||
|
rail_pos = vector(self.predecode_bus[rail_name].x, mid_point2.y)
|
||||||
|
self.add_wire(self.m1_stack, [pin_pos, mid_point1, mid_point2, rail_pos])
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=pin.center())
|
|
||||||
self.add_wire(("m3", "via2", "m2"), [rail_pos, mid_point, pin.uc()])
|
|
||||||
self.add_via_center(layers=self.m2_stack,
|
|
||||||
offset=rail_pos)
|
offset=rail_pos)
|
||||||
|
|
||||||
def input_load(self):
|
def input_load(self):
|
||||||
|
|
|
||||||
|
|
@ -94,13 +94,10 @@ class port_address(design.design):
|
||||||
mid2 = decoder_out_pos.scale(0.5, 0) + driver_in_pos.scale(0.5, 1)
|
mid2 = decoder_out_pos.scale(0.5, 0) + driver_in_pos.scale(0.5, 1)
|
||||||
self.add_path("m1", [decoder_out_pos, mid1, mid2, driver_in_pos])
|
self.add_path("m1", [decoder_out_pos, mid1, mid2, driver_in_pos])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
|
|
||||||
self.row_decoder = factory.create(module_type="decoder",
|
self.row_decoder = factory.create(module_type="decoder",
|
||||||
rows=self.num_rows)
|
num_outputs=self.num_rows)
|
||||||
self.add_mod(self.row_decoder)
|
self.add_mod(self.row_decoder)
|
||||||
|
|
||||||
self.wordline_driver = factory.create(module_type="wordline_driver",
|
self.wordline_driver = factory.create(module_type="wordline_driver",
|
||||||
|
|
@ -108,7 +105,6 @@ class port_address(design.design):
|
||||||
cols=self.num_cols)
|
cols=self.num_cols)
|
||||||
self.add_mod(self.wordline_driver)
|
self.add_mod(self.wordline_driver)
|
||||||
|
|
||||||
|
|
||||||
def create_row_decoder(self):
|
def create_row_decoder(self):
|
||||||
""" Create the hierarchical row decoder """
|
""" Create the hierarchical row decoder """
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -783,8 +783,13 @@ class port_data(design.design):
|
||||||
bottom_names = self._get_bitline_pins(bot_inst_group, bit)
|
bottom_names = self._get_bitline_pins(bot_inst_group, bit)
|
||||||
top_names = self._get_bitline_pins(top_inst_group, bit)
|
top_names = self._get_bitline_pins(top_inst_group, bit)
|
||||||
|
|
||||||
|
if bottom_names[0].layer == "m2":
|
||||||
|
bitline_dirs = ("H", "V")
|
||||||
|
elif bottom_names[0].layer == "m1":
|
||||||
|
bitline_dirs = ("V", "H")
|
||||||
|
|
||||||
route_map = list(zip(bottom_names, top_names))
|
route_map = list(zip(bottom_names, top_names))
|
||||||
self.create_horizontal_channel_route(route_map, offset, self.m1_stack)
|
self.create_horizontal_channel_route(route_map, offset, self.m1_stack, bitline_dirs)
|
||||||
|
|
||||||
def connect_bitlines(self, inst1, inst2, num_bits,
|
def connect_bitlines(self, inst1, inst2, num_bits,
|
||||||
inst1_bls_template="{inst}_{bit}",
|
inst1_bls_template="{inst}_{bit}",
|
||||||
|
|
|
||||||
|
|
@ -73,11 +73,12 @@ class precharge_array(design.design):
|
||||||
|
|
||||||
def add_layout_pins(self):
|
def add_layout_pins(self):
|
||||||
|
|
||||||
|
en_bar_pin = self.pc_cell.get_pin("en_bar")
|
||||||
self.add_layout_pin(text="en_bar",
|
self.add_layout_pin(text="en_bar",
|
||||||
layer="m1",
|
layer=en_bar_pin.layer,
|
||||||
offset=self.pc_cell.get_pin("en_bar").ll(),
|
offset=en_bar_pin.ll(),
|
||||||
width=self.width,
|
width=self.width,
|
||||||
height=drc("minwidth_m1"))
|
height=en_bar_pin.height())
|
||||||
|
|
||||||
for inst in self.local_insts:
|
for inst in self.local_insts:
|
||||||
self.copy_layout_pin(inst, "vdd")
|
self.copy_layout_pin(inst, "vdd")
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import debug
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
import logical_effort
|
import logical_effort
|
||||||
|
|
||||||
|
|
||||||
class sense_amp_array(design.design):
|
class sense_amp_array(design.design):
|
||||||
"""
|
"""
|
||||||
Array of sense amplifiers to read the bitlines through the column mux.
|
Array of sense amplifiers to read the bitlines through the column mux.
|
||||||
|
|
@ -142,19 +143,20 @@ class sense_amp_array(design.design):
|
||||||
amp_position = vector(xoffset, 0)
|
amp_position = vector(xoffset, 0)
|
||||||
self.local_insts[index].place(offset=amp_position,mirror=mirror)
|
self.local_insts[index].place(offset=amp_position,mirror=mirror)
|
||||||
|
|
||||||
|
|
||||||
def add_layout_pins(self):
|
def add_layout_pins(self):
|
||||||
for i in range(len(self.local_insts)):
|
for i in range(len(self.local_insts)):
|
||||||
inst = self.local_insts[i]
|
inst = self.local_insts[i]
|
||||||
|
|
||||||
|
gnd_pin = inst.get_pin("gnd")
|
||||||
self.add_power_pin(name="gnd",
|
self.add_power_pin(name="gnd",
|
||||||
loc = inst.get_pin("gnd").center(),
|
loc=gnd_pin.center(),
|
||||||
start_layer="m2",
|
start_layer=gnd_pin.layer,
|
||||||
vertical=True)
|
vertical=True)
|
||||||
|
|
||||||
|
vdd_pin = inst.get_pin("vdd")
|
||||||
self.add_power_pin(name="vdd",
|
self.add_power_pin(name="vdd",
|
||||||
loc = inst.get_pin("vdd").center(),
|
loc=vdd_pin.center(),
|
||||||
start_layer="m2",
|
start_layer=vdd_pin.layer,
|
||||||
vertical=True)
|
vertical=True)
|
||||||
|
|
||||||
bl_pin = inst.get_pin(inst.mod.get_bl_names())
|
bl_pin = inst.get_pin(inst.mod.get_bl_names())
|
||||||
|
|
@ -162,31 +164,31 @@ class sense_amp_array(design.design):
|
||||||
dout_pin = inst.get_pin(inst.mod.dout_name)
|
dout_pin = inst.get_pin(inst.mod.dout_name)
|
||||||
|
|
||||||
self.add_layout_pin(text=self.get_bl_name() + "_{0}".format(i),
|
self.add_layout_pin(text=self.get_bl_name() + "_{0}".format(i),
|
||||||
layer="m2",
|
layer=bl_pin.layer,
|
||||||
offset=bl_pin.ll(),
|
offset=bl_pin.ll(),
|
||||||
width=bl_pin.width(),
|
width=bl_pin.width(),
|
||||||
height=bl_pin.height())
|
height=bl_pin.height())
|
||||||
self.add_layout_pin(text=self.get_br_name() + "_{0}".format(i),
|
self.add_layout_pin(text=self.get_br_name() + "_{0}".format(i),
|
||||||
layer="m2",
|
layer=br_pin.layer,
|
||||||
offset=br_pin.ll(),
|
offset=br_pin.ll(),
|
||||||
width=br_pin.width(),
|
width=br_pin.width(),
|
||||||
height=br_pin.height())
|
height=br_pin.height())
|
||||||
|
|
||||||
self.add_layout_pin(text=self.data_name + "_{0}".format(i),
|
self.add_layout_pin(text=self.data_name + "_{0}".format(i),
|
||||||
layer="m2",
|
layer=dout_pin.layer,
|
||||||
offset=dout_pin.ll(),
|
offset=dout_pin.ll(),
|
||||||
width=dout_pin.width(),
|
width=dout_pin.width(),
|
||||||
height=dout_pin.height())
|
height=dout_pin.height())
|
||||||
|
|
||||||
|
|
||||||
def route_rails(self):
|
def route_rails(self):
|
||||||
# add sclk rail across entire array
|
# add sclk rail across entire array
|
||||||
|
sclk = self.amp.get_pin(self.amp.en_name)
|
||||||
sclk_offset = self.amp.get_pin(self.amp.en_name).ll().scale(0, 1)
|
sclk_offset = self.amp.get_pin(self.amp.en_name).ll().scale(0, 1)
|
||||||
self.add_layout_pin(text=self.en_name,
|
self.add_layout_pin(text=self.en_name,
|
||||||
layer="m1",
|
layer=sclk.layer,
|
||||||
offset=sclk_offset,
|
offset=sclk_offset,
|
||||||
width=self.width,
|
width=self.width,
|
||||||
height=drc("minwidth_m1"))
|
height=drc("minwidth_" + sclk.layer))
|
||||||
|
|
||||||
def input_load(self):
|
def input_load(self):
|
||||||
return self.amp.input_load()
|
return self.amp.input_load()
|
||||||
|
|
@ -194,7 +196,7 @@ class sense_amp_array(design.design):
|
||||||
def get_en_cin(self):
|
def get_en_cin(self):
|
||||||
"""Get the relative capacitance of all the sense amp enable connections in the array"""
|
"""Get the relative capacitance of all the sense amp enable connections in the array"""
|
||||||
sense_amp_en_cin = self.amp.get_en_cin()
|
sense_amp_en_cin = self.amp.get_en_cin()
|
||||||
return sense_amp_en_cin * (self.word_size + self.num_spare_cols)
|
return sense_amp_en_cin * self.word_size
|
||||||
|
|
||||||
def get_drain_cin(self):
|
def get_drain_cin(self):
|
||||||
"""Get the relative capacitance of the drain of the PMOS isolation TX"""
|
"""Get the relative capacitance of the drain of the PMOS isolation TX"""
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,15 @@
|
||||||
# (acting for and on behalf of Oklahoma State University)
|
# (acting for and on behalf of Oklahoma State University)
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
from math import log
|
|
||||||
import design
|
import design
|
||||||
import contact
|
|
||||||
from tech import drc
|
|
||||||
import debug
|
import debug
|
||||||
import math
|
from tech import layer
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
import logical_effort
|
import logical_effort
|
||||||
|
|
||||||
|
|
||||||
class single_level_column_mux_array(design.design):
|
class single_level_column_mux_array(design.design):
|
||||||
"""
|
"""
|
||||||
Dynamically generated column mux array.
|
Dynamically generated column mux array.
|
||||||
|
|
@ -33,6 +31,13 @@ class single_level_column_mux_array(design.design):
|
||||||
self.bitcell_bl = bitcell_bl
|
self.bitcell_bl = bitcell_bl
|
||||||
self.bitcell_br = bitcell_br
|
self.bitcell_br = bitcell_br
|
||||||
|
|
||||||
|
if "li" in layer:
|
||||||
|
self.col_mux_stack = self.li_stack
|
||||||
|
self.col_mux_stack_pitch = self.li_pitch
|
||||||
|
else:
|
||||||
|
self.col_mux_stack = self.m1_stack
|
||||||
|
self.col_mux_stack_pitch = self.m1_pitch
|
||||||
|
|
||||||
self.create_netlist()
|
self.create_netlist()
|
||||||
if not OPTS.netlist_only:
|
if not OPTS.netlist_only:
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
|
|
@ -58,8 +63,8 @@ class single_level_column_mux_array(design.design):
|
||||||
highest = self.find_highest_coords()
|
highest = self.find_highest_coords()
|
||||||
self.height = highest.y
|
self.height = highest.y
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
|
if "pwell" in layer:
|
||||||
self.add_enclosure(self.mux_inst, "pwell")
|
self.add_enclosure(self.mux_inst, "pwell")
|
||||||
|
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
|
|
@ -74,22 +79,18 @@ class single_level_column_mux_array(design.design):
|
||||||
self.add_pin("br_out_{}".format(i))
|
self.add_pin("br_out_{}".format(i))
|
||||||
self.add_pin("gnd")
|
self.add_pin("gnd")
|
||||||
|
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.mux = factory.create(module_type="single_level_column_mux",
|
self.mux = factory.create(module_type="single_level_column_mux",
|
||||||
bitcell_bl=self.bitcell_bl,
|
bitcell_bl=self.bitcell_bl,
|
||||||
bitcell_br=self.bitcell_br)
|
bitcell_br=self.bitcell_br)
|
||||||
self.add_mod(self.mux)
|
self.add_mod(self.mux)
|
||||||
|
|
||||||
|
|
||||||
def setup_layout_constants(self):
|
def setup_layout_constants(self):
|
||||||
self.column_addr_size = num_of_inputs = int(self.words_per_row / 2)
|
self.column_addr_size = int(self.words_per_row / 2)
|
||||||
self.width = self.columns * self.mux.width
|
self.width = self.columns * self.mux.width
|
||||||
# one set of metal1 routes for select signals and a pair to interconnect the mux outputs bl/br
|
# one set of metal1 routes for select signals and a pair to interconnect the mux outputs bl/br
|
||||||
# one extra route pitch is to space from the sense amp
|
# one extra route pitch is to space from the sense amp
|
||||||
self.route_height = (self.words_per_row + 3)*self.m1_pitch
|
self.route_height = (self.words_per_row + 3) * self.col_mux_stack_pitch
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_array(self):
|
def create_array(self):
|
||||||
self.mux_inst = []
|
self.mux_inst = []
|
||||||
|
|
@ -117,32 +118,31 @@ class single_level_column_mux_array(design.design):
|
||||||
else:
|
else:
|
||||||
mirror = ""
|
mirror = ""
|
||||||
|
|
||||||
name = "XMUX{0}".format(col_num)
|
|
||||||
offset = vector(xoffset, self.route_height)
|
offset = vector(xoffset, self.route_height)
|
||||||
self.mux_inst[col_num].place(offset=offset, mirror=mirror)
|
self.mux_inst[col_num].place(offset=offset, mirror=mirror)
|
||||||
|
|
||||||
|
|
||||||
def add_layout_pins(self):
|
def add_layout_pins(self):
|
||||||
""" Add the pins after we determine the height. """
|
""" Add the pins after we determine the height. """
|
||||||
# For every column, add a pass gate
|
# For every column, add a pass gate
|
||||||
for col_num in range(self.columns):
|
for col_num in range(self.columns):
|
||||||
mux_inst = self.mux_inst[col_num]
|
mux_inst = self.mux_inst[col_num]
|
||||||
offset = mux_inst.get_pin("bl").ll()
|
bl_pin = mux_inst.get_pin("bl")
|
||||||
|
offset = bl_pin.ll()
|
||||||
self.add_layout_pin(text="bl_{}".format(col_num),
|
self.add_layout_pin(text="bl_{}".format(col_num),
|
||||||
layer="m2",
|
layer=bl_pin.layer,
|
||||||
offset=offset,
|
offset=offset,
|
||||||
height=self.height - offset.y)
|
height=self.height - offset.y)
|
||||||
|
|
||||||
offset = mux_inst.get_pin("br").ll()
|
br_pin = mux_inst.get_pin("br")
|
||||||
|
offset = br_pin.ll()
|
||||||
self.add_layout_pin(text="br_{}".format(col_num),
|
self.add_layout_pin(text="br_{}".format(col_num),
|
||||||
layer="m2",
|
layer=br_pin.layer,
|
||||||
offset=offset,
|
offset=offset,
|
||||||
height=self.height - offset.y)
|
height=self.height - offset.y)
|
||||||
|
|
||||||
for inst in self.mux_inst:
|
for inst in self.mux_inst:
|
||||||
self.copy_layout_pin(inst, "gnd")
|
self.copy_layout_pin(inst, "gnd")
|
||||||
|
|
||||||
|
|
||||||
def add_routing(self):
|
def add_routing(self):
|
||||||
self.add_horizontal_input_rail()
|
self.add_horizontal_input_rail()
|
||||||
self.add_vertical_poly_rail()
|
self.add_vertical_poly_rail()
|
||||||
|
|
@ -151,9 +151,9 @@ class single_level_column_mux_array(design.design):
|
||||||
def add_horizontal_input_rail(self):
|
def add_horizontal_input_rail(self):
|
||||||
""" Create address input rails on M1 below the mux transistors """
|
""" Create address input rails on M1 below the mux transistors """
|
||||||
for j in range(self.words_per_row):
|
for j in range(self.words_per_row):
|
||||||
offset = vector(0, self.route_height + (j-self.words_per_row)*self.m1_pitch)
|
offset = vector(0, self.route_height + (j - self.words_per_row) * self.col_mux_stack_pitch)
|
||||||
self.add_layout_pin(text="sel_{}".format(j),
|
self.add_layout_pin(text="sel_{}".format(j),
|
||||||
layer="m1",
|
layer=self.col_mux_stack[0],
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=self.mux.width * self.columns)
|
width=self.mux.width * self.columns)
|
||||||
|
|
||||||
|
|
@ -167,11 +167,12 @@ class single_level_column_mux_array(design.design):
|
||||||
# Add the column x offset to find the right select bit
|
# Add the column x offset to find the right select bit
|
||||||
gate_offset = self.mux_inst[col].get_pin("sel").bc()
|
gate_offset = self.mux_inst[col].get_pin("sel").bc()
|
||||||
# height to connect the gate to the correct horizontal row
|
# height to connect the gate to the correct horizontal row
|
||||||
sel_height = self.get_pin("sel_{}".format(sel_index)).by()
|
# sel_height = self.get_pin("sel_{}".format(sel_index)).by()
|
||||||
# use the y offset from the sel pin and the x offset from the gate
|
# use the y offset from the sel pin and the x offset from the gate
|
||||||
offset = vector(gate_offset.x,self.get_pin("sel_{}".format(sel_index)).cy())
|
offset = vector(gate_offset.x,
|
||||||
|
self.get_pin("sel_{}".format(sel_index)).cy())
|
||||||
# Add the poly contact with a shift to account for the rotation
|
# Add the poly contact with a shift to account for the rotation
|
||||||
self.add_via_center(layers=("m1", "contact", "poly"),
|
self.add_via_center(layers=self.poly_stack,
|
||||||
offset=offset)
|
offset=offset)
|
||||||
self.add_path("poly", [offset, gate_offset])
|
self.add_path("poly", [offset, gate_offset])
|
||||||
|
|
||||||
|
|
@ -182,8 +183,8 @@ class single_level_column_mux_array(design.design):
|
||||||
bl_offset = self.mux_inst[j].get_pin("bl_out").bc()
|
bl_offset = self.mux_inst[j].get_pin("bl_out").bc()
|
||||||
br_offset = self.mux_inst[j].get_pin("br_out").bc()
|
br_offset = self.mux_inst[j].get_pin("br_out").bc()
|
||||||
|
|
||||||
bl_out_offset = bl_offset - vector(0,(self.words_per_row+1)*self.m1_pitch)
|
bl_out_offset = bl_offset - vector(0, (self.words_per_row + 1) * self.col_mux_stack_pitch)
|
||||||
br_out_offset = br_offset - vector(0,(self.words_per_row+2)*self.m1_pitch)
|
br_out_offset = br_offset - vector(0, (self.words_per_row + 2) * self.col_mux_stack_pitch)
|
||||||
|
|
||||||
bl_out_offset_end = bl_out_offset + vector(0, self.route_height)
|
bl_out_offset_end = bl_out_offset + vector(0, self.route_height)
|
||||||
br_out_offset_end = br_out_offset + vector(0, self.route_height)
|
br_out_offset_end = br_out_offset + vector(0, self.route_height)
|
||||||
|
|
@ -208,38 +209,36 @@ class single_level_column_mux_array(design.design):
|
||||||
else:
|
else:
|
||||||
dist = 0
|
dist = 0
|
||||||
|
|
||||||
self.add_path("m1", [bl_out_offset, bl_out_offset+vector(width+dist,0)])
|
self.add_path(self.col_mux_stack[0], [bl_out_offset, bl_out_offset + vector(width + dist, 0)])
|
||||||
self.add_path("m1", [br_out_offset, br_out_offset+vector(width-dist,0)])
|
self.add_path(self.col_mux_stack[0], [br_out_offset, br_out_offset + vector(width - dist, 0)])
|
||||||
|
|
||||||
# Extend the bitline output rails and gnd downward on the first bit of each n-way mux
|
# Extend the bitline output rails and gnd downward on the first bit of each n-way mux
|
||||||
self.add_layout_pin_segment_center(text="bl_out_{}".format(int(j / self.words_per_row)),
|
self.add_layout_pin_segment_center(text="bl_out_{}".format(int(j / self.words_per_row)),
|
||||||
layer="m2",
|
layer=self.col_mux_stack[2],
|
||||||
start=bl_out_offset,
|
start=bl_out_offset,
|
||||||
end=tmp_bl_out_end)
|
end=tmp_bl_out_end)
|
||||||
self.add_layout_pin_segment_center(text="br_out_{}".format(int(j / self.words_per_row)),
|
self.add_layout_pin_segment_center(text="br_out_{}".format(int(j / self.words_per_row)),
|
||||||
layer="m2",
|
layer=self.col_mux_stack[2],
|
||||||
start=br_out_offset,
|
start=br_out_offset,
|
||||||
end=tmp_br_out_end)
|
end=tmp_br_out_end)
|
||||||
|
|
||||||
|
|
||||||
# This via is on the right of the wire
|
# This via is on the right of the wire
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.col_mux_stack,
|
||||||
offset=bl_out_offset)
|
offset=bl_out_offset)
|
||||||
|
|
||||||
# This via is on the left of the wire
|
# This via is on the left of the wire
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.col_mux_stack,
|
||||||
offset=br_out_offset)
|
offset=br_out_offset)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
self.add_path(self.col_mux_stack[2], [bl_out_offset, bl_offset])
|
||||||
self.add_path("m2", [ bl_out_offset, tmp_bl_out_end])
|
self.add_path(self.col_mux_stack[2], [br_out_offset, br_offset])
|
||||||
self.add_path("m2", [ br_out_offset, tmp_br_out_end])
|
|
||||||
|
|
||||||
# This via is on the right of the wire
|
# This via is on the right of the wire
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.col_mux_stack,
|
||||||
offset=bl_out_offset)
|
offset=bl_out_offset)
|
||||||
# This via is on the left of the wire
|
# This via is on the left of the wire
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.col_mux_stack,
|
||||||
offset=br_out_offset)
|
offset=br_out_offset)
|
||||||
|
|
||||||
def get_drain_cin(self):
|
def get_drain_cin(self):
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,12 @@
|
||||||
#
|
#
|
||||||
import debug
|
import debug
|
||||||
import design
|
import design
|
||||||
|
import math
|
||||||
import contact
|
import contact
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
from tech import cell_properties
|
||||||
|
|
||||||
|
|
||||||
class wordline_driver(design.design):
|
class wordline_driver(design.design):
|
||||||
|
|
@ -27,6 +29,13 @@ class wordline_driver(design.design):
|
||||||
self.rows = rows
|
self.rows = rows
|
||||||
self.cols = cols
|
self.cols = cols
|
||||||
|
|
||||||
|
b = factory.create(module_type="bitcell")
|
||||||
|
try:
|
||||||
|
self.cell_multiple = cell_properties.bitcell.decoder_bitcell_multiple
|
||||||
|
except AttributeError:
|
||||||
|
self.cell_multiple = 1
|
||||||
|
self.cell_height = self.cell_multiple * b.height
|
||||||
|
|
||||||
self.create_netlist()
|
self.create_netlist()
|
||||||
if not OPTS.netlist_only:
|
if not OPTS.netlist_only:
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
|
|
@ -37,6 +46,7 @@ class wordline_driver(design.design):
|
||||||
self.create_drivers()
|
self.create_drivers()
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
|
self.setup_layout_constants()
|
||||||
self.place_drivers()
|
self.place_drivers()
|
||||||
self.route_layout()
|
self.route_layout()
|
||||||
self.route_vdd_gnd()
|
self.route_vdd_gnd()
|
||||||
|
|
@ -56,17 +66,10 @@ class wordline_driver(design.design):
|
||||||
self.add_pin("gnd", "GROUND")
|
self.add_pin("gnd", "GROUND")
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
b = factory.create(module_type="bitcell")
|
self.and2 = factory.create(module_type="pand2",
|
||||||
|
height=self.cell_height,
|
||||||
self.inv = factory.create(module_type="pdriver",
|
size=self.cols)
|
||||||
fanout=self.cols,
|
self.add_mod(self.and2)
|
||||||
neg_polarity=True,
|
|
||||||
height=b.height)
|
|
||||||
self.add_mod(self.inv)
|
|
||||||
|
|
||||||
self.nand2 = factory.create(module_type="pnand2",
|
|
||||||
height=b.height)
|
|
||||||
self.add_mod(self.nand2)
|
|
||||||
|
|
||||||
def route_vdd_gnd(self):
|
def route_vdd_gnd(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -75,68 +78,64 @@ class wordline_driver(design.design):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Find the x offsets for where the vias/pins should be placed
|
# Find the x offsets for where the vias/pins should be placed
|
||||||
a_xoffset = self.nand_inst[0].lx()
|
xoffset_list = [self.and_inst[0].lx()]
|
||||||
for num in range(self.rows):
|
for num in range(self.rows):
|
||||||
# this will result in duplicate polygons for rails, but who cares
|
# this will result in duplicate polygons for rails, but who cares
|
||||||
|
|
||||||
# use the inverter offset even though it will be the nand's too
|
# use the inverter offset even though it will be the and's too
|
||||||
(gate_offset, y_dir) = self.get_gate_offset(0,
|
(gate_offset, y_dir) = self.get_gate_offset(0,
|
||||||
self.inv.height,
|
self.and2.height,
|
||||||
num)
|
num)
|
||||||
|
|
||||||
# Route both supplies
|
# Route both supplies
|
||||||
for name in ["vdd", "gnd"]:
|
for name in ["vdd", "gnd"]:
|
||||||
supply_pin = self.inv2_inst[num].get_pin(name)
|
supply_pin = self.and_inst[num].get_pin(name)
|
||||||
|
|
||||||
# Add pins in two locations
|
# Add pins in two locations
|
||||||
for xoffset in [a_xoffset]:
|
for xoffset in xoffset_list:
|
||||||
pin_pos = vector(xoffset, supply_pin.cy())
|
pin_pos = vector(xoffset, supply_pin.cy())
|
||||||
self.add_power_pin(name, pin_pos)
|
self.add_power_pin(name, pin_pos)
|
||||||
|
|
||||||
def create_drivers(self):
|
def create_drivers(self):
|
||||||
self.nand_inst = []
|
self.and_inst = []
|
||||||
self.inv2_inst = []
|
|
||||||
for row in range(self.rows):
|
for row in range(self.rows):
|
||||||
name_nand = "wl_driver_nand{}".format(row)
|
name_and = "wl_driver_and{}".format(row)
|
||||||
name_inv2 = "wl_driver_inv{}".format(row)
|
|
||||||
|
|
||||||
# add nand 2
|
# add and2
|
||||||
self.nand_inst.append(self.add_inst(name=name_nand,
|
self.and_inst.append(self.add_inst(name=name_and,
|
||||||
mod=self.nand2))
|
mod=self.and2))
|
||||||
self.connect_inst(["en",
|
self.connect_inst(["en",
|
||||||
"in_{0}".format(row),
|
"in_{0}".format(row),
|
||||||
"wl_bar_{0}".format(row),
|
|
||||||
"vdd", "gnd"])
|
|
||||||
# add inv2
|
|
||||||
self.inv2_inst.append(self.add_inst(name=name_inv2,
|
|
||||||
mod=self.inv))
|
|
||||||
self.connect_inst(["wl_bar_{0}".format(row),
|
|
||||||
"wl_{0}".format(row),
|
"wl_{0}".format(row),
|
||||||
"vdd", "gnd"])
|
"vdd", "gnd"])
|
||||||
|
|
||||||
def place_drivers(self):
|
def setup_layout_constants(self):
|
||||||
nand2_xoffset = 2 * self.m1_width + 5 * self.m1_space
|
# We may have more than one bitcell per decoder row
|
||||||
inv2_xoffset = nand2_xoffset + self.nand2.width
|
self.num_rows = math.ceil(self.rows / self.cell_multiple)
|
||||||
|
# We will place this many final decoders per row
|
||||||
|
self.decoders_per_row = math.ceil(self.rows / self.num_rows)
|
||||||
|
|
||||||
self.width = inv2_xoffset + self.inv.width
|
def place_drivers(self):
|
||||||
self.height = self.inv.height * self.rows
|
and2_xoffset = 2 * self.m1_width + 5 * self.m1_space
|
||||||
|
|
||||||
|
self.width = and2_xoffset + self.and2.width
|
||||||
|
self.height = self.and2.height * self.num_rows
|
||||||
|
|
||||||
for row in range(self.rows):
|
for row in range(self.rows):
|
||||||
|
#row = math.floor(inst_index / self.decoders_per_row)
|
||||||
|
#dec = inst_index % self.decoders_per_row
|
||||||
|
|
||||||
if (row % 2):
|
if (row % 2):
|
||||||
y_offset = self.inv.height * (row + 1)
|
y_offset = self.and2.height * (row + 1)
|
||||||
inst_mirror = "MX"
|
inst_mirror = "MX"
|
||||||
else:
|
else:
|
||||||
y_offset = self.inv.height * row
|
y_offset = self.and2.height * row
|
||||||
inst_mirror = "R0"
|
inst_mirror = "R0"
|
||||||
|
|
||||||
nand2_offset = [nand2_xoffset, y_offset]
|
# x_off = self.internal_routing_width + dec * and_mod.width
|
||||||
inv2_offset = [inv2_xoffset, y_offset]
|
and2_offset = [and2_xoffset, y_offset]
|
||||||
|
|
||||||
# add nand 2
|
# add and2
|
||||||
self.nand_inst[row].place(offset=nand2_offset,
|
self.and_inst[row].place(offset=and2_offset,
|
||||||
mirror=inst_mirror)
|
|
||||||
# add inv2
|
|
||||||
self.inv2_inst[row].place(offset=inv2_offset,
|
|
||||||
mirror=inst_mirror)
|
mirror=inst_mirror)
|
||||||
|
|
||||||
def route_layout(self):
|
def route_layout(self):
|
||||||
|
|
@ -151,11 +150,10 @@ class wordline_driver(design.design):
|
||||||
height=self.height)
|
height=self.height)
|
||||||
|
|
||||||
for row in range(self.rows):
|
for row in range(self.rows):
|
||||||
nand_inst = self.nand_inst[row]
|
and_inst = self.and_inst[row]
|
||||||
inv2_inst = self.inv2_inst[row]
|
|
||||||
|
|
||||||
# en connection
|
# en connection
|
||||||
a_pin = nand_inst.get_pin("A")
|
a_pin = and_inst.get_pin("A")
|
||||||
a_pos = a_pin.lc()
|
a_pos = a_pin.lc()
|
||||||
clk_offset = vector(en_pin.bc().x, a_pos.y)
|
clk_offset = vector(en_pin.bc().x, a_pos.y)
|
||||||
self.add_segment_center(layer="m1",
|
self.add_segment_center(layer="m1",
|
||||||
|
|
@ -164,18 +162,10 @@ class wordline_driver(design.design):
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=clk_offset)
|
offset=clk_offset)
|
||||||
|
|
||||||
# Nand2 out to 2nd inv
|
# connect the decoder input pin to and2 B
|
||||||
zr_pos = nand_inst.get_pin("Z").rc()
|
b_pin = and_inst.get_pin("B")
|
||||||
al_pos = inv2_inst.get_pin("A").lc()
|
|
||||||
# ensure the bend is in the middle
|
|
||||||
mid1_pos = vector(0.5 * (zr_pos.x + al_pos.x), zr_pos.y)
|
|
||||||
mid2_pos = vector(0.5 * (zr_pos.x + al_pos.x), al_pos.y)
|
|
||||||
self.add_path("m1", [zr_pos, mid1_pos, mid2_pos, al_pos])
|
|
||||||
|
|
||||||
# connect the decoder input pin to nand2 B
|
|
||||||
b_pin = nand_inst.get_pin("B")
|
|
||||||
b_pos = b_pin.lc()
|
b_pos = b_pin.lc()
|
||||||
# needs to move down since B nand input is
|
# needs to move down since B and input is
|
||||||
# nearly aligned with A inv input
|
# nearly aligned with A inv input
|
||||||
up_or_down = self.m2_space if row % 2 else -self.m2_space
|
up_or_down = self.m2_space if row % 2 else -self.m2_space
|
||||||
input_offset = vector(0, b_pos.y + up_or_down)
|
input_offset = vector(0, b_pos.y + up_or_down)
|
||||||
|
|
@ -192,7 +182,7 @@ class wordline_driver(design.design):
|
||||||
offset=mid_via_offset,
|
offset=mid_via_offset,
|
||||||
directions=("V", "V"))
|
directions=("V", "V"))
|
||||||
|
|
||||||
# now connect to the nand2 B
|
# now connect to the and2 B
|
||||||
self.add_path("m2", [mid_via_offset, b_pos])
|
self.add_path("m2", [mid_via_offset, b_pos])
|
||||||
contact_offset = b_pos - vector(0.5 * contact.m1_via.height, 0)
|
contact_offset = b_pos - vector(0.5 * contact.m1_via.height, 0)
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
|
|
@ -200,7 +190,7 @@ class wordline_driver(design.design):
|
||||||
directions=("H", "H"))
|
directions=("H", "H"))
|
||||||
|
|
||||||
# output each WL on the right
|
# output each WL on the right
|
||||||
wl_offset = inv2_inst.get_pin("Z").rc()
|
wl_offset = and_inst.get_pin("Z").rc()
|
||||||
self.add_layout_pin_segment_center(text="wl_{0}".format(row),
|
self.add_layout_pin_segment_center(text="wl_{0}".format(row),
|
||||||
layer="m1",
|
layer="m1",
|
||||||
start=wl_offset,
|
start=wl_offset,
|
||||||
|
|
@ -213,13 +203,8 @@ class wordline_driver(design.design):
|
||||||
"""
|
"""
|
||||||
stage_effort_list = []
|
stage_effort_list = []
|
||||||
|
|
||||||
stage1_cout = self.inv.get_cin()
|
stage1 = self.and2.get_stage_effort(external_cout, inp_is_rise)
|
||||||
stage1 = self.nand2.get_stage_effort(stage1_cout, inp_is_rise)
|
|
||||||
stage_effort_list.append(stage1)
|
stage_effort_list.append(stage1)
|
||||||
last_stage_is_rise = stage1.is_rise
|
|
||||||
|
|
||||||
stage2 = self.inv.get_stage_efforts(external_cout, last_stage_is_rise)
|
|
||||||
stage_effort_list.extend(stage2)
|
|
||||||
|
|
||||||
return stage_effort_list
|
return stage_effort_list
|
||||||
|
|
||||||
|
|
@ -228,6 +213,6 @@ class wordline_driver(design.design):
|
||||||
Get the relative capacitance of all
|
Get the relative capacitance of all
|
||||||
the enable connections in the bank
|
the enable connections in the bank
|
||||||
"""
|
"""
|
||||||
# The enable is connected to a nand2 for every row.
|
# The enable is connected to a and2 for every row.
|
||||||
total_cin = self.nand2.get_cin() * self.rows
|
total_cin = self.and2.get_cin() * self.rows
|
||||||
return total_cin
|
return total_cin
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,13 @@
|
||||||
# (acting for and on behalf of Oklahoma State University)
|
# (acting for and on behalf of Oklahoma State University)
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
from math import log
|
|
||||||
import design
|
import design
|
||||||
from tech import drc
|
|
||||||
import debug
|
import debug
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
|
||||||
|
|
||||||
class write_driver_array(design.design):
|
class write_driver_array(design.design):
|
||||||
"""
|
"""
|
||||||
Array of tristate drivers to write to the bitlines through the column mux.
|
Array of tristate drivers to write to the bitlines through the column mux.
|
||||||
|
|
@ -182,26 +181,25 @@ class write_driver_array(design.design):
|
||||||
base = vector(xoffset, 0)
|
base = vector(xoffset, 0)
|
||||||
self.driver_insts[index].place(offset=base, mirror=mirror)
|
self.driver_insts[index].place(offset=base, mirror=mirror)
|
||||||
|
|
||||||
|
|
||||||
def add_layout_pins(self):
|
def add_layout_pins(self):
|
||||||
for i in range(self.word_size + self.num_spare_cols):
|
for i in range(self.word_size + self.num_spare_cols):
|
||||||
inst = self.driver_insts[i]
|
inst = self.driver_insts[i]
|
||||||
din_pin = inst.get_pin(inst.mod.din_name)
|
din_pin = inst.get_pin(inst.mod.din_name)
|
||||||
self.add_layout_pin(text=self.data_name + "_{0}".format(i),
|
self.add_layout_pin(text=self.data_name + "_{0}".format(i),
|
||||||
layer="m2",
|
layer=din_pin.layer,
|
||||||
offset=din_pin.ll(),
|
offset=din_pin.ll(),
|
||||||
width=din_pin.width(),
|
width=din_pin.width(),
|
||||||
height=din_pin.height())
|
height=din_pin.height())
|
||||||
bl_pin = inst.get_pin(inst.mod.get_bl_names())
|
bl_pin = inst.get_pin(inst.mod.get_bl_names())
|
||||||
self.add_layout_pin(text=self.get_bl_name() + "_{0}".format(i),
|
self.add_layout_pin(text=self.get_bl_name() + "_{0}".format(i),
|
||||||
layer="m2",
|
layer=bl_pin.layer,
|
||||||
offset=bl_pin.ll(),
|
offset=bl_pin.ll(),
|
||||||
width=bl_pin.width(),
|
width=bl_pin.width(),
|
||||||
height=bl_pin.height())
|
height=bl_pin.height())
|
||||||
|
|
||||||
br_pin = inst.get_pin(inst.mod.get_br_names())
|
br_pin = inst.get_pin(inst.mod.get_br_names())
|
||||||
self.add_layout_pin(text=self.get_br_name() + "_{0}".format(i),
|
self.add_layout_pin(text=self.get_br_name() + "_{0}".format(i),
|
||||||
layer="m2",
|
layer=br_pin.layer,
|
||||||
offset=br_pin.ll(),
|
offset=br_pin.ll(),
|
||||||
width=br_pin.width(),
|
width=br_pin.width(),
|
||||||
height=br_pin.height())
|
height=br_pin.height())
|
||||||
|
|
@ -212,7 +210,7 @@ class write_driver_array(design.design):
|
||||||
self.add_power_pin(name=n,
|
self.add_power_pin(name=n,
|
||||||
loc=pin.center(),
|
loc=pin.center(),
|
||||||
vertical=True,
|
vertical=True,
|
||||||
start_layer = "m2")
|
start_layer=pin.layer)
|
||||||
if self.write_size:
|
if self.write_size:
|
||||||
for bit in range(self.num_wmasks):
|
for bit in range(self.num_wmasks):
|
||||||
inst = self.driver_insts[bit * self.write_size]
|
inst = self.driver_insts[bit * self.write_size]
|
||||||
|
|
@ -253,7 +251,6 @@ class write_driver_array(design.design):
|
||||||
offset=inst.get_pin(inst.mod.en_name).ll().scale(0, 1),
|
offset=inst.get_pin(inst.mod.en_name).ll().scale(0, 1),
|
||||||
width=self.width)
|
width=self.width)
|
||||||
|
|
||||||
|
|
||||||
def get_w_en_cin(self):
|
def get_w_en_cin(self):
|
||||||
"""Get the relative capacitance of all the enable connections in the bank"""
|
"""Get the relative capacitance of all the enable connections in the bank"""
|
||||||
# The enable is connected to a nand2 for every row.
|
# The enable is connected to a nand2 for every row.
|
||||||
|
|
|
||||||
|
|
@ -30,13 +30,12 @@ class pand2(pgate.pgate):
|
||||||
self.create_insts()
|
self.create_insts()
|
||||||
|
|
||||||
def create_modules(self):
|
def create_modules(self):
|
||||||
# Shield the cap, but have at least a stage effort of 4
|
|
||||||
self.nand = factory.create(module_type="pnand2", height=self.height)
|
self.nand = factory.create(module_type="pnand2", height=self.height)
|
||||||
self.add_mod(self.nand)
|
self.add_mod(self.nand)
|
||||||
|
|
||||||
self.inv = factory.create(module_type="pdriver",
|
self.inv = factory.create(module_type="pdriver",
|
||||||
neg_polarity=True,
|
neg_polarity=True,
|
||||||
fanout=3*self.size,
|
fanout=self.size,
|
||||||
height=self.height)
|
height=self.height)
|
||||||
self.add_mod(self.inv)
|
self.add_mod(self.inv)
|
||||||
|
|
||||||
|
|
@ -45,6 +44,7 @@ class pand2(pgate.pgate):
|
||||||
self.place_insts()
|
self.place_insts()
|
||||||
self.add_wires()
|
self.add_wires()
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
|
self.add_boundary()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ class pand3(pgate.pgate):
|
||||||
self.place_insts()
|
self.place_insts()
|
||||||
self.add_wires()
|
self.add_wires()
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
|
self.add_boundary()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ class pbuf(pgate.pgate):
|
||||||
self.place_insts()
|
self.place_insts()
|
||||||
self.add_wires()
|
self.add_wires()
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
|
self.add_boundary()
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
self.add_pin("A", "INPUT")
|
self.add_pin("A", "INPUT")
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ class pdriver(pgate.pgate):
|
||||||
|
|
||||||
self.width = self.inv_inst_list[-1].rx()
|
self.width = self.inv_inst_list[-1].rx()
|
||||||
self.height = self.inv_inst_list[0].height
|
self.height = self.inv_inst_list[0].height
|
||||||
|
self.add_boundary()
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
self.add_pin("A", "INPUT")
|
self.add_pin("A", "INPUT")
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,14 @@
|
||||||
import contact
|
import contact
|
||||||
import design
|
import design
|
||||||
import debug
|
import debug
|
||||||
from tech import layer
|
import math
|
||||||
|
from bisect import bisect_left
|
||||||
|
from tech import layer, drc
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
|
||||||
|
if(OPTS.tech_name == "s8"):
|
||||||
|
from tech import nmos_bins, pmos_bins, accuracy_requirement
|
||||||
|
|
||||||
class pgate(design.design):
|
class pgate(design.design):
|
||||||
"""
|
"""
|
||||||
|
|
@ -107,7 +111,11 @@ class pgate(design.design):
|
||||||
else:
|
else:
|
||||||
debug.error("Invalid contact placement option.", -1)
|
debug.error("Invalid contact placement option.", -1)
|
||||||
|
|
||||||
v=self.add_via_center(layers=self.poly_stack,
|
if hasattr(self, "li_stack"):
|
||||||
|
self.add_via_center(layers=self.li_stack,
|
||||||
|
offset=contact_offset)
|
||||||
|
|
||||||
|
self.add_via_center(layers=self.poly_stack,
|
||||||
offset=contact_offset)
|
offset=contact_offset)
|
||||||
|
|
||||||
self.add_layout_pin_rect_center(text=name,
|
self.add_layout_pin_rect_center(text=name,
|
||||||
|
|
@ -187,6 +195,10 @@ class pgate(design.design):
|
||||||
offset=contact_offset,
|
offset=contact_offset,
|
||||||
implant_type="n",
|
implant_type="n",
|
||||||
well_type="n")
|
well_type="n")
|
||||||
|
if hasattr(self, "li_stack"):
|
||||||
|
self.add_via_center(layers=self.li_stack,
|
||||||
|
offset=contact_offset)
|
||||||
|
|
||||||
self.add_rect_center(layer="m1",
|
self.add_rect_center(layer="m1",
|
||||||
offset=contact_offset + vector(0, 0.5 * (self.height - contact_offset.y)),
|
offset=contact_offset + vector(0, 0.5 * (self.height - contact_offset.y)),
|
||||||
width=self.nwell_contact.mod.second_layer_width,
|
width=self.nwell_contact.mod.second_layer_width,
|
||||||
|
|
@ -221,8 +233,6 @@ class pgate(design.design):
|
||||||
|
|
||||||
layer_stack = self.active_stack
|
layer_stack = self.active_stack
|
||||||
|
|
||||||
pwell_position = vector(0, -0.5 * self.m1_width)
|
|
||||||
|
|
||||||
# To the right a spacing away from the nmos right active edge
|
# To the right a spacing away from the nmos right active edge
|
||||||
contact_xoffset = nmos_pos.x + nmos.active_width \
|
contact_xoffset = nmos_pos.x + nmos.active_width \
|
||||||
+ self.active_space
|
+ self.active_space
|
||||||
|
|
@ -240,6 +250,11 @@ class pgate(design.design):
|
||||||
offset=contact_offset,
|
offset=contact_offset,
|
||||||
implant_type="p",
|
implant_type="p",
|
||||||
well_type="p")
|
well_type="p")
|
||||||
|
|
||||||
|
if hasattr(self, "li_stack"):
|
||||||
|
self.add_via_center(layers=self.li_stack,
|
||||||
|
offset=contact_offset)
|
||||||
|
|
||||||
self.add_rect_center(layer="m1",
|
self.add_rect_center(layer="m1",
|
||||||
offset=contact_offset.scale(1, 0.5),
|
offset=contact_offset.scale(1, 0.5),
|
||||||
width=self.pwell_contact.mod.second_layer_width,
|
width=self.pwell_contact.mod.second_layer_width,
|
||||||
|
|
@ -272,4 +287,60 @@ class pgate(design.design):
|
||||||
self.well_width = self.width + 2 * self.nwell_enclose_active
|
self.well_width = self.width + 2 * self.nwell_enclose_active
|
||||||
# Height is an input parameter, so it is not recomputed.
|
# Height is an input parameter, so it is not recomputed.
|
||||||
|
|
||||||
|
def bin_width(self, tx_type, target_width):
|
||||||
|
|
||||||
|
if tx_type == "nmos":
|
||||||
|
bins = nmos_bins[drc("minwidth_poly")]
|
||||||
|
elif tx_type == "pmos":
|
||||||
|
bins = pmos_bins[drc("minwidth_poly")]
|
||||||
|
else:
|
||||||
|
debug.error("invalid tx type")
|
||||||
|
|
||||||
|
bins = bins[0:bisect_left(bins, target_width) + 1]
|
||||||
|
if len(bins) == 1:
|
||||||
|
selected_bin = bins[0]
|
||||||
|
scaling_factor = math.ceil(target_width / selected_bin)
|
||||||
|
scaled_bin = bins[0] * scaling_factor
|
||||||
|
|
||||||
|
else:
|
||||||
|
scaled_bins = []
|
||||||
|
scaling_factors = []
|
||||||
|
scaled_bins.append(bins[-1])
|
||||||
|
scaling_factors.append(1)
|
||||||
|
for width in bins[0:-1]:
|
||||||
|
m = math.ceil(target_width / width)
|
||||||
|
scaling_factors.append(m)
|
||||||
|
scaled_bins.append(m * width)
|
||||||
|
|
||||||
|
select = bisect_left(scaled_bins, target_width)
|
||||||
|
scaling_factor = scaling_factors[select]
|
||||||
|
scaled_bin = scaled_bins[select]
|
||||||
|
select = (select + 1) % len(scaled_bins)
|
||||||
|
selected_bin = bins[select]
|
||||||
|
|
||||||
|
debug.info(2, "binning {0} tx, target: {4}, found {1} x {2} = {3}".format(tx_type, selected_bin, scaling_factor, scaled_bin, target_width))
|
||||||
|
|
||||||
|
return(selected_bin, scaling_factor)
|
||||||
|
|
||||||
|
def permute_widths(self, tx_type, target_width):
|
||||||
|
|
||||||
|
if tx_type == "nmos":
|
||||||
|
bins = nmos_bins[drc("minwidth_poly")]
|
||||||
|
elif tx_type == "pmos":
|
||||||
|
bins = pmos_bins[drc("minwidth_poly")]
|
||||||
|
else:
|
||||||
|
debug.error("invalid tx type")
|
||||||
|
bins = bins[0:bisect_left(bins, target_width) + 1]
|
||||||
|
if len(bins) == 1:
|
||||||
|
scaled_bins = [(bins[0], math.ceil(target_width / bins[0]))]
|
||||||
|
else:
|
||||||
|
scaled_bins = []
|
||||||
|
scaled_bins.append((bins[-1], 1))
|
||||||
|
for width in bins[:-1]:
|
||||||
|
m = math.ceil(target_width / width)
|
||||||
|
scaled_bins.append((m * width, m))
|
||||||
|
|
||||||
|
return(scaled_bins)
|
||||||
|
|
||||||
|
def bin_accuracy(self, ideal_width, width):
|
||||||
|
return abs(1-(ideal_width - width)/ideal_width)
|
||||||
|
|
@ -8,14 +8,19 @@
|
||||||
import contact
|
import contact
|
||||||
import pgate
|
import pgate
|
||||||
import debug
|
import debug
|
||||||
|
import operator
|
||||||
from tech import drc, parameter, spice
|
from tech import drc, parameter, spice
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from math import ceil
|
from math import ceil
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from utils import round_to_grid
|
from utils import round_to_grid
|
||||||
|
from bisect import bisect_left
|
||||||
import logical_effort
|
import logical_effort
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
from errors import drc_error
|
||||||
|
|
||||||
|
if(OPTS.tech_name == "s8"):
|
||||||
|
from tech import nmos_bins, pmos_bins, accuracy_requirement
|
||||||
|
|
||||||
class pinv(pgate.pgate):
|
class pinv(pgate.pgate):
|
||||||
"""
|
"""
|
||||||
|
|
@ -63,6 +68,7 @@ class pinv(pgate.pgate):
|
||||||
"A",
|
"A",
|
||||||
position="farleft")
|
position="farleft")
|
||||||
self.route_outputs()
|
self.route_outputs()
|
||||||
|
self.add_boundary()
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
""" Adds pins for spice netlist """
|
""" Adds pins for spice netlist """
|
||||||
|
|
@ -81,6 +87,9 @@ class pinv(pgate.pgate):
|
||||||
self.tx_mults = 1
|
self.tx_mults = 1
|
||||||
self.nmos_width = self.nmos_size * drc("minwidth_tx")
|
self.nmos_width = self.nmos_size * drc("minwidth_tx")
|
||||||
self.pmos_width = self.pmos_size * drc("minwidth_tx")
|
self.pmos_width = self.pmos_size * drc("minwidth_tx")
|
||||||
|
if OPTS.tech_name == "s8":
|
||||||
|
(self.nmos_width, self.tx_mults) = self.bin_width("nmos", self.nmos_width)
|
||||||
|
(self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Do a quick sanity check and bail if unlikely feasible height
|
# Do a quick sanity check and bail if unlikely feasible height
|
||||||
|
|
@ -105,11 +114,14 @@ class pinv(pgate.pgate):
|
||||||
# This is a poly-to-poly of a flipped cell
|
# This is a poly-to-poly of a flipped cell
|
||||||
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
|
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
|
||||||
self.poly_extend_active + self.poly_space)
|
self.poly_extend_active + self.poly_space)
|
||||||
total_height = tx_height + min_channel + 2 * self.top_bottom_space
|
|
||||||
|
|
||||||
debug.check(self.height > total_height,
|
total_height = tx_height + min_channel + 2 * self.top_bottom_space
|
||||||
"Cell height {0} too small for simple min height {1}.".format(self.height,
|
# debug.check(self.height > total_height,
|
||||||
total_height))
|
# "Cell height {0} too small for simple min height {1}.".format(self.height,
|
||||||
|
# total_height))
|
||||||
|
if total_height > self.height:
|
||||||
|
msg = "Cell height {0} too small for simple min height {1}.".format(self.height, total_height)
|
||||||
|
raise drc_error(msg)
|
||||||
|
|
||||||
# Determine the height left to the transistors to determine
|
# Determine the height left to the transistors to determine
|
||||||
# the number of fingers
|
# the number of fingers
|
||||||
|
|
@ -127,6 +139,7 @@ class pinv(pgate.pgate):
|
||||||
|
|
||||||
# Determine the number of mults for each to fit width
|
# Determine the number of mults for each to fit width
|
||||||
# into available space
|
# into available space
|
||||||
|
if OPTS.tech_name != "s8":
|
||||||
self.nmos_width = self.nmos_size * drc("minwidth_tx")
|
self.nmos_width = self.nmos_size * drc("minwidth_tx")
|
||||||
self.pmos_width = self.pmos_size * drc("minwidth_tx")
|
self.pmos_width = self.pmos_size * drc("minwidth_tx")
|
||||||
nmos_required_mults = max(int(ceil(self.nmos_width / nmos_height_available)), 1)
|
nmos_required_mults = max(int(ceil(self.nmos_width / nmos_height_available)), 1)
|
||||||
|
|
@ -141,12 +154,47 @@ class pinv(pgate.pgate):
|
||||||
# with LVS property mismatch errors when fingers are not a grid
|
# with LVS property mismatch errors when fingers are not a grid
|
||||||
# length and get rounded in the offset geometry.
|
# length and get rounded in the offset geometry.
|
||||||
self.nmos_width = round_to_grid(self.nmos_width / self.tx_mults)
|
self.nmos_width = round_to_grid(self.nmos_width / self.tx_mults)
|
||||||
debug.check(self.nmos_width >= drc("minwidth_tx"),
|
# debug.check(self.nmos_width >= drc("minwidth_tx"),
|
||||||
"Cannot finger NMOS transistors to fit cell height.")
|
# "Cannot finger NMOS transistors to fit cell height.")
|
||||||
self.pmos_width = round_to_grid(self.pmos_width / self.tx_mults)
|
if self.nmos_width < drc("minwidth_tx"):
|
||||||
debug.check(self.pmos_width >= drc("minwidth_tx"),
|
raise drc_error("Cannot finger NMOS transistors to fit cell height.")
|
||||||
"Cannot finger PMOS transistors to fit cell height.")
|
|
||||||
|
|
||||||
|
self.pmos_width = round_to_grid(self.pmos_width / self.tx_mults)
|
||||||
|
#debug.check(self.pmos_width >= drc("minwidth_tx"),
|
||||||
|
# "Cannot finger PMOS transistors to fit cell height.")
|
||||||
|
if self.pmos_width < drc("minwidth_tx"):
|
||||||
|
raise drc_error("Cannot finger NMOS transistors to fit cell height.")
|
||||||
|
else:
|
||||||
|
self.nmos_width = self.nmos_size * drc("minwidth_tx")
|
||||||
|
self.pmos_width = self.pmos_size * drc("minwidth_tx")
|
||||||
|
nmos_bins = self.permute_widths("nmos", self.nmos_width)
|
||||||
|
pmos_bins = self.permute_widths("pmos", self.pmos_width)
|
||||||
|
|
||||||
|
valid_pmos = []
|
||||||
|
for bin in pmos_bins:
|
||||||
|
if self.bin_accuracy(self.pmos_width, bin[0]) > accuracy_requirement:
|
||||||
|
valid_pmos.append(bin)
|
||||||
|
valid_pmos.sort(key = operator.itemgetter(1))
|
||||||
|
|
||||||
|
valid_nmos = []
|
||||||
|
for bin in nmos_bins:
|
||||||
|
if self.bin_accuracy(self.nmos_width, bin[0]) > accuracy_requirement:
|
||||||
|
valid_nmos.append(bin)
|
||||||
|
valid_nmos.sort(key = operator.itemgetter(1))
|
||||||
|
|
||||||
|
for bin in valid_pmos:
|
||||||
|
if bin[0]/bin[1] < pmos_height_available:
|
||||||
|
self.pmos_width = bin[0]/bin[1]
|
||||||
|
pmos_mults = valid_pmos[0][1]
|
||||||
|
break
|
||||||
|
|
||||||
|
for bin in valid_nmos:
|
||||||
|
if bin[0]/bin[1] < nmos_height_available:
|
||||||
|
self.nmos_width = bin[0]/bin[1]
|
||||||
|
nmos_mults = valid_pmos[0][1]
|
||||||
|
break
|
||||||
|
|
||||||
|
self.tx_mults = max(pmos_mults, nmos_mults)
|
||||||
|
|
||||||
def add_ptx(self):
|
def add_ptx(self):
|
||||||
""" Create the PMOS and NMOS transistors. """
|
""" Create the PMOS and NMOS transistors. """
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ class pinvbuf(pgate.pgate):
|
||||||
self.place_modules()
|
self.place_modules()
|
||||||
self.route_wires()
|
self.route_wires()
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
|
self.add_boundary()
|
||||||
|
|
||||||
self.offset_all_coordinates()
|
self.offset_all_coordinates()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import contact
|
||||||
import pgate
|
import pgate
|
||||||
import debug
|
import debug
|
||||||
from tech import drc, parameter, spice
|
from tech import drc, parameter, spice
|
||||||
|
from globals import OPTS
|
||||||
from vector import vector
|
from vector import vector
|
||||||
import logical_effort
|
import logical_effort
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
|
@ -37,6 +38,10 @@ class pnand2(pgate.pgate):
|
||||||
debug.check(size == 1, "Size 1 pnand2 is only supported now.")
|
debug.check(size == 1, "Size 1 pnand2 is only supported now.")
|
||||||
self.tx_mults = 1
|
self.tx_mults = 1
|
||||||
|
|
||||||
|
if OPTS.tech_name == "s8":
|
||||||
|
(self.nmos_width, self.tx_mults) = self.bin_width("nmos", self.nmos_width)
|
||||||
|
(self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width)
|
||||||
|
|
||||||
# Creates the netlist and layout
|
# Creates the netlist and layout
|
||||||
pgate.pgate.__init__(self, name, height)
|
pgate.pgate.__init__(self, name, height)
|
||||||
|
|
||||||
|
|
@ -57,6 +62,7 @@ class pnand2(pgate.pgate):
|
||||||
self.extend_wells()
|
self.extend_wells()
|
||||||
self.route_inputs()
|
self.route_inputs()
|
||||||
self.route_output()
|
self.route_output()
|
||||||
|
self.add_boundary()
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
""" Adds pins for spice netlist """
|
""" Adds pins for spice netlist """
|
||||||
|
|
@ -66,13 +72,23 @@ class pnand2(pgate.pgate):
|
||||||
|
|
||||||
def add_ptx(self):
|
def add_ptx(self):
|
||||||
""" Create the PMOS and NMOS transistors. """
|
""" Create the PMOS and NMOS transistors. """
|
||||||
self.nmos = factory.create(module_type="ptx",
|
self.nmos_nd = factory.create(module_type="ptx",
|
||||||
width=self.nmos_width,
|
width=self.nmos_width,
|
||||||
mults=self.tx_mults,
|
mults=self.tx_mults,
|
||||||
tx_type="nmos",
|
tx_type="nmos",
|
||||||
|
add_drain_contact=False,
|
||||||
connect_poly=True,
|
connect_poly=True,
|
||||||
connect_active=True)
|
connect_active=True)
|
||||||
self.add_mod(self.nmos)
|
self.add_mod(self.nmos_nd)
|
||||||
|
|
||||||
|
self.nmos_ns = factory.create(module_type="ptx",
|
||||||
|
width=self.nmos_width,
|
||||||
|
mults=self.tx_mults,
|
||||||
|
tx_type="nmos",
|
||||||
|
add_source_contact=False,
|
||||||
|
connect_poly=True,
|
||||||
|
connect_active=True)
|
||||||
|
self.add_mod(self.nmos_ns)
|
||||||
|
|
||||||
self.pmos = factory.create(module_type="ptx",
|
self.pmos = factory.create(module_type="ptx",
|
||||||
width=self.pmos_width,
|
width=self.pmos_width,
|
||||||
|
|
@ -99,7 +115,7 @@ class pnand2(pgate.pgate):
|
||||||
|
|
||||||
# This is the extra space needed to ensure DRC rules
|
# This is the extra space needed to ensure DRC rules
|
||||||
# to the active contacts
|
# to the active contacts
|
||||||
extra_contact_space = max(-self.nmos.get_pin("D").by(), 0)
|
extra_contact_space = max(-self.nmos_nd.get_pin("D").by(), 0)
|
||||||
# This is a poly-to-poly of a flipped cell
|
# This is a poly-to-poly of a flipped cell
|
||||||
self.top_bottom_space = max(0.5 * self.m1_width + self.m1_space + extra_contact_space,
|
self.top_bottom_space = max(0.5 * self.m1_width + self.m1_space + extra_contact_space,
|
||||||
self.poly_extend_active + self.poly_space)
|
self.poly_extend_active + self.poly_space)
|
||||||
|
|
@ -130,11 +146,11 @@ class pnand2(pgate.pgate):
|
||||||
self.connect_inst(["Z", "B", "vdd", "vdd"])
|
self.connect_inst(["Z", "B", "vdd", "vdd"])
|
||||||
|
|
||||||
self.nmos1_inst = self.add_inst(name="pnand2_nmos1",
|
self.nmos1_inst = self.add_inst(name="pnand2_nmos1",
|
||||||
mod=self.nmos)
|
mod=self.nmos_nd)
|
||||||
self.connect_inst(["Z", "B", "net1", "gnd"])
|
self.connect_inst(["Z", "B", "net1", "gnd"])
|
||||||
|
|
||||||
self.nmos2_inst = self.add_inst(name="pnand2_nmos2",
|
self.nmos2_inst = self.add_inst(name="pnand2_nmos2",
|
||||||
mod=self.nmos)
|
mod=self.nmos_ns)
|
||||||
self.connect_inst(["net1", "A", "gnd", "gnd"])
|
self.connect_inst(["net1", "A", "gnd", "gnd"])
|
||||||
|
|
||||||
def place_ptx(self):
|
def place_ptx(self):
|
||||||
|
|
@ -160,7 +176,7 @@ class pnand2(pgate.pgate):
|
||||||
|
|
||||||
# Output position will be in between the PMOS and NMOS
|
# Output position will be in between the PMOS and NMOS
|
||||||
self.output_pos = vector(0,
|
self.output_pos = vector(0,
|
||||||
0.5 * (pmos1_pos.y + nmos1_pos.y + self.nmos.active_height))
|
0.5 * (pmos1_pos.y + nmos1_pos.y + self.nmos_nd.active_height))
|
||||||
|
|
||||||
def add_well_contacts(self):
|
def add_well_contacts(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -168,8 +184,10 @@ class pnand2(pgate.pgate):
|
||||||
AFTER the wells are created
|
AFTER the wells are created
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.add_nwell_contact(self.pmos, self.pmos2_pos)
|
self.add_nwell_contact(self.pmos,
|
||||||
self.add_pwell_contact(self.nmos, self.nmos2_pos)
|
self.pmos2_pos + vector(self.m1_pitch, 0))
|
||||||
|
self.add_pwell_contact(self.nmos_nd,
|
||||||
|
self.nmos2_pos + vector(self.m1_pitch, 0))
|
||||||
|
|
||||||
def connect_rails(self):
|
def connect_rails(self):
|
||||||
""" Connect the nmos and pmos to its respective power rails """
|
""" Connect the nmos and pmos to its respective power rails """
|
||||||
|
|
@ -187,7 +205,7 @@ class pnand2(pgate.pgate):
|
||||||
self.nmos2_inst,
|
self.nmos2_inst,
|
||||||
inputB_yoffset,
|
inputB_yoffset,
|
||||||
"B",
|
"B",
|
||||||
position="right")
|
position="center")
|
||||||
|
|
||||||
# This will help with the wells and the input/output placement
|
# This will help with the wells and the input/output placement
|
||||||
self.inputA_yoffset = self.pmos2_inst.by() - self.poly_extend_active \
|
self.inputA_yoffset = self.pmos2_inst.by() - self.poly_extend_active \
|
||||||
|
|
@ -199,6 +217,7 @@ class pnand2(pgate.pgate):
|
||||||
|
|
||||||
def route_output(self):
|
def route_output(self):
|
||||||
""" Route the Z output """
|
""" Route the Z output """
|
||||||
|
|
||||||
# PMOS1 drain
|
# PMOS1 drain
|
||||||
pmos_pin = self.pmos1_inst.get_pin("D")
|
pmos_pin = self.pmos1_inst.get_pin("D")
|
||||||
top_pin_offset = pmos_pin.center()
|
top_pin_offset = pmos_pin.center()
|
||||||
|
|
@ -207,28 +226,45 @@ class pnand2(pgate.pgate):
|
||||||
bottom_pin_offset = nmos_pin.center()
|
bottom_pin_offset = nmos_pin.center()
|
||||||
|
|
||||||
# Output pin
|
# Output pin
|
||||||
out_offset = vector(nmos_pin.center().x + self.m1_pitch,
|
c_pin = self.get_pin("B")
|
||||||
|
out_offset = vector(c_pin.cx() + self.m1_pitch,
|
||||||
self.inputA_yoffset)
|
self.inputA_yoffset)
|
||||||
|
|
||||||
# Midpoints of the L routes go horizontal first then vertical
|
# This routes on M2
|
||||||
mid1_offset = vector(out_offset.x, top_pin_offset.y)
|
# # Midpoints of the L routes go horizontal first then vertical
|
||||||
|
# mid1_offset = vector(out_offset.x, top_pin_offset.y)
|
||||||
|
# mid2_offset = vector(out_offset.x, bottom_pin_offset.y)
|
||||||
|
|
||||||
|
# # Non-preferred active contacts
|
||||||
|
# self.add_via_center(layers=self.m1_stack,
|
||||||
|
# directions=("V", "H"),
|
||||||
|
# offset=pmos_pin.center())
|
||||||
|
# # Non-preferred active contacts
|
||||||
|
# self.add_via_center(layers=self.m1_stack,
|
||||||
|
# directions=("V", "H"),
|
||||||
|
# offset=nmos_pin.center())
|
||||||
|
# self.add_via_center(layers=self.m1_stack,
|
||||||
|
# offset=out_offset)
|
||||||
|
|
||||||
|
# # PMOS1 to mid-drain to NMOS2 drain
|
||||||
|
# self.add_path("m2",
|
||||||
|
# [top_pin_offset, mid1_offset, out_offset,
|
||||||
|
# mid2_offset, bottom_pin_offset])
|
||||||
|
|
||||||
|
# This routes on M1
|
||||||
|
# Midpoints of the L routes goes vertical first then horizontal
|
||||||
|
mid1_offset = vector(top_pin_offset.x, out_offset.y)
|
||||||
|
# Midpoints of the L routes goes horizontal first then vertical
|
||||||
mid2_offset = vector(out_offset.x, bottom_pin_offset.y)
|
mid2_offset = vector(out_offset.x, bottom_pin_offset.y)
|
||||||
|
|
||||||
# Non-preferred active contacts
|
self.add_path("m1",
|
||||||
self.add_via_center(layers=self.m1_stack,
|
[top_pin_offset, mid1_offset, out_offset])
|
||||||
directions=("V", "H"),
|
# Route in two segments to have the width rule
|
||||||
offset=pmos_pin.center())
|
self.add_path("m1",
|
||||||
# Non-preferred active contacts
|
[bottom_pin_offset, mid2_offset + vector(0.5 * self.m1_width, 0)],
|
||||||
self.add_via_center(layers=self.m1_stack,
|
width=nmos_pin.height())
|
||||||
directions=("V", "H"),
|
self.add_path("m1",
|
||||||
offset=nmos_pin.center())
|
[mid2_offset, out_offset])
|
||||||
self.add_via_center(layers=self.m1_stack,
|
|
||||||
offset=out_offset)
|
|
||||||
|
|
||||||
# PMOS1 to mid-drain to NMOS2 drain
|
|
||||||
self.add_path("m2",
|
|
||||||
[top_pin_offset, mid1_offset, out_offset,
|
|
||||||
mid2_offset, bottom_pin_offset])
|
|
||||||
|
|
||||||
# This extends the output to the edge of the cell
|
# This extends the output to the edge of the cell
|
||||||
self.add_layout_pin_rect_center(text="Z",
|
self.add_layout_pin_rect_center(text="Z",
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ from tech import drc, parameter, spice
|
||||||
from vector import vector
|
from vector import vector
|
||||||
import logical_effort
|
import logical_effort
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
from globals import OPTS
|
||||||
|
|
||||||
class pnand3(pgate.pgate):
|
class pnand3(pgate.pgate):
|
||||||
"""
|
"""
|
||||||
|
|
@ -40,6 +40,10 @@ class pnand3(pgate.pgate):
|
||||||
"Size 1 pnand3 is only supported now.")
|
"Size 1 pnand3 is only supported now.")
|
||||||
self.tx_mults = 1
|
self.tx_mults = 1
|
||||||
|
|
||||||
|
if OPTS.tech_name == "s8":
|
||||||
|
(self.nmos_width, self.tx_mults) = self.bin_width("nmos", self.nmos_width)
|
||||||
|
(self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width)
|
||||||
|
|
||||||
# Creates the netlist and layout
|
# Creates the netlist and layout
|
||||||
pgate.pgate.__init__(self, name, height)
|
pgate.pgate.__init__(self, name, height)
|
||||||
|
|
||||||
|
|
@ -66,16 +70,37 @@ class pnand3(pgate.pgate):
|
||||||
self.extend_wells()
|
self.extend_wells()
|
||||||
self.route_inputs()
|
self.route_inputs()
|
||||||
self.route_output()
|
self.route_output()
|
||||||
|
self.add_boundary()
|
||||||
|
|
||||||
def add_ptx(self):
|
def add_ptx(self):
|
||||||
""" Create the PMOS and NMOS transistors. """
|
""" Create the PMOS and NMOS transistors. """
|
||||||
self.nmos = factory.create(module_type="ptx",
|
self.nmos_nsnd = factory.create(module_type="ptx",
|
||||||
width=self.nmos_width,
|
width=self.nmos_width,
|
||||||
mults=self.tx_mults,
|
mults=self.tx_mults,
|
||||||
tx_type="nmos",
|
tx_type="nmos",
|
||||||
|
add_source_contact=False,
|
||||||
|
add_drain_contact=False,
|
||||||
connect_poly=True,
|
connect_poly=True,
|
||||||
connect_active=True)
|
connect_active=True)
|
||||||
self.add_mod(self.nmos)
|
self.add_mod(self.nmos_nsnd)
|
||||||
|
|
||||||
|
self.nmos_ns = factory.create(module_type="ptx",
|
||||||
|
width=self.nmos_width,
|
||||||
|
mults=self.tx_mults,
|
||||||
|
tx_type="nmos",
|
||||||
|
add_source_contact=False,
|
||||||
|
connect_poly=True,
|
||||||
|
connect_active=True)
|
||||||
|
self.add_mod(self.nmos_ns)
|
||||||
|
|
||||||
|
self.nmos_nd = factory.create(module_type="ptx",
|
||||||
|
width=self.nmos_width,
|
||||||
|
mults=self.tx_mults,
|
||||||
|
tx_type="nmos",
|
||||||
|
add_drain_contact=False,
|
||||||
|
connect_poly=True,
|
||||||
|
connect_active=True)
|
||||||
|
self.add_mod(self.nmos_nd)
|
||||||
|
|
||||||
self.pmos = factory.create(module_type="ptx",
|
self.pmos = factory.create(module_type="ptx",
|
||||||
width=self.pmos_width,
|
width=self.pmos_width,
|
||||||
|
|
@ -130,15 +155,15 @@ class pnand3(pgate.pgate):
|
||||||
self.connect_inst(["Z", "C", "vdd", "vdd"])
|
self.connect_inst(["Z", "C", "vdd", "vdd"])
|
||||||
|
|
||||||
self.nmos1_inst = self.add_inst(name="pnand3_nmos1",
|
self.nmos1_inst = self.add_inst(name="pnand3_nmos1",
|
||||||
mod=self.nmos)
|
mod=self.nmos_nd)
|
||||||
self.connect_inst(["Z", "C", "net1", "gnd"])
|
self.connect_inst(["Z", "C", "net1", "gnd"])
|
||||||
|
|
||||||
self.nmos2_inst = self.add_inst(name="pnand3_nmos2",
|
self.nmos2_inst = self.add_inst(name="pnand3_nmos2",
|
||||||
mod=self.nmos)
|
mod=self.nmos_nsnd)
|
||||||
self.connect_inst(["net1", "B", "net2", "gnd"])
|
self.connect_inst(["net1", "B", "net2", "gnd"])
|
||||||
|
|
||||||
self.nmos3_inst = self.add_inst(name="pnand3_nmos3",
|
self.nmos3_inst = self.add_inst(name="pnand3_nmos3",
|
||||||
mod=self.nmos)
|
mod=self.nmos_ns)
|
||||||
self.connect_inst(["net2", "A", "gnd", "gnd"])
|
self.connect_inst(["net2", "A", "gnd", "gnd"])
|
||||||
|
|
||||||
def place_ptx(self):
|
def place_ptx(self):
|
||||||
|
|
@ -170,8 +195,10 @@ class pnand3(pgate.pgate):
|
||||||
def add_well_contacts(self):
|
def add_well_contacts(self):
|
||||||
""" Add n/p well taps to the layout and connect to supplies """
|
""" Add n/p well taps to the layout and connect to supplies """
|
||||||
|
|
||||||
self.add_nwell_contact(self.pmos, self.pmos3_pos)
|
self.add_nwell_contact(self.pmos,
|
||||||
self.add_pwell_contact(self.nmos, self.nmos3_pos)
|
self.pmos3_pos + vector(self.m1_pitch, 0))
|
||||||
|
self.add_pwell_contact(self.nmos_ns,
|
||||||
|
self.nmos3_pos + vector(self.m1_pitch, 0))
|
||||||
|
|
||||||
def connect_rails(self):
|
def connect_rails(self):
|
||||||
""" Connect the nmos and pmos to its respective power rails """
|
""" Connect the nmos and pmos to its respective power rails """
|
||||||
|
|
@ -194,22 +221,28 @@ class pnand3(pgate.pgate):
|
||||||
"B",
|
"B",
|
||||||
position="center")
|
position="center")
|
||||||
|
|
||||||
self.inputC_yoffset = self.inputB_yoffset - m1_pitch
|
# FIXME: constant hack
|
||||||
|
self.inputC_yoffset = self.inputB_yoffset - 1.15 * m1_pitch
|
||||||
self.route_input_gate(self.pmos3_inst,
|
self.route_input_gate(self.pmos3_inst,
|
||||||
self.nmos3_inst,
|
self.nmos3_inst,
|
||||||
self.inputC_yoffset,
|
self.inputC_yoffset,
|
||||||
"C",
|
"C",
|
||||||
position="center")
|
position="right")
|
||||||
|
|
||||||
self.inputA_yoffset = self.inputB_yoffset + m1_pitch
|
# FIXME: constant hack
|
||||||
|
if OPTS.tech_name == "s8":
|
||||||
|
self.inputA_yoffset = self.inputB_yoffset + 1.15 * m1_pitch
|
||||||
|
else:
|
||||||
|
self.inputA_yoffset = self.inputB_yoffset + 1.12 * m1_pitch
|
||||||
self.route_input_gate(self.pmos1_inst,
|
self.route_input_gate(self.pmos1_inst,
|
||||||
self.nmos1_inst,
|
self.nmos1_inst,
|
||||||
self.inputA_yoffset,
|
self.inputA_yoffset,
|
||||||
"A",
|
"A",
|
||||||
position="center")
|
position="left")
|
||||||
|
|
||||||
def route_output(self):
|
def route_output(self):
|
||||||
""" Route the Z output """
|
""" Route the Z output """
|
||||||
|
|
||||||
# PMOS1 drain
|
# PMOS1 drain
|
||||||
pmos1_pin = self.pmos1_inst.get_pin("D")
|
pmos1_pin = self.pmos1_inst.get_pin("D")
|
||||||
# PMOS3 drain
|
# PMOS3 drain
|
||||||
|
|
@ -217,29 +250,56 @@ class pnand3(pgate.pgate):
|
||||||
# NMOS3 drain
|
# NMOS3 drain
|
||||||
nmos3_pin = self.nmos3_inst.get_pin("D")
|
nmos3_pin = self.nmos3_inst.get_pin("D")
|
||||||
|
|
||||||
# Go up to metal2 for ease on all output pins
|
# midpoint for routing
|
||||||
self.add_via_center(layers=self.m1_stack,
|
mid_offset = vector(nmos3_pin.cx() + self.m1_pitch,
|
||||||
offset=pmos1_pin.center(),
|
self.inputA_yoffset)
|
||||||
directions=("V", "V"))
|
|
||||||
self.add_via_center(layers=self.m1_stack,
|
|
||||||
offset=pmos3_pin.center(),
|
|
||||||
directions=("V", "V"))
|
|
||||||
self.add_via_center(layers=self.m1_stack,
|
|
||||||
offset=nmos3_pin.center(),
|
|
||||||
directions=("V", "V"))
|
|
||||||
|
|
||||||
# PMOS3 and NMOS3 are drain aligned
|
# Aligned with the well taps
|
||||||
self.add_path("m2", [pmos3_pin.center(), nmos3_pin.center()])
|
out_offset = vector(self.nwell_contact.cx(),
|
||||||
# Route in the A input track (top track)
|
self.inputA_yoffset)
|
||||||
mid_offset = vector(nmos3_pin.center().x, self.inputA_yoffset)
|
|
||||||
self.add_path("m2", [pmos1_pin.center(), mid_offset, nmos3_pin.uc()])
|
# Go up to metal2 for ease on all output pins
|
||||||
|
# self.add_via_center(layers=self.m1_stack,
|
||||||
|
# offset=pmos1_pin.center(),
|
||||||
|
# directions=("V", "V"))
|
||||||
|
# self.add_via_center(layers=self.m1_stack,
|
||||||
|
# offset=pmos3_pin.center(),
|
||||||
|
# directions=("V", "V"))
|
||||||
|
# self.add_via_center(layers=self.m1_stack,
|
||||||
|
# offset=nmos3_pin.center(),
|
||||||
|
# directions=("V", "V"))
|
||||||
|
|
||||||
|
# # Route in the A input track (top track)
|
||||||
|
# mid_offset = vector(nmos3_pin.center().x, self.inputA_yoffset)
|
||||||
|
# self.add_path("m1", [pmos1_pin.center(), mid_offset, nmos3_pin.uc()])
|
||||||
|
|
||||||
# This extends the output to the edge of the cell
|
# This extends the output to the edge of the cell
|
||||||
self.add_via_center(layers=self.m1_stack,
|
# self.add_via_center(layers=self.m1_stack,
|
||||||
offset=mid_offset)
|
# offset=mid_offset)
|
||||||
|
|
||||||
|
top_left_pin_offset = pmos1_pin.center()
|
||||||
|
top_right_pin_offset = pmos3_pin.center()
|
||||||
|
bottom_pin_offset = nmos3_pin.center()
|
||||||
|
|
||||||
|
# PMOS1 to output
|
||||||
|
self.add_path("m1", [top_left_pin_offset,
|
||||||
|
vector(top_left_pin_offset.x, out_offset.y),
|
||||||
|
out_offset])
|
||||||
|
# PMOS3 to output
|
||||||
|
self.add_path("m1", [top_right_pin_offset,
|
||||||
|
vector(top_right_pin_offset.x, mid_offset.y),
|
||||||
|
mid_offset])
|
||||||
|
# NMOS3 to output
|
||||||
|
mid2_offset = vector(mid_offset.x, bottom_pin_offset.y)
|
||||||
|
self.add_path("m1",
|
||||||
|
[bottom_pin_offset, mid2_offset],
|
||||||
|
width=nmos3_pin.height())
|
||||||
|
mid3_offset = vector(mid_offset.x, nmos3_pin.by())
|
||||||
|
self.add_path("m1", [mid3_offset, mid_offset])
|
||||||
|
|
||||||
self.add_layout_pin_rect_center(text="Z",
|
self.add_layout_pin_rect_center(text="Z",
|
||||||
layer="m1",
|
layer="m1",
|
||||||
offset=mid_offset,
|
offset=out_offset,
|
||||||
width=contact.m1_via.first_layer_width,
|
width=contact.m1_via.first_layer_width,
|
||||||
height=contact.m1_via.first_layer_height)
|
height=contact.m1_via.first_layer_height)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
import contact
|
import contact
|
||||||
import pgate
|
import pgate
|
||||||
import debug
|
import debug
|
||||||
|
from globals import OPTS
|
||||||
from tech import drc, parameter, spice
|
from tech import drc, parameter, spice
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
|
@ -36,6 +37,10 @@ class pnor2(pgate.pgate):
|
||||||
debug.check(size==1, "Size 1 pnor2 is only supported now.")
|
debug.check(size==1, "Size 1 pnor2 is only supported now.")
|
||||||
self.tx_mults = 1
|
self.tx_mults = 1
|
||||||
|
|
||||||
|
if OPTS.tech_name == "s8":
|
||||||
|
(self.nmos_width, self.tx_mults) = self.bin_width("nmos", self.nmos_width)
|
||||||
|
(self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width)
|
||||||
|
|
||||||
# Creates the netlist and layout
|
# Creates the netlist and layout
|
||||||
pgate.pgate.__init__(self, name, height)
|
pgate.pgate.__init__(self, name, height)
|
||||||
|
|
||||||
|
|
@ -56,6 +61,7 @@ class pnor2(pgate.pgate):
|
||||||
self.extend_wells()
|
self.extend_wells()
|
||||||
self.route_inputs()
|
self.route_inputs()
|
||||||
self.route_output()
|
self.route_output()
|
||||||
|
self.add_boundary()
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
""" Adds pins for spice netlist """
|
""" Adds pins for spice netlist """
|
||||||
|
|
@ -73,13 +79,23 @@ class pnor2(pgate.pgate):
|
||||||
connect_active=True)
|
connect_active=True)
|
||||||
self.add_mod(self.nmos)
|
self.add_mod(self.nmos)
|
||||||
|
|
||||||
self.pmos = factory.create(module_type="ptx",
|
self.pmos_nd = factory.create(module_type="ptx",
|
||||||
width=self.pmos_width,
|
width=self.pmos_width,
|
||||||
mults=self.tx_mults,
|
mults=self.tx_mults,
|
||||||
tx_type="pmos",
|
tx_type="pmos",
|
||||||
|
add_drain_contact=False,
|
||||||
connect_poly=True,
|
connect_poly=True,
|
||||||
connect_active=True)
|
connect_active=True)
|
||||||
self.add_mod(self.pmos)
|
self.add_mod(self.pmos_nd)
|
||||||
|
|
||||||
|
self.pmos_ns = factory.create(module_type="ptx",
|
||||||
|
width=self.pmos_width,
|
||||||
|
mults=self.tx_mults,
|
||||||
|
tx_type="pmos",
|
||||||
|
add_source_contact=False,
|
||||||
|
connect_poly=True,
|
||||||
|
connect_active=True)
|
||||||
|
self.add_mod(self.pmos_ns)
|
||||||
|
|
||||||
def setup_layout_constants(self):
|
def setup_layout_constants(self):
|
||||||
""" Pre-compute some handy layout parameters. """
|
""" Pre-compute some handy layout parameters. """
|
||||||
|
|
@ -92,12 +108,12 @@ class pnor2(pgate.pgate):
|
||||||
|
|
||||||
# Compute the other pmos2 location, but determining
|
# Compute the other pmos2 location, but determining
|
||||||
# offset to overlap the source and drain pins
|
# offset to overlap the source and drain pins
|
||||||
self.overlap_offset = self.pmos.get_pin("D").ll() - self.pmos.get_pin("S").ll()
|
self.overlap_offset = self.pmos_ns.get_pin("D").ll() - self.pmos_nd.get_pin("S").ll()
|
||||||
|
|
||||||
# Two PMOS devices and a well contact. Separation between each.
|
# Two PMOS devices and a well contact. Separation between each.
|
||||||
# Enclosure space on the sides.
|
# Enclosure space on the sides.
|
||||||
self.width = 2 * self.pmos.active_width \
|
self.width = 2 * self.pmos_ns.active_width \
|
||||||
+ self.pmos.active_contact.width \
|
+ self.pmos_ns.active_contact.width \
|
||||||
+ 2 * self.active_space \
|
+ 2 * self.active_space \
|
||||||
+ 0.5 * self.nwell_enclose_active
|
+ 0.5 * self.nwell_enclose_active
|
||||||
self.well_width = self.width + 2 * self.nwell_enclose_active
|
self.well_width = self.width + 2 * self.nwell_enclose_active
|
||||||
|
|
@ -130,11 +146,11 @@ class pnor2(pgate.pgate):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.pmos1_inst = self.add_inst(name="pnor2_pmos1",
|
self.pmos1_inst = self.add_inst(name="pnor2_pmos1",
|
||||||
mod=self.pmos)
|
mod=self.pmos_nd)
|
||||||
self.connect_inst(["vdd", "A", "net1", "vdd"])
|
self.connect_inst(["vdd", "A", "net1", "vdd"])
|
||||||
|
|
||||||
self.pmos2_inst = self.add_inst(name="pnor2_pmos2",
|
self.pmos2_inst = self.add_inst(name="pnor2_pmos2",
|
||||||
mod=self.pmos)
|
mod=self.pmos_ns)
|
||||||
self.connect_inst(["net1", "B", "Z", "vdd"])
|
self.connect_inst(["net1", "B", "Z", "vdd"])
|
||||||
|
|
||||||
self.nmos1_inst = self.add_inst(name="pnor2_nmos1",
|
self.nmos1_inst = self.add_inst(name="pnor2_nmos1",
|
||||||
|
|
@ -151,15 +167,15 @@ class pnor2(pgate.pgate):
|
||||||
to provide maximum routing in channel
|
to provide maximum routing in channel
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pmos1_pos = vector(self.pmos.active_offset.x,
|
pmos1_pos = vector(self.pmos_ns.active_offset.x,
|
||||||
self.height - self.pmos.active_height \
|
self.height - self.pmos_ns.active_height \
|
||||||
- self.top_bottom_space)
|
- self.top_bottom_space)
|
||||||
self.pmos1_inst.place(pmos1_pos)
|
self.pmos1_inst.place(pmos1_pos)
|
||||||
|
|
||||||
self.pmos2_pos = pmos1_pos + self.overlap_offset
|
self.pmos2_pos = pmos1_pos + self.overlap_offset
|
||||||
self.pmos2_inst.place(self.pmos2_pos)
|
self.pmos2_inst.place(self.pmos2_pos)
|
||||||
|
|
||||||
nmos1_pos = vector(self.pmos.active_offset.x, self.top_bottom_space)
|
nmos1_pos = vector(self.pmos_ns.active_offset.x, self.top_bottom_space)
|
||||||
self.nmos1_inst.place(nmos1_pos)
|
self.nmos1_inst.place(nmos1_pos)
|
||||||
|
|
||||||
self.nmos2_pos = nmos1_pos + self.overlap_offset
|
self.nmos2_pos = nmos1_pos + self.overlap_offset
|
||||||
|
|
@ -172,7 +188,7 @@ class pnor2(pgate.pgate):
|
||||||
def add_well_contacts(self):
|
def add_well_contacts(self):
|
||||||
""" Add n/p well taps to the layout and connect to supplies """
|
""" Add n/p well taps to the layout and connect to supplies """
|
||||||
|
|
||||||
self.add_nwell_contact(self.pmos, self.pmos2_pos)
|
self.add_nwell_contact(self.pmos_ns, self.pmos2_pos)
|
||||||
self.add_pwell_contact(self.nmos, self.nmos2_pos)
|
self.add_pwell_contact(self.nmos, self.nmos2_pos)
|
||||||
|
|
||||||
def connect_rails(self):
|
def connect_rails(self):
|
||||||
|
|
@ -187,8 +203,7 @@ class pnor2(pgate.pgate):
|
||||||
def route_inputs(self):
|
def route_inputs(self):
|
||||||
""" Route the A and B inputs """
|
""" Route the A and B inputs """
|
||||||
# Use M2 spaces so we can drop vias on the pins later!
|
# Use M2 spaces so we can drop vias on the pins later!
|
||||||
inputB_yoffset = self.nmos2_pos.y + self.nmos.active_height \
|
inputB_yoffset = self.nmos2_inst.uy() + contact.poly_contact.height
|
||||||
+ self.m2_space + self.m2_width
|
|
||||||
self.route_input_gate(self.pmos2_inst,
|
self.route_input_gate(self.pmos2_inst,
|
||||||
self.nmos2_inst,
|
self.nmos2_inst,
|
||||||
inputB_yoffset,
|
inputB_yoffset,
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
import contact
|
import contact
|
||||||
import design
|
import design
|
||||||
import debug
|
import debug
|
||||||
|
from pgate import pgate
|
||||||
from tech import parameter
|
from tech import parameter
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
|
@ -28,6 +29,7 @@ class precharge(design.design):
|
||||||
self.bitcell = factory.create(module_type="bitcell")
|
self.bitcell = factory.create(module_type="bitcell")
|
||||||
self.beta = parameter["beta"]
|
self.beta = parameter["beta"]
|
||||||
self.ptx_width = self.beta * parameter["min_tx_size"]
|
self.ptx_width = self.beta * parameter["min_tx_size"]
|
||||||
|
self.ptx_mults = 1
|
||||||
self.width = self.bitcell.width
|
self.width = self.bitcell.width
|
||||||
self.bitcell_bl = bitcell_bl
|
self.bitcell_bl = bitcell_bl
|
||||||
self.bitcell_br = bitcell_br
|
self.bitcell_br = bitcell_br
|
||||||
|
|
@ -68,6 +70,7 @@ class precharge(design.design):
|
||||||
self.route_vdd_rail()
|
self.route_vdd_rail()
|
||||||
self.route_bitlines()
|
self.route_bitlines()
|
||||||
self.connect_to_bitlines()
|
self.connect_to_bitlines()
|
||||||
|
self.add_boundary()
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
self.add_pin_list(["bl", "br", "en_bar", "vdd"],
|
self.add_pin_list(["bl", "br", "en_bar", "vdd"],
|
||||||
|
|
@ -77,8 +80,11 @@ class precharge(design.design):
|
||||||
"""
|
"""
|
||||||
Initializes the upper and lower pmos
|
Initializes the upper and lower pmos
|
||||||
"""
|
"""
|
||||||
|
if(OPTS.tech_name == "s8"):
|
||||||
|
(self.ptx_width, self.ptx_mults) = pgate.bin_width(self, "pmos", self.ptx_width)
|
||||||
self.pmos = factory.create(module_type="ptx",
|
self.pmos = factory.create(module_type="ptx",
|
||||||
width=self.ptx_width,
|
width=self.ptx_width,
|
||||||
|
mults=self.ptx_mults,
|
||||||
tx_type="pmos")
|
tx_type="pmos")
|
||||||
self.add_mod(self.pmos)
|
self.add_mod(self.pmos)
|
||||||
|
|
||||||
|
|
@ -96,17 +102,24 @@ class precharge(design.design):
|
||||||
height=layer_width)
|
height=layer_width)
|
||||||
|
|
||||||
pmos_pin = self.upper_pmos2_inst.get_pin("S")
|
pmos_pin = self.upper_pmos2_inst.get_pin("S")
|
||||||
|
|
||||||
# center of vdd rail
|
# center of vdd rail
|
||||||
pmos_vdd_pos = vector(pmos_pin.cx(), vdd_position.y)
|
pmos_vdd_pos = vector(pmos_pin.cx(), vdd_position.y)
|
||||||
self.add_path("m1", [pmos_pin.uc(), pmos_vdd_pos])
|
self.add_path("m1", [pmos_pin.uc(), pmos_vdd_pos])
|
||||||
|
|
||||||
|
# if enable is not on M1, the supply can be
|
||||||
if self.en_layer != "m1":
|
if self.en_layer != "m1":
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=pmos_vdd_pos)
|
offset=pmos_vdd_pos)
|
||||||
|
|
||||||
|
self.add_power_pin("vdd",
|
||||||
|
self.well_contact_pos,
|
||||||
|
vertical=True)
|
||||||
|
|
||||||
|
# Hack for li layers
|
||||||
# Add vdd pin above the transistor
|
if hasattr(self, "li_stack"):
|
||||||
self.add_power_pin("vdd", self.well_contact_pos, vertical=True)
|
self.add_via_center(layers=self.li_stack,
|
||||||
|
offset=self.well_contact_pos)
|
||||||
|
|
||||||
def create_ptx(self):
|
def create_ptx(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -159,7 +172,7 @@ class precharge(design.design):
|
||||||
Connects the upper and lower pmos together
|
Connects the upper and lower pmos together
|
||||||
"""
|
"""
|
||||||
|
|
||||||
offset = self.lower_pmos_inst.get_pin("G").ll()
|
offset = self.lower_pmos_inst.get_pin("G").ul()
|
||||||
# connects the top and bottom pmos' gates together
|
# connects the top and bottom pmos' gates together
|
||||||
ylength = self.upper_pmos1_inst.get_pin("G").ll().y - offset.y
|
ylength = self.upper_pmos1_inst.get_pin("G").ll().y - offset.y
|
||||||
self.add_rect(layer="poly",
|
self.add_rect(layer="poly",
|
||||||
|
|
@ -191,7 +204,9 @@ class precharge(design.design):
|
||||||
if self.en_layer == "m2":
|
if self.en_layer == "m2":
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=offset)
|
offset=offset)
|
||||||
|
if hasattr(self, "li_stack"):
|
||||||
|
self.add_via_center(layers=self.li_stack,
|
||||||
|
offset=offset)
|
||||||
|
|
||||||
# adds the en rail on metal1
|
# adds the en rail on metal1
|
||||||
self.add_layout_pin_segment_center(text="en_bar",
|
self.add_layout_pin_segment_center(text="en_bar",
|
||||||
|
|
@ -205,13 +220,18 @@ class precharge(design.design):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# adds the contact from active to metal1
|
# adds the contact from active to metal1
|
||||||
self.well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1, 0) \
|
offset_height = self.upper_pmos1_inst.uy() + \
|
||||||
+ vector(0, self.upper_pmos1_inst.uy() + contact.active_contact.height / 2 \
|
0.5 * contact.active_contact.height + \
|
||||||
+ self.nwell_extend_active)
|
self.nwell_extend_active
|
||||||
|
self.well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1, 0) + \
|
||||||
|
vector(0, offset_height)
|
||||||
self.add_via_center(layers=self.active_stack,
|
self.add_via_center(layers=self.active_stack,
|
||||||
offset=self.well_contact_pos,
|
offset=self.well_contact_pos,
|
||||||
implant_type="n",
|
implant_type="n",
|
||||||
well_type="n")
|
well_type="n")
|
||||||
|
if hasattr(self, "li_stack"):
|
||||||
|
self.add_via_center(layers=self.li_stack,
|
||||||
|
offset=self.well_contact_pos)
|
||||||
|
|
||||||
self.height = self.well_contact_pos.y + contact.active_contact.height + self.m1_space
|
self.height = self.well_contact_pos.y + contact.active_contact.height + self.m1_space
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ class ptristate_inv(pgate.pgate):
|
||||||
self.connect_rails()
|
self.connect_rails()
|
||||||
self.route_inputs()
|
self.route_inputs()
|
||||||
self.route_outputs()
|
self.route_outputs()
|
||||||
|
self.add_boundary()
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
""" Adds pins for spice netlist """
|
""" Adds pins for spice netlist """
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@ from tech import layer, drc, spice
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
import contact
|
import contact
|
||||||
|
import logical_effort
|
||||||
|
import os
|
||||||
|
from globals import OPTS
|
||||||
|
|
||||||
|
|
||||||
class ptx(design.design):
|
class ptx(design.design):
|
||||||
|
|
@ -27,15 +30,23 @@ class ptx(design.design):
|
||||||
width=drc("minwidth_tx"),
|
width=drc("minwidth_tx"),
|
||||||
mults=1,
|
mults=1,
|
||||||
tx_type="nmos",
|
tx_type="nmos",
|
||||||
|
add_source_contact=True,
|
||||||
|
add_drain_contact=True,
|
||||||
|
series_devices=False,
|
||||||
connect_active=False,
|
connect_active=False,
|
||||||
connect_poly=False,
|
connect_poly=False,
|
||||||
series_devices=False,
|
|
||||||
num_contacts=None):
|
num_contacts=None):
|
||||||
# We need to keep unique names because outputting to GDSII
|
# We need to keep unique names because outputting to GDSII
|
||||||
# will use the last record with a given name. I.e., you will
|
# will use the last record with a given name. I.e., you will
|
||||||
# over-write a design in GDS if one has and the other doesn't
|
# over-write a design in GDS if one has and the other doesn't
|
||||||
# have poly connected, for example.
|
# have poly connected, for example.
|
||||||
name = "{0}_m{1}_w{2:.3f}".format(tx_type, mults, width)
|
name = "{0}_m{1}_w{2:.3f}".format(tx_type, mults, width)
|
||||||
|
if not add_source_contact:
|
||||||
|
name += "_ns"
|
||||||
|
if not add_drain_contact:
|
||||||
|
name += "_nd"
|
||||||
|
if series_devices:
|
||||||
|
name += "_sd"
|
||||||
if connect_active:
|
if connect_active:
|
||||||
name += "_a"
|
name += "_a"
|
||||||
if connect_poly:
|
if connect_poly:
|
||||||
|
|
@ -52,6 +63,8 @@ class ptx(design.design):
|
||||||
self.tx_width = width
|
self.tx_width = width
|
||||||
self.connect_active = connect_active
|
self.connect_active = connect_active
|
||||||
self.connect_poly = connect_poly
|
self.connect_poly = connect_poly
|
||||||
|
self.add_source_contact = add_source_contact
|
||||||
|
self.add_drain_contact = add_drain_contact
|
||||||
self.series_devices = series_devices
|
self.series_devices = series_devices
|
||||||
self.num_contacts = num_contacts
|
self.num_contacts = num_contacts
|
||||||
|
|
||||||
|
|
@ -90,12 +103,21 @@ class ptx(design.design):
|
||||||
dir_list = ['INOUT', 'INPUT', 'INOUT', body_dir]
|
dir_list = ['INOUT', 'INPUT', 'INOUT', body_dir]
|
||||||
self.add_pin_list(pin_list, dir_list)
|
self.add_pin_list(pin_list, dir_list)
|
||||||
|
|
||||||
# self.spice.append("\n.SUBCKT {0} {1}".format(self.name,
|
|
||||||
# " ".join(self.pins)))
|
|
||||||
# Just make a guess since these will actually
|
# Just make a guess since these will actually
|
||||||
# be decided in the layout later.
|
# be decided in the layout later.
|
||||||
area_sd = 2.5 * self.poly_width * self.tx_width
|
area_sd = 2.5 * self.poly_width * self.tx_width
|
||||||
perimeter_sd = 2 * self.poly_width + 2 * self.tx_width
|
perimeter_sd = 2 * self.poly_width + 2 * self.tx_width
|
||||||
|
if OPTS.tech_name == "s8":
|
||||||
|
# s8 technology is in microns
|
||||||
|
main_str = "M{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type],
|
||||||
|
self.mults,
|
||||||
|
self.tx_width,
|
||||||
|
drc("minwidth_poly"))
|
||||||
|
# Perimeters are in microns
|
||||||
|
# Area is in u since it is microns square
|
||||||
|
area_str = "pd={0:.2f} ps={0:.2f} as={1:.2f}u ad={1:.2f}u".format(perimeter_sd,
|
||||||
|
area_sd)
|
||||||
|
else:
|
||||||
main_str = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type],
|
main_str = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type],
|
||||||
self.mults,
|
self.mults,
|
||||||
self.tx_width,
|
self.tx_width,
|
||||||
|
|
@ -104,7 +126,14 @@ class ptx(design.design):
|
||||||
area_sd)
|
area_sd)
|
||||||
self.spice_device = main_str + area_str
|
self.spice_device = main_str + area_str
|
||||||
self.spice.append("\n* ptx " + self.spice_device)
|
self.spice.append("\n* ptx " + self.spice_device)
|
||||||
# self.spice.append(".ENDS {0}".format(self.name))
|
|
||||||
|
# LVS lib is always in SI units
|
||||||
|
if os.path.exists(OPTS.openram_tech + "lvs_lib"):
|
||||||
|
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type],
|
||||||
|
self.mults,
|
||||||
|
self.tx_width,
|
||||||
|
drc("minwidth_poly"))
|
||||||
|
|
||||||
|
|
||||||
def setup_layout_constants(self):
|
def setup_layout_constants(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -186,6 +215,8 @@ class ptx(design.design):
|
||||||
# The well is not included in the height and width
|
# The well is not included in the height and width
|
||||||
self.height = self.poly_height
|
self.height = self.poly_height
|
||||||
self.width = self.active_width
|
self.width = self.active_width
|
||||||
|
self.well_height = self.height
|
||||||
|
self.well_width = self.width
|
||||||
|
|
||||||
# This is the center of the first active contact offset (centered vertically)
|
# This is the center of the first active contact offset (centered vertically)
|
||||||
self.contact_offset = self.active_offset + vector(0.5 * self.active_contact.width,
|
self.contact_offset = self.active_offset + vector(0.5 * self.active_contact.width,
|
||||||
|
|
@ -379,18 +410,13 @@ class ptx(design.design):
|
||||||
# First one is always a SOURCE
|
# First one is always a SOURCE
|
||||||
label = "S"
|
label = "S"
|
||||||
pos = self.contact_offset
|
pos = self.contact_offset
|
||||||
contact=self.add_via_center(layers=self.active_stack,
|
if self.add_source_contact:
|
||||||
offset=pos,
|
contact = self.add_diff_contact(label, pos)
|
||||||
size=(1, self.num_contacts),
|
|
||||||
directions=("V","V"),
|
|
||||||
implant_type=self.implant_type,
|
|
||||||
well_type=self.well_type)
|
|
||||||
self.add_layout_pin_rect_center(text=label,
|
|
||||||
layer="m1",
|
|
||||||
offset=pos,
|
|
||||||
width=contact.mod.second_layer_width,
|
|
||||||
height=contact.mod.second_layer_height)
|
|
||||||
self.source_contacts.append(contact)
|
self.source_contacts.append(contact)
|
||||||
|
else:
|
||||||
|
self.add_layout_pin_rect_center(text=label,
|
||||||
|
layer="active",
|
||||||
|
offset=pos)
|
||||||
source_positions.append(pos)
|
source_positions.append(pos)
|
||||||
|
|
||||||
# Skip these if they are going to be in series
|
# Skip these if they are going to be in series
|
||||||
|
|
@ -406,22 +432,16 @@ class ptx(design.design):
|
||||||
label = "S"
|
label = "S"
|
||||||
source_positions.append(pos)
|
source_positions.append(pos)
|
||||||
|
|
||||||
contact=self.add_via_center(layers=self.active_stack,
|
if (label=="S" and self.add_source_contact) or (label=="D" and self.add_drain_contact):
|
||||||
offset=pos,
|
contact = self.add_diff_contact(label, pos)
|
||||||
size=(1, self.num_contacts),
|
|
||||||
directions=("V","V"),
|
|
||||||
implant_type=self.implant_type,
|
|
||||||
well_type=self.well_type)
|
|
||||||
self.add_layout_pin_rect_center(text=label,
|
|
||||||
layer="m1",
|
|
||||||
offset=pos,
|
|
||||||
width=contact.mod.second_layer_width,
|
|
||||||
height=contact.mod.second_layer_height)
|
|
||||||
|
|
||||||
if label == "S":
|
if label == "S":
|
||||||
self.source_contacts.append(contact)
|
self.source_contacts.append(contact)
|
||||||
else:
|
else:
|
||||||
self.drain_contacts.append(contact)
|
self.drain_contacts.append(contact)
|
||||||
|
else:
|
||||||
|
self.add_layout_pin_rect_center(text=label,
|
||||||
|
layer="active",
|
||||||
|
offset=pos)
|
||||||
|
|
||||||
pos = vector(self.active_offset.x + self.active_width - 0.5 * self.active_contact.width,
|
pos = vector(self.active_offset.x + self.active_width - 0.5 * self.active_contact.width,
|
||||||
self.contact_offset.y)
|
self.contact_offset.y)
|
||||||
|
|
@ -432,24 +452,70 @@ class ptx(design.design):
|
||||||
else:
|
else:
|
||||||
label = "S"
|
label = "S"
|
||||||
source_positions.append(pos)
|
source_positions.append(pos)
|
||||||
|
|
||||||
|
if (label=="S" and self.add_source_contact) or (label=="D" and self.add_drain_contact):
|
||||||
|
contact = self.add_diff_contact(label, pos)
|
||||||
|
if label == "S":
|
||||||
|
self.source_contacts.append(contact)
|
||||||
|
else:
|
||||||
|
self.drain_contacts.append(contact)
|
||||||
|
else:
|
||||||
|
self.add_layout_pin_rect_center(text=label,
|
||||||
|
layer="active",
|
||||||
|
offset=pos)
|
||||||
|
|
||||||
|
if self.connect_active:
|
||||||
|
self.connect_fingered_active(drain_positions, source_positions)
|
||||||
|
|
||||||
|
def get_stage_effort(self, cout):
|
||||||
|
"""Returns an object representing the parameters for delay in tau units."""
|
||||||
|
|
||||||
|
# FIXME: Using the same definition as the pinv.py.
|
||||||
|
parasitic_delay = 1
|
||||||
|
size = self.mults * self.tx_width / drc("minwidth_tx")
|
||||||
|
return logical_effort.logical_effort(self.name,
|
||||||
|
size,
|
||||||
|
self.input_load(),
|
||||||
|
cout,
|
||||||
|
parasitic_delay)
|
||||||
|
|
||||||
|
def input_load(self):
|
||||||
|
"""
|
||||||
|
Returns the relative gate cin of the tx
|
||||||
|
"""
|
||||||
|
|
||||||
|
# FIXME: this will be applied for the loads of the drain/source
|
||||||
|
return self.mults * self.tx_width / drc("minwidth_tx")
|
||||||
|
|
||||||
|
def add_diff_contact(self, label, pos):
|
||||||
contact=self.add_via_center(layers=self.active_stack,
|
contact=self.add_via_center(layers=self.active_stack,
|
||||||
offset=pos,
|
offset=pos,
|
||||||
size=(1, self.num_contacts),
|
size=(1, self.num_contacts),
|
||||||
directions=("V", "V"),
|
directions=("V", "V"),
|
||||||
implant_type=self.implant_type,
|
implant_type=self.implant_type,
|
||||||
well_type=self.well_type)
|
well_type=self.well_type)
|
||||||
|
|
||||||
|
if hasattr(self, "li_stack"):
|
||||||
|
contact=self.add_via_center(layers=self.li_stack,
|
||||||
|
offset=pos,
|
||||||
|
directions=("V", "V"))
|
||||||
|
|
||||||
|
# contact_area = contact.mod.second_layer_width * contact.mod.second_layer_height
|
||||||
|
# min_area = drc("minarea_m1")
|
||||||
|
# width = contact.mod.second_layer_width
|
||||||
|
# if contact_area < min_area:
|
||||||
|
# height = min_area / width
|
||||||
|
# else:
|
||||||
|
# height = contact.mod.second_layer_height
|
||||||
|
width = contact.mod.second_layer_width
|
||||||
|
height = contact.mod.second_layer_height
|
||||||
self.add_layout_pin_rect_center(text=label,
|
self.add_layout_pin_rect_center(text=label,
|
||||||
layer="m1",
|
layer="m1",
|
||||||
offset=pos,
|
offset=pos,
|
||||||
width=contact.mod.second_layer_width,
|
width=width,
|
||||||
height=contact.mod.second_layer_height)
|
height=height)
|
||||||
if label == "S":
|
|
||||||
self.source_contacts.append(contact)
|
|
||||||
else:
|
|
||||||
self.drain_contacts.append(contact)
|
|
||||||
|
|
||||||
if self.connect_active:
|
return(contact)
|
||||||
self.connect_fingered_active(drain_positions, source_positions)
|
|
||||||
|
|
||||||
def get_cin(self):
|
def get_cin(self):
|
||||||
"""Returns the relative gate cin of the tx"""
|
"""Returns the relative gate cin of the tx"""
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ class pwrite_driver(design.design):
|
||||||
self.place_modules()
|
self.place_modules()
|
||||||
self.route_wires()
|
self.route_wires()
|
||||||
self.route_supplies()
|
self.route_supplies()
|
||||||
|
self.add_boundary()
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
self.add_pin("din", "INPUT")
|
self.add_pin("din", "INPUT")
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#
|
#
|
||||||
import pgate
|
import pgate
|
||||||
import debug
|
import debug
|
||||||
from tech import drc
|
from tech import drc, layer
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
import logical_effort
|
import logical_effort
|
||||||
|
|
@ -57,7 +57,10 @@ class single_level_column_mux(pgate.pgate):
|
||||||
|
|
||||||
# Adds nmos_lower,nmos_upper to the module
|
# Adds nmos_lower,nmos_upper to the module
|
||||||
self.ptx_width = self.tx_size * drc("minwidth_tx")
|
self.ptx_width = self.tx_size * drc("minwidth_tx")
|
||||||
self.nmos = factory.create(module_type="ptx", width=self.ptx_width)
|
self.nmos = factory.create(module_type="ptx",
|
||||||
|
width=self.ptx_width,
|
||||||
|
add_source_contact=False,
|
||||||
|
add_drain_contact=False)
|
||||||
self.add_mod(self.nmos)
|
self.add_mod(self.nmos)
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
|
|
@ -66,26 +69,29 @@ class single_level_column_mux(pgate.pgate):
|
||||||
def add_bitline_pins(self):
|
def add_bitline_pins(self):
|
||||||
""" Add the top and bottom pins to this cell """
|
""" Add the top and bottom pins to this cell """
|
||||||
|
|
||||||
bl_pos = vector(self.bitcell.get_pin(self.bitcell_bl).lx(), 0)
|
bl_pin=self.bitcell.get_pin(self.bitcell_bl)
|
||||||
br_pos = vector(self.bitcell.get_pin(self.bitcell_br).lx(), 0)
|
br_pin=self.bitcell.get_pin(self.bitcell_br)
|
||||||
|
|
||||||
|
bl_pos = vector(bl_pin.lx(), 0)
|
||||||
|
br_pos = vector(br_pin.lx(), 0)
|
||||||
|
|
||||||
# bl and br
|
# bl and br
|
||||||
self.add_layout_pin(text="bl",
|
self.add_layout_pin(text="bl",
|
||||||
layer="m2",
|
layer=bl_pin.layer,
|
||||||
offset=bl_pos + vector(0, self.height - self.pin_height),
|
offset=bl_pos + vector(0, self.height - self.pin_height),
|
||||||
height=self.pin_height)
|
height=self.pin_height)
|
||||||
self.add_layout_pin(text="br",
|
self.add_layout_pin(text="br",
|
||||||
layer="m2",
|
layer=br_pin.layer,
|
||||||
offset=br_pos + vector(0, self.height - self.pin_height),
|
offset=br_pos + vector(0, self.height - self.pin_height),
|
||||||
height=self.pin_height)
|
height=self.pin_height)
|
||||||
|
|
||||||
# bl_out and br_out
|
# bl_out and br_out
|
||||||
self.add_layout_pin(text="bl_out",
|
self.add_layout_pin(text="bl_out",
|
||||||
layer="m2",
|
layer=bl_pin.layer,
|
||||||
offset=bl_pos,
|
offset=bl_pos,
|
||||||
height=self.pin_height)
|
height=self.pin_height)
|
||||||
self.add_layout_pin(text="br_out",
|
self.add_layout_pin(text="br_out",
|
||||||
layer="m2",
|
layer=br_pin.layer,
|
||||||
offset=br_pos,
|
offset=br_pos,
|
||||||
height=self.pin_height)
|
height=self.pin_height)
|
||||||
|
|
||||||
|
|
@ -102,7 +108,7 @@ class single_level_column_mux(pgate.pgate):
|
||||||
|
|
||||||
# This aligns it directly above the other tx with gates abutting
|
# This aligns it directly above the other tx with gates abutting
|
||||||
nmos_upper_position = nmos_lower_position \
|
nmos_upper_position = nmos_lower_position \
|
||||||
+ vector(0, self.nmos.active_height + self.poly_space)
|
+ vector(0, self.nmos.active_height + max(self.active_space,self.poly_space))
|
||||||
self.nmos_upper = self.add_inst(name="mux_tx2",
|
self.nmos_upper = self.add_inst(name="mux_tx2",
|
||||||
mod=self.nmos,
|
mod=self.nmos,
|
||||||
offset=nmos_upper_position)
|
offset=nmos_upper_position)
|
||||||
|
|
@ -111,14 +117,29 @@ class single_level_column_mux(pgate.pgate):
|
||||||
def connect_poly(self):
|
def connect_poly(self):
|
||||||
""" Connect the poly gate of the two pass transistors """
|
""" Connect the poly gate of the two pass transistors """
|
||||||
|
|
||||||
height = self.nmos_upper.get_pin("G").uy() - self.nmos_lower.get_pin("G").by()
|
# offset is the top of the lower nmos' diffusion
|
||||||
|
# height is the distance between the nmos' diffusions, which depends on max(self.active_space,self.poly_space)
|
||||||
|
offset = self.nmos_lower.get_pin("G").ul() - vector(0,self.poly_extend_active)
|
||||||
|
height = self.nmos_upper.get_pin("G").by() + self.poly_extend_active - offset.y
|
||||||
|
self.add_rect(layer="poly",
|
||||||
|
offset=offset,
|
||||||
|
height=height)
|
||||||
|
|
||||||
|
# Add the sel pin to the bottom of the mux
|
||||||
self.add_layout_pin(text="sel",
|
self.add_layout_pin(text="sel",
|
||||||
layer="poly",
|
layer="poly",
|
||||||
offset=self.nmos_lower.get_pin("G").ll(),
|
offset=self.nmos_lower.get_pin("G").ll(),
|
||||||
height=height)
|
height=self.poly_extend_active)
|
||||||
|
|
||||||
def connect_bitlines(self):
|
def connect_bitlines(self):
|
||||||
""" Connect the bitlines to the mux transistors """
|
""" Connect the bitlines to the mux transistors """
|
||||||
|
|
||||||
|
# If li exists, use li and m1 for the mux, otherwise use m1 and m2
|
||||||
|
if "li" in layer:
|
||||||
|
self.col_mux_stack = self.li_stack
|
||||||
|
else:
|
||||||
|
self.col_mux_stack = self.m1_stack
|
||||||
|
|
||||||
# These are on metal2
|
# These are on metal2
|
||||||
bl_pin = self.get_pin("bl")
|
bl_pin = self.get_pin("bl")
|
||||||
br_pin = self.get_pin("br")
|
br_pin = self.get_pin("br")
|
||||||
|
|
@ -132,22 +153,47 @@ class single_level_column_mux(pgate.pgate):
|
||||||
nmos_upper_d_pin = self.nmos_upper.get_pin("D")
|
nmos_upper_d_pin = self.nmos_upper.get_pin("D")
|
||||||
|
|
||||||
# Add vias to bl, br_out, nmos_upper/S, nmos_lower/D
|
# Add vias to bl, br_out, nmos_upper/S, nmos_lower/D
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.col_mux_stack,
|
||||||
offset=bl_pin.bc(),
|
offset=bl_pin.bc(),
|
||||||
directions=("V", "V"))
|
directions=("V", "V"))
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.col_mux_stack,
|
||||||
offset=br_out_pin.uc(),
|
offset=br_out_pin.uc(),
|
||||||
directions=("V", "V"))
|
directions=("V", "V"))
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.col_mux_stack,
|
||||||
offset=nmos_upper_s_pin.center(),
|
offset=nmos_upper_s_pin.center(),
|
||||||
directions=("V", "V"))
|
directions=("V", "V"))
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.col_mux_stack,
|
||||||
offset=nmos_lower_d_pin.center(),
|
offset=nmos_lower_d_pin.center(),
|
||||||
directions=("V", "V"))
|
directions=("V", "V"))
|
||||||
|
|
||||||
|
# Add diffusion contacts
|
||||||
|
# These were previously omitted with the options: add_source_contact=False, add_drain_contact=False
|
||||||
|
# They are added now and not previously so that they do not include m1 (which is usually included by default)
|
||||||
|
# This is only a concern when the local interconnect (li) layer is being used
|
||||||
|
self.add_via_center(layers=self.active_stack,
|
||||||
|
offset=nmos_upper_d_pin.center(),
|
||||||
|
directions=("V", "V"),
|
||||||
|
implant_type="n",
|
||||||
|
well_type="nwell")
|
||||||
|
self.add_via_center(layers=self.active_stack,
|
||||||
|
offset=nmos_lower_s_pin.center(),
|
||||||
|
directions=("V", "V"),
|
||||||
|
implant_type="n",
|
||||||
|
well_type="nwell")
|
||||||
|
self.add_via_center(layers=self.active_stack,
|
||||||
|
offset=nmos_upper_s_pin.center(),
|
||||||
|
directions=("V", "V"),
|
||||||
|
implant_type="n",
|
||||||
|
well_type="nwell")
|
||||||
|
self.add_via_center(layers=self.active_stack,
|
||||||
|
offset=nmos_lower_d_pin.center(),
|
||||||
|
directions=("V", "V"),
|
||||||
|
implant_type="n",
|
||||||
|
well_type="nwell")
|
||||||
|
|
||||||
# bl -> nmos_upper/D on metal1
|
# bl -> nmos_upper/D on metal1
|
||||||
# bl_out -> nmos_upper/S on metal2
|
# bl_out -> nmos_upper/S on metal2
|
||||||
self.add_path("m1",
|
self.add_path(self.col_mux_stack[0],
|
||||||
[bl_pin.ll(), vector(nmos_upper_d_pin.cx(), bl_pin.by()),
|
[bl_pin.ll(), vector(nmos_upper_d_pin.cx(), bl_pin.by()),
|
||||||
nmos_upper_d_pin.center()])
|
nmos_upper_d_pin.center()])
|
||||||
# halfway up, move over
|
# halfway up, move over
|
||||||
|
|
@ -155,12 +201,12 @@ class single_level_column_mux(pgate.pgate):
|
||||||
+ nmos_upper_s_pin.bc().scale(0, 0.4)
|
+ nmos_upper_s_pin.bc().scale(0, 0.4)
|
||||||
mid2 = bl_out_pin.uc().scale(0, 0.4) \
|
mid2 = bl_out_pin.uc().scale(0, 0.4) \
|
||||||
+ nmos_upper_s_pin.bc().scale(1, 0.4)
|
+ nmos_upper_s_pin.bc().scale(1, 0.4)
|
||||||
self.add_path("m2",
|
self.add_path(self.col_mux_stack[2],
|
||||||
[bl_out_pin.uc(), mid1, mid2, nmos_upper_s_pin.bc()])
|
[bl_out_pin.uc(), mid1, mid2, nmos_upper_s_pin.center()])
|
||||||
|
|
||||||
# br -> nmos_lower/D on metal2
|
# br -> nmos_lower/D on metal2
|
||||||
# br_out -> nmos_lower/S on metal1
|
# br_out -> nmos_lower/S on metal1
|
||||||
self.add_path("m1",
|
self.add_path(self.col_mux_stack[0],
|
||||||
[br_out_pin.uc(),
|
[br_out_pin.uc(),
|
||||||
vector(nmos_lower_s_pin.cx(), br_out_pin.uy()),
|
vector(nmos_lower_s_pin.cx(), br_out_pin.uy()),
|
||||||
nmos_lower_s_pin.center()])
|
nmos_lower_s_pin.center()])
|
||||||
|
|
@ -169,8 +215,8 @@ class single_level_column_mux(pgate.pgate):
|
||||||
+ nmos_lower_d_pin.uc().scale(0,0.5)
|
+ nmos_lower_d_pin.uc().scale(0,0.5)
|
||||||
mid2 = br_pin.bc().scale(0,0.5) \
|
mid2 = br_pin.bc().scale(0,0.5) \
|
||||||
+ nmos_lower_d_pin.uc().scale(1,0.5)
|
+ nmos_lower_d_pin.uc().scale(1,0.5)
|
||||||
self.add_path("m2",
|
self.add_path(self.col_mux_stack[2],
|
||||||
[br_pin.bc(), mid1, mid2, nmos_lower_d_pin.uc()])
|
[br_pin.bc(), mid1, mid2, nmos_lower_d_pin.center()])
|
||||||
|
|
||||||
def add_wells(self):
|
def add_wells(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -186,12 +232,17 @@ class single_level_column_mux(pgate.pgate):
|
||||||
implant_type="p",
|
implant_type="p",
|
||||||
well_type="p")
|
well_type="p")
|
||||||
|
|
||||||
|
# If there is a li layer, include it in the power stack
|
||||||
|
self.add_via_center(layers=self.col_mux_stack,
|
||||||
|
offset=active_pos)
|
||||||
|
|
||||||
# Add the M1->..->power_grid_layer stack
|
# Add the M1->..->power_grid_layer stack
|
||||||
self.add_power_pin(name = "gnd",
|
self.add_power_pin(name = "gnd",
|
||||||
loc = active_pos,
|
loc = active_pos,
|
||||||
start_layer="m1")
|
start_layer="m1")
|
||||||
|
|
||||||
# Add well enclosure over all the tx and contact
|
# Add well enclosure over all the tx and contact
|
||||||
|
if "pwell" in layer:
|
||||||
self.add_rect(layer="pwell",
|
self.add_rect(layer="pwell",
|
||||||
offset=vector(0, 0),
|
offset=vector(0, 0),
|
||||||
width=self.bitcell.width,
|
width=self.bitcell.width,
|
||||||
|
|
@ -211,4 +262,3 @@ class single_level_column_mux(pgate.pgate):
|
||||||
load,
|
load,
|
||||||
parasitic_delay,
|
parasitic_delay,
|
||||||
False)
|
False)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,9 @@ class sram():
|
||||||
def sp_write(self, name):
|
def sp_write(self, name):
|
||||||
self.s.sp_write(name)
|
self.s.sp_write(name)
|
||||||
|
|
||||||
|
def lvs_write(self, name):
|
||||||
|
self.s.lvs_write(name)
|
||||||
|
|
||||||
def lef_write(self, name):
|
def lef_write(self, name):
|
||||||
self.s.lef_write(name)
|
self.s.lef_write(name)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ class sram_base(design, verilog, lef):
|
||||||
|
|
||||||
start_time = datetime.datetime.now()
|
start_time = datetime.datetime.now()
|
||||||
# We only enable final verification if we have routed the design
|
# We only enable final verification if we have routed the design
|
||||||
self.DRC_LVS(final_verification=OPTS.route_supplies, top_level=True)
|
self.DRC_LVS(final_verification=OPTS.route_supplies)
|
||||||
if not OPTS.is_unit_test:
|
if not OPTS.is_unit_test:
|
||||||
print_time("Verification", datetime.datetime.now(), start_time)
|
print_time("Verification", datetime.datetime.now(), start_time)
|
||||||
|
|
||||||
|
|
@ -561,7 +561,7 @@ class sram_base(design, verilog, lef):
|
||||||
self.add_via_center(layers=self.m2_stack,
|
self.add_via_center(layers=self.m2_stack,
|
||||||
offset=out_pos)
|
offset=out_pos)
|
||||||
|
|
||||||
def sp_write(self, sp_name):
|
def sp_write(self, sp_name, lvs_netlist=False):
|
||||||
# Write the entire spice of the object to the file
|
# Write the entire spice of the object to the file
|
||||||
############################################################
|
############################################################
|
||||||
# Spice circuit
|
# Spice circuit
|
||||||
|
|
@ -581,10 +581,13 @@ class sram_base(design, verilog, lef):
|
||||||
# sp.write(".global {0} {1}\n".format(spice["vdd_name"],
|
# sp.write(".global {0} {1}\n".format(spice["vdd_name"],
|
||||||
# spice["gnd_name"]))
|
# spice["gnd_name"]))
|
||||||
usedMODS = list()
|
usedMODS = list()
|
||||||
self.sp_write_file(sp, usedMODS)
|
self.sp_write_file(sp, usedMODS, lvs_netlist=lvs_netlist)
|
||||||
del usedMODS
|
del usedMODS
|
||||||
sp.close()
|
sp.close()
|
||||||
|
|
||||||
|
def lvs_write(self, sp_name):
|
||||||
|
self.sp_write(sp_name, lvs_netlist=True)
|
||||||
|
|
||||||
def get_wordline_stage_efforts(self, inp_is_rise=True):
|
def get_wordline_stage_efforts(self, inp_is_rise=True):
|
||||||
"""Get the all the stage efforts for each stage in the path from clk_buf to a wordline"""
|
"""Get the all the stage efforts for each stage in the path from clk_buf to a wordline"""
|
||||||
stage_effort_list = []
|
stage_effort_list = []
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@ class library_lvs_test(openram_test):
|
||||||
|
|
||||||
def setup_files():
|
def setup_files():
|
||||||
gds_dir = OPTS.openram_tech + "/gds_lib"
|
gds_dir = OPTS.openram_tech + "/gds_lib"
|
||||||
|
sp_dir = OPTS.openram_tech + "/lvs_lib"
|
||||||
|
if not os.path.exists(sp_dir):
|
||||||
sp_dir = OPTS.openram_tech + "/sp_lib"
|
sp_dir = OPTS.openram_tech + "/sp_lib"
|
||||||
files = os.listdir(gds_dir)
|
files = os.listdir(gds_dir)
|
||||||
nametest = re.compile("\.gds$", re.IGNORECASE)
|
nametest = re.compile("\.gds$", re.IGNORECASE)
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ from globals import OPTS
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
import debug
|
import debug
|
||||||
|
|
||||||
|
|
||||||
class ptx_1finger_nmos_test(openram_test):
|
class ptx_1finger_nmos_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
#!/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
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class precharge_pbitcell_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
|
# check precharge in multi-port
|
||||||
|
OPTS.bitcell = "pbitcell"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
OPTS.num_w_ports = 1
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(2, "Checking precharge for pbitcell (innermost connections)")
|
||||||
|
tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl0", bitcell_br="br0")
|
||||||
|
self.local_check(tx)
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(2, "Checking precharge for pbitcell (innermost connections)")
|
||||||
|
tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl1", bitcell_br="br1")
|
||||||
|
self.local_check(tx)
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(2, "Checking precharge for pbitcell (outermost connections)")
|
||||||
|
tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl2", bitcell_br="br2")
|
||||||
|
self.local_check(tx)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# 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())
|
||||||
|
|
@ -15,6 +15,7 @@ from globals import OPTS
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
import debug
|
import debug
|
||||||
|
|
||||||
|
|
||||||
class precharge_test(openram_test):
|
class precharge_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
|
|
@ -26,27 +27,6 @@ class precharge_test(openram_test):
|
||||||
tx = factory.create(module_type="precharge", size=1)
|
tx = factory.create(module_type="precharge", size=1)
|
||||||
self.local_check(tx)
|
self.local_check(tx)
|
||||||
|
|
||||||
# check precharge in multi-port
|
|
||||||
OPTS.bitcell = "pbitcell"
|
|
||||||
OPTS.num_rw_ports = 1
|
|
||||||
OPTS.num_r_ports = 1
|
|
||||||
OPTS.num_w_ports = 1
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(2, "Checking precharge for pbitcell (innermost connections)")
|
|
||||||
tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl0", bitcell_br="br0")
|
|
||||||
self.local_check(tx)
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(2, "Checking precharge for pbitcell (innermost connections)")
|
|
||||||
tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl1", bitcell_br="br1")
|
|
||||||
self.local_check(tx)
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(2, "Checking precharge for pbitcell (outermost connections)")
|
|
||||||
tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl2", bitcell_br="br2")
|
|
||||||
self.local_check(tx)
|
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
# run the test from the command line
|
# run the test from the command line
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
#!/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
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
#@unittest.skip("SKIPPING 04_driver_test")
|
||||||
|
|
||||||
|
class single_level_column_mux_pbitcell_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
|
# check single level column mux in multi-port
|
||||||
|
OPTS.bitcell = "pbitcell"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
OPTS.num_w_ports = 1
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(2, "Checking column mux for pbitcell (innermost connections)")
|
||||||
|
tx = factory.create(module_type="single_level_column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0")
|
||||||
|
self.local_check(tx)
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(2, "Checking column mux for pbitcell (outermost connections)")
|
||||||
|
tx = factory.create(module_type="single_level_column_mux",tx_size=8, bitcell_bl="bl2", bitcell_br="br2")
|
||||||
|
self.local_check(tx)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# 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())
|
||||||
|
|
@ -28,22 +28,6 @@ class single_level_column_mux_test(openram_test):
|
||||||
tx = factory.create(module_type="single_level_column_mux", tx_size=8)
|
tx = factory.create(module_type="single_level_column_mux", tx_size=8)
|
||||||
self.local_check(tx)
|
self.local_check(tx)
|
||||||
|
|
||||||
# check single level column mux in multi-port
|
|
||||||
OPTS.bitcell = "pbitcell"
|
|
||||||
OPTS.num_rw_ports = 1
|
|
||||||
OPTS.num_r_ports = 1
|
|
||||||
OPTS.num_w_ports = 1
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(2, "Checking column mux for pbitcell (innermost connections)")
|
|
||||||
tx = factory.create(module_type="single_level_column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0")
|
|
||||||
self.local_check(tx)
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(2, "Checking column mux for pbitcell (outermost connections)")
|
|
||||||
tx = factory.create(module_type="single_level_column_mux",tx_size=8, bitcell_bl="bl2", bitcell_br="br2")
|
|
||||||
self.local_check(tx)
|
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
# run the test from the command line
|
# run the test from the command line
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ from globals import OPTS
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
import debug
|
import debug
|
||||||
|
|
||||||
class replica_bitcell_array_test(openram_test):
|
class replica_pbitcell_array_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
#!/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
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class hierarchical_decoder_pbitcell_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
# check hierarchical decoder for multi-port
|
||||||
|
OPTS.bitcell = "pbitcell"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_w_ports = 0
|
||||||
|
OPTS.num_r_ports = 0
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(1, "Testing 16 row sample for hierarchical_decoder (multi-port case)")
|
||||||
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=16)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(1, "Testing 17 row sample for hierarchical_decoder (multi-port case)")
|
||||||
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=17)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(1, "Testing 23 row sample for hierarchical_decoder (multi-port case)")
|
||||||
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=23)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(1, "Testing 32 row sample for hierarchical_decoder (multi-port case)")
|
||||||
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=32)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(1, "Testing 65 row sample for hierarchical_decoder (multi-port case)")
|
||||||
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=65)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(1, "Testing 128 row sample for hierarchical_decoder (multi-port case)")
|
||||||
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=128)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(1, "Testing 341 row sample for hierarchical_decoder (multi-port case)")
|
||||||
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=341)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(1, "Testing 512 row sample for hierarchical_decoder (multi-port case)")
|
||||||
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=512)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# 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())
|
||||||
|
|
@ -20,90 +20,38 @@ class hierarchical_decoder_test(openram_test):
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
globals.init_openram(config_file)
|
globals.init_openram(config_file)
|
||||||
# Doesn't require hierarchical decoder
|
|
||||||
# debug.info(1, "Testing 4 row sample for hierarchical_decoder")
|
|
||||||
# a = hierarchical_decoder.hierarchical_decoder(name="hd1, rows=4)
|
|
||||||
# self.local_check(a)
|
|
||||||
|
|
||||||
# Doesn't require hierarchical decoder
|
|
||||||
# debug.info(1, "Testing 8 row sample for hierarchical_decoder")
|
|
||||||
# a = hierarchical_decoder.hierarchical_decoder(name="hd2", rows=8)
|
|
||||||
# self.local_check(a)
|
|
||||||
|
|
||||||
# check hierarchical decoder for single port
|
# check hierarchical decoder for single port
|
||||||
debug.info(1, "Testing 16 row sample for hierarchical_decoder")
|
debug.info(1, "Testing 16 row sample for hierarchical_decoder")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=16)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=16)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 17 row sample for hierarchical_decoder")
|
debug.info(1, "Testing 17 row sample for hierarchical_decoder")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=17)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=17)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 23 row sample for hierarchical_decoder")
|
debug.info(1, "Testing 23 row sample for hierarchical_decoder")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=23)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=23)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 32 row sample for hierarchical_decoder")
|
debug.info(1, "Testing 32 row sample for hierarchical_decoder")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=32)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=32)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 65 row sample for hierarchical_decoder")
|
debug.info(1, "Testing 65 row sample for hierarchical_decoder")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=65)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=65)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 128 row sample for hierarchical_decoder")
|
debug.info(1, "Testing 128 row sample for hierarchical_decoder")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=128)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=128)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 341 row sample for hierarchical_decoder")
|
debug.info(1, "Testing 341 row sample for hierarchical_decoder")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=341)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=341)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 512 row sample for hierarchical_decoder")
|
debug.info(1, "Testing 512 row sample for hierarchical_decoder")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=512)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=512)
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
# check hierarchical decoder for multi-port
|
|
||||||
OPTS.bitcell = "pbitcell"
|
|
||||||
OPTS.num_rw_ports = 1
|
|
||||||
OPTS.num_w_ports = 0
|
|
||||||
OPTS.num_r_ports = 0
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(1, "Testing 16 row sample for hierarchical_decoder (multi-port case)")
|
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=16)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(1, "Testing 17 row sample for hierarchical_decoder (multi-port case)")
|
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=17)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(1, "Testing 23 row sample for hierarchical_decoder (multi-port case)")
|
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=23)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
debug.info(1, "Testing 32 row sample for hierarchical_decoder (multi-port case)")
|
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=32)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(1, "Testing 65 row sample for hierarchical_decoder (multi-port case)")
|
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=65)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
debug.info(1, "Testing 128 row sample for hierarchical_decoder (multi-port case)")
|
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=128)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(1, "Testing 341 row sample for hierarchical_decoder (multi-port case)")
|
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=341)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
debug.info(1, "Testing 512 row sample for hierarchical_decoder (multi-port case)")
|
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=512)
|
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
#!/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
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class hierarchical_predecode2x4_pbitcell_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
|
# checking hierarchical precode 2x4 for multi-port
|
||||||
|
OPTS.bitcell = "pbitcell"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_w_ports = 0
|
||||||
|
OPTS.num_r_ports = 0
|
||||||
|
|
||||||
|
debug.info(1, "Testing sample for hierarchy_predecode2x4 (multi-port case)")
|
||||||
|
a = factory.create(module_type="hierarchical_predecode2x4")
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# 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())
|
||||||
|
|
@ -26,16 +26,6 @@ class hierarchical_predecode2x4_test(openram_test):
|
||||||
a = factory.create(module_type="hierarchical_predecode2x4")
|
a = factory.create(module_type="hierarchical_predecode2x4")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
# checking hierarchical precode 2x4 for multi-port
|
|
||||||
OPTS.bitcell = "pbitcell"
|
|
||||||
OPTS.num_rw_ports = 1
|
|
||||||
OPTS.num_w_ports = 0
|
|
||||||
OPTS.num_r_ports = 0
|
|
||||||
|
|
||||||
debug.info(1, "Testing sample for hierarchy_predecode2x4 (multi-port case)")
|
|
||||||
a = factory.create(module_type="hierarchical_predecode2x4")
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
# run the test from the command line
|
# run the test from the command line
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
#!/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
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class hierarchical_predecode3x8_pbitcell_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
|
# checking hierarchical precode 3x8 for multi-port
|
||||||
|
OPTS.bitcell = "pbitcell"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_w_ports = 0
|
||||||
|
OPTS.num_r_ports = 0
|
||||||
|
|
||||||
|
debug.info(1, "Testing sample for hierarchy_predecode3x8 (multi-port case)")
|
||||||
|
a = factory.create(module_type="hierarchical_predecode3x8")
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# 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())
|
||||||
|
|
@ -26,16 +26,6 @@ class hierarchical_predecode3x8_test(openram_test):
|
||||||
a = factory.create(module_type="hierarchical_predecode3x8")
|
a = factory.create(module_type="hierarchical_predecode3x8")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
# checking hierarchical precode 3x8 for multi-port
|
|
||||||
OPTS.bitcell = "pbitcell"
|
|
||||||
OPTS.num_rw_ports = 1
|
|
||||||
OPTS.num_w_ports = 0
|
|
||||||
OPTS.num_r_ports = 0
|
|
||||||
|
|
||||||
debug.info(1, "Testing sample for hierarchy_predecode3x8 (multi-port case)")
|
|
||||||
a = factory.create(module_type="hierarchical_predecode3x8")
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
# run the test from the command line
|
# run the test from the command line
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
#!/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.
|
||||||
|
#
|
||||||
|
from testutils import *
|
||||||
|
import sys,os
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class single_level_column_mux_pbitcell_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
import single_level_column_mux_array
|
||||||
|
|
||||||
|
# check single level column mux array in multi-port
|
||||||
|
OPTS.bitcell = "pbitcell"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
OPTS.num_w_ports = 1
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(1, "Testing sample for 2-way column_mux_array in multi-port")
|
||||||
|
a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0")
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(1, "Testing sample for 4-way column_mux_array in multi-port")
|
||||||
|
a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (innermost connections)")
|
||||||
|
a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (outermost connections)")
|
||||||
|
a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2")
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
||||||
|
# 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())
|
||||||
|
|
@ -34,29 +34,6 @@ class single_level_column_mux_test(openram_test):
|
||||||
a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4)
|
a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
# check single level column mux array in multi-port
|
|
||||||
OPTS.bitcell = "pbitcell"
|
|
||||||
OPTS.num_rw_ports = 1
|
|
||||||
OPTS.num_r_ports = 1
|
|
||||||
OPTS.num_w_ports = 1
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(1, "Testing sample for 2-way column_mux_array in multi-port")
|
|
||||||
a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0")
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
debug.info(1, "Testing sample for 4-way column_mux_array in multi-port")
|
|
||||||
a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (innermost connections)")
|
|
||||||
a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (outermost connections)")
|
|
||||||
a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2")
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
#!/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
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class precharge_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
|
# check precharge array in multi-port
|
||||||
|
OPTS.bitcell = "bitcell_1rw_1r"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
OPTS.num_w_ports = 0
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(2, "Checking 3 column precharge array for 1RW/1R bitcell")
|
||||||
|
pc = factory.create(module_type="precharge_array", columns=3, bitcell_bl="bl0", bitcell_br="br0")
|
||||||
|
self.local_check(pc)
|
||||||
|
|
||||||
|
# debug.info(2, "Checking 3 column precharge array for pbitcell (innermost connections)")
|
||||||
|
# pc = precharge_array.precharge_array(name="pre3", columns=3, bitcell_bl="bl0", bitcell_br="br0")
|
||||||
|
# self.local_check(pc)
|
||||||
|
|
||||||
|
# debug.info(2, "Checking 3 column precharge array for pbitcell (outermost connections)")
|
||||||
|
# pc = precharge_array.precharge_array(name="pre4", columns=3, bitcell_bl="bl2", bitcell_br="br2")
|
||||||
|
# self.local_check(pc)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# 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())
|
||||||
|
|
@ -26,25 +26,6 @@ class precharge_test(openram_test):
|
||||||
pc = factory.create(module_type="precharge_array", columns=3)
|
pc = factory.create(module_type="precharge_array", columns=3)
|
||||||
self.local_check(pc)
|
self.local_check(pc)
|
||||||
|
|
||||||
# check precharge array in multi-port
|
|
||||||
OPTS.bitcell = "bitcell_1rw_1r"
|
|
||||||
OPTS.num_rw_ports = 1
|
|
||||||
OPTS.num_r_ports = 1
|
|
||||||
OPTS.num_w_ports = 0
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(2, "Checking 3 column precharge array for 1RW/1R bitcell")
|
|
||||||
pc = factory.create(module_type="precharge_array", columns=3, bitcell_bl="bl0", bitcell_br="br0")
|
|
||||||
self.local_check(pc)
|
|
||||||
|
|
||||||
# debug.info(2, "Checking 3 column precharge array for pbitcell (innermost connections)")
|
|
||||||
# pc = precharge_array.precharge_array(name="pre3", columns=3, bitcell_bl="bl0", bitcell_br="br0")
|
|
||||||
# self.local_check(pc)
|
|
||||||
|
|
||||||
# debug.info(2, "Checking 3 column precharge array for pbitcell (outermost connections)")
|
|
||||||
# pc = precharge_array.precharge_array(name="pre4", columns=3, bitcell_bl="bl2", bitcell_br="br2")
|
|
||||||
# self.local_check(pc)
|
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
# run the test from the command line
|
# run the test from the command line
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
#!/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
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
#@unittest.skip("SKIPPING 04_driver_test")
|
||||||
|
|
||||||
|
class wordline_driver_pbitcell_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
|
# check wordline driver for multi-port
|
||||||
|
OPTS.bitcell = "pbitcell"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_w_ports = 0
|
||||||
|
OPTS.num_r_ports = 0
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(2, "Checking driver (multi-port case)")
|
||||||
|
tx = factory.create(module_type="wordline_driver", rows=8, cols=64)
|
||||||
|
self.local_check(tx)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# 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())
|
||||||
|
|
@ -28,17 +28,6 @@ class wordline_driver_test(openram_test):
|
||||||
tx = factory.create(module_type="wordline_driver", rows=8, cols=32)
|
tx = factory.create(module_type="wordline_driver", rows=8, cols=32)
|
||||||
self.local_check(tx)
|
self.local_check(tx)
|
||||||
|
|
||||||
# check wordline driver for multi-port
|
|
||||||
OPTS.bitcell = "pbitcell"
|
|
||||||
OPTS.num_rw_ports = 1
|
|
||||||
OPTS.num_w_ports = 0
|
|
||||||
OPTS.num_r_ports = 0
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(2, "Checking driver (multi-port case)")
|
|
||||||
tx = factory.create(module_type="wordline_driver", rows=8, cols=64)
|
|
||||||
self.local_check(tx)
|
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
# run the test from the command line
|
# run the test from the command line
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,10 @@ class sense_amp_test(openram_test):
|
||||||
globals.init_openram(config_file)
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
# check sense amp array for single port
|
# check sense amp array for single port
|
||||||
|
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=1")
|
||||||
|
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=1)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2")
|
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2")
|
||||||
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=2)
|
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=2)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
@ -30,21 +34,6 @@ class sense_amp_test(openram_test):
|
||||||
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=4)
|
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=4)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
# check sense amp array for multi-port
|
|
||||||
OPTS.bitcell = "pbitcell"
|
|
||||||
OPTS.num_rw_ports = 1
|
|
||||||
OPTS.num_w_ports = 0
|
|
||||||
OPTS.num_r_ports = 0
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2 (multi-port case)")
|
|
||||||
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=2)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4 (multi-port case)")
|
|
||||||
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=4)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
# run the test from the command line
|
# run the test from the command line
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
#!/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
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class sense_amp_pbitcell_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
|
#check sense amp array for multi-port
|
||||||
|
OPTS.bitcell = "pbitcell"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_w_ports = 0
|
||||||
|
OPTS.num_r_ports = 0
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2 (multi-port case)")
|
||||||
|
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=2)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4 (multi-port case)")
|
||||||
|
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=4)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# 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())
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
#!/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
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class write_driver_pbitcell_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
|
# check write driver array for multi-port
|
||||||
|
OPTS.bitcell = "pbitcell"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_w_ports = 0
|
||||||
|
OPTS.num_r_ports = 0
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(2, "Testing write_driver_array for columns=8, word_size=8 (multi-port case)")
|
||||||
|
a = factory.create(module_type="write_driver_array", columns=8, word_size=8)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(2, "Testing write_driver_array for columns=16, word_size=8 (multi-port case)")
|
||||||
|
a = factory.create(module_type="write_driver_array", columns=16, word_size=8)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# 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())
|
||||||
|
|
@ -30,21 +30,6 @@ class write_driver_test(openram_test):
|
||||||
a = factory.create(module_type="write_driver_array", columns=16, word_size=8)
|
a = factory.create(module_type="write_driver_array", columns=16, word_size=8)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
# check write driver array for multi-port
|
|
||||||
OPTS.bitcell = "pbitcell"
|
|
||||||
OPTS.num_rw_ports = 1
|
|
||||||
OPTS.num_w_ports = 0
|
|
||||||
OPTS.num_r_ports = 0
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(2, "Testing write_driver_array for columns=8, word_size=8 (multi-port case)")
|
|
||||||
a = factory.create(module_type="write_driver_array", columns=8, word_size=8)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
debug.info(2, "Testing write_driver_array for columns=16, word_size=8 (multi-port case)")
|
|
||||||
a = factory.create(module_type="write_driver_array", columns=16, word_size=8)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
# run the test from the command line
|
# run the test from the command line
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
#!/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
|
||||||
|
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
|
||||||
|
class write_driver_pbitcell_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
|
# check write driver array for multi-port
|
||||||
|
OPTS.bitcell = "pbitcell"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_w_ports = 0
|
||||||
|
OPTS.num_r_ports = 0
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(2, "Testing write_driver_array for columns=8, word_size=8, write_size=4 (multi-port case)")
|
||||||
|
a = factory.create(module_type="write_driver_array", columns=8, word_size=8, write_size=4)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(2, "Testing write_driver_array for columns=16, word_size=8, write_size=4 (multi-port case)")
|
||||||
|
a = factory.create(module_type="write_driver_array", columns=16, word_size=8, write_size=4)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
||||||
|
# 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,21 +36,6 @@ class write_driver_test(openram_test):
|
||||||
a = factory.create(module_type="write_driver_array", columns=16, word_size=8, write_size=4)
|
a = factory.create(module_type="write_driver_array", columns=16, word_size=8, write_size=4)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
# check write driver array for multi-port
|
|
||||||
OPTS.bitcell = "pbitcell"
|
|
||||||
OPTS.num_rw_ports = 1
|
|
||||||
OPTS.num_w_ports = 0
|
|
||||||
OPTS.num_r_ports = 0
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(2, "Testing write_driver_array for columns=8, word_size=8, write_size=4 (multi-port case)")
|
|
||||||
a = factory.create(module_type="write_driver_array", columns=8, word_size=8, write_size=4)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
debug.info(2, "Testing write_driver_array for columns=16, word_size=8, write_size=4 (multi-port case)")
|
|
||||||
a = factory.create(module_type="write_driver_array", columns=16, word_size=8, write_size=4)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
#!/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
|
||||||
|
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
|
||||||
|
class write_mask_and_array_pbitcell_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
|
# check write driver array for multi-port
|
||||||
|
OPTS.bitcell = "pbitcell"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_w_ports = 0
|
||||||
|
OPTS.num_r_ports = 0
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(2, "Testing write_mask_and_array for columns=8, word_size=8, write_size=4 (multi-port case)")
|
||||||
|
a = factory.create(module_type="write_mask_and_array", columns=8, word_size=8, write_size=4)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(2, "Testing write_mask_and_array for columns=16, word_size=8, write_size=2 (multi-port case)")
|
||||||
|
a = factory.create(module_type="write_mask_and_array", columns=16, word_size=8, write_size=2)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
||||||
|
# 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,21 +36,6 @@ class write_mask_and_array_test(openram_test):
|
||||||
a = factory.create(module_type="write_mask_and_array", columns=16, word_size=8, write_size=2)
|
a = factory.create(module_type="write_mask_and_array", columns=16, word_size=8, write_size=2)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
# check write driver array for multi-port
|
|
||||||
OPTS.bitcell = "pbitcell"
|
|
||||||
OPTS.num_rw_ports = 1
|
|
||||||
OPTS.num_w_ports = 0
|
|
||||||
OPTS.num_r_ports = 0
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(2, "Testing write_mask_and_array for columns=8, word_size=8, write_size=4 (multi-port case)")
|
|
||||||
a = factory.create(module_type="write_mask_and_array", columns=8, word_size=8, write_size=4)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
debug.info(2, "Testing write_mask_and_array for columns=16, word_size=8, write_size=2 (multi-port case)")
|
|
||||||
a = factory.create(module_type="write_mask_and_array", columns=16, word_size=8, write_size=2)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# See LICENSE for licensing information.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016-2019 Regents of the University of California
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
import unittest
|
||||||
|
from testutils import *
|
||||||
|
import sys,os
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class port_data_1rw_1r_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
from sram_config import sram_config
|
||||||
|
|
||||||
|
OPTS.bitcell = "bitcell_1w_1r"
|
||||||
|
OPTS.num_rw_ports = 0
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
OPTS.num_w_ports = 1
|
||||||
|
|
||||||
|
c = sram_config(word_size=4,
|
||||||
|
num_words=16)
|
||||||
|
|
||||||
|
c.words_per_row=1
|
||||||
|
factory.reset()
|
||||||
|
c.recompute_sizes()
|
||||||
|
debug.info(1, "No column mux")
|
||||||
|
a = factory.create("port_data", sram_config=c, port=0)
|
||||||
|
self.local_check(a)
|
||||||
|
a = factory.create("port_data", sram_config=c, port=1)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
c.num_words=32
|
||||||
|
c.words_per_row=2
|
||||||
|
factory.reset()
|
||||||
|
c.recompute_sizes()
|
||||||
|
debug.info(1, "Two way column mux")
|
||||||
|
a = factory.create("port_data", sram_config=c, port=0)
|
||||||
|
self.local_check(a)
|
||||||
|
a = factory.create("port_data", sram_config=c, port=1)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
c.num_words=64
|
||||||
|
c.words_per_row=4
|
||||||
|
factory.reset()
|
||||||
|
c.recompute_sizes()
|
||||||
|
debug.info(1, "Four way column mux")
|
||||||
|
a = factory.create("port_data", sram_config=c, port=0)
|
||||||
|
self.local_check(a)
|
||||||
|
a = factory.create("port_data", sram_config=c, port=1)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
c.word_size=2
|
||||||
|
c.num_words=128
|
||||||
|
c.words_per_row=8
|
||||||
|
factory.reset()
|
||||||
|
c.recompute_sizes()
|
||||||
|
debug.info(1, "Eight way column mux")
|
||||||
|
a = factory.create("port_data", sram_config=c, port=0)
|
||||||
|
self.local_check(a)
|
||||||
|
a = factory.create("port_data", sram_config=c, port=1)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# 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())
|
||||||
|
|
@ -55,52 +55,6 @@ class port_data_test(openram_test):
|
||||||
a = factory.create("port_data", sram_config=c, port=0)
|
a = factory.create("port_data", sram_config=c, port=0)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
OPTS.bitcell = "bitcell_1w_1r"
|
|
||||||
OPTS.num_rw_ports = 0
|
|
||||||
OPTS.num_r_ports = 1
|
|
||||||
OPTS.num_w_ports = 1
|
|
||||||
|
|
||||||
c.num_words=16
|
|
||||||
c.words_per_row=1
|
|
||||||
factory.reset()
|
|
||||||
c.recompute_sizes()
|
|
||||||
debug.info(1, "No column mux")
|
|
||||||
a = factory.create("port_data", sram_config=c, port=0)
|
|
||||||
self.local_check(a)
|
|
||||||
a = factory.create("port_data", sram_config=c, port=1)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
c.num_words=32
|
|
||||||
c.words_per_row=2
|
|
||||||
factory.reset()
|
|
||||||
c.recompute_sizes()
|
|
||||||
debug.info(1, "Two way column mux")
|
|
||||||
a = factory.create("port_data", sram_config=c, port=0)
|
|
||||||
self.local_check(a)
|
|
||||||
a = factory.create("port_data", sram_config=c, port=1)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
c.num_words=64
|
|
||||||
c.words_per_row=4
|
|
||||||
factory.reset()
|
|
||||||
c.recompute_sizes()
|
|
||||||
debug.info(1, "Four way column mux")
|
|
||||||
a = factory.create("port_data", sram_config=c, port=0)
|
|
||||||
self.local_check(a)
|
|
||||||
a = factory.create("port_data", sram_config=c, port=1)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
c.word_size=2
|
|
||||||
c.num_words=128
|
|
||||||
c.words_per_row=8
|
|
||||||
factory.reset()
|
|
||||||
c.recompute_sizes()
|
|
||||||
debug.info(1, "Eight way column mux")
|
|
||||||
a = factory.create("port_data", sram_config=c, port=0)
|
|
||||||
self.local_check(a)
|
|
||||||
a = factory.create("port_data", sram_config=c, port=1)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
# run the test from the command line
|
# run the test from the command line
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
#!/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
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class bank_select_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
|
OPTS.bitcell = "pbitcell"
|
||||||
|
debug.info(1, "No column mux, rw control logic")
|
||||||
|
a = factory.create(module_type="bank_select", port="rw")
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
OPTS.num_rw_ports = 0
|
||||||
|
OPTS.num_w_ports = 1
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
|
||||||
|
debug.info(1, "No column mux, w control logic")
|
||||||
|
a = factory.create(module_type="bank_select", port="w")
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(1, "No column mux, r control logic")
|
||||||
|
a = factory.create(module_type="bank_select", port="r")
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# 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())
|
||||||
|
|
@ -25,23 +25,6 @@ class bank_select_test(openram_test):
|
||||||
a = factory.create(module_type="bank_select", port="rw")
|
a = factory.create(module_type="bank_select", port="rw")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
OPTS.bitcell = "pbitcell"
|
|
||||||
debug.info(1, "No column mux, rw control logic")
|
|
||||||
a = factory.create(module_type="bank_select", port="rw")
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
OPTS.num_rw_ports = 0
|
|
||||||
OPTS.num_w_ports = 1
|
|
||||||
OPTS.num_r_ports = 1
|
|
||||||
|
|
||||||
debug.info(1, "No column mux, w control logic")
|
|
||||||
a = factory.create(module_type="bank_select", port="w")
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
debug.info(1, "No column mux, r control logic")
|
|
||||||
a = factory.create(module_type="bank_select", port="r")
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
# run the test from the command line
|
# run the test from the command line
|
||||||
|
|
|
||||||
|
|
@ -62,27 +62,34 @@ class timing_sram_test(openram_test):
|
||||||
data.update(port_data[0])
|
data.update(port_data[0])
|
||||||
|
|
||||||
if OPTS.tech_name == "freepdk45":
|
if OPTS.tech_name == "freepdk45":
|
||||||
golden_data = {'delay_hl': [0.2383338],
|
golden_data = {'min_period': 0.898,
|
||||||
'delay_lh': [0.2383338],
|
'write1_power': [0.2659137999999999],
|
||||||
'leakage_power': 0.0014532999999999998,
|
'disabled_write0_power': [0.1782495],
|
||||||
'min_period': 0.898,
|
'disabled_read0_power': [0.14490679999999997],
|
||||||
'read0_power': [0.30059800000000003],
|
'write0_power': [0.3330119],
|
||||||
'read1_power': [0.30061810000000005],
|
'disabled_write1_power': [0.1865223],
|
||||||
'slew_hl': [0.25358420000000004],
|
'leakage_power': 0.0014532,
|
||||||
'slew_lh': [0.25358420000000004],
|
'disabled_read1_power': [0.1627516],
|
||||||
'write0_power': [0.34616749999999996],
|
'slew_lh': [0.25367799999999996],
|
||||||
'write1_power': [0.2792924]}
|
'slew_hl': [0.25367799999999996],
|
||||||
|
'delay_lh': [0.23820930000000004],
|
||||||
|
'delay_hl': [0.23820930000000004],
|
||||||
|
'read1_power': [0.3005756],
|
||||||
|
'read0_power': [0.3005888]}
|
||||||
elif OPTS.tech_name == "scn4m_subm":
|
elif OPTS.tech_name == "scn4m_subm":
|
||||||
golden_data = {'delay_hl': [1.7448],
|
golden_data = {'leakage_power': 0.0006356576000000001,
|
||||||
'delay_lh': [1.7448],
|
'write1_power': [11.292700000000002],
|
||||||
'leakage_power': 0.0006356744000000001,
|
'read0_power': [12.98],
|
||||||
|
'disabled_write1_power': [8.3707],
|
||||||
|
'write0_power': [14.4447], 'delay_hl': [1.7445000000000002],
|
||||||
|
'disabled_read0_power': [6.4325],
|
||||||
|
'slew_hl': [1.7437],
|
||||||
|
'disabled_write0_power': [8.1307],
|
||||||
|
'slew_lh': [1.7437],
|
||||||
|
'read1_power': [12.9869],
|
||||||
|
'disabled_read1_power': [7.706],
|
||||||
'min_period': 6.25,
|
'min_period': 6.25,
|
||||||
'read0_power': [12.9846],
|
'delay_lh': [1.7445000000000002]}
|
||||||
'read1_power': [12.9722],
|
|
||||||
'slew_hl': [1.7433],
|
|
||||||
'slew_lh': [1.7433],
|
|
||||||
'write0_power': [14.8772],
|
|
||||||
'write1_power': [11.7217]}
|
|
||||||
else:
|
else:
|
||||||
self.assertTrue(False) # other techs fail
|
self.assertTrue(False) # other techs fail
|
||||||
# Check if no too many or too few results
|
# Check if no too many or too few results
|
||||||
|
|
|
||||||
|
|
@ -55,27 +55,35 @@ class timing_sram_test(openram_test):
|
||||||
data.update(port_data[0])
|
data.update(port_data[0])
|
||||||
|
|
||||||
if OPTS.tech_name == "freepdk45":
|
if OPTS.tech_name == "freepdk45":
|
||||||
golden_data = {'delay_hl': [0.2264205],
|
golden_data = {'slew_lh': [0.2592187],
|
||||||
'delay_lh': [0.2264205],
|
'slew_hl': [0.2592187],
|
||||||
'leakage_power': 0.0021017429999999997,
|
'delay_lh': [0.2465583],
|
||||||
'min_period': 0.859,
|
'disabled_write0_power': [0.1924678],
|
||||||
'read0_power': [0.3339161],
|
'disabled_read0_power': [0.152483],
|
||||||
'read1_power': [0.31329440000000003],
|
'write0_power': [0.3409064],
|
||||||
'slew_hl': [0.2590786],
|
'disabled_read1_power': [0.1737818],
|
||||||
'slew_lh': [0.2590786],
|
'read0_power': [0.3096708],
|
||||||
'write0_power': [0.36360849999999995],
|
'read1_power': [0.3107916],
|
||||||
'write1_power': [0.3486931]}
|
'delay_hl': [0.2465583],
|
||||||
|
'write1_power': [0.26915849999999997],
|
||||||
|
'leakage_power': 0.002044307,
|
||||||
|
'min_period': 0.898,
|
||||||
|
'disabled_write1_power': [0.201411]}
|
||||||
elif OPTS.tech_name == "scn4m_subm":
|
elif OPTS.tech_name == "scn4m_subm":
|
||||||
golden_data = {'delay_hl': [1.85985],
|
golden_data = {'read1_power': [12.11658],
|
||||||
'delay_lh': [1.85985],
|
'write1_power': [10.52653],
|
||||||
|
'read0_power': [11.956710000000001],
|
||||||
|
'disabled_write0_power': [7.673665],
|
||||||
|
'disabled_write1_power': [7.981922000000001],
|
||||||
|
'slew_lh': [1.868836],
|
||||||
|
'slew_hl': [1.868836],
|
||||||
|
'delay_hl': [1.8598510000000001],
|
||||||
|
'delay_lh': [1.8598510000000001],
|
||||||
'leakage_power': 0.008613619,
|
'leakage_power': 0.008613619,
|
||||||
|
'disabled_read0_power': [5.904712],
|
||||||
'min_period': 6.875,
|
'min_period': 6.875,
|
||||||
'read0_power': [12.656310000000001],
|
'disabled_read1_power': [7.132159],
|
||||||
'read1_power': [12.11682],
|
'write0_power': [13.406400000000001]}
|
||||||
'slew_hl': [1.868942],
|
|
||||||
'slew_lh': [1.868942],
|
|
||||||
'write0_power': [13.978110000000001],
|
|
||||||
'write1_power': [11.437930000000001]}
|
|
||||||
else:
|
else:
|
||||||
self.assertTrue(False) # other techs fail
|
self.assertTrue(False) # other techs fail
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,9 @@ class verilog_test(openram_test):
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
globals.init_openram(config_file)
|
globals.init_openram(config_file)
|
||||||
|
OPTS.route_supplies=False
|
||||||
|
OPTS.check_lvsdrc=False
|
||||||
|
OPTS.netlist_only=True
|
||||||
from sram import sram
|
from sram import sram
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
c = sram_config(word_size=2,
|
c = sram_config(word_size=2,
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,6 @@ class openram_back_end_test(openram_test):
|
||||||
self.assertEqual(len(re.findall('ERROR', output)), 0)
|
self.assertEqual(len(re.findall('ERROR', output)), 0)
|
||||||
self.assertEqual(len(re.findall('WARNING', output)), 0)
|
self.assertEqual(len(re.findall('WARNING', output)), 0)
|
||||||
|
|
||||||
|
|
||||||
# now clean up the directory
|
# now clean up the directory
|
||||||
if OPTS.purge_temp:
|
if OPTS.purge_temp:
|
||||||
if os.path.exists(out_path):
|
if os.path.exists(out_path):
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,6 @@ class openram_front_end_test(openram_test):
|
||||||
self.assertEqual(len(re.findall('ERROR', output)), 0)
|
self.assertEqual(len(re.findall('ERROR', output)), 0)
|
||||||
self.assertEqual(len(re.findall('WARNING', output)), 0)
|
self.assertEqual(len(re.findall('WARNING', output)), 0)
|
||||||
|
|
||||||
|
|
||||||
# now clean up the directory
|
# now clean up the directory
|
||||||
if OPTS.purge_temp:
|
if OPTS.purge_temp:
|
||||||
if os.path.exists(out_path):
|
if os.path.exists(out_path):
|
||||||
|
|
|
||||||
|
|
@ -35,11 +35,14 @@ library (sram_2_16_1_freepdk45_FF_1p0V_25C_lib){
|
||||||
default_max_fanout : 4.0 ;
|
default_max_fanout : 4.0 ;
|
||||||
default_connection_class : universal ;
|
default_connection_class : universal ;
|
||||||
|
|
||||||
|
voltage_map ( VDD, 1.0 );
|
||||||
|
voltage_map ( GND, 0 );
|
||||||
|
|
||||||
lu_table_template(CELL_TABLE){
|
lu_table_template(CELL_TABLE){
|
||||||
variable_1 : input_net_transition;
|
variable_1 : input_net_transition;
|
||||||
variable_2 : total_output_net_capacitance;
|
variable_2 : total_output_net_capacitance;
|
||||||
index_1("0.00125, 0.005, 0.04");
|
index_1("0.00125, 0.005, 0.04");
|
||||||
index_2("0.052275, 0.2091, 1.6728");
|
index_2("5.2275e-05, 0.0002091, 0.0008364");
|
||||||
}
|
}
|
||||||
|
|
||||||
lu_table_template(CONSTRAINT_TABLE){
|
lu_table_template(CONSTRAINT_TABLE){
|
||||||
|
|
@ -78,17 +81,26 @@ cell (sram_2_16_1_freepdk45){
|
||||||
dont_use : true;
|
dont_use : true;
|
||||||
map_only : true;
|
map_only : true;
|
||||||
dont_touch : true;
|
dont_touch : true;
|
||||||
area : 1124.88;
|
area : 0;
|
||||||
|
|
||||||
|
pg_pin(vdd) {
|
||||||
|
voltage_name : VDD;
|
||||||
|
pg_type : primary_power;
|
||||||
|
}
|
||||||
|
|
||||||
|
pg_pin(gnd) {
|
||||||
|
voltage_name : GND;
|
||||||
|
pg_type : primary_ground;
|
||||||
|
}
|
||||||
|
|
||||||
leakage_power () {
|
leakage_power () {
|
||||||
when : "csb0";
|
value : 0.000198;
|
||||||
value : 0.000167;
|
|
||||||
}
|
}
|
||||||
cell_leakage_power : 0;
|
cell_leakage_power : 0.000198;
|
||||||
bus(din0){
|
bus(din0){
|
||||||
bus_type : data;
|
bus_type : data;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
memory_write(){
|
memory_write(){
|
||||||
address : addr0;
|
address : addr0;
|
||||||
clocked_on : clk0;
|
clocked_on : clk0;
|
||||||
|
|
@ -127,8 +139,8 @@ cell (sram_2_16_1_freepdk45){
|
||||||
bus(dout0){
|
bus(dout0){
|
||||||
bus_type : data;
|
bus_type : data;
|
||||||
direction : output;
|
direction : output;
|
||||||
max_capacitance : 1.6728;
|
max_capacitance : 0.0008364000000000001;
|
||||||
min_capacitance : 0.052275;
|
min_capacitance : 5.2275000000000003e-05;
|
||||||
memory_read(){
|
memory_read(){
|
||||||
address : addr0;
|
address : addr0;
|
||||||
}
|
}
|
||||||
|
|
@ -138,14 +150,14 @@ cell (sram_2_16_1_freepdk45){
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
timing_type : falling_edge;
|
timing_type : falling_edge;
|
||||||
cell_rise(CELL_TABLE) {
|
cell_rise(CELL_TABLE) {
|
||||||
values("0.088, 0.088, 0.088",\
|
values("0.193, 0.193, 0.194",\
|
||||||
"0.088, 0.088, 0.088",\
|
"0.193, 0.193, 0.194",\
|
||||||
"0.088, 0.088, 0.088");
|
"0.193, 0.193, 0.194");
|
||||||
}
|
}
|
||||||
cell_fall(CELL_TABLE) {
|
cell_fall(CELL_TABLE) {
|
||||||
values("0.088, 0.088, 0.088",\
|
values("0.193, 0.193, 0.194",\
|
||||||
"0.088, 0.088, 0.088",\
|
"0.193, 0.193, 0.194",\
|
||||||
"0.088, 0.088, 0.088");
|
"0.193, 0.193, 0.194");
|
||||||
}
|
}
|
||||||
rise_transition(CELL_TABLE) {
|
rise_transition(CELL_TABLE) {
|
||||||
values("0.001, 0.001, 0.001",\
|
values("0.001, 0.001, 0.001",\
|
||||||
|
|
@ -164,7 +176,7 @@ cell (sram_2_16_1_freepdk45){
|
||||||
bus(addr0){
|
bus(addr0){
|
||||||
bus_type : addr;
|
bus_type : addr;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
max_transition : 0.04;
|
max_transition : 0.04;
|
||||||
pin(addr0[3:0]){
|
pin(addr0[3:0]){
|
||||||
timing(){
|
timing(){
|
||||||
|
|
@ -200,7 +212,7 @@ cell (sram_2_16_1_freepdk45){
|
||||||
|
|
||||||
pin(csb0){
|
pin(csb0){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -233,7 +245,7 @@ cell (sram_2_16_1_freepdk45){
|
||||||
|
|
||||||
pin(web0){
|
pin(web0){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -267,52 +279,61 @@ cell (sram_2_16_1_freepdk45){
|
||||||
pin(clk0){
|
pin(clk0){
|
||||||
clock : true;
|
clock : true;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "!csb0 & clk0 & !web0";
|
when : "!csb0 & !web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("0.033101244168888884");
|
values("9.240667e-02");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("0.033101244168888884");
|
values("9.240667e-02");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "!csb0 & !clk0 & web0";
|
when : "csb0 & !web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("0.033101244168888884");
|
values("9.240667e-02");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("0.033101244168888884");
|
values("9.240667e-02");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "csb0";
|
when : "!csb0 & web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("0");
|
values("9.240667e-02");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("0");
|
values("9.240667e-02");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal_power(){
|
||||||
|
when : "csb0 & web0";
|
||||||
|
rise_power(scalar){
|
||||||
|
values("9.240667e-02");
|
||||||
|
}
|
||||||
|
fall_power(scalar){
|
||||||
|
values("9.240667e-02");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type :"min_pulse_width";
|
timing_type :"min_pulse_width";
|
||||||
related_pin : clk0;
|
related_pin : clk0;
|
||||||
rise_constraint(scalar) {
|
rise_constraint(scalar) {
|
||||||
values("0.009");
|
values("0.0195");
|
||||||
}
|
}
|
||||||
fall_constraint(scalar) {
|
fall_constraint(scalar) {
|
||||||
values("0.009");
|
values("0.0195");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type :"minimum_period";
|
timing_type :"minimum_period";
|
||||||
related_pin : clk0;
|
related_pin : clk0;
|
||||||
rise_constraint(scalar) {
|
rise_constraint(scalar) {
|
||||||
values("0.018");
|
values("0.039");
|
||||||
}
|
}
|
||||||
fall_constraint(scalar) {
|
fall_constraint(scalar) {
|
||||||
values("0.018");
|
values("0.039");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,11 +35,14 @@ library (sram_2_16_1_freepdk45_SS_1p0V_25C_lib){
|
||||||
default_max_fanout : 4.0 ;
|
default_max_fanout : 4.0 ;
|
||||||
default_connection_class : universal ;
|
default_connection_class : universal ;
|
||||||
|
|
||||||
|
voltage_map ( VDD, 1.0 );
|
||||||
|
voltage_map ( GND, 0 );
|
||||||
|
|
||||||
lu_table_template(CELL_TABLE){
|
lu_table_template(CELL_TABLE){
|
||||||
variable_1 : input_net_transition;
|
variable_1 : input_net_transition;
|
||||||
variable_2 : total_output_net_capacitance;
|
variable_2 : total_output_net_capacitance;
|
||||||
index_1("0.00125, 0.005, 0.04");
|
index_1("0.00125, 0.005, 0.04");
|
||||||
index_2("0.052275, 0.2091, 1.6728");
|
index_2("5.2275e-05, 0.0002091, 0.0008364");
|
||||||
}
|
}
|
||||||
|
|
||||||
lu_table_template(CONSTRAINT_TABLE){
|
lu_table_template(CONSTRAINT_TABLE){
|
||||||
|
|
@ -78,17 +81,26 @@ cell (sram_2_16_1_freepdk45){
|
||||||
dont_use : true;
|
dont_use : true;
|
||||||
map_only : true;
|
map_only : true;
|
||||||
dont_touch : true;
|
dont_touch : true;
|
||||||
area : 1124.88;
|
area : 0;
|
||||||
|
|
||||||
|
pg_pin(vdd) {
|
||||||
|
voltage_name : VDD;
|
||||||
|
pg_type : primary_power;
|
||||||
|
}
|
||||||
|
|
||||||
|
pg_pin(gnd) {
|
||||||
|
voltage_name : GND;
|
||||||
|
pg_type : primary_ground;
|
||||||
|
}
|
||||||
|
|
||||||
leakage_power () {
|
leakage_power () {
|
||||||
when : "csb0";
|
value : 0.000198;
|
||||||
value : 0.000167;
|
|
||||||
}
|
}
|
||||||
cell_leakage_power : 0;
|
cell_leakage_power : 0.000198;
|
||||||
bus(din0){
|
bus(din0){
|
||||||
bus_type : data;
|
bus_type : data;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
memory_write(){
|
memory_write(){
|
||||||
address : addr0;
|
address : addr0;
|
||||||
clocked_on : clk0;
|
clocked_on : clk0;
|
||||||
|
|
@ -127,8 +139,8 @@ cell (sram_2_16_1_freepdk45){
|
||||||
bus(dout0){
|
bus(dout0){
|
||||||
bus_type : data;
|
bus_type : data;
|
||||||
direction : output;
|
direction : output;
|
||||||
max_capacitance : 1.6728;
|
max_capacitance : 0.0008364000000000001;
|
||||||
min_capacitance : 0.052275;
|
min_capacitance : 5.2275000000000003e-05;
|
||||||
memory_read(){
|
memory_read(){
|
||||||
address : addr0;
|
address : addr0;
|
||||||
}
|
}
|
||||||
|
|
@ -138,14 +150,14 @@ cell (sram_2_16_1_freepdk45){
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
timing_type : falling_edge;
|
timing_type : falling_edge;
|
||||||
cell_rise(CELL_TABLE) {
|
cell_rise(CELL_TABLE) {
|
||||||
values("0.107, 0.107, 0.107",\
|
values("0.236, 0.236, 0.237",\
|
||||||
"0.107, 0.107, 0.107",\
|
"0.236, 0.236, 0.237",\
|
||||||
"0.107, 0.107, 0.107");
|
"0.236, 0.236, 0.237");
|
||||||
}
|
}
|
||||||
cell_fall(CELL_TABLE) {
|
cell_fall(CELL_TABLE) {
|
||||||
values("0.107, 0.107, 0.107",\
|
values("0.236, 0.236, 0.237",\
|
||||||
"0.107, 0.107, 0.107",\
|
"0.236, 0.236, 0.237",\
|
||||||
"0.107, 0.107, 0.107");
|
"0.236, 0.236, 0.237");
|
||||||
}
|
}
|
||||||
rise_transition(CELL_TABLE) {
|
rise_transition(CELL_TABLE) {
|
||||||
values("0.001, 0.001, 0.001",\
|
values("0.001, 0.001, 0.001",\
|
||||||
|
|
@ -164,7 +176,7 @@ cell (sram_2_16_1_freepdk45){
|
||||||
bus(addr0){
|
bus(addr0){
|
||||||
bus_type : addr;
|
bus_type : addr;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
max_transition : 0.04;
|
max_transition : 0.04;
|
||||||
pin(addr0[3:0]){
|
pin(addr0[3:0]){
|
||||||
timing(){
|
timing(){
|
||||||
|
|
@ -200,7 +212,7 @@ cell (sram_2_16_1_freepdk45){
|
||||||
|
|
||||||
pin(csb0){
|
pin(csb0){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -233,7 +245,7 @@ cell (sram_2_16_1_freepdk45){
|
||||||
|
|
||||||
pin(web0){
|
pin(web0){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -267,52 +279,61 @@ cell (sram_2_16_1_freepdk45){
|
||||||
pin(clk0){
|
pin(clk0){
|
||||||
clock : true;
|
clock : true;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "!csb0 & clk0 & !web0";
|
when : "!csb0 & !web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("0.033101244168888884");
|
values("7.560546e-02");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("0.033101244168888884");
|
values("7.560546e-02");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "!csb0 & !clk0 & web0";
|
when : "csb0 & !web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("0.033101244168888884");
|
values("7.560546e-02");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("0.033101244168888884");
|
values("7.560546e-02");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "csb0";
|
when : "!csb0 & web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("0");
|
values("7.560546e-02");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("0");
|
values("7.560546e-02");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal_power(){
|
||||||
|
when : "csb0 & web0";
|
||||||
|
rise_power(scalar){
|
||||||
|
values("7.560546e-02");
|
||||||
|
}
|
||||||
|
fall_power(scalar){
|
||||||
|
values("7.560546e-02");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type :"min_pulse_width";
|
timing_type :"min_pulse_width";
|
||||||
related_pin : clk0;
|
related_pin : clk0;
|
||||||
rise_constraint(scalar) {
|
rise_constraint(scalar) {
|
||||||
values("0.0105");
|
values("0.0235");
|
||||||
}
|
}
|
||||||
fall_constraint(scalar) {
|
fall_constraint(scalar) {
|
||||||
values("0.0105");
|
values("0.0235");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type :"minimum_period";
|
timing_type :"minimum_period";
|
||||||
related_pin : clk0;
|
related_pin : clk0;
|
||||||
rise_constraint(scalar) {
|
rise_constraint(scalar) {
|
||||||
values("0.021");
|
values("0.047");
|
||||||
}
|
}
|
||||||
fall_constraint(scalar) {
|
fall_constraint(scalar) {
|
||||||
values("0.021");
|
values("0.047");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,11 +35,14 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){
|
||||||
default_max_fanout : 4.0 ;
|
default_max_fanout : 4.0 ;
|
||||||
default_connection_class : universal ;
|
default_connection_class : universal ;
|
||||||
|
|
||||||
|
voltage_map ( VDD, 1.0 );
|
||||||
|
voltage_map ( GND, 0 );
|
||||||
|
|
||||||
lu_table_template(CELL_TABLE){
|
lu_table_template(CELL_TABLE){
|
||||||
variable_1 : input_net_transition;
|
variable_1 : input_net_transition;
|
||||||
variable_2 : total_output_net_capacitance;
|
variable_2 : total_output_net_capacitance;
|
||||||
index_1("0.00125, 0.005, 0.04");
|
index_1("0.00125, 0.005, 0.04");
|
||||||
index_2("0.052275, 0.2091, 1.6728");
|
index_2("5.2275e-05, 0.0002091, 0.0008364");
|
||||||
}
|
}
|
||||||
|
|
||||||
lu_table_template(CONSTRAINT_TABLE){
|
lu_table_template(CONSTRAINT_TABLE){
|
||||||
|
|
@ -78,17 +81,26 @@ cell (sram_2_16_1_freepdk45){
|
||||||
dont_use : true;
|
dont_use : true;
|
||||||
map_only : true;
|
map_only : true;
|
||||||
dont_touch : true;
|
dont_touch : true;
|
||||||
area : 977.4951374999999;
|
area : 0;
|
||||||
|
|
||||||
|
pg_pin(vdd) {
|
||||||
|
voltage_name : VDD;
|
||||||
|
pg_type : primary_power;
|
||||||
|
}
|
||||||
|
|
||||||
|
pg_pin(gnd) {
|
||||||
|
voltage_name : GND;
|
||||||
|
pg_type : primary_ground;
|
||||||
|
}
|
||||||
|
|
||||||
leakage_power () {
|
leakage_power () {
|
||||||
when : "csb0";
|
value : 0.00163;
|
||||||
value : 0.0011164579999999999;
|
|
||||||
}
|
}
|
||||||
cell_leakage_power : 0;
|
cell_leakage_power : 0.00163;
|
||||||
bus(din0){
|
bus(din0){
|
||||||
bus_type : data;
|
bus_type : data;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
memory_write(){
|
memory_write(){
|
||||||
address : addr0;
|
address : addr0;
|
||||||
clocked_on : clk0;
|
clocked_on : clk0;
|
||||||
|
|
@ -98,9 +110,9 @@ cell (sram_2_16_1_freepdk45){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
rise_constraint(CONSTRAINT_TABLE) {
|
rise_constraint(CONSTRAINT_TABLE) {
|
||||||
values("0.033, 0.033, 0.039",\
|
values("0.033, 0.033, 0.033",\
|
||||||
"0.033, 0.033, 0.039",\
|
"0.033, 0.033, 0.033",\
|
||||||
"0.033, 0.033, 0.039");
|
"0.033, 0.033, 0.033");
|
||||||
}
|
}
|
||||||
fall_constraint(CONSTRAINT_TABLE) {
|
fall_constraint(CONSTRAINT_TABLE) {
|
||||||
values("0.027, 0.027, 0.033",\
|
values("0.027, 0.027, 0.033",\
|
||||||
|
|
@ -112,14 +124,14 @@ cell (sram_2_16_1_freepdk45){
|
||||||
timing_type : hold_rising;
|
timing_type : hold_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
rise_constraint(CONSTRAINT_TABLE) {
|
rise_constraint(CONSTRAINT_TABLE) {
|
||||||
values("-0.01, -0.016, -0.022",\
|
values("-0.01, -0.01, 0.021",\
|
||||||
"-0.01, -0.016, -0.022",\
|
"-0.01, -0.01, 0.021",\
|
||||||
"-0.01, -0.016, -0.022");
|
"-0.01, -0.01, 0.021");
|
||||||
}
|
}
|
||||||
fall_constraint(CONSTRAINT_TABLE) {
|
fall_constraint(CONSTRAINT_TABLE) {
|
||||||
values("-0.016, -0.016, -0.016",\
|
values("-0.016, -0.01, -0.016",\
|
||||||
"-0.016, -0.016, -0.016",\
|
"-0.016, -0.01, -0.016",\
|
||||||
"-0.016, -0.016, -0.016");
|
"-0.016, -0.01, -0.016");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -127,8 +139,8 @@ cell (sram_2_16_1_freepdk45){
|
||||||
bus(dout0){
|
bus(dout0){
|
||||||
bus_type : data;
|
bus_type : data;
|
||||||
direction : output;
|
direction : output;
|
||||||
max_capacitance : 1.6728;
|
max_capacitance : 0.0008364000000000001;
|
||||||
min_capacitance : 0.052275;
|
min_capacitance : 5.2275000000000003e-05;
|
||||||
memory_read(){
|
memory_read(){
|
||||||
address : addr0;
|
address : addr0;
|
||||||
}
|
}
|
||||||
|
|
@ -138,24 +150,24 @@ cell (sram_2_16_1_freepdk45){
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
timing_type : falling_edge;
|
timing_type : falling_edge;
|
||||||
cell_rise(CELL_TABLE) {
|
cell_rise(CELL_TABLE) {
|
||||||
values("0.235, 0.235, 0.239",\
|
values("0.226, 0.227, 0.232",\
|
||||||
"0.235, 0.236, 0.24",\
|
"0.227, 0.228, 0.233",\
|
||||||
"0.241, 0.242, 0.246");
|
"0.232, 0.234, 0.238");
|
||||||
}
|
}
|
||||||
cell_fall(CELL_TABLE) {
|
cell_fall(CELL_TABLE) {
|
||||||
values("2.583, 2.585, 2.612",\
|
values("0.226, 0.227, 0.232",\
|
||||||
"2.584, 2.585, 2.613",\
|
"0.227, 0.228, 0.233",\
|
||||||
"2.59, 2.592, 2.62");
|
"0.232, 0.234, 0.238");
|
||||||
}
|
}
|
||||||
rise_transition(CELL_TABLE) {
|
rise_transition(CELL_TABLE) {
|
||||||
values("0.022, 0.022, 0.03",\
|
values("0.256, 0.256, 0.257",\
|
||||||
"0.022, 0.023, 0.03",\
|
"0.256, 0.256, 0.257",\
|
||||||
"0.022, 0.022, 0.03");
|
"0.256, 0.256, 0.257");
|
||||||
}
|
}
|
||||||
fall_transition(CELL_TABLE) {
|
fall_transition(CELL_TABLE) {
|
||||||
values("0.078, 0.079, 0.083",\
|
values("0.256, 0.256, 0.257",\
|
||||||
"0.078, 0.079, 0.083",\
|
"0.256, 0.256, 0.257",\
|
||||||
"0.079, 0.079, 0.083");
|
"0.256, 0.256, 0.257");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -164,16 +176,16 @@ cell (sram_2_16_1_freepdk45){
|
||||||
bus(addr0){
|
bus(addr0){
|
||||||
bus_type : addr;
|
bus_type : addr;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
max_transition : 0.04;
|
max_transition : 0.04;
|
||||||
pin(addr0[3:0]){
|
pin(addr0[3:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
rise_constraint(CONSTRAINT_TABLE) {
|
rise_constraint(CONSTRAINT_TABLE) {
|
||||||
values("0.033, 0.033, 0.039",\
|
values("0.033, 0.033, 0.033",\
|
||||||
"0.033, 0.033, 0.039",\
|
"0.033, 0.033, 0.033",\
|
||||||
"0.033, 0.033, 0.039");
|
"0.033, 0.033, 0.033");
|
||||||
}
|
}
|
||||||
fall_constraint(CONSTRAINT_TABLE) {
|
fall_constraint(CONSTRAINT_TABLE) {
|
||||||
values("0.027, 0.027, 0.033",\
|
values("0.027, 0.027, 0.033",\
|
||||||
|
|
@ -185,14 +197,14 @@ cell (sram_2_16_1_freepdk45){
|
||||||
timing_type : hold_rising;
|
timing_type : hold_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
rise_constraint(CONSTRAINT_TABLE) {
|
rise_constraint(CONSTRAINT_TABLE) {
|
||||||
values("-0.01, -0.016, -0.022",\
|
values("-0.01, -0.01, 0.021",\
|
||||||
"-0.01, -0.016, -0.022",\
|
"-0.01, -0.01, 0.021",\
|
||||||
"-0.01, -0.016, -0.022");
|
"-0.01, -0.01, 0.021");
|
||||||
}
|
}
|
||||||
fall_constraint(CONSTRAINT_TABLE) {
|
fall_constraint(CONSTRAINT_TABLE) {
|
||||||
values("-0.016, -0.016, -0.016",\
|
values("-0.016, -0.01, -0.016",\
|
||||||
"-0.016, -0.016, -0.016",\
|
"-0.016, -0.01, -0.016",\
|
||||||
"-0.016, -0.016, -0.016");
|
"-0.016, -0.01, -0.016");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -200,14 +212,14 @@ cell (sram_2_16_1_freepdk45){
|
||||||
|
|
||||||
pin(csb0){
|
pin(csb0){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
rise_constraint(CONSTRAINT_TABLE) {
|
rise_constraint(CONSTRAINT_TABLE) {
|
||||||
values("0.033, 0.033, 0.039",\
|
values("0.033, 0.033, 0.033",\
|
||||||
"0.033, 0.033, 0.039",\
|
"0.033, 0.033, 0.033",\
|
||||||
"0.033, 0.033, 0.039");
|
"0.033, 0.033, 0.033");
|
||||||
}
|
}
|
||||||
fall_constraint(CONSTRAINT_TABLE) {
|
fall_constraint(CONSTRAINT_TABLE) {
|
||||||
values("0.027, 0.027, 0.033",\
|
values("0.027, 0.027, 0.033",\
|
||||||
|
|
@ -219,28 +231,28 @@ cell (sram_2_16_1_freepdk45){
|
||||||
timing_type : hold_rising;
|
timing_type : hold_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
rise_constraint(CONSTRAINT_TABLE) {
|
rise_constraint(CONSTRAINT_TABLE) {
|
||||||
values("-0.01, -0.016, -0.022",\
|
values("-0.01, -0.01, 0.021",\
|
||||||
"-0.01, -0.016, -0.022",\
|
"-0.01, -0.01, 0.021",\
|
||||||
"-0.01, -0.016, -0.022");
|
"-0.01, -0.01, 0.021");
|
||||||
}
|
}
|
||||||
fall_constraint(CONSTRAINT_TABLE) {
|
fall_constraint(CONSTRAINT_TABLE) {
|
||||||
values("-0.016, -0.016, -0.016",\
|
values("-0.016, -0.01, -0.016",\
|
||||||
"-0.016, -0.016, -0.016",\
|
"-0.016, -0.01, -0.016",\
|
||||||
"-0.016, -0.016, -0.016");
|
"-0.016, -0.01, -0.016");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pin(web0){
|
pin(web0){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
rise_constraint(CONSTRAINT_TABLE) {
|
rise_constraint(CONSTRAINT_TABLE) {
|
||||||
values("0.033, 0.033, 0.039",\
|
values("0.033, 0.033, 0.033",\
|
||||||
"0.033, 0.033, 0.039",\
|
"0.033, 0.033, 0.033",\
|
||||||
"0.033, 0.033, 0.039");
|
"0.033, 0.033, 0.033");
|
||||||
}
|
}
|
||||||
fall_constraint(CONSTRAINT_TABLE) {
|
fall_constraint(CONSTRAINT_TABLE) {
|
||||||
values("0.027, 0.027, 0.033",\
|
values("0.027, 0.027, 0.033",\
|
||||||
|
|
@ -252,14 +264,14 @@ cell (sram_2_16_1_freepdk45){
|
||||||
timing_type : hold_rising;
|
timing_type : hold_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
rise_constraint(CONSTRAINT_TABLE) {
|
rise_constraint(CONSTRAINT_TABLE) {
|
||||||
values("-0.01, -0.016, -0.022",\
|
values("-0.01, -0.01, 0.021",\
|
||||||
"-0.01, -0.016, -0.022",\
|
"-0.01, -0.01, 0.021",\
|
||||||
"-0.01, -0.016, -0.022");
|
"-0.01, -0.01, 0.021");
|
||||||
}
|
}
|
||||||
fall_constraint(CONSTRAINT_TABLE) {
|
fall_constraint(CONSTRAINT_TABLE) {
|
||||||
values("-0.016, -0.016, -0.016",\
|
values("-0.016, -0.01, -0.016",\
|
||||||
"-0.016, -0.016, -0.016",\
|
"-0.016, -0.01, -0.016",\
|
||||||
"-0.016, -0.016, -0.016");
|
"-0.016, -0.01, -0.016");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -267,52 +279,61 @@ cell (sram_2_16_1_freepdk45){
|
||||||
pin(clk0){
|
pin(clk0){
|
||||||
clock : true;
|
clock : true;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "!csb0 & clk0 & !web0";
|
when : "!csb0 & !web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("0.03599689694444445");
|
values("3.069977e-01");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("0.03599689694444445");
|
values("3.686680e-01");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "!csb0 & !clk0 & web0";
|
when : "csb0 & !web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("0.029906643888888886");
|
values("2.055845e-01");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("0.029906643888888886");
|
values("1.933561e-01");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "csb0";
|
when : "!csb0 & web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("0");
|
values("3.315565e-01");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("0");
|
values("3.314553e-01");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal_power(){
|
||||||
|
when : "csb0 & web0";
|
||||||
|
rise_power(scalar){
|
||||||
|
values("1.777355e-01");
|
||||||
|
}
|
||||||
|
fall_power(scalar){
|
||||||
|
values("1.615044e-01");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type :"min_pulse_width";
|
timing_type :"min_pulse_width";
|
||||||
related_pin : clk0;
|
related_pin : clk0;
|
||||||
rise_constraint(scalar) {
|
rise_constraint(scalar) {
|
||||||
values("2.422");
|
values("0.449");
|
||||||
}
|
}
|
||||||
fall_constraint(scalar) {
|
fall_constraint(scalar) {
|
||||||
values("2.422");
|
values("0.449");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type :"minimum_period";
|
timing_type :"minimum_period";
|
||||||
related_pin : clk0;
|
related_pin : clk0;
|
||||||
rise_constraint(scalar) {
|
rise_constraint(scalar) {
|
||||||
values("4.844");
|
values("0.898");
|
||||||
}
|
}
|
||||||
fall_constraint(scalar) {
|
fall_constraint(scalar) {
|
||||||
values("4.844");
|
values("0.898");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,11 +35,14 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){
|
||||||
default_max_fanout : 4.0 ;
|
default_max_fanout : 4.0 ;
|
||||||
default_connection_class : universal ;
|
default_connection_class : universal ;
|
||||||
|
|
||||||
|
voltage_map ( VDD, 1.0 );
|
||||||
|
voltage_map ( GND, 0 );
|
||||||
|
|
||||||
lu_table_template(CELL_TABLE){
|
lu_table_template(CELL_TABLE){
|
||||||
variable_1 : input_net_transition;
|
variable_1 : input_net_transition;
|
||||||
variable_2 : total_output_net_capacitance;
|
variable_2 : total_output_net_capacitance;
|
||||||
index_1("0.00125, 0.005, 0.04");
|
index_1("0.00125, 0.005, 0.04");
|
||||||
index_2("0.052275, 0.2091, 1.6728");
|
index_2("5.2275e-05, 0.0002091, 0.0008364");
|
||||||
}
|
}
|
||||||
|
|
||||||
lu_table_template(CONSTRAINT_TABLE){
|
lu_table_template(CONSTRAINT_TABLE){
|
||||||
|
|
@ -78,17 +81,26 @@ cell (sram_2_16_1_freepdk45){
|
||||||
dont_use : true;
|
dont_use : true;
|
||||||
map_only : true;
|
map_only : true;
|
||||||
dont_touch : true;
|
dont_touch : true;
|
||||||
area : 977.4951374999999;
|
area : 0;
|
||||||
|
|
||||||
|
pg_pin(vdd) {
|
||||||
|
voltage_name : VDD;
|
||||||
|
pg_type : primary_power;
|
||||||
|
}
|
||||||
|
|
||||||
|
pg_pin(gnd) {
|
||||||
|
voltage_name : GND;
|
||||||
|
pg_type : primary_ground;
|
||||||
|
}
|
||||||
|
|
||||||
leakage_power () {
|
leakage_power () {
|
||||||
when : "csb0";
|
value : 0.000198;
|
||||||
value : 0.000179;
|
|
||||||
}
|
}
|
||||||
cell_leakage_power : 0;
|
cell_leakage_power : 0.000198;
|
||||||
bus(din0){
|
bus(din0){
|
||||||
bus_type : data;
|
bus_type : data;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
memory_write(){
|
memory_write(){
|
||||||
address : addr0;
|
address : addr0;
|
||||||
clocked_on : clk0;
|
clocked_on : clk0;
|
||||||
|
|
@ -127,8 +139,8 @@ cell (sram_2_16_1_freepdk45){
|
||||||
bus(dout0){
|
bus(dout0){
|
||||||
bus_type : data;
|
bus_type : data;
|
||||||
direction : output;
|
direction : output;
|
||||||
max_capacitance : 1.6728;
|
max_capacitance : 0.0008364000000000001;
|
||||||
min_capacitance : 0.052275;
|
min_capacitance : 5.2275000000000003e-05;
|
||||||
memory_read(){
|
memory_read(){
|
||||||
address : addr0;
|
address : addr0;
|
||||||
}
|
}
|
||||||
|
|
@ -138,14 +150,14 @@ cell (sram_2_16_1_freepdk45){
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
timing_type : falling_edge;
|
timing_type : falling_edge;
|
||||||
cell_rise(CELL_TABLE) {
|
cell_rise(CELL_TABLE) {
|
||||||
values("0.098, 0.098, 0.098",\
|
values("0.215, 0.215, 0.216",\
|
||||||
"0.098, 0.098, 0.098",\
|
"0.215, 0.215, 0.216",\
|
||||||
"0.098, 0.098, 0.098");
|
"0.215, 0.215, 0.216");
|
||||||
}
|
}
|
||||||
cell_fall(CELL_TABLE) {
|
cell_fall(CELL_TABLE) {
|
||||||
values("0.098, 0.098, 0.098",\
|
values("0.215, 0.215, 0.216",\
|
||||||
"0.098, 0.098, 0.098",\
|
"0.215, 0.215, 0.216",\
|
||||||
"0.098, 0.098, 0.098");
|
"0.215, 0.215, 0.216");
|
||||||
}
|
}
|
||||||
rise_transition(CELL_TABLE) {
|
rise_transition(CELL_TABLE) {
|
||||||
values("0.001, 0.001, 0.001",\
|
values("0.001, 0.001, 0.001",\
|
||||||
|
|
@ -164,7 +176,7 @@ cell (sram_2_16_1_freepdk45){
|
||||||
bus(addr0){
|
bus(addr0){
|
||||||
bus_type : addr;
|
bus_type : addr;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
max_transition : 0.04;
|
max_transition : 0.04;
|
||||||
pin(addr0[3:0]){
|
pin(addr0[3:0]){
|
||||||
timing(){
|
timing(){
|
||||||
|
|
@ -200,7 +212,7 @@ cell (sram_2_16_1_freepdk45){
|
||||||
|
|
||||||
pin(csb0){
|
pin(csb0){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -233,7 +245,7 @@ cell (sram_2_16_1_freepdk45){
|
||||||
|
|
||||||
pin(web0){
|
pin(web0){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -267,52 +279,61 @@ cell (sram_2_16_1_freepdk45){
|
||||||
pin(clk0){
|
pin(clk0){
|
||||||
clock : true;
|
clock : true;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.00020910000000000001;
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "!csb0 & clk0 & !web0";
|
when : "!csb0 & !web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("0.0747594982142222");
|
values("8.316600e-02");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("0.0747594982142222");
|
values("8.316600e-02");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "!csb0 & !clk0 & web0";
|
when : "csb0 & !web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("0.0747594982142222");
|
values("8.316600e-02");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("0.0747594982142222");
|
values("8.316600e-02");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "csb0";
|
when : "!csb0 & web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("0");
|
values("8.316600e-02");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("0");
|
values("8.316600e-02");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal_power(){
|
||||||
|
when : "csb0 & web0";
|
||||||
|
rise_power(scalar){
|
||||||
|
values("8.316600e-02");
|
||||||
|
}
|
||||||
|
fall_power(scalar){
|
||||||
|
values("8.316600e-02");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type :"min_pulse_width";
|
timing_type :"min_pulse_width";
|
||||||
related_pin : clk0;
|
related_pin : clk0;
|
||||||
rise_constraint(scalar) {
|
rise_constraint(scalar) {
|
||||||
values("0.0");
|
values("0.0215");
|
||||||
}
|
}
|
||||||
fall_constraint(scalar) {
|
fall_constraint(scalar) {
|
||||||
values("0.0");
|
values("0.0215");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type :"minimum_period";
|
timing_type :"minimum_period";
|
||||||
related_pin : clk0;
|
related_pin : clk0;
|
||||||
rise_constraint(scalar) {
|
rise_constraint(scalar) {
|
||||||
values("0");
|
values("0.043");
|
||||||
}
|
}
|
||||||
fall_constraint(scalar) {
|
fall_constraint(scalar) {
|
||||||
values("0");
|
values("0.043");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,11 +35,14 @@ library (sram_2_16_1_scn4m_subm_FF_5p0V_25C_lib){
|
||||||
default_max_fanout : 4.0 ;
|
default_max_fanout : 4.0 ;
|
||||||
default_connection_class : universal ;
|
default_connection_class : universal ;
|
||||||
|
|
||||||
|
voltage_map ( VDD, 5.0 );
|
||||||
|
voltage_map ( GND, 0 );
|
||||||
|
|
||||||
lu_table_template(CELL_TABLE){
|
lu_table_template(CELL_TABLE){
|
||||||
variable_1 : input_net_transition;
|
variable_1 : input_net_transition;
|
||||||
variable_2 : total_output_net_capacitance;
|
variable_2 : total_output_net_capacitance;
|
||||||
index_1("0.0125, 0.05, 0.4");
|
index_1("0.0125, 0.05, 0.4");
|
||||||
index_2("2.45605, 9.8242, 78.5936");
|
index_2("0.00245605, 0.0098242, 0.0392968");
|
||||||
}
|
}
|
||||||
|
|
||||||
lu_table_template(CONSTRAINT_TABLE){
|
lu_table_template(CONSTRAINT_TABLE){
|
||||||
|
|
@ -78,17 +81,26 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
dont_use : true;
|
dont_use : true;
|
||||||
map_only : true;
|
map_only : true;
|
||||||
dont_touch : true;
|
dont_touch : true;
|
||||||
area : 73068.14000000001;
|
area : 0;
|
||||||
|
|
||||||
|
pg_pin(vdd) {
|
||||||
|
voltage_name : VDD;
|
||||||
|
pg_type : primary_power;
|
||||||
|
}
|
||||||
|
|
||||||
|
pg_pin(gnd) {
|
||||||
|
voltage_name : GND;
|
||||||
|
pg_type : primary_ground;
|
||||||
|
}
|
||||||
|
|
||||||
leakage_power () {
|
leakage_power () {
|
||||||
when : "csb0";
|
value : 0.000198;
|
||||||
value : 0.000167;
|
|
||||||
}
|
}
|
||||||
cell_leakage_power : 0;
|
cell_leakage_power : 0.000198;
|
||||||
bus(din0){
|
bus(din0){
|
||||||
bus_type : data;
|
bus_type : data;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
memory_write(){
|
memory_write(){
|
||||||
address : addr0;
|
address : addr0;
|
||||||
clocked_on : clk0;
|
clocked_on : clk0;
|
||||||
|
|
@ -127,8 +139,8 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
bus(dout0){
|
bus(dout0){
|
||||||
bus_type : data;
|
bus_type : data;
|
||||||
direction : output;
|
direction : output;
|
||||||
max_capacitance : 78.5936;
|
max_capacitance : 0.0392968;
|
||||||
min_capacitance : 2.45605;
|
min_capacitance : 0.00245605;
|
||||||
memory_read(){
|
memory_read(){
|
||||||
address : addr0;
|
address : addr0;
|
||||||
}
|
}
|
||||||
|
|
@ -138,24 +150,24 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
timing_type : falling_edge;
|
timing_type : falling_edge;
|
||||||
cell_rise(CELL_TABLE) {
|
cell_rise(CELL_TABLE) {
|
||||||
values("0.241, 0.241, 0.241",\
|
values("1.183, 1.199, 1.264",\
|
||||||
"0.241, 0.241, 0.241",\
|
"1.183, 1.199, 1.264",\
|
||||||
"0.241, 0.241, 0.241");
|
"1.183, 1.199, 1.264");
|
||||||
}
|
}
|
||||||
cell_fall(CELL_TABLE) {
|
cell_fall(CELL_TABLE) {
|
||||||
values("0.241, 0.241, 0.241",\
|
values("1.183, 1.199, 1.264",\
|
||||||
"0.241, 0.241, 0.241",\
|
"1.183, 1.199, 1.264",\
|
||||||
"0.241, 0.241, 0.241");
|
"1.183, 1.199, 1.264");
|
||||||
}
|
}
|
||||||
rise_transition(CELL_TABLE) {
|
rise_transition(CELL_TABLE) {
|
||||||
values("0.004, 0.004, 0.004",\
|
values("0.006, 0.007, 0.014",\
|
||||||
"0.004, 0.004, 0.004",\
|
"0.006, 0.007, 0.014",\
|
||||||
"0.004, 0.004, 0.004");
|
"0.006, 0.007, 0.014");
|
||||||
}
|
}
|
||||||
fall_transition(CELL_TABLE) {
|
fall_transition(CELL_TABLE) {
|
||||||
values("0.004, 0.004, 0.004",\
|
values("0.006, 0.007, 0.014",\
|
||||||
"0.004, 0.004, 0.004",\
|
"0.006, 0.007, 0.014",\
|
||||||
"0.004, 0.004, 0.004");
|
"0.006, 0.007, 0.014");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -164,7 +176,7 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
bus(addr0){
|
bus(addr0){
|
||||||
bus_type : addr;
|
bus_type : addr;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
max_transition : 0.4;
|
max_transition : 0.4;
|
||||||
pin(addr0[3:0]){
|
pin(addr0[3:0]){
|
||||||
timing(){
|
timing(){
|
||||||
|
|
@ -200,7 +212,7 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
|
|
||||||
pin(csb0){
|
pin(csb0){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -233,7 +245,7 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
|
|
||||||
pin(web0){
|
pin(web0){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -267,52 +279,61 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
pin(clk0){
|
pin(clk0){
|
||||||
clock : true;
|
clock : true;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "!csb0 & clk0 & !web0";
|
when : "!csb0 & !web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("4.99880645");
|
values("7.797263e+00");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("4.99880645");
|
values("7.797263e+00");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "!csb0 & !clk0 & web0";
|
when : "csb0 & !web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("4.99880645");
|
values("7.797263e+00");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("4.99880645");
|
values("7.797263e+00");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "csb0";
|
when : "!csb0 & web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("0");
|
values("7.797263e+00");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("0");
|
values("7.797263e+00");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal_power(){
|
||||||
|
when : "csb0 & web0";
|
||||||
|
rise_power(scalar){
|
||||||
|
values("7.797263e+00");
|
||||||
|
}
|
||||||
|
fall_power(scalar){
|
||||||
|
values("7.797263e+00");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type :"min_pulse_width";
|
timing_type :"min_pulse_width";
|
||||||
related_pin : clk0;
|
related_pin : clk0;
|
||||||
rise_constraint(scalar) {
|
rise_constraint(scalar) {
|
||||||
values("0.024");
|
values("0.1265");
|
||||||
}
|
}
|
||||||
fall_constraint(scalar) {
|
fall_constraint(scalar) {
|
||||||
values("0.024");
|
values("0.1265");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type :"minimum_period";
|
timing_type :"minimum_period";
|
||||||
related_pin : clk0;
|
related_pin : clk0;
|
||||||
rise_constraint(scalar) {
|
rise_constraint(scalar) {
|
||||||
values("0.048");
|
values("0.253");
|
||||||
}
|
}
|
||||||
fall_constraint(scalar) {
|
fall_constraint(scalar) {
|
||||||
values("0.048");
|
values("0.253");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,11 +35,14 @@ library (sram_2_16_1_scn4m_subm_SS_5p0V_25C_lib){
|
||||||
default_max_fanout : 4.0 ;
|
default_max_fanout : 4.0 ;
|
||||||
default_connection_class : universal ;
|
default_connection_class : universal ;
|
||||||
|
|
||||||
|
voltage_map ( VDD, 5.0 );
|
||||||
|
voltage_map ( GND, 0 );
|
||||||
|
|
||||||
lu_table_template(CELL_TABLE){
|
lu_table_template(CELL_TABLE){
|
||||||
variable_1 : input_net_transition;
|
variable_1 : input_net_transition;
|
||||||
variable_2 : total_output_net_capacitance;
|
variable_2 : total_output_net_capacitance;
|
||||||
index_1("0.0125, 0.05, 0.4");
|
index_1("0.0125, 0.05, 0.4");
|
||||||
index_2("2.45605, 9.8242, 78.5936");
|
index_2("0.00245605, 0.0098242, 0.0392968");
|
||||||
}
|
}
|
||||||
|
|
||||||
lu_table_template(CONSTRAINT_TABLE){
|
lu_table_template(CONSTRAINT_TABLE){
|
||||||
|
|
@ -78,17 +81,26 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
dont_use : true;
|
dont_use : true;
|
||||||
map_only : true;
|
map_only : true;
|
||||||
dont_touch : true;
|
dont_touch : true;
|
||||||
area : 73068.14000000001;
|
area : 0;
|
||||||
|
|
||||||
|
pg_pin(vdd) {
|
||||||
|
voltage_name : VDD;
|
||||||
|
pg_type : primary_power;
|
||||||
|
}
|
||||||
|
|
||||||
|
pg_pin(gnd) {
|
||||||
|
voltage_name : GND;
|
||||||
|
pg_type : primary_ground;
|
||||||
|
}
|
||||||
|
|
||||||
leakage_power () {
|
leakage_power () {
|
||||||
when : "csb0";
|
value : 0.000198;
|
||||||
value : 0.000167;
|
|
||||||
}
|
}
|
||||||
cell_leakage_power : 0;
|
cell_leakage_power : 0.000198;
|
||||||
bus(din0){
|
bus(din0){
|
||||||
bus_type : data;
|
bus_type : data;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
memory_write(){
|
memory_write(){
|
||||||
address : addr0;
|
address : addr0;
|
||||||
clocked_on : clk0;
|
clocked_on : clk0;
|
||||||
|
|
@ -127,8 +139,8 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
bus(dout0){
|
bus(dout0){
|
||||||
bus_type : data;
|
bus_type : data;
|
||||||
direction : output;
|
direction : output;
|
||||||
max_capacitance : 78.5936;
|
max_capacitance : 0.0392968;
|
||||||
min_capacitance : 2.45605;
|
min_capacitance : 0.00245605;
|
||||||
memory_read(){
|
memory_read(){
|
||||||
address : addr0;
|
address : addr0;
|
||||||
}
|
}
|
||||||
|
|
@ -138,24 +150,24 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
timing_type : falling_edge;
|
timing_type : falling_edge;
|
||||||
cell_rise(CELL_TABLE) {
|
cell_rise(CELL_TABLE) {
|
||||||
values("0.294, 0.294, 0.294",\
|
values("1.446, 1.466, 1.545",\
|
||||||
"0.294, 0.294, 0.294",\
|
"1.446, 1.466, 1.545",\
|
||||||
"0.294, 0.294, 0.294");
|
"1.446, 1.466, 1.545");
|
||||||
}
|
}
|
||||||
cell_fall(CELL_TABLE) {
|
cell_fall(CELL_TABLE) {
|
||||||
values("0.294, 0.294, 0.294",\
|
values("1.446, 1.466, 1.545",\
|
||||||
"0.294, 0.294, 0.294",\
|
"1.446, 1.466, 1.545",\
|
||||||
"0.294, 0.294, 0.294");
|
"1.446, 1.466, 1.545");
|
||||||
}
|
}
|
||||||
rise_transition(CELL_TABLE) {
|
rise_transition(CELL_TABLE) {
|
||||||
values("0.004, 0.004, 0.004",\
|
values("0.007, 0.009, 0.017",\
|
||||||
"0.004, 0.004, 0.004",\
|
"0.007, 0.009, 0.017",\
|
||||||
"0.004, 0.004, 0.004");
|
"0.007, 0.009, 0.017");
|
||||||
}
|
}
|
||||||
fall_transition(CELL_TABLE) {
|
fall_transition(CELL_TABLE) {
|
||||||
values("0.004, 0.004, 0.004",\
|
values("0.007, 0.009, 0.017",\
|
||||||
"0.004, 0.004, 0.004",\
|
"0.007, 0.009, 0.017",\
|
||||||
"0.004, 0.004, 0.004");
|
"0.007, 0.009, 0.017");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -164,7 +176,7 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
bus(addr0){
|
bus(addr0){
|
||||||
bus_type : addr;
|
bus_type : addr;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
max_transition : 0.4;
|
max_transition : 0.4;
|
||||||
pin(addr0[3:0]){
|
pin(addr0[3:0]){
|
||||||
timing(){
|
timing(){
|
||||||
|
|
@ -200,7 +212,7 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
|
|
||||||
pin(csb0){
|
pin(csb0){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -233,7 +245,7 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
|
|
||||||
pin(web0){
|
pin(web0){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -267,52 +279,61 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
pin(clk0){
|
pin(clk0){
|
||||||
clock : true;
|
clock : true;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "!csb0 & clk0 & !web0";
|
when : "!csb0 & !web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("4.99880645");
|
values("6.379579e+00");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("4.99880645");
|
values("6.379579e+00");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "!csb0 & !clk0 & web0";
|
when : "csb0 & !web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("4.99880645");
|
values("6.379579e+00");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("4.99880645");
|
values("6.379579e+00");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "csb0";
|
when : "!csb0 & web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("0");
|
values("6.379579e+00");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("0");
|
values("6.379579e+00");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal_power(){
|
||||||
|
when : "csb0 & web0";
|
||||||
|
rise_power(scalar){
|
||||||
|
values("6.379579e+00");
|
||||||
|
}
|
||||||
|
fall_power(scalar){
|
||||||
|
values("6.379579e+00");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type :"min_pulse_width";
|
timing_type :"min_pulse_width";
|
||||||
related_pin : clk0;
|
related_pin : clk0;
|
||||||
rise_constraint(scalar) {
|
rise_constraint(scalar) {
|
||||||
values("0.0295");
|
values("0.1545");
|
||||||
}
|
}
|
||||||
fall_constraint(scalar) {
|
fall_constraint(scalar) {
|
||||||
values("0.0295");
|
values("0.1545");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type :"minimum_period";
|
timing_type :"minimum_period";
|
||||||
related_pin : clk0;
|
related_pin : clk0;
|
||||||
rise_constraint(scalar) {
|
rise_constraint(scalar) {
|
||||||
values("0.059");
|
values("0.309");
|
||||||
}
|
}
|
||||||
fall_constraint(scalar) {
|
fall_constraint(scalar) {
|
||||||
values("0.059");
|
values("0.309");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,11 +35,14 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){
|
||||||
default_max_fanout : 4.0 ;
|
default_max_fanout : 4.0 ;
|
||||||
default_connection_class : universal ;
|
default_connection_class : universal ;
|
||||||
|
|
||||||
|
voltage_map ( VDD, 5.0 );
|
||||||
|
voltage_map ( GND, 0 );
|
||||||
|
|
||||||
lu_table_template(CELL_TABLE){
|
lu_table_template(CELL_TABLE){
|
||||||
variable_1 : input_net_transition;
|
variable_1 : input_net_transition;
|
||||||
variable_2 : total_output_net_capacitance;
|
variable_2 : total_output_net_capacitance;
|
||||||
index_1("0.0125, 0.05, 0.4");
|
index_1("0.0125, 0.05, 0.4");
|
||||||
index_2("2.45605, 9.8242, 78.5936");
|
index_2("0.00245605, 0.0098242, 0.0392968");
|
||||||
}
|
}
|
||||||
|
|
||||||
lu_table_template(CONSTRAINT_TABLE){
|
lu_table_template(CONSTRAINT_TABLE){
|
||||||
|
|
@ -78,17 +81,26 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
dont_use : true;
|
dont_use : true;
|
||||||
map_only : true;
|
map_only : true;
|
||||||
dont_touch : true;
|
dont_touch : true;
|
||||||
area : 60774.3;
|
area : 0;
|
||||||
|
|
||||||
|
pg_pin(vdd) {
|
||||||
|
voltage_name : VDD;
|
||||||
|
pg_type : primary_power;
|
||||||
|
}
|
||||||
|
|
||||||
|
pg_pin(gnd) {
|
||||||
|
voltage_name : GND;
|
||||||
|
pg_type : primary_ground;
|
||||||
|
}
|
||||||
|
|
||||||
leakage_power () {
|
leakage_power () {
|
||||||
when : "csb0";
|
value : 0.000198;
|
||||||
value : 0.0009813788999999999;
|
|
||||||
}
|
}
|
||||||
cell_leakage_power : 0;
|
cell_leakage_power : 0.000198;
|
||||||
bus(din0){
|
bus(din0){
|
||||||
bus_type : data;
|
bus_type : data;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
memory_write(){
|
memory_write(){
|
||||||
address : addr0;
|
address : addr0;
|
||||||
clocked_on : clk0;
|
clocked_on : clk0;
|
||||||
|
|
@ -98,28 +110,28 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
rise_constraint(CONSTRAINT_TABLE) {
|
rise_constraint(CONSTRAINT_TABLE) {
|
||||||
values("0.167, 0.167, 0.228",\
|
values("0.009, 0.009, 0.009",\
|
||||||
"0.167, 0.167, 0.228",\
|
"0.009, 0.009, 0.009",\
|
||||||
"0.167, 0.167, 0.228");
|
"0.009, 0.009, 0.009");
|
||||||
}
|
}
|
||||||
fall_constraint(CONSTRAINT_TABLE) {
|
fall_constraint(CONSTRAINT_TABLE) {
|
||||||
values("0.131, 0.125, 0.137",\
|
values("0.009, 0.009, 0.009",\
|
||||||
"0.131, 0.125, 0.137",\
|
"0.009, 0.009, 0.009",\
|
||||||
"0.131, 0.125, 0.137");
|
"0.009, 0.009, 0.009");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : hold_rising;
|
timing_type : hold_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
rise_constraint(CONSTRAINT_TABLE) {
|
rise_constraint(CONSTRAINT_TABLE) {
|
||||||
values("-0.065, -0.071, -0.114",\
|
values("0.001, 0.001, 0.001",\
|
||||||
"-0.065, -0.071, -0.114",\
|
"0.001, 0.001, 0.001",\
|
||||||
"-0.065, -0.071, -0.114");
|
"0.001, 0.001, 0.001");
|
||||||
}
|
}
|
||||||
fall_constraint(CONSTRAINT_TABLE) {
|
fall_constraint(CONSTRAINT_TABLE) {
|
||||||
values("-0.089, -0.089, -0.089",\
|
values("0.001, 0.001, 0.001",\
|
||||||
"-0.089, -0.089, -0.089",\
|
"0.001, 0.001, 0.001",\
|
||||||
"-0.089, -0.089, -0.089");
|
"0.001, 0.001, 0.001");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -127,8 +139,8 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
bus(dout0){
|
bus(dout0){
|
||||||
bus_type : data;
|
bus_type : data;
|
||||||
direction : output;
|
direction : output;
|
||||||
max_capacitance : 78.5936;
|
max_capacitance : 0.0392968;
|
||||||
min_capacitance : 2.45605;
|
min_capacitance : 0.00245605;
|
||||||
memory_read(){
|
memory_read(){
|
||||||
address : addr0;
|
address : addr0;
|
||||||
}
|
}
|
||||||
|
|
@ -138,24 +150,24 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
timing_type : falling_edge;
|
timing_type : falling_edge;
|
||||||
cell_rise(CELL_TABLE) {
|
cell_rise(CELL_TABLE) {
|
||||||
values("1.556, 1.576, 1.751",\
|
values("1.314, 1.332, 1.404",\
|
||||||
"1.559, 1.579, 1.754",\
|
"1.314, 1.332, 1.404",\
|
||||||
"1.624, 1.643, 1.819");
|
"1.314, 1.332, 1.404");
|
||||||
}
|
}
|
||||||
cell_fall(CELL_TABLE) {
|
cell_fall(CELL_TABLE) {
|
||||||
values("3.445, 3.504, 3.926",\
|
values("1.314, 1.332, 1.404",\
|
||||||
"3.448, 3.507, 3.93",\
|
"1.314, 1.332, 1.404",\
|
||||||
"3.49, 3.549, 3.972");
|
"1.314, 1.332, 1.404");
|
||||||
}
|
}
|
||||||
rise_transition(CELL_TABLE) {
|
rise_transition(CELL_TABLE) {
|
||||||
values("0.13, 0.169, 0.574",\
|
values("0.006, 0.008, 0.015",\
|
||||||
"0.13, 0.169, 0.574",\
|
"0.006, 0.008, 0.015",\
|
||||||
"0.13, 0.169, 0.574");
|
"0.006, 0.008, 0.015");
|
||||||
}
|
}
|
||||||
fall_transition(CELL_TABLE) {
|
fall_transition(CELL_TABLE) {
|
||||||
values("0.467, 0.49, 0.959",\
|
values("0.006, 0.008, 0.015",\
|
||||||
"0.467, 0.49, 0.959",\
|
"0.006, 0.008, 0.015",\
|
||||||
"0.47, 0.493, 0.96");
|
"0.006, 0.008, 0.015");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -164,35 +176,35 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
bus(addr0){
|
bus(addr0){
|
||||||
bus_type : addr;
|
bus_type : addr;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
max_transition : 0.4;
|
max_transition : 0.4;
|
||||||
pin(addr0[3:0]){
|
pin(addr0[3:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
rise_constraint(CONSTRAINT_TABLE) {
|
rise_constraint(CONSTRAINT_TABLE) {
|
||||||
values("0.167, 0.167, 0.228",\
|
values("0.009, 0.009, 0.009",\
|
||||||
"0.167, 0.167, 0.228",\
|
"0.009, 0.009, 0.009",\
|
||||||
"0.167, 0.167, 0.228");
|
"0.009, 0.009, 0.009");
|
||||||
}
|
}
|
||||||
fall_constraint(CONSTRAINT_TABLE) {
|
fall_constraint(CONSTRAINT_TABLE) {
|
||||||
values("0.131, 0.125, 0.137",\
|
values("0.009, 0.009, 0.009",\
|
||||||
"0.131, 0.125, 0.137",\
|
"0.009, 0.009, 0.009",\
|
||||||
"0.131, 0.125, 0.137");
|
"0.009, 0.009, 0.009");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : hold_rising;
|
timing_type : hold_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
rise_constraint(CONSTRAINT_TABLE) {
|
rise_constraint(CONSTRAINT_TABLE) {
|
||||||
values("-0.065, -0.071, -0.114",\
|
values("0.001, 0.001, 0.001",\
|
||||||
"-0.065, -0.071, -0.114",\
|
"0.001, 0.001, 0.001",\
|
||||||
"-0.065, -0.071, -0.114");
|
"0.001, 0.001, 0.001");
|
||||||
}
|
}
|
||||||
fall_constraint(CONSTRAINT_TABLE) {
|
fall_constraint(CONSTRAINT_TABLE) {
|
||||||
values("-0.089, -0.089, -0.089",\
|
values("0.001, 0.001, 0.001",\
|
||||||
"-0.089, -0.089, -0.089",\
|
"0.001, 0.001, 0.001",\
|
||||||
"-0.089, -0.089, -0.089");
|
"0.001, 0.001, 0.001");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -200,66 +212,66 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
|
|
||||||
pin(csb0){
|
pin(csb0){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
rise_constraint(CONSTRAINT_TABLE) {
|
rise_constraint(CONSTRAINT_TABLE) {
|
||||||
values("0.167, 0.167, 0.228",\
|
values("0.009, 0.009, 0.009",\
|
||||||
"0.167, 0.167, 0.228",\
|
"0.009, 0.009, 0.009",\
|
||||||
"0.167, 0.167, 0.228");
|
"0.009, 0.009, 0.009");
|
||||||
}
|
}
|
||||||
fall_constraint(CONSTRAINT_TABLE) {
|
fall_constraint(CONSTRAINT_TABLE) {
|
||||||
values("0.131, 0.125, 0.137",\
|
values("0.009, 0.009, 0.009",\
|
||||||
"0.131, 0.125, 0.137",\
|
"0.009, 0.009, 0.009",\
|
||||||
"0.131, 0.125, 0.137");
|
"0.009, 0.009, 0.009");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : hold_rising;
|
timing_type : hold_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
rise_constraint(CONSTRAINT_TABLE) {
|
rise_constraint(CONSTRAINT_TABLE) {
|
||||||
values("-0.065, -0.071, -0.114",\
|
values("0.001, 0.001, 0.001",\
|
||||||
"-0.065, -0.071, -0.114",\
|
"0.001, 0.001, 0.001",\
|
||||||
"-0.065, -0.071, -0.114");
|
"0.001, 0.001, 0.001");
|
||||||
}
|
}
|
||||||
fall_constraint(CONSTRAINT_TABLE) {
|
fall_constraint(CONSTRAINT_TABLE) {
|
||||||
values("-0.089, -0.089, -0.089",\
|
values("0.001, 0.001, 0.001",\
|
||||||
"-0.089, -0.089, -0.089",\
|
"0.001, 0.001, 0.001",\
|
||||||
"-0.089, -0.089, -0.089");
|
"0.001, 0.001, 0.001");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pin(web0){
|
pin(web0){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
rise_constraint(CONSTRAINT_TABLE) {
|
rise_constraint(CONSTRAINT_TABLE) {
|
||||||
values("0.167, 0.167, 0.228",\
|
values("0.009, 0.009, 0.009",\
|
||||||
"0.167, 0.167, 0.228",\
|
"0.009, 0.009, 0.009",\
|
||||||
"0.167, 0.167, 0.228");
|
"0.009, 0.009, 0.009");
|
||||||
}
|
}
|
||||||
fall_constraint(CONSTRAINT_TABLE) {
|
fall_constraint(CONSTRAINT_TABLE) {
|
||||||
values("0.131, 0.125, 0.137",\
|
values("0.009, 0.009, 0.009",\
|
||||||
"0.131, 0.125, 0.137",\
|
"0.009, 0.009, 0.009",\
|
||||||
"0.131, 0.125, 0.137");
|
"0.009, 0.009, 0.009");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : hold_rising;
|
timing_type : hold_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
rise_constraint(CONSTRAINT_TABLE) {
|
rise_constraint(CONSTRAINT_TABLE) {
|
||||||
values("-0.065, -0.071, -0.114",\
|
values("0.001, 0.001, 0.001",\
|
||||||
"-0.065, -0.071, -0.114",\
|
"0.001, 0.001, 0.001",\
|
||||||
"-0.065, -0.071, -0.114");
|
"0.001, 0.001, 0.001");
|
||||||
}
|
}
|
||||||
fall_constraint(CONSTRAINT_TABLE) {
|
fall_constraint(CONSTRAINT_TABLE) {
|
||||||
values("-0.089, -0.089, -0.089",\
|
values("0.001, 0.001, 0.001",\
|
||||||
"-0.089, -0.089, -0.089",\
|
"0.001, 0.001, 0.001",\
|
||||||
"-0.089, -0.089, -0.089");
|
"0.001, 0.001, 0.001");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -267,52 +279,61 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
pin(clk0){
|
pin(clk0){
|
||||||
clock : true;
|
clock : true;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "!csb0 & clk0 & !web0";
|
when : "!csb0 & !web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("9.972790277777777");
|
values("7.017537e+00");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("9.972790277777777");
|
values("7.017537e+00");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "!csb0 & !clk0 & web0";
|
when : "csb0 & !web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("8.899322499999998");
|
values("7.017537e+00");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("8.899322499999998");
|
values("7.017537e+00");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "csb0";
|
when : "!csb0 & web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("0");
|
values("7.017537e+00");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("0");
|
values("7.017537e+00");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal_power(){
|
||||||
|
when : "csb0 & web0";
|
||||||
|
rise_power(scalar){
|
||||||
|
values("7.017537e+00");
|
||||||
|
}
|
||||||
|
fall_power(scalar){
|
||||||
|
values("7.017537e+00");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type :"min_pulse_width";
|
timing_type :"min_pulse_width";
|
||||||
related_pin : clk0;
|
related_pin : clk0;
|
||||||
rise_constraint(scalar) {
|
rise_constraint(scalar) {
|
||||||
values("2.344");
|
values("0.1405");
|
||||||
}
|
}
|
||||||
fall_constraint(scalar) {
|
fall_constraint(scalar) {
|
||||||
values("2.344");
|
values("0.1405");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type :"minimum_period";
|
timing_type :"minimum_period";
|
||||||
related_pin : clk0;
|
related_pin : clk0;
|
||||||
rise_constraint(scalar) {
|
rise_constraint(scalar) {
|
||||||
values("4.688");
|
values("0.281");
|
||||||
}
|
}
|
||||||
fall_constraint(scalar) {
|
fall_constraint(scalar) {
|
||||||
values("4.688");
|
values("0.281");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,11 +35,14 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){
|
||||||
default_max_fanout : 4.0 ;
|
default_max_fanout : 4.0 ;
|
||||||
default_connection_class : universal ;
|
default_connection_class : universal ;
|
||||||
|
|
||||||
|
voltage_map ( VDD, 5.0 );
|
||||||
|
voltage_map ( GND, 0 );
|
||||||
|
|
||||||
lu_table_template(CELL_TABLE){
|
lu_table_template(CELL_TABLE){
|
||||||
variable_1 : input_net_transition;
|
variable_1 : input_net_transition;
|
||||||
variable_2 : total_output_net_capacitance;
|
variable_2 : total_output_net_capacitance;
|
||||||
index_1("0.0125, 0.05, 0.4");
|
index_1("0.0125, 0.05, 0.4");
|
||||||
index_2("2.45605, 9.8242, 78.5936");
|
index_2("0.00245605, 0.0098242, 0.0392968");
|
||||||
}
|
}
|
||||||
|
|
||||||
lu_table_template(CONSTRAINT_TABLE){
|
lu_table_template(CONSTRAINT_TABLE){
|
||||||
|
|
@ -78,17 +81,26 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
dont_use : true;
|
dont_use : true;
|
||||||
map_only : true;
|
map_only : true;
|
||||||
dont_touch : true;
|
dont_touch : true;
|
||||||
area : 60774.3;
|
area : 0;
|
||||||
|
|
||||||
|
pg_pin(vdd) {
|
||||||
|
voltage_name : VDD;
|
||||||
|
pg_type : primary_power;
|
||||||
|
}
|
||||||
|
|
||||||
|
pg_pin(gnd) {
|
||||||
|
voltage_name : GND;
|
||||||
|
pg_type : primary_ground;
|
||||||
|
}
|
||||||
|
|
||||||
leakage_power () {
|
leakage_power () {
|
||||||
when : "csb0";
|
value : 0.000198;
|
||||||
value : 0.000179;
|
|
||||||
}
|
}
|
||||||
cell_leakage_power : 0;
|
cell_leakage_power : 0.000198;
|
||||||
bus(din0){
|
bus(din0){
|
||||||
bus_type : data;
|
bus_type : data;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
memory_write(){
|
memory_write(){
|
||||||
address : addr0;
|
address : addr0;
|
||||||
clocked_on : clk0;
|
clocked_on : clk0;
|
||||||
|
|
@ -127,8 +139,8 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
bus(dout0){
|
bus(dout0){
|
||||||
bus_type : data;
|
bus_type : data;
|
||||||
direction : output;
|
direction : output;
|
||||||
max_capacitance : 78.5936;
|
max_capacitance : 0.0392968;
|
||||||
min_capacitance : 2.45605;
|
min_capacitance : 0.00245605;
|
||||||
memory_read(){
|
memory_read(){
|
||||||
address : addr0;
|
address : addr0;
|
||||||
}
|
}
|
||||||
|
|
@ -138,24 +150,24 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
timing_type : falling_edge;
|
timing_type : falling_edge;
|
||||||
cell_rise(CELL_TABLE) {
|
cell_rise(CELL_TABLE) {
|
||||||
values("0.268, 0.268, 0.268",\
|
values("1.314, 1.332, 1.404",\
|
||||||
"0.268, 0.268, 0.268",\
|
"1.314, 1.332, 1.404",\
|
||||||
"0.268, 0.268, 0.268");
|
"1.314, 1.332, 1.404");
|
||||||
}
|
}
|
||||||
cell_fall(CELL_TABLE) {
|
cell_fall(CELL_TABLE) {
|
||||||
values("0.268, 0.268, 0.268",\
|
values("1.314, 1.332, 1.404",\
|
||||||
"0.268, 0.268, 0.268",\
|
"1.314, 1.332, 1.404",\
|
||||||
"0.268, 0.268, 0.268");
|
"1.314, 1.332, 1.404");
|
||||||
}
|
}
|
||||||
rise_transition(CELL_TABLE) {
|
rise_transition(CELL_TABLE) {
|
||||||
values("0.004, 0.004, 0.004",\
|
values("0.006, 0.008, 0.015",\
|
||||||
"0.004, 0.004, 0.004",\
|
"0.006, 0.008, 0.015",\
|
||||||
"0.004, 0.004, 0.004");
|
"0.006, 0.008, 0.015");
|
||||||
}
|
}
|
||||||
fall_transition(CELL_TABLE) {
|
fall_transition(CELL_TABLE) {
|
||||||
values("0.004, 0.004, 0.004",\
|
values("0.006, 0.008, 0.015",\
|
||||||
"0.004, 0.004, 0.004",\
|
"0.006, 0.008, 0.015",\
|
||||||
"0.004, 0.004, 0.004");
|
"0.006, 0.008, 0.015");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -164,7 +176,7 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
bus(addr0){
|
bus(addr0){
|
||||||
bus_type : addr;
|
bus_type : addr;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
max_transition : 0.4;
|
max_transition : 0.4;
|
||||||
pin(addr0[3:0]){
|
pin(addr0[3:0]){
|
||||||
timing(){
|
timing(){
|
||||||
|
|
@ -200,7 +212,7 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
|
|
||||||
pin(csb0){
|
pin(csb0){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -233,7 +245,7 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
|
|
||||||
pin(web0){
|
pin(web0){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -267,52 +279,61 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
pin(clk0){
|
pin(clk0){
|
||||||
clock : true;
|
clock : true;
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 0.0098242;
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "!csb0 & clk0 & !web0";
|
when : "!csb0 & !web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("11.3049604371");
|
values("7.017537e+00");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("11.3049604371");
|
values("7.017537e+00");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "!csb0 & !clk0 & web0";
|
when : "csb0 & !web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("11.3049604371");
|
values("7.017537e+00");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("11.3049604371");
|
values("7.017537e+00");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal_power(){
|
internal_power(){
|
||||||
when : "csb0";
|
when : "!csb0 & web0";
|
||||||
rise_power(scalar){
|
rise_power(scalar){
|
||||||
values("0");
|
values("7.017537e+00");
|
||||||
}
|
}
|
||||||
fall_power(scalar){
|
fall_power(scalar){
|
||||||
values("0");
|
values("7.017537e+00");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal_power(){
|
||||||
|
when : "csb0 & web0";
|
||||||
|
rise_power(scalar){
|
||||||
|
values("7.017537e+00");
|
||||||
|
}
|
||||||
|
fall_power(scalar){
|
||||||
|
values("7.017537e+00");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type :"min_pulse_width";
|
timing_type :"min_pulse_width";
|
||||||
related_pin : clk0;
|
related_pin : clk0;
|
||||||
rise_constraint(scalar) {
|
rise_constraint(scalar) {
|
||||||
values("0.0");
|
values("0.1405");
|
||||||
}
|
}
|
||||||
fall_constraint(scalar) {
|
fall_constraint(scalar) {
|
||||||
values("0.0");
|
values("0.1405");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timing(){
|
timing(){
|
||||||
timing_type :"minimum_period";
|
timing_type :"minimum_period";
|
||||||
related_pin : clk0;
|
related_pin : clk0;
|
||||||
rise_constraint(scalar) {
|
rise_constraint(scalar) {
|
||||||
values("0");
|
values("0.281");
|
||||||
}
|
}
|
||||||
fall_constraint(scalar) {
|
fall_constraint(scalar) {
|
||||||
values("0");
|
values("0.281");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,27 +39,40 @@ class openram_test(unittest.TestCase):
|
||||||
tempspice = "{0}{1}.sp".format(OPTS.openram_temp,a.name)
|
tempspice = "{0}{1}.sp".format(OPTS.openram_temp,a.name)
|
||||||
tempgds = "{0}{1}.gds".format(OPTS.openram_temp,a.name)
|
tempgds = "{0}{1}.gds".format(OPTS.openram_temp,a.name)
|
||||||
|
|
||||||
a.sp_write(tempspice)
|
a.lvs_write(tempspice)
|
||||||
# cannot write gds in netlist_only mode
|
# cannot write gds in netlist_only mode
|
||||||
if not OPTS.netlist_only:
|
if not OPTS.netlist_only:
|
||||||
a.gds_write(tempgds)
|
a.gds_write(tempgds)
|
||||||
|
|
||||||
import verify
|
import verify
|
||||||
result=verify.run_drc(a.name, tempgds, extract=True, final_verification=final_verification)
|
# Run both DRC and LVS even if DRC might fail
|
||||||
if result != 0:
|
# 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)
|
||||||
|
|
||||||
|
# Always run LVS if we are using magic
|
||||||
|
if "magic" in OPTS.drc_exe or drc_result == 0:
|
||||||
|
lvs_result=verify.run_lvs(a.name, tempgds, tempspice, final_verification=final_verification)
|
||||||
|
|
||||||
|
# Only allow DRC to fail and LVS to pass if we are using magic
|
||||||
|
if "magic" in OPTS.drc_exe and lvs_result == 0 and drc_result != 0:
|
||||||
|
#zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid())
|
||||||
|
#debug.info(0,"Archiving failed files to {}.zip".format(zip_file))
|
||||||
|
#shutil.make_archive(zip_file, 'zip', OPTS.openram_temp)
|
||||||
|
debug.warning("DRC failed but LVS passed: {}".format(a.name))
|
||||||
|
elif drc_result != 0:
|
||||||
#zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid())
|
#zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid())
|
||||||
#debug.info(0,"Archiving failed files to {}.zip".format(zip_file))
|
#debug.info(0,"Archiving failed files to {}.zip".format(zip_file))
|
||||||
#shutil.make_archive(zip_file, 'zip', OPTS.openram_temp)
|
#shutil.make_archive(zip_file, 'zip', OPTS.openram_temp)
|
||||||
self.fail("DRC failed: {}".format(a.name))
|
self.fail("DRC failed: {}".format(a.name))
|
||||||
|
|
||||||
|
if lvs_result != 0:
|
||||||
result=verify.run_lvs(a.name, tempgds, tempspice, final_verification=final_verification)
|
|
||||||
if result != 0:
|
|
||||||
#zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid())
|
#zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid())
|
||||||
#debug.info(0,"Archiving failed files to {}.zip".format(zip_file))
|
#debug.info(0,"Archiving failed files to {}.zip".format(zip_file))
|
||||||
#shutil.make_archive(zip_file, 'zip', OPTS.openram_temp)
|
#shutil.make_archive(zip_file, 'zip', OPTS.openram_temp)
|
||||||
self.fail("LVS mismatch: {}".format(a.name))
|
self.fail("LVS mismatch: {}".format(a.name))
|
||||||
|
|
||||||
|
|
||||||
# For debug...
|
# For debug...
|
||||||
#import pdb; pdb.set_trace()
|
#import pdb; pdb.set_trace()
|
||||||
if OPTS.purge_temp:
|
if OPTS.purge_temp:
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ and include its appropriate license.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import time
|
|
||||||
import shutil
|
import shutil
|
||||||
import debug
|
import debug
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
|
@ -68,6 +67,9 @@ def write_magic_script(cell_name, extract=False, final_verification=False):
|
||||||
pre = ""
|
pre = ""
|
||||||
if final_verification:
|
if final_verification:
|
||||||
f.write(pre + "extract unique all\n".format(cell_name))
|
f.write(pre + "extract unique all\n".format(cell_name))
|
||||||
|
# Hack to work around unit scales in SkyWater
|
||||||
|
if OPTS.tech_name=="s8":
|
||||||
|
f.write(pre + "extract style ngspice(si)\n")
|
||||||
f.write(pre + "extract\n".format(cell_name))
|
f.write(pre + "extract\n".format(cell_name))
|
||||||
# f.write(pre + "ext2spice hierarchy on\n")
|
# f.write(pre + "ext2spice hierarchy on\n")
|
||||||
# f.write(pre + "ext2spice scale off\n")
|
# f.write(pre + "ext2spice scale off\n")
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ drc_warned = False
|
||||||
lvs_warned = False
|
lvs_warned = False
|
||||||
pex_warned = False
|
pex_warned = False
|
||||||
|
|
||||||
|
|
||||||
def run_drc(cell_name, gds_name, extract=False, final_verification=False):
|
def run_drc(cell_name, gds_name, extract=False, final_verification=False):
|
||||||
global drc_warned
|
global drc_warned
|
||||||
if not drc_warned:
|
if not drc_warned:
|
||||||
|
|
@ -24,6 +25,7 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False):
|
||||||
# Since we warned, return a failing test.
|
# Since we warned, return a failing test.
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
|
def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
|
||||||
global lvs_warned
|
global lvs_warned
|
||||||
if not lvs_warned:
|
if not lvs_warned:
|
||||||
|
|
@ -32,6 +34,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
|
||||||
# Since we warned, return a failing test.
|
# Since we warned, return a failing test.
|
||||||
return 1
|
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):
|
||||||
global pex_warned
|
global pex_warned
|
||||||
if not pex_warned:
|
if not pex_warned:
|
||||||
|
|
@ -40,9 +43,14 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
|
||||||
# Since we warned, return a failing test.
|
# Since we warned, return a failing test.
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def print_drc_stats():
|
def print_drc_stats():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def print_lvs_stats():
|
def print_lvs_stats():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def print_pex_stats():
|
def print_pex_stats():
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue