mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'master' of https://github.com/mguthaus/OpenRAM into multiport
This commit is contained in:
commit
fb2572bd71
|
|
@ -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=="":
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"""
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"""
|
||||||
|
|
|
||||||
320
compiler/lef.py
320
compiler/lef.py
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 """
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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",\
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"])
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue