mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev'
This commit is contained in:
commit
9d318aadd7
44
LICENSE
44
LICENSE
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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('<','<').replace('"','"').replace('>',">")
|
||||
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('<','<').replace('"','"').replace('>',">")
|
||||
self.html += self.dlv_table.to_html()
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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.")
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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.")
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
14
lib/Makefile
14
lib/Makefile
|
|
@ -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)
|
||||
|
|
@ -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
Loading…
Reference in New Issue