Merge branch 'dev'

This commit is contained in:
Matt Guthaus 2019-01-30 10:17:40 -08:00
commit 9d318aadd7
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
(acting for and on behalf of Oklahoma State University)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
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
```
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.
@ -163,7 +163,7 @@ Each specific technology (e.g., [FreePDK45]) should be a subdirectory
* replica\_cell\_6t.gds
* sp_lib folder with all the .sp (premade) library netlists for the above cells.
* 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
* DRC/LVS rules needed for dynamic cells and routing
* Layer information

View File

@ -16,7 +16,9 @@ class contact(hierarchy_design.hierarchy_design):
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:
name = "{0}_{1}_{2}_{3}x{4}_{5}{6}".format(layer_stack[0],
layer_stack[1],
@ -164,13 +166,13 @@ class contact(hierarchy_design.hierarchy_design):
""" Get total power of a module """
return self.return_power()
from sram_factory import factory
# This is not instantiated and used for calculations only.
# These are static 1x1 contacts to reuse in all the design modules.
well = contact(layer_stack=("active", "contact", "metal1"))
active = contact(layer_stack=("active", "contact", "poly"))
poly = contact(layer_stack=("poly", "contact", "metal1"))
m1m2 = contact(layer_stack=("metal1", "via1", "metal2"))
m2m3 = contact(layer_stack=("metal2", "via2", "metal3"))
m3m4 = contact(layer_stack=("metal3", "via3", "metal4"))
well = factory.create(module_type="contact", layer_stack=("active", "contact", "metal1"))
active = factory.create(module_type="contact", layer_stack=("active", "contact", "poly"))
poly = factory.create(module_type="contact", layer_stack=("poly", "contact", "metal1"))
m1m2 = factory.create(module_type="contact", layer_stack=("metal1", "via1", "metal2"))
m2m3 = factory.create(module_type="contact", layer_stack=("metal2", "via2", "metal3"))
m3m4 = factory.create(module_type="contact", layer_stack=("metal3", "via3", "metal4"))

View File

@ -6,7 +6,6 @@ import debug
import os
from globals import OPTS
class design(hierarchy_design):
"""
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 = []
def __init__(self, name):
try:
self.gds_file
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.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds"
self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp"
self.name = name
hierarchy_layout.layout.__init__(self, name)
hierarchy_spice.spice.__init__(self, name)
# Check if the name already exists, if so, give an error
# because each reference must be a unique name.
# 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):
"""Connects a routing path on given layer,coordinates,width."""
debug.info(4,"add path " + str(layer) + " " + str(coordinates))
import path
import wire_path
# NOTE: (UNTESTED) add_path(...) is currently not used
# negative layers indicate "unused" layers in a given technology
#layer_num = techlayer[layer]
#if layer_num >= 0:
# self.objs.append(geometry.path(layer_num, coordinates, width))
path.path(obj=self,
layer=layer,
position_list=coordinates,
width=width)
wire_path.wire_path(obj=self,
layer=layer,
position_list=coordinates,
width=width)
def add_route(self, layers, coordinates, layer_widths):
"""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):
""" Add a three layer via structure. """
import contact
via = contact.contact(layer_stack=layers,
dimensions=size,
implant_type=implant_type,
well_type=well_type)
from sram_factory import factory
via = factory.create(module_type="contact",
layer_stack=layers,
dimensions=size,
implant_type=implant_type,
well_type=well_type)
self.add_mod(via)
inst=self.add_inst(name=via.name,
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):
""" Add a three layer via structure by the center coordinate accounting for mirroring and rotation. """
import contact
via = contact.contact(layer_stack=layers,
dimensions=size,
implant_type=implant_type,
well_type=well_type)
from sram_factory import factory
via = factory.create(module_type="contact",
layer_stack=layers,
dimensions=size,
implant_type=implant_type,
well_type=well_type)
height = via.height
width = via.width
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
self.supply_vias = 1
import contact
from sram_factory import factory
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:
self.supply_vias += 1
else:

View File

@ -16,13 +16,18 @@ class spice():
def __init__(self, name):
self.name = name
self.mods = [] # Holds subckts/mods for this module
self.pins = [] # Holds the pins for this module
self.pin_type = {} # The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND
# Holds subckts/mods for this module
self.mods = []
# 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
# 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)
self.conns = []
# Keep track of any comments to add the the spice
self.comments = []
self.sp_read()
@ -30,6 +35,10 @@ class spice():
# 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"):
""" Adds a pin to the pins list. Default type is INOUT signal. """
self.pins.append(name)
@ -93,8 +102,8 @@ class spice():
from pprint import pformat
modpins_string=pformat(self.insts[-1].mod.pins)
argpins_string=pformat(args)
debug.error("Connections: {}".format(modpins_string))
debug.error("Connections: {}".format(argpins_string))
debug.error("Mod connections: {}".format(modpins_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),
len(args)), 1)
self.conns.append(args)
@ -159,6 +168,9 @@ class spice():
sp.write("\n.SUBCKT {0} {1}\n".format(self.name,
" ".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.
if len(self.insts)!=len(self.conns):
debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name,

View File

@ -1,10 +1,10 @@
from tech import drc
import debug
from design import design
from contact import contact
from itertools import tee
from vector import vector
from vector3d import vector3d
from sram_factory import factory
class route(design):
"""
@ -45,7 +45,9 @@ class route(design):
self.horiz_layer_width = drc("minwidth_{0}".format(self.horiz_layer_name))
# 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):

View File

@ -1,9 +1,9 @@
from tech import drc
import debug
from contact import contact
from path import path
from wire_path import wire_path
from sram_factory import factory
class wire(path):
class wire(wire_path):
"""
Object metal wire; given the layer type
Add a wire of minimium metal width between a set of points.
@ -26,7 +26,7 @@ class wire(path):
self.create_rectilinear()
self.create_vias()
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):
(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_width = drc("minwidth_{0}".format(horiz_layer))
via_connect = contact(self.layer_stack,
(1, 1))
via_connect = factory.create(module_type="contact",
layer_stack=self.layer_stack,
dimensions=(1, 1))
self.node_to_node = [drc("minwidth_" + str(self.horiz_layer_name)) + via_connect.width,
drc("minwidth_" + str(self.horiz_layer_name)) + via_connect.height]
# create a 1x1 contact
def create_vias(self):
""" 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_height = self.c.height

View File

@ -18,12 +18,12 @@ def create_rectilinear_route(my_list):
my_list.append(vector(pl[-1]))
return my_list
class path():
class wire_path():
"""
Object metal path; given the layer type
Add a path of minimium metal width between a set of points.
Object metal wire_path; given the layer type
Add a wire_path of minimium metal width between a set of points.
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.
"""
def __init__(self, obj, layer, position_list, width=None):
@ -44,7 +44,7 @@ class path():
self.create_rectilinear()
self.connect_corner()
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):
""" 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)
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
nwise = lambda g,n=2: zip(*(islice(g,i,None) for i,g in enumerate(tee(g,n))))
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"])
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")
debug.info(2, "Create bitcell")
self.width = bitcell.width
self.height = bitcell.height
self.pin_map = bitcell.pin_map
def analytical_delay(self, slew, load=0, swing = 0.5):
# delay of bit cell is not like a driver(from WL)
# 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"])
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")
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.
#FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin
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
"""
def __init__(self, replica_bitcell=False):
def __init__(self, name, replica_bitcell=False):
self.num_rw_ports = OPTS.num_rw_ports
self.num_w_ports = OPTS.num_w_ports
self.num_r_ports = OPTS.num_r_ports
@ -21,11 +20,6 @@ class pbitcell(design.design):
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)
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,

View File

@ -14,7 +14,8 @@ class replica_bitcell(design.design):
(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"])
def __init__(self):
def __init__(self, name=""):
# Ignore the name argument
design.design.__init__(self, "replica_cell_6t")
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.
#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"]
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"])
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")
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.
#FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin
return 2*access_tx_cin

View File

@ -3,21 +3,20 @@ import design
from tech import drc, spice,parameter
from vector import vector
from globals import OPTS
from pbitcell import pbitcell
from sram_factory import factory
class replica_pbitcell(design.design):
"""
Creates a replica bitcell using pbitcell
"""
def __init__(self):
def __init__(self, name):
self.num_rw_ports = OPTS.num_rw_ports
self.num_w_ports = OPTS.num_w_ports
self.num_r_ports = OPTS.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,
self.num_w_ports,
self.num_r_ports))
@ -47,7 +46,7 @@ class replica_pbitcell(design.design):
self.add_pin("gnd")
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.height = self.prbc.height
@ -83,4 +82,4 @@ class replica_pbitcell(design.design):
def get_wl_cin(self):
"""Return the relative capacitance of the access transistor gates"""
#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),
OPTS.num_words,
OPTS.num_banks,
OPTS.num_rw_ports,
OPTS.num_rw_ports,
OPTS.num_w_ports,
OPTS.num_r_ports,
OPTS.tech_name,
@ -555,7 +555,7 @@ class lib:
LVS = str(total_lvs_errors)
datasheet.write("{0},{1},".format(DRC, LVS))
datasheet.write(str(self.sram.width * self.sram.height)+',')
for port in self.all_ports:
#DIN timings
if port in self.write_ports:

View File

@ -1,62 +1,60 @@
from table_gen import *
import os
import csv
import base64
from globals import OPTS
class datasheet():
"""
Defines the layout,but not the data, of the html datasheet
"""
def __init__(self,identifier):
def __init__(self, identifier):
self.name = identifier
self.html = ""
def generate_html(self):
"""
Generates html tables using flask-table
"""
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()
# with open(OPTS.openram_temp + "/datasheet.info") as info:
with open(OPTS.openram_temp + "/datasheet.info") as info:
self.html += '<!--'
# for row in info:
# self.html += row
for item in self.description:
self.html += item + ','
self.html += 'EOL'
self.html +='-->'
for row in info:
self.html += row
# for item in self.description:
# self.html += item + ','
self.html += '-->'
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())
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())
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: 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: 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 += 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 += self.operating_table.to_html()
@ -68,9 +66,6 @@ class datasheet():
# self.html += characterization_corners(self.corners,table_id='data').__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 += self.dlv_table.to_html()

View File

@ -1,21 +1,21 @@
#!/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.
"""
#TODO:
#include log file
#Diagram generation
#Improve css
# TODO:
# include power
# Diagram generation
# Improve css
import debug
from globals import OPTS
import os, math
import optparse
import os
import math
import csv
from datasheet import *
from table_gen import *
import datasheet
import table_gen
def process_name(corner):
"""
@ -30,20 +30,20 @@ def process_name(corner):
else:
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
current table
"""
with open(f) as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
line_count = 0
for row in csv_reader:
found = 0
col = 0
#defines layout of csv file
# defines layout of csv file
NAME = row[col]
col += 1
@ -85,29 +85,30 @@ def parse_characterizer_csv(sram,f,pages):
WORD_SIZE = row[col]
col += 1
ORIGIN_ID = row[col]
col += 1
DATETIME = row[col]
col+= 1
col += 1
DRC = row[col]
col += 1
LVS = row[col]
col += 1
for sheet in pages:
AREA = row[col]
col += 1
for sheet in pages:
if sheet.name == NAME:
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:
#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 float(TEMP) > float(item[3]):
@ -128,14 +129,13 @@ def parse_characterizer_csv(sram,f,pages):
if item[0] == 'Operating Frequncy (F)':
try:
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:
pass
while(True):
col_start = col
if(row[col].startswith('DIN')):
start = col
for item in sheet.timing_table.rows:
@ -253,7 +253,6 @@ def parse_characterizer_csv(sram,f,pages):
col += 1
elif(row[col].startswith('WEb')):
start = col
for item in sheet.timing_table.rows:
@ -293,7 +292,6 @@ def parse_characterizer_csv(sram,f,pages):
col += 1
elif(row[col].startswith('ADDR')):
start = col
for item in sheet.timing_table.rows:
@ -333,196 +331,225 @@ def parse_characterizer_csv(sram,f,pages):
col += 1
else:
for element in row[col_start: col - 1]:
sheet.description.append(str(element))
break
new_sheet.corners_table.add_row([PROC,process_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.corners_table.add_row([PROC, process_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, ''))])
if found == 0:
#if this is the first corner for this sram, run first time configuration and set up tables
new_sheet = datasheet(NAME)
# if this is the first corner for this sram, run first time configuration and set up tables
new_sheet = datasheet.datasheet(NAME)
pages.append(new_sheet)
new_sheet.git_id = ORIGIN_ID
new_sheet.time = DATETIME
new_sheet.DRC = DRC
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.add_row(['Corner Name','Process','Power Supply','Temperature','Library Name Suffix'])
new_sheet.corners_table.add_row([PROC,process_name(PROC),VOLT,TEMP,LIB_NAME.replace(OUT_DIR,'').replace(NAME,'')])
new_sheet.operating_table = table_gen("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'])
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([PROC, process_name(
PROC), VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')])
new_sheet.operating_table = table_gen.table_gen(
"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:
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:
new_sheet.operating_table.add_row(['Operating Frequency (F)','','',"not available in netlist only",'MHz']) #failed to provide non-zero MIN_PERIOD
new_sheet.timing_table = table_gen("timing")
new_sheet.timing_table.add_row(['Parameter','Min','Max','Units'])
# failed to provide non-zero MIN_PERIOD
new_sheet.operating_table.add_row(
['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):
col_start = col
if(row[col].startswith('DIN')):
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
new_sheet.timing_table.add_row(['{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'])
new_sheet.timing_table.add_row(
['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
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 +=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')):
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
new_sheet.timing_table.add_row(['{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'])
new_sheet.timing_table.add_row(
['{0} cell fall'.format(row[start]), row[col+1], row[col+2], 'ns'])
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 +=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')):
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
new_sheet.timing_table.add_row(['{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'])
new_sheet.timing_table.add_row(
['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
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 +=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')):
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
new_sheet.timing_table.add_row(['{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'])
new_sheet.timing_table.add_row(
['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
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 +=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')):
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
new_sheet.timing_table.add_row(['{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'])
new_sheet.timing_table.add_row(
['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
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 +=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:
for element in row[col_start:col-1]:
sheet.description.append(str(element))
break
new_sheet.dlv_table = table_gen.table_gen("dlv")
new_sheet.dlv_table.add_row(['Type', 'Description', 'Link'])
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 = table_gen.table_gen("io")
new_sheet.io_table.add_row(['Type', 'Value'])
if not OPTS.netlist_only:
#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(['.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])
# 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(
['.lef', 'LEF files', '<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name, 'lef')])
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():
def datasheet_write(sram,name):
def datasheet_write(name):
in_dir = OPTS.openram_temp
if not (os.path.isdir(in_dir)):
os.mkdir(in_dir)
datasheets = []
parse_characterizer_csv(sram, in_dir + "/datasheet.info", datasheets)
parse_characterizer_csv(in_dir + "/datasheet.info", datasheets)
for sheets in datasheets:
with open(name, 'w+') as f:

View File

@ -9,23 +9,56 @@ import sys
# 2 = verbose
# n = custom setting
def check(check,str):
def check(check, str):
(frame, filename, line_number, function_name, lines,
index) = inspect.getouterframes(inspect.currentframe())[1]
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
def error(str,return_value=0):
def error(str, return_value=0):
(frame, filename, line_number, function_name, lines,
index) = inspect.getouterframes(inspect.currentframe())[1]
sys.stderr.write("ERROR: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str))
assert return_value==0
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 return_value == 0
def warning(str):
(frame, filename, line_number, function_name, lines,
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):
@ -33,9 +66,10 @@ def info(lev, str):
if (OPTS.debug_level >= lev):
frm = inspect.stack()[1]
mod = inspect.getmodule(frm[0])
#classname = frm.f_globals['__name__']
# classname = frm.f_globals['__name__']
if mod.__name__ == None:
class_name=""
class_name = ""
else:
class_name=mod.__name__
print("[{0}/{1}]: {2}".format(class_name,frm[0].f_code.co_name,str))
class_name = mod.__name__
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 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
for drawing text and rectangles, since those functions take layernames, and gdsMill needs layer numbers.
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
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.
Files:
sram_examples:
gdsMill.sh: Adds gdsMill to python path.
Source this before working
printGDS.py: will dump a text version structures within the gds file.
usage: python printGDS.py file
cell6tDemo.py: Will tile cell6t from sram_lib2.gds and output into layoutB.gds. All cells from source are copied into layoutB.gds.
usage: python ./cell6tDemo.py
> 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,7 +1,8 @@
from .gdsPrimitives import *
from datetime import *
#from mpmath import matrix
from numpy import matrix
#from numpy import matrix
import numpy as np
#import gdsPrimitives
import debug
@ -170,21 +171,20 @@ class VlsiLayout:
else:
# MRG: Added negative to make CCW rotate 8/29/18
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],
[0.0,0.0,1.0]])
#set up the translation matrix
translateX = float(coordinates[0])
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)
scaleX = 1.0
if(transFlags[0]):
scaleY = -1.0
else:
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
#when we add an element to the xy tree, we apply all transforms from the bottom up
transformPath.append((mRotate,mScale,mTranslate))
@ -219,27 +219,26 @@ class VlsiLayout:
def populateCoordinateMap(self):
def addToXyTree(startingStructureName = None,transformPath = None):
#print("populateCoordinateMap")
uVector = matrix([1.0,0.0,0.0]).transpose() #start with normal basis vectors
vVector = matrix([0.0,1.0,0.0]).transpose()
origin = matrix([0.0,0.0,1.0]).transpose() #and an origin (Z component is 1.0 to indicate position instead of vector)
uVector = np.array([[1.0],[0.0],[0.0]]) #start with normal basis vectors
vVector = np.array([[0.0],[1.0],[0.0]])
origin = np.array([[0.0],[0.0],[1.0]]) #and an origin (Z component is 1.0 to indicate position instead of vector)
#make a copy of all the transforms and reverse it
reverseTransformPath = transformPath[:]
if len(reverseTransformPath) > 1:
reverseTransformPath.reverse()
reverseTransformPath.reverse()
#now go through each transform and apply them to our basis and origin in succession
for transform in reverseTransformPath:
origin = transform[0] * origin #rotate
uVector = transform[0] * uVector #rotate
vVector = transform[0] * vVector #rotate
origin = transform[1] * origin #scale
uVector = transform[1] * uVector #scale
vVector = transform[1] * vVector #scale
origin = transform[2] * origin #translate
origin = np.dot(transform[0], origin) #rotate
uVector = np.dot(transform[0], uVector) #rotate
vVector = np.dot(transform[0], vVector) #rotate
origin = np.dot(transform[1], origin) #scale
uVector = np.dot(transform[1], uVector) #scale
vVector = np.dot(transform[1], vVector) #scale
origin = np.dot(transform[2], origin) #translate
#we don't need to do a translation on the basis vectors
#uVector = transform[2] * uVector #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.traverseTheHierarchy(delegateFunction = addToXyTree)
@ -522,8 +521,7 @@ class VlsiLayout:
return True
def fillAreaDensity(self, layerToFill = 0, offsetInMicrons = (0,0), coverageWidth = 100.0, coverageHeight = 100.0,
minSpacing = 0.22, blockSize = 1.0):
def fillAreaDensity(self, layerToFill = 0, offsetInMicrons = (0,0), coverageWidth = 100.0, coverageHeight = 100.0, minSpacing = 0.22, blockSize = 1.0):
effectiveBlock = blockSize+minSpacing
widthInBlocks = int(coverageWidth/effectiveBlock)
heightInBlocks = int(coverageHeight/effectiveBlock)
@ -810,8 +808,8 @@ class VlsiLayout:
# This is fixed to be:
# |u[0] v[0]| |x| |x'|
# |u[1] v[1]|x|y|=|y'|
x=coordinate[0]*uVector[0].item()+coordinate[1]*vVector[0].item()
y=coordinate[0]*uVector[1].item()+coordinate[1]*vVector[1].item()
x=coordinate[0]*uVector[0][0]+coordinate[1]*vVector[0][0]
y=coordinate[0]*uVector[1][0]+coordinate[1]*vVector[1][0]
transformCoordinate=[x,y]
return transformCoordinate
@ -836,5 +834,3 @@ def boundaryArea(A):
area_A=(A[2]-A[0])*(A[3]-A[1])
return area_A

View File

@ -71,26 +71,26 @@ def print_banner():
if OPTS.is_unit_test:
return
print("|==============================================================================|")
debug.print_raw("|==============================================================================|")
name = "OpenRAM Compiler"
print("|=========" + name.center(60) + "=========|")
print("|=========" + " ".center(60) + "=========|")
print("|=========" + "VLSI Design and Automation Lab".center(60) + "=========|")
print("|=========" + "Computer Science and Engineering Department".center(60) + "=========|")
print("|=========" + "University of California Santa Cruz".center(60) + "=========|")
print("|=========" + " ".center(60) + "=========|")
print("|=========" + "VLSI Computer Architecture Research Group".center(60) + "=========|")
print("|=========" + "Electrical and Computer Engineering Department".center(60) + "=========|")
print("|=========" + "Oklahoma State University".center(60) + "=========|")
print("|=========" + " ".center(60) + "=========|")
debug.print_raw("|=========" + name.center(60) + "=========|")
debug.print_raw("|=========" + " ".center(60) + "=========|")
debug.print_raw("|=========" + "VLSI Design and Automation Lab".center(60) + "=========|")
debug.print_raw("|=========" + "Computer Science and Engineering Department".center(60) + "=========|")
debug.print_raw("|=========" + "University of California Santa Cruz".center(60) + "=========|")
debug.print_raw("|=========" + " ".center(60) + "=========|")
debug.print_raw("|=========" + "VLSI Computer Architecture Research Group".center(60) + "=========|")
debug.print_raw("|=========" + "Electrical and Computer Engineering Department".center(60) + "=========|")
debug.print_raw("|=========" + "Oklahoma State University".center(60) + "=========|")
debug.print_raw("|=========" + " ".center(60) + "=========|")
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"
print("|=========" + dev_info.center(60) + "=========|")
debug.print_raw("|=========" + dev_info.center(60) + "=========|")
temp_info = "Temp dir: {}".format(OPTS.openram_temp)
print("|=========" + temp_info.center(60) + "=========|")
print("|=========" + "See LICENSE for license info".center(60) + "=========|")
print("|==============================================================================|")
debug.print_raw("|=========" + temp_info.center(60) + "=========|")
debug.print_raw("|=========" + "See LICENSE for license info".center(60) + "=========|")
debug.print_raw("|==============================================================================|")
def check_versions():
@ -130,6 +130,9 @@ def init_openram(config_file, is_unit_test=True):
init_paths()
from sram_factory import factory
factory.reset()
# Reset the static duplicate name checker for unit tests.
import hierarchy_design
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"
else:
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():
@ -413,20 +416,20 @@ def report_status():
if not OPTS.tech_name:
debug.error("Tech name must be specified in config file.")
print("Technology: {0}".format(OPTS.tech_name))
print("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("Technology: {0}".format(OPTS.tech_name))
debug.print_raw("Total size: {} bits".format(OPTS.word_size*OPTS.num_words*OPTS.num_banks))
debug.print_raw("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size,
OPTS.num_words,
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_w_ports))
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:
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:
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
import contact
import pgates
from pinv import pinv
from pnand2 import pnand2
from pnor2 import pnor2
from sram_factory import factory
from vector import vector
from globals import OPTS
@ -396,25 +394,14 @@ class bank(design.design):
def add_modules(self):
""" 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 = self.mod_bitcell_array(cols=self.num_cols,
rows=self.num_rows)
self.bitcell_array = factory.create(module_type="bitcell_array",
cols=self.num_cols,
rows=self.num_rows)
self.add_mod(self.bitcell_array)
# 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.br_names = self.bitcell.list_all_br_names()
self.wl_names = self.bitcell.list_all_wl_names()
@ -423,7 +410,11 @@ class bank(design.design):
self.precharge_array = []
for port in self.all_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])
else:
self.precharge_array.append(None)
@ -431,32 +422,39 @@ class bank(design.design):
if self.col_addr_size > 0:
self.column_mux_array = []
for port in self.all_ports:
self.column_mux_array.append(self.mod_column_mux_array(columns=self.num_cols,
word_size=self.word_size,
bitcell_bl=self.bl_names[port],
bitcell_br=self.br_names[port]))
temp_col = factory.create(module_type="column_mux_array",
columns=self.num_cols,
word_size=self.word_size,
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.sense_amp_array = self.mod_sense_amp_array(word_size=self.word_size,
words_per_row=self.words_per_row)
self.sense_amp_array = factory.create(module_type="sense_amp_array",
word_size=self.word_size,
words_per_row=self.words_per_row)
self.add_mod(self.sense_amp_array)
self.write_driver_array = self.mod_write_driver_array(columns=self.num_cols,
word_size=self.word_size)
self.write_driver_array = factory.create(module_type="write_driver_array",
columns=self.num_cols,
word_size=self.word_size)
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.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.inv = pinv()
self.inv = factory.create(module_type="pinv")
self.add_mod(self.inv)
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)
@ -693,18 +691,17 @@ class bank(design.design):
"""
Create a 2:4 or 3:8 column address decoder.
"""
dff = factory.create(module_type="dff")
if self.col_addr_size == 0:
return
elif self.col_addr_size == 1:
from pinvbuf import pinvbuf
self.column_decoder = pinvbuf(height=self.mod_dff.height)
self.column_decoder = factory.create(module_type="pinvbuf", height=dff.height)
elif self.col_addr_size == 2:
from hierarchical_predecode2x4 import hierarchical_predecode2x4 as pre2x4
self.column_decoder = pre2x4(height=self.mod_dff.height)
self.column_decoder = factory.create(module_type="hierarchical_predecode2x4", height=dff.height)
elif self.col_addr_size == 3:
from hierarchical_predecode3x8 import hierarchical_predecode3x8 as pre3x8
self.column_decoder = pre3x8(height=self.mod_dff.height)
self.column_decoder = factory.create(module_type="hierarchical_predecode3x8", height=dff.height)
else:
# No error checking before?
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.
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()
mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0)
mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1)
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 = mid1.scale(1,0)+bitcell_wl_pos.scale(0.5,1)
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.
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()
mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0)
mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1)
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 = mid1.scale(1,0)+bitcell_wl_pos.scale(0,1)
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
def route_column_address_lines(self, port):
@ -1257,20 +1254,22 @@ class bank(design.design):
def get_wl_en_cin(self):
"""Get the relative capacitance of all the clk connections in the bank"""
#wl_en only used in the wordline driver.
total_clk_cin = self.wordline_driver.get_wl_en_cin()
return total_clk_cin
return self.wordline_driver.get_wl_en_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):
"""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.
#Precharges are the all the same in Mulitport, one is picked
port = self.read_ports[0]
total_clk_bar_cin = self.precharge_array[port].get_en_cin()
return total_clk_bar_cin
return self.precharge_array[port].get_en_cin()
def get_sen_cin(self):
"""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.
total_sen_cin = self.sense_amp_array.get_en_cin()
return total_sen_cin
return self.sense_amp_array.get_en_cin()

View File

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

View File

@ -3,8 +3,7 @@ import design
from tech import drc, spice
from vector import vector
from globals import OPTS
unique_id = 1
from sram_factory import factory
class bitcell_array(design.design):
"""
@ -12,16 +11,10 @@ class bitcell_array(design.design):
and word line is connected by abutment.
Connects the word lines and bit lines.
"""
unique_id = 1
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
def __init__(self, cols, rows, name):
design.design.__init__(self, name)
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.row_size = rows
@ -83,11 +76,7 @@ class bitcell_array(design.design):
def add_modules(self):
""" Add the modules used in this design """
from importlib import reload
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.cell = self.mod_bitcell()
self.cell = factory.create(module_type="bitcell")
self.add_mod(self.cell)
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
bitcell_wl_cin = self.cell.get_wl_cin()
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
import debug
import contact
from pinv import pinv
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
from sram_factory import factory
import math
from vector import vector
from globals import OPTS
@ -20,20 +14,26 @@ class control_logic(design.design):
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 """
name = "control_logic_" + port_type
design.design.__init__(self, 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.words_per_row = words_per_row
self.word_size = word_size
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
#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.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.
@ -73,46 +73,69 @@ class control_logic(design.design):
def add_modules(self):
""" Add all the required modules """
dff = dff_buf()
dff = factory.create(module_type="dff_buf")
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.and2 = pand2(size=4,height=dff_height)
self.and2 = factory.create(module_type="pand2",
size=4,
height=dff_height)
self.add_mod(self.and2)
# Special gates: inverters for buffering
# Size the clock for the number of rows (fanout)
clock_driver_size = max(1,int(self.num_rows/4))
self.clkbuf = pbuf(size=clock_driver_size, height=dff_height)
self.add_mod(self.clkbuf)
self.buf16 = pbuf(size=16, height=dff_height)
self.add_mod(self.buf16)
self.buf8 = pbuf(size=8, height=dff_height)
self.add_mod(self.buf8)
# clk_buf drives a flop for every address and control bit
# plus about 5 fanouts for the control logic
# each flop internally has a FO 4 approximately
clock_fanout = 4*(math.log(self.num_words,2) + math.log(self.words_per_row,2) \
+ self.num_control_signals) + 5
self.clk_buf_driver = factory.create(module_type="pdriver",
fanout=clock_fanout,
height=dff_height)
self.inv = self.inv1 = pinv(size=1, height=dff_height)
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)
self.add_mod(self.clk_buf_driver)
# 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"):
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()
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:
self.set_sen_wl_delays()
@ -124,8 +147,10 @@ class control_logic(design.design):
#This resizes based on total delay.
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.add_mod(self.replica_bitline)
@ -393,8 +418,8 @@ class control_logic(design.design):
def create_clk_buf_row(self):
""" Create the multistage and gated clock buffer """
self.clkbuf_inst = self.add_inst(name="clkbuf",
mod=self.clkbuf)
self.clk_buf_inst = self.add_inst(name="clkbuf",
mod=self.clk_buf_driver)
self.connect_inst(["clk","clk_buf","vdd","gnd"])
def place_clk_buf_row(self,row):
@ -403,12 +428,12 @@ class control_logic(design.design):
(y_off,mirror)=self.get_offset(row)
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):
clk_pin = self.clkbuf_inst.get_pin("A")
clk_pin = self.clk_buf_inst.get_pin("A")
clk_pos = clk_pin.center()
self.add_layout_pin_segment_center(text="clk",
layer="metal2",
@ -418,14 +443,17 @@ class control_logic(design.design):
offset=clk_pos)
clkbuf_map = zip(["Z"], ["clk_buf"])
self.connect_vertical_bus(clkbuf_map, self.clkbuf_inst, self.rail_offsets, ("metal3", "via2", "metal2"))
# Connect this at the bottom of the buffer
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
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):
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):
# input pre_p_en, output: 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"])
def place_wlen_row(self, row):
@ -574,7 +602,7 @@ class control_logic(design.design):
# input: pre_p_en, output: 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"])
@ -614,7 +642,7 @@ class control_logic(design.design):
# BUFFER FOR S_EN
# input: pre_s_en, output: 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"])
def place_sen_row(self,row):
@ -651,7 +679,7 @@ class control_logic(design.design):
# BUFFER FOR W_EN
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"])
@ -808,7 +836,7 @@ class control_logic(design.design):
#Calculate the load on wl_en within the module and add it to external load
external_cout = self.sram.get_wl_en_cin()
#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
#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.
if self.port_type == "rw":
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
#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)
last_stage_rise = stage_effort_list[-1].is_rise
#buffer stage, pre_s_en -(buffer)-> s_en
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
return stage_effort_list

View File

@ -1,10 +1,10 @@
import debug
import design
from tech import drc
from pinv import pinv
from contact import contact
from vector import vector
from globals import OPTS
from sram_factory import factory
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.
"""
unique_id = 1
def __init__(self, fanout_list, name="delay_chain"):
def __init__(self, name, fanout_list):
"""init function"""
name = name+"_{}".format(delay_chain.unique_id)
delay_chain.unique_id += 1
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
for f in fanout_list:
debug.check(f>=2,"Must have >=2 fanouts for each stage.")
@ -57,7 +55,7 @@ class delay_chain(design.design):
self.add_pin("gnd")
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)
def create_inverters(self):
@ -234,8 +232,8 @@ class delay_chain(design.design):
stage_cout = self.inv.get_cin()*(stage_fanout+1)
if len(stage_effort_list) == len(self.fanout_list)-1: #last stage
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)
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 math import log
from vector import vector
from sram_factory import factory
from globals import OPTS
class dff_array(design.design):
@ -11,7 +12,7 @@ class dff_array(design.design):
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.columns = columns
@ -19,7 +20,8 @@ class dff_array(design.design):
name = "dff_array_{0}x{1}".format(rows, columns)
design.design.__init__(self, name)
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()
if not OPTS.netlist_only:
self.create_layout()
@ -38,10 +40,7 @@ class dff_array(design.design):
self.DRC_LVS()
def add_modules(self):
from importlib import reload
c = reload(__import__(OPTS.dff))
self.mod_dff = getattr(c, OPTS.dff)
self.dff = self.mod_dff("dff")
self.dff = factory.create(module_type="dff")
self.add_mod(self.dff)
def add_pins(self):
@ -61,7 +60,7 @@ class dff_array(design.design):
for col in range(self.columns):
name = "dff_r{0}_c{1}".format(row,col)
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.get_dout_name(row,col),
"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"""
dff_clk_cin = self.dff.get_clk_cin()
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 vector import vector
from globals import OPTS
from pinv import pinv
from sram_factory import factory
class dff_buf(design.design):
"""
@ -21,7 +21,8 @@ class dff_buf(design.design):
dff_buf.unique_id += 1
design.design.__init__(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 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.
@ -50,16 +51,17 @@ class dff_buf(design.design):
self.DRC_LVS()
def add_modules(self):
from importlib import reload
c = reload(__import__(OPTS.dff))
self.mod_dff = getattr(c, OPTS.dff)
self.dff = self.mod_dff("dff")
self.dff = factory.create(module_type="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.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)
@ -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.
#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.
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 vector import vector
from globals import OPTS
import dff_buf
from sram_factory import factory
class dff_buf_array(design.design):
"""
@ -22,6 +22,9 @@ class dff_buf_array(design.design):
dff_buf_array.unique_id += 1
design.design.__init__(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.inv2_size = inv2_size
@ -54,7 +57,9 @@ class dff_buf_array(design.design):
self.add_pin("gnd")
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)
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"""
dff_clk_cin = self.dff.get_clk_cin()
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
design.design.__init__(self, name)
debug.info(1, "Creating {}".format(self.name))
self.add_comment("inv: {0}".format(inv_size))
self.inv_size = inv_size
# 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")
def add_modules(self):
from importlib import reload
c = reload(__import__(OPTS.dff))
self.mod_dff = getattr(c, OPTS.dff)
self.dff = self.mod_dff("dff")
self.dff = dff_inv.dff_inv(self.inv_size)
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)
def create_modules(self):
@ -152,4 +153,4 @@ class dff_inv(design.design):
def get_clk_cin(self):
"""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
design.design.__init__(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.create_netlist()
@ -42,7 +45,7 @@ class dff_inv_array(design.design):
self.DRC_LVS()
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)
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"""
dff_clk_cin = self.dff.get_clk_cin()
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 sqrt
import math
import contact
from pnand2 import pnand2
from pnand3 import pnand3
from pinv import pinv
from hierarchical_predecode2x4 import hierarchical_predecode2x4 as pre2x4
from hierarchical_predecode3x8 import hierarchical_predecode3x8 as pre3x8
import contact
from sram_factory import factory
from vector import vector
from globals import OPTS
@ -17,11 +13,8 @@ class hierarchical_decoder(design.design):
"""
Dynamically generated hierarchical decoder.
"""
unique_id = 1
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
def __init__(self, name, rows, height=None):
design.design.__init__(self, name)
self.NAND_FORMAT = "DEC_NAND_{0}"
self.INV_FORMAT = "DEC_INV_{0}"
@ -57,21 +50,26 @@ class hierarchical_decoder(design.design):
self.DRC_LVS()
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.nand2 = pnand2(height=self.cell_height)
self.nand2 = factory.create(module_type="pnand2",
height=self.cell_height)
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_decoders()
def add_decoders(self):
""" 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.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)
def determine_predecodes(self,num_inputs):

View File

@ -3,24 +3,19 @@ import design
import math
from tech import drc
import contact
from pinv import pinv
from vector import vector
from globals import OPTS
from pnand2 import pnand2
from pnand3 import pnand3
from sram_factory import factory
class hierarchical_predecode(design.design):
"""
Pre 2x4 and 3x8 decoder shared code.
"""
unique_id = 1
def __init__(self, input_number, height=None):
def __init__(self, name, input_number, height=None):
self.number_of_inputs = input_number
self.cell_height = height
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))
hierarchical_predecode.unique_id += 1
design.design.__init__(self, name)
def add_pins(self):
for k in range(self.number_of_inputs):
@ -33,7 +28,8 @@ class hierarchical_predecode(design.design):
def add_modules(self):
""" 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_nand(self.number_of_inputs)
@ -42,9 +38,11 @@ class hierarchical_predecode(design.design):
def add_nand(self,inputs):
""" Create the NAND for the predecode input stage """
if inputs==2:
self.nand = pnand2(height=self.cell_height)
self.nand = factory.create(module_type="pnand2",
height=self.cell_height)
elif inputs==3:
self.nand = pnand3(height=self.cell_height)
self.nand = factory.create(module_type="pnand3",
height=self.cell_height)
else:
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.
"""
def __init__(self, height=None):
hierarchical_predecode.__init__(self, 2, height)
def __init__(self, name, height=None):
hierarchical_predecode.__init__(self, name, 2, height)
self.create_netlist()
if not OPTS.netlist_only:

View File

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

View File

@ -5,12 +5,8 @@ import design
import math
from math import log,sqrt,ceil
import contact
from pinv import pinv
from pnand2 import pnand2
from pnor2 import pnor2
from vector import vector
from pinvbuf import pinvbuf
from sram_factory import factory
from globals import OPTS
class multibank(design.design):
@ -21,21 +17,8 @@ class multibank(design.design):
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)
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
from tech import drc
from vector import vector
from precharge import precharge
from sram_factory import factory
from globals import OPTS
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.
"""
unique_id = 1
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
def __init__(self, name, columns, size=1, bitcell_bl="bl", bitcell_br="br"):
design.design.__init__(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.size = size
self.bitcell_bl = bitcell_bl
@ -50,10 +47,12 @@ class precharge_array(design.design):
self.DRC_LVS()
def add_modules(self):
self.pc_cell = precharge(name="precharge",
size=self.size,
bitcell_bl=self.bitcell_bl,
bitcell_br=self.bitcell_br)
self.pc_cell = factory.create(module_type="precharge",
size=self.size,
bitcell_bl=self.bitcell_bl,
bitcell_br=self.bitcell_br)
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"""
#Assume single port
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 design
from tech import drc
from pinv import pinv
import contact
from bitcell_array import bitcell_array
from ptx import ptx
from sram_factory import factory
from vector import vector
from globals import OPTS
@ -15,7 +13,7 @@ class replica_bitline(design.design):
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)
self.bitcell_loads = bitcell_loads
@ -78,29 +76,25 @@ class replica_bitline(design.design):
def add_modules(self):
""" Add the modules for later usage """
from importlib import reload
#g = reload(__import__(OPTS.delay_chain))
#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)
self.replica_bitcell = factory.create(module_type="replica_bitcell")
self.add_mod(self.replica_bitcell)
# 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)
# FIXME: The FO and depth of this should be tuned
from delay_chain import delay_chain
self.delay_chain = delay_chain(self.delay_fanout_list)
self.delay_chain = factory.create(module_type="delay_chain",
fanout_list=self.delay_fanout_list)
self.add_mod(self.delay_chain)
self.inv = pinv()
self.inv = factory.create(module_type="pinv")
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)
def create_instances(self):
@ -132,7 +126,6 @@ class replica_bitline(design.design):
temp.append("vdd")
temp.append("gnd")
self.connect_inst(temp)
#self.connect_inst(["bl_0", "br_0", "delayed_en", "vdd", "gnd"])
self.rbl_inst=self.add_inst(name="load",
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
#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)
return stage_effort_list
@ -631,4 +624,4 @@ class replica_bitline(design.design):
access_tx_cin = self.access_tx.get_cin()
rbc_cin = self.replica_bitcell.get_wl_cin()
return access_tx_cin + rbc_cin

View File

@ -1,6 +1,7 @@
import design
from tech import drc
from vector import vector
from sram_factory import factory
import debug
from globals import OPTS
@ -10,9 +11,11 @@ class sense_amp_array(design.design):
Dynamically generated sense amp array for all bitlines.
"""
def __init__(self, word_size, words_per_row):
design.design.__init__(self, "sense_amp_array")
def __init__(self, name, word_size, words_per_row):
design.design.__init__(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.words_per_row = words_per_row
@ -51,17 +54,13 @@ class sense_amp_array(design.design):
self.add_pin("gnd")
def add_modules(self):
from importlib import reload
c = reload(__import__(OPTS.sense_amp))
self.mod_sense_amp = getattr(c, OPTS.sense_amp)
self.amp = self.mod_sense_amp("sense_amp")
self.amp = factory.create(module_type="sense_amp")
self.add_mod(self.amp)
# This is just used for measurements,
# so don't add the module
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
self.bitcell = factory.create(module_type="bitcell")
def create_sense_amp_array(self):
self.local_insts = []
@ -143,4 +142,4 @@ class sense_amp_array(design.design):
def get_en_cin(self):
"""Get the relative capacitance of all the sense amp enable connections in the array"""
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
import design
from single_level_column_mux import single_level_column_mux
import contact
from tech import drc
import debug
import math
from vector import vector
from sram_factory import factory
from globals import OPTS
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.
"""
unique_id = 1
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
def __init__(self, name, columns, word_size, bitcell_bl="bl", bitcell_br="br"):
design.design.__init__(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.word_size = 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):
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)

View File

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

View File

@ -5,9 +5,8 @@ import contact
from math import log
from math import sqrt
import math
from pinv import pinv
from pnand2 import pnand2
from vector import vector
from sram_factory import factory
from globals import OPTS
class wordline_driver(design.design):
@ -16,10 +15,13 @@ class wordline_driver(design.design):
Generates the wordline-driver to drive the bitcell
"""
def __init__(self, rows):
design.design.__init__(self, "wordline_driver")
def __init__(self, name, rows, cols):
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.cols = cols
self.create_netlist()
if not OPTS.netlist_only:
@ -53,13 +55,16 @@ class wordline_driver(design.design):
# This is just used for measurements,
# 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.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.nand2 = pnand2()
self.nand2 = factory.create(module_type="pnand2")
self.add_mod(self.nand2)
@ -224,12 +229,12 @@ class wordline_driver(design.design):
stage_effort_list = []
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)
last_stage_is_rise = stage1.is_rise
stage2 = self.inv.get_effort_stage(external_cout, last_stage_is_rise)
stage_effort_list.append(stage2)
stage2 = self.inv.get_stage_efforts(external_cout, last_stage_is_rise)
stage_effort_list.extend(stage2)
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"""
#The enable is connected to a nand2 for every row.
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.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
from tech import drc
import debug
from sram_factory import factory
from vector import vector
from globals import OPTS
@ -11,9 +12,11 @@ class write_driver_array(design.design):
Dynamically generated write driver array of all bitlines.
"""
def __init__(self, columns, word_size):
design.design.__init__(self, "write_driver_array")
def __init__(self, name, columns, word_size):
design.design.__init__(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.word_size = word_size
@ -53,17 +56,12 @@ class write_driver_array(design.design):
self.add_pin("gnd")
def add_modules(self):
from importlib import reload
c = reload(__import__(OPTS.write_driver))
self.mod_write_driver = getattr(c, OPTS.write_driver)
self.driver = self.mod_write_driver("write_driver")
self.driver = factory.create(module_type="write_driver")
self.add_mod(self.driver)
# This is just used for measurements,
# so don't add the module
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
self.bitcell = factory.create(module_type="bitcell")
def create_write_array(self):
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
c = sram_config(word_size=OPTS.word_size,
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 *
output_extensions = ["sp","v","lib","py","html"]
output_extensions = ["sp","v","lib","py","html","log"]
if not OPTS.netlist_only:
output_extensions.extend(["gds","lef"])
output_files = ["{0}{1}.{2}".format(OPTS.output_path,OPTS.output_name,x) for x in output_extensions]
print("Output files are: ")
print(*output_files,sep="\n")
debug.print_raw("Output files are: ")
for path in output_files:
debug.print_raw(path)
from sram import sram

View File

@ -72,23 +72,24 @@ class options(optparse.Values):
num_banks = 1
# 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"
delay_chain = "delay_chain"
dff_array = "dff_array"
dff = "dff"
control_logic = "control_logic"
bitcell_array = "bitcell_array"
sense_amp = "sense_amp"
sense_amp_array = "sense_amp_array"
precharge_array = "precharge_array"
column_mux_array = "single_level_column_mux_array"
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"
ptx = "ptx"
replica_bitcell = "replica_bitcell"
bitcell = "bitcell"
delay_chain = "delay_chain"
bank_select = "bank_select"
replica_bitline = "replica_bitline"
sense_amp_array = "sense_amp_array"
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 vector import vector
from globals import OPTS
from pnand2 import pnand2
from pinv import pinv
import pgate
from sram_factory import factory
class pand2(pgate.pgate):
"""
This is a simple buffer used for driving loads.
"""
from importlib import reload
c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.bitcell)
unique_id = 1
def __init__(self, size=1, height=None, name=""):
def __init__(self, name, size=1, height=None):
self.size = size
if name=="":
name = "pand2_{0}_{1}".format(size, pand2.unique_id)
pand2.unique_id += 1
pgate.pgate.__init__(self, name, height)
debug.info(1, "Creating {}".format(self.name))
self.add_comment("size: {}".format(size))
self.create_netlist()
if not OPTS.netlist_only:
@ -41,10 +29,10 @@ class pand2(pgate.pgate):
def create_modules(self):
# 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.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)
def create_layout(self):
@ -125,15 +113,15 @@ class pand2(pgate.pgate):
inv_delay = self.inv.analytical_delay(slew=nand_delay.slew, load=load)
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"""
stage_effort_list = []
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)
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)
return stage_effort_list

View File

@ -3,32 +3,23 @@ from tech import drc
from math import log
from vector import vector
from globals import OPTS
from pinv import pinv
import pgate
from sram_factory import factory
class pbuf(pgate.pgate):
"""
This is a simple buffer used for driving loads.
"""
from importlib import reload
c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.bitcell)
unique_id = 1
def __init__(self, size=4, height=None, name=""):
def __init__(self, name, size=4, height=None):
self.stage_effort = 4
self.size = size
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)
debug.info(1, "creating {0} with size of {1}".format(self.name,self.size))
self.add_comment("size: {}".format(size))
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@ -54,10 +45,10 @@ class pbuf(pgate.pgate):
def create_modules(self):
# Shield the cap, but have at least a stage effort of 4
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.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)
def create_insts(self):
@ -125,15 +116,15 @@ class pbuf(pgate.pgate):
inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load)
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"""
stage_effort_list = []
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)
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)
return stage_effort_list
@ -141,4 +132,4 @@ class pbuf(pgate.pgate):
def get_cin(self):
"""Returns the relative capacitance of the input"""
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 vector import vector
from globals import OPTS
from pinv import pinv
from sram_factory import factory
class pdriver(pgate.pgate):
"""
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 = 4
self.stage_effort = 3
self.height = height
self.neg_polarity = neg_polarity
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):
debug.error("Cannot specify both size_list and neg_polarity or fanout_size.", -1)
if self.size_list and self.fanout != 0:
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)
debug.info(1, "Creating {}".format(self.name))
self.compute_sizes()
self.add_comment("sizes: {}".format(str(self.size_list)))
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
def compute_sizes(self):
# size_list specified
if len(self.size_list) > 0:
if not len(self.size_list) % 2:
neg_polarity = True
self.num_inv = len(self.size_list)
if self.size_list:
self.num_stages = len(self.size_list)
else:
# find the number of stages
#fanout_size is a unit inverter fanout, not a capacitance so c_in=1
num_stages = max(1,int(round(log(self.fanout_size)/log(4))))
# Find the optimal number of stages for the given effort
self.num_stages = max(1,int(round(log(self.fanout)/log(self.stage_effort))))
# find inv_num and compute sizes
if self.neg_polarity:
if (num_stages % 2 == 0): # if num_stages is even
self.diff_polarity(num_stages=num_stages)
else: # if num_stages is odd
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)
# Increase the number of stages if we need to fix polarity
if self.neg_polarity and (self.num_stages%2==0):
self.num_stages += 1
elif not self.neg_polarity and (self.num_stages%2):
self.num_stages += 1
def same_polarity(self, num_stages):
self.calc_size_list = []
self.num_inv = num_stages
# 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/self.stage_effort))
self.calc_size_list.append(fanout_size_prev)
self.size_list = []
# compute sizes backwards from the fanout
fanout_prev = self.fanout
for x in range(self.num_stages):
fanout_prev = max(round(fanout_prev/self.stage_effort),1)
self.size_list.append(fanout_prev)
def diff_polarity(self, num_stages):
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)
# reverse the sizes to be from input to output
self.size_list.reverse()
def create_netlist(self):
inv_list = []
self.add_pins()
self.add_modules()
self.create_insts()
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.route_wires()
self.add_layout_pins()
self.width = self.inv_inst_list[-1].rx()
self.height = self.inv_inst_list[0].height
self.DRC_LVS()
def add_pins(self):
@ -121,31 +83,27 @@ class pdriver(pgate.pgate):
def add_modules(self):
self.inv_list = []
if len(self.size_list) > 0: # size list specified
for x in range(len(self.size_list)):
self.inv_list.append(pinv(size=self.size_list[x], height=self.height))
self.add_mod(self.inv_list[x])
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])
for size in self.size_list:
temp_inv = factory.create(module_type="pinv", size=size, height=self.height)
self.inv_list.append(temp_inv)
self.add_mod(temp_inv)
def create_insts(self):
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
if x == 1:
zbx_int = "Zb{}_int".format(x);
self.inv_inst_list.append(self.add_inst(name="buf_inv{}".format(x),
mod=self.inv_list[x-1]))
if self.num_inv == 1:
if self.num_stages == 1:
self.connect_inst(["A", "Z", "vdd", "gnd"])
else:
self.connect_inst(["A", zbx_int, "vdd", "gnd"])
# Create last inverter
elif x == self.num_inv:
elif x == self.num_stages:
zbn_int = "Zb{}_int".format(x-1);
self.inv_inst_list.append(self.add_inst(name="buf_inv{}".format(x),
mod=self.inv_list[x-1]))
@ -161,10 +119,10 @@ class pdriver(pgate.pgate):
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))
# 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)):
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(),
height = a_pin.height())
def input_load(self):
return self.inv_list[0].input_load()
def analytical_delay(self, slew, load=0.0):
"""Calculate the analytical delay of INV1 -> ... -> INVn"""
delay = 0;
if len(self.inv_inst_list) == 1:
delay = self.inv_inst_list[x].analytical_delay(slew=slew);
else:
for x in range(len(self.inv_inst_list-1)):
load_next = 0.0
for n in range(x,len(self.inv_inst_list+1)):
load_next += self.inv_inst_list[x+1]
if x == 1:
delay += self.inv_inst_list[x].analytical_delay(slew=slew,
load=load_next)
else:
delay += self.inv_inst_list[x+1].analytical_delay(slew=delay.slew,
load=load_next)
cout_list = []
for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]):
cout_list.append(inv.input_load())
cout_list.append(load)
input_slew = slew
delays = []
for inv,cout in zip(self.inv_list,cout_list):
delays.append(inv.analytical_delay(slew=input_slew, load=cout))
input_slew = delays[-1].slew
delay = delays[0]
for i in range(len(delays)-1):
delay += delays[i]
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 debug
from tech import drc, parameter, spice
from ptx import ptx
from vector import vector
from globals import OPTS
from sram_factory import factory
class pgate(design.design):
"""
@ -18,15 +18,12 @@ class pgate(design.design):
if height:
self.height = height
elif not height:
from importlib import reload
c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.bitcell)
b = bitcell()
b = factory.create(module_type="bitcell")
self.height = b.height
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)
supply_pin = self.get_pin(supply)
if supply_pin.overlaps(source_pin):

View File

@ -2,12 +2,12 @@ import contact
import pgate
import debug
from tech import drc, parameter, spice
from ptx import ptx
from vector import vector
from math import ceil
from globals import OPTS
from utils import round_to_grid
import logical_effort
from sram_factory import factory
class pinv(pgate.pgate):
"""
@ -19,17 +19,14 @@ class pinv(pgate.pgate):
output to the right side of the cell for easier access.
"""
unique_id = 1
def __init__(self, size=1, beta=parameter["beta"], height=None, route_output=True):
def __init__(self, name, size=1, beta=parameter["beta"], height=None, route_output=True):
# We need to keep unique names because outputting to GDSII
# 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
# have poly connected, for example.
name = "pinv_{}".format(pinv.unique_id)
pinv.unique_id += 1
pgate.pgate.__init__(self, name, height)
debug.info(2, "create pinv structure {0} with size of {1}".format(name, size))
self.add_comment("size: {}".format(size))
self.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?
# Assume we need 3 metal 1 pitches (2 power rails, one between the tx for the drain)
# plus the tx height
nmos = ptx(tx_type="nmos")
pmos = ptx(width=drc("minwidth_tx"), tx_type="pmos")
nmos = factory.create(module_type="ptx", tx_type="nmos")
pmos = factory.create(module_type="ptx", width=drc("minwidth_tx"), tx_type="pmos")
tx_height = nmos.poly_height + pmos.poly_height
# rotated m1 pitch or poly to active spacing
min_channel = max(contact.poly.width + self.m1_space,
@ -147,18 +144,20 @@ class pinv(pgate.pgate):
def add_ptx(self):
""" Create the PMOS and NMOS transistors. """
self.nmos = ptx(width=self.nmos_width,
mults=self.tx_mults,
tx_type="nmos",
connect_poly=True,
connect_active=True)
self.nmos = factory.create(module_type="ptx",
width=self.nmos_width,
mults=self.tx_mults,
tx_type="nmos",
connect_poly=True,
connect_active=True)
self.add_mod(self.nmos)
self.pmos = ptx(width=self.pmos_width,
mults=self.tx_mults,
tx_type="pmos",
connect_poly=True,
connect_active=True)
self.pmos = factory.create(module_type="ptx",
width=self.pmos_width,
mults=self.tx_mults,
tx_type="pmos",
connect_poly=True,
connect_active=True)
self.add_mod(self.pmos)
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 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.
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 vector import vector
from globals import OPTS
from pinv import pinv
from sram_factory import factory
class pinvbuf(design.design):
"""
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.
"""
unique_id = 1
def __init__(self, driver_size=4, height=None, name=""):
def __init__(self, name, size=4, height=None):
self.stage_effort = 4
self.row_height = height
@ -22,14 +20,12 @@ class pinvbuf(design.design):
# stage effort of 4 or less
# 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
self.driver_size = driver_size
self.predriver_size = max(int(self.driver_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
self.size = size
self.predriver_size = max(int(self.size/(self.stage_effort/2)),1)
design.design.__init__(self, name)
debug.info(1, "Creating {}".format(self.name))
self.add_comment("size: {}".format(size))
self.create_netlist()
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
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.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.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)
def create_insts(self):
@ -191,11 +187,11 @@ class pinvbuf(design.design):
"""Get the stage efforts of the clk -> clk_buf path"""
stage_effort_list = []
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)
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)
return stage_effort_list
@ -205,16 +201,16 @@ class pinvbuf(design.design):
#After (almost) every stage, the direction of the signal inverts.
stage_effort_list = []
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)
last_stage_is_rise = stage_effort_list[-1].is_rise
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)
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)
return stage_effort_list
return stage_effort_list

View File

@ -2,25 +2,21 @@ import contact
import pgate
import debug
from tech import drc, parameter, spice
from ptx import ptx
from vector import vector
from globals import OPTS
import logical_effort
from sram_factory import factory
class pnand2(pgate.pgate):
"""
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.
"""
unique_id = 1
def __init__(self, size=1, height=None):
def __init__(self, name, size=1, height=None):
""" 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)
debug.info(2, "create pnand2 structure {0} with size of {1}".format(name, size))
self.add_comment("size: {}".format(size))
self.size = size
self.nmos_size = 2*size
@ -61,18 +57,20 @@ class pnand2(pgate.pgate):
def add_ptx(self):
""" Create the PMOS and NMOS transistors. """
self.nmos = ptx(width=self.nmos_width,
mults=self.tx_mults,
tx_type="nmos",
connect_poly=True,
connect_active=True)
self.nmos = factory.create(module_type="ptx",
width=self.nmos_width,
mults=self.tx_mults,
tx_type="nmos",
connect_poly=True,
connect_active=True)
self.add_mod(self.nmos)
self.pmos = ptx(width=self.pmos_width,
mults=self.tx_mults,
tx_type="pmos",
connect_poly=True,
connect_active=True)
self.pmos = factory.create(module_type="ptx",
width=self.pmos_width,
mults=self.tx_mults,
tx_type="pmos",
connect_poly=True,
connect_active=True)
self.add_mod(self.pmos)
def setup_layout_constants(self):
@ -255,9 +253,9 @@ class pnand2(pgate.pgate):
"""Return the relative input capacitance of a single input"""
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.
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
"""
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 debug
from tech import drc, parameter, spice
from ptx import ptx
from vector import vector
from globals import OPTS
from sram_factory import factory
class pnand3(pgate.pgate):
"""
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.
"""
unique_id = 1
def __init__(self, size=1, height=None):
def __init__(self, name, size=1, height=None):
""" 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)
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...
# If we relax this, we could size this better.
@ -61,18 +57,20 @@ class pnand3(pgate.pgate):
def add_ptx(self):
""" Create the PMOS and NMOS transistors. """
self.nmos = ptx(width=self.nmos_width,
mults=self.tx_mults,
tx_type="nmos",
connect_poly=True,
connect_active=True)
self.nmos = factory.create(module_type="ptx",
width=self.nmos_width,
mults=self.tx_mults,
tx_type="nmos",
connect_poly=True,
connect_active=True)
self.add_mod(self.nmos)
self.pmos = ptx(width=self.pmos_width,
mults=self.tx_mults,
tx_type="pmos",
connect_poly=True,
connect_active=True)
self.pmos = factory.create(module_type="ptx",
width=self.pmos_width,
mults=self.tx_mults,
tx_type="pmos",
connect_poly=True,
connect_active=True)
self.add_mod(self.pmos)
def setup_layout_constants(self):
@ -93,7 +91,7 @@ class pnand3(pgate.pgate):
self.output_pos = vector(0,0.5*self.height)
# 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)
# 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,
@ -267,9 +265,9 @@ class pnand3(pgate.pgate):
"""Return the relative input capacitance of a single input"""
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.
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
"""
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 debug
from tech import drc, parameter, spice
from ptx import ptx
from vector import vector
from globals import OPTS
import contact
from sram_factory import factory
class pnor2(pgate.pgate):
"""
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.
"""
unique_id = 1
def __init__(self, size=1, height=None):
def __init__(self, name, size=1, height=None):
""" 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)
debug.info(2, "create pnor2 structure {0} with size of {1}".format(name, size))
self.add_comment("size: {}".format(size))
self.nmos_size = size
# 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):
""" Create the PMOS and NMOS transistors. """
self.nmos = ptx(width=self.nmos_width,
mults=self.tx_mults,
tx_type="nmos",
connect_poly=True,
connect_active=True)
self.nmos = factory.create(module_type="ptx",
width=self.nmos_width,
mults=self.tx_mults,
tx_type="nmos",
connect_poly=True,
connect_active=True)
self.add_mod(self.nmos)
self.pmos = ptx(width=self.pmos_width,
mults=self.tx_mults,
tx_type="pmos",
connect_poly=True,
connect_active=True)
self.pmos = factory.create(module_type="ptx",
width=self.pmos_width,
mults=self.tx_mults,
tx_type="pmos",
connect_poly=True,
connect_active=True)
self.add_mod(self.pmos)
def setup_layout_constants(self):
""" 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
self.input_spacing = max(self.poly_space + poly_contact.first_layer_width,
self.m1_space + m1m2_via.first_layer_width,
self.m2_space + m2m3_via.first_layer_width,
self.m3_space + m2m3_via.second_layer_width)
self.input_spacing = max(self.poly_space + contact.poly.first_layer_width,
self.m1_space + contact.m1m2.first_layer_width,
self.m2_space + contact.m2m3.first_layer_width,
self.m3_space + contact.m2m3.second_layer_width)
# Compute the other pmos2 location, but determining offset to overlap the
# source and drain pins

View File

@ -2,28 +2,20 @@ import contact
import pgate
import debug
from tech import drc, parameter
from ptx import ptx
from vector import vector
from globals import OPTS
from sram_factory import factory
class precharge(pgate.pgate):
"""
Creates a single precharge cell
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"):
name = name+"_{}".format(precharge.unique_id)
precharge.unique_id += 1
pgate.pgate.__init__(self, name)
debug.info(2, "create single precharge cell: {0}".format(name))
from importlib import reload
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
self.bitcell = factory.create(module_type="bitcell")
self.beta = parameter["beta"]
self.ptx_width = self.beta*parameter["min_tx_size"]
@ -57,8 +49,9 @@ class precharge(pgate.pgate):
"""
Initializes the upper and lower pmos
"""
self.pmos = ptx(width=self.ptx_width,
tx_type="pmos")
self.pmos = factory.create(module_type="ptx",
width=self.ptx_width,
tx_type="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.
pmos_cin = self.pmos.get_cin()
return 3*pmos_cin

View File

@ -2,9 +2,8 @@ import design
import debug
from tech import drc, spice
from vector import vector
from contact import contact
from globals import OPTS
import path
from sram_factory import factory
class ptx(design.design):
"""
@ -15,7 +14,7 @@ class ptx(design.design):
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
# 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
@ -97,8 +96,9 @@ class ptx(design.design):
# This is not actually instantiated but used for calculations
self.active_contact = contact(layer_stack=("active", "contact", "metal1"),
dimensions=(1, self.num_contacts))
self.active_contact = factory.create(module_type="contact",
layer_stack=("active", "contact", "metal1"),
dimensions=(1, self.num_contacts))
# The contacted poly pitch (or uncontacted in an odd technology)
@ -355,4 +355,4 @@ class ptx(design.design):
def get_cin(self):
"""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 vector import vector
import contact
from ptx import ptx
from globals import OPTS
from sram_factory import factory
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:
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)
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)
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()
def add_modules(self):
# This is just used for measurements,
# 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()
self.bitcell = factory.create(module_type="bitcell")
# Adds nmos_lower,nmos_upper to the module
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)

View File

@ -65,21 +65,21 @@ class sram():
# Write the layout
start_time = datetime.datetime.now()
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)
print_time("GDS", datetime.datetime.now(), start_time)
# Create a LEF physical model
start_time = datetime.datetime.now()
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)
print_time("LEF", datetime.datetime.now(), start_time)
# Save the spice file
start_time = datetime.datetime.now()
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)
print_time("Spice writing", datetime.datetime.now(), start_time)
@ -98,14 +98,14 @@ class sram():
# Characterize the design
start_time = datetime.datetime.now()
from characterizer import lib
print("LIB: Characterizing... ")
debug.print_raw("LIB: Characterizing... ")
if OPTS.analytical_delay:
print("Using analytical delay models (no characterization)")
debug.print_raw("Using analytical delay models (no characterization)")
else:
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:
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)
print_time("Characterization", datetime.datetime.now(), start_time)
@ -114,20 +114,20 @@ class sram():
start_time = datetime.datetime.now()
from shutil import copyfile
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)
# Write the datasheet
start_time = datetime.datetime.now()
from datasheet_gen import datasheet_gen
dname = OPTS.output_path + self.s.name + ".html"
print("Datasheet: Writing to {0}".format(dname))
datasheet_gen.datasheet_write(self.s,dname)
debug.print_raw("Datasheet: Writing to {0}".format(dname))
datasheet_gen.datasheet_write(dname)
print_time("Datasheet", datetime.datetime.now(), start_time)
# Write a verilog model
start_time = datetime.datetime.now()
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)
print_time("Verilog", datetime.datetime.now(), start_time)

View File

@ -10,6 +10,7 @@ import logical_effort
from design import design
from verilog import verilog
from lef import lef
from sram_factory import factory
class sram_base(design, verilog, lef):
"""
@ -239,10 +240,7 @@ class sram_base(design, verilog, lef):
def add_modules(self):
""" Create all the modules that will be used """
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
self.bitcell = factory.create(module_type=OPTS.bitcell)
# Create the address and control flops (but not the clk)
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
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,
word_size=self.word_size,
sram=self,
port_type="rw")
self.add_mod(self.control_logic_rw)
if len(self.writeonly_ports)>0:
self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row,
word_size=self.word_size,
sram=self,
port_type="w")
self.add_mod(self.control_logic_w)
if len(self.readonly_ports)>0:
self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row,
word_size=self.word_size,
sram=self,
port_type="r")
self.add_mod(self.control_logic_r)
@ -514,25 +515,30 @@ class sram_base(design, verilog, lef):
def get_wl_en_cin(self):
"""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
bank_clk_cin = self.bank.get_wl_en_cin()
return bank_clk_cin
return self.bank.get_wl_en_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):
"""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.
#Only the precharge cells use this signal (other than the control logic)
bank_clk_cin = self.bank.get_clk_bar_cin()
return bank_clk_cin
return self.bank.get_clk_bar_cin()
def get_sen_cin(self):
"""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)
bank_sen_cin = self.bank.get_sen_cin()
return bank_sen_cin
return self.bank.get_sen_cin()

View File

@ -2,6 +2,7 @@ import debug
from math import log,sqrt,ceil
from importlib import reload
from globals import OPTS
from sram_factory import factory
class sram_config:
""" This is a structure that is used to hold the SRAM configuration options. """
@ -29,10 +30,7 @@ class sram_config:
def compute_sizes(self):
""" Computes the organization of the memory using bitcell size by trying to make it square."""
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
# pass a copy of myself for the port numbers
self.bitcell = self.mod_bitcell()
self.bitcell = factory.create(module_type="bitcell")
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:
if re.search("gdsMill", code):
continue
if re.search("options.py$", code):
continue
if re.search("debug.py$", code):
continue
if re.search("testutils.py$", code):
continue
if re.search("globals.py$", code):
continue
if re.search("openram.py$", code):
continue
if re.search("sram.py$", code):
if re.search("testutils.py$", code):
continue
if re.search("gen_stimulus.py$", code):
continue

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -19,7 +19,7 @@ class pinv_test(openram_test):
import tech
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)
globals.end_openram()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -10,29 +10,31 @@ sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
from sram_factory import factory
class replica_pbitcell_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import replica_pbitcell
import tech
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
factory.reset()
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)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 1
factory.reset()
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)
globals.end_openram()

View File

@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
from sram_factory import factory
#@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
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)
# 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_r_ports = 1
OPTS.num_w_ports = 1
factory.reset()
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)
factory.reset()
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)
globals.end_openram()

View File

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

View File

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

View File

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

View File

@ -9,6 +9,7 @@ sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
from sram_factory import factory
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
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)
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)
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)
# 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_r_ports = 1
OPTS.num_w_ports = 1
factory.reset()
debug.info(1, "Testing sample for 2-way column_mux_array in multi-port")
a = 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)
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)
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)
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)
globals.end_openram()

View File

@ -10,17 +10,17 @@ sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
from sram_factory import factory
class precharge_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import precharge_array
import tech
# check precharge array in single port
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)
# check precharge array in multi-port
@ -28,17 +28,18 @@ class precharge_test(openram_test):
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
factory.reset()
debug.info(2, "Checking 3 column precharge array for 1RW/1R bitcell")
pc = 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)
# 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)
# 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)
globals.end_openram()

View File

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

View File

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

View File

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

View File

@ -18,7 +18,7 @@ class delay_chain_test(openram_test):
import 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)
globals.end_openram()

View File

@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
from sram_factory import factory
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_r_ports = 1
OPTS.num_w_ports = 0
factory.reset()
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)
# 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_r_ports = 0
factory.reset()
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)
OPTS.num_rw_ports = 1
OPTS.num_w_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))
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)
globals.end_openram()

View File

@ -22,14 +22,14 @@ class replica_bitline_test(openram_test):
fanout=4
rows=13
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)
#debug.error("Exiting...", 1)
stages=8
rows=100
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)

View File

@ -20,7 +20,7 @@ class control_logic_test(openram_test):
# check control logic for single port
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)
# check control logic for multi-port
@ -31,7 +31,7 @@ class control_logic_test(openram_test):
OPTS.num_r_ports = 0
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)
# Check port specific control logic
@ -40,15 +40,15 @@ class control_logic_test(openram_test):
OPTS.num_r_ports = 1
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)
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)
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)
globals.end_openram()

View File

@ -10,15 +10,13 @@ sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
from sram_factory import factory
#@unittest.skip("SKIPPING 19_psingle_bank_test")
class psingle_bank_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
from bank import bank
from sram_config import sram_config
OPTS.bitcell = "pbitcell"
@ -31,6 +29,7 @@ class psingle_bank_test(openram_test):
num_words=16)
c.words_per_row=1
factory.reset()
c.recompute_sizes()
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)
@ -39,6 +38,7 @@ class psingle_bank_test(openram_test):
c.num_words=32
c.words_per_row=2
factory.reset()
c.recompute_sizes()
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)
@ -47,6 +47,7 @@ class psingle_bank_test(openram_test):
c.num_words=64
c.words_per_row=4
factory.reset()
c.recompute_sizes()
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)
@ -56,6 +57,7 @@ class psingle_bank_test(openram_test):
c.word_size=2
c.num_words=128
c.words_per_row=8
factory.reset()
c.recompute_sizes()
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)

View File

@ -53,27 +53,27 @@ class timing_sram_test(openram_test):
data.update(port_data[0])
if OPTS.tech_name == "freepdk45":
golden_data = {'delay_hl': [0.2011],
'delay_lh': [0.2011],
'leakage_power': 0.002,
'min_period': 0.41,
'read0_power': [0.63604],
'read1_power': [0.6120599999999999],
'slew_hl': [0.10853],
'slew_lh': [0.10853],
'write0_power': [0.51742],
'write1_power': [0.51095]}
golden_data = {'delay_hl': [0.2152017],
'delay_lh': [0.2152017],
'leakage_power': 0.0022907,
'min_period': 0.488,
'read0_power': [0.47437749999999995],
'read1_power': [0.45026109999999997],
'slew_hl': [0.0846786],
'slew_lh': [0.0846786],
'write0_power': [0.40809259999999997],
'write1_power': [0.4078904]}
elif OPTS.tech_name == "scn4m_subm":
golden_data = {'delay_hl': [1.3911],
'delay_lh': [1.3911],
'leakage_power': 0.0278488,
'min_period': 2.812,
'read0_power': [22.1183],
'read1_power': [21.4388],
'slew_hl': [0.7397553],
'slew_lh': [0.7397553],
'write0_power': [19.4103],
'write1_power': [20.1167]}
golden_data = {'delay_hl': [1.4333000000000002],
'delay_lh': [1.4333000000000002],
'leakage_power': 0.0271847,
'min_period': 2.891,
'read0_power': [15.714200000000002],
'read1_power': [14.9848],
'slew_hl': [0.6819276999999999],
'slew_lh': [0.6819276999999999],
'write0_power': [13.9658],
'write1_power': [14.8422]}
else:
self.assertTrue(False) # other techs fail
# 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])
if OPTS.tech_name == "freepdk45":
golden_data = {'delay_hl': [0.20443139999999999],
'delay_lh': [0.20443139999999999],
'leakage_power': 0.0017840640000000001,
'min_period': 0.41,
'read0_power': [0.6435831],
'read1_power': [0.6233463],
'slew_hl': [0.1138734],
'slew_lh': [0.1138734],
'write0_power': [0.5205761],
'write1_power': [0.5213689]}
golden_data = {'delay_hl': [0.221699],
'delay_lh': [0.221699],
'leakage_power': 0.001467648,
'min_period': 0.605,
'read0_power': [0.3879335],
'read1_power': [0.3662724],
'slew_hl': [0.08562444999999999],
'slew_lh': [0.08562444999999999],
'write0_power': [0.3362456],
'write1_power': [0.3372035]}
elif OPTS.tech_name == "scn4m_subm":
golden_data = {'delay_hl': [1.610911],
'delay_lh': [1.610911],
'leakage_power': 0.0023593859999999998,
'min_period': 3.281,
'read0_power': [20.763569999999998],
'read1_power': [20.32745],
'slew_hl': [0.7986348999999999],
'slew_lh': [0.7986348999999999],
'write0_power': [17.58272],
'write1_power': [18.523419999999998]}
golden_data = {'delay_hl': [1.7951730000000001],
'delay_lh': [1.7951730000000001],
'leakage_power': 0.001669513,
'min_period': 3.594,
'read0_power': [17.03022],
'read1_power': [16.55897],
'slew_hl': [0.7079951],
'slew_lh': [0.7079951],
'write0_power': [15.16726],
'write1_power': [16.13527]}
else:
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
#'lvsAbortOnSupplyError' : 0
# This should be removed for final verification
if not final_verification:
lvs_runset['cmnVConnectReport']=1
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