Merge branch 'dev' into bisr

This commit is contained in:
Aditi Sinha 2020-05-02 07:48:35 +00:00
commit 2498ff07ea
96 changed files with 3358 additions and 1983 deletions

2
.gitignore vendored
View File

@ -8,3 +8,5 @@
*.toc *.toc
*.synctex.gz *.synctex.gz
**/model_data **/model_data
outputs
technology/freepdk45/ncsu_basekit

15
compiler/base/errors.py Normal file
View File

@ -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

View File

@ -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) + " )"

View File

@ -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

View File

@ -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):
""" """

View File

@ -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)

View File

@ -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

View File

@ -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 \

View File

@ -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,

View File

@ -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

View File

@ -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.

View File

@ -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))

View File

@ -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.

View File

@ -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.

View File

@ -6,6 +6,7 @@
# All rights reserved. # All rights reserved.
# #
class drc_value(): class drc_value():
""" """
A single DRC value. A single DRC value.

View File

@ -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"

View File

@ -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()

View File

@ -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()

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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 """

View File

@ -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}",

View File

@ -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")

View File

@ -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"""

View File

@ -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):

View File

@ -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

View File

@ -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.

View File

@ -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):

View File

@ -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):

View File

@ -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")

View File

@ -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")

View File

@ -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)

View File

@ -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. """

View File

@ -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()

View File

@ -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",

View File

@ -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)

View File

@ -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,

View File

@ -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

View File

@ -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 """

View File

@ -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"""

View File

@ -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")

View File

@ -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)

View File

@ -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)

View File

@ -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 = []

View File

@ -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)

View File

@ -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):

View File

@ -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())

View File

@ -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

View File

@ -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())

View File

@ -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

View File

@ -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"))

View File

@ -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())

View File

@ -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()

View File

@ -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())

View File

@ -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

View File

@ -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())

View File

@ -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

View File

@ -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())

View File

@ -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()

View File

@ -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())

View File

@ -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

View File

@ -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())

View File

@ -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

View File

@ -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

View File

@ -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())

View File

@ -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())

View File

@ -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

View File

@ -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())

View File

@ -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()

View File

@ -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())

View File

@ -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()

View File

@ -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())

View File

@ -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

View File

@ -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())

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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):

View File

@ -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):

View File

@ -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");
} }
} }
} }

View File

@ -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");
} }
} }
} }

View File

@ -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");
} }
} }
} }

View File

@ -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");
} }
} }
} }

View File

@ -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");
} }
} }
} }

View File

@ -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");
} }
} }
} }

View File

@ -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");
} }
} }
} }

View File

@ -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");
} }
} }
} }

View File

@ -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:

View File

@ -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")

View File

@ -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