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 = ""
if OPTS.analytical_delay:
debug.info(1,"Using analytical delay models (no characterization)")
else:
if not OPTS.analytical_delay:
if OPTS.spice_name != "":
spice_exe=find_exe(OPTS.spice_name)
if spice_exe=="":

View File

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

View File

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

View File

@ -3,7 +3,9 @@ This provides a set of useful generic types for the gdsMill interface.
"""
import debug
from vector import vector
from tech import GDS
import tech
import math
from globals import OPTS
class geometry:
"""
@ -23,40 +25,24 @@ class geometry:
""" override print function output """
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):
"""
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.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 transform_coords(self, coords, offset, mirr, angle):
"""Calculate coordinates after flip, rotate, and shift"""
coordinate = []
for item in coords:
x = item[0]*math.cos(angle) - item[1]*mirr*math.sin(angle) + offset[0]
y = item[0]*math.sin(angle) + item[1]*mirr*math.cos(angle) + offset[1]
coordinate += [[x, y]]
return coordinate
def normalize(self):
""" Re-find the LL and UR points after a transform """
(first,second)=self.boundary
@ -67,7 +53,7 @@ class instance(geometry):
def compute_boundary(self,offset=vector(0,0),mirror="",rotate=0):
""" 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. """
(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":
ll=ll.scale(1,-1)
ur=ur.scale(1,-1)
@ -123,6 +109,78 @@ class instance(geometry):
def rx(self):
""" Return the right edge """
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):
""" Return an absolute pin that is offset and transformed based on
@ -187,6 +245,10 @@ class path(geometry):
coordinates=self.coordinates,
width=self.path_width)
def get_blockages(self, layer):
""" Fail since we don't support paths yet. """
assert(0)
def __str__(self):
""" override print function output """
return "path: layer=" + self.layerNumber + " w=" + self.width
@ -206,12 +268,12 @@ class label(geometry):
self.text = text
self.layerNumber = layerNumber
self.offset = vector(offset).snap_to_grid()
if zoom<0:
self.zoom = GDS["zoom"]
self.zoom = tech.GDS["zoom"]
else:
self.zoom = zoom
self.size = 0
debug.info(4,"creating label " + self.text + " " + str(self.layerNumber) + " " + str(self.offset))
@ -226,6 +288,10 @@ class label(geometry):
magnification=self.zoom,
rotate=None)
def get_blockages(self, layer):
""" Returns an empty list since text cannot be blockages. """
return []
def __str__(self):
""" override print function output """
return "label: " + self.text + " layer=" + str(self.layerNumber)
@ -246,10 +312,18 @@ class rectangle(geometry):
self.size = vector(width, height).snap_to_grid()
self.width = self.size.x
self.height = self.size.y
self.compute_boundary(offset,"",0)
debug.info(4, "creating rectangle (" + str(self.layerNumber) + "): "
+ 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):
"""Writes the rectangular shape to GDS"""

View File

@ -43,10 +43,6 @@ class hierarchical_decoder(design.design):
self.create_row_decoder()
self.create_vertical_rail()
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):
self.inv = pinv()

View File

@ -7,8 +7,9 @@ from tech import layer as techlayer
import os
from vector import vector
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
This provides a set of useful generic types for hierarchy
@ -18,7 +19,8 @@ class layout:
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.width = None
self.height = None
@ -26,7 +28,7 @@ class layout:
self.objs = [] # Holds all other objects (labels, geometries, etc)
self.pin_map = {} # Holds name->pin_layout map for all pins
self.visited = False # Flag for traversing the hierarchy
self.is_library_cell = False # Flag for library cells
self.gds_read()
############################################################
@ -36,7 +38,6 @@ class layout:
""" This function is called after everything is placed to
shift the origin in the lowest left corner """
offset = self.find_lowest_coords()
#self.offset_attributes(offset)
self.translate_all(offset)
def get_gate_offset(self, x_offset, height, inv_num):
@ -59,19 +60,22 @@ class layout:
def find_lowest_coords(self):
"""Finds the lowest set of 2d cartesian coordinates within
this layout"""
# FIXME: don't depend on 1e9
try:
lowestx1 = min(rect.offset.x for rect in self.objs)
lowesty1 = min(rect.offset.y for rect in self.objs)
except:
[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]
lowestx1 = min(obj.lx() for obj in self.objs if obj.name!="label")
lowesty1 = min(obj.by() for obj in self.objs if obj.name!="label")
lowestx2 = min(inst.lx() for inst in self.insts)
lowesty2 = min(inst.by() for inst in self.insts)
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):
"""
@ -111,9 +115,9 @@ class layout:
if height==0:
height=drc["minwidth_{}".format(layer)]
# negative layers indicate "unused" layers in a given technology
layerNumber = techlayer[layer]
if layerNumber >= 0:
self.objs.append(geometry.rectangle(layerNumber, offset, width, height))
layer_num = techlayer[layer]
if layer_num >= 0:
self.objs.append(geometry.rectangle(layer_num, offset, width, height))
return self.objs[-1]
return None
@ -124,10 +128,10 @@ class layout:
if height==0:
height=drc["minwidth_{}".format(layer)]
# 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)
if layerNumber >= 0:
self.objs.append(geometry.rectangle(layerNumber, corrected_offset, width, height))
if layer_num >= 0:
self.objs.append(geometry.rectangle(layer_num, corrected_offset, width, height))
return self.objs[-1]
return None
@ -259,9 +263,9 @@ class layout:
"""Adds a text label on the given layer,offset, and zoom level"""
# negative layers indicate "unused" layers in a given technology
debug.info(5,"add label " + str(text) + " " + layer + " " + str(offset))
layerNumber = techlayer[layer]
if layerNumber >= 0:
self.objs.append(geometry.label(text, layerNumber, offset, zoom))
layer_num = techlayer[layer]
if layer_num >= 0:
self.objs.append(geometry.label(text, layer_num, offset, zoom))
return self.objs[-1]
return None
@ -272,9 +276,9 @@ class layout:
import path
# NOTE: (UNTESTED) add_path(...) is currently not used
# negative layers indicate "unused" layers in a given technology
#layerNumber = techlayer[layer]
#if layerNumber >= 0:
# self.objs.append(geometry.path(layerNumber, coordinates, width))
#layer_num = techlayer[layer]
#if layer_num >= 0:
# self.objs.append(geometry.path(layer_num, coordinates, width))
path.path(obj=self,
layer=layer,
@ -390,6 +394,7 @@ class layout:
# open the gds file if it exists or else create a blank layout
if os.path.isfile(self.gds_file):
debug.info(3, "opening %s" % self.gds_file)
self.is_library_cell=True
self.gds = gdsMill.VlsiLayout(units=GDS["unit"])
reader = gdsMill.Gds2reader(self.gds)
reader.loadFromFile(self.gds_file)
@ -440,6 +445,49 @@ class layout:
# self.gds.prepareForWrite()
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):
# NOTE: Currently does not work (Needs further research)
#self.pdf_name = self.name + ".pdf"
@ -465,20 +513,22 @@ class layout:
debug.info(0,
"|==============================================================================|")
debug.info(0,
"|========= LIST OF OBJECTS (Rects) FOR: " + self.attr["name"])
"|========= LIST OF OBJECTS (Rects) FOR: " + self.name)
debug.info(0,
"|==============================================================================|")
for obj in self.objs:
debug.info(0, "layer={0} : offset={1} : size={2}".format(
obj.layerNumber, obj.offset, obj.size))
debug.info(0, "layer={0} : offset={1} : size={2}".format(obj.layerNumber,
obj.offset,
obj.size))
debug.info(0,
"|==============================================================================|")
debug.info(0,
"|========= LIST OF INSTANCES FOR: " +
self.attr["name"])
"|========= LIST OF INSTANCES FOR: " + self.name)
debug.info(0,
"|==============================================================================|")
for inst in self.insts:
debug.info(0, "name={0} : mod={1} : offset={2}".format(
inst.name, inst.mod.name, inst.offset))
debug.info(0, "name={0} : mod={1} : offset={2}".format(inst.name,
inst.mod.name,
inst.offset))

View File

@ -2,9 +2,9 @@ import debug
import re
import os
import math
import verilog
class spice:
class spice(verilog.verilog):
"""
This provides a set of useful generic types for hierarchy
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.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
# THIS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the
# Spice format)
@ -31,13 +31,35 @@ class spice:
# Spice circuit
############################################################
def add_pin(self, name):
"""Adds a pin to the pins list"""
def add_pin(self, name, pin_type="INOUT"):
""" Adds a pin to the pins list. Default type is INOUT signal. """
self.pins.append(name)
self.pin_type[name]=pin_type
def add_pin_list(self, pin_list):
"""Adds a pin_list to the pins list"""
self.pins = self.pins + pin_list
def add_pin_list(self, pin_list, pin_type_list="INOUT"):
""" Adds a pin_list to the pins 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):
"""Adds a subckt/submodule to the subckt hierarchy"""

View File

@ -3,6 +3,7 @@ import tech
import globals
import math
import debug
import datetime
from collections import defaultdict
class lef:
@ -10,246 +11,105 @@ class lef:
SRAM LEF Class open GDS file, read pins information, obstruction
and write them to LEF file
"""
def __init__(self, gdsName, lefName, sr):
self.gdsName = gdsName
self.lef = open(lefName,"w")
self.sr = sr
self.myLayout = gdsMill.VlsiLayout(units=tech.GDS["unit"])
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 __init__(self,layers):
# LEF db units per micron
self.lef_units = 1000
# These are the layers of the obstructions
self.lef_layers = layers
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()
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.writePin(pin, 1)
self.lef.write("{0}MACRO {1}\n".format(self.indent,self.name))
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)
for pin in inout_pin_name:
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))
def lef_write_footer(self):
self.lef.write("{0}END {1}\n".format(self.indent,self.name))
self.indent = self.indent[:-3]
self.lef.write("END LIBRARY\n")
def powerPinName(self):
return ["vdd"]
def groundPinName(self):
return ["gnd"]
def inputPinName(self):
input_pin_name = []
for i in range(self.sr.addr_size + int(math.log(self.sr.num_banks, 2))):
input_pin_name.append("ADDR[{0}]".format(i))
input_pin_name.append("CSb")
input_pin_name.append("OEb")
input_pin_name.append("WEb")
input_pin_name.append("clk")
return input_pin_name
def lef_write_pin(self, name):
pin_dir = self.get_pin_dir(name)
pin_type = self.get_pin_type(name)
self.lef.write("{0}PIN {1}\n".format(self.indent,name))
self.indent += " "
def inoutPinName(self):
inout_pin_name = []
for i in range(self.sr.word_size):
inout_pin_name.append("DATA[{0}]".format(i))
self.lef.write("{0}DIRECTION {1} ;\n".format(self.indent,pin_dir))
if pin_type in ["POWER","GROUND"]:
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
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))
self.lef.write("{0}PORT\n".format(self.indent))
self.indent += " "
pin_layer_coord = self.pinLayerCoord(self.sr.name, pinName)
for pinLayer in pin_layer_coord:
lay = [key for key, value in tech.layer.iteritems() if value == pinLayer][0]
self.lef.write(" LAYER {0} ;\n".format(lay))
for pinCoord in pin_layer_coord[pinLayer]:
self.writePinCoord(self.sr.name, pinName, pinLayer, pinCoord,
mirr = 1,angle = math.radians(float(0)), xyShift = (0, 0))
self.lef.write(" END\n")
self.lef.write(" END {0}\n".format(pinName))
# We could sort these together to minimize different layer sections, but meh.
pin_list = self.get_pins(name)
for pin in pin_list:
self.lef.write("{0}LAYER {1} ;\n".format(self.indent,pin.layer))
self.lef_write_rect(pin.rect)
# End the PORT
self.indent = self.indent[:-3]
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 =[]):
"""Recursive find a lowest left conner on each Structure in GDS file"""
for boundary in self.myLayout.structures[sr].boundaries:
coordTrans = self.coordinatesTranslate(boundary.coordinates, mirr, angle, xyShift)
minX = min(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])
maxX = max(coordTrans[0][0], coordTrans[1][0], coordTrans[2][0], coordTrans[3][0])
maxY = max(coordTrans[0][1], coordTrans[1][1], coordTrans[2][1], coordTrans[3][1])
listMinX.append(minX)
listMinY.append(minY)
listMaxX.append(maxX)
listMaxY.append(maxY)
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.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
# End the PIN
self.indent = self.indent[:-3]
self.lef.write("{0}END {1}\n".format(self.indent,name))
def lef_write_obstructions(self):
""" Write all the obstructions on each layer """
self.lef.write("{0}OBS\n".format(self.indent))
for layer in self.lef_layers:
self.lef.write("{0}LAYER {1} ;\n".format(self.indent,layer))
self.indent += " "
blockages = self.get_blockages(layer,True)
for b in blockages:
self.lef_write_rect(b)
self.indent = self.indent[:-3]
self.lef.write("{0}END\n".format(self.indent))
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("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
import verify
import sram
@ -81,7 +71,8 @@ import sram
start_time = datetime.datetime.now()
last_time = start_time
print_time("Start",datetime.datetime.now())
if not OPTS.check_lvsdrc:
print("DRC/LVS/PEX checking is disabled.")
# import SRAM test generation
s = sram.sram(word_size=word_size,
num_words=num_words,
@ -110,6 +101,13 @@ if OPTS.use_pex:
from characterizer import lib
libname = OPTS.output_path + s.name + ".lib"
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)
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)
# Create a LEF physical model
import lef
lefname = OPTS.output_path + s.name + ".lef"
print("LEF: Writing to {0}".format(lefname))
lef.lef(gdsname,lefname,s)
last_time=print_time("LEF writing", datetime.datetime.now(), last_time)
s.lef_write(lefname)
last_time=print_time("LEF", datetime.datetime.now(), last_time)
# Write a verilog model
import verilog
vname = OPTS.output_path + s.name + ".v"
print("Verilog: Writing to {0}".format(vname))
verilog.verilog(vname,s)
last_time=print_time("Verilog writing", datetime.datetime.now(), last_time)
s.verilog_write(vname)
last_time=print_time("Verilog", datetime.datetime.now(), last_time)
globals.end_openram()
print_time("End",datetime.datetime.now(), start_time)

View File

@ -32,6 +32,8 @@ class options(optparse.Values):
use_pex = False
# Remove noncritical memory cells for characterization speed-up
trim_netlist = True
# Use detailed LEF blockages
detailed_blockages = True
# Define the output file paths
output_path = ""
# 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)]
else:
self.layer=layer_name_num
self.layer_num = layer[self.layer]
def __str__(self):
""" override print function output """

View File

@ -74,7 +74,7 @@ class precharge(pgate.pgate):
self.lower_pmos_inst=self.add_inst(name="lower_pmos",
mod=self.pmos,
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
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 the BL on metal 2
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",
offset=offset,
width=drc['minwidth_metal2'],
@ -158,7 +158,7 @@ class precharge(pgate.pgate):
# adds the BR on metal 2
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",
offset=offset,
width=drc['minwidth_metal2'],
@ -166,10 +166,10 @@ class precharge(pgate.pgate):
def connect_to_bitlines(self):
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("D"),self.get_pin("BR"))
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.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.upper_pmos1_inst.get_pin("S"),self.get_pin("bl"))
self.connect_pmos(self.upper_pmos2_inst.get_pin("D"),self.get_pin("br"))
def add_bitline_contacts(self):

View File

@ -50,7 +50,6 @@ class precharge_array(design.design):
width=self.width,
height=drc["minwidth_metal1"])
#self.offset_all_coordinates()
def add_insts(self):
"""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,
mod=self.pc_cell,
offset=offset)
bl_pin = inst.get_pin("BL")
bl_pin = inst.get_pin("bl")
self.add_layout_pin(text="bl[{0}]".format(i),
layer="metal2",
offset=bl_pin.ll(),
width=drc["minwidth_metal2"],
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),
layer="metal2",
offset=br_pin.ll(),

View File

@ -45,8 +45,6 @@ class sense_amp_array(design.design):
self.add_sense_amp()
self.connect_rails()
#self.offset_all_coordinates()
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 """
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",
offset=self.nmos1.get_pin("G").ll(),
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
sel_index = col % self.words_per_row
# 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
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

View File

@ -67,6 +67,11 @@ class sram(design.design):
# Can remove the following, but it helps for debug!
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()
def compute_sizes(self):
@ -131,15 +136,17 @@ class sram(design.design):
""" Add pins for entire SRAM. """
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):
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_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(pin)
self.add_pin_list(self.control_logic_inputs,"INPUT")
self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND")
def create_layout(self):
""" Layout creation """
@ -221,7 +228,6 @@ class sram(design.design):
self.add_path("metal3",[pin_pos,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):

View File

@ -38,8 +38,7 @@ class lib_test(unittest.TestCase):
# let's diff the result with a golden model
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.01),True)
self.assertEqual(isapproxdiff(libname,golden,0.15),True)
globals.end_openram()

View File

@ -36,14 +36,13 @@ class lib_test(unittest.TestCase):
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
filename = s.name + ".lib"
filename = s.name + "_pruned.lib"
libname = OPTS.openram_temp + filename
lib.lib(libname=libname,sram=s,spfile=tempspice,use_model=False)
# let's diff the result with a golden model
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.20),True)
self.assertEqual(isapproxdiff(libname,golden,0.30),True)
OPTS.analytical_delay = True
reload(characterizer)

View File

@ -42,7 +42,7 @@ class lib_test(unittest.TestCase):
# let's diff the result with a golden model
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.trim_netlist = True

View File

@ -21,7 +21,6 @@ class lef_test(unittest.TestCase):
OPTS.check_lvsdrc = False
import sram
import lef
debug.info(1, "Testing LEF for sample 2 bit, 16 words SRAM with 1 bank")
s = sram.sram(word_size=2,
@ -36,7 +35,7 @@ class lef_test(unittest.TestCase):
gdsname = OPTS.openram_temp + gdsfile
lefname = OPTS.openram_temp + leffile
s.gds_write(gdsname)
lef.lef(gdsname,lefname,s)
s.lef_write(lefname)
# let's diff the result with a golden model
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
import sram
import verilog
debug.info(1, "Testing Verilog for sample 2 bit, 16 words SRAM with 1 bank")
s = sram.sram(word_size=2,
@ -33,7 +32,7 @@ class verilog_test(unittest.TestCase):
vfile = s.name + ".v"
vname = OPTS.openram_temp + vfile
verilog.verilog(vname,s)
s.verilog_write(vname)
# 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;
map_only : true;
dont_touch : true;
area : 696.39825;
area : 0.023625;
bus(DATA){
bus_type : DATA;
@ -92,10 +92,10 @@ cell (sram_2_16_1_freepdk45){
internal_power(){
when : "OEb & !clk";
rise_power(scalar){
values("0.0308667");
values("0.027781");
}
fall_power(scalar){
values("0.0304125");
values("0.026752");
}
}
timing(){
@ -129,10 +129,10 @@ cell (sram_2_16_1_freepdk45){
internal_power(){
when : "!OEb & !clk";
rise_power(scalar){
values("0.0362061");
values("0.031198");
}
fall_power(scalar){
values("0.0364614");
values("0.031252");
}
}
timing(){
@ -140,23 +140,23 @@ cell (sram_2_16_1_freepdk45){
related_pin : "clk";
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("0.047, 0.048, 0.055",\
"0.048, 0.049, 0.056",\
"0.053, 0.054, 0.061");
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.143, 0.144, 0.152",\
"0.144, 0.145, 0.153",\
"0.149, 0.15, 0.158");
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.016, 0.027");
"0.014, 0.015, 0.027");
}
fall_transition(CELL_TABLE) {
values("0.019, 0.02, 0.035",\
"0.019, 0.02, 0.035",\
values("0.018, 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";
related_pin : clk;
rise_constraint(scalar) {
values("0.205");
values("0.1955");
}
fall_constraint(scalar) {
values("0.205");
values("0.1955");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(scalar) {
values("0.41");
values("0.391");
}
fall_constraint(scalar) {
values("0.41");
values("0.391");
}
}
}

View File

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

View File

@ -74,7 +74,7 @@ cell (sram_2_16_1_scn3me_subm){
dont_use : true;
map_only : true;
dont_touch : true;
area : 90431.64;
area : 2.7;
bus(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:
""" Create a behavioral Verilog file for simulation."""
def __init__(self,verilog_name,sram):
self.sram_name = sram.name
self.num_words = sram.num_words
self.word_size = sram.word_size
self.addr_size = sram.addr_size
def verilog_write(self,verilog_name):
""" Write a behavioral Verilog model. """
self.vf = open(verilog_name, "w")
self.create()
self.vf.close()
def create(self):
self.vf.write("// OpenRAM SRAM model\n")
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("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(" parameter DATA_WIDTH = {0} ;\n".format(self.word_size))
self.vf.write(" parameter ADDR_WIDTH = {0} ;\n".format(self.addr_size))
@ -65,47 +56,5 @@ class verilog:
self.vf.write("endmodule\n")
# //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
self.vf.close()

View File

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