Merge remote-tracking branch 'private/dev' into dev

This commit is contained in:
Matt Guthaus 2019-01-28 17:08:52 -08:00
commit 78a857d0df
123 changed files with 1286 additions and 1462 deletions

44
LICENSE
View File

@ -1,31 +1,31 @@
Copyright 2018 Regents of the University of California and The Board BSD 3-Clause License
Copyright (c) 2019 Regents of the University of California and The Board
of Regents for the Oklahoma Agricultural and Mechanical College of Regents for the Oklahoma Agricultural and Mechanical College
(acting for and on behalf of Oklahoma State University) (acting for and on behalf of Oklahoma State University)
All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are met:
met:
1. Redistributions of source code must retain the above copyright * Redistributions of source code must retain the above copyright notice, this
notice, this list of conditions and the following disclaimer. list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright * Redistributions in binary form must reproduce the above copyright notice,
notice, this list of conditions and the following disclaimer in the this list of conditions and the following disclaimer in the documentation
documentation and/or other materials provided with the distribution. and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its * Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from contributors may be used to endorse or promote products derived from
this software without specific prior written permission. this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -132,7 +132,7 @@ To increase the verbosity of the test, add one (or more) -v options:
python3 tests/00_code_format_check_test.py -v -t freepdk45 python3 tests/00_code_format_check_test.py -v -t freepdk45
``` ```
To specify a particular technology use "-t <techname>" such as To specify a particular technology use "-t <techname>" such as
"-t freepdk45" or "-t scn4m\_subm". The default for a unit test is scn4m_subm. "-t freepdk45". The default for a unit test is scn4m_subm.
The default for openram.py is specified in the configuration file. The default for openram.py is specified in the configuration file.
@ -163,7 +163,7 @@ Each specific technology (e.g., [FreePDK45]) should be a subdirectory
* replica\_cell\_6t.gds * replica\_cell\_6t.gds
* sp_lib folder with all the .sp (premade) library netlists for the above cells. * sp_lib folder with all the .sp (premade) library netlists for the above cells.
* layers.map * layers.map
* A valid tech Python module (tech directory with __init__.py and tech.py) with: * A valid tech Python module (tech directory with \_\_init\_\_.py and tech.py) with:
* References in tech.py to spice models * References in tech.py to spice models
* DRC/LVS rules needed for dynamic cells and routing * DRC/LVS rules needed for dynamic cells and routing
* Layer information * Layer information

View File

@ -16,7 +16,9 @@ class contact(hierarchy_design.hierarchy_design):
hierarchy as the contact. hierarchy as the contact.
""" """
def __init__(self, layer_stack, dimensions=[1,1], implant_type=None, well_type=None): def __init__(self, layer_stack, dimensions=[1,1], implant_type=None, well_type=None, name=""):
# This will ignore the name parameter since we can guarantee a unique name here
if implant_type or well_type: if implant_type or well_type:
name = "{0}_{1}_{2}_{3}x{4}_{5}{6}".format(layer_stack[0], name = "{0}_{1}_{2}_{3}x{4}_{5}{6}".format(layer_stack[0],
layer_stack[1], layer_stack[1],
@ -164,13 +166,13 @@ class contact(hierarchy_design.hierarchy_design):
""" Get total power of a module """ """ Get total power of a module """
return self.return_power() return self.return_power()
from sram_factory import factory
# This is not instantiated and used for calculations only. # This is not instantiated and used for calculations only.
# These are static 1x1 contacts to reuse in all the design modules. # These are static 1x1 contacts to reuse in all the design modules.
well = contact(layer_stack=("active", "contact", "metal1")) well = factory.create(module_type="contact", layer_stack=("active", "contact", "metal1"))
active = contact(layer_stack=("active", "contact", "poly")) active = factory.create(module_type="contact", layer_stack=("active", "contact", "poly"))
poly = contact(layer_stack=("poly", "contact", "metal1")) poly = factory.create(module_type="contact", layer_stack=("poly", "contact", "metal1"))
m1m2 = contact(layer_stack=("metal1", "via1", "metal2")) m1m2 = factory.create(module_type="contact", layer_stack=("metal1", "via1", "metal2"))
m2m3 = contact(layer_stack=("metal2", "via2", "metal3")) m2m3 = factory.create(module_type="contact", layer_stack=("metal2", "via2", "metal3"))
m3m4 = contact(layer_stack=("metal3", "via3", "metal4")) m3m4 = factory.create(module_type="contact", layer_stack=("metal3", "via3", "metal4"))

View File

@ -6,7 +6,6 @@ import debug
import os import os
from globals import OPTS from globals import OPTS
class design(hierarchy_design): class design(hierarchy_design):
""" """
This is the same as the hierarchy_design class except it contains This is the same as the hierarchy_design class except it contains

View File

@ -17,20 +17,14 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
name_map = [] name_map = []
def __init__(self, name): def __init__(self, name):
try: self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds"
self.gds_file self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp"
except AttributeError:
self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds"
try:
self.sp_file
except AttributeError:
self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp"
self.name = name self.name = name
hierarchy_layout.layout.__init__(self, name) hierarchy_layout.layout.__init__(self, name)
hierarchy_spice.spice.__init__(self, name) hierarchy_spice.spice.__init__(self, name)
# Check if the name already exists, if so, give an error # Check if the name already exists, if so, give an error
# because each reference must be a unique name. # because each reference must be a unique name.
# These modules ensure unique names or have no changes if they # These modules ensure unique names or have no changes if they

View File

@ -320,17 +320,17 @@ class layout():
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 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 # negative layers indicate "unused" layers in a given technology
#layer_num = techlayer[layer] #layer_num = techlayer[layer]
#if layer_num >= 0: #if layer_num >= 0:
# self.objs.append(geometry.path(layer_num, coordinates, width)) # self.objs.append(geometry.path(layer_num, coordinates, width))
path.path(obj=self, wire_path.wire_path(obj=self,
layer=layer, layer=layer,
position_list=coordinates, position_list=coordinates,
width=width) width=width)
def add_route(self, layers, coordinates, layer_widths): def add_route(self, layers, coordinates, layer_widths):
"""Connects a routing path on given layer,coordinates,width. The """Connects a routing path on given layer,coordinates,width. The
@ -378,11 +378,12 @@ class layout():
def add_via(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None): def add_via(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
""" Add a three layer via structure. """ """ Add a three layer via structure. """
import contact from sram_factory import factory
via = contact.contact(layer_stack=layers, via = factory.create(module_type="contact",
dimensions=size, layer_stack=layers,
implant_type=implant_type, dimensions=size,
well_type=well_type) implant_type=implant_type,
well_type=well_type)
self.add_mod(via) self.add_mod(via)
inst=self.add_inst(name=via.name, inst=self.add_inst(name=via.name,
mod=via, mod=via,
@ -395,11 +396,12 @@ class layout():
def add_via_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None): def add_via_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
""" Add a three layer via structure by the center coordinate accounting for mirroring and rotation. """ """ Add a three layer via structure by the center coordinate accounting for mirroring and rotation. """
import contact from sram_factory import factory
via = contact.contact(layer_stack=layers, via = factory.create(module_type="contact",
dimensions=size, layer_stack=layers,
implant_type=implant_type, dimensions=size,
well_type=well_type) implant_type=implant_type,
well_type=well_type)
height = via.height height = via.height
width = via.width width = via.width
debug.check(mirror=="R0","Use rotate to rotate vias instead of mirror.") debug.check(mirror=="R0","Use rotate to rotate vias instead of mirror.")
@ -1039,9 +1041,11 @@ class layout():
# Find the number of vias for this pitch # Find the number of vias for this pitch
self.supply_vias = 1 self.supply_vias = 1
import contact from sram_factory import factory
while True: while True:
c=contact.contact(("metal1","via1","metal2"), (self.supply_vias, self.supply_vias)) c=factory.create(module_type="contact",
layer_stack=("metal1","via1","metal2"),
dimensions=(self.supply_vias, self.supply_vias))
if c.second_layer_width < self.supply_rail_width and c.second_layer_height < self.supply_rail_width: if c.second_layer_width < self.supply_rail_width and c.second_layer_height < self.supply_rail_width:
self.supply_vias += 1 self.supply_vias += 1
else: else:

View File

@ -16,13 +16,18 @@ class spice():
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
self.mods = [] # Holds subckts/mods for this module # Holds subckts/mods for this module
self.pins = [] # Holds the pins for this module self.mods = []
self.pin_type = {} # The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND # Holds the pins for this module
self.pins = []
# The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND
# for each instance, this is the set of nets/nodes that map to the pins for this instance # for each instance, this is the set of nets/nodes that map to the pins for this instance
# THIS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the self.pin_type = {}
# THE CONNECTIONS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the
# Spice format) # Spice format)
self.conns = [] self.conns = []
# Keep track of any comments to add the the spice
self.comments = []
self.sp_read() self.sp_read()
@ -30,6 +35,10 @@ class spice():
# Spice circuit # Spice circuit
############################################################ ############################################################
def add_comment(self, comment):
""" Add a comment to the spice file """
self.comments.append(comment)
def add_pin(self, name, pin_type="INOUT"): def add_pin(self, name, pin_type="INOUT"):
""" Adds a pin to the pins list. Default type is INOUT signal. """ """ Adds a pin to the pins list. Default type is INOUT signal. """
self.pins.append(name) self.pins.append(name)
@ -93,8 +102,8 @@ class spice():
from pprint import pformat from pprint import pformat
modpins_string=pformat(self.insts[-1].mod.pins) modpins_string=pformat(self.insts[-1].mod.pins)
argpins_string=pformat(args) argpins_string=pformat(args)
debug.error("Connections: {}".format(modpins_string)) debug.error("Mod connections: {}".format(modpins_string))
debug.error("Connections: {}".format(argpins_string)) debug.error("Inst connections: {}".format(argpins_string))
debug.error("Number of net connections ({0}) does not match last instance ({1})".format(len(self.insts[-1].mod.pins), debug.error("Number of net connections ({0}) does not match last instance ({1})".format(len(self.insts[-1].mod.pins),
len(args)), 1) len(args)), 1)
self.conns.append(args) self.conns.append(args)
@ -159,6 +168,9 @@ class spice():
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)))
for line in self.comments:
sp.write("* {}\n".format(line))
# every instance must have a set of connections, even if it is empty. # every instance must have a set of connections, even if it is empty.
if len(self.insts)!=len(self.conns): if len(self.insts)!=len(self.conns):
debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name, debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name,

View File

@ -1,10 +1,10 @@
from tech import drc from tech import drc
import debug import debug
from design import design from design import design
from contact import contact
from itertools import tee from itertools import tee
from vector import vector from vector import vector
from vector3d import vector3d from vector3d import vector3d
from sram_factory import factory
class route(design): class route(design):
""" """
@ -45,7 +45,9 @@ class route(design):
self.horiz_layer_width = drc("minwidth_{0}".format(self.horiz_layer_name)) self.horiz_layer_width = drc("minwidth_{0}".format(self.horiz_layer_name))
# offset this by 1/2 the via size # offset this by 1/2 the via size
self.c=contact(self.layer_stack, (self.num_vias, self.num_vias)) self.c=factory.create(module_type="contact",
layer_stack=self.layer_stack,
dimensions=(self.num_vias, self.num_vias))
def create_wires(self): def create_wires(self):

View File

@ -1,9 +1,9 @@
from tech import drc from tech import drc
import debug import debug
from contact import contact from wire_path import wire_path
from path import path from sram_factory import factory
class wire(path): class wire(wire_path):
""" """
Object metal wire; given the layer type Object metal wire; given the layer type
Add a wire of minimium metal width between a set of points. Add a wire of minimium metal width between a set of points.
@ -26,7 +26,7 @@ class wire(path):
self.create_rectilinear() self.create_rectilinear()
self.create_vias() self.create_vias()
self.create_rectangles() self.create_rectangles()
# wires and 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
@ -37,15 +37,18 @@ class wire(path):
self.horiz_layer_name = horiz_layer self.horiz_layer_name = horiz_layer
self.horiz_layer_width = drc("minwidth_{0}".format(horiz_layer)) self.horiz_layer_width = drc("minwidth_{0}".format(horiz_layer))
via_connect = contact(self.layer_stack, via_connect = factory.create(module_type="contact",
(1, 1)) layer_stack=self.layer_stack,
dimensions=(1, 1))
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]
# create a 1x1 contact # create a 1x1 contact
def create_vias(self): def create_vias(self):
""" Add a via and corner square at every corner of the path.""" """ Add a via and corner square at every corner of the path."""
self.c=contact(self.layer_stack, (1, 1)) self.c=factory.create(module_type="contact",
layer_stack=self.layer_stack,
dimensions=(1, 1))
c_width = self.c.width c_width = self.c.width
c_height = self.c.height c_height = self.c.height

View File

@ -18,12 +18,12 @@ def create_rectilinear_route(my_list):
my_list.append(vector(pl[-1])) my_list.append(vector(pl[-1]))
return my_list return my_list
class path(): class wire_path():
""" """
Object metal path; given the layer type Object metal wire_path; given the layer type
Add a path of minimium metal width between a set of points. Add a wire_path of minimium metal width between a set of points.
The points should be rectilinear to control the bend points. If The points should be rectilinear to control the bend points. If
not, it will always go down first. The points are the center of the path. not, it will always go down first. The points are the center of the wire_path.
If width is not given, it uses minimum layer width. If width is not given, it uses minimum layer width.
""" """
def __init__(self, obj, layer, position_list, width=None): def __init__(self, obj, layer, position_list, width=None):
@ -44,7 +44,7 @@ class path():
self.create_rectilinear() self.create_rectilinear()
self.connect_corner() self.connect_corner()
self.create_rectangles() self.create_rectangles()
# wires and paths should not be offset to (0,0) # wires and wire_paths should not be offset to (0,0)
def create_rectilinear(self): def create_rectilinear(self):
""" Add intermediate nodes if it isn't rectilinear. Also skip """ Add intermediate nodes if it isn't rectilinear. Also skip
@ -52,7 +52,7 @@ class path():
self.position_list = create_rectilinear_route(self.position_list) self.position_list = create_rectilinear_route(self.position_list)
def connect_corner(self): def connect_corner(self):
""" Add a corner square at every corner of the path.""" """ Add a corner square at every corner of the wire_path."""
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)

View File

@ -15,14 +15,15 @@ class bitcell(design.design):
(width,height) = utils.get_libcell_size("cell_6t", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("cell_6t", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "cell_6t", GDS["unit"]) pin_map = utils.get_libcell_pins(pin_names, "cell_6t", GDS["unit"])
def __init__(self): def __init__(self, name=""):
# Ignore the name argument
design.design.__init__(self, "cell_6t") design.design.__init__(self, "cell_6t")
debug.info(2, "Create bitcell") debug.info(2, "Create bitcell")
self.width = bitcell.width self.width = bitcell.width
self.height = bitcell.height self.height = bitcell.height
self.pin_map = bitcell.pin_map self.pin_map = bitcell.pin_map
def analytical_delay(self, slew, load=0, swing = 0.5): def analytical_delay(self, slew, load=0, swing = 0.5):
# delay of bit cell is not like a driver(from WL) # delay of bit cell is not like a driver(from WL)
# so the slew used should be 0 # so the slew used should be 0

View File

@ -15,7 +15,8 @@ class bitcell_1rw_1r(design.design):
(width,height) = utils.get_libcell_size("cell_1rw_1r", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("cell_1rw_1r", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "cell_1rw_1r", GDS["unit"]) pin_map = utils.get_libcell_pins(pin_names, "cell_1rw_1r", GDS["unit"])
def __init__(self): def __init__(self, name=""):
# Ignore the name argument
design.design.__init__(self, "cell_1rw_1r") design.design.__init__(self, "cell_1rw_1r")
debug.info(2, "Create bitcell with 1RW and 1R Port") debug.info(2, "Create bitcell with 1RW and 1R Port")
@ -102,4 +103,4 @@ class bitcell_1rw_1r(design.design):
#Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width. #Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
#FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed. #FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"] access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin return 2*access_tx_cin

View File

@ -12,8 +12,7 @@ class pbitcell(design.design):
with a variable number of read/write, write, and read ports with a variable number of read/write, write, and read ports
""" """
def __init__(self, replica_bitcell=False): def __init__(self, name, replica_bitcell=False):
self.num_rw_ports = OPTS.num_rw_ports self.num_rw_ports = OPTS.num_rw_ports
self.num_w_ports = OPTS.num_w_ports self.num_w_ports = OPTS.num_w_ports
self.num_r_ports = OPTS.num_r_ports self.num_r_ports = OPTS.num_r_ports
@ -21,11 +20,6 @@ class pbitcell(design.design):
self.replica_bitcell = replica_bitcell self.replica_bitcell = replica_bitcell
if self.replica_bitcell:
name = "replica_pbitcell_{0}RW_{1}W_{2}R".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports)
else:
name = "pbitcell_{0}RW_{1}W_{2}R".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports)
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(2, "create a multi-port bitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports, debug.info(2, "create a multi-port bitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports,
self.num_w_ports, self.num_w_ports,

View File

@ -14,7 +14,8 @@ class replica_bitcell(design.design):
(width,height) = utils.get_libcell_size("replica_cell_6t", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("replica_cell_6t", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_6t", GDS["unit"]) pin_map = utils.get_libcell_pins(pin_names, "replica_cell_6t", GDS["unit"])
def __init__(self): def __init__(self, name=""):
# Ignore the name argument
design.design.__init__(self, "replica_cell_6t") design.design.__init__(self, "replica_cell_6t")
debug.info(2, "Create replica bitcell object") debug.info(2, "Create replica bitcell object")
@ -27,4 +28,4 @@ class replica_bitcell(design.design):
#This is a handmade cell so the value must be entered in the tech.py file or estimated. #This is a handmade cell so the value must be entered in the tech.py file or estimated.
#Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width. #Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"] access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin return 2*access_tx_cin

View File

@ -14,7 +14,8 @@ class replica_bitcell_1rw_1r(design.design):
(width,height) = utils.get_libcell_size("replica_cell_1rw_1r", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("replica_cell_1rw_1r", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_1rw_1r", GDS["unit"]) pin_map = utils.get_libcell_pins(pin_names, "replica_cell_1rw_1r", GDS["unit"])
def __init__(self): def __init__(self, name=""):
# Ignore the name argument
design.design.__init__(self, "replica_cell_1rw_1r") design.design.__init__(self, "replica_cell_1rw_1r")
debug.info(2, "Create replica bitcell 1rw+1r object") debug.info(2, "Create replica bitcell 1rw+1r object")
@ -28,4 +29,4 @@ class replica_bitcell_1rw_1r(design.design):
#Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width. #Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
#FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed. #FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"] access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin return 2*access_tx_cin

View File

@ -3,21 +3,20 @@ import design
from tech import drc, spice,parameter from tech import drc, spice,parameter
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from pbitcell import pbitcell from sram_factory import factory
class replica_pbitcell(design.design): class replica_pbitcell(design.design):
""" """
Creates a replica bitcell using pbitcell Creates a replica bitcell using pbitcell
""" """
def __init__(self): def __init__(self, name):
self.num_rw_ports = OPTS.num_rw_ports self.num_rw_ports = OPTS.num_rw_ports
self.num_w_ports = OPTS.num_w_ports self.num_w_ports = OPTS.num_w_ports
self.num_r_ports = OPTS.num_r_ports self.num_r_ports = OPTS.num_r_ports
self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports
design.design.__init__(self, "replica_pbitcell") design.design.__init__(self, name)
debug.info(1, "create a replica bitcell using pbitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports, debug.info(1, "create a replica bitcell using pbitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports,
self.num_w_ports, self.num_w_ports,
self.num_r_ports)) self.num_r_ports))
@ -47,7 +46,7 @@ class replica_pbitcell(design.design):
self.add_pin("gnd") self.add_pin("gnd")
def add_modules(self): def add_modules(self):
self.prbc = pbitcell(replica_bitcell=True) self.prbc = factory.create(module_type="pbitcell",replica_bitcell=True)
self.add_mod(self.prbc) self.add_mod(self.prbc)
self.height = self.prbc.height self.height = self.prbc.height
@ -83,4 +82,4 @@ class replica_pbitcell(design.design):
def get_wl_cin(self): def get_wl_cin(self):
"""Return the relative capacitance of the access transistor gates""" """Return the relative capacitance of the access transistor gates"""
#This module is made using a pbitcell. Get the cin from that module #This module is made using a pbitcell. Get the cin from that module
return self.prbc.get_wl_cin() return self.prbc.get_wl_cin()

View File

@ -530,7 +530,7 @@ class lib:
"sram_{0}_{1}_{2}".format(OPTS.word_size, OPTS.num_words, OPTS.tech_name), "sram_{0}_{1}_{2}".format(OPTS.word_size, OPTS.num_words, OPTS.tech_name),
OPTS.num_words, OPTS.num_words,
OPTS.num_banks, OPTS.num_banks,
OPTS.num_rw_ports, OPTS.num_rw_ports,
OPTS.num_w_ports, OPTS.num_w_ports,
OPTS.num_r_ports, OPTS.num_r_ports,
OPTS.tech_name, OPTS.tech_name,
@ -555,7 +555,7 @@ class lib:
LVS = str(total_lvs_errors) LVS = str(total_lvs_errors)
datasheet.write("{0},{1},".format(DRC, LVS)) datasheet.write("{0},{1},".format(DRC, LVS))
datasheet.write(str(self.sram.width * self.sram.height)+',')
for port in self.all_ports: for port in self.all_ports:
#DIN timings #DIN timings
if port in self.write_ports: if port in self.write_ports:

View File

@ -1,62 +1,60 @@
from table_gen import * from table_gen import *
import os import os
import csv
import base64 import base64
from globals import OPTS from globals import OPTS
class datasheet(): class datasheet():
""" """
Defines the layout,but not the data, of the html datasheet Defines the layout,but not the data, of the html datasheet
""" """
def __init__(self,identifier):
def __init__(self, identifier):
self.name = identifier self.name = identifier
self.html = "" self.html = ""
def generate_html(self): def generate_html(self):
""" """
Generates html tables using flask-table Generates html tables using flask-table
""" """
with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/datasheet.css', 'r') as datasheet_css: with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/datasheet.css', 'r') as datasheet_css:
#css styling is kept in a seperate file # css styling is kept in a seperate file
self.html += datasheet_css.read() self.html += datasheet_css.read()
with open(OPTS.openram_temp + "/datasheet.info") as info:
# with open(OPTS.openram_temp + "/datasheet.info") as info:
self.html += '<!--' self.html += '<!--'
# for row in info: for row in info:
# self.html += row self.html += row
for item in self.description: # for item in self.description:
self.html += item + ',' # self.html += item + ','
self.html += 'EOL' self.html += '-->'
self.html +='-->'
vlsi_logo = 0 vlsi_logo = 0
with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/vlsi_logo.png' , "rb") as image_file: with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/vlsi_logo.png', "rb") as image_file:
vlsi_logo = base64.b64encode(image_file.read()) vlsi_logo = base64.b64encode(image_file.read())
openram_logo = 0 openram_logo = 0
with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/openram_logo_placeholder.png' , "rb") as image_file: with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/openram_logo_placeholder.png', "rb") as image_file:
openram_logo = base64.b64encode(image_file.read()) openram_logo = base64.b64encode(image_file.read())
self.html += '<a href="https://vlsida.soe.ucsc.edu/"><img src="data:image/png;base64,{0}" alt="VLSIDA"></a>'.format(str(vlsi_logo)[
2:-1])
self.html += '<a href="https://vlsida.soe.ucsc.edu/"><img src="data:image/png;base64,{0}" alt="VLSIDA"></a>'.format(str(vlsi_logo)[2:-1]) self.html += '<p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">' + \
self.name + '.html' + '</p>'
self.html += '<p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Compiled at: ' + self.time + '</p>'
self.html += '<p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">' + \
'DRC errors: ' + str(self.DRC) + '</p>'
self.html += '<p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">' + \
'LVS errors: ' + str(self.LVS) + '</p>'
self.html += '<p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">' + \
'Git commit id: ' + str(self.git_id) + '</p>'
self.html += '<p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Ports and Configuration</p>'
self.html +='<p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">'+ self.name + '.html' + '</p>'
self.html +='<p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Compiled at: '+ self.time + '</p>'
self.html +='<p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">'+ 'DRC errors: ' + str(self.DRC) + '</p>'
self.html +='<p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">'+ 'LVS errors: ' + str(self.LVS) + '</p>'
self.html += '<p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">'+ 'Git commit id: ' + str(self.git_id) + '</p>'
self.html +='<p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Ports and Configuration</p>'
# self.html += in_out(self.io,table_id='data').__html__().replace('&lt;','<').replace('&#34;','"').replace('&gt;',">") # self.html += in_out(self.io,table_id='data').__html__().replace('&lt;','<').replace('&#34;','"').replace('&gt;',">")
self.html += self.io_table.to_html() self.html += self.io_table.to_html()
self.html +='<p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Operating Conditions</p>' self.html += '<p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Operating Conditions</p>'
# self.html += operating_conditions(self.operating,table_id='data').__html__() # self.html += operating_conditions(self.operating,table_id='data').__html__()
self.html += self.operating_table.to_html() self.html += self.operating_table.to_html()
@ -68,9 +66,6 @@ class datasheet():
# self.html += characterization_corners(self.corners,table_id='data').__html__() # self.html += characterization_corners(self.corners,table_id='data').__html__()
self.html += self.corners_table.to_html() self.html += self.corners_table.to_html()
self.html +='<p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Deliverables</p>' self.html += '<p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Deliverables</p>'
# self.html += deliverables(self.dlv,table_id='data').__html__().replace('&lt;','<').replace('&#34;','"').replace('&gt;',">") # self.html += deliverables(self.dlv,table_id='data').__html__().replace('&lt;','<').replace('&#34;','"').replace('&gt;',">")
self.html += self.dlv_table.to_html() self.html += self.dlv_table.to_html()

View File

@ -1,21 +1,21 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
This is a script to load data from the characterization and layout processes into This is a script to load data from the characterization and layout processes into
a web friendly html datasheet. a web friendly html datasheet.
""" """
#TODO: # TODO:
#include log file # include power
#Diagram generation # Diagram generation
#Improve css # Improve css
import debug
from globals import OPTS from globals import OPTS
import os, math import os
import optparse import math
import csv import csv
from datasheet import * import datasheet
from table_gen import * import table_gen
def process_name(corner): def process_name(corner):
""" """
@ -30,20 +30,20 @@ def process_name(corner):
else: else:
return "custom" return "custom"
def parse_characterizer_csv(sram,f,pages):
def parse_characterizer_csv(f, pages):
""" """
Parses output data of the Liberty file generator in order to construct the timing and Parses output data of the Liberty file generator in order to construct the timing and
current table current table
""" """
with open(f) as csv_file: with open(f) as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',') csv_reader = csv.reader(csv_file, delimiter=',')
line_count = 0
for row in csv_reader: for row in csv_reader:
found = 0 found = 0
col = 0 col = 0
#defines layout of csv file # defines layout of csv file
NAME = row[col] NAME = row[col]
col += 1 col += 1
@ -85,29 +85,30 @@ def parse_characterizer_csv(sram,f,pages):
WORD_SIZE = row[col] WORD_SIZE = row[col]
col += 1 col += 1
ORIGIN_ID = row[col] ORIGIN_ID = row[col]
col += 1 col += 1
DATETIME = row[col] DATETIME = row[col]
col+= 1 col += 1
DRC = row[col] DRC = row[col]
col += 1 col += 1
LVS = row[col] LVS = row[col]
col += 1 col += 1
for sheet in pages:
AREA = row[col]
col += 1
for sheet in pages:
if sheet.name == NAME: if sheet.name == NAME:
found = 1 found = 1
#if the .lib information is for an existing datasheet compare timing data # if the .lib information is for an existing datasheet compare timing data
for item in sheet.operating_table.rows: for item in sheet.operating_table.rows:
#check if the new corner data is worse than the previous worse corner data # check if the new corner data is worse than the previous worse corner data
if item[0] == 'Operating Temperature': if item[0] == 'Operating Temperature':
if float(TEMP) > float(item[3]): if float(TEMP) > float(item[3]):
@ -128,14 +129,13 @@ def parse_characterizer_csv(sram,f,pages):
if item[0] == 'Operating Frequncy (F)': if item[0] == 'Operating Frequncy (F)':
try: try:
if float(math.floor(1000/float(MIN_PERIOD)) < float(item[3])): if float(math.floor(1000/float(MIN_PERIOD)) < float(item[3])):
item[3] = str(math.floor(1000/float(MIN_PERIOD))) item[3] = str(math.floor(
1000/float(MIN_PERIOD)))
except Exception: except Exception:
pass pass
while(True): while(True):
col_start = col
if(row[col].startswith('DIN')): if(row[col].startswith('DIN')):
start = col start = col
for item in sheet.timing_table.rows: for item in sheet.timing_table.rows:
@ -253,7 +253,6 @@ def parse_characterizer_csv(sram,f,pages):
col += 1 col += 1
elif(row[col].startswith('WEb')): elif(row[col].startswith('WEb')):
start = col start = col
for item in sheet.timing_table.rows: for item in sheet.timing_table.rows:
@ -293,7 +292,6 @@ def parse_characterizer_csv(sram,f,pages):
col += 1 col += 1
elif(row[col].startswith('ADDR')): elif(row[col].startswith('ADDR')):
start = col start = col
for item in sheet.timing_table.rows: for item in sheet.timing_table.rows:
@ -333,196 +331,225 @@ def parse_characterizer_csv(sram,f,pages):
col += 1 col += 1
else: else:
for element in row[col_start: col - 1]:
sheet.description.append(str(element))
break break
new_sheet.corners_table.add_row([PROC, process_name(
new_sheet.corners_table.add_row([PROC,process_name(PROC),VOLT,TEMP,LIB_NAME.replace(OUT_DIR,'').replace(NAME,'')]) PROC), VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')])
new_sheet.dlv_table.add_row(['.lib','Synthesis models','<a href="file://{0}">{1}</a>'.format(LIB_NAME,LIB_NAME.replace(OUT_DIR,''))]) new_sheet.dlv_table.add_row(
['.lib', 'Synthesis models', '<a href="file://{0}">{1}</a>'.format(LIB_NAME, LIB_NAME.replace(OUT_DIR, ''))])
if found == 0: if found == 0:
#if this is the first corner for this sram, run first time configuration and set up tables # if this is the first corner for this sram, run first time configuration and set up tables
new_sheet = datasheet(NAME) new_sheet = datasheet.datasheet(NAME)
pages.append(new_sheet) pages.append(new_sheet)
new_sheet.git_id = ORIGIN_ID new_sheet.git_id = ORIGIN_ID
new_sheet.time = DATETIME new_sheet.time = DATETIME
new_sheet.DRC = DRC new_sheet.DRC = DRC
new_sheet.LVS = LVS new_sheet.LVS = LVS
new_sheet.description = [NAME, NUM_WORDS, NUM_BANKS, NUM_RW_PORTS, NUM_W_PORTS, NUM_R_PORTS, TECH_NAME, WORD_SIZE, ORIGIN_ID, DATETIME] new_sheet.description = [NAME, NUM_WORDS, NUM_BANKS, NUM_RW_PORTS, NUM_W_PORTS,
NUM_R_PORTS, TECH_NAME, MIN_PERIOD, WORD_SIZE, ORIGIN_ID, DATETIME]
new_sheet.corners_table = table_gen("corners") new_sheet.corners_table = table_gen.table_gen("corners")
new_sheet.corners_table.add_row(['Corner Name','Process','Power Supply','Temperature','Library Name Suffix']) new_sheet.corners_table.add_row(
new_sheet.corners_table.add_row([PROC,process_name(PROC),VOLT,TEMP,LIB_NAME.replace(OUT_DIR,'').replace(NAME,'')]) ['Corner Name', 'Process', 'Power Supply', 'Temperature', 'Library Name Suffix'])
new_sheet.operating_table = table_gen("operating_table") new_sheet.corners_table.add_row([PROC, process_name(
new_sheet.operating_table.add_row(['Parameter','Min','Typ','Max','Units']) PROC), VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')])
new_sheet.operating_table.add_row(['Power supply (VDD) range',VOLT,VOLT,VOLT,'Volts']) new_sheet.operating_table = table_gen.table_gen(
new_sheet.operating_table.add_row(['Operating Temperature',TEMP,TEMP,TEMP,'Celsius']) "operating_table")
new_sheet.operating_table.add_row(
['Parameter', 'Min', 'Typ', 'Max', 'Units'])
new_sheet.operating_table.add_row(
['Power supply (VDD) range', VOLT, VOLT, VOLT, 'Volts'])
new_sheet.operating_table.add_row(
['Operating Temperature', TEMP, TEMP, TEMP, 'Celsius'])
try: try:
new_sheet.operating_table.add_row(['Operating Frequency (F)','','',str(math.floor(1000/float(MIN_PERIOD))),'MHz']) new_sheet.operating_table.add_row(['Operating Frequency (F)', '', '', str(
math.floor(1000/float(MIN_PERIOD))), 'MHz'])
except Exception: except Exception:
new_sheet.operating_table.add_row(['Operating Frequency (F)','','',"not available in netlist only",'MHz']) #failed to provide non-zero MIN_PERIOD # failed to provide non-zero MIN_PERIOD
new_sheet.timing_table = table_gen("timing") new_sheet.operating_table.add_row(
new_sheet.timing_table.add_row(['Parameter','Min','Max','Units']) ['Operating Frequency (F)', '', '', "not available in netlist only", 'MHz'])
new_sheet.timing_table = table_gen.table_gen("timing")
new_sheet.timing_table.add_row(
['Parameter', 'Min', 'Max', 'Units'])
while(True): while(True):
col_start = col
if(row[col].startswith('DIN')): if(row[col].startswith('DIN')):
start = col start = col
new_sheet.timing_table.add_row(['{0} setup rising'.format(row[start]),row[col+1],row[col+2],'ns']) new_sheet.timing_table.add_row(
['{0} setup rising'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2 col += 2
new_sheet.timing_table.add_row(
new_sheet.timing_table.add_row(['{0} setup falling'.format(row[start]),row[col+1],row[col+2],'ns']) ['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2
new_sheet.timing_table.add_row(['{0} hold rising'.format(row[start]),row[col+1],row[col+2],'ns'])
col += 2 col += 2
new_sheet.timing_table.add_row(['{0} hold falling'.format(row[start]),row[col+1],row[col+2],'ns']) new_sheet.timing_table.add_row(
['{0} hold rising'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2 col += 2
col +=1 new_sheet.timing_table.add_row(
['{0} hold falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2
col += 1
elif(row[col].startswith('DOUT')): elif(row[col].startswith('DOUT')):
start = col start = col
new_sheet.timing_table.add_row(['{0} cell rise'.format(row[start]),row[col+1],row[col+2],'ns']) new_sheet.timing_table.add_row(
['{0} cell rise'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2 col += 2
new_sheet.timing_table.add_row(
new_sheet.timing_table.add_row(['{0} cell fall'.format(row[start]),row[col+1],row[col+2],'ns']) ['{0} cell fall'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2
new_sheet.timing_table.add_row(['{0} rise transition'.format(row[start]),row[col+1],row[col+2],'ns'])
col += 2 col += 2
new_sheet.timing_table.add_row(['{0} fall transition'.format(row[start]),row[col+1],row[col+2],'ns']) new_sheet.timing_table.add_row(
['{0} rise transition'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2 col += 2
col +=1 new_sheet.timing_table.add_row(
['{0} fall transition'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2
col += 1
elif(row[col].startswith('CSb')): elif(row[col].startswith('CSb')):
start = col start = col
new_sheet.timing_table.add_row(['{0} setup rising'.format(row[start]),row[col+1],row[col+2],'ns']) new_sheet.timing_table.add_row(
['{0} setup rising'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2 col += 2
new_sheet.timing_table.add_row(
new_sheet.timing_table.add_row(['{0} setup falling'.format(row[start]),row[col+1],row[col+2],'ns']) ['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2
new_sheet.timing_table.add_row(['{0} hold rising'.format(row[start]),row[col+1],row[col+2],'ns'])
col += 2 col += 2
new_sheet.timing_table.add_row(['{0} hold falling'.format(row[start]),row[col+1],row[col+2],'ns']) new_sheet.timing_table.add_row(
['{0} hold rising'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2 col += 2
col +=1 new_sheet.timing_table.add_row(
['{0} hold falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2
col += 1
elif(row[col].startswith('WEb')): elif(row[col].startswith('WEb')):
start = col start = col
new_sheet.timing_table.add_row(['{0} setup rising'.format(row[start]),row[col+1],row[col+2],'ns']) new_sheet.timing_table.add_row(
['{0} setup rising'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2 col += 2
new_sheet.timing_table.add_row(
new_sheet.timing_table.add_row(['{0} setup falling'.format(row[start]),row[col+1],row[col+2],'ns']) ['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2
new_sheet.timing_table.add_row(['{0} hold rising'.format(row[start]),row[col+1],row[col+2],'ns'])
col += 2 col += 2
new_sheet.timing_table.add_row(['{0} hold falling'.format(row[start]),row[col+1],row[col+2],'ns']) new_sheet.timing_table.add_row(
['{0} hold rising'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2 col += 2
col +=1 new_sheet.timing_table.add_row(
['{0} hold falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2
col += 1
elif(row[col].startswith('ADDR')): elif(row[col].startswith('ADDR')):
start = col start = col
new_sheet.timing_table.add_row(['{0} setup rising'.format(row[start]),row[col+1],row[col+2],'ns']) new_sheet.timing_table.add_row(
['{0} setup rising'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2 col += 2
new_sheet.timing_table.add_row(
new_sheet.timing_table.add_row(['{0} setup falling'.format(row[start]),row[col+1],row[col+2],'ns']) ['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2
new_sheet.timing_table.add_row(['{0} hold rising'.format(row[start]),row[col+1],row[col+2],'ns'])
col += 2 col += 2
new_sheet.timing_table.add_row(['{0} hold falling'.format(row[start]),row[col+1],row[col+2],'ns']) new_sheet.timing_table.add_row(
['{0} hold rising'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2 col += 2
col +=1 new_sheet.timing_table.add_row(
['{0} hold falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
col += 2
col += 1
else: else:
for element in row[col_start:col-1]:
sheet.description.append(str(element))
break break
new_sheet.dlv_table = table_gen.table_gen("dlv")
new_sheet.dlv_table.add_row(['Type', 'Description', 'Link'])
new_sheet.io_table = table_gen.table_gen("io")
new_sheet.dlv_table = table_gen("dlv")
new_sheet.dlv_table.add_row(['Type','Description','Link'])
new_sheet.io_table = table_gen("io")
new_sheet.io_table.add_row(['Type', 'Value']) new_sheet.io_table.add_row(['Type', 'Value'])
if not OPTS.netlist_only: if not OPTS.netlist_only:
#physical layout files should not be generated in netlist only mode # physical layout files should not be generated in netlist only mode
new_sheet.dlv_table.add_row(['.gds','GDSII layout views','<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name,'gds')]) new_sheet.dlv_table.add_row(
new_sheet.dlv_table.add_row(['.lef','LEF files','<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name,'lef')]) ['.gds', 'GDSII layout views', '<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name, 'gds')])
new_sheet.dlv_table.add_row(
['.lef', 'LEF files', '<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name, 'lef')])
new_sheet.dlv_table.add_row(['.sp','SPICE netlists','<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name,'sp')])
new_sheet.dlv_table.add_row(['.v','Verilog simulation models','<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name,'v')])
new_sheet.dlv_table.add_row(['.html','This datasheet','<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name,'html')])
new_sheet.dlv_table.add_row(['.lib','Synthesis models','<a href="{1}">{1}</a>'.format(LIB_NAME,LIB_NAME.replace(OUT_DIR,''))])
new_sheet.dlv_table.add_row(['.py','OpenRAM configuration file','<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name,'py')])
new_sheet.io_table.add_row(['WORD_SIZE',WORD_SIZE])
new_sheet.io_table.add_row(['NUM_WORDS',NUM_WORDS])
new_sheet.io_table.add_row(['NUM_BANKS',NUM_BANKS])
new_sheet.io_table.add_row(['NUM_RW_PORTS',NUM_RW_PORTS])
new_sheet.io_table.add_row(['NUM_R_PORTS',NUM_R_PORTS])
new_sheet.io_table.add_row(['NUM_W_PORTS',NUM_W_PORTS])
new_sheet.io_table.add_row(['Area',sram.width * sram.height])
new_sheet.dlv_table.add_row(
['.log', 'OpenRAM compile log', '<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name, 'log')])
new_sheet.dlv_table.add_row(
['.v', 'Verilog simulation models', '<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name, 'v')])
new_sheet.dlv_table.add_row(
['.html', 'This datasheet', '<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name, 'html')])
new_sheet.dlv_table.add_row(
['.lib', 'Synthesis models', '<a href="{1}">{1}</a>'.format(LIB_NAME, LIB_NAME.replace(OUT_DIR, ''))])
new_sheet.dlv_table.add_row(
['.py', 'OpenRAM configuration file', '<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name, 'py')])
new_sheet.dlv_table.add_row(
['.sp', 'SPICE netlists', '<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name, 'sp')])
new_sheet.io_table.add_row(['WORD_SIZE', WORD_SIZE])
new_sheet.io_table.add_row(['NUM_WORDS', NUM_WORDS])
new_sheet.io_table.add_row(['NUM_BANKS', NUM_BANKS])
new_sheet.io_table.add_row(['NUM_RW_PORTS', NUM_RW_PORTS])
new_sheet.io_table.add_row(['NUM_R_PORTS', NUM_R_PORTS])
new_sheet.io_table.add_row(['NUM_W_PORTS', NUM_W_PORTS])
new_sheet.io_table.add_row(['Area', AREA])
class datasheet_gen(): class datasheet_gen():
def datasheet_write(sram,name): def datasheet_write(name):
in_dir = OPTS.openram_temp in_dir = OPTS.openram_temp
if not (os.path.isdir(in_dir)): if not (os.path.isdir(in_dir)):
os.mkdir(in_dir) os.mkdir(in_dir)
datasheets = [] datasheets = []
parse_characterizer_csv(sram, in_dir + "/datasheet.info", datasheets) parse_characterizer_csv(in_dir + "/datasheet.info", datasheets)
for sheets in datasheets: for sheets in datasheets:
with open(name, 'w+') as f: with open(name, 'w+') as f:

View File

@ -9,23 +9,56 @@ import sys
# 2 = verbose # 2 = verbose
# n = custom setting # n = custom setting
def check(check,str):
def check(check, str):
(frame, filename, line_number, function_name, lines, (frame, filename, line_number, function_name, lines,
index) = inspect.getouterframes(inspect.currentframe())[1] index) = inspect.getouterframes(inspect.currentframe())[1]
if not check: if not check:
sys.stderr.write("ERROR: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) sys.stderr.write("ERROR: file {0}: line {1}: {2}\n".format(
os.path.basename(filename), line_number, str))
log("ERROR: file {0}: line {1}: {2}\n".format(
os.path.basename(filename), line_number, str))
assert 0 assert 0
def error(str,return_value=0):
def error(str, return_value=0):
(frame, filename, line_number, function_name, lines, (frame, filename, line_number, function_name, lines,
index) = inspect.getouterframes(inspect.currentframe())[1] index) = inspect.getouterframes(inspect.currentframe())[1]
sys.stderr.write("ERROR: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) sys.stderr.write("ERROR: file {0}: line {1}: {2}\n".format(
assert return_value==0 os.path.basename(filename), line_number, str))
log("ERROR: file {0}: line {1}: {2}\n".format(
os.path.basename(filename), line_number, str))
assert return_value == 0
def warning(str): def warning(str):
(frame, filename, line_number, function_name, lines, (frame, filename, line_number, function_name, lines,
index) = inspect.getouterframes(inspect.currentframe())[1] index) = inspect.getouterframes(inspect.currentframe())[1]
sys.stderr.write("WARNING: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) sys.stderr.write("WARNING: file {0}: line {1}: {2}\n".format(
os.path.basename(filename), line_number, str))
log("WARNING: file {0}: line {1}: {2}\n".format(
os.path.basename(filename), line_number, str))
def print_raw(str):
print(str)
log(str)
def log(str):
if log.create_file:
compile_log = open(globals.OPTS.output_path +
globals.OPTS.output_name + '.log', "w")
log.create_file = 0
else:
compile_log = open(globals.OPTS.output_path +
globals.OPTS.output_name + '.log', "a")
compile_log.write(str + '\n')
log.create_file = 1
def info(lev, str): def info(lev, str):
@ -33,9 +66,10 @@ def info(lev, str):
if (OPTS.debug_level >= lev): if (OPTS.debug_level >= lev):
frm = inspect.stack()[1] frm = inspect.stack()[1]
mod = inspect.getmodule(frm[0]) mod = inspect.getmodule(frm[0])
#classname = frm.f_globals['__name__'] # classname = frm.f_globals['__name__']
if mod.__name__ == None: if mod.__name__ == None:
class_name="" class_name = ""
else: else:
class_name=mod.__name__ class_name = mod.__name__
print("[{0}/{1}]: {2}".format(class_name,frm[0].f_code.co_name,str)) print_raw("[{0}/{1}]: {2}".format(class_name, frm[0].f_code.co_name, str))

View File

@ -1,78 +0,0 @@
Delivered-To: mrg@ucsc.edu
Received: by 10.216.164.197 with SMTP id c47cs36474wel;
Sat, 19 Nov 2011 21:23:28 -0800 (PST)
Received: by 10.216.133.5 with SMTP id p5mr1106280wei.105.1321766513080;
Sat, 19 Nov 2011 21:21:53 -0800 (PST)
Received-SPF: softfail (google.com: best guess record for domain of transitioning wieckows@umich.edu does not designate 128.114.48.32 as permitted sender) client-ip=128.114.48.32;
Received: by 10.241.242.69 with POP3 id 5mf3470160wwf.5;
Sat, 19 Nov 2011 21:21:53 -0800 (PST)
X-Gmail-Fetch-Info: mguthaus@gmail.com 1 smtp.gmail.com 995 mguthaus
Delivered-To: mguthaus@gmail.com
Received: by 10.231.207.15 with SMTP id fw15cs52829ibb;
Thu, 14 Oct 2010 12:49:35 -0700 (PDT)
Received: by 10.142.224.8 with SMTP id w8mr3585480wfg.123.1287085774723;
Thu, 14 Oct 2010 12:49:34 -0700 (PDT)
Return-Path: <wieckows@umich.edu>
Received: from mail-01.cse.ucsc.edu (mail-01.cse.ucsc.edu [128.114.48.32])
by mx.google.com with ESMTP id x31si25240170wfd.118.2010.10.14.12.49.34;
Thu, 14 Oct 2010 12:49:34 -0700 (PDT)
Received-SPF: neutral (google.com: 128.114.48.32 is neither permitted nor denied by best guess record for domain of wieckows@umich.edu) client-ip=128.114.48.32;
Authentication-Results: mx.google.com; spf=neutral (google.com: 128.114.48.32 is neither permitted nor denied by best guess record for domain of wieckows@umich.edu) smtp.mail=wieckows@umich.edu
Received: from services.cse.ucsc.edu (services.cse.ucsc.edu [128.114.48.10])
by mail-01.cse.ucsc.edu (Postfix) with ESMTP id 60660100985C
for <mrg@mail-01.cse.ucsc.edu>; Thu, 14 Oct 2010 12:49:34 -0700 (PDT)
Received: from mailgw.soe.ucsc.edu (mailgw.cse.ucsc.edu [128.114.48.9])
by services.cse.ucsc.edu (8.13.6/8.13.6) with ESMTP id o9EJnXcg026705
(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL)
for <mrg@soe.ucsc.edu>; Thu, 14 Oct 2010 12:49:34 -0700 (PDT)
X-ASG-Debug-ID: 1287085773-35c0a0820001-k66d7V
Received: from hellskitchen.mr.itd.umich.edu (smtp.mail.umich.edu [141.211.14.82]) by mailgw.soe.ucsc.edu with ESMTP id iCFqYJFhVj1wHPNy for <mrg@soe.ucsc.edu>; Thu, 14 Oct 2010 12:49:33 -0700 (PDT)
X-Barracuda-Envelope-From: wieckows@umich.edu
X-Barracuda-Apparent-Source-IP: 141.211.14.82
Received: FROM [10.0.1.4] (adsl-99-67-97-169.dsl.sfldmi.sbcglobal.net [99.67.97.169])
By hellskitchen.mr.itd.umich.edu ID 4CB75ECA.5F7DC.12653 ;
Authuser wieckows;
14 Oct 2010 15:49:30 EDT
Content-Type: text/plain; charset=us-ascii
Mime-Version: 1.0 (Apple Message framework v1081)
Subject: Re: GDS Mill
From: Michael Wieckowski <wieckows@umich.edu>
X-ASG-Orig-Subj: Re: GDS Mill
In-Reply-To: <BEC6726E-7B98-43D8-8AAA-2AA259DFFDA8@soe.ucsc.edu>
Date: Thu, 14 Oct 2010 15:49:29 -0400
Content-Transfer-Encoding: quoted-printable
Message-Id: <7C1B8C49-7D87-4BF2-8ABF-6555CF7B37AD@umich.edu>
References: <BEC6726E-7B98-43D8-8AAA-2AA259DFFDA8@soe.ucsc.edu>
To: Matthew Guthaus <mrg@soe.ucsc.edu>
X-Mailer: Apple Mail (2.1081)
X-Barracuda-Connect: smtp.mail.umich.edu[141.211.14.82]
X-Barracuda-Start-Time: 1287085773
X-Barracuda-URL: http://mailgw.cse.ucsc.edu:8000/cgi-mod/mark.cgi
X-Virus-Scanned: by bsmtpd at soe.ucsc.edu
Hi Matt,
Feel free to use / modify / distribute the code as you like.
-Mike
On Oct 14, 2010, at 3:07 PM, Matthew Guthaus wrote:
> Hi Michael (& Dennis),
>=20
> A student and I were looking at your GDS tools, but we noticed that =
there is no license. What is the license?
>=20
> Thanks,
>=20
> Matt
>=20
> ---
> Matthew Guthaus
> Assistant Professor, Computer Engineering
> University of California Santa Cruz
> http://vlsida.soe.ucsc.edu/
>=20
>=20
>=20

View File

@ -1,30 +1,81 @@
README BY TOM GOLUBEV
gdsMill was adapted from gdsMill by Michael Wieckowski. gdsMill was adapted from gdsMill by Michael Wieckowski.
gdsMill allows one to work with GDS files, opening, reading, writing and altering.
It is a library and does not work by itself. To get started, refer to ExampleUserDir.
To look at sram compiler related example, refer to the sram_examples subdir.
gdsMill takes a layermap, in a standard format (virtuoso .map files). This is necessary Delivered-To: mrg@ucsc.edu
for drawing text and rectangles, since those functions take layernames, and gdsMill needs layer numbers. Received: by 10.216.164.197 with SMTP id c47cs36474wel;
Sat, 19 Nov 2011 21:23:28 -0800 (PST)
Received: by 10.216.133.5 with SMTP id p5mr1106280wei.105.1321766513080;
Sat, 19 Nov 2011 21:21:53 -0800 (PST)
Received-SPF: softfail (google.com: best guess record for domain of transitioning wieckows@umich.edu does not designate 128.114.48.32 as permitted sender) client-ip=128.114.48.32;
Received: by 10.241.242.69 with POP3 id 5mf3470160wwf.5;
Sat, 19 Nov 2011 21:21:53 -0800 (PST)
X-Gmail-Fetch-Info: mguthaus@gmail.com 1 smtp.gmail.com 995 mguthaus
Delivered-To: mguthaus@gmail.com
Received: by 10.231.207.15 with SMTP id fw15cs52829ibb;
Thu, 14 Oct 2010 12:49:35 -0700 (PDT)
Received: by 10.142.224.8 with SMTP id w8mr3585480wfg.123.1287085774723;
Thu, 14 Oct 2010 12:49:34 -0700 (PDT)
Return-Path: <wieckows@umich.edu>
Received: from mail-01.cse.ucsc.edu (mail-01.cse.ucsc.edu [128.114.48.32])
by mx.google.com with ESMTP id x31si25240170wfd.118.2010.10.14.12.49.34;
Thu, 14 Oct 2010 12:49:34 -0700 (PDT)
Received-SPF: neutral (google.com: 128.114.48.32 is neither permitted nor denied by best guess record for domain of wieckows@umich.edu) client-ip=128.114.48.32;
Authentication-Results: mx.google.com; spf=neutral (google.com: 128.114.48.32 is neither permitted nor denied by best guess record for domain of wieckows@umich.edu) smtp.mail=wieckows@umich.edu
Received: from services.cse.ucsc.edu (services.cse.ucsc.edu [128.114.48.10])
by mail-01.cse.ucsc.edu (Postfix) with ESMTP id 60660100985C
for <mrg@mail-01.cse.ucsc.edu>; Thu, 14 Oct 2010 12:49:34 -0700 (PDT)
Received: from mailgw.soe.ucsc.edu (mailgw.cse.ucsc.edu [128.114.48.9])
by services.cse.ucsc.edu (8.13.6/8.13.6) with ESMTP id o9EJnXcg026705
(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL)
for <mrg@soe.ucsc.edu>; Thu, 14 Oct 2010 12:49:34 -0700 (PDT)
X-ASG-Debug-ID: 1287085773-35c0a0820001-k66d7V
Received: from hellskitchen.mr.itd.umich.edu (smtp.mail.umich.edu [141.211.14.82]) by mailgw.soe.ucsc.edu with ESMTP id iCFqYJFhVj1wHPNy for <mrg@soe.ucsc.edu>; Thu, 14 Oct 2010 12:49:33 -0700 (PDT)
X-Barracuda-Envelope-From: wieckows@umich.edu
X-Barracuda-Apparent-Source-IP: 141.211.14.82
Received: FROM [10.0.1.4] (adsl-99-67-97-169.dsl.sfldmi.sbcglobal.net [99.67.97.169])
By hellskitchen.mr.itd.umich.edu ID 4CB75ECA.5F7DC.12653 ;
Authuser wieckows;
14 Oct 2010 15:49:30 EDT
Content-Type: text/plain; charset=us-ascii
Mime-Version: 1.0 (Apple Message framework v1081)
Subject: Re: GDS Mill
From: Michael Wieckowski <wieckows@umich.edu>
X-ASG-Orig-Subj: Re: GDS Mill
In-Reply-To: <BEC6726E-7B98-43D8-8AAA-2AA259DFFDA8@soe.ucsc.edu>
Date: Thu, 14 Oct 2010 15:49:29 -0400
Content-Transfer-Encoding: quoted-printable
Message-Id: <7C1B8C49-7D87-4BF2-8ABF-6555CF7B37AD@umich.edu>
References: <BEC6726E-7B98-43D8-8AAA-2AA259DFFDA8@soe.ucsc.edu>
To: Matthew Guthaus <mrg@soe.ucsc.edu>
X-Mailer: Apple Mail (2.1081)
X-Barracuda-Connect: smtp.mail.umich.edu[141.211.14.82]
X-Barracuda-Start-Time: 1287085773
X-Barracuda-URL: http://mailgw.cse.ucsc.edu:8000/cgi-mod/mark.cgi
X-Virus-Scanned: by bsmtpd at soe.ucsc.edu
Hi Matt,
Feel free to use / modify / distribute the code as you like.
-Mike
gdsMill funcionality: On Oct 14, 2010, at 3:07 PM, Matthew Guthaus wrote:
The main functions are from vlsilayout. They allow creating a new layout, fill in a box, text, and instancing other structures. > Hi Michael (& Dennis),
>=20
Files: > A student and I were looking at your GDS tools, but we noticed that =
there is no license. What is the license?
sram_examples: >=20
> Thanks,
gdsMill.sh: Adds gdsMill to python path. >=20
Source this before working > Matt
>=20
printGDS.py: will dump a text version structures within the gds file. > ---
usage: python printGDS.py file > Matthew Guthaus
> Assistant Professor, Computer Engineering
cell6tDemo.py: Will tile cell6t from sram_lib2.gds and output into layoutB.gds. All cells from source are copied into layoutB.gds. > University of California Santa Cruz
usage: python ./cell6tDemo.py > http://vlsida.soe.ucsc.edu/
>=20
>=20
>=20

View File

@ -1,7 +1,8 @@
from .gdsPrimitives import * from .gdsPrimitives import *
from datetime import * from datetime import *
#from mpmath import matrix #from mpmath import matrix
from numpy import matrix #from numpy import matrix
import numpy as np
#import gdsPrimitives #import gdsPrimitives
import debug import debug
@ -170,21 +171,20 @@ class VlsiLayout:
else: else:
# MRG: Added negative to make CCW rotate 8/29/18 # MRG: Added negative to make CCW rotate 8/29/18
angle = math.radians(float(rotateAngle)) angle = math.radians(float(rotateAngle))
mRotate = matrix([[math.cos(angle),-math.sin(angle),0.0], mRotate = np.array([[math.cos(angle),-math.sin(angle),0.0],
[math.sin(angle),math.cos(angle),0.0], [math.sin(angle),math.cos(angle),0.0],
[0.0,0.0,1.0]]) [0.0,0.0,1.0]])
#set up the translation matrix #set up the translation matrix
translateX = float(coordinates[0]) translateX = float(coordinates[0])
translateY = float(coordinates[1]) translateY = float(coordinates[1])
mTranslate = matrix([[1.0,0.0,translateX],[0.0,1.0,translateY],[0.0,0.0,1.0]]) mTranslate = np.array([[1.0,0.0,translateX],[0.0,1.0,translateY],[0.0,0.0,1.0]])
#set up the scale matrix (handles mirror X) #set up the scale matrix (handles mirror X)
scaleX = 1.0 scaleX = 1.0
if(transFlags[0]): if(transFlags[0]):
scaleY = -1.0 scaleY = -1.0
else: else:
scaleY = 1.0 scaleY = 1.0
mScale = matrix([[scaleX,0.0,0.0],[0.0,scaleY,0.0],[0.0,0.0,1.0]]) mScale = np.array([[scaleX,0.0,0.0],[0.0,scaleY,0.0],[0.0,0.0,1.0]])
#we need to keep track of all transforms in the hierarchy #we need to keep track of all transforms in the hierarchy
#when we add an element to the xy tree, we apply all transforms from the bottom up #when we add an element to the xy tree, we apply all transforms from the bottom up
transformPath.append((mRotate,mScale,mTranslate)) transformPath.append((mRotate,mScale,mTranslate))
@ -219,27 +219,26 @@ class VlsiLayout:
def populateCoordinateMap(self): def populateCoordinateMap(self):
def addToXyTree(startingStructureName = None,transformPath = None): def addToXyTree(startingStructureName = None,transformPath = None):
#print("populateCoordinateMap") uVector = np.array([[1.0],[0.0],[0.0]]) #start with normal basis vectors
uVector = matrix([1.0,0.0,0.0]).transpose() #start with normal basis vectors vVector = np.array([[0.0],[1.0],[0.0]])
vVector = matrix([0.0,1.0,0.0]).transpose() origin = np.array([[0.0],[0.0],[1.0]]) #and an origin (Z component is 1.0 to indicate position instead of vector)
origin = matrix([0.0,0.0,1.0]).transpose() #and an origin (Z component is 1.0 to indicate position instead of vector)
#make a copy of all the transforms and reverse it #make a copy of all the transforms and reverse it
reverseTransformPath = transformPath[:] reverseTransformPath = transformPath[:]
if len(reverseTransformPath) > 1: if len(reverseTransformPath) > 1:
reverseTransformPath.reverse() reverseTransformPath.reverse()
#now go through each transform and apply them to our basis and origin in succession #now go through each transform and apply them to our basis and origin in succession
for transform in reverseTransformPath: for transform in reverseTransformPath:
origin = transform[0] * origin #rotate origin = np.dot(transform[0], origin) #rotate
uVector = transform[0] * uVector #rotate uVector = np.dot(transform[0], uVector) #rotate
vVector = transform[0] * vVector #rotate vVector = np.dot(transform[0], vVector) #rotate
origin = transform[1] * origin #scale origin = np.dot(transform[1], origin) #scale
uVector = transform[1] * uVector #scale uVector = np.dot(transform[1], uVector) #scale
vVector = transform[1] * vVector #scale vVector = np.dot(transform[1], vVector) #scale
origin = transform[2] * origin #translate origin = np.dot(transform[2], origin) #translate
#we don't need to do a translation on the basis vectors #we don't need to do a translation on the basis vectors
#uVector = transform[2] * uVector #translate #uVector = transform[2] * uVector #translate
#vVector = transform[2] * vVector #translate #vVector = transform[2] * vVector #translate
#populate the xyTree with each structureName and coordinate space #populate the xyTree with each structureName and coordinate space
self.xyTree.append((startingStructureName,origin,uVector,vVector)) self.xyTree.append((startingStructureName,origin,uVector,vVector))
self.traverseTheHierarchy(delegateFunction = addToXyTree) self.traverseTheHierarchy(delegateFunction = addToXyTree)
@ -522,8 +521,7 @@ class VlsiLayout:
return True return True
def fillAreaDensity(self, layerToFill = 0, offsetInMicrons = (0,0), coverageWidth = 100.0, coverageHeight = 100.0, def fillAreaDensity(self, layerToFill = 0, offsetInMicrons = (0,0), coverageWidth = 100.0, coverageHeight = 100.0, minSpacing = 0.22, blockSize = 1.0):
minSpacing = 0.22, blockSize = 1.0):
effectiveBlock = blockSize+minSpacing effectiveBlock = blockSize+minSpacing
widthInBlocks = int(coverageWidth/effectiveBlock) widthInBlocks = int(coverageWidth/effectiveBlock)
heightInBlocks = int(coverageHeight/effectiveBlock) heightInBlocks = int(coverageHeight/effectiveBlock)
@ -810,8 +808,8 @@ class VlsiLayout:
# This is fixed to be: # This is fixed to be:
# |u[0] v[0]| |x| |x'| # |u[0] v[0]| |x| |x'|
# |u[1] v[1]|x|y|=|y'| # |u[1] v[1]|x|y|=|y'|
x=coordinate[0]*uVector[0].item()+coordinate[1]*vVector[0].item() x=coordinate[0]*uVector[0][0]+coordinate[1]*vVector[0][0]
y=coordinate[0]*uVector[1].item()+coordinate[1]*vVector[1].item() y=coordinate[0]*uVector[1][0]+coordinate[1]*vVector[1][0]
transformCoordinate=[x,y] transformCoordinate=[x,y]
return transformCoordinate return transformCoordinate
@ -836,5 +834,3 @@ def boundaryArea(A):
area_A=(A[2]-A[0])*(A[3]-A[1]) area_A=(A[2]-A[0])*(A[3]-A[1])
return area_A return area_A

View File

@ -71,26 +71,26 @@ def print_banner():
if OPTS.is_unit_test: if OPTS.is_unit_test:
return return
print("|==============================================================================|") debug.print_raw("|==============================================================================|")
name = "OpenRAM Compiler" name = "OpenRAM Compiler"
print("|=========" + name.center(60) + "=========|") debug.print_raw("|=========" + name.center(60) + "=========|")
print("|=========" + " ".center(60) + "=========|") debug.print_raw("|=========" + " ".center(60) + "=========|")
print("|=========" + "VLSI Design and Automation Lab".center(60) + "=========|") debug.print_raw("|=========" + "VLSI Design and Automation Lab".center(60) + "=========|")
print("|=========" + "Computer Science and Engineering Department".center(60) + "=========|") debug.print_raw("|=========" + "Computer Science and Engineering Department".center(60) + "=========|")
print("|=========" + "University of California Santa Cruz".center(60) + "=========|") debug.print_raw("|=========" + "University of California Santa Cruz".center(60) + "=========|")
print("|=========" + " ".center(60) + "=========|") debug.print_raw("|=========" + " ".center(60) + "=========|")
print("|=========" + "VLSI Computer Architecture Research Group".center(60) + "=========|") debug.print_raw("|=========" + "VLSI Computer Architecture Research Group".center(60) + "=========|")
print("|=========" + "Electrical and Computer Engineering Department".center(60) + "=========|") debug.print_raw("|=========" + "Electrical and Computer Engineering Department".center(60) + "=========|")
print("|=========" + "Oklahoma State University".center(60) + "=========|") debug.print_raw("|=========" + "Oklahoma State University".center(60) + "=========|")
print("|=========" + " ".center(60) + "=========|") debug.print_raw("|=========" + " ".center(60) + "=========|")
user_info = "Usage help: openram-user-group@ucsc.edu" user_info = "Usage help: openram-user-group@ucsc.edu"
print("|=========" + user_info.center(60) + "=========|") debug.print_raw("|=========" + user_info.center(60) + "=========|")
dev_info = "Development help: openram-dev-group@ucsc.edu" dev_info = "Development help: openram-dev-group@ucsc.edu"
print("|=========" + dev_info.center(60) + "=========|") debug.print_raw("|=========" + dev_info.center(60) + "=========|")
temp_info = "Temp dir: {}".format(OPTS.openram_temp) temp_info = "Temp dir: {}".format(OPTS.openram_temp)
print("|=========" + temp_info.center(60) + "=========|") debug.print_raw("|=========" + temp_info.center(60) + "=========|")
print("|=========" + "See LICENSE for license info".center(60) + "=========|") debug.print_raw("|=========" + "See LICENSE for license info".center(60) + "=========|")
print("|==============================================================================|") debug.print_raw("|==============================================================================|")
def check_versions(): def check_versions():
@ -130,6 +130,9 @@ def init_openram(config_file, is_unit_test=True):
init_paths() init_paths()
from sram_factory import factory
factory.reset()
# Reset the static duplicate name checker for unit tests. # Reset the static duplicate name checker for unit tests.
import hierarchy_design import hierarchy_design
hierarchy_design.hierarchy_design.name_map=[] hierarchy_design.hierarchy_design.name_map=[]
@ -397,7 +400,7 @@ def print_time(name, now_time, last_time=None, indentation=2):
time = str(round((now_time-last_time).total_seconds(),1)) + " seconds" time = str(round((now_time-last_time).total_seconds(),1)) + " seconds"
else: else:
time = now_time.strftime('%m/%d/%Y %H:%M:%S') time = now_time.strftime('%m/%d/%Y %H:%M:%S')
print("{0} {1}: {2}".format("*"*indentation,name,time)) debug.print_raw("{0} {1}: {2}".format("*"*indentation,name,time))
def report_status(): def report_status():
@ -413,20 +416,20 @@ def report_status():
if not OPTS.tech_name: if not OPTS.tech_name:
debug.error("Tech name must be specified in config file.") debug.error("Tech name must be specified in config file.")
print("Technology: {0}".format(OPTS.tech_name)) debug.print_raw("Technology: {0}".format(OPTS.tech_name))
print("Total size: {} bits".format(OPTS.word_size*OPTS.num_words*OPTS.num_banks)) debug.print_raw("Total size: {} bits".format(OPTS.word_size*OPTS.num_words*OPTS.num_banks))
print("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size, debug.print_raw("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size,
OPTS.num_words, OPTS.num_words,
OPTS.num_banks)) OPTS.num_banks))
print("RW ports: {0}\nR-only ports: {1}\nW-only ports: {2}".format(OPTS.num_rw_ports, debug.print_raw("RW ports: {0}\nR-only ports: {1}\nW-only ports: {2}".format(OPTS.num_rw_ports,
OPTS.num_r_ports, OPTS.num_r_ports,
OPTS.num_w_ports)) OPTS.num_w_ports))
if OPTS.netlist_only: if OPTS.netlist_only:
print("Netlist only mode (no physical design is being done).") debug.print_raw("Netlist only mode (no physical design is being done).")
if not OPTS.inline_lvsdrc: if not OPTS.inline_lvsdrc:
print("DRC/LVS/PEX is only run on the top-level design.") debug.print_raw("DRC/LVS/PEX is only run on the top-level design.")
if not OPTS.check_lvsdrc: if not OPTS.check_lvsdrc:
print("DRC/LVS/PEX is completely disabled.") debug.print_raw("DRC/LVS/PEX is completely disabled.")

View File

@ -6,9 +6,7 @@ import math
from math import log,sqrt,ceil from math import log,sqrt,ceil
import contact import contact
import pgates import pgates
from pinv import pinv from sram_factory import factory
from pnand2 import pnand2
from pnor2 import pnor2
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
@ -396,25 +394,14 @@ class bank(design.design):
def add_modules(self): def add_modules(self):
""" Add all the modules using the class loader """ """ Add all the modules using the class loader """
mod_list = ["bitcell", "decoder", "wordline_driver",
"bitcell_array", "sense_amp_array", "precharge_array",
"column_mux_array", "write_driver_array",
"dff", "bank_select"]
from importlib import reload
for mod_name in mod_list:
config_mod_name = getattr(OPTS, mod_name)
class_file = reload(__import__(config_mod_name))
mod_class = getattr(class_file , config_mod_name)
setattr (self, "mod_"+mod_name, mod_class)
self.bitcell_array = factory.create(module_type="bitcell_array",
cols=self.num_cols,
self.bitcell_array = self.mod_bitcell_array(cols=self.num_cols, rows=self.num_rows)
rows=self.num_rows)
self.add_mod(self.bitcell_array) self.add_mod(self.bitcell_array)
# create arrays of bitline and bitline_bar names for read, write, or all ports # create arrays of bitline and bitline_bar names for read, write, or all ports
self.bitcell = self.mod_bitcell() self.bitcell = factory.create(module_type="bitcell")
self.bl_names = self.bitcell.list_all_bl_names() self.bl_names = self.bitcell.list_all_bl_names()
self.br_names = self.bitcell.list_all_br_names() self.br_names = self.bitcell.list_all_br_names()
self.wl_names = self.bitcell.list_all_wl_names() self.wl_names = self.bitcell.list_all_wl_names()
@ -423,7 +410,11 @@ class bank(design.design):
self.precharge_array = [] self.precharge_array = []
for port in self.all_ports: for port in self.all_ports:
if port in self.read_ports: if port in self.read_ports:
self.precharge_array.append(self.mod_precharge_array(columns=self.num_cols, bitcell_bl=self.bl_names[port], bitcell_br=self.br_names[port])) temp_pre = factory.create(module_type="precharge_array",
columns=self.num_cols,
bitcell_bl=self.bl_names[port],
bitcell_br=self.br_names[port])
self.precharge_array.append(temp_pre)
self.add_mod(self.precharge_array[port]) self.add_mod(self.precharge_array[port])
else: else:
self.precharge_array.append(None) self.precharge_array.append(None)
@ -431,32 +422,39 @@ class bank(design.design):
if self.col_addr_size > 0: if self.col_addr_size > 0:
self.column_mux_array = [] self.column_mux_array = []
for port in self.all_ports: for port in self.all_ports:
self.column_mux_array.append(self.mod_column_mux_array(columns=self.num_cols, temp_col = factory.create(module_type="column_mux_array",
word_size=self.word_size, columns=self.num_cols,
bitcell_bl=self.bl_names[port], word_size=self.word_size,
bitcell_br=self.br_names[port])) bitcell_bl=self.bl_names[port],
bitcell_br=self.br_names[port])
self.column_mux_array.append(temp_col)
self.add_mod(self.column_mux_array[port]) self.add_mod(self.column_mux_array[port])
self.sense_amp_array = self.mod_sense_amp_array(word_size=self.word_size, self.sense_amp_array = factory.create(module_type="sense_amp_array",
words_per_row=self.words_per_row) word_size=self.word_size,
words_per_row=self.words_per_row)
self.add_mod(self.sense_amp_array) self.add_mod(self.sense_amp_array)
self.write_driver_array = self.mod_write_driver_array(columns=self.num_cols, self.write_driver_array = factory.create(module_type="write_driver_array",
word_size=self.word_size) columns=self.num_cols,
word_size=self.word_size)
self.add_mod(self.write_driver_array) self.add_mod(self.write_driver_array)
self.row_decoder = self.mod_decoder(rows=self.num_rows) self.row_decoder = factory.create(module_type="decoder",
rows=self.num_rows)
self.add_mod(self.row_decoder) self.add_mod(self.row_decoder)
self.wordline_driver = self.mod_wordline_driver(rows=self.num_rows) self.wordline_driver = factory.create(module_type="wordline_driver",
rows=self.num_rows,
cols=self.num_cols)
self.add_mod(self.wordline_driver) self.add_mod(self.wordline_driver)
self.inv = pinv() self.inv = factory.create(module_type="pinv")
self.add_mod(self.inv) self.add_mod(self.inv)
if(self.num_banks > 1): if(self.num_banks > 1):
self.bank_select = self.mod_bank_select() self.bank_select = factory.create(module_type="bank_select")
self.add_mod(self.bank_select) self.add_mod(self.bank_select)
@ -693,18 +691,17 @@ class bank(design.design):
""" """
Create a 2:4 or 3:8 column address decoder. Create a 2:4 or 3:8 column address decoder.
""" """
dff = factory.create(module_type="dff")
if self.col_addr_size == 0: if self.col_addr_size == 0:
return return
elif self.col_addr_size == 1: elif self.col_addr_size == 1:
from pinvbuf import pinvbuf self.column_decoder = factory.create(module_type="pinvbuf", height=dff.height)
self.column_decoder = pinvbuf(height=self.mod_dff.height)
elif self.col_addr_size == 2: elif self.col_addr_size == 2:
from hierarchical_predecode2x4 import hierarchical_predecode2x4 as pre2x4 self.column_decoder = factory.create(module_type="hierarchical_predecode2x4", height=dff.height)
self.column_decoder = pre2x4(height=self.mod_dff.height)
elif self.col_addr_size == 3: elif self.col_addr_size == 3:
from hierarchical_predecode3x8 import hierarchical_predecode3x8 as pre3x8 self.column_decoder = factory.create(module_type="hierarchical_predecode3x8", height=dff.height)
self.column_decoder = pre3x8(height=self.mod_dff.height)
else: else:
# No error checking before? # No error checking before?
debug.error("Invalid column decoder?",-1) debug.error("Invalid column decoder?",-1)
@ -1071,8 +1068,8 @@ class bank(design.design):
# The mid guarantees we exit the input cell to the right. # The mid guarantees we exit the input cell to the right.
driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).rc() driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).rc()
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).lc() bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).lc()
mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0) mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.wordline_driver_inst[port].rx() + 0.5*self.bitcell_array_inst.lx(),0)
mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1) mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0.5,1)
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
@ -1090,8 +1087,8 @@ class bank(design.design):
# The mid guarantees we exit the input cell to the right. # The mid guarantees we exit the input cell to the right.
driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).lc() driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).lc()
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).rc() bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).rc()
mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0) mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.wordline_driver_inst[port].lx() + 0.5*self.bitcell_array_inst.rx(),0)
mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1) mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0,1)
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
def route_column_address_lines(self, port): def route_column_address_lines(self, port):
@ -1257,20 +1254,22 @@ class bank(design.design):
def get_wl_en_cin(self): def get_wl_en_cin(self):
"""Get the relative capacitance of all the clk connections in the bank""" """Get the relative capacitance of all the clk connections in the bank"""
#wl_en only used in the wordline driver. #wl_en only used in the wordline driver.
total_clk_cin = self.wordline_driver.get_wl_en_cin() return self.wordline_driver.get_wl_en_cin()
return total_clk_cin
def get_w_en_cin(self):
"""Get the relative capacitance of all the clk connections in the bank"""
#wl_en only used in the wordline driver.
return self.write_driver.get_w_en_cin()
def get_clk_bar_cin(self): def get_clk_bar_cin(self):
"""Get the relative capacitance of all the clk_bar connections in the bank""" """Get the relative capacitance of all the clk_bar connections in the bank"""
#Current bank only uses clock bar (clk_buf_bar) as an enable for the precharge array. #Current bank only uses clock bar (clk_buf_bar) as an enable for the precharge array.
#Precharges are the all the same in Mulitport, one is picked #Precharges are the all the same in Mulitport, one is picked
port = self.read_ports[0] port = self.read_ports[0]
total_clk_bar_cin = self.precharge_array[port].get_en_cin() return self.precharge_array[port].get_en_cin()
return total_clk_bar_cin
def get_sen_cin(self): def get_sen_cin(self):
"""Get the relative capacitance of all the sense amp enable connections in the bank""" """Get the relative capacitance of all the sense amp enable connections in the bank"""
#Current bank only uses sen as an enable for the sense amps. #Current bank only uses sen as an enable for the sense amps.
total_sen_cin = self.sense_amp_array.get_en_cin() return self.sense_amp_array.get_en_cin()
return total_sen_cin

View File

@ -7,6 +7,7 @@ from pinv import pinv
from pnand2 import pnand2 from pnand2 import pnand2
from pnor2 import pnor2 from pnor2 import pnor2
from vector import vector from vector import vector
from sram_factory import factory
from globals import OPTS from globals import OPTS
class bank_select(design.design): class bank_select(design.design):
@ -62,28 +63,25 @@ class bank_select(design.design):
def add_modules(self): def add_modules(self):
""" Create modules for later instantiation """ """ Create modules for later instantiation """
from importlib import reload self.bitcell = factory.create(module_type="bitcell")
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
height = self.bitcell.height + drc("poly_to_active") height = self.bitcell.height + drc("poly_to_active")
# 1x Inverter # 1x Inverter
self.inv_sel = pinv(height=height) self.inv_sel = factory.create(module_type="pinv", height=height)
self.add_mod(self.inv_sel) self.add_mod(self.inv_sel)
# 4x Inverter # 4x Inverter
self.inv = self.inv4x = pinv(4) self.inv4x = factory.create(module_type="pinv", height=height, size=4)
self.add_mod(self.inv4x) self.add_mod(self.inv4x)
self.nor2 = pnor2(height=height) self.nor2 = factory.create(module_type="pnor2", height=height)
self.add_mod(self.nor2) self.add_mod(self.nor2)
self.inv4x_nor = pinv(size=4, height=height) self.inv4x_nor = factory.create(module_type="pinv", height=height, size=4)
self.add_mod(self.inv4x_nor) self.add_mod(self.inv4x_nor)
self.nand2 = pnand2() self.nand2 = factory.create(module_type="pnand2")
self.add_mod(self.nand2) self.add_mod(self.nand2)
def calculate_module_offsets(self): def calculate_module_offsets(self):
@ -94,7 +92,7 @@ class bank_select(design.design):
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.inv.height self.yoffset_maxpoint = self.num_control_lines * self.inv4x.height
# Include the M1 pitches for the supply rails and spacing # Include the M1 pitches for the supply rails and spacing
self.height = self.yoffset_maxpoint + 2*self.m1_pitch self.height = self.yoffset_maxpoint + 2*self.m1_pitch
self.width = self.xoffset_inv + self.inv4x.width self.width = self.xoffset_inv + self.inv4x.width
@ -170,10 +168,10 @@ class bank_select(design.design):
if i == 0: if i == 0:
y_offset = 0 y_offset = 0
else: else:
y_offset = self.inv4x_nor.height + self.inv.height * (i-1) y_offset = self.inv4x_nor.height + self.inv4x.height * (i-1)
if i%2: if i%2:
y_offset += self.inv.height y_offset += self.inv4x.height
mirror = "MX" mirror = "MX"
else: else:
mirror = "" mirror = ""
@ -223,7 +221,7 @@ class bank_select(design.design):
self.add_label_pin(text="bank_sel_bar", self.add_label_pin(text="bank_sel_bar",
layer="metal2", layer="metal2",
offset=vector(xoffset_bank_sel_bar, 0), offset=vector(xoffset_bank_sel_bar, 0),
height=self.inv.height) height=self.inv4x.height)
self.add_via_center(layers=("metal1","via1","metal2"), self.add_via_center(layers=("metal1","via1","metal2"),
offset=bank_sel_bar_pin.rc()) offset=bank_sel_bar_pin.rc())

View File

@ -3,8 +3,7 @@ import design
from tech import drc, spice from tech import drc, spice
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory
unique_id = 1
class bitcell_array(design.design): class bitcell_array(design.design):
""" """
@ -12,16 +11,10 @@ class bitcell_array(design.design):
and word line is connected by abutment. and word line is connected by abutment.
Connects the word lines and bit lines. Connects the word lines and bit lines.
""" """
unique_id = 1 def __init__(self, cols, rows, name):
def __init__(self, cols, rows, name=""):
if name == "":
name = "bitcell_array_{0}x{1}_{2}".format(rows,cols,bitcell_array.unique_id)
bitcell_array.unique_id += 1
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
self.column_size = cols self.column_size = cols
self.row_size = rows self.row_size = rows
@ -83,11 +76,7 @@ class bitcell_array(design.design):
def add_modules(self): def add_modules(self):
""" Add the modules used in this design """ """ Add the modules used in this design """
self.cell = factory.create(module_type="bitcell")
from importlib import reload
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.cell = self.mod_bitcell()
self.add_mod(self.cell) self.add_mod(self.cell)
def create_instances(self): def create_instances(self):
@ -210,4 +199,4 @@ class bitcell_array(design.design):
#A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns #A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns
bitcell_wl_cin = self.cell.get_wl_cin() bitcell_wl_cin = self.cell.get_wl_cin()
total_cin = bitcell_wl_cin * self.column_size total_cin = bitcell_wl_cin * self.column_size
return total_cin return total_cin

View File

@ -3,13 +3,7 @@ import design
from tech import drc, parameter from tech import drc, parameter
import debug import debug
import contact import contact
from pinv import pinv from sram_factory import factory
from pbuf import pbuf
from pand2 import pand2
from pnand2 import pnand2
from pinvbuf import pinvbuf
from dff_buf import dff_buf
from dff_buf_array import dff_buf_array
import math import math
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
@ -20,20 +14,26 @@ class control_logic(design.design):
Dynamically generated Control logic for the total SRAM circuit. Dynamically generated Control logic for the total SRAM circuit.
""" """
def __init__(self, num_rows, words_per_row, sram=None, port_type="rw"): def __init__(self, num_rows, words_per_row, word_size, sram=None, port_type="rw"):
""" Constructor """ """ Constructor """
name = "control_logic_" + port_type name = "control_logic_" + port_type
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {}".format(name)) debug.info(1, "Creating {}".format(name))
self.add_comment("num_rows: {0}".format(num_rows))
self.add_comment("words_per_row: {0}".format(words_per_row))
self.add_comment("word_size {0}".format(word_size))
self.sram=sram
self.num_rows = num_rows self.num_rows = num_rows
self.words_per_row = words_per_row self.words_per_row = words_per_row
self.word_size = word_size
self.port_type = port_type self.port_type = port_type
self.num_cols = word_size*words_per_row
self.num_words = num_rows * words_per_row
self.enable_delay_chain_resizing = False self.enable_delay_chain_resizing = False
#This is needed to resize the delay chain. Likely to be changed at some point.
self.sram=sram
#self.sram=None #disable re-sizing for debugging, FIXME: resizing is not working, needs to be adjusted for new control logic. #self.sram=None #disable re-sizing for debugging, FIXME: resizing is not working, needs to be adjusted for new control logic.
self.wl_timing_tolerance = 1 #Determines how much larger the sen delay should be. Accounts for possible error in model. self.wl_timing_tolerance = 1 #Determines how much larger the sen delay should be. Accounts for possible error in model.
self.parasitic_inv_delay = parameter["min_inv_para_delay"] #Keeping 0 for now until further testing. self.parasitic_inv_delay = parameter["min_inv_para_delay"] #Keeping 0 for now until further testing.
@ -73,46 +73,69 @@ class control_logic(design.design):
def add_modules(self): def add_modules(self):
""" Add all the required modules """ """ Add all the required modules """
dff = dff_buf() dff = factory.create(module_type="dff_buf")
dff_height = dff.height dff_height = dff.height
self.ctrl_dff_array = dff_buf_array(rows=self.num_control_signals,columns=1) self.ctrl_dff_array = factory.create(module_type="dff_buf_array",
rows=self.num_control_signals,
columns=1)
self.add_mod(self.ctrl_dff_array) self.add_mod(self.ctrl_dff_array)
self.and2 = pand2(size=4,height=dff_height) self.and2 = factory.create(module_type="pand2",
size=4,
height=dff_height)
self.add_mod(self.and2) self.add_mod(self.and2)
# Special gates: inverters for buffering # clk_buf drives a flop for every address and control bit
# Size the clock for the number of rows (fanout) # plus about 5 fanouts for the control logic
clock_driver_size = max(1,int(self.num_rows/4)) # each flop internally has a FO 4 approximately
self.clkbuf = pbuf(size=clock_driver_size, height=dff_height) clock_fanout = 4*(math.log(self.num_words,2) + math.log(self.words_per_row,2) \
self.add_mod(self.clkbuf) + self.num_control_signals) + 5
self.clk_buf_driver = factory.create(module_type="pdriver",
self.buf16 = pbuf(size=16, height=dff_height) fanout=clock_fanout,
self.add_mod(self.buf16) height=dff_height)
self.buf8 = pbuf(size=8, height=dff_height)
self.add_mod(self.buf8)
self.inv = self.inv1 = pinv(size=1, height=dff_height) self.add_mod(self.clk_buf_driver)
self.add_mod(self.inv1)
self.inv8 = pinv(size=8, height=dff_height)
self.add_mod(self.inv8)
# self.inv2 = pinv(size=4, height=dff_height)
# self.add_mod(self.inv2)
#self.inv16 = pinv(size=16, height=dff_height)
#self.add_mod(self.inv16)
# wl_en drives every row in the bank
self.wl_en_driver = factory.create(module_type="pdriver",
fanout=self.num_rows,
height=dff_height)
self.add_mod(self.wl_en_driver)
# w_en drives every write driver
self.w_en_driver = factory.create(module_type="pdriver",
fanout=self.word_size+8,
height=dff_height)
self.add_mod(self.w_en_driver)
# s_en drives every sense amp
self.s_en_driver = factory.create(module_type="pdriver",
fanout=self.word_size,
height=dff_height)
self.add_mod(self.s_en_driver)
# used to generate inverted signals with low fanout
self.inv = factory.create(module_type="pinv",
size=1,
height=dff_height)
self.add_mod(self.inv)
# p_en_bar drives every column in the bicell array
self.p_en_bar_driver = factory.create(module_type="pdriver",
neg_polarity=True,
fanout=self.num_cols,
height=dff_height)
self.add_mod(self.p_en_bar_driver)
if (self.port_type == "rw") or (self.port_type == "r"): if (self.port_type == "rw") or (self.port_type == "r"):
from importlib import reload
c = reload(__import__(OPTS.replica_bitline))
replica_bitline = getattr(c, OPTS.replica_bitline)
delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size() delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size()
bitcell_loads = int(math.ceil(self.num_rows / 2.0)) bitcell_loads = int(math.ceil(self.num_rows / 2.0))
self.replica_bitline = replica_bitline([delay_fanout_heuristic]*delay_stages_heuristic, bitcell_loads, name="replica_bitline_"+self.port_type) self.replica_bitline = factory.create(module_type="replica_bitline",
delay_fanout_list=[delay_fanout_heuristic]*delay_stages_heuristic,
bitcell_loads=bitcell_loads)
if self.sram != None: if self.sram != None:
self.set_sen_wl_delays() self.set_sen_wl_delays()
@ -124,8 +147,10 @@ class control_logic(design.design):
#This resizes based on total delay. #This resizes based on total delay.
delay_stages, delay_fanout = self.get_dynamic_delay_chain_size(delay_stages_heuristic, delay_fanout_heuristic) delay_stages, delay_fanout = self.get_dynamic_delay_chain_size(delay_stages_heuristic, delay_fanout_heuristic)
self.replica_bitline = replica_bitline([delay_fanout]*delay_stages, bitcell_loads, name="replica_bitline_resized_"+self.port_type) self.replica_bitline = factory.create(module_type="replica_bitline",
delay_fanout_list=[delay_fanout]*delay_stages,
bitcell_loads=bitcell_loads)
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.add_mod(self.replica_bitline) self.add_mod(self.replica_bitline)
@ -393,8 +418,8 @@ class control_logic(design.design):
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.clkbuf_inst = self.add_inst(name="clkbuf", self.clk_buf_inst = self.add_inst(name="clkbuf",
mod=self.clkbuf) mod=self.clk_buf_driver)
self.connect_inst(["clk","clk_buf","vdd","gnd"]) self.connect_inst(["clk","clk_buf","vdd","gnd"])
def place_clk_buf_row(self,row): def place_clk_buf_row(self,row):
@ -403,12 +428,12 @@ class control_logic(design.design):
(y_off,mirror)=self.get_offset(row) (y_off,mirror)=self.get_offset(row)
offset = vector(x_off,y_off) offset = vector(x_off,y_off)
self.clkbuf_inst.place(offset, mirror) self.clk_buf_inst.place(offset, mirror)
self.row_end_inst.append(self.clkbuf_inst) self.row_end_inst.append(self.clk_buf_inst)
def route_clk_buf(self): def route_clk_buf(self):
clk_pin = self.clkbuf_inst.get_pin("A") clk_pin = self.clk_buf_inst.get_pin("A")
clk_pos = clk_pin.center() clk_pos = clk_pin.center()
self.add_layout_pin_segment_center(text="clk", self.add_layout_pin_segment_center(text="clk",
layer="metal2", layer="metal2",
@ -418,14 +443,17 @@ class control_logic(design.design):
offset=clk_pos) offset=clk_pos)
clkbuf_map = zip(["Z"], ["clk_buf"]) # Connect this at the bottom of the buffer
self.connect_vertical_bus(clkbuf_map, self.clkbuf_inst, self.rail_offsets, ("metal3", "via2", "metal2")) out_pos = self.clk_buf_inst.get_pin("Z").center()
mid1 = vector(out_pos.x,2*self.m2_pitch)
mid2 = vector(self.rail_offsets["clk_buf"].x, mid1.y)
bus_pos = self.rail_offsets["clk_buf"]
self.add_wire(("metal3","via2","metal2"),[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=("metal1","via1","metal2"), self.add_via_center(layers=("metal1","via1","metal2"),
offset=self.clkbuf_inst.get_pin("Z").center()) offset=self.clk_buf_inst.get_pin("Z").center())
self.connect_output(self.clkbuf_inst, "Z", "clk_buf") self.connect_output(self.clk_buf_inst, "Z", "clk_buf")
def create_gated_clk_bar_row(self): def create_gated_clk_bar_row(self):
self.clk_bar_inst = self.add_inst(name="inv_clk_bar", self.clk_bar_inst = self.add_inst(name="inv_clk_bar",
@ -504,7 +532,7 @@ class control_logic(design.design):
def create_wlen_row(self): def create_wlen_row(self):
# input pre_p_en, output: wl_en # input pre_p_en, output: wl_en
self.wl_en_inst=self.add_inst(name="buf_wl_en", self.wl_en_inst=self.add_inst(name="buf_wl_en",
mod=self.buf16) mod=self.wl_en_driver)
self.connect_inst(["gated_clk_bar", "wl_en", "vdd", "gnd"]) self.connect_inst(["gated_clk_bar", "wl_en", "vdd", "gnd"])
def place_wlen_row(self, row): def place_wlen_row(self, row):
@ -574,7 +602,7 @@ class control_logic(design.design):
# input: pre_p_en, output: p_en_bar # input: pre_p_en, output: p_en_bar
self.p_en_bar_inst=self.add_inst(name="inv_p_en_bar", self.p_en_bar_inst=self.add_inst(name="inv_p_en_bar",
mod=self.inv8) mod=self.p_en_bar_driver)
self.connect_inst([input_name, "p_en_bar", "vdd", "gnd"]) self.connect_inst([input_name, "p_en_bar", "vdd", "gnd"])
@ -614,7 +642,7 @@ class control_logic(design.design):
# BUFFER FOR S_EN # BUFFER FOR S_EN
# input: pre_s_en, output: s_en # input: pre_s_en, output: s_en
self.s_en_inst=self.add_inst(name="buf_s_en", self.s_en_inst=self.add_inst(name="buf_s_en",
mod=self.buf8) mod=self.s_en_driver)
self.connect_inst(["pre_s_en", "s_en", "vdd", "gnd"]) self.connect_inst(["pre_s_en", "s_en", "vdd", "gnd"])
def place_sen_row(self,row): def place_sen_row(self,row):
@ -651,7 +679,7 @@ class control_logic(design.design):
# BUFFER FOR W_EN # BUFFER FOR W_EN
self.w_en_inst = self.add_inst(name="buf_w_en_buf", self.w_en_inst = self.add_inst(name="buf_w_en_buf",
mod=self.buf8) mod=self.w_en_driver)
self.connect_inst([input_name, "w_en", "vdd", "gnd"]) self.connect_inst([input_name, "w_en", "vdd", "gnd"])
@ -808,7 +836,7 @@ class control_logic(design.design):
#Calculate the load on wl_en within the module and add it to external load #Calculate the load on wl_en within the module and add it to external load
external_cout = self.sram.get_wl_en_cin() external_cout = self.sram.get_wl_en_cin()
#First stage is the clock buffer #First stage is the clock buffer
stage_effort_list += self.clkbuf.get_output_stage_efforts(external_cout, is_clk_bar_rise) stage_effort_list += self.clk_buf_driver.get_stage_efforts(external_cout, is_clk_bar_rise)
last_stage_is_rise = stage_effort_list[-1].is_rise last_stage_is_rise = stage_effort_list[-1].is_rise
#Then ask the sram for the other path delays (from the bank) #Then ask the sram for the other path delays (from the bank)
@ -839,18 +867,18 @@ class control_logic(design.design):
#First stage, gated_clk_bar -(and2)-> rbl_in. Only for RW ports. #First stage, gated_clk_bar -(and2)-> rbl_in. Only for RW ports.
if self.port_type == "rw": if self.port_type == "rw":
stage1_cout = self.replica_bitline.get_en_cin() stage1_cout = self.replica_bitline.get_en_cin()
stage_effort_list += self.and2.get_output_stage_efforts(stage1_cout, last_stage_rise) stage_effort_list += self.and2.get_stage_efforts(stage1_cout, last_stage_rise)
last_stage_rise = stage_effort_list[-1].is_rise last_stage_rise = stage_effort_list[-1].is_rise
#Replica bitline stage, rbl_in -(rbl)-> pre_s_en #Replica bitline stage, rbl_in -(rbl)-> pre_s_en
stage2_cout = self.buf8.get_cin() stage2_cout = self.s_en_driver.get_cin()
stage_effort_list += self.replica_bitline.determine_sen_stage_efforts(stage2_cout, last_stage_rise) stage_effort_list += self.replica_bitline.determine_sen_stage_efforts(stage2_cout, last_stage_rise)
last_stage_rise = stage_effort_list[-1].is_rise last_stage_rise = stage_effort_list[-1].is_rise
#buffer stage, pre_s_en -(buffer)-> s_en #buffer stage, pre_s_en -(buffer)-> s_en
stage3_cout = self.sram.get_sen_cin() stage3_cout = self.sram.get_sen_cin()
stage_effort_list += self.buf8.get_output_stage_efforts(stage3_cout, last_stage_rise) stage_effort_list += self.s_en_driver.get_stage_efforts(stage3_cout, last_stage_rise)
last_stage_rise = stage_effort_list[-1].is_rise last_stage_rise = stage_effort_list[-1].is_rise
return stage_effort_list return stage_effort_list

View File

@ -1,10 +1,10 @@
import debug import debug
import design import design
from tech import drc from tech import drc
from pinv import pinv
from contact import contact 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
class delay_chain(design.design): class delay_chain(design.design):
""" """
@ -13,14 +13,12 @@ class delay_chain(design.design):
Usually, this will be constant, but it could have varied fanout. Usually, this will be constant, but it could have varied fanout.
""" """
unique_id = 1 def __init__(self, name, fanout_list):
def __init__(self, fanout_list, name="delay_chain"):
"""init function""" """init function"""
name = name+"_{}".format(delay_chain.unique_id)
delay_chain.unique_id += 1
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "creating delay chain {0}".format(str(fanout_list)))
self.add_comment("fanouts: {0}".format(str(fanout_list)))
# Two fanouts are needed so that we can route the vdd/gnd connections # Two fanouts are needed so that we can route the vdd/gnd connections
for f in fanout_list: for f in fanout_list:
debug.check(f>=2,"Must have >=2 fanouts for each stage.") debug.check(f>=2,"Must have >=2 fanouts for each stage.")
@ -57,7 +55,7 @@ class delay_chain(design.design):
self.add_pin("gnd") self.add_pin("gnd")
def add_modules(self): def add_modules(self):
self.inv = pinv(route_output=False) self.inv = factory.create(module_type="pinv", route_output=False)
self.add_mod(self.inv) self.add_mod(self.inv)
def create_inverters(self): def create_inverters(self):
@ -234,8 +232,8 @@ class delay_chain(design.design):
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: #last stage
stage_cout+=ext_delayed_en_cout stage_cout+=ext_delayed_en_cout
stage = self.inv.get_effort_stage(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)
last_stage_is_rise = stage.is_rise last_stage_is_rise = stage.is_rise
return stage_effort_list return stage_effort_list

View File

@ -3,6 +3,7 @@ import design
from tech import drc from tech import drc
from math import log from math import log
from vector import vector from vector import vector
from sram_factory import factory
from globals import OPTS from globals import OPTS
class dff_array(design.design): class dff_array(design.design):
@ -11,7 +12,7 @@ class dff_array(design.design):
Unlike the data flops, these are never spaced out. Unlike the data flops, these are never spaced out.
""" """
def __init__(self, rows, columns, inv1_size=2, inv2_size=4, name=""): def __init__(self, rows, columns, name=""):
self.rows = rows self.rows = rows
self.columns = columns self.columns = columns
@ -19,7 +20,8 @@ class dff_array(design.design):
name = "dff_array_{0}x{1}".format(rows, columns) name = "dff_array_{0}x{1}".format(rows, columns)
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {0} rows={1} cols={2}".format(self.name, self.rows, self.columns)) debug.info(1, "Creating {0} rows={1} cols={2}".format(self.name, self.rows, self.columns))
self.add_comment("rows: {0} cols: {1}".format(rows, columns))
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.create_layout() self.create_layout()
@ -38,10 +40,7 @@ class dff_array(design.design):
self.DRC_LVS() self.DRC_LVS()
def add_modules(self): def add_modules(self):
from importlib import reload self.dff = factory.create(module_type="dff")
c = reload(__import__(OPTS.dff))
self.mod_dff = getattr(c, OPTS.dff)
self.dff = self.mod_dff("dff")
self.add_mod(self.dff) self.add_mod(self.dff)
def add_pins(self): def add_pins(self):
@ -61,7 +60,7 @@ class dff_array(design.design):
for col in range(self.columns): for col in range(self.columns):
name = "dff_r{0}_c{1}".format(row,col) name = "dff_r{0}_c{1}".format(row,col)
self.dff_insts[row,col]=self.add_inst(name=name, self.dff_insts[row,col]=self.add_inst(name=name,
mod=self.dff) mod=self.dff)
self.connect_inst([self.get_din_name(row,col), self.connect_inst([self.get_din_name(row,col),
self.get_dout_name(row,col), self.get_dout_name(row,col),
"clk", "clk",
@ -162,4 +161,4 @@ class dff_array(design.design):
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" """Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
dff_clk_cin = self.dff.get_clk_cin() dff_clk_cin = self.dff.get_clk_cin()
total_cin = dff_clk_cin * self.rows * self.columns total_cin = dff_clk_cin * self.rows * self.columns
return total_cin return total_cin

View File

@ -4,7 +4,7 @@ from tech import drc,parameter
from math import log from math import log
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from pinv import pinv from sram_factory import factory
class dff_buf(design.design): class dff_buf(design.design):
""" """
@ -21,7 +21,8 @@ class dff_buf(design.design):
dff_buf.unique_id += 1 dff_buf.unique_id += 1
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {}".format(self.name)) debug.info(1, "Creating {}".format(self.name))
self.add_comment("inv1: {0} inv2: {1}".format(inv1_size, inv2_size))
# This is specifically for SCMOS where the DFF vdd/gnd rails are more than min width. # This is specifically for SCMOS where the DFF vdd/gnd rails are more than min width.
# This causes a DRC in the pinv which assumes min width rails. This ensures the output # This causes a DRC in the pinv which assumes min width rails. This ensures the output
# contact does not violate spacing to the rail in the NMOS. # contact does not violate spacing to the rail in the NMOS.
@ -50,16 +51,17 @@ class dff_buf(design.design):
self.DRC_LVS() self.DRC_LVS()
def add_modules(self): def add_modules(self):
from importlib import reload self.dff = factory.create(module_type="dff")
c = reload(__import__(OPTS.dff))
self.mod_dff = getattr(c, OPTS.dff)
self.dff = self.mod_dff("dff")
self.add_mod(self.dff) self.add_mod(self.dff)
self.inv1 = pinv(size=self.inv1_size,height=self.dff.height) self.inv1 = factory.create(module_type="pinv",
size=self.inv1_size,
height=self.dff.height)
self.add_mod(self.inv1) self.add_mod(self.inv1)
self.inv2 = pinv(size=self.inv2_size,height=self.dff.height) self.inv2 = factory.create(module_type="pinv",
size=self.inv2_size,
height=self.dff.height)
self.add_mod(self.inv2) self.add_mod(self.inv2)
@ -182,4 +184,4 @@ class dff_buf(design.design):
#This is a handmade cell so the value must be entered in the tech.py file or estimated. #This is a handmade cell so the value must be entered in the tech.py file or estimated.
#Calculated in the tech file by summing the widths of all the gates and dividing by the minimum width. #Calculated in the tech file by summing the widths of all the gates and dividing by the minimum width.
#FIXME: Dff changed in a past commit. The parameter need to be updated. #FIXME: Dff changed in a past commit. The parameter need to be updated.
return parameter["dff_clk_cin"] return parameter["dff_clk_cin"]

View File

@ -4,7 +4,7 @@ from tech import drc
from math import log from math import log
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
import dff_buf from sram_factory import factory
class dff_buf_array(design.design): class dff_buf_array(design.design):
""" """
@ -22,6 +22,9 @@ class dff_buf_array(design.design):
dff_buf_array.unique_id += 1 dff_buf_array.unique_id += 1
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {}".format(self.name)) debug.info(1, "Creating {}".format(self.name))
self.add_comment("rows: {0} cols: {1}".format(rows, columns))
self.add_comment("inv1: {0} inv2: {1}".format(inv1_size, inv2_size))
self.inv1_size = inv1_size self.inv1_size = inv1_size
self.inv2_size = inv2_size self.inv2_size = inv2_size
@ -54,7 +57,9 @@ class dff_buf_array(design.design):
self.add_pin("gnd") self.add_pin("gnd")
def add_modules(self): def add_modules(self):
self.dff = dff_buf.dff_buf(self.inv1_size, self.inv2_size) self.dff = factory.create(module_type="dff_buf",
inv1_size=self.inv1_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):
@ -189,4 +194,4 @@ class dff_buf_array(design.design):
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" """Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
dff_clk_cin = self.dff.get_clk_cin() dff_clk_cin = self.dff.get_clk_cin()
total_cin = dff_clk_cin * self.rows * self.columns total_cin = dff_clk_cin * self.rows * self.columns
return total_cin return total_cin

View File

@ -20,6 +20,8 @@ class dff_inv(design.design):
dff_inv.unique_id += 1 dff_inv.unique_id += 1
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {}".format(self.name)) debug.info(1, "Creating {}".format(self.name))
self.add_comment("inv: {0}".format(inv_size))
self.inv_size = inv_size self.inv_size = inv_size
# This is specifically for SCMOS where the DFF vdd/gnd rails are more than min width. # This is specifically for SCMOS where the DFF vdd/gnd rails are more than min width.
@ -55,13 +57,12 @@ class dff_inv(design.design):
self.add_pin("gnd") self.add_pin("gnd")
def add_modules(self): def add_modules(self):
from importlib import reload self.dff = dff_inv.dff_inv(self.inv_size)
c = reload(__import__(OPTS.dff))
self.mod_dff = getattr(c, OPTS.dff)
self.dff = self.mod_dff("dff")
self.add_mod(self.dff) self.add_mod(self.dff)
self.inv1 = pinv(size=self.inv_size,height=self.dff.height) self.inv1 = factory.create(module_type="pinv",
size=self.inv_size,
height=self.dff.height)
self.add_mod(self.inv1) self.add_mod(self.inv1)
def create_modules(self): def create_modules(self):
@ -152,4 +153,4 @@ class dff_inv(design.design):
def get_clk_cin(self): def get_clk_cin(self):
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff""" """Return the total capacitance (in relative units) that the clock is loaded by in the dff"""
return self.dff.get_clk_cin() return self.dff.get_clk_cin()

View File

@ -22,6 +22,9 @@ class dff_inv_array(design.design):
dff_inv_array.unique_id += 1 dff_inv_array.unique_id += 1
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {}".format(self.name)) debug.info(1, "Creating {}".format(self.name))
self.add_comment("rows: {0} cols: {1}".format(rows, columns))
self.add_comment("inv1: {0}".format(inv1_size))
self.inv_size = inv_size self.inv_size = inv_size
self.create_netlist() self.create_netlist()
@ -42,7 +45,7 @@ class dff_inv_array(design.design):
self.DRC_LVS() self.DRC_LVS()
def add_modules(self): def add_modules(self):
self.dff = dff_inv.dff_inv(self.inv_size) self.dff = factory.create(module_type="dff")
self.add_mod(self.dff) self.add_mod(self.dff)
def add_pins(self): def add_pins(self):
@ -189,4 +192,4 @@ class dff_inv_array(design.design):
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" """Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
dff_clk_cin = self.dff.get_clk_cin() dff_clk_cin = self.dff.get_clk_cin()
total_cin = dff_clk_cin * self.rows * self.columns total_cin = dff_clk_cin * self.rows * self.columns
return total_cin return total_cin

View File

@ -4,12 +4,8 @@ import design
from math import log from math import log
from math import sqrt from math import sqrt
import math import math
import contact import contact
from pnand2 import pnand2 from sram_factory import factory
from pnand3 import pnand3
from pinv import pinv
from hierarchical_predecode2x4 import hierarchical_predecode2x4 as pre2x4
from hierarchical_predecode3x8 import hierarchical_predecode3x8 as pre3x8
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
@ -17,11 +13,8 @@ class hierarchical_decoder(design.design):
""" """
Dynamically generated hierarchical decoder. Dynamically generated hierarchical decoder.
""" """
unique_id = 1 def __init__(self, name, rows, height=None):
design.design.__init__(self, name)
def __init__(self, rows, height=None):
design.design.__init__(self, "hierarchical_decoder_{0}rows_{1}".format(rows,hierarchical_decoder.unique_id))
hierarchical_decoder.unique_id += 1
self.NAND_FORMAT = "DEC_NAND_{0}" self.NAND_FORMAT = "DEC_NAND_{0}"
self.INV_FORMAT = "DEC_INV_{0}" self.INV_FORMAT = "DEC_INV_{0}"
@ -57,21 +50,26 @@ class hierarchical_decoder(design.design):
self.DRC_LVS() self.DRC_LVS()
def add_modules(self): def add_modules(self):
self.inv = pinv(height=self.cell_height) self.inv = factory.create(module_type="pinv",
height=self.cell_height)
self.add_mod(self.inv) self.add_mod(self.inv)
self.nand2 = pnand2(height=self.cell_height) self.nand2 = factory.create(module_type="pnand2",
height=self.cell_height)
self.add_mod(self.nand2) self.add_mod(self.nand2)
self.nand3 = pnand3(height=self.cell_height) self.nand3 = factory.create(module_type="pnand3",
height=self.cell_height)
self.add_mod(self.nand3) self.add_mod(self.nand3)
self.add_decoders() self.add_decoders()
def add_decoders(self): def add_decoders(self):
""" Create the decoders based on the number of pre-decodes """ """ Create the decoders based on the number of pre-decodes """
self.pre2_4 = pre2x4(height=self.cell_height) self.pre2_4 = factory.create(module_type="hierarchical_predecode2x4",
height=self.cell_height)
self.add_mod(self.pre2_4) self.add_mod(self.pre2_4)
self.pre3_8 = pre3x8(height=self.cell_height) self.pre3_8 = factory.create(module_type="hierarchical_predecode3x8",
height=self.cell_height)
self.add_mod(self.pre3_8) self.add_mod(self.pre3_8)
def determine_predecodes(self,num_inputs): def determine_predecodes(self,num_inputs):

View File

@ -3,24 +3,19 @@ import design
import math import math
from tech import drc from tech import drc
import contact import contact
from pinv import pinv
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from pnand2 import pnand2 from sram_factory import factory
from pnand3 import pnand3
class hierarchical_predecode(design.design): class hierarchical_predecode(design.design):
""" """
Pre 2x4 and 3x8 decoder shared code. Pre 2x4 and 3x8 decoder shared code.
""" """
unique_id = 1 def __init__(self, name, input_number, height=None):
def __init__(self, input_number, height=None):
self.number_of_inputs = input_number self.number_of_inputs = input_number
self.cell_height = height self.cell_height = height
self.number_of_outputs = int(math.pow(2, self.number_of_inputs)) self.number_of_outputs = int(math.pow(2, self.number_of_inputs))
design.design.__init__(self, name="pre{0}x{1}_{2}".format(self.number_of_inputs,self.number_of_outputs,hierarchical_predecode.unique_id)) design.design.__init__(self, name)
hierarchical_predecode.unique_id += 1
def add_pins(self): def add_pins(self):
for k in range(self.number_of_inputs): for k in range(self.number_of_inputs):
@ -33,7 +28,8 @@ class hierarchical_predecode(design.design):
def add_modules(self): def add_modules(self):
""" Add the INV and NAND gate modules """ """ Add the INV and NAND gate modules """
self.inv = pinv(height=self.cell_height) self.inv = factory.create(module_type="pinv",
height=self.cell_height)
self.add_mod(self.inv) self.add_mod(self.inv)
self.add_nand(self.number_of_inputs) self.add_nand(self.number_of_inputs)
@ -42,9 +38,11 @@ class hierarchical_predecode(design.design):
def add_nand(self,inputs): def add_nand(self,inputs):
""" Create the NAND for the predecode input stage """ """ Create the NAND for the predecode input stage """
if inputs==2: if inputs==2:
self.nand = pnand2(height=self.cell_height) self.nand = factory.create(module_type="pnand2",
height=self.cell_height)
elif inputs==3: elif inputs==3:
self.nand = pnand3(height=self.cell_height) self.nand = factory.create(module_type="pnand3",
height=self.cell_height)
else: else:
debug.error("Invalid number of predecode inputs: {}".format(inputs),-1) debug.error("Invalid number of predecode inputs: {}".format(inputs),-1)

View File

@ -9,8 +9,8 @@ class hierarchical_predecode2x4(hierarchical_predecode):
""" """
Pre 2x4 decoder used in hierarchical_decoder. Pre 2x4 decoder used in hierarchical_decoder.
""" """
def __init__(self, height=None): def __init__(self, name, height=None):
hierarchical_predecode.__init__(self, 2, height) hierarchical_predecode.__init__(self, name, 2, height)
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:

View File

@ -9,8 +9,8 @@ class hierarchical_predecode3x8(hierarchical_predecode):
""" """
Pre 3x8 decoder used in hierarchical_decoder. Pre 3x8 decoder used in hierarchical_decoder.
""" """
def __init__(self, height=None): def __init__(self, name, height=None):
hierarchical_predecode.__init__(self, 3, height) hierarchical_predecode.__init__(self, name, 3, height)
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:

View File

@ -5,12 +5,8 @@ import design
import math import math
from math import log,sqrt,ceil from math import log,sqrt,ceil
import contact import contact
from pinv import pinv
from pnand2 import pnand2
from pnor2 import pnor2
from vector import vector from vector import vector
from pinvbuf import pinvbuf from sram_factory import factory
from globals import OPTS from globals import OPTS
class multibank(design.design): class multibank(design.design):
@ -21,21 +17,8 @@ class multibank(design.design):
This module includes the tristate and bank select logic. This module includes the tristate and bank select logic.
""" """
def __init__(self, word_size, num_words, words_per_row, num_banks=1, name=""): def __init__(self, name, word_size, num_words, words_per_row, num_banks=1):
mod_list = ["tri_gate", "bitcell", "decoder", "wordline_driver",
"bitcell_array", "sense_amp_array", "precharge_array",
"column_mux_array", "write_driver_array", "tri_gate_array",
"dff", "bank_select"]
from importlib import reload
for mod_name in mod_list:
config_mod_name = getattr(OPTS, mod_name)
class_file = reload(__import__(config_mod_name))
mod_class = getattr(class_file , config_mod_name)
setattr (self, "mod_"+mod_name, mod_class)
if name == "":
name = "bank_{0}_{1}".format(word_size, num_words)
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(2, "create sram of size {0} with {1} words".format(word_size,num_words)) debug.info(2, "create sram of size {0} with {1} words".format(word_size,num_words))

View File

@ -2,7 +2,7 @@ import design
import debug import debug
from tech import drc from tech import drc
from vector import vector from vector import vector
from precharge import precharge from sram_factory import factory
from globals import OPTS from globals import OPTS
class precharge_array(design.design): class precharge_array(design.design):
@ -11,14 +11,11 @@ class precharge_array(design.design):
of bit line columns, height is the height of the bit-cell array. of bit line columns, height is the height of the bit-cell array.
""" """
unique_id = 1 def __init__(self, name, columns, size=1, bitcell_bl="bl", bitcell_br="br"):
def __init__(self, columns, size=1, bitcell_bl="bl", bitcell_br="br"):
name = "precharge_array_{}".format(precharge_array.unique_id)
precharge_array.unique_id += 1
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name)) debug.info(1, "Creating {0}".format(self.name))
self.add_comment("cols: {0} size: {1} bl: {2} br: {3}".format(columns, size, bitcell_bl, bitcell_br))
self.columns = columns self.columns = columns
self.size = size self.size = size
self.bitcell_bl = bitcell_bl self.bitcell_bl = bitcell_bl
@ -50,10 +47,12 @@ class precharge_array(design.design):
self.DRC_LVS() self.DRC_LVS()
def add_modules(self): def add_modules(self):
self.pc_cell = precharge(name="precharge", self.pc_cell = factory.create(module_type="precharge",
size=self.size, size=self.size,
bitcell_bl=self.bitcell_bl, bitcell_bl=self.bitcell_bl,
bitcell_br=self.bitcell_br) bitcell_br=self.bitcell_br)
self.add_mod(self.pc_cell) self.add_mod(self.pc_cell)
@ -107,4 +106,4 @@ class precharge_array(design.design):
"""Get the relative capacitance of all the clk connections in the precharge array""" """Get the relative capacitance of all the clk connections in the precharge array"""
#Assume single port #Assume single port
precharge_en_cin = self.pc_cell.get_en_cin() precharge_en_cin = self.pc_cell.get_en_cin()
return precharge_en_cin*self.columns return precharge_en_cin*self.columns

View File

@ -1,10 +1,8 @@
import debug import debug
import design import design
from tech import drc from tech import drc
from pinv import pinv
import contact import contact
from bitcell_array import bitcell_array from sram_factory import factory
from ptx import ptx
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
@ -15,7 +13,7 @@ class replica_bitline(design.design):
line and rows is the height of the replica bit loads. line and rows is the height of the replica bit loads.
""" """
def __init__(self, delay_fanout_list, bitcell_loads, name="replica_bitline"): def __init__(self, name, delay_fanout_list, bitcell_loads):
design.design.__init__(self, name) design.design.__init__(self, name)
self.bitcell_loads = bitcell_loads self.bitcell_loads = bitcell_loads
@ -78,29 +76,25 @@ class replica_bitline(design.design):
def add_modules(self): def add_modules(self):
""" Add the modules for later usage """ """ Add the modules for later usage """
from importlib import reload self.replica_bitcell = factory.create(module_type="replica_bitcell")
#g = reload(__import__(OPTS.delay_chain)) self.add_mod(self.replica_bitcell)
#self.mod_delay_chain = getattr(g, OPTS.delay_chain)
g = reload(__import__(OPTS.replica_bitcell))
self.mod_replica_bitcell = getattr(g, OPTS.replica_bitcell)
self.bitcell = self.replica_bitcell = self.mod_replica_bitcell()
self.add_mod(self.bitcell)
# This is the replica bitline load column that is the height of our array # This is the replica bitline load column that is the height of our array
self.rbl = bitcell_array(cols=1, rows=self.bitcell_loads) self.rbl = factory.create(module_type="bitcell_array",
cols=1,
rows=self.bitcell_loads)
self.add_mod(self.rbl) self.add_mod(self.rbl)
# FIXME: The FO and depth of this should be tuned # FIXME: The FO and depth of this should be tuned
from delay_chain import delay_chain self.delay_chain = factory.create(module_type="delay_chain",
self.delay_chain = delay_chain(self.delay_fanout_list) fanout_list=self.delay_fanout_list)
self.add_mod(self.delay_chain) self.add_mod(self.delay_chain)
self.inv = pinv() self.inv = factory.create(module_type="pinv")
self.add_mod(self.inv) self.add_mod(self.inv)
self.access_tx = ptx(tx_type="pmos") self.access_tx = factory.create(module_type="ptx",
tx_type="pmos")
self.add_mod(self.access_tx) self.add_mod(self.access_tx)
def create_instances(self): def create_instances(self):
@ -132,7 +126,6 @@ class replica_bitline(design.design):
temp.append("vdd") temp.append("vdd")
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) self.connect_inst(temp)
#self.connect_inst(["bl_0", "br_0", "delayed_en", "vdd", "gnd"])
self.rbl_inst=self.add_inst(name="load", self.rbl_inst=self.add_inst(name="load",
mod=self.rbl) mod=self.rbl)
@ -621,7 +614,7 @@ class replica_bitline(design.design):
#The delay chain triggers the enable on the replica bitline (rbl). This is used to track the bitline delay whereas this #The delay chain triggers the enable on the replica bitline (rbl). This is used to track the bitline delay whereas this
#model is intended to track every but that. Therefore, the next stage is the inverter after the rbl. #model is intended to track every but that. Therefore, the next stage is the inverter after the rbl.
stage2 = self.inv.get_effort_stage(ext_cout, last_stage_is_rise) stage2 = self.inv.get_stage_effort(ext_cout, last_stage_is_rise)
stage_effort_list.append(stage2) stage_effort_list.append(stage2)
return stage_effort_list return stage_effort_list
@ -631,4 +624,4 @@ class replica_bitline(design.design):
access_tx_cin = self.access_tx.get_cin() access_tx_cin = self.access_tx.get_cin()
rbc_cin = self.replica_bitcell.get_wl_cin() rbc_cin = self.replica_bitcell.get_wl_cin()
return access_tx_cin + rbc_cin return access_tx_cin + rbc_cin

View File

@ -1,6 +1,7 @@
import design import design
from tech import drc from tech import drc
from vector import vector from vector import vector
from sram_factory import factory
import debug import debug
from globals import OPTS from globals import OPTS
@ -10,9 +11,11 @@ class sense_amp_array(design.design):
Dynamically generated sense amp array for all bitlines. Dynamically generated sense amp array for all bitlines.
""" """
def __init__(self, word_size, words_per_row): def __init__(self, name, word_size, words_per_row):
design.design.__init__(self, "sense_amp_array") design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name)) debug.info(1, "Creating {0}".format(self.name))
self.add_comment("word_size {0}".format(word_size))
self.add_comment("words_per_row: {0}".format(words_per_row))
self.word_size = word_size self.word_size = word_size
self.words_per_row = words_per_row self.words_per_row = words_per_row
@ -51,17 +54,13 @@ class sense_amp_array(design.design):
self.add_pin("gnd") self.add_pin("gnd")
def add_modules(self): def add_modules(self):
from importlib import reload self.amp = factory.create(module_type="sense_amp")
c = reload(__import__(OPTS.sense_amp))
self.mod_sense_amp = getattr(c, OPTS.sense_amp)
self.amp = self.mod_sense_amp("sense_amp")
self.add_mod(self.amp) self.add_mod(self.amp)
# This is just used for measurements, # This is just used for measurements,
# so don't add the module # so don't add the module
c = reload(__import__(OPTS.bitcell)) self.bitcell = factory.create(module_type="bitcell")
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
def create_sense_amp_array(self): def create_sense_amp_array(self):
self.local_insts = [] self.local_insts = []
@ -143,4 +142,4 @@ 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.words_per_row return sense_amp_en_cin * self.words_per_row

View File

@ -1,11 +1,11 @@
from math import log from math import log
import design import design
from single_level_column_mux import single_level_column_mux
import contact import contact
from tech import drc from tech import drc
import debug import debug
import math import math
from vector import vector from vector import vector
from sram_factory import factory
from globals import OPTS from globals import OPTS
class single_level_column_mux_array(design.design): class single_level_column_mux_array(design.design):
@ -14,13 +14,11 @@ class single_level_column_mux_array(design.design):
Array of column mux to read the bitlines through the 6T. Array of column mux to read the bitlines through the 6T.
""" """
unique_id = 1 def __init__(self, name, columns, word_size, bitcell_bl="bl", bitcell_br="br"):
def __init__(self, columns, word_size, bitcell_bl="bl", bitcell_br="br"):
name="single_level_column_mux_array_{}".format(single_level_column_mux_array.unique_id)
single_level_column_mux_array.unique_id += 1
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name)) debug.info(1, "Creating {0}".format(self.name))
self.add_comment("cols: {0} word_size: {1} bl: {2} br: {3}".format(columns, word_size, bitcell_bl, bitcell_br))
self.columns = columns self.columns = columns
self.word_size = word_size self.word_size = word_size
self.words_per_row = int(self.columns / self.word_size) self.words_per_row = int(self.columns / self.word_size)
@ -61,7 +59,9 @@ class single_level_column_mux_array(design.design):
def add_modules(self): def add_modules(self):
self.mux = single_level_column_mux(bitcell_bl=self.bitcell_bl, bitcell_br=self.bitcell_br) self.mux = factory.create(module_type="single_level_column_mux",
bitcell_bl=self.bitcell_bl,
bitcell_br=self.bitcell_br)
self.add_mod(self.mux) self.add_mod(self.mux)

View File

@ -2,6 +2,7 @@ import debug
from tech import drc from tech import drc
import design import design
from vector import vector from vector import vector
from sram_factory import factory
from globals import OPTS from globals import OPTS
class tri_gate_array(design.design): class tri_gate_array(design.design):
@ -36,10 +37,7 @@ class tri_gate_array(design.design):
self.DRC_LVS() self.DRC_LVS()
def add_modules(self): def add_modules(self):
from importlib import reload self.tri = factory.create(module_type="tri_gate")
c = reload(__import__(OPTS.tri_gate))
self.mod_tri_gate = getattr(c, OPTS.tri_gate)
self.tri = self.mod_tri_gate("tri_gate")
self.add_mod(self.tri) self.add_mod(self.tri)
def add_pins(self): def add_pins(self):

View File

@ -5,9 +5,8 @@ import contact
from math import log from math import log
from math import sqrt from math import sqrt
import math import math
from pinv import pinv
from pnand2 import pnand2
from vector import vector from vector import vector
from sram_factory import factory
from globals import OPTS from globals import OPTS
class wordline_driver(design.design): class wordline_driver(design.design):
@ -16,10 +15,13 @@ class wordline_driver(design.design):
Generates the wordline-driver to drive the bitcell Generates the wordline-driver to drive the bitcell
""" """
def __init__(self, rows): def __init__(self, name, rows, cols):
design.design.__init__(self, "wordline_driver") design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
self.rows = rows self.rows = rows
self.cols = cols
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
@ -53,13 +55,16 @@ class wordline_driver(design.design):
# This is just used for measurements, # This is just used for measurements,
# so don't add the module # so don't add the module
self.inv = pinv() self.inv = factory.create(module_type="pdriver",
fanout=self.cols,
neg_polarity=True)
self.add_mod(self.inv) self.add_mod(self.inv)
self.inv_no_output = pinv(route_output=False) self.inv_no_output = factory.create(module_type="pinv",
route_output=False)
self.add_mod(self.inv_no_output) self.add_mod(self.inv_no_output)
self.nand2 = pnand2() self.nand2 = factory.create(module_type="pnand2")
self.add_mod(self.nand2) self.add_mod(self.nand2)
@ -224,12 +229,12 @@ class wordline_driver(design.design):
stage_effort_list = [] stage_effort_list = []
stage1_cout = self.inv.get_cin() stage1_cout = self.inv.get_cin()
stage1 = self.nand2.get_effort_stage(stage1_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 last_stage_is_rise = stage1.is_rise
stage2 = self.inv.get_effort_stage(external_cout, last_stage_is_rise) stage2 = self.inv.get_stage_efforts(external_cout, last_stage_is_rise)
stage_effort_list.append(stage2) stage_effort_list.extend(stage2)
return stage_effort_list return stage_effort_list
@ -237,4 +242,4 @@ class wordline_driver(design.design):
"""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.
total_cin = self.nand2.get_cin() * self.rows total_cin = self.nand2.get_cin() * self.rows
return total_cin return total_cin

View File

@ -23,3 +23,8 @@ class write_driver(design.design):
self.height = write_driver.height self.height = write_driver.height
self.pin_map = write_driver.pin_map self.pin_map = write_driver.pin_map
def get_w_en_cin(self):
"""Get the relative capacitance of a single input"""
# This is approximated from SCMOS. It has roughly 5 3x transistor gates.
return 5*3

View File

@ -2,6 +2,7 @@ from math import log
import design import design
from tech import drc from tech import drc
import debug import debug
from sram_factory import factory
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
@ -11,9 +12,11 @@ class write_driver_array(design.design):
Dynamically generated write driver array of all bitlines. Dynamically generated write driver array of all bitlines.
""" """
def __init__(self, columns, word_size): def __init__(self, name, columns, word_size):
design.design.__init__(self, "write_driver_array") design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name)) debug.info(1, "Creating {0}".format(self.name))
self.add_comment("columns: {0}".format(columns))
self.add_comment("word_size {0}".format(word_size))
self.columns = columns self.columns = columns
self.word_size = word_size self.word_size = word_size
@ -53,17 +56,12 @@ class write_driver_array(design.design):
self.add_pin("gnd") self.add_pin("gnd")
def add_modules(self): def add_modules(self):
from importlib import reload self.driver = factory.create(module_type="write_driver")
c = reload(__import__(OPTS.write_driver))
self.mod_write_driver = getattr(c, OPTS.write_driver)
self.driver = self.mod_write_driver("write_driver")
self.add_mod(self.driver) self.add_mod(self.driver)
# This is just used for measurements, # This is just used for measurements,
# so don't add the module # so don't add the module
c = reload(__import__(OPTS.bitcell)) self.bitcell = factory.create(module_type="bitcell")
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
def create_write_array(self): def create_write_array(self):
self.driver_insts = {} self.driver_insts = {}
@ -134,3 +132,7 @@ class write_driver_array(design.design):
def get_w_en_cin(self):
"""Get the relative capacitance of all the enable connections in the bank"""
#The enable is connected to a nand2 for every row.
return self.driver.get_w_en_cin() * len(self.driver_insts)

View File

@ -44,15 +44,16 @@ from sram_config import sram_config
# Configure the SRAM organization # Configure the SRAM organization
c = sram_config(word_size=OPTS.word_size, c = sram_config(word_size=OPTS.word_size,
num_words=OPTS.num_words) num_words=OPTS.num_words)
print("Words per row: {}".format(c.words_per_row)) debug.print_raw("Words per row: {}".format(c.words_per_row))
#from parser import * #from parser import *
output_extensions = ["sp","v","lib","py","html"] output_extensions = ["sp","v","lib","py","html","log"]
if not OPTS.netlist_only: if not OPTS.netlist_only:
output_extensions.extend(["gds","lef"]) output_extensions.extend(["gds","lef"])
output_files = ["{0}{1}.{2}".format(OPTS.output_path,OPTS.output_name,x) for x in output_extensions] output_files = ["{0}{1}.{2}".format(OPTS.output_path,OPTS.output_name,x) for x in output_extensions]
print("Output files are: ") debug.print_raw("Output files are: ")
print(*output_files,sep="\n") for path in output_files:
debug.print_raw(path)
from sram import sram from sram import sram

View File

@ -72,23 +72,24 @@ class options(optparse.Values):
num_banks = 1 num_banks = 1
# These are the default modules that can be over-riden # These are the default modules that can be over-riden
bank_select = "bank_select"
bitcell_array = "bitcell_array"
bitcell = "bitcell"
column_mux_array = "single_level_column_mux_array"
control_logic = "control_logic"
decoder = "hierarchical_decoder" decoder = "hierarchical_decoder"
delay_chain = "delay_chain"
dff_array = "dff_array" dff_array = "dff_array"
dff = "dff" dff = "dff"
control_logic = "control_logic"
bitcell_array = "bitcell_array"
sense_amp = "sense_amp"
sense_amp_array = "sense_amp_array"
precharge_array = "precharge_array" precharge_array = "precharge_array"
column_mux_array = "single_level_column_mux_array" ptx = "ptx"
write_driver = "write_driver"
write_driver_array = "write_driver_array"
tri_gate = "tri_gate"
tri_gate_array = "tri_gate_array"
wordline_driver = "wordline_driver"
replica_bitline = "replica_bitline"
replica_bitcell = "replica_bitcell" replica_bitcell = "replica_bitcell"
bitcell = "bitcell" replica_bitline = "replica_bitline"
delay_chain = "delay_chain" sense_amp_array = "sense_amp_array"
bank_select = "bank_select" sense_amp = "sense_amp"
tri_gate_array = "tri_gate_array"
tri_gate = "tri_gate"
wordline_driver = "wordline_driver"
write_driver_array = "write_driver_array"
write_driver = "write_driver"

View File

@ -3,31 +3,19 @@ from tech import drc
from math import log from math import log
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from pnand2 import pnand2
from pinv import pinv
import pgate import pgate
from sram_factory import factory
class pand2(pgate.pgate): class pand2(pgate.pgate):
""" """
This is a simple buffer used for driving loads. This is a simple buffer used for driving loads.
""" """
from importlib import reload def __init__(self, name, size=1, height=None):
c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.bitcell)
unique_id = 1
def __init__(self, size=1, height=None, name=""):
self.size = size self.size = size
if name=="":
name = "pand2_{0}_{1}".format(size, pand2.unique_id)
pand2.unique_id += 1
pgate.pgate.__init__(self, name, height) pgate.pgate.__init__(self, name, height)
debug.info(1, "Creating {}".format(self.name)) debug.info(1, "Creating {}".format(self.name))
self.add_comment("size: {}".format(size))
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
@ -41,10 +29,10 @@ class pand2(pgate.pgate):
def create_modules(self): def create_modules(self):
# Shield the cap, but have at least a stage effort of 4 # Shield the cap, but have at least a stage effort of 4
self.nand = 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 = pinv(size=self.size, height=self.height) self.inv = factory.create(module_type="pinv", size=self.size, height=self.height)
self.add_mod(self.inv) self.add_mod(self.inv)
def create_layout(self): def create_layout(self):
@ -125,15 +113,15 @@ class pand2(pgate.pgate):
inv_delay = self.inv.analytical_delay(slew=nand_delay.slew, load=load) inv_delay = self.inv.analytical_delay(slew=nand_delay.slew, load=load)
return nand_delay + inv_delay return nand_delay + inv_delay
def get_output_stage_efforts(self, external_cout, inp_is_rise=False): def get_stage_efforts(self, external_cout, inp_is_rise=False):
"""Get the stage efforts of the A or B -> Z path""" """Get the stage efforts of the A or B -> Z path"""
stage_effort_list = [] stage_effort_list = []
stage1_cout = self.inv.get_cin() stage1_cout = self.inv.get_cin()
stage1 = self.nand.get_effort_stage(stage1_cout, inp_is_rise) stage1 = self.nand.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 last_stage_is_rise = stage1.is_rise
stage2 = self.inv.get_effort_stage(external_cout, last_stage_is_rise) stage2 = self.inv.get_stage_effort(external_cout, last_stage_is_rise)
stage_effort_list.append(stage2) stage_effort_list.append(stage2)
return stage_effort_list return stage_effort_list

View File

@ -3,32 +3,23 @@ from tech import drc
from math import log from math import log
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from pinv import pinv
import pgate import pgate
from sram_factory import factory
class pbuf(pgate.pgate): class pbuf(pgate.pgate):
""" """
This is a simple buffer used for driving loads. This is a simple buffer used for driving loads.
""" """
from importlib import reload def __init__(self, name, size=4, height=None):
c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.bitcell)
unique_id = 1
def __init__(self, size=4, height=None, name=""):
self.stage_effort = 4 self.stage_effort = 4
self.size = size self.size = size
self.height = height self.height = height
if name=="":
name = "pbuf_{0}_{1}".format(self.size, pbuf.unique_id)
pbuf.unique_id += 1
pgate.pgate.__init__(self, name, height) pgate.pgate.__init__(self, name, height)
debug.info(1, "creating {0} with size of {1}".format(self.name,self.size)) debug.info(1, "creating {0} with size of {1}".format(self.name,self.size))
self.add_comment("size: {}".format(size))
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.create_layout() self.create_layout()
@ -54,10 +45,10 @@ class pbuf(pgate.pgate):
def create_modules(self): def create_modules(self):
# Shield the cap, but have at least a stage effort of 4 # Shield the cap, but have at least a stage effort of 4
input_size = max(1,int(self.size/self.stage_effort)) input_size = max(1,int(self.size/self.stage_effort))
self.inv1 = pinv(size=input_size, height=self.height) self.inv1 = factory.create(module_type="pinv", size=input_size, height=self.height)
self.add_mod(self.inv1) self.add_mod(self.inv1)
self.inv2 = pinv(size=self.size, height=self.height) self.inv2 = factory.create(module_type="pinv", size=self.size, height=self.height)
self.add_mod(self.inv2) self.add_mod(self.inv2)
def create_insts(self): def create_insts(self):
@ -125,15 +116,15 @@ class pbuf(pgate.pgate):
inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load) inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load)
return inv1_delay + inv2_delay return inv1_delay + inv2_delay
def get_output_stage_efforts(self, external_cout, inp_is_rise=False): def get_stage_efforts(self, external_cout, inp_is_rise=False):
"""Get the stage efforts of the A -> Z path""" """Get the stage efforts of the A -> Z path"""
stage_effort_list = [] stage_effort_list = []
stage1_cout = self.inv2.get_cin() stage1_cout = self.inv2.get_cin()
stage1 = self.inv1.get_effort_stage(stage1_cout, inp_is_rise) stage1 = self.inv1.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 last_stage_is_rise = stage1.is_rise
stage2 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise) stage2 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise)
stage_effort_list.append(stage2) stage_effort_list.append(stage2)
return stage_effort_list return stage_effort_list
@ -141,4 +132,4 @@ class pbuf(pgate.pgate):
def get_cin(self): def get_cin(self):
"""Returns the relative capacitance of the input""" """Returns the relative capacitance of the input"""
input_cin = self.inv1.get_cin() input_cin = self.inv1.get_cin()
return input_cin return input_cin

View File

@ -5,112 +5,74 @@ from tech import drc
from math import log from math import log
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from pinv import pinv from sram_factory import factory
class pdriver(pgate.pgate): class pdriver(pgate.pgate):
""" """
This instantiates an even or odd number of inverters sized for driving a load. This instantiates an even or odd number of inverters sized for driving a load.
""" """
unique_id = 1 def __init__(self, name, neg_polarity=False, fanout=0, size_list=None, height=None):
def __init__(self, neg_polarity=False, fanout_size=8, size_list = [], height=None, name=""): self.stage_effort = 3
self.stage_effort = 4
self.height = height self.height = height
self.neg_polarity = neg_polarity self.neg_polarity = neg_polarity
self.size_list = size_list self.size_list = size_list
self.fanout_size = fanout_size self.fanout = fanout
if len(self.size_list) > 0 and (self.fanout_size != 8 or self.neg_polarity): if self.size_list and self.fanout != 0:
debug.error("Cannot specify both size_list and neg_polarity or fanout_size.", -1) debug.error("Cannot specify both size_list and fanout.", -1)
if self.size_list and self.neg_polarity:
debug.error("Cannot specify both size_list and neg_polarity.", -1)
if name=="":
name = "pdriver_{}".format(pdriver.unique_id)
pdriver.unique_id += 1
pgate.pgate.__init__(self, name, height) pgate.pgate.__init__(self, name, height)
debug.info(1, "Creating {}".format(self.name)) debug.info(1, "Creating {}".format(self.name))
self.compute_sizes() self.compute_sizes()
self.add_comment("sizes: {}".format(str(self.size_list)))
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.create_layout() self.create_layout()
def compute_sizes(self): def compute_sizes(self):
# size_list specified # size_list specified
if len(self.size_list) > 0: if self.size_list:
if not len(self.size_list) % 2: self.num_stages = len(self.size_list)
neg_polarity = True
self.num_inv = len(self.size_list)
else: else:
# find the number of stages # Find the optimal number of stages for the given effort
#fanout_size is a unit inverter fanout, not a capacitance so c_in=1 self.num_stages = max(1,int(round(log(self.fanout)/log(self.stage_effort))))
num_stages = max(1,int(round(log(self.fanout_size)/log(4))))
# find inv_num and compute sizes # Increase the number of stages if we need to fix polarity
if self.neg_polarity: if self.neg_polarity and (self.num_stages%2==0):
if (num_stages % 2 == 0): # if num_stages is even self.num_stages += 1
self.diff_polarity(num_stages=num_stages) elif not self.neg_polarity and (self.num_stages%2):
else: # if num_stages is odd self.num_stages += 1
self.same_polarity(num_stages=num_stages)
else: # positive polarity
if (num_stages % 2 == 0):
self.same_polarity(num_stages=num_stages)
else:
self.diff_polarity(num_stages=num_stages)
def same_polarity(self, num_stages): self.size_list = []
self.calc_size_list = [] # compute sizes backwards from the fanout
self.num_inv = num_stages fanout_prev = self.fanout
# compute sizes for x in range(self.num_stages):
fanout_size_prev = self.fanout_size fanout_prev = max(round(fanout_prev/self.stage_effort),1)
for x in range(self.num_inv-1,-1,-1): self.size_list.append(fanout_prev)
fanout_size_prev = int(round(fanout_size_prev/self.stage_effort))
self.calc_size_list.append(fanout_size_prev)
# reverse the sizes to be from input to output
def diff_polarity(self, num_stages): self.size_list.reverse()
self.calc_size_list = []
# find which delay is smaller
if (num_stages > 1):
delay_below = ((num_stages-1)*(self.fanout_size**(1/num_stages-1))) + num_stages-1
delay_above = ((num_stages+1)*(self.fanout_size**(1/num_stages+1))) + num_stages+1
if (delay_above < delay_below):
# recompute stage_effort for this delay
self.num_inv = num_stages+1
polarity_stage_effort = self.fanout_size**(1/self.num_inv)
else:
self.num_inv = num_stages-1
polarity_stage_effort = self.fanout_size**(1/self.num_inv)
else: # num_stages is 1, can't go to 0
self.num_inv = num_stages+1
polarity_stage_effort = self.fanout_size**(1/self.num_inv)
# compute sizes
fanout_size_prev = self.fanout_size
for x in range(self.num_inv-1,-1,-1):
fanout_size_prev = int(round(fanout_size_prev/polarity_stage_effort))
self.calc_size_list.append(fanout_size_prev)
def create_netlist(self): def create_netlist(self):
inv_list = []
self.add_pins() self.add_pins()
self.add_modules() self.add_modules()
self.create_insts() self.create_insts()
def create_layout(self): def create_layout(self):
self.width = self.num_inv * self.inv_list[0].width
self.height = self.inv_list[0].height
self.place_modules() self.place_modules()
self.route_wires() self.route_wires()
self.add_layout_pins() self.add_layout_pins()
self.width = self.inv_inst_list[-1].rx()
self.height = self.inv_inst_list[0].height
self.DRC_LVS() self.DRC_LVS()
def add_pins(self): def add_pins(self):
@ -121,31 +83,27 @@ class pdriver(pgate.pgate):
def add_modules(self): def add_modules(self):
self.inv_list = [] self.inv_list = []
if len(self.size_list) > 0: # size list specified for size in self.size_list:
for x in range(len(self.size_list)): temp_inv = factory.create(module_type="pinv", size=size, height=self.height)
self.inv_list.append(pinv(size=self.size_list[x], height=self.height)) self.inv_list.append(temp_inv)
self.add_mod(self.inv_list[x]) self.add_mod(temp_inv)
else: # find inv sizes
for x in range(len(self.calc_size_list)):
self.inv_list.append(pinv(size=self.calc_size_list[x], height=self.height))
self.add_mod(self.inv_list[x])
def create_insts(self): def create_insts(self):
self.inv_inst_list = [] self.inv_inst_list = []
for x in range(1,self.num_inv+1): for x in range(1,self.num_stages+1):
# Create first inverter # Create first inverter
if x == 1: if x == 1:
zbx_int = "Zb{}_int".format(x); zbx_int = "Zb{}_int".format(x);
self.inv_inst_list.append(self.add_inst(name="buf_inv{}".format(x), self.inv_inst_list.append(self.add_inst(name="buf_inv{}".format(x),
mod=self.inv_list[x-1])) mod=self.inv_list[x-1]))
if self.num_inv == 1: if self.num_stages == 1:
self.connect_inst(["A", "Z", "vdd", "gnd"]) self.connect_inst(["A", "Z", "vdd", "gnd"])
else: else:
self.connect_inst(["A", zbx_int, "vdd", "gnd"]) self.connect_inst(["A", zbx_int, "vdd", "gnd"])
# Create last inverter # Create last inverter
elif x == self.num_inv: elif x == self.num_stages:
zbn_int = "Zb{}_int".format(x-1); zbn_int = "Zb{}_int".format(x-1);
self.inv_inst_list.append(self.add_inst(name="buf_inv{}".format(x), self.inv_inst_list.append(self.add_inst(name="buf_inv{}".format(x),
mod=self.inv_list[x-1])) mod=self.inv_list[x-1]))
@ -161,10 +119,10 @@ class pdriver(pgate.pgate):
def place_modules(self): def place_modules(self):
# Add INV1 to the left # Add the first inverter at the origin
self.inv_inst_list[0].place(vector(0,0)) self.inv_inst_list[0].place(vector(0,0))
# Add inverters to the right of INV1 # Add inverters to the right of the previous inverter
for x in range(1,len(self.inv_inst_list)): for x in range(1,len(self.inv_inst_list)):
self.inv_inst_list[x].place(vector(self.inv_inst_list[x-1].rx(),0)) self.inv_inst_list[x].place(vector(self.inv_inst_list[x-1].rx(),0))
@ -211,22 +169,49 @@ class pdriver(pgate.pgate):
width = a_pin.width(), width = a_pin.width(),
height = a_pin.height()) height = a_pin.height())
def input_load(self):
return self.inv_list[0].input_load()
def analytical_delay(self, slew, load=0.0): def analytical_delay(self, slew, load=0.0):
"""Calculate the analytical delay of INV1 -> ... -> INVn""" """Calculate the analytical delay of INV1 -> ... -> INVn"""
delay = 0;
if len(self.inv_inst_list) == 1: cout_list = []
delay = self.inv_inst_list[x].analytical_delay(slew=slew); for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]):
else: cout_list.append(inv.input_load())
for x in range(len(self.inv_inst_list-1)): cout_list.append(load)
load_next = 0.0
for n in range(x,len(self.inv_inst_list+1)): input_slew = slew
load_next += self.inv_inst_list[x+1]
if x == 1: delays = []
delay += self.inv_inst_list[x].analytical_delay(slew=slew, for inv,cout in zip(self.inv_list,cout_list):
load=load_next) delays.append(inv.analytical_delay(slew=input_slew, load=cout))
else: input_slew = delays[-1].slew
delay += self.inv_inst_list[x+1].analytical_delay(slew=delay.slew,
load=load_next) delay = delays[0]
for i in range(len(delays)-1):
delay += delays[i]
return delay return delay
def get_stage_efforts(self, external_cout, inp_is_rise=False):
"""Get the stage efforts of the A -> Z path"""
cout_list = {}
for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]):
cout_list[prev_inv]=inv.get_cin()
cout_list[self.inv_list[-1]]=external_cout
stage_effort_list = []
last_inp_is_rise = inp_is_rise
for inv in self.inv_list:
stage = inv.get_stage_effort(cout_list[inv], last_inp_is_rise)
stage_effort_list.append(stage)
last_inp_is_rise = stage.is_rise
return stage_effort_list
def get_cin(self):
"""Returns the relative capacitance of the input"""
return self.inv_list[0].get_cin()

View File

@ -2,9 +2,9 @@ import contact
import design import design
import debug import debug
from tech import drc, parameter, spice from tech import drc, parameter, spice
from ptx import ptx
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory
class pgate(design.design): class pgate(design.design):
""" """
@ -18,15 +18,12 @@ class pgate(design.design):
if height: if height:
self.height = height self.height = height
elif not height: elif not height:
from importlib import reload b = factory.create(module_type="bitcell")
c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.bitcell)
b = bitcell()
self.height = b.height self.height = b.height
def connect_pin_to_rail(self,inst,pin,supply): def connect_pin_to_rail(self,inst,pin,supply):
""" Conencts a ptx pin to a supply rail. """ """ Connects a ptx pin to a supply rail. """
source_pin = inst.get_pin(pin) source_pin = inst.get_pin(pin)
supply_pin = self.get_pin(supply) supply_pin = self.get_pin(supply)
if supply_pin.overlaps(source_pin): if supply_pin.overlaps(source_pin):

View File

@ -2,12 +2,12 @@ import contact
import pgate import pgate
import debug import debug
from tech import drc, parameter, spice from tech import drc, parameter, spice
from ptx import ptx
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
import logical_effort import logical_effort
from sram_factory import factory
class pinv(pgate.pgate): class pinv(pgate.pgate):
""" """
@ -19,17 +19,14 @@ class pinv(pgate.pgate):
output to the right side of the cell for easier access. output to the right side of the cell for easier access.
""" """
unique_id = 1 def __init__(self, name, size=1, beta=parameter["beta"], height=None, route_output=True):
def __init__(self, size=1, beta=parameter["beta"], height=None, route_output=True):
# 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 = "pinv_{}".format(pinv.unique_id)
pinv.unique_id += 1
pgate.pgate.__init__(self, name, height) pgate.pgate.__init__(self, name, height)
debug.info(2, "create pinv structure {0} with size of {1}".format(name, size)) debug.info(2, "create pinv structure {0} with size of {1}".format(name, size))
self.add_comment("size: {}".format(size))
self.size = size self.size = size
self.nmos_size = size self.nmos_size = size
@ -86,8 +83,8 @@ class pinv(pgate.pgate):
# Sanity check. can we make an inverter in the height with minimum tx sizes? # Sanity check. can we make an inverter in the height with minimum tx sizes?
# Assume we need 3 metal 1 pitches (2 power rails, one between the tx for the drain) # Assume we need 3 metal 1 pitches (2 power rails, one between the tx for the drain)
# plus the tx height # plus the tx height
nmos = ptx(tx_type="nmos") nmos = factory.create(module_type="ptx", tx_type="nmos")
pmos = ptx(width=drc("minwidth_tx"), tx_type="pmos") pmos = factory.create(module_type="ptx", width=drc("minwidth_tx"), tx_type="pmos")
tx_height = nmos.poly_height + pmos.poly_height tx_height = nmos.poly_height + pmos.poly_height
# rotated m1 pitch or poly to active spacing # rotated m1 pitch or poly to active spacing
min_channel = max(contact.poly.width + self.m1_space, min_channel = max(contact.poly.width + self.m1_space,
@ -147,18 +144,20 @@ class pinv(pgate.pgate):
def add_ptx(self): def add_ptx(self):
""" Create the PMOS and NMOS transistors. """ """ Create the PMOS and NMOS transistors. """
self.nmos = ptx(width=self.nmos_width, self.nmos = factory.create(module_type="ptx",
mults=self.tx_mults, width=self.nmos_width,
tx_type="nmos", mults=self.tx_mults,
connect_poly=True, tx_type="nmos",
connect_active=True) connect_poly=True,
connect_active=True)
self.add_mod(self.nmos) self.add_mod(self.nmos)
self.pmos = ptx(width=self.pmos_width, self.pmos = factory.create(module_type="ptx",
mults=self.tx_mults, width=self.pmos_width,
tx_type="pmos", mults=self.tx_mults,
connect_poly=True, tx_type="pmos",
connect_active=True) connect_poly=True,
connect_active=True)
self.add_mod(self.pmos) self.add_mod(self.pmos)
def route_supply_rails(self): def route_supply_rails(self):
@ -288,7 +287,7 @@ class pinv(pgate.pgate):
"""Return the capacitance of the gate connection in generic capacitive units relative to the minimum width of a transistor""" """Return the capacitance of the gate connection in generic capacitive units relative to the minimum width of a transistor"""
return self.nmos_size + self.pmos_size return self.nmos_size + self.pmos_size
def get_effort_stage(self, cout, inp_is_rise=True): def get_stage_effort(self, cout, inp_is_rise=True):
"""Returns an object representing the parameters for delay in tau units. """Returns an object representing the parameters for delay in tau units.
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage. Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
""" """

View File

@ -4,16 +4,14 @@ from tech import drc
from math import log from math import log
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from pinv import pinv from sram_factory import factory
class pinvbuf(design.design): class pinvbuf(design.design):
""" """
This is a simple inverter/buffer used for driving loads. It is This is a simple inverter/buffer used for driving loads. It is
used in the column decoder for 1:2 decoding and as the clock buffer. used in the column decoder for 1:2 decoding and as the clock buffer.
""" """
unique_id = 1 def __init__(self, name, size=4, height=None):
def __init__(self, driver_size=4, height=None, name=""):
self.stage_effort = 4 self.stage_effort = 4
self.row_height = height self.row_height = height
@ -22,14 +20,12 @@ class pinvbuf(design.design):
# stage effort of 4 or less # stage effort of 4 or less
# The pinvbuf has a FO of 2 for the first stage, so the second stage # The pinvbuf has a FO of 2 for the first stage, so the second stage
# should be sized "half" to prevent loading of the first stage # should be sized "half" to prevent loading of the first stage
self.driver_size = driver_size self.size = size
self.predriver_size = max(int(self.driver_size/(self.stage_effort/2)),1) self.predriver_size = max(int(self.size/(self.stage_effort/2)),1)
if name=="":
name = "pinvbuf_{0}_{1}_{2}".format(self.predriver_size, self.driver_size, pinvbuf.unique_id)
pinvbuf.unique_id += 1
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {}".format(self.name)) debug.info(1, "Creating {}".format(self.name))
self.add_comment("size: {}".format(size))
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
@ -65,13 +61,13 @@ class pinvbuf(design.design):
# Shield the cap, but have at least a stage effort of 4 # Shield the cap, but have at least a stage effort of 4
input_size = max(1,int(self.predriver_size/self.stage_effort)) input_size = max(1,int(self.predriver_size/self.stage_effort))
self.inv = pinv(size=input_size, height=self.row_height) self.inv = factory.create(module_type="pinv", size=input_size, height=self.row_height)
self.add_mod(self.inv) self.add_mod(self.inv)
self.inv1 = pinv(size=self.predriver_size, height=self.row_height) self.inv1 = factory.create(module_type="pinv", size=self.predriver_size, height=self.row_height)
self.add_mod(self.inv1) self.add_mod(self.inv1)
self.inv2 = pinv(size=self.driver_size, height=self.row_height) self.inv2 = factory.create(module_type="pinv", size=self.size, height=self.row_height)
self.add_mod(self.inv2) self.add_mod(self.inv2)
def create_insts(self): def create_insts(self):
@ -191,11 +187,11 @@ class pinvbuf(design.design):
"""Get the stage efforts of the clk -> clk_buf path""" """Get the stage efforts of the clk -> clk_buf path"""
stage_effort_list = [] stage_effort_list = []
stage1_cout = self.inv1.get_cin() + self.inv2.get_cin() stage1_cout = self.inv1.get_cin() + self.inv2.get_cin()
stage1 = self.inv.get_effort_stage(stage1_cout, inp_is_rise) stage1 = self.inv.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 last_stage_is_rise = stage1.is_rise
stage2 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise) stage2 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise)
stage_effort_list.append(stage2) stage_effort_list.append(stage2)
return stage_effort_list return stage_effort_list
@ -205,16 +201,16 @@ class pinvbuf(design.design):
#After (almost) every stage, the direction of the signal inverts. #After (almost) every stage, the direction of the signal inverts.
stage_effort_list = [] stage_effort_list = []
stage1_cout = self.inv1.get_cin() + self.inv2.get_cin() stage1_cout = self.inv1.get_cin() + self.inv2.get_cin()
stage1 = self.inv.get_effort_stage(stage1_cout, inp_is_rise) stage1 = self.inv.get_stage_effort(stage1_cout, inp_is_rise)
stage_effort_list.append(stage1) stage_effort_list.append(stage1)
last_stage_is_rise = stage_effort_list[-1].is_rise last_stage_is_rise = stage_effort_list[-1].is_rise
stage2_cout = self.inv2.get_cin() stage2_cout = self.inv2.get_cin()
stage2 = self.inv1.get_effort_stage(stage2_cout, last_stage_is_rise) stage2 = self.inv1.get_stage_effort(stage2_cout, last_stage_is_rise)
stage_effort_list.append(stage2) stage_effort_list.append(stage2)
last_stage_is_rise = stage_effort_list[-1].is_rise last_stage_is_rise = stage_effort_list[-1].is_rise
stage3 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise) stage3 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise)
stage_effort_list.append(stage3) stage_effort_list.append(stage3)
return stage_effort_list return stage_effort_list

View File

@ -2,25 +2,21 @@ import contact
import pgate import pgate
import debug import debug
from tech import drc, parameter, spice from tech import drc, parameter, spice
from ptx import ptx
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
import logical_effort import logical_effort
from sram_factory import factory
class pnand2(pgate.pgate): class pnand2(pgate.pgate):
""" """
This module generates gds of a parametrically sized 2-input nand. This module generates gds of a parametrically sized 2-input nand.
This model use ptx to generate a 2-input nand within a cetrain height. This model use ptx to generate a 2-input nand within a cetrain height.
""" """
def __init__(self, name, size=1, height=None):
unique_id = 1
def __init__(self, size=1, height=None):
""" Creates a cell for a simple 2 input nand """ """ Creates a cell for a simple 2 input nand """
name = "pnand2_{0}".format(pnand2.unique_id)
pnand2.unique_id += 1
pgate.pgate.__init__(self, name, height) pgate.pgate.__init__(self, name, height)
debug.info(2, "create pnand2 structure {0} with size of {1}".format(name, size)) debug.info(2, "create pnand2 structure {0} with size of {1}".format(name, size))
self.add_comment("size: {}".format(size))
self.size = size self.size = size
self.nmos_size = 2*size self.nmos_size = 2*size
@ -61,18 +57,20 @@ 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 = ptx(width=self.nmos_width, self.nmos = factory.create(module_type="ptx",
mults=self.tx_mults, width=self.nmos_width,
tx_type="nmos", mults=self.tx_mults,
connect_poly=True, tx_type="nmos",
connect_active=True) connect_poly=True,
connect_active=True)
self.add_mod(self.nmos) self.add_mod(self.nmos)
self.pmos = ptx(width=self.pmos_width, self.pmos = factory.create(module_type="ptx",
mults=self.tx_mults, width=self.pmos_width,
tx_type="pmos", mults=self.tx_mults,
connect_poly=True, tx_type="pmos",
connect_active=True) connect_poly=True,
connect_active=True)
self.add_mod(self.pmos) self.add_mod(self.pmos)
def setup_layout_constants(self): def setup_layout_constants(self):
@ -255,9 +253,9 @@ class pnand2(pgate.pgate):
"""Return the relative input capacitance of a single input""" """Return the relative input capacitance of a single input"""
return self.nmos_size+self.pmos_size return self.nmos_size+self.pmos_size
def get_effort_stage(self, cout, inp_is_rise=True): def get_stage_effort(self, cout, inp_is_rise=True):
"""Returns an object representing the parameters for delay in tau units. """Returns an object representing the parameters for delay in tau units.
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage. Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
""" """
parasitic_delay = 2 parasitic_delay = 2
return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise) return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)

View File

@ -2,24 +2,20 @@ import contact
import pgate import pgate
import debug import debug
from tech import drc, parameter, spice from tech import drc, parameter, spice
from ptx import ptx
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory
class pnand3(pgate.pgate): class pnand3(pgate.pgate):
""" """
This module generates gds of a parametrically sized 2-input nand. This module generates gds of a parametrically sized 2-input nand.
This model use ptx to generate a 2-input nand within a cetrain height. This model use ptx to generate a 2-input nand within a cetrain height.
""" """
def __init__(self, name, size=1, height=None):
unique_id = 1
def __init__(self, size=1, height=None):
""" Creates a cell for a simple 3 input nand """ """ Creates a cell for a simple 3 input nand """
name = "pnand3_{0}".format(pnand3.unique_id)
pnand3.unique_id += 1
pgate.pgate.__init__(self, name, height) pgate.pgate.__init__(self, name, height)
debug.info(2, "create pnand3 structure {0} with size of {1}".format(name, size)) debug.info(2, "create pnand3 structure {0} with size of {1}".format(name, size))
self.add_comment("size: {}".format(size))
# We have trouble pitch matching a 3x sizes to the bitcell... # We have trouble pitch matching a 3x sizes to the bitcell...
# If we relax this, we could size this better. # If we relax this, we could size this better.
@ -61,18 +57,20 @@ class pnand3(pgate.pgate):
def add_ptx(self): def add_ptx(self):
""" Create the PMOS and NMOS transistors. """ """ Create the PMOS and NMOS transistors. """
self.nmos = ptx(width=self.nmos_width, self.nmos = factory.create(module_type="ptx",
mults=self.tx_mults, width=self.nmos_width,
tx_type="nmos", mults=self.tx_mults,
connect_poly=True, tx_type="nmos",
connect_active=True) connect_poly=True,
connect_active=True)
self.add_mod(self.nmos) self.add_mod(self.nmos)
self.pmos = ptx(width=self.pmos_width, self.pmos = factory.create(module_type="ptx",
mults=self.tx_mults, width=self.pmos_width,
tx_type="pmos", mults=self.tx_mults,
connect_poly=True, tx_type="pmos",
connect_active=True) connect_poly=True,
connect_active=True)
self.add_mod(self.pmos) self.add_mod(self.pmos)
def setup_layout_constants(self): def setup_layout_constants(self):
@ -93,7 +91,7 @@ class pnand3(pgate.pgate):
self.output_pos = vector(0,0.5*self.height) self.output_pos = vector(0,0.5*self.height)
# This is the extra space needed to ensure DRC rules to the active contacts # This is the extra space needed to ensure DRC rules to the active contacts
nmos = ptx(tx_type="nmos") nmos = factory.create(module_type="ptx", tx_type="nmos")
extra_contact_space = max(-nmos.get_pin("D").by(),0) extra_contact_space = max(-nmos.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,
@ -267,9 +265,9 @@ class pnand3(pgate.pgate):
"""Return the relative input capacitance of a single input""" """Return the relative input capacitance of a single input"""
return self.nmos_size+self.pmos_size return self.nmos_size+self.pmos_size
def get_effort_stage(self, cout, inp_is_rise=True): def get_stage_effort(self, cout, inp_is_rise=True):
"""Returns an object representing the parameters for delay in tau units. """Returns an object representing the parameters for delay in tau units.
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage. Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
""" """
parasitic_delay = 3 parasitic_delay = 3
return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise) return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)

View File

@ -1,25 +1,21 @@
import contact
import pgate import pgate
import debug import debug
from tech import drc, parameter, spice from tech import drc, parameter, spice
from ptx import ptx
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
import contact
from sram_factory import factory
class pnor2(pgate.pgate): class pnor2(pgate.pgate):
""" """
This module generates gds of a parametrically sized 2-input nor. This module generates gds of a parametrically sized 2-input nor.
This model use ptx to generate a 2-input nor within a cetrain height. This model use ptx to generate a 2-input nor within a cetrain height.
""" """
def __init__(self, name, size=1, height=None):
unique_id = 1
def __init__(self, size=1, height=None):
""" Creates a cell for a simple 2 input nor """ """ Creates a cell for a simple 2 input nor """
name = "pnor2_{0}".format(pnor2.unique_id)
pnor2.unique_id += 1
pgate.pgate.__init__(self, name, height) pgate.pgate.__init__(self, name, height)
debug.info(2, "create pnor2 structure {0} with size of {1}".format(name, size)) debug.info(2, "create pnor2 structure {0} with size of {1}".format(name, size))
self.add_comment("size: {}".format(size))
self.nmos_size = size self.nmos_size = size
# We will just make this 1.5 times for now. NORs are not ideal anyhow. # We will just make this 1.5 times for now. NORs are not ideal anyhow.
@ -58,32 +54,30 @@ class pnor2(pgate.pgate):
def create_ptx(self): def create_ptx(self):
""" Create the PMOS and NMOS transistors. """ """ Create the PMOS and NMOS transistors. """
self.nmos = ptx(width=self.nmos_width, self.nmos = factory.create(module_type="ptx",
mults=self.tx_mults, width=self.nmos_width,
tx_type="nmos", mults=self.tx_mults,
connect_poly=True, tx_type="nmos",
connect_active=True) connect_poly=True,
connect_active=True)
self.add_mod(self.nmos) self.add_mod(self.nmos)
self.pmos = ptx(width=self.pmos_width, self.pmos = factory.create(module_type="ptx",
mults=self.tx_mults, width=self.pmos_width,
tx_type="pmos", mults=self.tx_mults,
connect_poly=True, tx_type="pmos",
connect_active=True) connect_poly=True,
connect_active=True)
self.add_mod(self.pmos) self.add_mod(self.pmos)
def setup_layout_constants(self): def setup_layout_constants(self):
""" Pre-compute some handy layout parameters. """ """ Pre-compute some handy layout parameters. """
poly_contact = contact.contact(("poly","contact","metal1"))
m1m2_via = contact.contact(("metal1","via1","metal2"))
m2m3_via = contact.contact(("metal2","via2","metal3"))
# metal spacing to allow contacts on any layer # metal spacing to allow contacts on any layer
self.input_spacing = max(self.poly_space + poly_contact.first_layer_width, self.input_spacing = max(self.poly_space + contact.poly.first_layer_width,
self.m1_space + m1m2_via.first_layer_width, self.m1_space + contact.m1m2.first_layer_width,
self.m2_space + m2m3_via.first_layer_width, self.m2_space + contact.m2m3.first_layer_width,
self.m3_space + m2m3_via.second_layer_width) self.m3_space + contact.m2m3.second_layer_width)
# Compute the other pmos2 location, but determining offset to overlap the # Compute the other pmos2 location, but determining offset to overlap the
# source and drain pins # source and drain pins

View File

@ -2,28 +2,20 @@ import contact
import pgate import pgate
import debug import debug
from tech import drc, parameter from tech import drc, parameter
from ptx import ptx
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory
class precharge(pgate.pgate): class precharge(pgate.pgate):
""" """
Creates a single precharge cell Creates a single precharge cell
This module implements the precharge bitline cell used in the design. This module implements the precharge bitline cell used in the design.
""" """
unique_id = 1
def __init__(self, name, size=1, bitcell_bl="bl", bitcell_br="br"): def __init__(self, name, size=1, bitcell_bl="bl", bitcell_br="br"):
name = name+"_{}".format(precharge.unique_id)
precharge.unique_id += 1
pgate.pgate.__init__(self, name) pgate.pgate.__init__(self, name)
debug.info(2, "create single precharge cell: {0}".format(name)) debug.info(2, "create single precharge cell: {0}".format(name))
from importlib import reload self.bitcell = factory.create(module_type="bitcell")
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_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"]
@ -57,8 +49,9 @@ class precharge(pgate.pgate):
""" """
Initializes the upper and lower pmos Initializes the upper and lower pmos
""" """
self.pmos = ptx(width=self.ptx_width, self.pmos = factory.create(module_type="ptx",
tx_type="pmos") width=self.ptx_width,
tx_type="pmos")
self.add_mod(self.pmos) self.add_mod(self.pmos)
@ -268,4 +261,4 @@ class precharge(pgate.pgate):
#The enable connect to three pmos gates. They all use the same size pmos. #The enable connect to three pmos gates. They all use the same size pmos.
pmos_cin = self.pmos.get_cin() pmos_cin = self.pmos.get_cin()
return 3*pmos_cin return 3*pmos_cin

View File

@ -2,9 +2,8 @@ import design
import debug import debug
from tech import drc, spice from tech import drc, spice
from vector import vector from vector import vector
from contact import contact
from globals import OPTS from globals import OPTS
import path from sram_factory import factory
class ptx(design.design): class ptx(design.design):
""" """
@ -15,7 +14,7 @@ class ptx(design.design):
you to connect the fingered gates and active for parallel devices. you to connect the fingered gates and active for parallel devices.
""" """
def __init__(self, width=drc("minwidth_tx"), mults=1, tx_type="nmos", connect_active=False, connect_poly=False, num_contacts=None): def __init__(self, name="", width=drc("minwidth_tx"), mults=1, tx_type="nmos", connect_active=False, connect_poly=False, 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
@ -97,8 +96,9 @@ class ptx(design.design):
# This is not actually instantiated but used for calculations # This is not actually instantiated but used for calculations
self.active_contact = contact(layer_stack=("active", "contact", "metal1"), self.active_contact = factory.create(module_type="contact",
dimensions=(1, self.num_contacts)) layer_stack=("active", "contact", "metal1"),
dimensions=(1, self.num_contacts))
# The contacted poly pitch (or uncontacted in an odd technology) # The contacted poly pitch (or uncontacted in an odd technology)
@ -355,4 +355,4 @@ class ptx(design.design):
def get_cin(self): def get_cin(self):
"""Returns the relative gate cin of the tx""" """Returns the relative gate cin of the tx"""
return self.tx_width/drc("minwidth_tx") return self.tx_width/drc("minwidth_tx")

View File

@ -3,8 +3,8 @@ import debug
from tech import drc from tech import drc
from vector import vector from vector import vector
import contact import contact
from ptx import ptx
from globals import OPTS from globals import OPTS
from sram_factory import factory
class single_level_column_mux(design.design): class single_level_column_mux(design.design):
""" """
@ -13,14 +13,10 @@ class single_level_column_mux(design.design):
to minimum size. Default is 8x. Per Samira and Hodges-Jackson book: to minimum size. Default is 8x. Per Samira and Hodges-Jackson book:
Column-mux transistors driven by the decoder must be sized for optimal speed Column-mux transistors driven by the decoder must be sized for optimal speed
""" """
def __init__(self, name, tx_size=8, bitcell_bl="bl", bitcell_br="br"):
# This is needed for different bitline spacings
unique_id = 1
def __init__(self, tx_size=8, bitcell_bl="bl", bitcell_br="br"):
self.tx_size = int(tx_size) self.tx_size = int(tx_size)
name="single_level_column_mux_{}_{}".format(self.tx_size,single_level_column_mux.unique_id)
single_level_column_mux.unique_id += 1
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(2, "create single column mux cell: {0}".format(name)) debug.info(2, "create single column mux cell: {0}".format(name))
@ -47,16 +43,11 @@ class single_level_column_mux(design.design):
self.add_wells() self.add_wells()
def add_modules(self): def add_modules(self):
# This is just used for measurements, self.bitcell = factory.create(module_type="bitcell")
# so don't add the module
from importlib import reload
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
# 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 = ptx(width=self.ptx_width) self.nmos = factory.create(module_type="ptx", width=self.ptx_width)
self.add_mod(self.nmos) self.add_mod(self.nmos)

View File

@ -65,21 +65,21 @@ class sram():
# Write the layout # Write the layout
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
gdsname = OPTS.output_path + self.s.name + ".gds" gdsname = OPTS.output_path + self.s.name + ".gds"
print("GDS: Writing to {0}".format(gdsname)) debug.print_raw("GDS: Writing to {0}".format(gdsname))
self.gds_write(gdsname) self.gds_write(gdsname)
print_time("GDS", datetime.datetime.now(), start_time) print_time("GDS", datetime.datetime.now(), start_time)
# Create a LEF physical model # Create a LEF physical model
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
lefname = OPTS.output_path + self.s.name + ".lef" lefname = OPTS.output_path + self.s.name + ".lef"
print("LEF: Writing to {0}".format(lefname)) debug.print_raw("LEF: Writing to {0}".format(lefname))
self.lef_write(lefname) self.lef_write(lefname)
print_time("LEF", datetime.datetime.now(), start_time) print_time("LEF", datetime.datetime.now(), start_time)
# Save the spice file # Save the spice file
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
spname = OPTS.output_path + self.s.name + ".sp" spname = OPTS.output_path + self.s.name + ".sp"
print("SP: Writing to {0}".format(spname)) debug.print_raw("SP: Writing to {0}".format(spname))
self.sp_write(spname) self.sp_write(spname)
print_time("Spice writing", datetime.datetime.now(), start_time) print_time("Spice writing", datetime.datetime.now(), start_time)
@ -98,14 +98,14 @@ class sram():
# Characterize the design # Characterize the design
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
from characterizer import lib from characterizer import lib
print("LIB: Characterizing... ") debug.print_raw("LIB: Characterizing... ")
if OPTS.analytical_delay: if OPTS.analytical_delay:
print("Using analytical delay models (no characterization)") debug.print_raw("Using analytical delay models (no characterization)")
else: else:
if OPTS.spice_name!="": if OPTS.spice_name!="":
print("Performing simulation-based characterization with {}".format(OPTS.spice_name)) debug.print_raw("Performing simulation-based characterization with {}".format(OPTS.spice_name))
if OPTS.trim_netlist: if OPTS.trim_netlist:
print("Trimming netlist to speed up characterization.") debug.print_raw("Trimming netlist to speed up characterization.")
lib(out_dir=OPTS.output_path, sram=self.s, sp_file=sp_file) lib(out_dir=OPTS.output_path, sram=self.s, sp_file=sp_file)
print_time("Characterization", datetime.datetime.now(), start_time) print_time("Characterization", datetime.datetime.now(), start_time)
@ -114,20 +114,20 @@ class sram():
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
from shutil import copyfile from shutil import copyfile
copyfile(OPTS.config_file + '.py', OPTS.output_path + OPTS.output_name + '.py') copyfile(OPTS.config_file + '.py', OPTS.output_path + OPTS.output_name + '.py')
print("Config: Writing to {0}".format(OPTS.output_path + OPTS.output_name + '.py')) debug.print_raw("Config: Writing to {0}".format(OPTS.output_path + OPTS.output_name + '.py'))
print_time("Config", datetime.datetime.now(), start_time) print_time("Config", datetime.datetime.now(), start_time)
# Write the datasheet # Write the datasheet
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
from datasheet_gen import datasheet_gen from datasheet_gen import datasheet_gen
dname = OPTS.output_path + self.s.name + ".html" dname = OPTS.output_path + self.s.name + ".html"
print("Datasheet: Writing to {0}".format(dname)) debug.print_raw("Datasheet: Writing to {0}".format(dname))
datasheet_gen.datasheet_write(self.s,dname) datasheet_gen.datasheet_write(dname)
print_time("Datasheet", datetime.datetime.now(), start_time) print_time("Datasheet", datetime.datetime.now(), start_time)
# Write a verilog model # Write a verilog model
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
vname = OPTS.output_path + self.s.name + ".v" vname = OPTS.output_path + self.s.name + ".v"
print("Verilog: Writing to {0}".format(vname)) debug.print_raw("Verilog: Writing to {0}".format(vname))
self.verilog_write(vname) self.verilog_write(vname)
print_time("Verilog", datetime.datetime.now(), start_time) print_time("Verilog", datetime.datetime.now(), start_time)

View File

@ -10,6 +10,7 @@ import logical_effort
from design import design from design import design
from verilog import verilog from verilog import verilog
from lef import lef from lef import lef
from sram_factory import factory
class sram_base(design, verilog, lef): class sram_base(design, verilog, lef):
""" """
@ -239,10 +240,7 @@ class sram_base(design, verilog, lef):
def add_modules(self): def add_modules(self):
""" Create all the modules that will be used """ self.bitcell = factory.create(module_type=OPTS.bitcell)
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
# Create the address and control flops (but not the clk) # Create the address and control flops (but not the clk)
from dff_array import dff_array from dff_array import dff_array
@ -281,20 +279,23 @@ class sram_base(design, verilog, lef):
# Create the control logic module for each port type # Create the control logic module for each port type
if len(self.readwrite_ports)>0: if len(self.readwrite_ports)>0:
self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows, self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row, words_per_row=self.words_per_row,
word_size=self.word_size,
sram=self, sram=self,
port_type="rw") port_type="rw")
self.add_mod(self.control_logic_rw) self.add_mod(self.control_logic_rw)
if len(self.writeonly_ports)>0: if len(self.writeonly_ports)>0:
self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows, self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row, words_per_row=self.words_per_row,
word_size=self.word_size,
sram=self, sram=self,
port_type="w") port_type="w")
self.add_mod(self.control_logic_w) self.add_mod(self.control_logic_w)
if len(self.readonly_ports)>0: if len(self.readonly_ports)>0:
self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows, self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row, words_per_row=self.words_per_row,
word_size=self.word_size,
sram=self, sram=self,
port_type="r") port_type="r")
self.add_mod(self.control_logic_r) self.add_mod(self.control_logic_r)
@ -514,25 +515,30 @@ class sram_base(design, verilog, lef):
def get_wl_en_cin(self): def get_wl_en_cin(self):
"""Gets the capacitive load the of clock (clk_buf) for the sram""" """Gets the capacitive load the of clock (clk_buf) for the sram"""
#As clk_buf is an output of the control logic. The cap for that module is not determined here.
#Only the wordline drivers within the bank use this signal #Only the wordline drivers within the bank use this signal
bank_clk_cin = self.bank.get_wl_en_cin() return self.bank.get_wl_en_cin()
return bank_clk_cin def get_w_en_cin(self):
"""Gets the capacitive load the of write enable (w_en) for the sram"""
#Only the write drivers within the bank use this signal
return self.bank.get_w_en_cin()
def get_p_en_bar_cin(self):
"""Gets the capacitive load the of precharge enable (p_en_bar) for the sram"""
#Only the precharges within the bank use this signal
return self.bank.get_p_en_bar_cin()
def get_clk_bar_cin(self): def get_clk_bar_cin(self):
"""Gets the capacitive load the of clock (clk_buf_bar) for the sram""" """Gets the capacitive load the of clock (clk_buf_bar) for the sram"""
#As clk_buf_bar is an output of the control logic. The cap for that module is not determined here. #As clk_buf_bar is an output of the control logic. The cap for that module is not determined here.
#Only the precharge cells use this signal (other than the control logic) #Only the precharge cells use this signal (other than the control logic)
bank_clk_cin = self.bank.get_clk_bar_cin() return self.bank.get_clk_bar_cin()
return bank_clk_cin
def get_sen_cin(self): def get_sen_cin(self):
"""Gets the capacitive load the of sense amp enable for the sram""" """Gets the capacitive load the of sense amp enable for the sram"""
#As clk_buf_bar is an output of the control logic. The cap for that module is not determined here.
#Only the sense_amps use this signal (other than the control logic) #Only the sense_amps use this signal (other than the control logic)
bank_sen_cin = self.bank.get_sen_cin() return self.bank.get_sen_cin()
return bank_sen_cin

View File

@ -2,6 +2,7 @@ import debug
from math import log,sqrt,ceil from math import log,sqrt,ceil
from importlib import reload from importlib import reload
from globals import OPTS from globals import OPTS
from sram_factory import factory
class sram_config: class sram_config:
""" This is a structure that is used to hold the SRAM configuration options. """ """ This is a structure that is used to hold the SRAM configuration options. """
@ -29,10 +30,7 @@ class sram_config:
def compute_sizes(self): def compute_sizes(self):
""" Computes the organization of the memory using bitcell size by trying to make it square.""" """ Computes the organization of the memory using bitcell size by trying to make it square."""
c = reload(__import__(OPTS.bitcell)) self.bitcell = factory.create(module_type="bitcell")
self.mod_bitcell = getattr(c, OPTS.bitcell)
# pass a copy of myself for the port numbers
self.bitcell = self.mod_bitcell()
debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.") debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.")

78
compiler/sram_factory.py Normal file
View File

@ -0,0 +1,78 @@
import debug
from globals import OPTS
from importlib import reload
class sram_factory:
"""
This is a factory pattern to create modules for usage in an SRAM.
Since GDSII has a flat namespace, it requires modules to have unique
names if their layout differs. This module ensures that any module
with different layouts will have different names. It also ensures that
identical layouts will share the same name to reduce file size and promote
hierarchical sharing.
"""
def __init__(self):
# A dictionary of modules indexed by module type
self.modules = {}
# These are the indices to append to name to make unique object names
self.module_indices = {}
# A dictionary of instance lists indexed by module type
self.objects = {}
def reset(self):
"""
Clear the factory instances for testing.
"""
self.__init__()
def create(self, module_type, **kwargs):
"""
A generic function to create a module with a given module_type. The args
are passed directly to the module constructor.
"""
# if name!="":
# # This is a special case where the name and type don't match
# # Can't be overridden in the config file
# module_name = name
if hasattr(OPTS, module_type):
# Retrieve the name from OPTS if it exists,
# otherwise just use the name
module_name = getattr(OPTS, module_type)
else:
module_name = module_type
# Either retrieve the already loaded module or load it
try:
mod = self.modules[module_type]
except KeyError:
c = reload(__import__(module_name))
mod = getattr(c, module_name)
self.modules[module_type] = mod
self.module_indices[module_type] = 0
self.objects[module_type] = []
# Either retreive a previous object or create a new one
for obj in self.objects[module_type]:
(obj_kwargs, obj_item) = obj
# Must have the same dictionary exactly (conservative)
if obj_kwargs == kwargs:
#debug.info(1, "Existing module: type={0} name={1} kwargs={2}".format(module_type, obj_item.name, str(kwargs)))
return obj_item
# Use the default name if there are default arguments
# This is especially for library cells so that the spice and gds files can be found.
if len(kwargs)>0:
# Create a unique name and increment the index
module_name = "{0}_{1}".format(module_name, self.module_indices[module_type])
self.module_indices[module_type] += 1
#debug.info(1, "New module: type={0} name={1} kwargs={2}".format(module_type,module_name,str(kwargs)))
obj = mod(name=module_name,**kwargs)
self.objects[module_type].append((kwargs,obj))
return obj
# Make a factory
factory = sram_factory()

View File

@ -25,17 +25,11 @@ class code_format_test(openram_test):
for code in source_codes: for code in source_codes:
if re.search("gdsMill", code): if re.search("gdsMill", code):
continue continue
if re.search("options.py$", code):
continue
if re.search("debug.py$", code): if re.search("debug.py$", code):
continue continue
if re.search("testutils.py$", code):
continue
if re.search("globals.py$", code):
continue
if re.search("openram.py$", code): if re.search("openram.py$", code):
continue continue
if re.search("sram.py$", code): if re.search("testutils.py$", code):
continue continue
if re.search("gen_stimulus.py$", code): if re.search("gen_stimulus.py$", code):
continue continue

View File

@ -13,7 +13,7 @@ class path_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import path import wire_path
import tech import tech
import design import design
@ -27,7 +27,7 @@ class path_test(openram_test):
[0, 3 * min_space ], [0, 3 * min_space ],
[0, 6 * min_space ]] [0, 6 * min_space ]]
w = design.design("path_test0") w = design.design("path_test0")
path.path(w,layer_stack, position_list) wire_path.wire_path(w,layer_stack, position_list)
self.local_drc_check(w) self.local_drc_check(w)
@ -44,7 +44,7 @@ class path_test(openram_test):
[-1 * min_space, 0]] [-1 * min_space, 0]]
position_list = [[x+min_space, y+min_space] for x,y in old_position_list] position_list = [[x+min_space, y+min_space] for x,y in old_position_list]
w = design.design("path_test1") w = design.design("path_test1")
path.path(w,layer_stack, position_list) wire_path.wire_path(w,layer_stack, position_list)
self.local_drc_check(w) self.local_drc_check(w)
min_space = 2 * tech.drc["minwidth_metal2"] min_space = 2 * tech.drc["minwidth_metal2"]
@ -60,7 +60,7 @@ class path_test(openram_test):
[-1 * min_space, 0]] [-1 * min_space, 0]]
position_list = [[x-min_space, y-min_space] for x,y in old_position_list] position_list = [[x-min_space, y-min_space] for x,y in old_position_list]
w = design.design("path_test2") w = design.design("path_test2")
path.path(w, layer_stack, position_list) wire_path.wire_path(w, layer_stack, position_list)
self.local_drc_check(w) self.local_drc_check(w)
min_space = 2 * tech.drc["minwidth_metal3"] min_space = 2 * tech.drc["minwidth_metal3"]
@ -77,7 +77,7 @@ class path_test(openram_test):
# run on the reverse list # run on the reverse list
position_list.reverse() position_list.reverse()
w = design.design("path_test3") w = design.design("path_test3")
path.path(w, layer_stack, position_list) wire_path.wire_path(w, layer_stack, position_list)
self.local_drc_check(w) self.local_drc_check(w)
globals.end_openram() globals.end_openram()

View File

@ -21,7 +21,7 @@ class pand2_test(openram_test):
import pand2 import pand2
debug.info(2, "Testing pand2 gate 4x") debug.info(2, "Testing pand2 gate 4x")
a = pand2.pand2(4) a = pand2.pand2(name="pand2x4", size=4)
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -10,8 +10,7 @@ sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
from sram_factory import factory
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 04_pbitcell_test") #@unittest.skip("SKIPPING 04_pbitcell_test")
class pbitcell_test(openram_test): class pbitcell_test(openram_test):
@ -19,75 +18,85 @@ class pbitcell_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
from pbitcell import pbitcell from pbitcell import pbitcell
import tech
OPTS.num_rw_ports=1 OPTS.num_rw_ports=1
OPTS.num_w_ports=1 OPTS.num_w_ports=1
OPTS.num_r_ports=1 OPTS.num_r_ports=1
factory.reset()
debug.info(2, "Bitcell with 1 of each port: read/write, write, and read") debug.info(2, "Bitcell with 1 of each port: read/write, write, and read")
tx = pbitcell() tx = pbitcell(name="pbc")
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports=0 OPTS.num_rw_ports=0
OPTS.num_w_ports=1 OPTS.num_w_ports=1
OPTS.num_r_ports=1 OPTS.num_r_ports=1
factory.reset()
debug.info(2, "Bitcell with 0 read/write ports") debug.info(2, "Bitcell with 0 read/write ports")
tx = pbitcell() tx = pbitcell(name="pbc")
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports=1 OPTS.num_rw_ports=1
OPTS.num_w_ports=0 OPTS.num_w_ports=0
OPTS.num_r_ports=1 OPTS.num_r_ports=1
factory.reset()
debug.info(2, "Bitcell with 0 write ports") debug.info(2, "Bitcell with 0 write ports")
tx = pbitcell() tx = pbitcell(name="pbc")
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports=1 OPTS.num_rw_ports=1
OPTS.num_w_ports=1 OPTS.num_w_ports=1
OPTS.num_r_ports=0 OPTS.num_r_ports=0
factory.reset()
debug.info(2, "Bitcell with 0 read ports") debug.info(2, "Bitcell with 0 read ports")
tx = pbitcell() tx = pbitcell(name="pbc")
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports=1 OPTS.num_rw_ports=1
OPTS.num_w_ports=0 OPTS.num_w_ports=0
OPTS.num_r_ports=0 OPTS.num_r_ports=0
factory.reset()
debug.info(2, "Bitcell with 0 read ports and 0 write ports") debug.info(2, "Bitcell with 0 read ports and 0 write ports")
tx = pbitcell() tx = pbitcell(name="pbc")
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports=2 OPTS.num_rw_ports=2
OPTS.num_w_ports=2 OPTS.num_w_ports=2
OPTS.num_r_ports=2 OPTS.num_r_ports=2
factory.reset()
debug.info(2, "Bitcell with 2 of each port: read/write, write, and read") debug.info(2, "Bitcell with 2 of each port: read/write, write, and read")
tx = pbitcell() tx = pbitcell(name="pbc")
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports=0 OPTS.num_rw_ports=0
OPTS.num_w_ports=2 OPTS.num_w_ports=2
OPTS.num_r_ports=2 OPTS.num_r_ports=2
factory.reset()
debug.info(2, "Bitcell with 0 read/write ports") debug.info(2, "Bitcell with 0 read/write ports")
tx = pbitcell() tx = pbitcell(name="pbc")
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports=2 OPTS.num_rw_ports=2
OPTS.num_w_ports=0 OPTS.num_w_ports=0
OPTS.num_r_ports=2 OPTS.num_r_ports=2
factory.reset()
debug.info(2, "Bitcell with 0 write ports") debug.info(2, "Bitcell with 0 write ports")
tx = pbitcell() tx = pbitcell(name="pbc")
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports=2 OPTS.num_rw_ports=2
OPTS.num_w_ports=2 OPTS.num_w_ports=2
OPTS.num_r_ports=0 OPTS.num_r_ports=0
factory.reset()
debug.info(2, "Bitcell with 0 read ports") debug.info(2, "Bitcell with 0 read ports")
tx = pbitcell() tx = pbitcell(name="pbc")
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports=2 OPTS.num_rw_ports=2
OPTS.num_w_ports=0 OPTS.num_w_ports=0
OPTS.num_r_ports=0 OPTS.num_r_ports=0
factory.reset()
debug.info(2, "Bitcell with 0 read ports and 0 write ports") debug.info(2, "Bitcell with 0 read ports and 0 write ports")
tx = pbitcell() tx = pbitcell(name="pbc")
self.local_check(tx) self.local_check(tx)
globals.end_openram() globals.end_openram()

View File

@ -21,7 +21,7 @@ class pbuf_test(openram_test):
import pbuf import pbuf
debug.info(2, "Testing inverter/buffer 4x 8x") debug.info(2, "Testing inverter/buffer 4x 8x")
a = pbuf.pbuf(8) a = pbuf.pbuf(name="pbufx8", size=8)
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -22,17 +22,22 @@ class pdriver_test(openram_test):
debug.info(2, "Testing inverter/buffer 4x 8x") debug.info(2, "Testing inverter/buffer 4x 8x")
# a tests the error message for specifying conflicting conditions # a tests the error message for specifying conflicting conditions
#a = pdriver.pdriver(fanout_size = 4,size_list = [1,2,4,8]) #a = pdriver.pdriver(fanout = 4,size_list = [1,2,4,8])
b = pdriver.pdriver(size_list = [1,2,4,8])
c = pdriver.pdriver(fanout_size = 50)
d = pdriver.pdriver(fanout_size = 50, neg_polarity = True)
e = pdriver.pdriver(fanout_size = 64)
f = pdriver.pdriver(fanout_size = 64, neg_polarity = True)
#self.local_check(a) #self.local_check(a)
b = pdriver.pdriver(name="pdriver1", size_list = [1,2,4,8])
self.local_check(b) self.local_check(b)
c = pdriver.pdriver(name="pdriver2", fanout = 50)
self.local_check(c) self.local_check(c)
d = pdriver.pdriver(name="pdriver3", fanout = 50, neg_polarity = True)
self.local_check(d) self.local_check(d)
e = pdriver.pdriver(name="pdriver4", fanout = 64)
self.local_check(e) self.local_check(e)
f = pdriver.pdriver(name="pdriver5", fanout = 64, neg_polarity = True)
self.local_check(f) self.local_check(f)
globals.end_openram() globals.end_openram()

View File

@ -19,7 +19,7 @@ class pinv_test(openram_test):
import tech import tech
debug.info(2, "Checking 10x inverter") debug.info(2, "Checking 10x inverter")
tx = pinv.pinv(size=8) tx = pinv.pinv(name="pinvx10",size=8)
self.local_check(tx) self.local_check(tx)
globals.end_openram() globals.end_openram()

View File

@ -19,7 +19,7 @@ class pinv_test(openram_test):
import tech import tech
debug.info(2, "Checking 1x beta=3 size inverter") debug.info(2, "Checking 1x beta=3 size inverter")
tx = pinv.pinv(size=1, beta=3) tx = pinv.pinv(name="pinvx1b", size=1, beta=3)
self.local_check(tx) self.local_check(tx)
globals.end_openram() globals.end_openram()

View File

@ -18,7 +18,7 @@ class pinv_test(openram_test):
import tech import tech
debug.info(2, "Checking 1x size inverter") debug.info(2, "Checking 1x size inverter")
tx = pinv.pinv(size=1) tx = pinv.pinv(name="pinvx1", size=1)
self.local_check(tx) self.local_check(tx)
globals.end_openram() globals.end_openram()

View File

@ -19,7 +19,7 @@ class pinv_test(openram_test):
import tech import tech
debug.info(2, "Checking 2x size inverter") debug.info(2, "Checking 2x size inverter")
tx = pinv.pinv(size=2) tx = pinv.pinv(name="pinvx2", size=2)
self.local_check(tx) self.local_check(tx)
globals.end_openram() globals.end_openram()

View File

@ -18,7 +18,7 @@ class pinvbuf_test(openram_test):
import pinvbuf import pinvbuf
debug.info(2, "Testing inverter/buffer 4x 8x") debug.info(2, "Testing inverter/buffer 4x 8x")
a = pinvbuf.pinvbuf(8) a = pinvbuf.pinvbuf(name="pinvufx8", size=8)
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -21,7 +21,7 @@ class pnand2_test(openram_test):
import tech import tech
debug.info(2, "Checking 2-input nand gate") debug.info(2, "Checking 2-input nand gate")
tx = pnand2.pnand2(size=1) tx = pnand2.pnand2(name="pnand2", size=1)
self.local_check(tx) self.local_check(tx)
globals.end_openram() globals.end_openram()

View File

@ -21,7 +21,7 @@ class pnand3_test(openram_test):
import tech import tech
debug.info(2, "Checking 3-input nand gate") debug.info(2, "Checking 3-input nand gate")
tx = pnand3.pnand3(size=1) tx = pnand3.pnand3(name="pnand3", size=1)
self.local_check(tx) self.local_check(tx)
globals.end_openram() globals.end_openram()

View File

@ -21,7 +21,7 @@ class pnor2_test(openram_test):
import tech import tech
debug.info(2, "Checking 2-input nor gate") debug.info(2, "Checking 2-input nor gate")
tx = pnor2.pnor2(size=1) tx = pnor2.pnor2(name="pnor2", size=1)
self.local_check(tx) self.local_check(tx)
globals.end_openram() globals.end_openram()

View File

@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
from sram_factory import factory
class precharge_test(openram_test): class precharge_test(openram_test):
@ -28,7 +29,8 @@ class precharge_test(openram_test):
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 1 OPTS.num_w_ports = 1
factory.reset()
debug.info(2, "Checking precharge for pbitcell (innermost connections)") debug.info(2, "Checking precharge for pbitcell (innermost connections)")
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl0", bitcell_br="br0") tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(tx) self.local_check(tx)

View File

@ -10,29 +10,31 @@ sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
from sram_factory import factory
class replica_pbitcell_test(openram_test): class replica_pbitcell_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import replica_pbitcell import replica_pbitcell
import tech
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0 OPTS.num_r_ports = 0
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
factory.reset()
debug.info(2, "Checking replica bitcell using pbitcell (small cell)") debug.info(2, "Checking replica bitcell using pbitcell (small cell)")
tx = replica_pbitcell.replica_pbitcell() tx = replica_pbitcell.replica_pbitcell(name="rpbc")
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 1 OPTS.num_w_ports = 1
factory.reset()
debug.info(2, "Checking replica bitcell using pbitcell (large cell)") debug.info(2, "Checking replica bitcell using pbitcell (large cell)")
tx = replica_pbitcell.replica_pbitcell() tx = replica_pbitcell.replica_pbitcell(name="rpbc")
self.local_check(tx) self.local_check(tx)
globals.end_openram() globals.end_openram()

View File

@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
from sram_factory import factory
#@unittest.skip("SKIPPING 04_driver_test") #@unittest.skip("SKIPPING 04_driver_test")
@ -22,7 +23,7 @@ class single_level_column_mux_test(openram_test):
# check single level column mux in single port # check single level column mux in single port
debug.info(2, "Checking column mux") debug.info(2, "Checking column mux")
tx = single_level_column_mux.single_level_column_mux(tx_size=8) tx = single_level_column_mux.single_level_column_mux(name="mux8", tx_size=8)
self.local_check(tx) self.local_check(tx)
# check single level column mux in multi-port # check single level column mux in multi-port
@ -30,13 +31,15 @@ class single_level_column_mux_test(openram_test):
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 1 OPTS.num_w_ports = 1
factory.reset()
debug.info(2, "Checking column mux for pbitcell (innermost connections)") debug.info(2, "Checking column mux for pbitcell (innermost connections)")
tx = single_level_column_mux.single_level_column_mux(tx_size=8, bitcell_bl="bl0", bitcell_br="br0") tx = single_level_column_mux.single_level_column_mux(name="mux8_2", tx_size=8, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(tx) self.local_check(tx)
factory.reset()
debug.info(2, "Checking column mux for pbitcell (outermost connections)") debug.info(2, "Checking column mux for pbitcell (outermost connections)")
tx = single_level_column_mux.single_level_column_mux(tx_size=8, bitcell_bl="bl2", bitcell_br="br2") tx = single_level_column_mux.single_level_column_mux(name="mux8_3", tx_size=8, bitcell_bl="bl2", bitcell_br="br2")
self.local_check(tx) self.local_check(tx)
globals.end_openram() globals.end_openram()

View File

@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
from sram_factory import factory
class hierarchical_decoder_test(openram_test): class hierarchical_decoder_test(openram_test):
@ -20,29 +21,29 @@ class hierarchical_decoder_test(openram_test):
# Doesn't require hierarchical decoder # Doesn't require hierarchical decoder
# debug.info(1, "Testing 4 row sample for hierarchical_decoder") # debug.info(1, "Testing 4 row sample for hierarchical_decoder")
# a = hierarchical_decoder.hierarchical_decoder(rows=4) # a = hierarchical_decoder.hierarchical_decoder(name="hd1, rows=4)
# self.local_check(a) # self.local_check(a)
# Doesn't require hierarchical decoder # Doesn't require hierarchical decoder
# debug.info(1, "Testing 8 row sample for hierarchical_decoder") # debug.info(1, "Testing 8 row sample for hierarchical_decoder")
# a = hierarchical_decoder.hierarchical_decoder(rows=8) # a = hierarchical_decoder.hierarchical_decoder(name="hd2", rows=8)
# self.local_check(a) # 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 = hierarchical_decoder.hierarchical_decoder(rows=16) a = hierarchical_decoder.hierarchical_decoder(name="hd3", rows=16)
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 = hierarchical_decoder.hierarchical_decoder(rows=32) a = hierarchical_decoder.hierarchical_decoder(name="hd4", rows=32)
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 = hierarchical_decoder.hierarchical_decoder(rows=128) a = hierarchical_decoder.hierarchical_decoder(name="hd5", rows=128)
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 = hierarchical_decoder.hierarchical_decoder(rows=512) a = hierarchical_decoder.hierarchical_decoder(name="hd6", rows=512)
self.local_check(a) self.local_check(a)
# check hierarchical decoder for multi-port # check hierarchical decoder for multi-port
@ -50,21 +51,22 @@ class hierarchical_decoder_test(openram_test):
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_ports = 0 OPTS.num_r_ports = 0
factory.reset()
debug.info(1, "Testing 16 row sample for hierarchical_decoder (multi-port case)") debug.info(1, "Testing 16 row sample for hierarchical_decoder (multi-port case)")
a = hierarchical_decoder.hierarchical_decoder(rows=16) a = hierarchical_decoder.hierarchical_decoder(name="hd7", rows=16)
self.local_check(a) self.local_check(a)
debug.info(1, "Testing 32 row sample for hierarchical_decoder (multi-port case)") debug.info(1, "Testing 32 row sample for hierarchical_decoder (multi-port case)")
a = hierarchical_decoder.hierarchical_decoder(rows=32) a = hierarchical_decoder.hierarchical_decoder(name="hd8", rows=32)
self.local_check(a) self.local_check(a)
debug.info(1, "Testing 128 row sample for hierarchical_decoder (multi-port case)") debug.info(1, "Testing 128 row sample for hierarchical_decoder (multi-port case)")
a = hierarchical_decoder.hierarchical_decoder(rows=128) a = hierarchical_decoder.hierarchical_decoder(name="hd9", rows=128)
self.local_check(a) self.local_check(a)
debug.info(1, "Testing 512 row sample for hierarchical_decoder (multi-port case)") debug.info(1, "Testing 512 row sample for hierarchical_decoder (multi-port case)")
a = hierarchical_decoder.hierarchical_decoder(rows=512) a = hierarchical_decoder.hierarchical_decoder(name="hd10", rows=512)
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -20,7 +20,7 @@ class hierarchical_predecode2x4_test(openram_test):
# checking hierarchical precode 2x4 for single port # checking hierarchical precode 2x4 for single port
debug.info(1, "Testing sample for hierarchy_predecode2x4") debug.info(1, "Testing sample for hierarchy_predecode2x4")
a = pre.hierarchical_predecode2x4() a = pre.hierarchical_predecode2x4(name="pre1")
self.local_check(a) self.local_check(a)
# checking hierarchical precode 2x4 for multi-port # checking hierarchical precode 2x4 for multi-port
@ -30,7 +30,7 @@ class hierarchical_predecode2x4_test(openram_test):
OPTS.num_r_ports = 0 OPTS.num_r_ports = 0
debug.info(1, "Testing sample for hierarchy_predecode2x4 (multi-port case)") debug.info(1, "Testing sample for hierarchy_predecode2x4 (multi-port case)")
a = pre.hierarchical_predecode2x4() a = pre.hierarchical_predecode2x4(name="pre2")
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -20,7 +20,7 @@ class hierarchical_predecode3x8_test(openram_test):
# checking hierarchical precode 3x8 for single port # checking hierarchical precode 3x8 for single port
debug.info(1, "Testing sample for hierarchy_predecode3x8") debug.info(1, "Testing sample for hierarchy_predecode3x8")
a = pre.hierarchical_predecode3x8() a = pre.hierarchical_predecode3x8(name="pre1")
self.local_check(a) self.local_check(a)
# checking hierarchical precode 3x8 for multi-port # checking hierarchical precode 3x8 for multi-port
@ -30,7 +30,7 @@ class hierarchical_predecode3x8_test(openram_test):
OPTS.num_r_ports = 0 OPTS.num_r_ports = 0
debug.info(1, "Testing sample for hierarchy_predecode3x8 (multi-port case)") debug.info(1, "Testing sample for hierarchy_predecode3x8 (multi-port case)")
a = pre.hierarchical_predecode3x8() a = pre.hierarchical_predecode3x8(name="pre2")
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -9,6 +9,7 @@ sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
from sram_factory import factory
class single_level_column_mux_test(openram_test): class single_level_column_mux_test(openram_test):
@ -18,15 +19,15 @@ class single_level_column_mux_test(openram_test):
# check single level column mux array in single port # check single level column mux array in single port
debug.info(1, "Testing sample for 2-way column_mux_array") debug.info(1, "Testing sample for 2-way column_mux_array")
a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=8) a = single_level_column_mux_array.single_level_column_mux_array(name="mux1", columns=16, word_size=8)
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 4-way column_mux_array") debug.info(1, "Testing sample for 4-way column_mux_array")
a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=4) a = single_level_column_mux_array.single_level_column_mux_array(name="mux2", columns=16, word_size=4)
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array") debug.info(1, "Testing sample for 8-way column_mux_array")
a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4) a = single_level_column_mux_array.single_level_column_mux_array(name="mux3", columns=32, word_size=4)
self.local_check(a) self.local_check(a)
# check single level column mux array in multi-port # check single level column mux array in multi-port
@ -34,21 +35,22 @@ class single_level_column_mux_test(openram_test):
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 1 OPTS.num_w_ports = 1
factory.reset()
debug.info(1, "Testing sample for 2-way column_mux_array in multi-port") debug.info(1, "Testing sample for 2-way column_mux_array in multi-port")
a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0") a = single_level_column_mux_array.single_level_column_mux_array(name="mux4", columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 4-way column_mux_array in multi-port") debug.info(1, "Testing sample for 4-way column_mux_array in multi-port")
a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0") a = single_level_column_mux_array.single_level_column_mux_array(name="mux5", columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (innermost connections)") debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (innermost connections)")
a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0") a = single_level_column_mux_array.single_level_column_mux_array(name="mux6", columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (outermost connections)") debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (outermost connections)")
a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2") a = single_level_column_mux_array.single_level_column_mux_array(name="mux7", columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2")
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -10,17 +10,17 @@ sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
from sram_factory import factory
class precharge_test(openram_test): class precharge_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import precharge_array import precharge_array
import tech
# check precharge array in single port # check precharge array in single port
debug.info(2, "Checking 3 column precharge") debug.info(2, "Checking 3 column precharge")
pc = precharge_array.precharge_array(columns=3) pc = precharge_array.precharge_array(name="pre1", columns=3)
self.local_check(pc) self.local_check(pc)
# check precharge array in multi-port # check precharge array in multi-port
@ -28,17 +28,18 @@ class precharge_test(openram_test):
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
factory.reset()
debug.info(2, "Checking 3 column precharge array for 1RW/1R bitcell") debug.info(2, "Checking 3 column precharge array for 1RW/1R bitcell")
pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl0", bitcell_br="br0") pc = precharge_array.precharge_array(name="pre2", columns=3, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(pc) self.local_check(pc)
# debug.info(2, "Checking 3 column precharge array for pbitcell (innermost connections)") # debug.info(2, "Checking 3 column precharge array for pbitcell (innermost connections)")
# pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl0", bitcell_br="br0") # pc = precharge_array.precharge_array(name="pre3", columns=3, bitcell_bl="bl0", bitcell_br="br0")
# self.local_check(pc) # self.local_check(pc)
# debug.info(2, "Checking 3 column precharge array for pbitcell (outermost connections)") # debug.info(2, "Checking 3 column precharge array for pbitcell (outermost connections)")
# pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl2", bitcell_br="br2") # pc = precharge_array.precharge_array(name="pre4", columns=3, bitcell_bl="bl2", bitcell_br="br2")
# self.local_check(pc) # self.local_check(pc)
globals.end_openram() globals.end_openram()

View File

@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
from sram_factory import factory
#@unittest.skip("SKIPPING 04_driver_test") #@unittest.skip("SKIPPING 04_driver_test")
@ -18,11 +19,10 @@ class wordline_driver_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import wordline_driver import wordline_driver
import tech
# check wordline driver for single port # check wordline driver for single port
debug.info(2, "Checking driver") debug.info(2, "Checking driver")
tx = wordline_driver.wordline_driver(rows=8) tx = wordline_driver.wordline_driver(name="wld1", rows=8, cols=32)
self.local_check(tx) self.local_check(tx)
# check wordline driver for multi-port # check wordline driver for multi-port
@ -30,9 +30,10 @@ class wordline_driver_test(openram_test):
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_ports = 0 OPTS.num_r_ports = 0
factory.reset()
debug.info(2, "Checking driver (multi-port case)") debug.info(2, "Checking driver (multi-port case)")
tx = wordline_driver.wordline_driver(rows=8) tx = wordline_driver.wordline_driver(name="wld2", rows=8, cols=64)
self.local_check(tx) self.local_check(tx)
globals.end_openram() globals.end_openram()

View File

@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
from sram_factory import factory
class sense_amp_test(openram_test): class sense_amp_test(openram_test):
@ -19,11 +20,11 @@ class sense_amp_test(openram_test):
# 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=2") debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2")
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2) a = sense_amp_array.sense_amp_array(name="sa1", word_size=4, words_per_row=2)
self.local_check(a) self.local_check(a)
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4") debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4")
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4) a = sense_amp_array.sense_amp_array(name="sa2", word_size=4, words_per_row=4)
self.local_check(a) self.local_check(a)
# check sense amp array for multi-port # check sense amp array for multi-port
@ -31,13 +32,14 @@ class sense_amp_test(openram_test):
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_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)") debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2 (multi-port case)")
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2) a = sense_amp_array.sense_amp_array(name="sa3", word_size=4, words_per_row=2)
self.local_check(a) self.local_check(a)
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4 (multi-port case)") debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4 (multi-port case)")
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4) a = sense_amp_array.sense_amp_array(name="sa4", word_size=4, words_per_row=4)
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
from sram_factory import factory
class write_driver_test(openram_test): class write_driver_test(openram_test):
@ -19,11 +20,11 @@ class write_driver_test(openram_test):
# check write driver array for single port # check write driver array for single port
debug.info(2, "Testing write_driver_array for columns=8, word_size=8") debug.info(2, "Testing write_driver_array for columns=8, word_size=8")
a = write_driver_array.write_driver_array(columns=8, word_size=8) a = write_driver_array.write_driver_array(name="wd1", columns=8, word_size=8)
self.local_check(a) self.local_check(a)
debug.info(2, "Testing write_driver_array for columns=16, word_size=8") debug.info(2, "Testing write_driver_array for columns=16, word_size=8")
a = write_driver_array.write_driver_array(columns=16, word_size=8) a = write_driver_array.write_driver_array(name="wd2", columns=16, word_size=8)
self.local_check(a) self.local_check(a)
# check write driver array for multi-port # check write driver array for multi-port
@ -31,13 +32,14 @@ class write_driver_test(openram_test):
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_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)") debug.info(2, "Testing write_driver_array for columns=8, word_size=8 (multi-port case)")
a = write_driver_array.write_driver_array(columns=8, word_size=8) a = write_driver_array.write_driver_array(name="wd3", columns=8, word_size=8)
self.local_check(a) self.local_check(a)
debug.info(2, "Testing write_driver_array for columns=16, word_size=8 (multi-port case)") debug.info(2, "Testing write_driver_array for columns=16, word_size=8 (multi-port case)")
a = write_driver_array.write_driver_array(columns=16, word_size=8) a = write_driver_array.write_driver_array(name="wd4", columns=16, word_size=8)
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -18,7 +18,7 @@ class delay_chain_test(openram_test):
import delay_chain import delay_chain
debug.info(2, "Testing delay_chain") debug.info(2, "Testing delay_chain")
a = delay_chain.delay_chain(fanout_list=[4, 4, 4, 4]) a = delay_chain.delay_chain(name="dc", fanout_list=[4, 4, 4, 4])
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
from sram_factory import factory
class replica_bitline_multiport_test(openram_test): class replica_bitline_multiport_test(openram_test):
@ -26,9 +27,10 @@ class replica_bitline_multiport_test(openram_test):
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
factory.reset()
debug.info(2, "Testing 1rw 1r RBL with {0} FO4 stages, {1} rows".format(stages,rows)) debug.info(2, "Testing 1rw 1r RBL with {0} FO4 stages, {1} rows".format(stages,rows))
a = replica_bitline.replica_bitline(stages*[fanout],rows) a = replica_bitline.replica_bitline(name="rbl1", delay_fanout_list=stages*[fanout], bitcell_loads=rows)
self.local_check(a) self.local_check(a)
# check replica bitline in pbitcell multi-port # check replica bitline in pbitcell multi-port
@ -38,16 +40,18 @@ class replica_bitline_multiport_test(openram_test):
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_ports = 0 OPTS.num_r_ports = 0
factory.reset()
debug.info(2, "Testing RBL pbitcell 1rw with {0} FO4 stages, {1} rows".format(stages,rows)) debug.info(2, "Testing RBL pbitcell 1rw with {0} FO4 stages, {1} rows".format(stages,rows))
a = replica_bitline.replica_bitline(stages*[fanout],rows) a = replica_bitline.replica_bitline(name="rbl2", delay_fanout_list=stages*[fanout], bitcell_loads=rows)
self.local_check(a) self.local_check(a)
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 1 OPTS.num_w_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
factory.reset()
debug.info(2, "Testing RBL pbitcell 1rw 1w 1r with {0} FO4 stages, {1} rows".format(stages,rows)) debug.info(2, "Testing RBL pbitcell 1rw 1w 1r with {0} FO4 stages, {1} rows".format(stages,rows))
a = replica_bitline.replica_bitline(stages*[fanout],rows) a = replica_bitline.replica_bitline(name="rbl3", delay_fanout_list=stages*[fanout], bitcell_loads=rows)
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -22,14 +22,14 @@ class replica_bitline_test(openram_test):
fanout=4 fanout=4
rows=13 rows=13
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows)) debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
a = replica_bitline.replica_bitline(stages*[fanout],rows) a = replica_bitline.replica_bitline(name="rbl1", delay_fanout_list=stages*[fanout], bitcell_loads=rows)
self.local_check(a) self.local_check(a)
#debug.error("Exiting...", 1) #debug.error("Exiting...", 1)
stages=8 stages=8
rows=100 rows=100
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows)) debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
a = replica_bitline.replica_bitline(stages*[fanout],rows) a = replica_bitline.replica_bitline(name="rbl2", delay_fanout_list=stages*[fanout], bitcell_loads=rows)
self.local_check(a) self.local_check(a)

View File

@ -20,7 +20,7 @@ class control_logic_test(openram_test):
# check control logic for single port # check control logic for single port
debug.info(1, "Testing sample for control_logic") debug.info(1, "Testing sample for control_logic")
a = control_logic.control_logic(num_rows=128, words_per_row=1) a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=32)
self.local_check(a) self.local_check(a)
# check control logic for multi-port # check control logic for multi-port
@ -31,7 +31,7 @@ class control_logic_test(openram_test):
OPTS.num_r_ports = 0 OPTS.num_r_ports = 0
debug.info(1, "Testing sample for control_logic for multiport") debug.info(1, "Testing sample for control_logic for multiport")
a = control_logic.control_logic(num_rows=128, words_per_row=1) a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8)
self.local_check(a) self.local_check(a)
# Check port specific control logic # Check port specific control logic
@ -40,15 +40,15 @@ class control_logic_test(openram_test):
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
debug.info(1, "Testing sample for control_logic for multiport, only write control logic") debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
a = control_logic.control_logic(num_rows=128, words_per_row=1, port_type="rw") a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="rw")
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for control_logic for multiport, only write control logic") debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
a = control_logic.control_logic(num_rows=128, words_per_row=1, port_type="w") a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="w")
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for control_logic for multiport, only read control logic") debug.info(1, "Testing sample for control_logic for multiport, only read control logic")
a = control_logic.control_logic(num_rows=128, words_per_row=1, port_type="r") a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="r")
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -10,15 +10,13 @@ sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
from sram_factory import factory
#@unittest.skip("SKIPPING 19_psingle_bank_test") #@unittest.skip("SKIPPING 19_psingle_bank_test")
class psingle_bank_test(openram_test): class psingle_bank_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
from bank import bank from bank import bank
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
@ -31,6 +29,7 @@ class psingle_bank_test(openram_test):
num_words=16) num_words=16)
c.words_per_row=1 c.words_per_row=1
factory.reset()
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "No column mux") debug.info(1, "No column mux")
name = "bank1_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) name = "bank1_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports)
@ -39,6 +38,7 @@ class psingle_bank_test(openram_test):
c.num_words=32 c.num_words=32
c.words_per_row=2 c.words_per_row=2
factory.reset()
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "Two way column mux") debug.info(1, "Two way column mux")
name = "bank2_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) name = "bank2_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports)
@ -47,6 +47,7 @@ class psingle_bank_test(openram_test):
c.num_words=64 c.num_words=64
c.words_per_row=4 c.words_per_row=4
factory.reset()
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "Four way column mux") debug.info(1, "Four way column mux")
name = "bank3_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) name = "bank3_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports)
@ -56,6 +57,7 @@ class psingle_bank_test(openram_test):
c.word_size=2 c.word_size=2
c.num_words=128 c.num_words=128
c.words_per_row=8 c.words_per_row=8
factory.reset()
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "Four way column mux") debug.info(1, "Four way column mux")
name = "bank4_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) name = "bank4_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports)

View File

@ -53,27 +53,27 @@ 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.2011], golden_data = {'delay_hl': [0.2152017],
'delay_lh': [0.2011], 'delay_lh': [0.2152017],
'leakage_power': 0.002, 'leakage_power': 0.0022907,
'min_period': 0.41, 'min_period': 0.488,
'read0_power': [0.63604], 'read0_power': [0.47437749999999995],
'read1_power': [0.6120599999999999], 'read1_power': [0.45026109999999997],
'slew_hl': [0.10853], 'slew_hl': [0.0846786],
'slew_lh': [0.10853], 'slew_lh': [0.0846786],
'write0_power': [0.51742], 'write0_power': [0.40809259999999997],
'write1_power': [0.51095]} 'write1_power': [0.4078904]}
elif OPTS.tech_name == "scn4m_subm": elif OPTS.tech_name == "scn4m_subm":
golden_data = {'delay_hl': [1.3911], golden_data = {'delay_hl': [1.4333000000000002],
'delay_lh': [1.3911], 'delay_lh': [1.4333000000000002],
'leakage_power': 0.0278488, 'leakage_power': 0.0271847,
'min_period': 2.812, 'min_period': 2.891,
'read0_power': [22.1183], 'read0_power': [15.714200000000002],
'read1_power': [21.4388], 'read1_power': [14.9848],
'slew_hl': [0.7397553], 'slew_hl': [0.6819276999999999],
'slew_lh': [0.7397553], 'slew_lh': [0.6819276999999999],
'write0_power': [19.4103], 'write0_power': [13.9658],
'write1_power': [20.1167]} 'write1_power': [14.8422]}
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

@ -51,27 +51,27 @@ 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.20443139999999999], golden_data = {'delay_hl': [0.221699],
'delay_lh': [0.20443139999999999], 'delay_lh': [0.221699],
'leakage_power': 0.0017840640000000001, 'leakage_power': 0.001467648,
'min_period': 0.41, 'min_period': 0.605,
'read0_power': [0.6435831], 'read0_power': [0.3879335],
'read1_power': [0.6233463], 'read1_power': [0.3662724],
'slew_hl': [0.1138734], 'slew_hl': [0.08562444999999999],
'slew_lh': [0.1138734], 'slew_lh': [0.08562444999999999],
'write0_power': [0.5205761], 'write0_power': [0.3362456],
'write1_power': [0.5213689]} 'write1_power': [0.3372035]}
elif OPTS.tech_name == "scn4m_subm": elif OPTS.tech_name == "scn4m_subm":
golden_data = {'delay_hl': [1.610911], golden_data = {'delay_hl': [1.7951730000000001],
'delay_lh': [1.610911], 'delay_lh': [1.7951730000000001],
'leakage_power': 0.0023593859999999998, 'leakage_power': 0.001669513,
'min_period': 3.281, 'min_period': 3.594,
'read0_power': [20.763569999999998], 'read0_power': [17.03022],
'read1_power': [20.32745], 'read1_power': [16.55897],
'slew_hl': [0.7986348999999999], 'slew_hl': [0.7079951],
'slew_lh': [0.7986348999999999], 'slew_lh': [0.7079951],
'write0_power': [17.58272], 'write0_power': [15.16726],
'write1_power': [18.523419999999998]} 'write1_power': [16.13527]}
else: else:
self.assertTrue(False) # other techs fail self.assertTrue(False) # other techs fail

View File

@ -182,7 +182,6 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
# FIXME: Remove when vdd/gnd connected # FIXME: Remove when vdd/gnd connected
#'lvsAbortOnSupplyError' : 0 #'lvsAbortOnSupplyError' : 0
# This should be removed for final verification
if not final_verification: if not final_verification:
lvs_runset['cmnVConnectReport']=1 lvs_runset['cmnVConnectReport']=1
lvs_runset['cmnVConnectNamesState']='SOME' lvs_runset['cmnVConnectNamesState']='SOME'

View File

@ -1,14 +0,0 @@
SUBDIRS := $(wildcard */.)
SUBDIRSCLEAN=$(addsuffix clean,$(SUBDIRS))
all: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -k -C $@
clean:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir $@; \
done
.PHONY: all $(SUBDIRS) $(SUBDIRSCLEAN)

View File

@ -1,5 +0,0 @@
This directory contains a set of common sizes based on
discussions with users. All of the files are pre-computed
to that common-case users don't need to setup/use OpenRAM.
The results will be updated automatically as improvements
are made to OpenRAM.

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