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 = ""
|
||||
|
||||
if OPTS.analytical_delay:
|
||||
debug.info(1,"Using analytical delay models (no characterization)")
|
||||
else:
|
||||
if not OPTS.analytical_delay:
|
||||
if OPTS.spice_name != "":
|
||||
spice_exe=find_exe(OPTS.spice_name)
|
||||
if spice_exe=="":
|
||||
|
|
|
|||
|
|
@ -181,8 +181,8 @@ class control_logic(design.design):
|
|||
pin=self.clk_inv1.get_pin("A")
|
||||
self.add_layout_pin(text="clk",
|
||||
layer="metal1",
|
||||
offset=pin.ll(),
|
||||
width=pin.width(),
|
||||
offset=pin.ll().scale(0,1),
|
||||
width=pin.rx(),
|
||||
height=pin.height())
|
||||
|
||||
pin=self.clk_inv1.get_pin("gnd")
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
word_size = 2
|
||||
num_words = 16
|
||||
num_words = 128
|
||||
num_banks = 1
|
||||
|
||||
tech_name = "freepdk45"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ This provides a set of useful generic types for the gdsMill interface.
|
|||
"""
|
||||
import debug
|
||||
from vector import vector
|
||||
from tech import GDS
|
||||
import tech
|
||||
import math
|
||||
from globals import OPTS
|
||||
|
||||
class geometry:
|
||||
"""
|
||||
|
|
@ -23,40 +25,24 @@ class geometry:
|
|||
""" override print function output """
|
||||
debug.error("__repr__ must be overridden by all geometry types.",1)
|
||||
|
||||
# def translate_coords(self, coords, mirr, angle, xyShift):
|
||||
# """Calculate coordinates after flip, rotate, and shift"""
|
||||
# coordinate = []
|
||||
# for item in coords:
|
||||
# x = (item[0]*math.cos(angle)-item[1]*mirr*math.sin(angle)+xyShift[0])
|
||||
# y = (item[0]*math.sin(angle)+item[1]*mirr*math.cos(angle)+xyShift[1])
|
||||
# coordinate += [(x, y)]
|
||||
# return coordinate
|
||||
|
||||
class instance(geometry):
|
||||
"""
|
||||
An instance of an instance/module with a specified location and
|
||||
rotation
|
||||
"""
|
||||
def __init__(self, name, mod, offset, mirror, rotate):
|
||||
"""Initializes an instance to represent a module"""
|
||||
geometry.__init__(self)
|
||||
debug.check(mirror not in ["R90","R180","R270"], "Please use rotation and not mirroring during instantiation.")
|
||||
|
||||
self.name = name
|
||||
self.mod = mod
|
||||
self.gds = mod.gds
|
||||
self.rotate = rotate
|
||||
self.offset = vector(offset).snap_to_grid()
|
||||
self.mirror = mirror
|
||||
|
||||
self.compute_boundary(offset,mirror,rotate)
|
||||
|
||||
debug.info(4, "creating instance: " + self.name)
|
||||
|
||||
def gds_write_file(self, newLayout):
|
||||
"""Recursively writes all the sub-modules in this instance"""
|
||||
debug.info(4, "writing instance: " + self.name)
|
||||
# make sure to write out my module/structure
|
||||
# (it will only be written the first time though)
|
||||
self.mod.gds_write_file(self.gds)
|
||||
# now write an instance of my module/structure
|
||||
newLayout.addInstance(self.gds,
|
||||
offsetInMicrons=self.offset,
|
||||
mirror=self.mirror,
|
||||
rotate=self.rotate)
|
||||
|
||||
def transform_coords(self, coords, offset, mirr, angle):
|
||||
"""Calculate coordinates after flip, rotate, and shift"""
|
||||
coordinate = []
|
||||
for item in coords:
|
||||
x = item[0]*math.cos(angle) - item[1]*mirr*math.sin(angle) + offset[0]
|
||||
y = item[0]*math.sin(angle) + item[1]*mirr*math.cos(angle) + offset[1]
|
||||
coordinate += [[x, y]]
|
||||
return coordinate
|
||||
|
||||
def normalize(self):
|
||||
""" Re-find the LL and UR points after a transform """
|
||||
(first,second)=self.boundary
|
||||
|
|
@ -67,7 +53,7 @@ class instance(geometry):
|
|||
def compute_boundary(self,offset=vector(0,0),mirror="",rotate=0):
|
||||
""" Transform with offset, mirror and rotation to get the absolute pin location.
|
||||
We must then re-find the ll and ur. The master is the cell instance. """
|
||||
(ll,ur) = [vector(0,0),vector(self.mod.width,self.mod.height)]
|
||||
(ll,ur) = [vector(0,0),vector(self.width,self.height)]
|
||||
if mirror=="MX":
|
||||
ll=ll.scale(1,-1)
|
||||
ur=ur.scale(1,-1)
|
||||
|
|
@ -123,6 +109,78 @@ class instance(geometry):
|
|||
def rx(self):
|
||||
""" Return the right edge """
|
||||
return self.boundary[1].x
|
||||
|
||||
|
||||
class instance(geometry):
|
||||
"""
|
||||
An instance of an instance/module with a specified location and
|
||||
rotation
|
||||
"""
|
||||
def __init__(self, name, mod, offset, mirror, rotate):
|
||||
"""Initializes an instance to represent a module"""
|
||||
geometry.__init__(self)
|
||||
debug.check(mirror not in ["R90","R180","R270"], "Please use rotation and not mirroring during instantiation.")
|
||||
|
||||
self.name = name
|
||||
self.mod = mod
|
||||
self.gds = mod.gds
|
||||
self.rotate = rotate
|
||||
self.offset = vector(offset).snap_to_grid()
|
||||
self.mirror = mirror
|
||||
self.width = mod.width
|
||||
self.height = mod.height
|
||||
self.compute_boundary(offset,mirror,rotate)
|
||||
|
||||
debug.info(4, "creating instance: " + self.name)
|
||||
|
||||
def get_blockages(self, layer, top=False):
|
||||
""" Retrieve rectangular blockages of all modules in this instance.
|
||||
Apply the transform of the instance placement to give absolute blockages."""
|
||||
angle = math.radians(float(self.rotate))
|
||||
mirr = 1
|
||||
if self.mirror=="R90":
|
||||
angle += math.radians(90.0)
|
||||
elif self.mirror=="R180":
|
||||
angle += math.radians(180.0)
|
||||
elif self.mirror=="R270":
|
||||
angle += math.radians(270.0)
|
||||
elif self.mirror=="MX":
|
||||
mirr = -1
|
||||
elif self.mirror=="MY":
|
||||
mirr = -1
|
||||
angle += math.radians(180.0)
|
||||
elif self.mirror=="XY":
|
||||
mirr = 1
|
||||
angle += math.radians(180.0)
|
||||
|
||||
if self.mod.is_library_cell:
|
||||
# For lib cells, block the whole thing except on metal3
|
||||
# since they shouldn't use metal3
|
||||
if layer==tech.layer["metal1"] or layer==tech.layer["metal2"]:
|
||||
return [self.transform_coords(self.mod.get_boundary(), self.offset, mirr, angle)]
|
||||
else:
|
||||
return []
|
||||
else:
|
||||
|
||||
blockages = self.mod.get_blockages(layer)
|
||||
new_blockages = []
|
||||
for b in blockages:
|
||||
new_blockages.append(self.transform_coords(b,self.offset, mirr, angle))
|
||||
return new_blockages
|
||||
|
||||
def gds_write_file(self, new_layout):
|
||||
"""Recursively writes all the sub-modules in this instance"""
|
||||
debug.info(4, "writing instance: " + self.name)
|
||||
# make sure to write out my module/structure
|
||||
# (it will only be written the first time though)
|
||||
self.mod.gds_write_file(self.gds)
|
||||
# now write an instance of my module/structure
|
||||
new_layout.addInstance(self.gds,
|
||||
offsetInMicrons=self.offset,
|
||||
mirror=self.mirror,
|
||||
rotate=self.rotate)
|
||||
|
||||
|
||||
|
||||
def get_pin(self,name,index=-1):
|
||||
""" Return an absolute pin that is offset and transformed based on
|
||||
|
|
@ -187,6 +245,10 @@ class path(geometry):
|
|||
coordinates=self.coordinates,
|
||||
width=self.path_width)
|
||||
|
||||
def get_blockages(self, layer):
|
||||
""" Fail since we don't support paths yet. """
|
||||
assert(0)
|
||||
|
||||
def __str__(self):
|
||||
""" override print function output """
|
||||
return "path: layer=" + self.layerNumber + " w=" + self.width
|
||||
|
|
@ -206,12 +268,12 @@ class label(geometry):
|
|||
self.text = text
|
||||
self.layerNumber = layerNumber
|
||||
self.offset = vector(offset).snap_to_grid()
|
||||
|
||||
if zoom<0:
|
||||
self.zoom = GDS["zoom"]
|
||||
self.zoom = tech.GDS["zoom"]
|
||||
else:
|
||||
self.zoom = zoom
|
||||
|
||||
|
||||
self.size = 0
|
||||
|
||||
debug.info(4,"creating label " + self.text + " " + str(self.layerNumber) + " " + str(self.offset))
|
||||
|
|
@ -226,6 +288,10 @@ class label(geometry):
|
|||
magnification=self.zoom,
|
||||
rotate=None)
|
||||
|
||||
def get_blockages(self, layer):
|
||||
""" Returns an empty list since text cannot be blockages. """
|
||||
return []
|
||||
|
||||
def __str__(self):
|
||||
""" override print function output """
|
||||
return "label: " + self.text + " layer=" + str(self.layerNumber)
|
||||
|
|
@ -246,10 +312,18 @@ class rectangle(geometry):
|
|||
self.size = vector(width, height).snap_to_grid()
|
||||
self.width = self.size.x
|
||||
self.height = self.size.y
|
||||
self.compute_boundary(offset,"",0)
|
||||
|
||||
debug.info(4, "creating rectangle (" + str(self.layerNumber) + "): "
|
||||
+ str(self.width) + "x" + str(self.height) + " @ " + str(self.offset))
|
||||
|
||||
|
||||
def get_blockages(self, layer):
|
||||
""" Returns a list of one rectangle if it is on this layer"""
|
||||
if self.layerNumber == layer:
|
||||
return [[self.offset, vector(self.offset.x+self.width,self.offset.y+self.height)]]
|
||||
else:
|
||||
return []
|
||||
|
||||
def gds_write_file(self, newLayout):
|
||||
"""Writes the rectangular shape to GDS"""
|
||||
|
|
|
|||
|
|
@ -43,10 +43,6 @@ class hierarchical_decoder(design.design):
|
|||
self.create_row_decoder()
|
||||
self.create_vertical_rail()
|
||||
self.route_vdd_gnd()
|
||||
# We only need to call the offset_all_coordinate function when there
|
||||
# are vertical metal rails.
|
||||
#if (self.num_inputs >= 4):
|
||||
# self.offset_all_coordinates()
|
||||
|
||||
def add_modules(self):
|
||||
self.inv = pinv()
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@ from tech import layer as techlayer
|
|||
import os
|
||||
from vector import vector
|
||||
from pin_layout import pin_layout
|
||||
import lef
|
||||
|
||||
class layout:
|
||||
class layout(lef.lef):
|
||||
"""
|
||||
Class consisting of a set of objs and instances for a module
|
||||
This provides a set of useful generic types for hierarchy
|
||||
|
|
@ -18,7 +19,8 @@ class layout:
|
|||
layout/netlist and perform LVS/DRC.
|
||||
"""
|
||||
|
||||
def __init__(self, name):
|
||||
def __init__(self, name):
|
||||
lef.lef.__init__(self, ["metal1", "metal2", "metal3"])
|
||||
self.name = name
|
||||
self.width = None
|
||||
self.height = None
|
||||
|
|
@ -26,7 +28,7 @@ class layout:
|
|||
self.objs = [] # Holds all other objects (labels, geometries, etc)
|
||||
self.pin_map = {} # Holds name->pin_layout map for all pins
|
||||
self.visited = False # Flag for traversing the hierarchy
|
||||
|
||||
self.is_library_cell = False # Flag for library cells
|
||||
self.gds_read()
|
||||
|
||||
############################################################
|
||||
|
|
@ -36,7 +38,6 @@ class layout:
|
|||
""" This function is called after everything is placed to
|
||||
shift the origin in the lowest left corner """
|
||||
offset = self.find_lowest_coords()
|
||||
#self.offset_attributes(offset)
|
||||
self.translate_all(offset)
|
||||
|
||||
def get_gate_offset(self, x_offset, height, inv_num):
|
||||
|
|
@ -59,19 +60,22 @@ class layout:
|
|||
def find_lowest_coords(self):
|
||||
"""Finds the lowest set of 2d cartesian coordinates within
|
||||
this layout"""
|
||||
# FIXME: don't depend on 1e9
|
||||
try:
|
||||
lowestx1 = min(rect.offset.x for rect in self.objs)
|
||||
lowesty1 = min(rect.offset.y for rect in self.objs)
|
||||
except:
|
||||
[lowestx1, lowesty1] = [1000000.0, 1000000.0]
|
||||
try:
|
||||
lowestx2 = min(inst.offset.x for inst in self.insts)
|
||||
lowesty2 = min(inst.offset.y for inst in self.insts)
|
||||
except:
|
||||
[lowestx2, lowesty2] = [1000000.0, 1000000.0]
|
||||
|
||||
lowestx1 = min(obj.lx() for obj in self.objs if obj.name!="label")
|
||||
lowesty1 = min(obj.by() for obj in self.objs if obj.name!="label")
|
||||
lowestx2 = min(inst.lx() for inst in self.insts)
|
||||
lowesty2 = min(inst.by() for inst in self.insts)
|
||||
return vector(min(lowestx1, lowestx2), min(lowesty1, lowesty2))
|
||||
|
||||
def find_highest_coords(self):
|
||||
"""Finds the highest set of 2d cartesian coordinates within
|
||||
this layout"""
|
||||
highestx1 = min(obj.rx() for obj in self.objs if obj.name!="label")
|
||||
highesty1 = min(obj.uy() for obj in self.objs if obj.name!="label")
|
||||
highestx2 = min(inst.rx() for inst in self.insts)
|
||||
highesty2 = min(inst.uy() for inst in self.insts)
|
||||
return vector(min(highestx1, highestx2), min(highesty1, highesty2))
|
||||
|
||||
|
||||
def translate_all(self, offset):
|
||||
"""
|
||||
|
|
@ -111,9 +115,9 @@ class layout:
|
|||
if height==0:
|
||||
height=drc["minwidth_{}".format(layer)]
|
||||
# negative layers indicate "unused" layers in a given technology
|
||||
layerNumber = techlayer[layer]
|
||||
if layerNumber >= 0:
|
||||
self.objs.append(geometry.rectangle(layerNumber, offset, width, height))
|
||||
layer_num = techlayer[layer]
|
||||
if layer_num >= 0:
|
||||
self.objs.append(geometry.rectangle(layer_num, offset, width, height))
|
||||
return self.objs[-1]
|
||||
return None
|
||||
|
||||
|
|
@ -124,10 +128,10 @@ class layout:
|
|||
if height==0:
|
||||
height=drc["minwidth_{}".format(layer)]
|
||||
# negative layers indicate "unused" layers in a given technology
|
||||
layerNumber = techlayer[layer]
|
||||
layer_num = techlayer[layer]
|
||||
corrected_offset = offset - vector(0.5*width,0.5*height)
|
||||
if layerNumber >= 0:
|
||||
self.objs.append(geometry.rectangle(layerNumber, corrected_offset, width, height))
|
||||
if layer_num >= 0:
|
||||
self.objs.append(geometry.rectangle(layer_num, corrected_offset, width, height))
|
||||
return self.objs[-1]
|
||||
return None
|
||||
|
||||
|
|
@ -259,9 +263,9 @@ class layout:
|
|||
"""Adds a text label on the given layer,offset, and zoom level"""
|
||||
# negative layers indicate "unused" layers in a given technology
|
||||
debug.info(5,"add label " + str(text) + " " + layer + " " + str(offset))
|
||||
layerNumber = techlayer[layer]
|
||||
if layerNumber >= 0:
|
||||
self.objs.append(geometry.label(text, layerNumber, offset, zoom))
|
||||
layer_num = techlayer[layer]
|
||||
if layer_num >= 0:
|
||||
self.objs.append(geometry.label(text, layer_num, offset, zoom))
|
||||
return self.objs[-1]
|
||||
return None
|
||||
|
||||
|
|
@ -272,9 +276,9 @@ class layout:
|
|||
import path
|
||||
# NOTE: (UNTESTED) add_path(...) is currently not used
|
||||
# negative layers indicate "unused" layers in a given technology
|
||||
#layerNumber = techlayer[layer]
|
||||
#if layerNumber >= 0:
|
||||
# self.objs.append(geometry.path(layerNumber, coordinates, width))
|
||||
#layer_num = techlayer[layer]
|
||||
#if layer_num >= 0:
|
||||
# self.objs.append(geometry.path(layer_num, coordinates, width))
|
||||
|
||||
path.path(obj=self,
|
||||
layer=layer,
|
||||
|
|
@ -390,6 +394,7 @@ class layout:
|
|||
# open the gds file if it exists or else create a blank layout
|
||||
if os.path.isfile(self.gds_file):
|
||||
debug.info(3, "opening %s" % self.gds_file)
|
||||
self.is_library_cell=True
|
||||
self.gds = gdsMill.VlsiLayout(units=GDS["unit"])
|
||||
reader = gdsMill.Gds2reader(self.gds)
|
||||
reader.loadFromFile(self.gds_file)
|
||||
|
|
@ -440,6 +445,49 @@ class layout:
|
|||
# self.gds.prepareForWrite()
|
||||
writer.writeToFile(gds_name)
|
||||
|
||||
def get_boundary(self):
|
||||
""" Return the lower-left and upper-right coordinates of boundary """
|
||||
# This assumes nothing spans outside of the width and height!
|
||||
return [vector(0,0), vector(self.width, self.height)]
|
||||
#return [self.find_lowest_coords(), self.find_highest_coords()]
|
||||
|
||||
def get_blockages(self, layer, top_level=False):
|
||||
"""
|
||||
Write all of the obstacles in the current (and children) modules to the lef file
|
||||
Do not write the pins since they aren't obstructions.
|
||||
"""
|
||||
if type(layer)==str:
|
||||
layer_num = techlayer[layer]
|
||||
else:
|
||||
layer_num = layer
|
||||
|
||||
blockages = []
|
||||
for i in self.objs:
|
||||
blockages += i.get_blockages(layer_num)
|
||||
for i in self.insts:
|
||||
blockages += i.get_blockages(layer_num)
|
||||
# Must add pin blockages to non-top cells
|
||||
if not top_level:
|
||||
blockages += self.get_pin_blockages(layer_num)
|
||||
return blockages
|
||||
|
||||
def get_pin_blockages(self, layer_num):
|
||||
""" Return the pin shapes as blockages for non-top-level blocks. """
|
||||
# FIXME: We don't have a body contact in ptx, so just ignore it for now
|
||||
import copy
|
||||
pin_names = copy.deepcopy(self.pins)
|
||||
if self.name.startswith("pmos") or self.name.startswith("nmos"):
|
||||
pin_names.remove("B")
|
||||
|
||||
blockages = []
|
||||
for pin_name in pin_names:
|
||||
pin_list = self.get_pins(pin_name)
|
||||
for pin in pin_list:
|
||||
if pin.layer_num==layer_num:
|
||||
blockages += [pin.rect]
|
||||
|
||||
return blockages
|
||||
|
||||
def pdf_write(self, pdf_name):
|
||||
# NOTE: Currently does not work (Needs further research)
|
||||
#self.pdf_name = self.name + ".pdf"
|
||||
|
|
@ -465,20 +513,22 @@ class layout:
|
|||
debug.info(0,
|
||||
"|==============================================================================|")
|
||||
debug.info(0,
|
||||
"|========= LIST OF OBJECTS (Rects) FOR: " + self.attr["name"])
|
||||
"|========= LIST OF OBJECTS (Rects) FOR: " + self.name)
|
||||
debug.info(0,
|
||||
"|==============================================================================|")
|
||||
for obj in self.objs:
|
||||
debug.info(0, "layer={0} : offset={1} : size={2}".format(
|
||||
obj.layerNumber, obj.offset, obj.size))
|
||||
debug.info(0, "layer={0} : offset={1} : size={2}".format(obj.layerNumber,
|
||||
obj.offset,
|
||||
obj.size))
|
||||
|
||||
debug.info(0,
|
||||
"|==============================================================================|")
|
||||
debug.info(0,
|
||||
"|========= LIST OF INSTANCES FOR: " +
|
||||
self.attr["name"])
|
||||
"|========= LIST OF INSTANCES FOR: " + self.name)
|
||||
debug.info(0,
|
||||
"|==============================================================================|")
|
||||
for inst in self.insts:
|
||||
debug.info(0, "name={0} : mod={1} : offset={2}".format(
|
||||
inst.name, inst.mod.name, inst.offset))
|
||||
debug.info(0, "name={0} : mod={1} : offset={2}".format(inst.name,
|
||||
inst.mod.name,
|
||||
inst.offset))
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ import debug
|
|||
import re
|
||||
import os
|
||||
import math
|
||||
import verilog
|
||||
|
||||
|
||||
class spice:
|
||||
class spice(verilog.verilog):
|
||||
"""
|
||||
This provides a set of useful generic types for hierarchy
|
||||
management. If a module is a custom designed cell, it will read from
|
||||
|
|
@ -19,7 +19,7 @@ class spice:
|
|||
|
||||
self.mods = [] # Holds subckts/mods for this module
|
||||
self.pins = [] # Holds the pins for this module
|
||||
|
||||
self.pin_type = {} # The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND
|
||||
# for each instance, this is the set of nets/nodes that map to the pins for this instance
|
||||
# THIS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the
|
||||
# Spice format)
|
||||
|
|
@ -31,13 +31,35 @@ class spice:
|
|||
# Spice circuit
|
||||
############################################################
|
||||
|
||||
def add_pin(self, name):
|
||||
"""Adds a pin to the pins list"""
|
||||
def add_pin(self, name, pin_type="INOUT"):
|
||||
""" Adds a pin to the pins list. Default type is INOUT signal. """
|
||||
self.pins.append(name)
|
||||
self.pin_type[name]=pin_type
|
||||
|
||||
def add_pin_list(self, pin_list):
|
||||
"""Adds a pin_list to the pins list"""
|
||||
self.pins = self.pins + pin_list
|
||||
def add_pin_list(self, pin_list, pin_type_list="INOUT"):
|
||||
""" Adds a pin_list to the pins list """
|
||||
# The type list can be a single type for all pins
|
||||
# or a list that is the same length as the pin list.
|
||||
if type(pin_type_list)==str:
|
||||
for pin in pin_list:
|
||||
self.add_pin(pin,pin_type_list)
|
||||
elif len(pin_type_list)==len(pin_list):
|
||||
for (pin,ptype) in zip(pin_list, pin_type_list):
|
||||
self.add_pin(pin,ptype)
|
||||
else:
|
||||
debug.error("Mismatch in type and pin list lengths.", -1)
|
||||
|
||||
def get_pin_type(self, name):
|
||||
""" Returns the type of the signal pin. """
|
||||
return self.pin_type[name]
|
||||
|
||||
def get_pin_dir(self, name):
|
||||
""" Returns the direction of the pin. (Supply/ground are INOUT). """
|
||||
if self.pin_type[name] in ["POWER","GROUND"]:
|
||||
return "INOUT"
|
||||
else:
|
||||
return self.pin_type[name]
|
||||
|
||||
|
||||
def add_mod(self, mod):
|
||||
"""Adds a subckt/submodule to the subckt hierarchy"""
|
||||
|
|
|
|||
320
compiler/lef.py
320
compiler/lef.py
|
|
@ -3,6 +3,7 @@ import tech
|
|||
import globals
|
||||
import math
|
||||
import debug
|
||||
import datetime
|
||||
from collections import defaultdict
|
||||
|
||||
class lef:
|
||||
|
|
@ -10,246 +11,105 @@ class lef:
|
|||
SRAM LEF Class open GDS file, read pins information, obstruction
|
||||
and write them to LEF file
|
||||
"""
|
||||
def __init__(self, gdsName, lefName, sr):
|
||||
self.gdsName = gdsName
|
||||
self.lef = open(lefName,"w")
|
||||
self.sr = sr
|
||||
self.myLayout = gdsMill.VlsiLayout(units=tech.GDS["unit"])
|
||||
self.reader = gdsMill.Gds2reader(self.myLayout)
|
||||
self.reader.loadFromFile(gdsName)
|
||||
self.unit = float(self.myLayout.info['units'][0])
|
||||
self.layer = ["metal1", "via1", "metal2", "via2", "metal3"]
|
||||
|
||||
self.create()
|
||||
def __init__(self,layers):
|
||||
# LEF db units per micron
|
||||
self.lef_units = 1000
|
||||
# These are the layers of the obstructions
|
||||
self.lef_layers = layers
|
||||
|
||||
def lef_write(self, lef_name):
|
||||
"""Write the entire lef of the object to the file."""
|
||||
debug.info(3, "Writing to {0}".format(lef_name))
|
||||
|
||||
self.indent = "" # To maintain the indent level easily
|
||||
|
||||
self.lef = open(lef_name,"w")
|
||||
self.lef_write_header()
|
||||
for pin in self.pins:
|
||||
self.lef_write_pin(pin)
|
||||
self.lef_write_obstructions()
|
||||
self.lef_write_footer()
|
||||
self.lef.close()
|
||||
|
||||
def create(self):
|
||||
"""Write to LEF file"""
|
||||
power_pin_name = self.powerPinName()
|
||||
ground_pin_name = self.groundPinName()
|
||||
input_pin_name = self.inputPinName()
|
||||
inout_pin_name = self.inoutPinName()
|
||||
|
||||
self.writeLefHeader()
|
||||
def lef_write_header(self):
|
||||
""" Header of LEF file """
|
||||
self.lef.write("VERSION 5.4 ;\n")
|
||||
self.lef.write("NAMESCASESENSITIVE ON ;\n")
|
||||
self.lef.write("BUSBITCHARS \"[]\" ;\n")
|
||||
self.lef.write("DIVIDERCHAR \"/\" ;\n")
|
||||
self.lef.write("UNITS\n")
|
||||
self.lef.write(" DATABASE MICRONS {0} ;\n".format(self.lef_units))
|
||||
self.lef.write("END UNITS\n")
|
||||
|
||||
self.lef.write("SITE MacroSite\n")
|
||||
self.indent += " "
|
||||
self.lef.write("{0}CLASS Core ;\n".format(self.indent))
|
||||
self.lef.write("{0}SIZE {1} by {2} ;\n".format(self.indent,
|
||||
self.lef_units*self.width,
|
||||
self.lef_units*self.height))
|
||||
self.indent = self.indent[:-3]
|
||||
self.lef.write("END MacroSite\n")
|
||||
|
||||
for pin in power_pin_name:
|
||||
self.writePin(pin, 1)
|
||||
self.lef.write("{0}MACRO {1}\n".format(self.indent,self.name))
|
||||
self.indent += " "
|
||||
self.lef.write("{0}CLASS BLOCK ;\n".format(self.indent))
|
||||
self.lef.write("{0}SIZE {1} BY {2} ;\n" .format(self.indent,
|
||||
self.lef_units*self.width,
|
||||
self.lef_units*self.height))
|
||||
self.lef.write("{0}SYMMETRY X Y R90 ;\n".format(self.indent))
|
||||
self.lef.write("{0}SITE MacroSite ;\n".format(self.indent))
|
||||
|
||||
for pin in ground_pin_name:
|
||||
self.writePin(pin, 2)
|
||||
|
||||
for pin in inout_pin_name:
|
||||
self.writePin(pin, 3)
|
||||
|
||||
for pin in input_pin_name:
|
||||
self.writePin(pin,4)
|
||||
|
||||
self.lef.write(" OBS\n")
|
||||
for lay in self.layer:
|
||||
self.lef.write(" LAYER {0} ;\n".format(lay))
|
||||
self.writeObstruct(self.sr.name, lay, mirr = 1, angle = math.radians(float(0)), xyShift = (0, 0))
|
||||
self.lef.write(" END\n")
|
||||
|
||||
self.writeLefFooter()
|
||||
|
||||
def coordinatesTranslate(self, coord, mirr, angle, xyShift):
|
||||
"""Calculate coordinates after flip, rotate, and shift"""
|
||||
coordinate = []
|
||||
for item in coord:
|
||||
x = (item[0]*math.cos(angle)-item[1]*mirr*math.sin(angle)+xyShift[0])
|
||||
y = (item[0]*math.sin(angle)+item[1]*mirr*math.cos(angle)+xyShift[1])
|
||||
coordinate += [(x, y)]
|
||||
return coordinate
|
||||
|
||||
def writeObstruct(self, sr, lay, mirr = 1, angle = math.radians(float(0)), xyShift = (0, 0)):
|
||||
"""Recursive write boundaries on each Structure in GDS file to LEF"""
|
||||
for boundary in self.myLayout.structures[sr].boundaries:
|
||||
coordTrans = self.coordinatesTranslate(boundary.coordinates, mirr, angle, xyShift)
|
||||
rect = self.minMaxCoord(coordTrans)
|
||||
lay_convert = tech.layer[lay]
|
||||
if boundary.drawingLayer == lay_convert:
|
||||
self.lef.write(" RECT ")
|
||||
for item in rect:
|
||||
self.lef.write(" {0} {1}".format(item[0]*self.unit, item[1]*self.unit))
|
||||
self.lef.write(" ;\n")
|
||||
|
||||
for sref in self.myLayout.structures[sr].srefs:
|
||||
sMirr = 1
|
||||
if sref.transFlags[0] == True:
|
||||
sMirr = -1
|
||||
sAngle = math.radians(float(0))
|
||||
if sref.rotateAngle:
|
||||
sAngle = math.radians(float(sref.rotateAngle))
|
||||
sAngle += angle
|
||||
x = sref.coordinates[0]
|
||||
y = sref.coordinates[1]
|
||||
newX = (x)*math.cos(angle) - mirr*(y)*math.sin(angle) + xyShift[0]
|
||||
newY = (x)*math.sin(angle) + mirr*(y)*math.cos(angle) + xyShift[1]
|
||||
sxyShift = (newX, newY)
|
||||
self.writeObstruct(sref.sName, lay,sMirr, sAngle, sxyShift)
|
||||
|
||||
def writePinCoord(self, sr, pinName, pinLayer, pinCoord, mirr = 1,
|
||||
angle = math.radians(float(0)), xyShift = (0, 0)):
|
||||
"""Write PIN information to LEF"""
|
||||
for boundary in self.myLayout.structures[sr].boundaries:
|
||||
if (pinLayer == boundary.drawingLayer):
|
||||
coordTrans = self.coordinatesTranslate(boundary.coordinates, mirr, angle, xyShift)
|
||||
rect = self.minMaxCoord(coordTrans)
|
||||
if self.pointInsideRect(pinCoord, rect):
|
||||
self.lef.write(" RECT ")
|
||||
for item in rect:
|
||||
self.lef.write(" {0} {1}".format(item[0]*self.unit, item[1]*self.unit))
|
||||
self.lef.write(" ;\n")
|
||||
|
||||
for sref in self.myLayout.structures[sr].srefs:
|
||||
sMirr = 1
|
||||
if sref.transFlags[0] == True:
|
||||
sMirr = -1
|
||||
sAngle = math.radians(float(0))
|
||||
if sref.rotateAngle:
|
||||
sAngle = math.radians(float(sref.rotateAngle))
|
||||
sAngle += angle
|
||||
x = sref.coordinates[0]
|
||||
y = sref.coordinates[1]
|
||||
newX = (x*math.cos(angle) - mirr*y*math.sin(angle)) + xyShift[0]
|
||||
newY = (x*math.sin(angle) + mirr*y*math.cos(angle)) + xyShift[1]
|
||||
sxyShift = (newX, newY)
|
||||
self.writePinCoord(sref.sName, pinName, pinLayer, pinCoord, sMirr, sAngle, sxyShift)
|
||||
|
||||
def pinLayerCoord(self, sr, pinName):
|
||||
"""Get Pin Layer and Coordinates {layer:[coord1, coord2, ...]}"""
|
||||
layCoord = defaultdict(list)
|
||||
for text in self.myLayout.structures[self.sr.name].texts:
|
||||
if text.textString.strip('\x00') == pinName:
|
||||
k = text.drawingLayer
|
||||
v = text.coordinates
|
||||
d = {k: v}
|
||||
layCoord.setdefault(k, []).append(v)
|
||||
return layCoord
|
||||
|
||||
def minMaxCoord(self, coordTrans):
|
||||
"""Find the lowest and highest conner of a Rectangle"""
|
||||
coordinate = []
|
||||
minx = min(coordTrans[0][0], coordTrans[1][0], coordTrans[2][0], coordTrans[3][0])
|
||||
maxx = max(coordTrans[0][0], coordTrans[1][0], coordTrans[2][0], coordTrans[3][0])
|
||||
miny = min(coordTrans[0][1], coordTrans[1][1], coordTrans[2][1], coordTrans[3][1])
|
||||
maxy = max(coordTrans[0][1], coordTrans[1][1], coordTrans[2][1], coordTrans[3][1])
|
||||
coordinate += [(minx, miny)]
|
||||
coordinate += [(maxx, maxy)]
|
||||
return coordinate
|
||||
|
||||
def pointInsideRect(self, p, rect):
|
||||
"""Check if a point is inside a rectangle"""
|
||||
inside = False
|
||||
if ((p[0][0] >= rect[0][0])& (p[0][0] <= rect[1][0])
|
||||
& (p[0][1] >= rect[0][1]) &(p[0][1] <= rect[1][1])):
|
||||
inside = not inside
|
||||
return inside
|
||||
|
||||
def writeLefHeader(self):
|
||||
"""Heafer of LEF file"""
|
||||
coord = self.lowestLeftCorner(self.sr.name, 1, 0.0, (0, 0), [], [], [], [])
|
||||
self.lef.write("MACRO {0}\n".format(self.sr.name))
|
||||
self.lef.write(" CLASS RING ;\n")
|
||||
self.lef.write(" ORIGIN {0} {1} ;\n".format(-coord[0][0]*self.unit, coord[0][1]*self.unit))
|
||||
self.lef.write(" FOREIGN sram {0} {1} ;\n"
|
||||
.format(0.0, 0.0))
|
||||
self.lef.write(" SIZE {0} BY {1} ;\n"
|
||||
.format(self.sr.width, self.sr.height))
|
||||
self.lef.write(" SYMMETRY X Y R90 ;\n")
|
||||
|
||||
def writeLefFooter(self):
|
||||
self.lef.write("END {0}\n".format(self.sr.name))
|
||||
|
||||
def lef_write_footer(self):
|
||||
self.lef.write("{0}END {1}\n".format(self.indent,self.name))
|
||||
self.indent = self.indent[:-3]
|
||||
self.lef.write("END LIBRARY\n")
|
||||
|
||||
def powerPinName(self):
|
||||
return ["vdd"]
|
||||
|
||||
def groundPinName(self):
|
||||
return ["gnd"]
|
||||
|
||||
def inputPinName(self):
|
||||
input_pin_name = []
|
||||
for i in range(self.sr.addr_size + int(math.log(self.sr.num_banks, 2))):
|
||||
input_pin_name.append("ADDR[{0}]".format(i))
|
||||
input_pin_name.append("CSb")
|
||||
input_pin_name.append("OEb")
|
||||
input_pin_name.append("WEb")
|
||||
input_pin_name.append("clk")
|
||||
return input_pin_name
|
||||
def lef_write_pin(self, name):
|
||||
pin_dir = self.get_pin_dir(name)
|
||||
pin_type = self.get_pin_type(name)
|
||||
self.lef.write("{0}PIN {1}\n".format(self.indent,name))
|
||||
self.indent += " "
|
||||
|
||||
def inoutPinName(self):
|
||||
inout_pin_name = []
|
||||
for i in range(self.sr.word_size):
|
||||
inout_pin_name.append("DATA[{0}]".format(i))
|
||||
self.lef.write("{0}DIRECTION {1} ;\n".format(self.indent,pin_dir))
|
||||
|
||||
if pin_type in ["POWER","GROUND"]:
|
||||
self.lef.write("{0}USE {1} ; \n".format(self.indent,pin_type))
|
||||
self.lef.write("{0}SHAPE ABUTMENT ; \n".format(self.indent))
|
||||
|
||||
return inout_pin_name
|
||||
|
||||
def writePin(self, pinName, typ):
|
||||
self.lef.write(" PIN {0}\n".format(pinName))
|
||||
if typ == 1:
|
||||
self.lef.write(" DIRECTION INOUT ;\n")
|
||||
self.lef.write(" USE POWER ;\n")
|
||||
self.lef.write(" SHAPE ABUTMENT ;\n")
|
||||
self.lef.write(" PORT\n")
|
||||
elif typ == 2:
|
||||
self.lef.write(" DIRECTION INOUT ;\n")
|
||||
self.lef.write(" USE GROUND ;\n")
|
||||
self.lef.write(" SHAPE ABUTMENT ;\n")
|
||||
self.lef.write(" PORT\n")
|
||||
elif typ == 3:
|
||||
self.lef.write(" DIRECTION INOUT ;\n")
|
||||
self.lef.write(" PORT\n")
|
||||
elif typ == 4:
|
||||
self.lef.write(" DIRECTION INPUT ;\n")
|
||||
self.lef.write(" PORT\n")
|
||||
else:
|
||||
debug.error("Invalid pin type on pin {0}".format(pinName))
|
||||
self.lef.write("{0}PORT\n".format(self.indent))
|
||||
self.indent += " "
|
||||
|
||||
pin_layer_coord = self.pinLayerCoord(self.sr.name, pinName)
|
||||
for pinLayer in pin_layer_coord:
|
||||
lay = [key for key, value in tech.layer.iteritems() if value == pinLayer][0]
|
||||
self.lef.write(" LAYER {0} ;\n".format(lay))
|
||||
for pinCoord in pin_layer_coord[pinLayer]:
|
||||
self.writePinCoord(self.sr.name, pinName, pinLayer, pinCoord,
|
||||
mirr = 1,angle = math.radians(float(0)), xyShift = (0, 0))
|
||||
self.lef.write(" END\n")
|
||||
self.lef.write(" END {0}\n".format(pinName))
|
||||
# We could sort these together to minimize different layer sections, but meh.
|
||||
pin_list = self.get_pins(name)
|
||||
for pin in pin_list:
|
||||
self.lef.write("{0}LAYER {1} ;\n".format(self.indent,pin.layer))
|
||||
self.lef_write_rect(pin.rect)
|
||||
|
||||
# End the PORT
|
||||
self.indent = self.indent[:-3]
|
||||
self.lef.write("{0}END\n".format(self.indent))
|
||||
|
||||
def lowestLeftCorner(self, sr, mirr = 1, angle = math.radians(float(0)), xyShift = (0, 0), listMinX = [], listMinY = [], listMaxX = [], listMaxY =[]):
|
||||
"""Recursive find a lowest left conner on each Structure in GDS file"""
|
||||
for boundary in self.myLayout.structures[sr].boundaries:
|
||||
coordTrans = self.coordinatesTranslate(boundary.coordinates, mirr, angle, xyShift)
|
||||
minX = min(coordTrans[0][0], coordTrans[1][0], coordTrans[2][0], coordTrans[3][0])
|
||||
minY = min(coordTrans[0][1], coordTrans[1][1], coordTrans[2][1], coordTrans[3][1])
|
||||
maxX = max(coordTrans[0][0], coordTrans[1][0], coordTrans[2][0], coordTrans[3][0])
|
||||
maxY = max(coordTrans[0][1], coordTrans[1][1], coordTrans[2][1], coordTrans[3][1])
|
||||
listMinX.append(minX)
|
||||
listMinY.append(minY)
|
||||
listMaxX.append(maxX)
|
||||
listMaxY.append(maxY)
|
||||
|
||||
for sref in self.myLayout.structures[sr].srefs:
|
||||
sMirr = 1
|
||||
if sref.transFlags[0] == True:
|
||||
sMirr = -1
|
||||
sAngle = math.radians(float(0))
|
||||
if sref.rotateAngle:
|
||||
sAngle = math.radians(float(sref.rotateAngle))
|
||||
sAngle += angle
|
||||
x = sref.coordinates[0]
|
||||
y = sref.coordinates[1]
|
||||
newX = (x*math.cos(angle) - mirr*y*math.sin(angle)) + xyShift[0]
|
||||
newY = (x*math.sin(angle) + mirr*y*math.cos(angle)) + xyShift[1]
|
||||
sxyShift = (newX, newY)
|
||||
self.lowestLeftCorner(sref.sName, sMirr, sAngle, sxyShift, listMinX, listMinY, listMaxX, listMaxY)
|
||||
coordinate = []
|
||||
lowestX = min(listMinX)
|
||||
lowestY = min(float(item) for item in listMinY)
|
||||
highestX = max(float(item) for item in listMaxX)
|
||||
highestY = max(float(item) for item in listMaxY)
|
||||
coordinate.append((lowestX, lowestY))
|
||||
coordinate.append((highestX, highestY))
|
||||
return coordinate
|
||||
# End the PIN
|
||||
self.indent = self.indent[:-3]
|
||||
self.lef.write("{0}END {1}\n".format(self.indent,name))
|
||||
|
||||
def lef_write_obstructions(self):
|
||||
""" Write all the obstructions on each layer """
|
||||
self.lef.write("{0}OBS\n".format(self.indent))
|
||||
for layer in self.lef_layers:
|
||||
self.lef.write("{0}LAYER {1} ;\n".format(self.indent,layer))
|
||||
self.indent += " "
|
||||
blockages = self.get_blockages(layer,True)
|
||||
for b in blockages:
|
||||
self.lef_write_rect(b)
|
||||
self.indent = self.indent[:-3]
|
||||
self.lef.write("{0}END\n".format(self.indent))
|
||||
|
||||
def lef_write_rect(self, rect):
|
||||
""" Write a LEF rectangle """
|
||||
self.lef.write("{0}RECT ".format(self.indent))
|
||||
for item in rect:
|
||||
self.lef.write(" {0} {1}".format(self.lef_units*item[0], self.lef_units*item[1]))
|
||||
self.lef.write(" ;\n")
|
||||
|
|
|
|||
|
|
@ -64,16 +64,6 @@ print("Output files are " + OPTS.output_name + ".(sp|gds|v|lib|lef)")
|
|||
print("Technology: {0}".format(OPTS.tech_name))
|
||||
print("Word size: {0}\nWords: {1}\nBanks: {2}".format(word_size,num_words,num_banks))
|
||||
|
||||
if not OPTS.check_lvsdrc:
|
||||
print("DRC/LVS/PEX checking is disabled.")
|
||||
|
||||
if OPTS.analytical_delay:
|
||||
print("Using analytical delay models (no characterization)")
|
||||
else:
|
||||
print("Performing simulation-based characterization with {}".format(OPTS.spice_name))
|
||||
if OPTS.trim_netlist:
|
||||
print("Trimming netlist to speed up characterization (sacrificing some accuracy).")
|
||||
|
||||
# only start importing modules after we have the config file
|
||||
import verify
|
||||
import sram
|
||||
|
|
@ -81,7 +71,8 @@ import sram
|
|||
start_time = datetime.datetime.now()
|
||||
last_time = start_time
|
||||
print_time("Start",datetime.datetime.now())
|
||||
|
||||
if not OPTS.check_lvsdrc:
|
||||
print("DRC/LVS/PEX checking is disabled.")
|
||||
# import SRAM test generation
|
||||
s = sram.sram(word_size=word_size,
|
||||
num_words=num_words,
|
||||
|
|
@ -110,6 +101,13 @@ if OPTS.use_pex:
|
|||
from characterizer import lib
|
||||
libname = OPTS.output_path + s.name + ".lib"
|
||||
print("LIB: Writing to {0}".format(libname))
|
||||
if OPTS.analytical_delay:
|
||||
print("Using analytical delay models (no characterization)")
|
||||
else:
|
||||
if OPTS.spice_name!="":
|
||||
print("Performing simulation-based characterization with {}".format(OPTS.spice_name))
|
||||
if OPTS.trim_netlist:
|
||||
print("Trimming netlist to speed up characterization.")
|
||||
lib.lib(libname,s,sram_file)
|
||||
last_time=print_time("Characterization", datetime.datetime.now(), last_time)
|
||||
|
||||
|
|
@ -120,18 +118,16 @@ s.gds_write(gdsname)
|
|||
last_time=print_time("GDS", datetime.datetime.now(), last_time)
|
||||
|
||||
# Create a LEF physical model
|
||||
import lef
|
||||
lefname = OPTS.output_path + s.name + ".lef"
|
||||
print("LEF: Writing to {0}".format(lefname))
|
||||
lef.lef(gdsname,lefname,s)
|
||||
last_time=print_time("LEF writing", datetime.datetime.now(), last_time)
|
||||
s.lef_write(lefname)
|
||||
last_time=print_time("LEF", datetime.datetime.now(), last_time)
|
||||
|
||||
# Write a verilog model
|
||||
import verilog
|
||||
vname = OPTS.output_path + s.name + ".v"
|
||||
print("Verilog: Writing to {0}".format(vname))
|
||||
verilog.verilog(vname,s)
|
||||
last_time=print_time("Verilog writing", datetime.datetime.now(), last_time)
|
||||
s.verilog_write(vname)
|
||||
last_time=print_time("Verilog", datetime.datetime.now(), last_time)
|
||||
|
||||
globals.end_openram()
|
||||
print_time("End",datetime.datetime.now(), start_time)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ class options(optparse.Values):
|
|||
use_pex = False
|
||||
# Remove noncritical memory cells for characterization speed-up
|
||||
trim_netlist = True
|
||||
# Use detailed LEF blockages
|
||||
detailed_blockages = True
|
||||
# Define the output file paths
|
||||
output_path = ""
|
||||
# Define the output file base name
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ class pin_layout:
|
|||
self.layer = layer.keys()[layer.values().index(layer_name_num)]
|
||||
else:
|
||||
self.layer=layer_name_num
|
||||
self.layer_num = layer[self.layer]
|
||||
|
||||
def __str__(self):
|
||||
""" override print function output """
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ class precharge(pgate.pgate):
|
|||
self.lower_pmos_inst=self.add_inst(name="lower_pmos",
|
||||
mod=self.pmos,
|
||||
offset=self.lower_pmos_position)
|
||||
self.connect_inst(["bl", "clk", "br", "vdd"])
|
||||
self.connect_inst(["bl", "clk", "BR", "vdd"])
|
||||
|
||||
# adds the upper pmos(s) to layout
|
||||
ydiff = self.pmos.height + 2*self.m1_space + contact.poly.width
|
||||
|
|
@ -150,7 +150,7 @@ class precharge(pgate.pgate):
|
|||
"""Adds both bit-line and bit-line-bar to the module"""
|
||||
# adds the BL on metal 2
|
||||
offset = vector(self.bitcell.get_pin("BL").cx(),0) - vector(0.5 * self.m2_width,0)
|
||||
self.add_layout_pin(text="BL",
|
||||
self.add_layout_pin(text="bl",
|
||||
layer="metal2",
|
||||
offset=offset,
|
||||
width=drc['minwidth_metal2'],
|
||||
|
|
@ -158,7 +158,7 @@ class precharge(pgate.pgate):
|
|||
|
||||
# adds the BR on metal 2
|
||||
offset = vector(self.bitcell.get_pin("BR").cx(),0) - vector(0.5 * self.m2_width,0)
|
||||
self.add_layout_pin(text="BR",
|
||||
self.add_layout_pin(text="br",
|
||||
layer="metal2",
|
||||
offset=offset,
|
||||
width=drc['minwidth_metal2'],
|
||||
|
|
@ -166,10 +166,10 @@ class precharge(pgate.pgate):
|
|||
|
||||
def connect_to_bitlines(self):
|
||||
self.add_bitline_contacts()
|
||||
self.connect_pmos(self.lower_pmos_inst.get_pin("S"),self.get_pin("BL"))
|
||||
self.connect_pmos(self.lower_pmos_inst.get_pin("D"),self.get_pin("BR"))
|
||||
self.connect_pmos(self.upper_pmos1_inst.get_pin("S"),self.get_pin("BL"))
|
||||
self.connect_pmos(self.upper_pmos2_inst.get_pin("D"),self.get_pin("BR"))
|
||||
self.connect_pmos(self.lower_pmos_inst.get_pin("S"),self.get_pin("bl"))
|
||||
self.connect_pmos(self.lower_pmos_inst.get_pin("D"),self.get_pin("br"))
|
||||
self.connect_pmos(self.upper_pmos1_inst.get_pin("S"),self.get_pin("bl"))
|
||||
self.connect_pmos(self.upper_pmos2_inst.get_pin("D"),self.get_pin("br"))
|
||||
|
||||
|
||||
def add_bitline_contacts(self):
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ class precharge_array(design.design):
|
|||
width=self.width,
|
||||
height=drc["minwidth_metal1"])
|
||||
|
||||
#self.offset_all_coordinates()
|
||||
|
||||
def add_insts(self):
|
||||
"""Creates a precharge array by horizontally tiling the precharge cell"""
|
||||
|
|
@ -60,13 +59,13 @@ class precharge_array(design.design):
|
|||
inst=self.add_inst(name=name,
|
||||
mod=self.pc_cell,
|
||||
offset=offset)
|
||||
bl_pin = inst.get_pin("BL")
|
||||
bl_pin = inst.get_pin("bl")
|
||||
self.add_layout_pin(text="bl[{0}]".format(i),
|
||||
layer="metal2",
|
||||
offset=bl_pin.ll(),
|
||||
width=drc["minwidth_metal2"],
|
||||
height=bl_pin.height())
|
||||
br_pin = inst.get_pin("BR")
|
||||
br_pin = inst.get_pin("br")
|
||||
self.add_layout_pin(text="br[{0}]".format(i),
|
||||
layer="metal2",
|
||||
offset=br_pin.ll(),
|
||||
|
|
|
|||
|
|
@ -45,8 +45,6 @@ class sense_amp_array(design.design):
|
|||
|
||||
self.add_sense_amp()
|
||||
self.connect_rails()
|
||||
#self.offset_all_coordinates()
|
||||
|
||||
|
||||
|
||||
def add_sense_amp(self):
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ class single_level_column_mux(design.design):
|
|||
""" Connect the poly gate of the two pass transistors """
|
||||
|
||||
height=self.nmos2.get_pin("G").uy() - self.nmos1.get_pin("G").by()
|
||||
self.add_layout_pin(text="col_addr",
|
||||
self.add_layout_pin(text="sel",
|
||||
layer="poly",
|
||||
offset=self.nmos1.get_pin("G").ll(),
|
||||
height=height)
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ class single_level_column_mux_array(design.design):
|
|||
# which select bit should this column connect to depends on the position in the word
|
||||
sel_index = col % self.words_per_row
|
||||
# Add the column x offset to find the right select bit
|
||||
gate_offset = self.mux_inst[col].get_pin("col_addr").bc()
|
||||
gate_offset = self.mux_inst[col].get_pin("sel").bc()
|
||||
# height to connect the gate to the correct horizontal row
|
||||
sel_height = self.get_pin("sel[{}]".format(sel_index)).by()
|
||||
# use the y offset from the sel pin and the x offset from the gate
|
||||
|
|
|
|||
|
|
@ -67,6 +67,11 @@ class sram(design.design):
|
|||
# Can remove the following, but it helps for debug!
|
||||
self.add_lvs_correspondence_points()
|
||||
|
||||
self.offset_all_coordinates()
|
||||
sizes = self.find_highest_coords()
|
||||
self.width = sizes[0]
|
||||
self.height = sizes[1]
|
||||
|
||||
self.DRC_LVS()
|
||||
|
||||
def compute_sizes(self):
|
||||
|
|
@ -131,15 +136,17 @@ class sram(design.design):
|
|||
""" Add pins for entire SRAM. """
|
||||
|
||||
for i in range(self.word_size):
|
||||
self.add_pin("DATA[{0}]".format(i))
|
||||
self.add_pin("DATA[{0}]".format(i),"INOUT")
|
||||
for i in range(self.addr_size):
|
||||
self.add_pin("ADDR[{0}]".format(i))
|
||||
self.add_pin("ADDR[{0}]".format(i),"INPUT")
|
||||
|
||||
# These are used to create the physical pins too
|
||||
self.control_logic_inputs=["CSb", "WEb", "OEb", "clk"]
|
||||
self.control_logic_outputs=["s_en", "w_en", "tri_en", "tri_en_bar", "clk_bar", "clk_buf"]
|
||||
|
||||
for pin in self.control_logic_inputs+["vdd","gnd"]:
|
||||
self.add_pin(pin)
|
||||
self.add_pin_list(self.control_logic_inputs,"INPUT")
|
||||
self.add_pin("vdd","POWER")
|
||||
self.add_pin("gnd","GROUND")
|
||||
|
||||
def create_layout(self):
|
||||
""" Layout creation """
|
||||
|
|
@ -221,7 +228,6 @@ class sram(design.design):
|
|||
self.add_path("metal3",[pin_pos,rail_pos])
|
||||
self.add_via_center(("metal2","via2","metal3"),rail_pos)
|
||||
|
||||
# connect the horizontal control bus to the vertical bus
|
||||
|
||||
|
||||
def route_four_banks(self):
|
||||
|
|
|
|||
|
|
@ -38,8 +38,7 @@ class lib_test(unittest.TestCase):
|
|||
|
||||
# let's diff the result with a golden model
|
||||
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
|
||||
# Randomly decided 1% difference between spice simulators is ok.
|
||||
self.assertEqual(isapproxdiff(libname,golden,0.01),True)
|
||||
self.assertEqual(isapproxdiff(libname,golden,0.15),True)
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
|
|
|
|||
|
|
@ -36,14 +36,13 @@ class lib_test(unittest.TestCase):
|
|||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
s.sp_write(tempspice)
|
||||
|
||||
filename = s.name + ".lib"
|
||||
filename = s.name + "_pruned.lib"
|
||||
libname = OPTS.openram_temp + filename
|
||||
lib.lib(libname=libname,sram=s,spfile=tempspice,use_model=False)
|
||||
|
||||
# let's diff the result with a golden model
|
||||
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
|
||||
# 15% worked in freepdk, but scmos needed 20%
|
||||
self.assertEqual(isapproxdiff(libname,golden,0.20),True)
|
||||
self.assertEqual(isapproxdiff(libname,golden,0.30),True)
|
||||
|
||||
OPTS.analytical_delay = True
|
||||
reload(characterizer)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class lib_test(unittest.TestCase):
|
|||
|
||||
# let's diff the result with a golden model
|
||||
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
|
||||
self.assertEqual(isapproxdiff(libname,golden,0.25),True)
|
||||
self.assertEqual(isapproxdiff(libname,golden,0.15),True)
|
||||
|
||||
OPTS.analytical_delay = True
|
||||
OPTS.trim_netlist = True
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ class lef_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = False
|
||||
|
||||
import sram
|
||||
import lef
|
||||
|
||||
debug.info(1, "Testing LEF for sample 2 bit, 16 words SRAM with 1 bank")
|
||||
s = sram.sram(word_size=2,
|
||||
|
|
@ -36,7 +35,7 @@ class lef_test(unittest.TestCase):
|
|||
gdsname = OPTS.openram_temp + gdsfile
|
||||
lefname = OPTS.openram_temp + leffile
|
||||
s.gds_write(gdsname)
|
||||
lef.lef(gdsname,lefname,s)
|
||||
s.lef_write(lefname)
|
||||
|
||||
# let's diff the result with a golden model
|
||||
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),leffile)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ class verilog_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = False
|
||||
|
||||
import sram
|
||||
import verilog
|
||||
|
||||
debug.info(1, "Testing Verilog for sample 2 bit, 16 words SRAM with 1 bank")
|
||||
s = sram.sram(word_size=2,
|
||||
|
|
@ -33,7 +32,7 @@ class verilog_test(unittest.TestCase):
|
|||
|
||||
vfile = s.name + ".v"
|
||||
vname = OPTS.openram_temp + vfile
|
||||
verilog.verilog(vname,s)
|
||||
s.verilog_write(vname)
|
||||
|
||||
|
||||
# let's diff the result with a golden model
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -74,7 +74,7 @@ cell (sram_2_16_1_freepdk45){
|
|||
dont_use : true;
|
||||
map_only : true;
|
||||
dont_touch : true;
|
||||
area : 696.39825;
|
||||
area : 0.023625;
|
||||
|
||||
bus(DATA){
|
||||
bus_type : DATA;
|
||||
|
|
@ -92,10 +92,10 @@ cell (sram_2_16_1_freepdk45){
|
|||
internal_power(){
|
||||
when : "OEb & !clk";
|
||||
rise_power(scalar){
|
||||
values("0.0308667");
|
||||
values("0.027781");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("0.0304125");
|
||||
values("0.026752");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
|
|
@ -129,10 +129,10 @@ cell (sram_2_16_1_freepdk45){
|
|||
internal_power(){
|
||||
when : "!OEb & !clk";
|
||||
rise_power(scalar){
|
||||
values("0.0362061");
|
||||
values("0.031198");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("0.0364614");
|
||||
values("0.031252");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
|
|
@ -140,23 +140,23 @@ cell (sram_2_16_1_freepdk45){
|
|||
related_pin : "clk";
|
||||
timing_type : falling_edge;
|
||||
cell_rise(CELL_TABLE) {
|
||||
values("0.047, 0.048, 0.055",\
|
||||
"0.048, 0.049, 0.056",\
|
||||
"0.053, 0.054, 0.061");
|
||||
values("0.046, 0.047, 0.054",\
|
||||
"0.047, 0.047, 0.054",\
|
||||
"0.052, 0.052, 0.059");
|
||||
}
|
||||
cell_fall(CELL_TABLE) {
|
||||
values("0.143, 0.144, 0.152",\
|
||||
"0.144, 0.145, 0.153",\
|
||||
"0.149, 0.15, 0.158");
|
||||
values("0.132, 0.133, 0.142",\
|
||||
"0.133, 0.134, 0.142",\
|
||||
"0.138, 0.139, 0.147");
|
||||
}
|
||||
rise_transition(CELL_TABLE) {
|
||||
values("0.014, 0.015, 0.027",\
|
||||
"0.014, 0.015, 0.027",\
|
||||
"0.014, 0.016, 0.027");
|
||||
"0.014, 0.015, 0.027");
|
||||
}
|
||||
fall_transition(CELL_TABLE) {
|
||||
values("0.019, 0.02, 0.035",\
|
||||
"0.019, 0.02, 0.035",\
|
||||
values("0.018, 0.02, 0.036",\
|
||||
"0.019, 0.02, 0.036",\
|
||||
"0.019, 0.02, 0.036");
|
||||
}
|
||||
}
|
||||
|
|
@ -308,20 +308,20 @@ cell (sram_2_16_1_freepdk45){
|
|||
timing_type :"min_pulse_width";
|
||||
related_pin : clk;
|
||||
rise_constraint(scalar) {
|
||||
values("0.205");
|
||||
values("0.1955");
|
||||
}
|
||||
fall_constraint(scalar) {
|
||||
values("0.205");
|
||||
values("0.1955");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type :"minimum_period";
|
||||
related_pin : clk;
|
||||
rise_constraint(scalar) {
|
||||
values("0.41");
|
||||
values("0.391");
|
||||
}
|
||||
fall_constraint(scalar) {
|
||||
values("0.41");
|
||||
values("0.391");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ cell (sram_2_16_1_freepdk45){
|
|||
dont_use : true;
|
||||
map_only : true;
|
||||
dont_touch : true;
|
||||
area : 692.2795;
|
||||
area : 0.023625;
|
||||
|
||||
bus(DATA){
|
||||
bus_type : DATA;
|
||||
|
|
@ -140,14 +140,14 @@ cell (sram_2_16_1_freepdk45){
|
|||
related_pin : "clk";
|
||||
timing_type : falling_edge;
|
||||
cell_rise(CELL_TABLE) {
|
||||
values("0.122, 0.123, 0.132",\
|
||||
"0.122, 0.123, 0.132",\
|
||||
"0.122, 0.123, 0.132");
|
||||
values("0.123, 0.124, 0.133",\
|
||||
"0.123, 0.124, 0.133",\
|
||||
"0.123, 0.124, 0.133");
|
||||
}
|
||||
cell_fall(CELL_TABLE) {
|
||||
values("0.122, 0.123, 0.132",\
|
||||
"0.122, 0.123, 0.132",\
|
||||
"0.122, 0.123, 0.132");
|
||||
values("0.123, 0.124, 0.133",\
|
||||
"0.123, 0.124, 0.133",\
|
||||
"0.123, 0.124, 0.133");
|
||||
}
|
||||
rise_transition(CELL_TABLE) {
|
||||
values("0.006, 0.007, 0.018",\
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
map_only : true;
|
||||
dont_touch : true;
|
||||
area : 90431.64;
|
||||
area : 2.7;
|
||||
|
||||
bus(DATA){
|
||||
bus_type : DATA;
|
||||
|
|
@ -92,10 +92,10 @@ cell (sram_2_16_1_scn3me_subm){
|
|||
internal_power(){
|
||||
when : "OEb & !clk";
|
||||
rise_power(scalar){
|
||||
values("3.1581");
|
||||
values("3.2612");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("3.4945");
|
||||
values("3.5985");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
|
|
@ -129,10 +129,10 @@ cell (sram_2_16_1_scn3me_subm){
|
|||
internal_power(){
|
||||
when : "!OEb & !clk";
|
||||
rise_power(scalar){
|
||||
values("5.0577");
|
||||
values("5.1597");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("5.0831");
|
||||
values("5.1863");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
|
|
@ -140,24 +140,24 @@ cell (sram_2_16_1_scn3me_subm){
|
|||
related_pin : "clk";
|
||||
timing_type : falling_edge;
|
||||
cell_rise(CELL_TABLE) {
|
||||
values("0.542, 0.626, 1.298",\
|
||||
"0.544, 0.627, 1.304",\
|
||||
"0.594, 0.674, 1.35");
|
||||
values("0.509, 0.592, 1.265",\
|
||||
"0.512, 0.595, 1.271",\
|
||||
"0.561, 0.642, 1.317");
|
||||
}
|
||||
cell_fall(CELL_TABLE) {
|
||||
values("1.535, 1.637, 2.604",\
|
||||
"1.54, 1.641, 2.612",\
|
||||
"1.59, 1.693, 2.662");
|
||||
values("1.449, 1.549, 2.511",\
|
||||
"1.453, 1.555, 2.518",\
|
||||
"1.505, 1.607, 2.568");
|
||||
}
|
||||
rise_transition(CELL_TABLE) {
|
||||
values("0.191, 0.337, 1.883",\
|
||||
"0.193, 0.338, 1.885",\
|
||||
"0.195, 0.341, 1.884");
|
||||
values("0.19, 0.335, 1.887",\
|
||||
"0.192, 0.336, 1.886",\
|
||||
"0.194, 0.339, 1.886");
|
||||
}
|
||||
fall_transition(CELL_TABLE) {
|
||||
values("0.252, 0.446, 2.468",\
|
||||
"0.253, 0.448, 2.448",\
|
||||
"0.253, 0.447, 2.454");
|
||||
values("0.282, 0.465, 2.464",\
|
||||
"0.283, 0.466, 2.463",\
|
||||
"0.283, 0.465, 2.455");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ cell (sram_2_16_1_scn3me_subm){
|
|||
dont_use : true;
|
||||
map_only : true;
|
||||
dont_touch : true;
|
||||
area : 90431.64;
|
||||
area : 2.7;
|
||||
|
||||
bus(DATA){
|
||||
bus_type : DATA;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
""" Create a behavioral Verilog file for simulation."""
|
||||
|
||||
def __init__(self,verilog_name,sram):
|
||||
self.sram_name = sram.name
|
||||
self.num_words = sram.num_words
|
||||
self.word_size = sram.word_size
|
||||
self.addr_size = sram.addr_size
|
||||
|
||||
def verilog_write(self,verilog_name):
|
||||
""" Write a behavioral Verilog model. """
|
||||
|
||||
self.vf = open(verilog_name, "w")
|
||||
|
||||
self.create()
|
||||
|
||||
self.vf.close()
|
||||
|
||||
|
||||
def create(self):
|
||||
self.vf.write("// OpenRAM SRAM model\n")
|
||||
self.vf.write("// Words: {0}\n".format(self.num_words))
|
||||
self.vf.write("// Word size: {0}\n\n".format(self.word_size))
|
||||
|
||||
self.vf.write("module {0}(DATA,ADDR,CSb,WEb,OEb,clk);\n".format(self.sram_name))
|
||||
self.vf.write("module {0}(DATA,ADDR,CSb,WEb,OEb,clk);\n".format(self.name))
|
||||
self.vf.write("\n")
|
||||
self.vf.write(" parameter DATA_WIDTH = {0} ;\n".format(self.word_size))
|
||||
self.vf.write(" parameter ADDR_WIDTH = {0} ;\n".format(self.addr_size))
|
||||
|
|
@ -65,47 +56,5 @@ class verilog:
|
|||
self.vf.write("endmodule\n")
|
||||
|
||||
|
||||
|
||||
# //SRAM Model
|
||||
# module sram(CSB,WRB,ABUS,DATABUS);
|
||||
# input CSB; // active low chip select
|
||||
# input WRB; // active low write control
|
||||
# input [11:0] ABUS; // 12-bit address bus
|
||||
# inout [7:0] DATABUS; // 8-bit data bus
|
||||
# //** internal signals
|
||||
# reg [7:0] DATABUS_driver;
|
||||
# wire [7:0] DATABUS = DATABUS_driver;
|
||||
# reg [7:0] ram[0:4095]; // memory cells
|
||||
# integer i;
|
||||
|
||||
# initial //initialize all RAM cells to 0 at startup
|
||||
# begin
|
||||
# DATABUS_driver = 8'bzzzzzzzz;
|
||||
# for (i=0; i < 4095; i = i + 1)
|
||||
# ram[i] = 0;
|
||||
# end
|
||||
|
||||
# always @(CSB or WRB or ABUS)
|
||||
# begin
|
||||
# if (CSB == 1'b0)
|
||||
# begin
|
||||
# if (WRB == 1'b0) //Start: latch Data on rising edge of CSB or WRB
|
||||
# begin
|
||||
# DATABUS_driver <= #10 8'bzzzzzzzz;
|
||||
# @(posedge CSB or posedge WRB);
|
||||
# $display($time," Writing %m ABUS=%b DATA=%b",ABUS,DATABUS);
|
||||
# ram[ABUS] = DATABUS;
|
||||
# end
|
||||
# if (WRB == 1'b1) //Reading from sram (data becomes valid after 10ns)
|
||||
# begin
|
||||
# #10 DATABUS_driver = ram[ABUS];
|
||||
# $display($time," Reading %m ABUS=%b DATA=%b",ABUS,DATABUS_driver);
|
||||
# end
|
||||
# end
|
||||
# else //sram unselected, stop driving bus after 10ns
|
||||
# begin
|
||||
# DATABUS_driver <= #10 8'bzzzzzzzz;
|
||||
# end
|
||||
# end
|
||||
# endmodule
|
||||
self.vf.close()
|
||||
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ class write_driver_array(design.design):
|
|||
for i in range(self.word_size):
|
||||
self.add_pin("data[{0}]".format(i))
|
||||
for i in range(self.word_size):
|
||||
self.add_pin("bl_out[{0}]".format(i))
|
||||
self.add_pin("br_out[{0}]".format(i))
|
||||
self.add_pin("bl[{0}]".format(i))
|
||||
self.add_pin("br[{0}]".format(i))
|
||||
self.add_pin("en")
|
||||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
|
@ -44,7 +44,6 @@ class write_driver_array(design.design):
|
|||
def create_layout(self):
|
||||
self.create_write_array()
|
||||
self.add_layout_pins()
|
||||
#self.offset_all_coordinates()
|
||||
|
||||
def create_write_array(self):
|
||||
self.driver_insts = {}
|
||||
|
|
@ -57,8 +56,8 @@ class write_driver_array(design.design):
|
|||
offset=base)
|
||||
|
||||
self.connect_inst(["data[{0}]".format(i/self.words_per_row),
|
||||
"bl_out[{0}]".format(i/self.words_per_row),
|
||||
"br_out[{0}]".format(i/self.words_per_row),
|
||||
"bl[{0}]".format(i/self.words_per_row),
|
||||
"br[{0}]".format(i/self.words_per_row),
|
||||
"en", "vdd", "gnd"])
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue