Merge branch 'master' of https://github.com/mguthaus/OpenRAM into multiport

This commit is contained in:
Michael Timothy Grimes 2018-01-28 21:44:22 -08:00
commit fb2572bd71
32 changed files with 11687 additions and 22895 deletions

View File

@ -10,9 +10,7 @@ debug.info(2,"Initializing characterizer...")
spice_exe = "" spice_exe = ""
if OPTS.analytical_delay: if not OPTS.analytical_delay:
debug.info(1,"Using analytical delay models (no characterization)")
else:
if OPTS.spice_name != "": if OPTS.spice_name != "":
spice_exe=find_exe(OPTS.spice_name) spice_exe=find_exe(OPTS.spice_name)
if spice_exe=="": if spice_exe=="":

View File

@ -181,8 +181,8 @@ class control_logic(design.design):
pin=self.clk_inv1.get_pin("A") pin=self.clk_inv1.get_pin("A")
self.add_layout_pin(text="clk", self.add_layout_pin(text="clk",
layer="metal1", layer="metal1",
offset=pin.ll(), offset=pin.ll().scale(0,1),
width=pin.width(), width=pin.rx(),
height=pin.height()) height=pin.height())
pin=self.clk_inv1.get_pin("gnd") pin=self.clk_inv1.get_pin("gnd")

View File

@ -1,5 +1,5 @@
word_size = 2 word_size = 2
num_words = 16 num_words = 128
num_banks = 1 num_banks = 1
tech_name = "freepdk45" tech_name = "freepdk45"

View File

@ -3,7 +3,9 @@ This provides a set of useful generic types for the gdsMill interface.
""" """
import debug import debug
from vector import vector from vector import vector
from tech import GDS import tech
import math
from globals import OPTS
class geometry: class geometry:
""" """
@ -23,40 +25,24 @@ class geometry:
""" override print function output """ """ override print function output """
debug.error("__repr__ must be overridden by all geometry types.",1) debug.error("__repr__ must be overridden by all geometry types.",1)
# def translate_coords(self, coords, mirr, angle, xyShift):
# """Calculate coordinates after flip, rotate, and shift"""
# coordinate = []
# for item in coords:
# x = (item[0]*math.cos(angle)-item[1]*mirr*math.sin(angle)+xyShift[0])
# y = (item[0]*math.sin(angle)+item[1]*mirr*math.cos(angle)+xyShift[1])
# coordinate += [(x, y)]
# return coordinate
class instance(geometry): def transform_coords(self, coords, offset, mirr, angle):
""" """Calculate coordinates after flip, rotate, and shift"""
An instance of an instance/module with a specified location and coordinate = []
rotation for item in coords:
""" x = item[0]*math.cos(angle) - item[1]*mirr*math.sin(angle) + offset[0]
def __init__(self, name, mod, offset, mirror, rotate): y = item[0]*math.sin(angle) + item[1]*mirr*math.cos(angle) + offset[1]
"""Initializes an instance to represent a module""" coordinate += [[x, y]]
geometry.__init__(self) return coordinate
debug.check(mirror not in ["R90","R180","R270"], "Please use rotation and not mirroring during instantiation.")
self.name = name
self.mod = mod
self.gds = mod.gds
self.rotate = rotate
self.offset = vector(offset).snap_to_grid()
self.mirror = mirror
self.compute_boundary(offset,mirror,rotate)
debug.info(4, "creating instance: " + self.name)
def gds_write_file(self, newLayout):
"""Recursively writes all the sub-modules in this instance"""
debug.info(4, "writing instance: " + self.name)
# make sure to write out my module/structure
# (it will only be written the first time though)
self.mod.gds_write_file(self.gds)
# now write an instance of my module/structure
newLayout.addInstance(self.gds,
offsetInMicrons=self.offset,
mirror=self.mirror,
rotate=self.rotate)
def normalize(self): def normalize(self):
""" Re-find the LL and UR points after a transform """ """ Re-find the LL and UR points after a transform """
(first,second)=self.boundary (first,second)=self.boundary
@ -67,7 +53,7 @@ class instance(geometry):
def compute_boundary(self,offset=vector(0,0),mirror="",rotate=0): def compute_boundary(self,offset=vector(0,0),mirror="",rotate=0):
""" Transform with offset, mirror and rotation to get the absolute pin location. """ Transform with offset, mirror and rotation to get the absolute pin location.
We must then re-find the ll and ur. The master is the cell instance. """ We must then re-find the ll and ur. The master is the cell instance. """
(ll,ur) = [vector(0,0),vector(self.mod.width,self.mod.height)] (ll,ur) = [vector(0,0),vector(self.width,self.height)]
if mirror=="MX": if mirror=="MX":
ll=ll.scale(1,-1) ll=ll.scale(1,-1)
ur=ur.scale(1,-1) ur=ur.scale(1,-1)
@ -123,6 +109,78 @@ class instance(geometry):
def rx(self): def rx(self):
""" Return the right edge """ """ Return the right edge """
return self.boundary[1].x return self.boundary[1].x
class instance(geometry):
"""
An instance of an instance/module with a specified location and
rotation
"""
def __init__(self, name, mod, offset, mirror, rotate):
"""Initializes an instance to represent a module"""
geometry.__init__(self)
debug.check(mirror not in ["R90","R180","R270"], "Please use rotation and not mirroring during instantiation.")
self.name = name
self.mod = mod
self.gds = mod.gds
self.rotate = rotate
self.offset = vector(offset).snap_to_grid()
self.mirror = mirror
self.width = mod.width
self.height = mod.height
self.compute_boundary(offset,mirror,rotate)
debug.info(4, "creating instance: " + self.name)
def get_blockages(self, layer, top=False):
""" Retrieve rectangular blockages of all modules in this instance.
Apply the transform of the instance placement to give absolute blockages."""
angle = math.radians(float(self.rotate))
mirr = 1
if self.mirror=="R90":
angle += math.radians(90.0)
elif self.mirror=="R180":
angle += math.radians(180.0)
elif self.mirror=="R270":
angle += math.radians(270.0)
elif self.mirror=="MX":
mirr = -1
elif self.mirror=="MY":
mirr = -1
angle += math.radians(180.0)
elif self.mirror=="XY":
mirr = 1
angle += math.radians(180.0)
if self.mod.is_library_cell:
# For lib cells, block the whole thing except on metal3
# since they shouldn't use metal3
if layer==tech.layer["metal1"] or layer==tech.layer["metal2"]:
return [self.transform_coords(self.mod.get_boundary(), self.offset, mirr, angle)]
else:
return []
else:
blockages = self.mod.get_blockages(layer)
new_blockages = []
for b in blockages:
new_blockages.append(self.transform_coords(b,self.offset, mirr, angle))
return new_blockages
def gds_write_file(self, new_layout):
"""Recursively writes all the sub-modules in this instance"""
debug.info(4, "writing instance: " + self.name)
# make sure to write out my module/structure
# (it will only be written the first time though)
self.mod.gds_write_file(self.gds)
# now write an instance of my module/structure
new_layout.addInstance(self.gds,
offsetInMicrons=self.offset,
mirror=self.mirror,
rotate=self.rotate)
def get_pin(self,name,index=-1): def get_pin(self,name,index=-1):
""" Return an absolute pin that is offset and transformed based on """ Return an absolute pin that is offset and transformed based on
@ -187,6 +245,10 @@ class path(geometry):
coordinates=self.coordinates, coordinates=self.coordinates,
width=self.path_width) width=self.path_width)
def get_blockages(self, layer):
""" Fail since we don't support paths yet. """
assert(0)
def __str__(self): def __str__(self):
""" override print function output """ """ override print function output """
return "path: layer=" + self.layerNumber + " w=" + self.width return "path: layer=" + self.layerNumber + " w=" + self.width
@ -206,12 +268,12 @@ class label(geometry):
self.text = text self.text = text
self.layerNumber = layerNumber self.layerNumber = layerNumber
self.offset = vector(offset).snap_to_grid() self.offset = vector(offset).snap_to_grid()
if zoom<0: if zoom<0:
self.zoom = GDS["zoom"] self.zoom = tech.GDS["zoom"]
else: else:
self.zoom = zoom self.zoom = zoom
self.size = 0 self.size = 0
debug.info(4,"creating label " + self.text + " " + str(self.layerNumber) + " " + str(self.offset)) debug.info(4,"creating label " + self.text + " " + str(self.layerNumber) + " " + str(self.offset))
@ -226,6 +288,10 @@ class label(geometry):
magnification=self.zoom, magnification=self.zoom,
rotate=None) rotate=None)
def get_blockages(self, layer):
""" Returns an empty list since text cannot be blockages. """
return []
def __str__(self): def __str__(self):
""" override print function output """ """ override print function output """
return "label: " + self.text + " layer=" + str(self.layerNumber) return "label: " + self.text + " layer=" + str(self.layerNumber)
@ -246,10 +312,18 @@ class rectangle(geometry):
self.size = vector(width, height).snap_to_grid() self.size = vector(width, height).snap_to_grid()
self.width = self.size.x self.width = self.size.x
self.height = self.size.y self.height = self.size.y
self.compute_boundary(offset,"",0)
debug.info(4, "creating rectangle (" + str(self.layerNumber) + "): " debug.info(4, "creating rectangle (" + str(self.layerNumber) + "): "
+ str(self.width) + "x" + str(self.height) + " @ " + str(self.offset)) + str(self.width) + "x" + str(self.height) + " @ " + str(self.offset))
def get_blockages(self, layer):
""" Returns a list of one rectangle if it is on this layer"""
if self.layerNumber == layer:
return [[self.offset, vector(self.offset.x+self.width,self.offset.y+self.height)]]
else:
return []
def gds_write_file(self, newLayout): def gds_write_file(self, newLayout):
"""Writes the rectangular shape to GDS""" """Writes the rectangular shape to GDS"""

View File

@ -43,10 +43,6 @@ class hierarchical_decoder(design.design):
self.create_row_decoder() self.create_row_decoder()
self.create_vertical_rail() self.create_vertical_rail()
self.route_vdd_gnd() self.route_vdd_gnd()
# We only need to call the offset_all_coordinate function when there
# are vertical metal rails.
#if (self.num_inputs >= 4):
# self.offset_all_coordinates()
def add_modules(self): def add_modules(self):
self.inv = pinv() self.inv = pinv()

View File

@ -7,8 +7,9 @@ from tech import layer as techlayer
import os import os
from vector import vector from vector import vector
from pin_layout import pin_layout from pin_layout import pin_layout
import lef
class layout: class layout(lef.lef):
""" """
Class consisting of a set of objs and instances for a module Class consisting of a set of objs and instances for a module
This provides a set of useful generic types for hierarchy This provides a set of useful generic types for hierarchy
@ -18,7 +19,8 @@ class layout:
layout/netlist and perform LVS/DRC. layout/netlist and perform LVS/DRC.
""" """
def __init__(self, name): def __init__(self, name):
lef.lef.__init__(self, ["metal1", "metal2", "metal3"])
self.name = name self.name = name
self.width = None self.width = None
self.height = None self.height = None
@ -26,7 +28,7 @@ class layout:
self.objs = [] # Holds all other objects (labels, geometries, etc) self.objs = [] # Holds all other objects (labels, geometries, etc)
self.pin_map = {} # Holds name->pin_layout map for all pins self.pin_map = {} # Holds name->pin_layout map for all pins
self.visited = False # Flag for traversing the hierarchy self.visited = False # Flag for traversing the hierarchy
self.is_library_cell = False # Flag for library cells
self.gds_read() self.gds_read()
############################################################ ############################################################
@ -36,7 +38,6 @@ class layout:
""" This function is called after everything is placed to """ This function is called after everything is placed to
shift the origin in the lowest left corner """ shift the origin in the lowest left corner """
offset = self.find_lowest_coords() offset = self.find_lowest_coords()
#self.offset_attributes(offset)
self.translate_all(offset) self.translate_all(offset)
def get_gate_offset(self, x_offset, height, inv_num): def get_gate_offset(self, x_offset, height, inv_num):
@ -59,19 +60,22 @@ class layout:
def find_lowest_coords(self): def find_lowest_coords(self):
"""Finds the lowest set of 2d cartesian coordinates within """Finds the lowest set of 2d cartesian coordinates within
this layout""" this layout"""
# FIXME: don't depend on 1e9
try: lowestx1 = min(obj.lx() for obj in self.objs if obj.name!="label")
lowestx1 = min(rect.offset.x for rect in self.objs) lowesty1 = min(obj.by() for obj in self.objs if obj.name!="label")
lowesty1 = min(rect.offset.y for rect in self.objs) lowestx2 = min(inst.lx() for inst in self.insts)
except: lowesty2 = min(inst.by() for inst in self.insts)
[lowestx1, lowesty1] = [1000000.0, 1000000.0]
try:
lowestx2 = min(inst.offset.x for inst in self.insts)
lowesty2 = min(inst.offset.y for inst in self.insts)
except:
[lowestx2, lowesty2] = [1000000.0, 1000000.0]
return vector(min(lowestx1, lowestx2), min(lowesty1, lowesty2)) return vector(min(lowestx1, lowestx2), min(lowesty1, lowesty2))
def find_highest_coords(self):
"""Finds the highest set of 2d cartesian coordinates within
this layout"""
highestx1 = min(obj.rx() for obj in self.objs if obj.name!="label")
highesty1 = min(obj.uy() for obj in self.objs if obj.name!="label")
highestx2 = min(inst.rx() for inst in self.insts)
highesty2 = min(inst.uy() for inst in self.insts)
return vector(min(highestx1, highestx2), min(highesty1, highesty2))
def translate_all(self, offset): def translate_all(self, offset):
""" """
@ -111,9 +115,9 @@ class layout:
if height==0: if height==0:
height=drc["minwidth_{}".format(layer)] height=drc["minwidth_{}".format(layer)]
# negative layers indicate "unused" layers in a given technology # negative layers indicate "unused" layers in a given technology
layerNumber = techlayer[layer] layer_num = techlayer[layer]
if layerNumber >= 0: if layer_num >= 0:
self.objs.append(geometry.rectangle(layerNumber, offset, width, height)) self.objs.append(geometry.rectangle(layer_num, offset, width, height))
return self.objs[-1] return self.objs[-1]
return None return None
@ -124,10 +128,10 @@ class layout:
if height==0: if height==0:
height=drc["minwidth_{}".format(layer)] height=drc["minwidth_{}".format(layer)]
# negative layers indicate "unused" layers in a given technology # negative layers indicate "unused" layers in a given technology
layerNumber = techlayer[layer] layer_num = techlayer[layer]
corrected_offset = offset - vector(0.5*width,0.5*height) corrected_offset = offset - vector(0.5*width,0.5*height)
if layerNumber >= 0: if layer_num >= 0:
self.objs.append(geometry.rectangle(layerNumber, corrected_offset, width, height)) self.objs.append(geometry.rectangle(layer_num, corrected_offset, width, height))
return self.objs[-1] return self.objs[-1]
return None return None
@ -259,9 +263,9 @@ class layout:
"""Adds a text label on the given layer,offset, and zoom level""" """Adds a text label on the given layer,offset, and zoom level"""
# negative layers indicate "unused" layers in a given technology # negative layers indicate "unused" layers in a given technology
debug.info(5,"add label " + str(text) + " " + layer + " " + str(offset)) debug.info(5,"add label " + str(text) + " " + layer + " " + str(offset))
layerNumber = techlayer[layer] layer_num = techlayer[layer]
if layerNumber >= 0: if layer_num >= 0:
self.objs.append(geometry.label(text, layerNumber, offset, zoom)) self.objs.append(geometry.label(text, layer_num, offset, zoom))
return self.objs[-1] return self.objs[-1]
return None return None
@ -272,9 +276,9 @@ class layout:
import path import path
# NOTE: (UNTESTED) add_path(...) is currently not used # NOTE: (UNTESTED) add_path(...) is currently not used
# negative layers indicate "unused" layers in a given technology # negative layers indicate "unused" layers in a given technology
#layerNumber = techlayer[layer] #layer_num = techlayer[layer]
#if layerNumber >= 0: #if layer_num >= 0:
# self.objs.append(geometry.path(layerNumber, coordinates, width)) # self.objs.append(geometry.path(layer_num, coordinates, width))
path.path(obj=self, path.path(obj=self,
layer=layer, layer=layer,
@ -390,6 +394,7 @@ class layout:
# open the gds file if it exists or else create a blank layout # open the gds file if it exists or else create a blank layout
if os.path.isfile(self.gds_file): if os.path.isfile(self.gds_file):
debug.info(3, "opening %s" % self.gds_file) debug.info(3, "opening %s" % self.gds_file)
self.is_library_cell=True
self.gds = gdsMill.VlsiLayout(units=GDS["unit"]) self.gds = gdsMill.VlsiLayout(units=GDS["unit"])
reader = gdsMill.Gds2reader(self.gds) reader = gdsMill.Gds2reader(self.gds)
reader.loadFromFile(self.gds_file) reader.loadFromFile(self.gds_file)
@ -440,6 +445,49 @@ class layout:
# self.gds.prepareForWrite() # self.gds.prepareForWrite()
writer.writeToFile(gds_name) writer.writeToFile(gds_name)
def get_boundary(self):
""" Return the lower-left and upper-right coordinates of boundary """
# This assumes nothing spans outside of the width and height!
return [vector(0,0), vector(self.width, self.height)]
#return [self.find_lowest_coords(), self.find_highest_coords()]
def get_blockages(self, layer, top_level=False):
"""
Write all of the obstacles in the current (and children) modules to the lef file
Do not write the pins since they aren't obstructions.
"""
if type(layer)==str:
layer_num = techlayer[layer]
else:
layer_num = layer
blockages = []
for i in self.objs:
blockages += i.get_blockages(layer_num)
for i in self.insts:
blockages += i.get_blockages(layer_num)
# Must add pin blockages to non-top cells
if not top_level:
blockages += self.get_pin_blockages(layer_num)
return blockages
def get_pin_blockages(self, layer_num):
""" Return the pin shapes as blockages for non-top-level blocks. """
# FIXME: We don't have a body contact in ptx, so just ignore it for now
import copy
pin_names = copy.deepcopy(self.pins)
if self.name.startswith("pmos") or self.name.startswith("nmos"):
pin_names.remove("B")
blockages = []
for pin_name in pin_names:
pin_list = self.get_pins(pin_name)
for pin in pin_list:
if pin.layer_num==layer_num:
blockages += [pin.rect]
return blockages
def pdf_write(self, pdf_name): def pdf_write(self, pdf_name):
# NOTE: Currently does not work (Needs further research) # NOTE: Currently does not work (Needs further research)
#self.pdf_name = self.name + ".pdf" #self.pdf_name = self.name + ".pdf"
@ -465,20 +513,22 @@ class layout:
debug.info(0, debug.info(0,
"|==============================================================================|") "|==============================================================================|")
debug.info(0, debug.info(0,
"|========= LIST OF OBJECTS (Rects) FOR: " + self.attr["name"]) "|========= LIST OF OBJECTS (Rects) FOR: " + self.name)
debug.info(0, debug.info(0,
"|==============================================================================|") "|==============================================================================|")
for obj in self.objs: for obj in self.objs:
debug.info(0, "layer={0} : offset={1} : size={2}".format( debug.info(0, "layer={0} : offset={1} : size={2}".format(obj.layerNumber,
obj.layerNumber, obj.offset, obj.size)) obj.offset,
obj.size))
debug.info(0, debug.info(0,
"|==============================================================================|") "|==============================================================================|")
debug.info(0, debug.info(0,
"|========= LIST OF INSTANCES FOR: " + "|========= LIST OF INSTANCES FOR: " + self.name)
self.attr["name"])
debug.info(0, debug.info(0,
"|==============================================================================|") "|==============================================================================|")
for inst in self.insts: for inst in self.insts:
debug.info(0, "name={0} : mod={1} : offset={2}".format( debug.info(0, "name={0} : mod={1} : offset={2}".format(inst.name,
inst.name, inst.mod.name, inst.offset)) inst.mod.name,
inst.offset))

View File

@ -2,9 +2,9 @@ import debug
import re import re
import os import os
import math import math
import verilog
class spice(verilog.verilog):
class spice:
""" """
This provides a set of useful generic types for hierarchy This provides a set of useful generic types for hierarchy
management. If a module is a custom designed cell, it will read from management. If a module is a custom designed cell, it will read from
@ -19,7 +19,7 @@ class spice:
self.mods = [] # Holds subckts/mods for this module self.mods = [] # Holds subckts/mods for this module
self.pins = [] # Holds the pins 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
# for each instance, this is the set of nets/nodes that map to the pins for this instance # for each instance, this is the set of nets/nodes that map to the pins for this instance
# THIS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the # THIS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the
# Spice format) # Spice format)
@ -31,13 +31,35 @@ class spice:
# Spice circuit # Spice circuit
############################################################ ############################################################
def add_pin(self, name): def add_pin(self, name, pin_type="INOUT"):
"""Adds a pin to the pins list""" """ Adds a pin to the pins list. Default type is INOUT signal. """
self.pins.append(name) self.pins.append(name)
self.pin_type[name]=pin_type
def add_pin_list(self, pin_list): def add_pin_list(self, pin_list, pin_type_list="INOUT"):
"""Adds a pin_list to the pins list""" """ Adds a pin_list to the pins list """
self.pins = self.pins + pin_list # The type list can be a single type for all pins
# or a list that is the same length as the pin list.
if type(pin_type_list)==str:
for pin in pin_list:
self.add_pin(pin,pin_type_list)
elif len(pin_type_list)==len(pin_list):
for (pin,ptype) in zip(pin_list, pin_type_list):
self.add_pin(pin,ptype)
else:
debug.error("Mismatch in type and pin list lengths.", -1)
def get_pin_type(self, name):
""" Returns the type of the signal pin. """
return self.pin_type[name]
def get_pin_dir(self, name):
""" Returns the direction of the pin. (Supply/ground are INOUT). """
if self.pin_type[name] in ["POWER","GROUND"]:
return "INOUT"
else:
return self.pin_type[name]
def add_mod(self, mod): def add_mod(self, mod):
"""Adds a subckt/submodule to the subckt hierarchy""" """Adds a subckt/submodule to the subckt hierarchy"""

View File

@ -3,6 +3,7 @@ import tech
import globals import globals
import math import math
import debug import debug
import datetime
from collections import defaultdict from collections import defaultdict
class lef: class lef:
@ -10,246 +11,105 @@ class lef:
SRAM LEF Class open GDS file, read pins information, obstruction SRAM LEF Class open GDS file, read pins information, obstruction
and write them to LEF file and write them to LEF file
""" """
def __init__(self, gdsName, lefName, sr): def __init__(self,layers):
self.gdsName = gdsName # LEF db units per micron
self.lef = open(lefName,"w") self.lef_units = 1000
self.sr = sr # These are the layers of the obstructions
self.myLayout = gdsMill.VlsiLayout(units=tech.GDS["unit"]) self.lef_layers = layers
self.reader = gdsMill.Gds2reader(self.myLayout)
self.reader.loadFromFile(gdsName)
self.unit = float(self.myLayout.info['units'][0])
self.layer = ["metal1", "via1", "metal2", "via2", "metal3"]
self.create()
def lef_write(self, lef_name):
"""Write the entire lef of the object to the file."""
debug.info(3, "Writing to {0}".format(lef_name))
self.indent = "" # To maintain the indent level easily
self.lef = open(lef_name,"w")
self.lef_write_header()
for pin in self.pins:
self.lef_write_pin(pin)
self.lef_write_obstructions()
self.lef_write_footer()
self.lef.close() self.lef.close()
def create(self):
"""Write to LEF file"""
power_pin_name = self.powerPinName()
ground_pin_name = self.groundPinName()
input_pin_name = self.inputPinName()
inout_pin_name = self.inoutPinName()
self.writeLefHeader() def lef_write_header(self):
""" Header of LEF file """
self.lef.write("VERSION 5.4 ;\n")
self.lef.write("NAMESCASESENSITIVE ON ;\n")
self.lef.write("BUSBITCHARS \"[]\" ;\n")
self.lef.write("DIVIDERCHAR \"/\" ;\n")
self.lef.write("UNITS\n")
self.lef.write(" DATABASE MICRONS {0} ;\n".format(self.lef_units))
self.lef.write("END UNITS\n")
self.lef.write("SITE MacroSite\n")
self.indent += " "
self.lef.write("{0}CLASS Core ;\n".format(self.indent))
self.lef.write("{0}SIZE {1} by {2} ;\n".format(self.indent,
self.lef_units*self.width,
self.lef_units*self.height))
self.indent = self.indent[:-3]
self.lef.write("END MacroSite\n")
for pin in power_pin_name: self.lef.write("{0}MACRO {1}\n".format(self.indent,self.name))
self.writePin(pin, 1) self.indent += " "
self.lef.write("{0}CLASS BLOCK ;\n".format(self.indent))
self.lef.write("{0}SIZE {1} BY {2} ;\n" .format(self.indent,
self.lef_units*self.width,
self.lef_units*self.height))
self.lef.write("{0}SYMMETRY X Y R90 ;\n".format(self.indent))
self.lef.write("{0}SITE MacroSite ;\n".format(self.indent))
for pin in ground_pin_name:
self.writePin(pin, 2) def lef_write_footer(self):
self.lef.write("{0}END {1}\n".format(self.indent,self.name))
for pin in inout_pin_name: self.indent = self.indent[:-3]
self.writePin(pin, 3)
for pin in input_pin_name:
self.writePin(pin,4)
self.lef.write(" OBS\n")
for lay in self.layer:
self.lef.write(" LAYER {0} ;\n".format(lay))
self.writeObstruct(self.sr.name, lay, mirr = 1, angle = math.radians(float(0)), xyShift = (0, 0))
self.lef.write(" END\n")
self.writeLefFooter()
def coordinatesTranslate(self, coord, mirr, angle, xyShift):
"""Calculate coordinates after flip, rotate, and shift"""
coordinate = []
for item in coord:
x = (item[0]*math.cos(angle)-item[1]*mirr*math.sin(angle)+xyShift[0])
y = (item[0]*math.sin(angle)+item[1]*mirr*math.cos(angle)+xyShift[1])
coordinate += [(x, y)]
return coordinate
def writeObstruct(self, sr, lay, mirr = 1, angle = math.radians(float(0)), xyShift = (0, 0)):
"""Recursive write boundaries on each Structure in GDS file to LEF"""
for boundary in self.myLayout.structures[sr].boundaries:
coordTrans = self.coordinatesTranslate(boundary.coordinates, mirr, angle, xyShift)
rect = self.minMaxCoord(coordTrans)
lay_convert = tech.layer[lay]
if boundary.drawingLayer == lay_convert:
self.lef.write(" RECT ")
for item in rect:
self.lef.write(" {0} {1}".format(item[0]*self.unit, item[1]*self.unit))
self.lef.write(" ;\n")
for sref in self.myLayout.structures[sr].srefs:
sMirr = 1
if sref.transFlags[0] == True:
sMirr = -1
sAngle = math.radians(float(0))
if sref.rotateAngle:
sAngle = math.radians(float(sref.rotateAngle))
sAngle += angle
x = sref.coordinates[0]
y = sref.coordinates[1]
newX = (x)*math.cos(angle) - mirr*(y)*math.sin(angle) + xyShift[0]
newY = (x)*math.sin(angle) + mirr*(y)*math.cos(angle) + xyShift[1]
sxyShift = (newX, newY)
self.writeObstruct(sref.sName, lay,sMirr, sAngle, sxyShift)
def writePinCoord(self, sr, pinName, pinLayer, pinCoord, mirr = 1,
angle = math.radians(float(0)), xyShift = (0, 0)):
"""Write PIN information to LEF"""
for boundary in self.myLayout.structures[sr].boundaries:
if (pinLayer == boundary.drawingLayer):
coordTrans = self.coordinatesTranslate(boundary.coordinates, mirr, angle, xyShift)
rect = self.minMaxCoord(coordTrans)
if self.pointInsideRect(pinCoord, rect):
self.lef.write(" RECT ")
for item in rect:
self.lef.write(" {0} {1}".format(item[0]*self.unit, item[1]*self.unit))
self.lef.write(" ;\n")
for sref in self.myLayout.structures[sr].srefs:
sMirr = 1
if sref.transFlags[0] == True:
sMirr = -1
sAngle = math.radians(float(0))
if sref.rotateAngle:
sAngle = math.radians(float(sref.rotateAngle))
sAngle += angle
x = sref.coordinates[0]
y = sref.coordinates[1]
newX = (x*math.cos(angle) - mirr*y*math.sin(angle)) + xyShift[0]
newY = (x*math.sin(angle) + mirr*y*math.cos(angle)) + xyShift[1]
sxyShift = (newX, newY)
self.writePinCoord(sref.sName, pinName, pinLayer, pinCoord, sMirr, sAngle, sxyShift)
def pinLayerCoord(self, sr, pinName):
"""Get Pin Layer and Coordinates {layer:[coord1, coord2, ...]}"""
layCoord = defaultdict(list)
for text in self.myLayout.structures[self.sr.name].texts:
if text.textString.strip('\x00') == pinName:
k = text.drawingLayer
v = text.coordinates
d = {k: v}
layCoord.setdefault(k, []).append(v)
return layCoord
def minMaxCoord(self, coordTrans):
"""Find the lowest and highest conner of a Rectangle"""
coordinate = []
minx = min(coordTrans[0][0], coordTrans[1][0], coordTrans[2][0], coordTrans[3][0])
maxx = max(coordTrans[0][0], coordTrans[1][0], coordTrans[2][0], coordTrans[3][0])
miny = min(coordTrans[0][1], coordTrans[1][1], coordTrans[2][1], coordTrans[3][1])
maxy = max(coordTrans[0][1], coordTrans[1][1], coordTrans[2][1], coordTrans[3][1])
coordinate += [(minx, miny)]
coordinate += [(maxx, maxy)]
return coordinate
def pointInsideRect(self, p, rect):
"""Check if a point is inside a rectangle"""
inside = False
if ((p[0][0] >= rect[0][0])& (p[0][0] <= rect[1][0])
& (p[0][1] >= rect[0][1]) &(p[0][1] <= rect[1][1])):
inside = not inside
return inside
def writeLefHeader(self):
"""Heafer of LEF file"""
coord = self.lowestLeftCorner(self.sr.name, 1, 0.0, (0, 0), [], [], [], [])
self.lef.write("MACRO {0}\n".format(self.sr.name))
self.lef.write(" CLASS RING ;\n")
self.lef.write(" ORIGIN {0} {1} ;\n".format(-coord[0][0]*self.unit, coord[0][1]*self.unit))
self.lef.write(" FOREIGN sram {0} {1} ;\n"
.format(0.0, 0.0))
self.lef.write(" SIZE {0} BY {1} ;\n"
.format(self.sr.width, self.sr.height))
self.lef.write(" SYMMETRY X Y R90 ;\n")
def writeLefFooter(self):
self.lef.write("END {0}\n".format(self.sr.name))
self.lef.write("END LIBRARY\n") self.lef.write("END LIBRARY\n")
def powerPinName(self):
return ["vdd"]
def groundPinName(self):
return ["gnd"]
def inputPinName(self): def lef_write_pin(self, name):
input_pin_name = [] pin_dir = self.get_pin_dir(name)
for i in range(self.sr.addr_size + int(math.log(self.sr.num_banks, 2))): pin_type = self.get_pin_type(name)
input_pin_name.append("ADDR[{0}]".format(i)) self.lef.write("{0}PIN {1}\n".format(self.indent,name))
input_pin_name.append("CSb") self.indent += " "
input_pin_name.append("OEb")
input_pin_name.append("WEb")
input_pin_name.append("clk")
return input_pin_name
def inoutPinName(self): self.lef.write("{0}DIRECTION {1} ;\n".format(self.indent,pin_dir))
inout_pin_name = []
for i in range(self.sr.word_size): if pin_type in ["POWER","GROUND"]:
inout_pin_name.append("DATA[{0}]".format(i)) self.lef.write("{0}USE {1} ; \n".format(self.indent,pin_type))
self.lef.write("{0}SHAPE ABUTMENT ; \n".format(self.indent))
return inout_pin_name self.lef.write("{0}PORT\n".format(self.indent))
self.indent += " "
def writePin(self, pinName, typ):
self.lef.write(" PIN {0}\n".format(pinName))
if typ == 1:
self.lef.write(" DIRECTION INOUT ;\n")
self.lef.write(" USE POWER ;\n")
self.lef.write(" SHAPE ABUTMENT ;\n")
self.lef.write(" PORT\n")
elif typ == 2:
self.lef.write(" DIRECTION INOUT ;\n")
self.lef.write(" USE GROUND ;\n")
self.lef.write(" SHAPE ABUTMENT ;\n")
self.lef.write(" PORT\n")
elif typ == 3:
self.lef.write(" DIRECTION INOUT ;\n")
self.lef.write(" PORT\n")
elif typ == 4:
self.lef.write(" DIRECTION INPUT ;\n")
self.lef.write(" PORT\n")
else:
debug.error("Invalid pin type on pin {0}".format(pinName))
pin_layer_coord = self.pinLayerCoord(self.sr.name, pinName) # We could sort these together to minimize different layer sections, but meh.
for pinLayer in pin_layer_coord: pin_list = self.get_pins(name)
lay = [key for key, value in tech.layer.iteritems() if value == pinLayer][0] for pin in pin_list:
self.lef.write(" LAYER {0} ;\n".format(lay)) self.lef.write("{0}LAYER {1} ;\n".format(self.indent,pin.layer))
for pinCoord in pin_layer_coord[pinLayer]: self.lef_write_rect(pin.rect)
self.writePinCoord(self.sr.name, pinName, pinLayer, pinCoord,
mirr = 1,angle = math.radians(float(0)), xyShift = (0, 0)) # End the PORT
self.lef.write(" END\n") self.indent = self.indent[:-3]
self.lef.write(" END {0}\n".format(pinName)) self.lef.write("{0}END\n".format(self.indent))
def lowestLeftCorner(self, sr, mirr = 1, angle = math.radians(float(0)), xyShift = (0, 0), listMinX = [], listMinY = [], listMaxX = [], listMaxY =[]): # End the PIN
"""Recursive find a lowest left conner on each Structure in GDS file""" self.indent = self.indent[:-3]
for boundary in self.myLayout.structures[sr].boundaries: self.lef.write("{0}END {1}\n".format(self.indent,name))
coordTrans = self.coordinatesTranslate(boundary.coordinates, mirr, angle, xyShift)
minX = min(coordTrans[0][0], coordTrans[1][0], coordTrans[2][0], coordTrans[3][0]) def lef_write_obstructions(self):
minY = min(coordTrans[0][1], coordTrans[1][1], coordTrans[2][1], coordTrans[3][1]) """ Write all the obstructions on each layer """
maxX = max(coordTrans[0][0], coordTrans[1][0], coordTrans[2][0], coordTrans[3][0]) self.lef.write("{0}OBS\n".format(self.indent))
maxY = max(coordTrans[0][1], coordTrans[1][1], coordTrans[2][1], coordTrans[3][1]) for layer in self.lef_layers:
listMinX.append(minX) self.lef.write("{0}LAYER {1} ;\n".format(self.indent,layer))
listMinY.append(minY) self.indent += " "
listMaxX.append(maxX) blockages = self.get_blockages(layer,True)
listMaxY.append(maxY) for b in blockages:
self.lef_write_rect(b)
for sref in self.myLayout.structures[sr].srefs: self.indent = self.indent[:-3]
sMirr = 1 self.lef.write("{0}END\n".format(self.indent))
if sref.transFlags[0] == True:
sMirr = -1
sAngle = math.radians(float(0))
if sref.rotateAngle:
sAngle = math.radians(float(sref.rotateAngle))
sAngle += angle
x = sref.coordinates[0]
y = sref.coordinates[1]
newX = (x*math.cos(angle) - mirr*y*math.sin(angle)) + xyShift[0]
newY = (x*math.sin(angle) + mirr*y*math.cos(angle)) + xyShift[1]
sxyShift = (newX, newY)
self.lowestLeftCorner(sref.sName, sMirr, sAngle, sxyShift, listMinX, listMinY, listMaxX, listMaxY)
coordinate = []
lowestX = min(listMinX)
lowestY = min(float(item) for item in listMinY)
highestX = max(float(item) for item in listMaxX)
highestY = max(float(item) for item in listMaxY)
coordinate.append((lowestX, lowestY))
coordinate.append((highestX, highestY))
return coordinate
def lef_write_rect(self, rect):
""" Write a LEF rectangle """
self.lef.write("{0}RECT ".format(self.indent))
for item in rect:
self.lef.write(" {0} {1}".format(self.lef_units*item[0], self.lef_units*item[1]))
self.lef.write(" ;\n")

View File

@ -64,16 +64,6 @@ print("Output files are " + OPTS.output_name + ".(sp|gds|v|lib|lef)")
print("Technology: {0}".format(OPTS.tech_name)) print("Technology: {0}".format(OPTS.tech_name))
print("Word size: {0}\nWords: {1}\nBanks: {2}".format(word_size,num_words,num_banks)) print("Word size: {0}\nWords: {1}\nBanks: {2}".format(word_size,num_words,num_banks))
if not OPTS.check_lvsdrc:
print("DRC/LVS/PEX checking is disabled.")
if OPTS.analytical_delay:
print("Using analytical delay models (no characterization)")
else:
print("Performing simulation-based characterization with {}".format(OPTS.spice_name))
if OPTS.trim_netlist:
print("Trimming netlist to speed up characterization (sacrificing some accuracy).")
# only start importing modules after we have the config file # only start importing modules after we have the config file
import verify import verify
import sram import sram
@ -81,7 +71,8 @@ import sram
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
last_time = start_time last_time = start_time
print_time("Start",datetime.datetime.now()) print_time("Start",datetime.datetime.now())
if not OPTS.check_lvsdrc:
print("DRC/LVS/PEX checking is disabled.")
# import SRAM test generation # import SRAM test generation
s = sram.sram(word_size=word_size, s = sram.sram(word_size=word_size,
num_words=num_words, num_words=num_words,
@ -110,6 +101,13 @@ if OPTS.use_pex:
from characterizer import lib from characterizer import lib
libname = OPTS.output_path + s.name + ".lib" libname = OPTS.output_path + s.name + ".lib"
print("LIB: Writing to {0}".format(libname)) print("LIB: Writing to {0}".format(libname))
if OPTS.analytical_delay:
print("Using analytical delay models (no characterization)")
else:
if OPTS.spice_name!="":
print("Performing simulation-based characterization with {}".format(OPTS.spice_name))
if OPTS.trim_netlist:
print("Trimming netlist to speed up characterization.")
lib.lib(libname,s,sram_file) lib.lib(libname,s,sram_file)
last_time=print_time("Characterization", datetime.datetime.now(), last_time) last_time=print_time("Characterization", datetime.datetime.now(), last_time)
@ -120,18 +118,16 @@ s.gds_write(gdsname)
last_time=print_time("GDS", datetime.datetime.now(), last_time) last_time=print_time("GDS", datetime.datetime.now(), last_time)
# Create a LEF physical model # Create a LEF physical model
import lef
lefname = OPTS.output_path + s.name + ".lef" lefname = OPTS.output_path + s.name + ".lef"
print("LEF: Writing to {0}".format(lefname)) print("LEF: Writing to {0}".format(lefname))
lef.lef(gdsname,lefname,s) s.lef_write(lefname)
last_time=print_time("LEF writing", datetime.datetime.now(), last_time) last_time=print_time("LEF", datetime.datetime.now(), last_time)
# Write a verilog model # Write a verilog model
import verilog
vname = OPTS.output_path + s.name + ".v" vname = OPTS.output_path + s.name + ".v"
print("Verilog: Writing to {0}".format(vname)) print("Verilog: Writing to {0}".format(vname))
verilog.verilog(vname,s) s.verilog_write(vname)
last_time=print_time("Verilog writing", datetime.datetime.now(), last_time) last_time=print_time("Verilog", datetime.datetime.now(), last_time)
globals.end_openram() globals.end_openram()
print_time("End",datetime.datetime.now(), start_time) print_time("End",datetime.datetime.now(), start_time)

View File

@ -32,6 +32,8 @@ class options(optparse.Values):
use_pex = False use_pex = False
# Remove noncritical memory cells for characterization speed-up # Remove noncritical memory cells for characterization speed-up
trim_netlist = True trim_netlist = True
# Use detailed LEF blockages
detailed_blockages = True
# Define the output file paths # Define the output file paths
output_path = "" output_path = ""
# Define the output file base name # Define the output file base name

View File

@ -23,6 +23,7 @@ class pin_layout:
self.layer = layer.keys()[layer.values().index(layer_name_num)] self.layer = layer.keys()[layer.values().index(layer_name_num)]
else: else:
self.layer=layer_name_num self.layer=layer_name_num
self.layer_num = layer[self.layer]
def __str__(self): def __str__(self):
""" override print function output """ """ override print function output """

View File

@ -74,7 +74,7 @@ class precharge(pgate.pgate):
self.lower_pmos_inst=self.add_inst(name="lower_pmos", self.lower_pmos_inst=self.add_inst(name="lower_pmos",
mod=self.pmos, mod=self.pmos,
offset=self.lower_pmos_position) offset=self.lower_pmos_position)
self.connect_inst(["bl", "clk", "br", "vdd"]) self.connect_inst(["bl", "clk", "BR", "vdd"])
# adds the upper pmos(s) to layout # adds the upper pmos(s) to layout
ydiff = self.pmos.height + 2*self.m1_space + contact.poly.width ydiff = self.pmos.height + 2*self.m1_space + contact.poly.width
@ -150,7 +150,7 @@ class precharge(pgate.pgate):
"""Adds both bit-line and bit-line-bar to the module""" """Adds both bit-line and bit-line-bar to the module"""
# adds the BL on metal 2 # adds the BL on metal 2
offset = vector(self.bitcell.get_pin("BL").cx(),0) - vector(0.5 * self.m2_width,0) offset = vector(self.bitcell.get_pin("BL").cx(),0) - vector(0.5 * self.m2_width,0)
self.add_layout_pin(text="BL", self.add_layout_pin(text="bl",
layer="metal2", layer="metal2",
offset=offset, offset=offset,
width=drc['minwidth_metal2'], width=drc['minwidth_metal2'],
@ -158,7 +158,7 @@ class precharge(pgate.pgate):
# adds the BR on metal 2 # adds the BR on metal 2
offset = vector(self.bitcell.get_pin("BR").cx(),0) - vector(0.5 * self.m2_width,0) offset = vector(self.bitcell.get_pin("BR").cx(),0) - vector(0.5 * self.m2_width,0)
self.add_layout_pin(text="BR", self.add_layout_pin(text="br",
layer="metal2", layer="metal2",
offset=offset, offset=offset,
width=drc['minwidth_metal2'], width=drc['minwidth_metal2'],
@ -166,10 +166,10 @@ class precharge(pgate.pgate):
def connect_to_bitlines(self): def connect_to_bitlines(self):
self.add_bitline_contacts() self.add_bitline_contacts()
self.connect_pmos(self.lower_pmos_inst.get_pin("S"),self.get_pin("BL")) self.connect_pmos(self.lower_pmos_inst.get_pin("S"),self.get_pin("bl"))
self.connect_pmos(self.lower_pmos_inst.get_pin("D"),self.get_pin("BR")) self.connect_pmos(self.lower_pmos_inst.get_pin("D"),self.get_pin("br"))
self.connect_pmos(self.upper_pmos1_inst.get_pin("S"),self.get_pin("BL")) self.connect_pmos(self.upper_pmos1_inst.get_pin("S"),self.get_pin("bl"))
self.connect_pmos(self.upper_pmos2_inst.get_pin("D"),self.get_pin("BR")) self.connect_pmos(self.upper_pmos2_inst.get_pin("D"),self.get_pin("br"))
def add_bitline_contacts(self): def add_bitline_contacts(self):

View File

@ -50,7 +50,6 @@ class precharge_array(design.design):
width=self.width, width=self.width,
height=drc["minwidth_metal1"]) height=drc["minwidth_metal1"])
#self.offset_all_coordinates()
def add_insts(self): def add_insts(self):
"""Creates a precharge array by horizontally tiling the precharge cell""" """Creates a precharge array by horizontally tiling the precharge cell"""
@ -60,13 +59,13 @@ class precharge_array(design.design):
inst=self.add_inst(name=name, inst=self.add_inst(name=name,
mod=self.pc_cell, mod=self.pc_cell,
offset=offset) offset=offset)
bl_pin = inst.get_pin("BL") bl_pin = inst.get_pin("bl")
self.add_layout_pin(text="bl[{0}]".format(i), self.add_layout_pin(text="bl[{0}]".format(i),
layer="metal2", layer="metal2",
offset=bl_pin.ll(), offset=bl_pin.ll(),
width=drc["minwidth_metal2"], width=drc["minwidth_metal2"],
height=bl_pin.height()) height=bl_pin.height())
br_pin = inst.get_pin("BR") br_pin = inst.get_pin("br")
self.add_layout_pin(text="br[{0}]".format(i), self.add_layout_pin(text="br[{0}]".format(i),
layer="metal2", layer="metal2",
offset=br_pin.ll(), offset=br_pin.ll(),

View File

@ -45,8 +45,6 @@ class sense_amp_array(design.design):
self.add_sense_amp() self.add_sense_amp()
self.connect_rails() self.connect_rails()
#self.offset_all_coordinates()
def add_sense_amp(self): def add_sense_amp(self):

View File

@ -90,7 +90,7 @@ class single_level_column_mux(design.design):
""" Connect the poly gate of the two pass transistors """ """ Connect the poly gate of the two pass transistors """
height=self.nmos2.get_pin("G").uy() - self.nmos1.get_pin("G").by() height=self.nmos2.get_pin("G").uy() - self.nmos1.get_pin("G").by()
self.add_layout_pin(text="col_addr", self.add_layout_pin(text="sel",
layer="poly", layer="poly",
offset=self.nmos1.get_pin("G").ll(), offset=self.nmos1.get_pin("G").ll(),
height=height) height=height)

View File

@ -125,7 +125,7 @@ class single_level_column_mux_array(design.design):
# which select bit should this column connect to depends on the position in the word # which select bit should this column connect to depends on the position in the word
sel_index = col % self.words_per_row sel_index = col % self.words_per_row
# Add the column x offset to find the right select bit # Add the column x offset to find the right select bit
gate_offset = self.mux_inst[col].get_pin("col_addr").bc() gate_offset = self.mux_inst[col].get_pin("sel").bc()
# height to connect the gate to the correct horizontal row # height to connect the gate to the correct horizontal row
sel_height = self.get_pin("sel[{}]".format(sel_index)).by() sel_height = self.get_pin("sel[{}]".format(sel_index)).by()
# use the y offset from the sel pin and the x offset from the gate # use the y offset from the sel pin and the x offset from the gate

View File

@ -67,6 +67,11 @@ class sram(design.design):
# Can remove the following, but it helps for debug! # Can remove the following, but it helps for debug!
self.add_lvs_correspondence_points() self.add_lvs_correspondence_points()
self.offset_all_coordinates()
sizes = self.find_highest_coords()
self.width = sizes[0]
self.height = sizes[1]
self.DRC_LVS() self.DRC_LVS()
def compute_sizes(self): def compute_sizes(self):
@ -131,15 +136,17 @@ class sram(design.design):
""" Add pins for entire SRAM. """ """ Add pins for entire SRAM. """
for i in range(self.word_size): for i in range(self.word_size):
self.add_pin("DATA[{0}]".format(i)) self.add_pin("DATA[{0}]".format(i),"INOUT")
for i in range(self.addr_size): for i in range(self.addr_size):
self.add_pin("ADDR[{0}]".format(i)) self.add_pin("ADDR[{0}]".format(i),"INPUT")
# These are used to create the physical pins too
self.control_logic_inputs=["CSb", "WEb", "OEb", "clk"] self.control_logic_inputs=["CSb", "WEb", "OEb", "clk"]
self.control_logic_outputs=["s_en", "w_en", "tri_en", "tri_en_bar", "clk_bar", "clk_buf"] self.control_logic_outputs=["s_en", "w_en", "tri_en", "tri_en_bar", "clk_bar", "clk_buf"]
for pin in self.control_logic_inputs+["vdd","gnd"]: self.add_pin_list(self.control_logic_inputs,"INPUT")
self.add_pin(pin) self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND")
def create_layout(self): def create_layout(self):
""" Layout creation """ """ Layout creation """
@ -221,7 +228,6 @@ class sram(design.design):
self.add_path("metal3",[pin_pos,rail_pos]) self.add_path("metal3",[pin_pos,rail_pos])
self.add_via_center(("metal2","via2","metal3"),rail_pos) self.add_via_center(("metal2","via2","metal3"),rail_pos)
# connect the horizontal control bus to the vertical bus
def route_four_banks(self): def route_four_banks(self):

View File

@ -38,8 +38,7 @@ class lib_test(unittest.TestCase):
# let's diff the result with a golden model # let's diff the result with a golden model
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename) golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
# Randomly decided 1% difference between spice simulators is ok. self.assertEqual(isapproxdiff(libname,golden,0.15),True)
self.assertEqual(isapproxdiff(libname,golden,0.01),True)
globals.end_openram() globals.end_openram()

View File

@ -36,14 +36,13 @@ class lib_test(unittest.TestCase):
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
filename = s.name + ".lib" filename = s.name + "_pruned.lib"
libname = OPTS.openram_temp + filename libname = OPTS.openram_temp + filename
lib.lib(libname=libname,sram=s,spfile=tempspice,use_model=False) lib.lib(libname=libname,sram=s,spfile=tempspice,use_model=False)
# let's diff the result with a golden model # let's diff the result with a golden model
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename) golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
# 15% worked in freepdk, but scmos needed 20% self.assertEqual(isapproxdiff(libname,golden,0.30),True)
self.assertEqual(isapproxdiff(libname,golden,0.20),True)
OPTS.analytical_delay = True OPTS.analytical_delay = True
reload(characterizer) reload(characterizer)

View File

@ -42,7 +42,7 @@ class lib_test(unittest.TestCase):
# let's diff the result with a golden model # let's diff the result with a golden model
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename) golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
self.assertEqual(isapproxdiff(libname,golden,0.25),True) self.assertEqual(isapproxdiff(libname,golden,0.15),True)
OPTS.analytical_delay = True OPTS.analytical_delay = True
OPTS.trim_netlist = True OPTS.trim_netlist = True

View File

@ -21,7 +21,6 @@ class lef_test(unittest.TestCase):
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import sram import sram
import lef
debug.info(1, "Testing LEF for sample 2 bit, 16 words SRAM with 1 bank") debug.info(1, "Testing LEF for sample 2 bit, 16 words SRAM with 1 bank")
s = sram.sram(word_size=2, s = sram.sram(word_size=2,
@ -36,7 +35,7 @@ class lef_test(unittest.TestCase):
gdsname = OPTS.openram_temp + gdsfile gdsname = OPTS.openram_temp + gdsfile
lefname = OPTS.openram_temp + leffile lefname = OPTS.openram_temp + leffile
s.gds_write(gdsname) s.gds_write(gdsname)
lef.lef(gdsname,lefname,s) s.lef_write(lefname)
# let's diff the result with a golden model # let's diff the result with a golden model
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),leffile) golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),leffile)

View File

@ -21,7 +21,6 @@ class verilog_test(unittest.TestCase):
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import sram import sram
import verilog
debug.info(1, "Testing Verilog for sample 2 bit, 16 words SRAM with 1 bank") debug.info(1, "Testing Verilog for sample 2 bit, 16 words SRAM with 1 bank")
s = sram.sram(word_size=2, s = sram.sram(word_size=2,
@ -33,7 +32,7 @@ class verilog_test(unittest.TestCase):
vfile = s.name + ".v" vfile = s.name + ".v"
vname = OPTS.openram_temp + vfile vname = OPTS.openram_temp + vfile
verilog.verilog(vname,s) s.verilog_write(vname)
# let's diff the result with a golden model # let's diff the result with a golden model

File diff suppressed because it is too large Load Diff

View File

@ -74,7 +74,7 @@ cell (sram_2_16_1_freepdk45){
dont_use : true; dont_use : true;
map_only : true; map_only : true;
dont_touch : true; dont_touch : true;
area : 696.39825; area : 0.023625;
bus(DATA){ bus(DATA){
bus_type : DATA; bus_type : DATA;
@ -92,10 +92,10 @@ cell (sram_2_16_1_freepdk45){
internal_power(){ internal_power(){
when : "OEb & !clk"; when : "OEb & !clk";
rise_power(scalar){ rise_power(scalar){
values("0.0308667"); values("0.027781");
} }
fall_power(scalar){ fall_power(scalar){
values("0.0304125"); values("0.026752");
} }
} }
timing(){ timing(){
@ -129,10 +129,10 @@ cell (sram_2_16_1_freepdk45){
internal_power(){ internal_power(){
when : "!OEb & !clk"; when : "!OEb & !clk";
rise_power(scalar){ rise_power(scalar){
values("0.0362061"); values("0.031198");
} }
fall_power(scalar){ fall_power(scalar){
values("0.0364614"); values("0.031252");
} }
} }
timing(){ timing(){
@ -140,23 +140,23 @@ cell (sram_2_16_1_freepdk45){
related_pin : "clk"; related_pin : "clk";
timing_type : falling_edge; timing_type : falling_edge;
cell_rise(CELL_TABLE) { cell_rise(CELL_TABLE) {
values("0.047, 0.048, 0.055",\ values("0.046, 0.047, 0.054",\
"0.048, 0.049, 0.056",\ "0.047, 0.047, 0.054",\
"0.053, 0.054, 0.061"); "0.052, 0.052, 0.059");
} }
cell_fall(CELL_TABLE) { cell_fall(CELL_TABLE) {
values("0.143, 0.144, 0.152",\ values("0.132, 0.133, 0.142",\
"0.144, 0.145, 0.153",\ "0.133, 0.134, 0.142",\
"0.149, 0.15, 0.158"); "0.138, 0.139, 0.147");
} }
rise_transition(CELL_TABLE) { rise_transition(CELL_TABLE) {
values("0.014, 0.015, 0.027",\ values("0.014, 0.015, 0.027",\
"0.014, 0.015, 0.027",\ "0.014, 0.015, 0.027",\
"0.014, 0.016, 0.027"); "0.014, 0.015, 0.027");
} }
fall_transition(CELL_TABLE) { fall_transition(CELL_TABLE) {
values("0.019, 0.02, 0.035",\ values("0.018, 0.02, 0.036",\
"0.019, 0.02, 0.035",\ "0.019, 0.02, 0.036",\
"0.019, 0.02, 0.036"); "0.019, 0.02, 0.036");
} }
} }
@ -308,20 +308,20 @@ cell (sram_2_16_1_freepdk45){
timing_type :"min_pulse_width"; timing_type :"min_pulse_width";
related_pin : clk; related_pin : clk;
rise_constraint(scalar) { rise_constraint(scalar) {
values("0.205"); values("0.1955");
} }
fall_constraint(scalar) { fall_constraint(scalar) {
values("0.205"); values("0.1955");
} }
} }
timing(){ timing(){
timing_type :"minimum_period"; timing_type :"minimum_period";
related_pin : clk; related_pin : clk;
rise_constraint(scalar) { rise_constraint(scalar) {
values("0.41"); values("0.391");
} }
fall_constraint(scalar) { fall_constraint(scalar) {
values("0.41"); values("0.391");
} }
} }
} }

View File

@ -74,7 +74,7 @@ cell (sram_2_16_1_freepdk45){
dont_use : true; dont_use : true;
map_only : true; map_only : true;
dont_touch : true; dont_touch : true;
area : 692.2795; area : 0.023625;
bus(DATA){ bus(DATA){
bus_type : DATA; bus_type : DATA;
@ -140,14 +140,14 @@ cell (sram_2_16_1_freepdk45){
related_pin : "clk"; related_pin : "clk";
timing_type : falling_edge; timing_type : falling_edge;
cell_rise(CELL_TABLE) { cell_rise(CELL_TABLE) {
values("0.122, 0.123, 0.132",\ values("0.123, 0.124, 0.133",\
"0.122, 0.123, 0.132",\ "0.123, 0.124, 0.133",\
"0.122, 0.123, 0.132"); "0.123, 0.124, 0.133");
} }
cell_fall(CELL_TABLE) { cell_fall(CELL_TABLE) {
values("0.122, 0.123, 0.132",\ values("0.123, 0.124, 0.133",\
"0.122, 0.123, 0.132",\ "0.123, 0.124, 0.133",\
"0.122, 0.123, 0.132"); "0.123, 0.124, 0.133");
} }
rise_transition(CELL_TABLE) { rise_transition(CELL_TABLE) {
values("0.006, 0.007, 0.018",\ values("0.006, 0.007, 0.018",\

View File

@ -0,0 +1,329 @@
library (sram_2_16_1_freepdk45_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
voltage_unit : "1v" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
capacitive_load_unit(1 ,fF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(TT){
voltage : 1.0 ;
temperature : 25.000 ;
}
input_threshold_pct_fall : 50.0 ;
output_threshold_pct_fall : 50.0 ;
input_threshold_pct_rise : 50.0 ;
output_threshold_pct_rise : 50.0 ;
slew_lower_threshold_pct_fall : 10.0 ;
slew_upper_threshold_pct_fall : 90.0 ;
slew_lower_threshold_pct_rise : 10.0 ;
slew_upper_threshold_pct_rise : 90.0 ;
default_cell_leakage_power : 0.0 ;
default_leakage_power_density : 0.0 ;
default_input_pin_cap : 1.0 ;
default_inout_pin_cap : 1.0 ;
default_output_pin_cap : 0.0 ;
default_max_transition : 0.5 ;
default_fanout_load : 1.0 ;
default_max_fanout : 4.0 ;
default_connection_class : universal ;
lu_table_template(CELL_TABLE){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1("0.00125, 0.005, 0.04");
index_2("0.052275, 0.2091, 1.6728");
}
lu_table_template(CONSTRAINT_TABLE){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1("0.00125, 0.005, 0.04");
index_2("0.00125, 0.005, 0.04");
}
default_operating_conditions : TT;
type (DATA){
base_type : array;
data_type : bit;
bit_width : 2;
bit_from : 0;
bit_to : 1;
}
type (ADDR){
base_type : array;
data_type : bit;
bit_width : 4;
bit_from : 0;
bit_to : 3;
}
cell (sram_2_16_1_freepdk45){
memory(){
type : ram;
address_width : 4;
word_width : 2;
}
interface_timing : true;
dont_use : true;
map_only : true;
dont_touch : true;
area : 0.023625;
bus(DATA){
bus_type : DATA;
direction : inout;
max_capacitance : 1.6728;
three_state : "!OEb & !clk";
memory_write(){
address : ADDR;
clocked_on : clk;
}
memory_read(){
address : ADDR;
}
pin(DATA[1:0]){
internal_power(){
when : "OEb & !clk";
rise_power(scalar){
values("0.027781");
}
fall_power(scalar){
values("0.026752");
}
}
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
internal_power(){
when : "!OEb & !clk";
rise_power(scalar){
values("0.031198");
}
fall_power(scalar){
values("0.031252");
}
}
timing(){
timing_sense : non_unate;
related_pin : "clk";
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("0.046, 0.047, 0.054",\
"0.047, 0.047, 0.054",\
"0.052, 0.052, 0.059");
}
cell_fall(CELL_TABLE) {
values("0.132, 0.133, 0.142",\
"0.133, 0.134, 0.142",\
"0.138, 0.139, 0.147");
}
rise_transition(CELL_TABLE) {
values("0.014, 0.015, 0.027",\
"0.014, 0.015, 0.027",\
"0.014, 0.015, 0.027");
}
fall_transition(CELL_TABLE) {
values("0.018, 0.02, 0.036",\
"0.019, 0.02, 0.036",\
"0.019, 0.02, 0.036");
}
}
}
}
bus(ADDR){
bus_type : ADDR;
direction : input;
capacitance : 0.2091;
max_transition : 0.04;
fanout_load : 1.000000;
pin(ADDR[3:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
}
pin(CSb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(OEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(WEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(clk){
clock : true;
direction : input;
capacitance : 0.2091;
timing(){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(scalar) {
values("0.1955");
}
fall_constraint(scalar) {
values("0.1955");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(scalar) {
values("0.391");
}
fall_constraint(scalar) {
values("0.391");
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -74,7 +74,7 @@ cell (sram_2_16_1_scn3me_subm){
dont_use : true; dont_use : true;
map_only : true; map_only : true;
dont_touch : true; dont_touch : true;
area : 90431.64; area : 2.7;
bus(DATA){ bus(DATA){
bus_type : DATA; bus_type : DATA;
@ -92,10 +92,10 @@ cell (sram_2_16_1_scn3me_subm){
internal_power(){ internal_power(){
when : "OEb & !clk"; when : "OEb & !clk";
rise_power(scalar){ rise_power(scalar){
values("3.1581"); values("3.2612");
} }
fall_power(scalar){ fall_power(scalar){
values("3.4945"); values("3.5985");
} }
} }
timing(){ timing(){
@ -129,10 +129,10 @@ cell (sram_2_16_1_scn3me_subm){
internal_power(){ internal_power(){
when : "!OEb & !clk"; when : "!OEb & !clk";
rise_power(scalar){ rise_power(scalar){
values("5.0577"); values("5.1597");
} }
fall_power(scalar){ fall_power(scalar){
values("5.0831"); values("5.1863");
} }
} }
timing(){ timing(){
@ -140,24 +140,24 @@ cell (sram_2_16_1_scn3me_subm){
related_pin : "clk"; related_pin : "clk";
timing_type : falling_edge; timing_type : falling_edge;
cell_rise(CELL_TABLE) { cell_rise(CELL_TABLE) {
values("0.542, 0.626, 1.298",\ values("0.509, 0.592, 1.265",\
"0.544, 0.627, 1.304",\ "0.512, 0.595, 1.271",\
"0.594, 0.674, 1.35"); "0.561, 0.642, 1.317");
} }
cell_fall(CELL_TABLE) { cell_fall(CELL_TABLE) {
values("1.535, 1.637, 2.604",\ values("1.449, 1.549, 2.511",\
"1.54, 1.641, 2.612",\ "1.453, 1.555, 2.518",\
"1.59, 1.693, 2.662"); "1.505, 1.607, 2.568");
} }
rise_transition(CELL_TABLE) { rise_transition(CELL_TABLE) {
values("0.191, 0.337, 1.883",\ values("0.19, 0.335, 1.887",\
"0.193, 0.338, 1.885",\ "0.192, 0.336, 1.886",\
"0.195, 0.341, 1.884"); "0.194, 0.339, 1.886");
} }
fall_transition(CELL_TABLE) { fall_transition(CELL_TABLE) {
values("0.252, 0.446, 2.468",\ values("0.282, 0.465, 2.464",\
"0.253, 0.448, 2.448",\ "0.283, 0.466, 2.463",\
"0.253, 0.447, 2.454"); "0.283, 0.465, 2.455");
} }
} }
} }

View File

@ -74,7 +74,7 @@ cell (sram_2_16_1_scn3me_subm){
dont_use : true; dont_use : true;
map_only : true; map_only : true;
dont_touch : true; dont_touch : true;
area : 90431.64; area : 2.7;
bus(DATA){ bus(DATA){
bus_type : DATA; bus_type : DATA;

View File

@ -0,0 +1,329 @@
library (sram_2_16_1_scn3me_subm_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
voltage_unit : "1v" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
capacitive_load_unit(1 ,fF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(TT){
voltage : 5.0 ;
temperature : 25.000 ;
}
input_threshold_pct_fall : 50.0 ;
output_threshold_pct_fall : 50.0 ;
input_threshold_pct_rise : 50.0 ;
output_threshold_pct_rise : 50.0 ;
slew_lower_threshold_pct_fall : 10.0 ;
slew_upper_threshold_pct_fall : 90.0 ;
slew_lower_threshold_pct_rise : 10.0 ;
slew_upper_threshold_pct_rise : 90.0 ;
default_cell_leakage_power : 0.0 ;
default_leakage_power_density : 0.0 ;
default_input_pin_cap : 1.0 ;
default_inout_pin_cap : 1.0 ;
default_output_pin_cap : 0.0 ;
default_max_transition : 0.5 ;
default_fanout_load : 1.0 ;
default_max_fanout : 4.0 ;
default_connection_class : universal ;
lu_table_template(CELL_TABLE){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1("0.0125, 0.05, 0.4");
index_2("2.45605, 9.8242, 78.5936");
}
lu_table_template(CONSTRAINT_TABLE){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1("0.0125, 0.05, 0.4");
index_2("0.0125, 0.05, 0.4");
}
default_operating_conditions : TT;
type (DATA){
base_type : array;
data_type : bit;
bit_width : 2;
bit_from : 0;
bit_to : 1;
}
type (ADDR){
base_type : array;
data_type : bit;
bit_width : 4;
bit_from : 0;
bit_to : 3;
}
cell (sram_2_16_1_scn3me_subm){
memory(){
type : ram;
address_width : 4;
word_width : 2;
}
interface_timing : true;
dont_use : true;
map_only : true;
dont_touch : true;
area : 2.7;
bus(DATA){
bus_type : DATA;
direction : inout;
max_capacitance : 78.5936;
three_state : "!OEb & !clk";
memory_write(){
address : ADDR;
clocked_on : clk;
}
memory_read(){
address : ADDR;
}
pin(DATA[1:0]){
internal_power(){
when : "OEb & !clk";
rise_power(scalar){
values("2.8745");
}
fall_power(scalar){
values("3.0265");
}
}
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175");
}
}
internal_power(){
when : "!OEb & !clk";
rise_power(scalar){
values("4.4921");
}
fall_power(scalar){
values("4.5139");
}
}
timing(){
timing_sense : non_unate;
related_pin : "clk";
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("0.496, 0.579, 1.253",\
"0.499, 0.581, 1.258",\
"0.547, 0.627, 1.305");
}
cell_fall(CELL_TABLE) {
values("1.429, 1.539, 2.523",\
"1.433, 1.544, 2.526",\
"1.485, 1.595, 2.578");
}
rise_transition(CELL_TABLE) {
values("0.189, 0.335, 1.879",\
"0.19, 0.336, 1.879",\
"0.192, 0.337, 1.879");
}
fall_transition(CELL_TABLE) {
values("0.224, 0.437, 2.462",\
"0.225, 0.437, 2.472",\
"0.225, 0.436, 2.458");
}
}
}
}
bus(ADDR){
bus_type : ADDR;
direction : input;
capacitance : 9.8242;
max_transition : 0.4;
fanout_load : 1.000000;
pin(ADDR[3:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175");
}
}
}
}
pin(CSb){
direction : input;
capacitance : 9.8242;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175");
}
}
}
pin(OEb){
direction : input;
capacitance : 9.8242;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175");
}
}
}
pin(WEb){
direction : input;
capacitance : 9.8242;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175");
}
}
}
pin(clk){
clock : true;
direction : input;
capacitance : 9.8242;
timing(){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(scalar) {
values("4.375");
}
fall_constraint(scalar) {
values("4.375");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(scalar) {
values("8.75");
}
fall_constraint(scalar) {
values("8.75");
}
}
}
}
}

View File

@ -3,25 +3,16 @@ import debug
class verilog: class verilog:
""" Create a behavioral Verilog file for simulation.""" """ Create a behavioral Verilog file for simulation."""
def __init__(self,verilog_name,sram): def verilog_write(self,verilog_name):
self.sram_name = sram.name """ Write a behavioral Verilog model. """
self.num_words = sram.num_words
self.word_size = sram.word_size
self.addr_size = sram.addr_size
self.vf = open(verilog_name, "w") self.vf = open(verilog_name, "w")
self.create()
self.vf.close()
def create(self):
self.vf.write("// OpenRAM SRAM model\n") self.vf.write("// OpenRAM SRAM model\n")
self.vf.write("// Words: {0}\n".format(self.num_words)) self.vf.write("// Words: {0}\n".format(self.num_words))
self.vf.write("// Word size: {0}\n\n".format(self.word_size)) self.vf.write("// Word size: {0}\n\n".format(self.word_size))
self.vf.write("module {0}(DATA,ADDR,CSb,WEb,OEb,clk);\n".format(self.sram_name)) self.vf.write("module {0}(DATA,ADDR,CSb,WEb,OEb,clk);\n".format(self.name))
self.vf.write("\n") self.vf.write("\n")
self.vf.write(" parameter DATA_WIDTH = {0} ;\n".format(self.word_size)) self.vf.write(" parameter DATA_WIDTH = {0} ;\n".format(self.word_size))
self.vf.write(" parameter ADDR_WIDTH = {0} ;\n".format(self.addr_size)) self.vf.write(" parameter ADDR_WIDTH = {0} ;\n".format(self.addr_size))
@ -65,47 +56,5 @@ class verilog:
self.vf.write("endmodule\n") self.vf.write("endmodule\n")
self.vf.close()
# //SRAM Model
# module sram(CSB,WRB,ABUS,DATABUS);
# input CSB; // active low chip select
# input WRB; // active low write control
# input [11:0] ABUS; // 12-bit address bus
# inout [7:0] DATABUS; // 8-bit data bus
# //** internal signals
# reg [7:0] DATABUS_driver;
# wire [7:0] DATABUS = DATABUS_driver;
# reg [7:0] ram[0:4095]; // memory cells
# integer i;
# initial //initialize all RAM cells to 0 at startup
# begin
# DATABUS_driver = 8'bzzzzzzzz;
# for (i=0; i < 4095; i = i + 1)
# ram[i] = 0;
# end
# always @(CSB or WRB or ABUS)
# begin
# if (CSB == 1'b0)
# begin
# if (WRB == 1'b0) //Start: latch Data on rising edge of CSB or WRB
# begin
# DATABUS_driver <= #10 8'bzzzzzzzz;
# @(posedge CSB or posedge WRB);
# $display($time," Writing %m ABUS=%b DATA=%b",ABUS,DATABUS);
# ram[ABUS] = DATABUS;
# end
# if (WRB == 1'b1) //Reading from sram (data becomes valid after 10ns)
# begin
# #10 DATABUS_driver = ram[ABUS];
# $display($time," Reading %m ABUS=%b DATA=%b",ABUS,DATABUS_driver);
# end
# end
# else //sram unselected, stop driving bus after 10ns
# begin
# DATABUS_driver <= #10 8'bzzzzzzzz;
# end
# end
# endmodule

View File

@ -35,8 +35,8 @@ class write_driver_array(design.design):
for i in range(self.word_size): for i in range(self.word_size):
self.add_pin("data[{0}]".format(i)) self.add_pin("data[{0}]".format(i))
for i in range(self.word_size): for i in range(self.word_size):
self.add_pin("bl_out[{0}]".format(i)) self.add_pin("bl[{0}]".format(i))
self.add_pin("br_out[{0}]".format(i)) self.add_pin("br[{0}]".format(i))
self.add_pin("en") self.add_pin("en")
self.add_pin("vdd") self.add_pin("vdd")
self.add_pin("gnd") self.add_pin("gnd")
@ -44,7 +44,6 @@ class write_driver_array(design.design):
def create_layout(self): def create_layout(self):
self.create_write_array() self.create_write_array()
self.add_layout_pins() self.add_layout_pins()
#self.offset_all_coordinates()
def create_write_array(self): def create_write_array(self):
self.driver_insts = {} self.driver_insts = {}
@ -57,8 +56,8 @@ class write_driver_array(design.design):
offset=base) offset=base)
self.connect_inst(["data[{0}]".format(i/self.words_per_row), self.connect_inst(["data[{0}]".format(i/self.words_per_row),
"bl_out[{0}]".format(i/self.words_per_row), "bl[{0}]".format(i/self.words_per_row),
"br_out[{0}]".format(i/self.words_per_row), "br[{0}]".format(i/self.words_per_row),
"en", "vdd", "gnd"]) "en", "vdd", "gnd"])