Merge branch 'dev' into multiport_characterization

This commit is contained in:
Hunter Nichols 2018-09-06 00:25:11 -07:00
commit f824d039c6
77 changed files with 1133 additions and 858 deletions

View File

@ -15,6 +15,7 @@ class contact(hierarchy_design.hierarchy_design):
necessary to import layouts into Magic which requires the select to be in the same GDS necessary to import layouts into Magic which requires the select to be in the same GDS
hierarchy as the contact. hierarchy as the contact.
""" """
def __init__(self, layer_stack, dimensions=[1,1], implant_type=None, well_type=None): def __init__(self, layer_stack, dimensions=[1,1], implant_type=None, well_type=None):
if implant_type or well_type: if implant_type or well_type:
name = "{0}_{1}_{2}_{3}x{4}_{5}{6}".format(layer_stack[0], name = "{0}_{1}_{2}_{3}x{4}_{5}{6}".format(layer_stack[0],
@ -24,12 +25,13 @@ class contact(hierarchy_design.hierarchy_design):
dimensions[1], dimensions[1],
implant_type, implant_type,
well_type) well_type)
else: else:
name = "{0}_{1}_{2}_{3}x{4}".format(layer_stack[0], name = "{0}_{1}_{2}_{3}x{4}".format(layer_stack[0],
layer_stack[1], layer_stack[1],
layer_stack[2], layer_stack[2],
dimensions[0], dimensions[0],
dimensions[1]) dimensions[1])
hierarchy_design.hierarchy_design.__init__(self, name) hierarchy_design.hierarchy_design.__init__(self, name)
debug.info(4, "create contact object {0}".format(name)) debug.info(4, "create contact object {0}".format(name))

View File

@ -379,11 +379,9 @@ class layout(lef.lef):
dimensions=size, dimensions=size,
implant_type=implant_type, implant_type=implant_type,
well_type=well_type) well_type=well_type)
debug.check(mirror=="R0","Use rotate to rotate vias instead of mirror.")
height = via.height height = via.height
width = via.width width = via.width
debug.check(mirror=="R0","Use rotate to rotate vias instead of mirror.")
if rotate==0: if rotate==0:
corrected_offset = offset + vector(-0.5*width,-0.5*height) corrected_offset = offset + vector(-0.5*width,-0.5*height)
@ -849,10 +847,10 @@ class layout(lef.lef):
""" """
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=loc, offset=loc,
rotate=rotate) rotate=float(rotate))
via=self.add_via_center(layers=("metal2", "via2", "metal3"), via=self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=loc, offset=loc,
rotate=rotate) rotate=float(rotate))
self.add_layout_pin_rect_center(text=name, self.add_layout_pin_rect_center(text=name,
layer="metal3", layer="metal3",
offset=loc, offset=loc,

View File

@ -1,5 +1,5 @@
import debug import debug
from tech import GDS from tech import GDS, drc
from vector import vector from vector import vector
from tech import layer from tech import layer
@ -36,16 +36,29 @@ class pin_layout:
def __eq__(self, other): def __eq__(self, other):
""" Check if these are the same pins for duplicate checks """ """ Check if these are the same pins for duplicate checks """
if isinstance(other, self.__class__): if isinstance(other, self.__class__):
return (self.name==other.name and self.layer==other.layer and self.rect == other.rect) return (self.layer==other.layer and self.rect == other.rect)
else: else:
return False return False
def inflate(self, spacing=None):
"""
Inflate the rectangle by the spacing (or other rule)
and return the new rectangle.
"""
if not spacing:
spacing = drc["{0}_to_{0}".format(self.layer)]
(ll,ur) = self.rect
spacing = vector(spacing, spacing)
newll = ll - spacing
newur = ur + spacing
return (newll, newur)
def overlaps(self, other): def overlaps(self, other):
""" Check if a shape overlaps with a rectangle """ """ Check if a shape overlaps with a rectangle """
ll = self.rect[0] (ll,ur) = self.rect
ur = self.rect[1] (oll,our) = other.rect
oll = other.rect[0]
our = other.rect[1]
# Start assuming no overlaps # Start assuming no overlaps
x_overlaps = False x_overlaps = False
y_overlaps = False y_overlaps = False

View File

@ -294,7 +294,7 @@ class Gds2reader:
mirrorFlag = bool(transFlags&0x8000) ##these flags are a bit sketchy mirrorFlag = bool(transFlags&0x8000) ##these flags are a bit sketchy
rotateFlag = bool(transFlags&0x0002) rotateFlag = bool(transFlags&0x0002)
magnifyFlag = bool(transFlags&0x0004) magnifyFlag = bool(transFlags&0x0004)
thisSref.transFlags=[mirrorFlag,rotateFlag,magnifyFlag] thisSref.transFlags=[mirrorFlag,magnifyFlag,rotateFlag]
if(self.debugToTerminal==1): if(self.debugToTerminal==1):
print("\t\t\tMirror X:"+str(mirrorFlag)) print("\t\t\tMirror X:"+str(mirrorFlag))
print( "\t\t\tRotate:"+str(rotateFlag)) print( "\t\t\tRotate:"+str(rotateFlag))
@ -345,7 +345,7 @@ class Gds2reader:
mirrorFlag = bool(transFlags&0x8000) ##these flags are a bit sketchy mirrorFlag = bool(transFlags&0x8000) ##these flags are a bit sketchy
rotateFlag = bool(transFlags&0x0002) rotateFlag = bool(transFlags&0x0002)
magnifyFlag = bool(transFlags&0x0004) magnifyFlag = bool(transFlags&0x0004)
thisAref.transFlags=[mirrorFlag,rotateFlag,magnifyFlag] thisAref.transFlags=[mirrorFlag,magnifyFlag,rotateFlag]
if(self.debugToTerminal==1): if(self.debugToTerminal==1):
print("\t\t\tMirror X:"+str(mirrorFlag)) print("\t\t\tMirror X:"+str(mirrorFlag))
print("\t\t\tRotate:"+str(rotateFlag)) print("\t\t\tRotate:"+str(rotateFlag))
@ -408,7 +408,7 @@ class Gds2reader:
mirrorFlag = bool(transFlags&0x8000) ##these flags are a bit sketchy mirrorFlag = bool(transFlags&0x8000) ##these flags are a bit sketchy
rotateFlag = bool(transFlags&0x0002) rotateFlag = bool(transFlags&0x0002)
magnifyFlag = bool(transFlags&0x0004) magnifyFlag = bool(transFlags&0x0004)
thisText.transFlags=[mirrorFlag,rotateFlag,magnifyFlag] thisText.transFlags=[mirrorFlag,magnifyFlag,rotateFlag]
if(self.debugToTerminal==1): if(self.debugToTerminal==1):
print("\t\t\tMirror X:"+str(mirrorFlag)) print("\t\t\tMirror X:"+str(mirrorFlag))
print("\t\t\tRotate:"+str(rotateFlag)) print("\t\t\tRotate:"+str(rotateFlag))

View File

@ -280,8 +280,13 @@ class Gds2writer:
if(thisSref.transFlags!=""): if(thisSref.transFlags!=""):
idBits=b'\x1A\x01' idBits=b'\x1A\x01'
mirrorFlag = int(thisSref.transFlags[0])<<15 mirrorFlag = int(thisSref.transFlags[0])<<15
rotateFlag = int(thisSref.transFlags[1])<<1 # The rotate and magnify flags specify "absolute" rotate and magnify.
magnifyFlag = int(thisSref.transFlags[2])<<3 # It is unclear what that is (ignore all further rotates/mags in the
# hierarchy? But anyway, calibre doesn't support it.
rotateFlag=0
magnifyFlag = 0
#rotateFlag = int(thisSref.transFlags[2])<<1
#magnifyFlag = int(thisSref.transFlags[1])<<2
transFlags = struct.pack(">H",mirrorFlag|rotateFlag|magnifyFlag) transFlags = struct.pack(">H",mirrorFlag|rotateFlag|magnifyFlag)
self.writeRecord(idBits+transFlags) self.writeRecord(idBits+transFlags)
if(thisSref.magFactor!=""): if(thisSref.magFactor!=""):
@ -327,15 +332,20 @@ class Gds2writer:
if(thisAref.transFlags): if(thisAref.transFlags):
idBits=b'\x1A\x01' idBits=b'\x1A\x01'
mirrorFlag = int(thisAref.transFlags[0])<<15 mirrorFlag = int(thisAref.transFlags[0])<<15
rotateFlag = int(thisAref.transFlags[1])<<1 # The rotate and magnify flags specify "absolute" rotate and magnify.
magnifyFlag = int(thisAref.transFlags[0])<<3 # It is unclear what that is (ignore all further rotates/mags in the
# hierarchy? But anyway, calibre doesn't support it.
rotateFlag=0
magnifyFlag = 0
#rotateFlag = int(thisAref.transFlags[2])<<1
#magnifyFlag = int(thisAref.transFlags[1])<<2
transFlags = struct.pack(">H",mirrorFlag|rotateFlag|magnifyFlag) transFlags = struct.pack(">H",mirrorFlag|rotateFlag|magnifyFlag)
self.writeRecord(idBits+transFlags) self.writeRecord(idBits+transFlags)
if(thisAref.magFactor): if(thisAref.magFactor!=""):
idBits=b'\x1B\x05' idBits=b'\x1B\x05'
magFactor=self.ibmDataFromIeeeDouble(thisAref.magFactor) magFactor=self.ibmDataFromIeeeDouble(thisAref.magFactor)
self.writeRecord(idBits+magFactor) self.writeRecord(idBits+magFactor)
if(thisAref.rotateAngle): if(thisAref.rotateAngle!=""):
idBits=b'\x1C\x05' idBits=b'\x1C\x05'
rotateAngle=self.ibmDataFromIeeeDouble(thisAref.rotateAngle) rotateAngle=self.ibmDataFromIeeeDouble(thisAref.rotateAngle)
self.writeRecord(idBits+rotateAngle) self.writeRecord(idBits+rotateAngle)
@ -374,15 +384,20 @@ class Gds2writer:
if(thisText.transFlags != ""): if(thisText.transFlags != ""):
idBits=b'\x1A\x01' idBits=b'\x1A\x01'
mirrorFlag = int(thisText.transFlags[0])<<15 mirrorFlag = int(thisText.transFlags[0])<<15
rotateFlag = int(thisText.transFlags[1])<<1 # The rotate and magnify flags specify "absolute" rotate and magnify.
magnifyFlag = int(thisText.transFlags[0])<<3 # It is unclear what that is (ignore all further rotates/mags in the
# hierarchy? But anyway, calibre doesn't support it.
rotateFlag=0
magnifyFlag = 0
#rotateFlag = int(thisText.transFlags[2])<<1
#magnifyFlag = int(thisText.transFlags[1])<<2
transFlags = struct.pack(">H",mirrorFlag|rotateFlag|magnifyFlag) transFlags = struct.pack(">H",mirrorFlag|rotateFlag|magnifyFlag)
self.writeRecord(idBits+transFlags) self.writeRecord(idBits+transFlags)
if(thisText.magFactor != ""): if(thisText.magFactor!=""):
idBits=b'\x1B\x05' idBits=b'\x1B\x05'
magFactor=self.ibmDataFromIeeeDouble(thisText.magFactor) magFactor=self.ibmDataFromIeeeDouble(thisText.magFactor)
self.writeRecord(idBits+magFactor) self.writeRecord(idBits+magFactor)
if(thisText.rotateAngle != ""): if(thisText.rotateAngle!=""):
idBits=b'\x1C\x05' idBits=b'\x1C\x05'
rotateAngle=self.ibmDataFromIeeeDouble(thisText.rotateAngle) rotateAngle=self.ibmDataFromIeeeDouble(thisText.rotateAngle)
self.writeRecord(idBits+rotateAngle) self.writeRecord(idBits+rotateAngle)

View File

@ -141,7 +141,7 @@ class GdsText:
self.plex="" self.plex=""
self.drawingLayer="" self.drawingLayer=""
self.purposeLayer = None self.purposeLayer = None
self.transFlags=[0,00] self.transFlags=[0,0,0]
self.magFactor="" self.magFactor=""
self.rotateAngle="" self.rotateAngle=""
self.pathType="" self.pathType=""

View File

@ -64,10 +64,11 @@ class VlsiLayout:
#helper method to rotate a list of coordinates #helper method to rotate a list of coordinates
angle=math.radians(float(0)) angle=math.radians(float(0))
if(rotateAngle): if(rotateAngle):
angle = math.radians(float(repr(rotateAngle))) angle = math.radians(float(rotateAngle))
coordinatesRotate = [] #this will hold the rotated values coordinatesRotate = [] #this will hold the rotated values
for coordinate in coordinatesToRotate: for coordinate in coordinatesToRotate:
# This is the CCW rotation matrix
newX = coordinate[0]*math.cos(angle) - coordinate[1]*math.sin(angle) newX = coordinate[0]*math.cos(angle) - coordinate[1]*math.sin(angle)
newY = coordinate[0]*math.sin(angle) + coordinate[1]*math.cos(angle) newY = coordinate[0]*math.sin(angle) + coordinate[1]*math.cos(angle)
coordinatesRotate.extend((newX,newY)) coordinatesRotate.extend((newX,newY))
@ -274,8 +275,9 @@ class VlsiLayout:
Method to insert one layout into another at a particular offset. Method to insert one layout into another at a particular offset.
""" """
offsetInLayoutUnits = (self.userUnits(offsetInMicrons[0]),self.userUnits(offsetInMicrons[1])) offsetInLayoutUnits = (self.userUnits(offsetInMicrons[0]),self.userUnits(offsetInMicrons[1]))
if self.debug==1: if self.debug:
debug.info(0,"DEBUG: GdsMill vlsiLayout: addInstance: type %s, nameOfLayout "%type(layoutToAdd),nameOfLayout) debug.info(0,"DEBUG: GdsMill vlsiLayout: addInstance: type {0}, nameOfLayout {1}".format(type(layoutToAdd),nameOfLayout))
debug.info(0,"DEBUG: name={0} offset={1} mirror={2} rotate={3}".format(layoutToAdd.rootStructureName,offsetInMicrons, mirror, rotate))
@ -295,7 +297,7 @@ class VlsiLayout:
# If layoutToAdd is a unique object (not this), then copy heirarchy, # If layoutToAdd is a unique object (not this), then copy hierarchy,
# otherwise, if it is a text name of an internal structure, use it. # otherwise, if it is a text name of an internal structure, use it.
if layoutToAdd != self: if layoutToAdd != self:
@ -316,9 +318,7 @@ class VlsiLayout:
if mirror or rotate: if mirror or rotate:
layoutToAddSref.transFlags = [0,0,0] layoutToAddSref.transFlags = [0,0,0]
# This is NOT the same as the order in the GDS spec! # transFlags = (mirror around x-axis, magnification, rotation)
# It gets written out in gds2writer in the right order though.
# transFlags = (mirror around x-axis, rotation, magnification)
# If magnification or rotation is true, it is the flags are then # If magnification or rotation is true, it is the flags are then
# followed by an amount in the record # followed by an amount in the record
if mirror=="R90": if mirror=="R90":
@ -328,17 +328,16 @@ class VlsiLayout:
if mirror=="R270": if mirror=="R270":
rotate = 270.0 rotate = 270.0
if rotate: if rotate:
#layoutToAddSref.transFlags = [0,1,0] #layoutToAddSref.transFlags[2] = 1
layoutToAddSref.rotateAngle = rotate layoutToAddSref.rotateAngle = rotate
if mirror == "x" or mirror == "MX": if mirror == "x" or mirror == "MX":
layoutToAddSref.transFlags = [1,0,0] layoutToAddSref.transFlags[0] = 1
if mirror == "y" or mirror == "MY": #NOTE: "MY" option will override specified rotate angle if mirror == "y" or mirror == "MY": #NOTE: "MY" option will override specified rotate angle
#layoutToAddSref.transFlags = [1,1,0] layoutToAddSref.transFlags[0] = 1
layoutToAddSref.transFlags = [1,0,0] #layoutToAddSref.transFlags[2] = 1
layoutToAddSref.rotateAngle = 180.0 layoutToAddSref.rotateAngle = 180.0
if mirror == "xy" or mirror == "XY": #NOTE: "XY" option will override specified rotate angle if mirror == "xy" or mirror == "XY": #NOTE: "XY" option will override specified rotate angle
#layoutToAddSref.transFlags = [0,1,0] #layoutToAddSref.transFlags[2] = 1
layoutToAddSref.transFlags = [0,0,0]
layoutToAddSref.rotateAngle = 180.0 layoutToAddSref.rotateAngle = 180.0
#add the sref to the root structure #add the sref to the root structure
@ -405,10 +404,10 @@ class VlsiLayout:
if(len(text)%2 == 1): if(len(text)%2 == 1):
text = text + '\x00' text = text + '\x00'
textToAdd.textString = text textToAdd.textString = text
textToAdd.transFlags = [0,0,1] #textToAdd.transFlags[1] = 1
textToAdd.magFactor = magnification textToAdd.magFactor = magnification
if rotate: if rotate:
textToAdd.transFlags = [0,1,1] #textToAdd.transFlags[2] = 1
textToAdd.rotateAngle = rotate textToAdd.rotateAngle = rotate
#add the sref to the root structure #add the sref to the root structure
self.structures[self.rootStructureName].texts.append(textToAdd) self.structures[self.rootStructureName].texts.append(textToAdd)
@ -816,10 +815,10 @@ class VlsiLayout:
""" """
(structureName,structureOrigin,structureuVector,structurevVector)=structure (structureName,structureOrigin,structureuVector,structurevVector)=structure
#print(structureName,"u",structureuVector.transpose(),"v",structurevVector.transpose(),"o",structureOrigin.transpose())
boundaries = [] boundaries = []
for boundary in self.structures[str(structureName)].boundaries: for boundary in self.structures[str(structureName)].boundaries:
# Pin enclosures only work on rectangular pins so ignore any non rectangle # FIXME: Right now, this only supports rectangular shapes!
# This may report not finding pins, but the user should fix this by adding a rectangle.
if len(boundary.coordinates)!=5: if len(boundary.coordinates)!=5:
continue continue
if layer==boundary.drawingLayer: if layer==boundary.drawingLayer:
@ -827,10 +826,11 @@ class VlsiLayout:
right_top=boundary.coordinates[2] right_top=boundary.coordinates[2]
# Rectangle is [leftx, bottomy, rightx, topy]. # Rectangle is [leftx, bottomy, rightx, topy].
boundaryRect=[left_bottom[0],left_bottom[1],right_top[0],right_top[1]] boundaryRect=[left_bottom[0],left_bottom[1],right_top[0],right_top[1]]
# perform the rotation
boundaryRect=self.transformRectangle(boundaryRect,structureuVector,structurevVector) boundaryRect=self.transformRectangle(boundaryRect,structureuVector,structurevVector)
# add the offset
boundaryRect=[boundaryRect[0]+structureOrigin[0].item(),boundaryRect[1]+structureOrigin[1].item(), boundaryRect=[boundaryRect[0]+structureOrigin[0].item(),boundaryRect[1]+structureOrigin[1].item(),
boundaryRect[2]+structureOrigin[0].item(),boundaryRect[3]+structureOrigin[1].item()] boundaryRect[2]+structureOrigin[0].item(),boundaryRect[3]+structureOrigin[1].item()]
boundaries.append(boundaryRect) boundaries.append(boundaryRect)
return boundaries return boundaries
@ -858,8 +858,12 @@ class VlsiLayout:
""" """
Rotate a coordinate in space. Rotate a coordinate in space.
""" """
x=coordinate[0]*uVector[0].item()+coordinate[1]*uVector[1].item() # MRG: 9/3/18 Incorrect matrixi multiplication!
y=coordinate[1]*vVector[1].item()+coordinate[0]*vVector[0].item() # This is fixed to be:
# |u[0] v[0]| |x| |x'|
# |u[1] v[1]|x|y|=|y'|
x=coordinate[0]*uVector[0].item()+coordinate[1]*vVector[0].item()
y=coordinate[0]*uVector[1].item()+coordinate[1]*vVector[1].item()
transformCoordinate=[x,y] transformCoordinate=[x,y]
return transformCoordinate return transformCoordinate

View File

@ -116,6 +116,8 @@ def init_openram(config_file, is_unit_test=True):
import_tech() import_tech()
init_paths()
# Reset the static duplicate name checker for unit tests. # Reset the static duplicate name checker for unit tests.
import hierarchy_design import hierarchy_design
hierarchy_design.hierarchy_design.name_map=[] hierarchy_design.hierarchy_design.name_map=[]
@ -205,12 +207,14 @@ def read_config(config_file, is_unit_test=True):
if not k in OPTS.__dict__ or k=="tech_name": if not k in OPTS.__dict__ or k=="tech_name":
OPTS.__dict__[k]=v OPTS.__dict__[k]=v
# Massage the output path to be an absolute one
if not OPTS.output_path.endswith('/'): if not OPTS.output_path.endswith('/'):
OPTS.output_path += "/" OPTS.output_path += "/"
if not OPTS.output_path.startswith('/'): if not OPTS.output_path.startswith('/'):
OPTS.output_path = os.getcwd() + "/" + OPTS.output_path OPTS.output_path = os.getcwd() + "/" + OPTS.output_path
debug.info(1, "Output saved in " + OPTS.output_path) debug.info(1, "Output saved in " + OPTS.output_path)
# Remember if we are running unit tests to reduce output
OPTS.is_unit_test=is_unit_test OPTS.is_unit_test=is_unit_test
# If we are only generating a netlist, we can't do DRC/LVS # If we are only generating a netlist, we can't do DRC/LVS
@ -219,21 +223,14 @@ def read_config(config_file, is_unit_test=True):
# If config didn't set output name, make a reasonable default. # If config didn't set output name, make a reasonable default.
if (OPTS.output_name == ""): if (OPTS.output_name == ""):
OPTS.output_name = "sram_{0}rw_{1}b_{2}w_{3}bank_{4}".format(OPTS.rw_ports, OPTS.output_name = "sram_{0}b_{1}w_{2}bank_{3}rw_{4}w_{5}r_{6}".format(OPTS.word_size,
OPTS.word_size, OPTS.num_words,
OPTS.num_words, OPTS.num_banks,
OPTS.num_banks, OPTS.num_rw_ports,
OPTS.tech_name) OPTS.num_w_ports,
OPTS.num_r_ports,
OPTS.tech_name)
# Don't delete the output dir, it may have other files!
# make the directory if it doesn't exist
try:
os.makedirs(OPTS.output_path, 0o750)
except OSError as e:
if e.errno == 17: # errno.EEXIST
os.chmod(OPTS.output_path, 0o750)
except:
debug.error("Unable to make output directory.",-1)
def end_openram(): def end_openram():
@ -257,7 +254,8 @@ def cleanup_paths():
if not OPTS.purge_temp: if not OPTS.purge_temp:
debug.info(0,"Preserving temp directory: {}".format(OPTS.openram_temp)) debug.info(0,"Preserving temp directory: {}".format(OPTS.openram_temp))
return return
if os.path.exists(OPTS.openram_temp): elif os.path.exists(OPTS.openram_temp):
debug.info(1,"Purging temp directory: {}".format(OPTS.openram_temp))
# This annoyingly means you have to re-cd into the directory each debug iteration # This annoyingly means you have to re-cd into the directory each debug iteration
#shutil.rmtree(OPTS.openram_temp, ignore_errors=True) #shutil.rmtree(OPTS.openram_temp, ignore_errors=True)
contents = [os.path.join(OPTS.openram_temp, i) for i in os.listdir(OPTS.openram_temp)] contents = [os.path.join(OPTS.openram_temp, i) for i in os.listdir(OPTS.openram_temp)]
@ -293,14 +291,6 @@ def setup_paths():
OPTS.openram_temp += "/" OPTS.openram_temp += "/"
debug.info(1, "Temporary files saved in " + OPTS.openram_temp) debug.info(1, "Temporary files saved in " + OPTS.openram_temp)
cleanup_paths()
# make the directory if it doesn't exist
try:
os.makedirs(OPTS.openram_temp, 0o750)
except OSError as e:
if e.errno == 17: # errno.EEXIST
os.chmod(OPTS.openram_temp, 0o750)
def is_exe(fpath): def is_exe(fpath):
@ -317,6 +307,28 @@ def find_exe(check_exe):
return exe return exe
return None return None
def init_paths():
""" Create the temp and output directory if it doesn't exist """
# make the directory if it doesn't exist
try:
debug.info(1,"Creating temp directory: {}".format(OPTS.openram_temp))
os.makedirs(OPTS.openram_temp, 0o750)
except OSError as e:
if e.errno == 17: # errno.EEXIST
os.chmod(OPTS.openram_temp, 0o750)
# Don't delete the output dir, it may have other files!
# make the directory if it doesn't exist
try:
os.makedirs(OPTS.output_path, 0o750)
except OSError as e:
if e.errno == 17: # errno.EEXIST
os.chmod(OPTS.output_path, 0o750)
except:
debug.error("Unable to make output directory.",-1)
# imports correct technology directories for testing # imports correct technology directories for testing
def import_tech(): def import_tech():
global OPTS global OPTS

View File

@ -20,21 +20,19 @@ class bank(design.design):
write driver and sense amplifiers. write driver and sense amplifiers.
""" """
def __init__(self, word_size, num_words, words_per_row, num_banks=1, name=""): def __init__(self, sram_config, name=""):
sram_config.set_local_config(self)
if name == "": if name == "":
name = "bank_{0}_{1}".format(word_size, num_words) name = "bank_{0}_{1}".format(self.word_size, self.num_words)
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(2, "create sram of size {0} with {1} words".format(word_size,num_words)) debug.info(2, "create sram of size {0} with {1} words".format(self.word_size,self.num_words))
self.word_size = word_size
self.num_words = num_words
self.words_per_row = words_per_row
self.num_banks = num_banks
self.total_write = OPTS.rw_ports + OPTS.w_ports self.total_write = OPTS.num_rw_ports + OPTS.num_w_ports
self.total_read = OPTS.rw_ports + OPTS.r_ports self.total_read = OPTS.num_rw_ports + OPTS.num_r_ports
self.total_ports = OPTS.rw_ports + OPTS.w_ports + OPTS.r_ports self.total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
# The local control signals are gated when we have bank select logic, # The local control signals are gated when we have bank select logic,
# so this prefix will be added to all of the input signals to create # so this prefix will be added to all of the input signals to create
@ -70,24 +68,25 @@ class bank(design.design):
def add_pins(self): def add_pins(self):
""" Adding pins for Bank module""" """ Adding pins for Bank module"""
for k in range(self.total_read): for port in range(self.total_read):
for i in range(self.word_size): for bit in range(self.word_size):
self.add_pin("dout{0}[{1}]".format(k,i),"OUT") self.add_pin("dout{0}[{1}]".format(port,bit),"OUT")
for k in range(self.total_write): for port in range(self.total_write):
for i in range(self.word_size): for bit in range(self.word_size):
self.add_pin("din{0}[{1}]".format(k,i),"IN") self.add_pin("din{0}[{1}]".format(port,bit),"IN")
for k in range(self.total_ports): for port in range(self.total_ports):
for i in range(self.addr_size): for bit in range(self.addr_size):
self.add_pin("addr{0}[{1}]".format(k,i),"INPUT") self.add_pin("addr{0}[{1}]".format(port,bit),"INPUT")
# For more than one bank, we have a bank select and name # For more than one bank, we have a bank select and name
# the signals gated_*. # the signals gated_*.
if self.num_banks > 1: if self.num_banks > 1:
self.add_pin("bank_sel","INPUT") for port in range(self.total_ports):
for k in range(self.total_read): self.add_pin("bank_sel{}".format(port),"INPUT")
self.add_pin("s_en{0}".format(k), "INPUT") for port in range(self.total_read):
for k in range(self.total_write): self.add_pin("s_en{0}".format(port), "INPUT")
self.add_pin("w_en{0}".format(k), "INPUT") for port in range(self.total_write):
self.add_pin("w_en{0}".format(port), "INPUT")
for pin in ["clk_buf_bar","clk_buf"]: for pin in ["clk_buf_bar","clk_buf"]:
self.add_pin(pin,"INPUT") self.add_pin(pin,"INPUT")
self.add_pin("vdd","POWER") self.add_pin("vdd","POWER")
@ -228,9 +227,9 @@ class bank(design.design):
self.total_bitline_list = self.bitcell.list_all_bitline_names() self.total_bitline_list = self.bitcell.list_all_bitline_names()
self.precharge_array = [] self.precharge_array = []
for k in range(self.total_read): for port in range(self.total_read):
self.precharge_array.append(self.mod_precharge_array(columns=self.num_cols, bitcell_bl=self.read_bl_list[k], bitcell_br=self.read_br_list[k])) self.precharge_array.append(self.mod_precharge_array(columns=self.num_cols, bitcell_bl=self.read_bl_list[port], bitcell_br=self.read_br_list[port]))
self.add_mod(self.precharge_array[k]) self.add_mod(self.precharge_array[port])
if self.col_addr_size > 0: if self.col_addr_size > 0:
self.column_mux_array = self.mod_column_mux_array(columns=self.num_cols, self.column_mux_array = self.mod_column_mux_array(columns=self.num_cols,
@ -287,13 +286,13 @@ class bank(design.design):
""" Creating Precharge """ """ Creating Precharge """
self.precharge_array_inst = [] self.precharge_array_inst = []
for k in range(self.total_read): for port in range(self.total_read):
self.precharge_array_inst.append(self.add_inst(name="precharge_array{}".format(k), self.precharge_array_inst.append(self.add_inst(name="precharge_array{}".format(port),
mod=self.precharge_array[k])) mod=self.precharge_array[port]))
temp = [] temp = []
for i in range(self.num_cols): for i in range(self.num_cols):
temp.append(self.read_bl_list[k]+"[{0}]".format(i)) temp.append(self.read_bl_list[port]+"[{0}]".format(i))
temp.append(self.read_br_list[k]+"[{0}]".format(i)) temp.append(self.read_br_list[port]+"[{0}]".format(i))
temp.extend([self.prefix+"clk_buf_bar", "vdd"]) temp.extend([self.prefix+"clk_buf_bar", "vdd"])
self.connect_inst(temp) self.connect_inst(temp)
@ -301,11 +300,11 @@ class bank(design.design):
""" Placing Precharge """ """ Placing Precharge """
# FIXME: place for multiport # FIXME: place for multiport
for k in range(self.total_read): for port in range(self.total_read):
# The wells must be far enough apart # The wells must be far enough apart
# The enclosure is for the well and the spacing is to the bitcell wells # The enclosure is for the well and the spacing is to the bitcell wells
y_offset = self.bitcell_array.height + self.m2_gap y_offset = self.bitcell_array.height + self.m2_gap
self.precharge_array_inst[k].place(vector(0,y_offset)) self.precharge_array_inst[port].place(vector(0,y_offset))
def create_column_mux_array(self): def create_column_mux_array(self):
""" Creating Column Mux when words_per_row > 1 . """ """ Creating Column Mux when words_per_row > 1 . """
@ -313,19 +312,19 @@ class bank(design.design):
return return
self.col_mux_array_inst = [] self.col_mux_array_inst = []
for k in range(self.total_ports): for port in range(self.total_ports):
self.col_mux_array_inst.append(self.add_inst(name="column_mux_array{}".format(k), self.col_mux_array_inst.append(self.add_inst(name="column_mux_array{}".format(port),
mod=self.column_mux_array)) mod=self.column_mux_array))
temp = [] temp = []
for i in range(self.num_cols): for col in range(self.num_cols):
temp.append(self.total_bl_list[k]+"[{0}]".format(i)) temp.append(self.total_bl_list[port]+"[{0}]".format(col))
temp.append(self.total_br_list[k]+"[{0}]".format(i)) temp.append(self.total_br_list[port]+"[{0}]".format(col))
for h in range(self.words_per_row): for word in range(self.words_per_row):
temp.append("sel{0}[{1}]".format(k,h)) temp.append("sel{0}[{1}]".format(port,word))
for j in range(self.word_size): for bit in range(self.word_size):
temp.append(self.total_bl_list[k]+"_out[{0}]".format(j)) temp.append(self.total_bl_list[port]+"_out[{0}]".format(bit))
temp.append(self.total_br_list[k]+"_out[{0}]".format(j)) temp.append(self.total_br_list[port]+"_out[{0}]".format(bit))
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) self.connect_inst(temp)
@ -337,68 +336,68 @@ class bank(design.design):
self.column_mux_height = 0 self.column_mux_height = 0
return return
for k in range(self.total_ports): for port in range(self.total_ports):
y_offset = self.column_mux_height y_offset = self.column_mux_height
self.col_mux_array_inst[k].place(vector(0,y_offset).scale(-1,-1)) self.col_mux_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
def create_sense_amp_array(self): def create_sense_amp_array(self):
""" Creating Sense amp """ """ Creating Sense amp """
self.sense_amp_array_inst = [] self.sense_amp_array_inst = []
for k in range(self.total_read): for port in range(self.total_read):
self.sense_amp_array_inst.append(self.add_inst(name="sense_amp_array{}".format(k), self.sense_amp_array_inst.append(self.add_inst(name="sense_amp_array{}".format(port),
mod=self.sense_amp_array)) mod=self.sense_amp_array))
temp = [] temp = []
for i in range(self.word_size): for bit in range(self.word_size):
temp.append("dout{0}[{1}]".format(k,i)) temp.append("dout{0}[{1}]".format(port,bit))
if self.words_per_row == 1: if self.words_per_row == 1:
temp.append(self.read_bl_list[k]+"[{0}]".format(i)) temp.append(self.read_bl_list[port]+"[{0}]".format(bit))
temp.append(self.read_br_list[k]+"[{0}]".format(i)) temp.append(self.read_br_list[port]+"[{0}]".format(bit))
else: else:
temp.append(self.read_bl_list[k]+"_out[{0}]".format(i)) temp.append(self.read_bl_list[port]+"_out[{0}]".format(bit))
temp.append(self.read_br_list[k]+"_out[{0}]".format(i)) temp.append(self.read_br_list[port]+"_out[{0}]".format(bit))
temp.extend([self.prefix+"s_en{0}".format(k), "vdd", "gnd"]) temp.extend([self.prefix+"s_en{0}".format(port), "vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_sense_amp_array(self): def place_sense_amp_array(self):
""" Placing Sense amp """ """ Placing Sense amp """
# FIXME: place for multiport # FIXME: place for multiport
for k in range(self.total_read): for port in range(self.total_read):
y_offset = self.column_mux_height + self.sense_amp_array.height + self.m2_gap y_offset = self.column_mux_height + self.sense_amp_array.height + self.m2_gap
self.sense_amp_array_inst[k].place(vector(0,y_offset).scale(-1,-1)) self.sense_amp_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
def create_write_driver_array(self): def create_write_driver_array(self):
""" Creating Write Driver """ """ Creating Write Driver """
self.write_driver_array_inst = [] self.write_driver_array_inst = []
for k in range(self.total_write): for port in range(self.total_write):
self.write_driver_array_inst.append(self.add_inst(name="write_driver_array{}".format(k), self.write_driver_array_inst.append(self.add_inst(name="write_driver_array{}".format(port),
mod=self.write_driver_array)) mod=self.write_driver_array))
temp = [] temp = []
for i in range(self.word_size): for bit in range(self.word_size):
temp.append("din{0}[{1}]".format(k,i)) temp.append("din{0}[{1}]".format(port,bit))
for i in range(self.word_size): for bit in range(self.word_size):
if (self.words_per_row == 1): if (self.words_per_row == 1):
temp.append(self.write_bl_list[k]+"[{0}]".format(i)) temp.append(self.write_bl_list[port]+"[{0}]".format(bit))
temp.append(self.write_br_list[k]+"[{0}]".format(i)) temp.append(self.write_br_list[port]+"[{0}]".format(bit))
else: else:
temp.append(self.write_bl_list[k]+"_out[{0}]".format(i)) temp.append(self.write_bl_list[port]+"_out[{0}]".format(bit))
temp.append(self.write_br_list[k]+"_out[{0}]".format(i)) temp.append(self.write_br_list[port]+"_out[{0}]".format(bit))
temp.extend([self.prefix+"w_en{0}".format(k), "vdd", "gnd"]) temp.extend([self.prefix+"w_en{0}".format(port), "vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_write_driver_array(self): def place_write_driver_array(self):
""" Placing Write Driver """ """ Placing Write Driver """
# FIXME: place for multiport # FIXME: place for multiport
for k in range(self.total_write): for port in range(self.total_write):
y_offset = self.sense_amp_array.height + self.column_mux_height \ y_offset = self.sense_amp_array.height + self.column_mux_height \
+ self.m2_gap + self.write_driver_array.height + self.m2_gap + self.write_driver_array.height
self.write_driver_array_inst[k].place(vector(0,y_offset).scale(-1,-1)) self.write_driver_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
@ -406,15 +405,15 @@ class bank(design.design):
""" Create the hierarchical row decoder """ """ Create the hierarchical row decoder """
self.row_decoder_inst = [] self.row_decoder_inst = []
for k in range(self.total_ports): for port in range(self.total_ports):
self.row_decoder_inst.append(self.add_inst(name="row_decoder{}".format(k), self.row_decoder_inst.append(self.add_inst(name="row_decoder{}".format(port),
mod=self.row_decoder)) mod=self.row_decoder))
temp = [] temp = []
for i in range(self.row_addr_size): for bit in range(self.row_addr_size):
temp.append("addr{0}[{1}]".format(k,i+self.col_addr_size)) temp.append("addr{0}[{1}]".format(port,bit+self.col_addr_size))
for j in range(self.num_rows): for row in range(self.num_rows):
temp.append("dec_out{0}[{1}]".format(k,j)) temp.append("dec_out{0}[{1}]".format(port,row))
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
@ -428,24 +427,24 @@ class bank(design.design):
# The address flop and decoder are aligned in the x coord. # The address flop and decoder are aligned in the x coord.
# FIXME: place for multiport # FIXME: place for multiport
for k in range(self.total_ports): for port in range(self.total_ports):
x_offset = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width) x_offset = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width)
self.row_decoder_inst[k].place(vector(x_offset,0)) self.row_decoder_inst[port].place(vector(x_offset,0))
def create_wordline_driver(self): def create_wordline_driver(self):
""" Create the Wordline Driver """ """ Create the Wordline Driver """
self.wordline_driver_inst = [] self.wordline_driver_inst = []
for k in range(self.total_ports): for port in range(self.total_ports):
self.wordline_driver_inst.append(self.add_inst(name="wordline_driver{}".format(k), self.wordline_driver_inst.append(self.add_inst(name="wordline_driver{}".format(port),
mod=self.wordline_driver)) mod=self.wordline_driver))
temp = [] temp = []
for i in range(self.num_rows): for row in range(self.num_rows):
temp.append("dec_out{0}[{1}]".format(k,i)) temp.append("dec_out{0}[{1}]".format(port,row))
for i in range(self.num_rows): for row in range(self.num_rows):
temp.append(self.total_wl_list[k]+"[{0}]".format(i)) temp.append(self.total_wl_list[port]+"[{0}]".format(row))
temp.append(self.prefix+"clk_buf") temp.append(self.prefix+"clk_buf")
temp.append("vdd") temp.append("vdd")
temp.append("gnd") temp.append("gnd")
@ -455,10 +454,10 @@ class bank(design.design):
""" Place the Wordline Driver """ """ Place the Wordline Driver """
# FIXME: place for multiport # FIXME: place for multiport
for k in range(self.total_ports): for port in range(self.total_ports):
# The wordline driver is placed to the right of the main decoder width. # The wordline driver is placed to the right of the main decoder width.
x_offset = -(self.central_bus_width + self.wordline_driver.width) + self.m2_pitch x_offset = -(self.central_bus_width + self.wordline_driver.width) + self.m2_pitch
self.wordline_driver_inst[k].place(vector(x_offset,0)) self.wordline_driver_inst[port].place(vector(x_offset,0))
def create_column_decoder(self): def create_column_decoder(self):
@ -480,15 +479,15 @@ class bank(design.design):
debug.error("Invalid column decoder?",-1) debug.error("Invalid column decoder?",-1)
self.col_decoder_inst = [] self.col_decoder_inst = []
for k in range(self.total_ports): for port in range(self.total_ports):
self.col_decoder_inst.append(self.add_inst(name="col_address_decoder{}".format(k), self.col_decoder_inst.append(self.add_inst(name="col_address_decoder{}".format(port),
mod=self.col_decoder)) mod=self.col_decoder))
temp = [] temp = []
for i in range(self.col_addr_size): for bit in range(self.col_addr_size):
temp.append("addr{0}[{1}]".format(k,i)) temp.append("addr{0}[{1}]".format(port,bit))
for j in range(self.num_col_addr_lines): for bit in range(self.num_col_addr_lines):
temp.append("sel{0}[{1}]".format(k,j)) temp.append("sel{0}[{1}]".format(port,bit))
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
@ -500,11 +499,11 @@ class bank(design.design):
return return
# FIXME: place for multiport # FIXME: place for multiport
for k in range(self.total_ports): for port in range(self.total_ports):
# Place the col decoder right aligned with row decoder # Place the col decoder right aligned with row decoder
x_off = -(self.central_bus_width + self.wordline_driver.width + self.col_decoder.width) x_off = -(self.central_bus_width + self.wordline_driver.width + self.col_decoder.width)
y_off = -(self.col_decoder.height + 2*drc["well_to_well"]) y_off = -(self.col_decoder.height + 2*drc["well_to_well"])
self.col_decoder_inst[k].place(vector(x_off,y_off)) self.col_decoder_inst[port].place(vector(x_off,y_off))
def create_bank_select(self): def create_bank_select(self):
@ -514,13 +513,13 @@ class bank(design.design):
return return
self.bank_select_inst = [] self.bank_select_inst = []
for k in range(self.total_ports): for port in range(self.total_ports):
self.bank_select_inst.append(self.add_inst(name="bank_select", self.bank_select_inst.append(self.add_inst(name="bank_select{}".format(port),
mod=self.bank_select)) mod=self.bank_select))
temp = [] temp = []
temp.extend(self.input_control_signals) temp.extend(self.input_control_signals)
temp.append("bank_sel") temp.append("bank_sel{}".format(port))
temp.extend(self.control_signals) temp.extend(self.control_signals)
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
@ -532,7 +531,7 @@ class bank(design.design):
return return
# FIXME: place for multiport # FIXME: place for multiport
for k in range(self.total_ports): for port in range(self.total_ports):
x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width) x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width)
if self.col_addr_size > 0: if self.col_addr_size > 0:
y_off = min(self.col_decoder_inst[0].by(), self.col_mux_array_inst[0].by()) y_off = min(self.col_decoder_inst[0].by(), self.col_mux_array_inst[0].by())
@ -540,7 +539,7 @@ class bank(design.design):
y_off = self.row_decoder_inst[0].by() y_off = self.row_decoder_inst[0].by()
y_off -= (self.bank_select.height + drc["well_to_well"]) y_off -= (self.bank_select.height + drc["well_to_well"])
self.bank_select_pos = vector(x_off,y_off) self.bank_select_pos = vector(x_off,y_off)
self.bank_select_inst[k].place(self.bank_select_pos) self.bank_select_inst[port].place(self.bank_select_pos)
def route_vdd_gnd(self): def route_vdd_gnd(self):
@ -549,19 +548,19 @@ class bank(design.design):
# These are the instances that every bank has # These are the instances that every bank has
top_instances = [self.bitcell_array_inst] top_instances = [self.bitcell_array_inst]
for k in range(self.total_ports): for port in range(self.total_ports):
top_instances.extend([self.precharge_array_inst[k], top_instances.extend([self.precharge_array_inst[port],
self.sense_amp_array_inst[k], self.sense_amp_array_inst[port],
self.write_driver_array_inst[k], self.write_driver_array_inst[port],
self.row_decoder_inst[k], self.row_decoder_inst[port],
self.wordline_driver_inst[k]]) self.wordline_driver_inst[port]])
# Add these if we use the part... # Add these if we use the part...
if self.col_addr_size > 0: if self.col_addr_size > 0:
top_instances.append(self.col_decoder_inst[k]) top_instances.append(self.col_decoder_inst[port])
top_instances.append(self.col_mux_array_inst[k]) top_instances.append(self.col_mux_array_inst[port])
if self.num_banks > 1: if self.num_banks > 1:
top_instances.append(self.bank_select_inst[k]) top_instances.append(self.bank_select_inst[port])
for inst in top_instances: for inst in top_instances:
@ -575,13 +574,13 @@ class bank(design.design):
def route_bank_select(self): def route_bank_select(self):
""" Route the bank select logic. """ """ Route the bank select logic. """
for k in range(self.total_ports): for port in range(self.total_ports):
for input_name in self.input_control_signals+["bank_sel"]: for input_name in self.input_control_signals+["bank_sel"]:
self.copy_layout_pin(self.bank_select_inst[k], input_name) self.copy_layout_pin(self.bank_select_inst[port], input_name)
for gated_name in self.control_signals: for gated_name in self.control_signals:
# Connect the inverter output to the central bus # Connect the inverter output to the central bus
out_pos = self.bank_select_inst[k].get_pin(gated_name).rc() out_pos = self.bank_select_inst[port].get_pin(gated_name).rc()
bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y) bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y)
self.add_path("metal3",[out_pos, bus_pos]) self.add_path("metal3",[out_pos, bus_pos])
self.add_via_center(layers=("metal2", "via2", "metal3"), self.add_via_center(layers=("metal2", "via2", "metal3"),
@ -659,12 +658,12 @@ class bank(design.design):
""" Routing of BL and BR between pre-charge and bitcell array """ """ Routing of BL and BR between pre-charge and bitcell array """
# FIXME: Update for multiport # FIXME: Update for multiport
for k in range(self.total_read): for port in range(self.total_read):
for i in range(self.num_cols): for col in range(self.num_cols):
precharge_bl = self.precharge_array_inst[k].get_pin("bl[{}]".format(i)).bc() precharge_bl = self.precharge_array_inst[port].get_pin("bl[{}]".format(col)).bc()
precharge_br = self.precharge_array_inst[k].get_pin("br[{}]".format(i)).bc() precharge_br = self.precharge_array_inst[port].get_pin("br[{}]".format(col)).bc()
bitcell_bl = self.bitcell_array_inst.get_pin(self.read_bl_list[k]+"[{}]".format(i)).uc() bitcell_bl = self.bitcell_array_inst.get_pin(self.read_bl_list[port]+"[{}]".format(col)).uc()
bitcell_br = self.bitcell_array_inst.get_pin(self.read_br_list[k]+"[{}]".format(i)).uc() bitcell_br = self.bitcell_array_inst.get_pin(self.read_br_list[port]+"[{}]".format(col)).uc()
yoffset = 0.5*(precharge_bl.y+bitcell_bl.y) yoffset = 0.5*(precharge_bl.y+bitcell_bl.y)
self.add_path("metal2",[precharge_bl, vector(precharge_bl.x,yoffset), self.add_path("metal2",[precharge_bl, vector(precharge_bl.x,yoffset),
@ -681,12 +680,12 @@ class bank(design.design):
return return
# FIXME: Update for multiport # FIXME: Update for multiport
for k in range(self.total_ports): for port in range(self.total_ports):
for i in range(self.num_cols): for col in range(self.num_cols):
col_mux_bl = self.col_mux_array_inst[k].get_pin("bl[{}]".format(i)).uc() col_mux_bl = self.col_mux_array_inst[port].get_pin("bl[{}]".format(col)).uc()
col_mux_br = self.col_mux_array_inst[k].get_pin("br[{}]".format(i)).uc() col_mux_br = self.col_mux_array_inst[port].get_pin("br[{}]".format(col)).uc()
bitcell_bl = self.bitcell_array_inst.get_pin(self.total_bl_list[k]+"[{}]".format(i)).bc() bitcell_bl = self.bitcell_array_inst.get_pin(self.total_bl_list[port]+"[{}]".format(col)).bc()
bitcell_br = self.bitcell_array_inst.get_pin(self.total_br_list[k]+"[{}]".format(i)).bc() bitcell_br = self.bitcell_array_inst.get_pin(self.total_br_list[port]+"[{}]".format(col)).bc()
yoffset = 0.5*(col_mux_bl.y+bitcell_bl.y) yoffset = 0.5*(col_mux_bl.y+bitcell_bl.y)
self.add_path("metal2",[col_mux_bl, vector(col_mux_bl.x,yoffset), self.add_path("metal2",[col_mux_bl, vector(col_mux_bl.x,yoffset),
@ -697,19 +696,19 @@ class bank(design.design):
def route_sense_amp_to_col_mux_or_bitcell_array(self): def route_sense_amp_to_col_mux_or_bitcell_array(self):
""" Routing of BL and BR between sense_amp and column mux or bitcell array """ """ Routing of BL and BR between sense_amp and column mux or bitcell array """
for k in range(self.total_read): for port in range(self.total_read):
for i in range(self.word_size): for bit in range(self.word_size):
sense_amp_bl = self.sense_amp_array_inst[k].get_pin("bl[{}]".format(i)).uc() sense_amp_bl = self.sense_amp_array_inst[port].get_pin("bl[{}]".format(bit)).uc()
sense_amp_br = self.sense_amp_array_inst[k].get_pin("br[{}]".format(i)).uc() sense_amp_br = self.sense_amp_array_inst[port].get_pin("br[{}]".format(bit)).uc()
if self.col_addr_size>0: if self.col_addr_size>0:
# Sense amp is connected to the col mux # Sense amp is connected to the col mux
connect_bl = self.col_mux_array_inst[k].get_pin("bl_out[{}]".format(i)).bc() connect_bl = self.col_mux_array_inst[port].get_pin("bl_out[{}]".format(bit)).bc()
connect_br = self.col_mux_array_inst[k].get_pin("br_out[{}]".format(i)).bc() connect_br = self.col_mux_array_inst[port].get_pin("br_out[{}]".format(bit)).bc()
else: else:
# Sense amp is directly connected to the bitcell array # Sense amp is directly connected to the bitcell array
connect_bl = self.bitcell_array_inst.get_pin(self.read_bl_list[k]+"[{}]".format(i)).bc() connect_bl = self.bitcell_array_inst.get_pin(self.read_bl_list[port]+"[{}]".format(bit)).bc()
connect_br = self.bitcell_array_inst.get_pin(self.read_br_list[k]+"[{}]".format(i)).bc() connect_br = self.bitcell_array_inst.get_pin(self.read_br_list[port]+"[{}]".format(bit)).bc()
yoffset = 0.5*(sense_amp_bl.y+connect_bl.y) yoffset = 0.5*(sense_amp_bl.y+connect_bl.y)
@ -721,9 +720,11 @@ class bank(design.design):
def route_sense_amp_out(self): def route_sense_amp_out(self):
""" Add pins for the sense amp output """ """ Add pins for the sense amp output """
for i in range(self.word_size):
data_pin = self.sense_amp_array_inst[0].get_pin("data[{}]".format(i)) # FIXME: Update for multiport
self.add_layout_pin_rect_center(text="dout0[{}]".format(i), for bit in range(self.word_size):
data_pin = self.sense_amp_array_inst[0].get_pin("data[{}]".format(bit))
self.add_layout_pin_rect_center(text="dout0[{}]".format(bit),
layer=data_pin.layer, layer=data_pin.layer,
offset=data_pin.center(), offset=data_pin.center(),
height=data_pin.height(), height=data_pin.height(),
@ -733,10 +734,11 @@ class bank(design.design):
def route_row_decoder(self): def route_row_decoder(self):
""" Routes the row decoder inputs and supplies """ """ Routes the row decoder inputs and supplies """
# FIXME: Update for multiport
# Create inputs for the row address lines # Create inputs for the row address lines
for i in range(self.row_addr_size): for row in range(self.row_addr_size):
addr_idx = i + self.col_addr_size addr_idx = row + self.col_addr_size
decoder_name = "addr[{}]".format(i) decoder_name = "addr[{}]".format(row)
addr_name = "addr0[{}]".format(addr_idx) addr_name = "addr0[{}]".format(addr_idx)
self.copy_layout_pin(self.row_decoder_inst[0], decoder_name, addr_name) self.copy_layout_pin(self.row_decoder_inst[0], decoder_name, addr_name)
@ -744,9 +746,9 @@ class bank(design.design):
def route_write_driver(self): def route_write_driver(self):
""" Connecting write driver """ """ Connecting write driver """
for i in range(self.word_size): for row in range(self.word_size):
data_name = "data[{}]".format(i) data_name = "data[{}]".format(row)
din_name = "din0[{}]".format(i) din_name = "din0[{}]".format(row)
self.copy_layout_pin(self.write_driver_array_inst[0], data_name, din_name) self.copy_layout_pin(self.write_driver_array_inst[0], data_name, din_name)
@ -754,17 +756,17 @@ class bank(design.design):
def route_wordline_driver(self): def route_wordline_driver(self):
""" Connecting Wordline driver output to Bitcell WL connection """ """ Connecting Wordline driver output to Bitcell WL connection """
for i in range(self.num_rows): for row in range(self.num_rows):
# The pre/post is to access the pin from "outside" the cell to avoid DRCs # The pre/post is to access the pin from "outside" the cell to avoid DRCs
decoder_out_pos = self.row_decoder_inst[0].get_pin("decode[{}]".format(i)).rc() decoder_out_pos = self.row_decoder_inst[0].get_pin("decode[{}]".format(row)).rc()
driver_in_pos = self.wordline_driver_inst[0].get_pin("in[{}]".format(i)).lc() driver_in_pos = self.wordline_driver_inst[0].get_pin("in[{}]".format(row)).lc()
mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0) mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0)
mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1) mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1)
self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos]) self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos])
# The mid guarantees we exit the input cell to the right. # The mid guarantees we exit the input cell to the right.
driver_wl_pos = self.wordline_driver_inst[0].get_pin("wl[{}]".format(i)).rc() driver_wl_pos = self.wordline_driver_inst[0].get_pin("wl[{}]".format(row)).rc()
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_list[0]+"[{}]".format(i)).lc() bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_list[0]+"[{}]".format(row)).lc()
mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0) mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0)
mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1) mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1)
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])

View File

@ -53,11 +53,6 @@ class delay_chain(design.design):
self.add_pin("gnd") self.add_pin("gnd")
def add_modules(self): def add_modules(self):
from importlib import reload
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
self.inv = pinv(route_output=False) self.inv = pinv(route_output=False)
self.add_mod(self.inv) self.add_mod(self.inv)

View File

@ -115,11 +115,11 @@ class dff_inv_array(design.design):
def add_layout_pins(self): def add_layout_pins(self):
for row in range(self.rows): for row in range(self.rows):
for col in range(self.columns): for col in range(self.columns):
# Continous vdd rail along with label. # Adds power pin on left of row
vdd_pin=self.dff_insts[row,col].get_pin("vdd") vdd_pin=self.dff_insts[row,col].get_pin("vdd")
self.add_power_pin("vdd", vdd_pin.lc()) self.add_power_pin("vdd", vdd_pin.lc())
# Continous gnd rail along with label. # Adds gnd pin on left of row
gnd_pin=self.dff_insts[row,col].get_pin("gnd") gnd_pin=self.dff_insts[row,col].get_pin("gnd")
self.add_power_pin("gnd", gnd_pin.lc()) self.add_power_pin("gnd", gnd_pin.lc())

View File

@ -24,7 +24,8 @@ class hierarchical_decoder(design.design):
from importlib import reload from importlib import reload
c = reload(__import__(OPTS.bitcell)) c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell) self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell_height = self.mod_bitcell.height b = self.mod_bitcell()
self.bitcell_height = b.height
self.NAND_FORMAT = "DEC_NAND[{0}]" self.NAND_FORMAT = "DEC_NAND[{0}]"
self.INV_FORMAT = "DEC_INV_[{0}]" self.INV_FORMAT = "DEC_INV_[{0}]"
@ -130,7 +131,7 @@ class hierarchical_decoder(design.design):
self.total_number_of_predecoder_outputs = 4*self.no_of_pre2x4 + 8*self.no_of_pre3x8 self.total_number_of_predecoder_outputs = 4*self.no_of_pre2x4 + 8*self.no_of_pre3x8
else: else:
self.total_number_of_predecoder_outputs = 0 self.total_number_of_predecoder_outputs = 0
debug.error("Not enough rows for a hierarchical decoder. Non-hierarchical not supported yet.",-1) debug.error("Not enough rows ({}) for a hierarchical decoder. Non-hierarchical not supported yet.".format(self.num_inputs),-1)
# Calculates height and width of pre-decoder, # Calculates height and width of pre-decoder,
if self.no_of_pre3x8 > 0: if self.no_of_pre3x8 > 0:

View File

@ -10,7 +10,7 @@ class replica_bitcell(design.design):
is a hand-made cell, so the layout and netlist should be available in is a hand-made cell, so the layout and netlist should be available in
the technology library. """ the technology library. """
pin_names = ["BL", "BR", "WL", "vdd", "gnd"] pin_names = ["bl", "br", "wl", "vdd", "gnd"]
(width,height) = utils.get_libcell_size("replica_cell_6t", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("replica_cell_6t", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_6t", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "replica_cell_6t", GDS["unit"], layer["boundary"])

View File

@ -228,7 +228,7 @@ class replica_bitline(design.design):
# 3. Route the contact of previous route to the bitcell WL # 3. Route the contact of previous route to the bitcell WL
# route bend of previous net to bitcell WL # route bend of previous net to bitcell WL
wl_offset = self.rbc_inst.get_pin("WL").lc() wl_offset = self.rbc_inst.get_pin("wl").lc()
xmid_point= 0.5*(wl_offset.x+contact_offset.x) xmid_point= 0.5*(wl_offset.x+contact_offset.x)
wl_mid1 = vector(xmid_point,contact_offset.y) wl_mid1 = vector(xmid_point,contact_offset.y)
wl_mid2 = vector(xmid_point,wl_offset.y) wl_mid2 = vector(xmid_point,wl_offset.y)
@ -247,7 +247,7 @@ class replica_bitline(design.design):
# Route the connection of the source route to the RBL bitline (left) # Route the connection of the source route to the RBL bitline (left)
# Via will go halfway down from the bitcell # Via will go halfway down from the bitcell
bl_offset = self.rbc_inst.get_pin("BL").bc() bl_offset = self.rbc_inst.get_pin("bl").bc()
# Route down a pitch so we can use M2 routing # Route down a pitch so we can use M2 routing
bl_down_offset = bl_offset - vector(0, self.m2_pitch) bl_down_offset = bl_offset - vector(0, self.m2_pitch)
self.add_path("metal2",[source_offset, bl_down_offset, bl_offset]) self.add_path("metal2",[source_offset, bl_down_offset, bl_offset])

View File

@ -30,7 +30,11 @@ class sense_amp_array(design.design):
def create_layout(self): def create_layout(self):
self.height = self.amp.height self.height = self.amp.height
self.width = self.amp.width * self.word_size * self.words_per_row
if self.bitcell.width > self.amp.width:
self.width = self.bitcell.width * self.word_size * self.words_per_row
else:
self.width = self.amp.width * self.word_size * self.words_per_row
self.place_sense_amp_array() self.place_sense_amp_array()
self.add_layout_pins() self.add_layout_pins()
@ -53,6 +57,11 @@ class sense_amp_array(design.design):
self.amp = self.mod_sense_amp("sense_amp") self.amp = self.mod_sense_amp("sense_amp")
self.add_mod(self.amp) self.add_mod(self.amp)
# This is just used for measurements,
# so don't add the module
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
def create_sense_amp_array(self): def create_sense_amp_array(self):
self.local_insts = [] self.local_insts = []
@ -68,7 +77,10 @@ class sense_amp_array(design.design):
def place_sense_amp_array(self): def place_sense_amp_array(self):
amp_spacing = self.amp.width * self.words_per_row if self.bitcell.width > self.amp.width:
amp_spacing = self.bitcell.width * self.words_per_row
else:
amp_spacing = self.amp.width * self.words_per_row
for i in range(0,self.word_size): for i in range(0,self.word_size):
amp_position = vector(amp_spacing * i, 0) amp_position = vector(amp_spacing * i, 0)
self.local_insts[i].place(amp_position) self.local_insts[i].place(amp_position)

View File

@ -50,6 +50,13 @@ class wordline_driver(design.design):
def add_modules(self): def add_modules(self):
# This is just used for measurements,
# so don't add the module
from importlib import reload
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
self.inv = pinv() self.inv = pinv()
self.add_mod(self.inv) self.add_mod(self.inv)
@ -59,6 +66,7 @@ class wordline_driver(design.design):
self.nand2 = pnand2() self.nand2 = pnand2()
self.add_mod(self.nand2) self.add_mod(self.nand2)
def route_vdd_gnd(self): def route_vdd_gnd(self):
""" Add a pin for each row of vdd/gnd which are must-connects next level up. """ """ Add a pin for each row of vdd/gnd which are must-connects next level up. """
@ -125,16 +133,20 @@ class wordline_driver(design.design):
nand2_xoffset = inv1_xoffset + self.inv.width nand2_xoffset = inv1_xoffset + self.inv.width
inv2_xoffset = nand2_xoffset + self.nand2.width inv2_xoffset = nand2_xoffset + self.nand2.width
self.width = inv2_xoffset + self.inv.width self.width = inv2_xoffset + self.inv.height
self.height = self.inv.height * self.rows if self.bitcell.height > self.inv.height:
self.height = self.bitcell.height * self.rows
driver_height = self.bitcell.height
else:
self.height = self.inv.height * self.rows
driver_height = self.inv.height
for row in range(self.rows): for row in range(self.rows):
if (row % 2): if (row % 2):
y_offset = self.inv.height*(row + 1) y_offset = driver_height*(row + 1)
inst_mirror = "MX" inst_mirror = "MX"
else: else:
y_offset = self.inv.height*row y_offset = driver_height*row
inst_mirror = "R0" inst_mirror = "R0"
inv1_offset = [inv1_xoffset, y_offset] inv1_offset = [inv1_xoffset, y_offset]

View File

@ -30,7 +30,12 @@ class write_driver_array(design.design):
self.create_write_array() self.create_write_array()
def create_layout(self): def create_layout(self):
self.width = self.columns * self.driver.width
if self.bitcell.width > self.driver.width:
self.width = self.columns * self.bitcell.width
else:
self.width = self.columns * self.driver.width
self.height = self.driver.height self.height = self.driver.height
self.place_write_array() self.place_write_array()
@ -54,6 +59,12 @@ class write_driver_array(design.design):
self.driver = self.mod_write_driver("write_driver") self.driver = self.mod_write_driver("write_driver")
self.add_mod(self.driver) self.add_mod(self.driver)
# This is just used for measurements,
# so don't add the module
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
def create_write_array(self): def create_write_array(self):
self.driver_insts = {} self.driver_insts = {}
for i in range(0,self.columns,self.words_per_row): for i in range(0,self.columns,self.words_per_row):
@ -69,9 +80,14 @@ class write_driver_array(design.design):
def place_write_array(self): def place_write_array(self):
if self.bitcell.width > self.driver.width:
driver_spacing = self.bitcell.width
else:
driver_spacing = self.driver.width
for i in range(0,self.columns,self.words_per_row): for i in range(0,self.columns,self.words_per_row):
index = int(i/self.words_per_row) index = int(i/self.words_per_row)
base = vector(i * self.driver.width,0) base = vector(i * driver_spacing,0)
self.driver_insts[index].place(base) self.driver_insts[index].place(base)

View File

@ -38,7 +38,8 @@ report_status()
# Start importing design modules after we have the config file # Start importing design modules after we have the config file
import verify import verify
import sram from sram import sram
from sram_config import sram_config
output_extensions = ["sp","v","lib"] output_extensions = ["sp","v","lib"]
if not OPTS.netlist_only: if not OPTS.netlist_only:
@ -51,11 +52,13 @@ print(*output_files,sep="\n")
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
print_time("Start",start_time) print_time("Start",start_time)
# Configure the SRAM organization
c = sram_config(word_size=OPTS.word_size,
num_words=OPTS.num_words)
# import SRAM test generation # import SRAM test generation
s = sram.sram(word_size=OPTS.word_size, s = sram(sram_config=c,
num_words=OPTS.num_words, name=OPTS.output_name)
num_banks=OPTS.num_banks,
name=OPTS.output_name)
# Output the files for the resulting SRAM # Output the files for the resulting SRAM
s.save() s.save()

View File

@ -52,14 +52,20 @@ class options(optparse.Values):
purge_temp = True purge_temp = True
# These are the configuration parameters # These are the configuration parameters
rw_ports = 1 num_rw_ports = 1
r_ports = 0 num_r_ports = 0
w_ports = 0 num_w_ports = 0
# These will get initialized by the the file # These will get initialized by the the file
supply_voltages = "" supply_voltages = ""
temperatures = "" temperatures = ""
process_corners = "" process_corners = ""
# These are the main configuration parameters that should be over-ridden
# in a configuration file.
#num_words = 0
#num_banks = 1
#word_size = 0
# These are the default modules that can be over-riden # These are the default modules that can be over-riden
decoder = "hierarchical_decoder" decoder = "hierarchical_decoder"

View File

@ -1,5 +1,4 @@
import contact import contact
import pgate
import design import design
import debug import debug
from tech import drc, parameter, spice from tech import drc, parameter, spice
@ -7,35 +6,29 @@ from vector import vector
from ptx import ptx from ptx import ptx
from globals import OPTS from globals import OPTS
class pbitcell(pgate.pgate): class pbitcell(design.design):
""" """
This module implements a parametrically sized multi-port bitcell, This module implements a parametrically sized multi-port bitcell,
with a variable number of read/write, write, and read ports with a variable number of read/write, write, and read ports
""" """
width = None def __init__(self):
height = None
unique_id = 1 self.num_rw_ports = OPTS.num_rw_ports
self.num_w_ports = OPTS.num_w_ports
self.num_r_ports = OPTS.num_r_ports
def __init__(self, num_readwrite=OPTS.rw_ports, num_write=OPTS.w_ports, num_read=OPTS.r_ports): name = "pbitcell_{0}RW_{1}W_{2}R".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports)
name = "pbitcell_{0}RW_{1}W_{2}R_{3}".format(num_readwrite, num_write, num_read, pbitcell.unique_id) # This is not a pgate because pgates depend on the bitcell height!
pbitcell.unique_id += 1 design.design.__init__(self, name)
pgate.pgate.__init__(self, name) debug.info(2, "create a multi-port bitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports,
debug.info(2, "create a multi-port bitcell with {0} write ports and {1} read ports".format(num_write, num_read)) self.num_w_ports,
self.num_r_ports))
self.num_readwrite = num_readwrite
self.num_write = num_write
self.num_read = num_read
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: # We must always create the bitcell layout because
self.create_layout() # some transistor sizes in the other netlists depend on it
self.create_layout()
# FIXME: Why is this static set here?
pbitcell.width = self.width
pbitcell.height = self.height
def create_netlist(self): def create_netlist(self):
@ -43,11 +36,11 @@ class pbitcell(pgate.pgate):
self.add_modules() self.add_modules()
self.create_storage() self.create_storage()
if(self.num_readwrite > 0): if(self.num_rw_ports > 0):
self.create_readwrite_ports() self.create_readwrite_ports()
if(self.num_write > 0): if(self.num_w_ports > 0):
self.create_write_ports() self.create_write_ports()
if(self.num_read > 0): if(self.num_r_ports > 0):
self.create_read_ports() self.create_read_ports()
def create_layout(self): def create_layout(self):
@ -58,11 +51,11 @@ class pbitcell(pgate.pgate):
self.route_storage() self.route_storage()
self.route_rails() self.route_rails()
if(self.num_readwrite > 0): if(self.num_rw_ports > 0):
self.place_readwrite_ports() self.place_readwrite_ports()
if(self.num_write > 0): if(self.num_w_ports > 0):
self.place_write_ports() self.place_write_ports()
if(self.num_read > 0): if(self.num_r_ports > 0):
self.place_read_ports() self.place_read_ports()
self.extend_well() self.extend_well()
@ -70,31 +63,30 @@ class pbitcell(pgate.pgate):
self.DRC_LVS() self.DRC_LVS()
def add_pins(self): def add_pins(self):
for k in range(self.num_readwrite): for k in range(self.num_rw_ports):
self.add_pin("rwbl{}".format(k)) self.add_pin("rwbl{}".format(k))
self.add_pin("rwbl_bar{}".format(k)) self.add_pin("rwbl_bar{}".format(k))
for k in range(self.num_write): for k in range(self.num_w_ports):
self.add_pin("wbl{}".format(k)) self.add_pin("wbl{}".format(k))
self.add_pin("wbl_bar{}".format(k)) self.add_pin("wbl_bar{}".format(k))
for k in range(self.num_read): for k in range(self.num_r_ports):
self.add_pin("rbl{}".format(k)) self.add_pin("rbl{}".format(k))
self.add_pin("rbl_bar{}".format(k)) self.add_pin("rbl_bar{}".format(k))
for k in range(self.num_readwrite): for k in range(self.num_rw_ports):
self.add_pin("rwwl{}".format(k)) self.add_pin("rwwl{}".format(k))
for k in range(self.num_write): for k in range(self.num_w_ports):
self.add_pin("wwl{}".format(k)) self.add_pin("wwl{}".format(k))
for k in range(self.num_read): for k in range(self.num_r_ports):
self.add_pin("rwl{}".format(k)) self.add_pin("rwl{}".format(k))
self.add_pin("vdd") self.add_pin("vdd")
self.add_pin("gnd") self.add_pin("gnd")
def add_modules(self): def add_modules(self):
# if there are any read/write ports, then the inverter nmos is sized based the number of them # if there are any read/write ports, then the inverter nmos is sized based the number of them
if(self.num_readwrite > 0): if(self.num_rw_ports > 0):
inverter_nmos_width = self.num_readwrite*3*parameter["min_tx_size"] inverter_nmos_width = self.num_rw_ports*3*parameter["min_tx_size"]
inverter_pmos_width = parameter["min_tx_size"] inverter_pmos_width = parameter["min_tx_size"]
readwrite_nmos_width = 1.5*parameter["min_tx_size"] readwrite_nmos_width = 1.5*parameter["min_tx_size"]
write_nmos_width = parameter["min_tx_size"] write_nmos_width = parameter["min_tx_size"]
@ -133,7 +125,6 @@ class pbitcell(pgate.pgate):
tx_type="nmos") tx_type="nmos")
self.add_mod(self.read_nmos) self.add_mod(self.read_nmos)
def calculate_spacing(self): def calculate_spacing(self):
""" Calculate transistor spacings """ """ Calculate transistor spacings """
@ -153,15 +144,15 @@ class pbitcell(pgate.pgate):
# readwrite to readwrite transistor spacing (also acts as readwrite to write transistor spacing) # readwrite to readwrite transistor spacing (also acts as readwrite to write transistor spacing)
if(self.readwrite_nmos_contact_extension > self.gate_contact_thres): if(self.readwrite_nmos_contact_extension > self.gate_contact_thres):
self.readwrite_to_readwrite_spacing = drc["minwidth_metal2"] + self.readwrite_nmos_contact_extension + contact.poly.width + drc["poly_to_field_poly"] + drc["poly_extend_active"] self.readwrite_to_readwrite_spacing = drc["minwidth_metal2"] + self.readwrite_nmos_contact_extension + contact.poly.width + drc["poly_to_polycontact"] + drc["poly_extend_active"]
else: else:
self.readwrite_to_readwrite_spacing = drc["poly_to_active"] + contact.poly.width + drc["poly_to_field_poly"] + drc["poly_extend_active"] self.readwrite_to_readwrite_spacing = drc["poly_to_active"] + contact.poly.width + drc["poly_to_polycontact"] + drc["poly_extend_active"]
# write to write transistor spacing # write to write transistor spacing
if(self.write_nmos_contact_extension > self.gate_contact_thres): if(self.write_nmos_contact_extension > self.gate_contact_thres):
self.write_to_write_spacing = drc["minwidth_metal2"] + self.write_nmos_contact_extension + contact.poly.width + drc["poly_to_field_poly"] + drc["poly_extend_active"] self.write_to_write_spacing = drc["minwidth_metal2"] + self.write_nmos_contact_extension + contact.poly.width + drc["poly_to_polycontact"] + drc["poly_extend_active"]
else: else:
self.write_to_write_spacing = drc["poly_to_active"] + contact.poly.width + drc["poly_to_field_poly"] + drc["poly_extend_active"] self.write_to_write_spacing = drc["poly_to_active"] + contact.poly.width + drc["poly_to_polycontact"] + drc["poly_extend_active"]
# read to read transistor spacing # read to read transistor spacing
if(self.read_nmos_contact_extension > self.gate_contact_thres): if(self.read_nmos_contact_extension > self.gate_contact_thres):
@ -171,7 +162,7 @@ class pbitcell(pgate.pgate):
# write to read transistor spacing (also acts as readwrite to read transistor spacing) # write to read transistor spacing (also acts as readwrite to read transistor spacing)
# calculation is dependent on whether the read transistor is adjacent to a write transistor or a readwrite transistor # calculation is dependent on whether the read transistor is adjacent to a write transistor or a readwrite transistor
if(self.num_write > 0): if(self.num_w_ports > 0):
if(self.write_nmos_contact_extension > self.gate_contact_thres): if(self.write_nmos_contact_extension > self.gate_contact_thres):
write_portion = drc["minwidth_metal2"] + self.write_nmos_contact_extension write_portion = drc["minwidth_metal2"] + self.write_nmos_contact_extension
else: else:
@ -187,7 +178,7 @@ class pbitcell(pgate.pgate):
else: else:
read_portion = drc["poly_to_active"] read_portion = drc["poly_to_active"]
self.write_to_read_spacing = write_portion + read_portion + 2*contact.poly.width + drc["poly_to_field_poly"] self.write_to_read_spacing = write_portion + read_portion + 2*contact.poly.width + drc["poly_to_polycontact"]
""" calculations for transistor tiling (transistor + spacing) """ """ calculations for transistor tiling (transistor + spacing) """
self.inverter_tile_width = self.inverter_nmos.active_width + 0.5*self.inverter_to_inverter_spacing self.inverter_tile_width = self.inverter_nmos.active_width + 0.5*self.inverter_to_inverter_spacing
@ -196,13 +187,13 @@ class pbitcell(pgate.pgate):
self.read_tile_width = self.read_to_read_spacing + self.read_nmos.active_height self.read_tile_width = self.read_to_read_spacing + self.read_nmos.active_height
""" calculation for row line tiling """ """ calculation for row line tiling """
self.rail_tile_height = drc["active_to_body_active"] + 0.5*(drc["minwidth_tx"] - drc["minwidth_metal1"]) + drc["minwidth_metal1"] self.rail_tile_height = drc["active_to_body_active"] + contact.well.width #0.5*(drc["minwidth_tx"] - drc["minwidth_metal1"]) + drc["minwidth_metal1"]
self.rowline_tile_height = drc["minwidth_metal1"] + contact.m1m2.width self.rowline_tile_height = drc["minwidth_metal1"] + contact.m1m2.width
""" calculations related to inverter connections """ """ calculations related to inverter connections """
self.inverter_gap = drc["poly_to_active"] + drc["poly_to_field_poly"] + 2*contact.poly.width + drc["minwidth_metal1"] + self.inverter_pmos_contact_extension self.inverter_gap = drc["poly_to_active"] + drc["poly_to_polycontact"] + 2*contact.poly.width + drc["minwidth_metal1"] + self.inverter_pmos_contact_extension
self.cross_couple_lower_ypos = self.inverter_nmos.active_height + drc["poly_to_active"] + 0.5*contact.poly.width self.cross_couple_lower_ypos = self.inverter_nmos.active_height + drc["poly_to_active"] + 0.5*contact.poly.width
self.cross_couple_upper_ypos = self.inverter_nmos.active_height + drc["poly_to_active"] + drc["poly_to_field_poly"] + 1.5*contact.poly.width self.cross_couple_upper_ypos = self.inverter_nmos.active_height + drc["poly_to_active"] + drc["poly_to_polycontact"] + 1.5*contact.poly.width
def calculate_postions(self): def calculate_postions(self):
@ -210,23 +201,23 @@ class pbitcell(pgate.pgate):
Calculate positions that describe the edges of the cell Calculate positions that describe the edges of the cell
""" """
# create flags for excluding readwrite, write, or read port calculations if they are not included in the bitcell # create flags for excluding readwrite, write, or read port calculations if they are not included in the bitcell
if(self.num_readwrite > 0): if(self.num_rw_ports > 0):
self.readwrite_port_flag = True self.readwrite_port_flag = True
else: else:
self.readwrite_port_flag = False self.readwrite_port_flag = False
if(self.num_write > 0): if(self.num_w_ports > 0):
self.write_port_flag = True self.write_port_flag = True
else: else:
self.write_port_flag = False self.write_port_flag = False
if(self.num_read > 0): if(self.num_r_ports > 0):
self.read_port_flag = True self.read_port_flag = True
else: else:
self.read_port_flag = False self.read_port_flag = False
# determine the distance of the leftmost/rightmost transistor gate connection # determine the distance of the leftmost/rightmost transistor gate connection
if (self.num_read > 0): if (self.num_r_ports > 0):
if(self.read_nmos_contact_extension > self.gate_contact_thres): if(self.read_nmos_contact_extension > self.gate_contact_thres):
end_connection = drc["minwidth_metal2"] + self.read_nmos_contact_extension + contact.m1m2.height end_connection = drc["minwidth_metal2"] + self.read_nmos_contact_extension + contact.m1m2.height
else: else:
@ -240,22 +231,22 @@ class pbitcell(pgate.pgate):
# leftmost position = storage width + read/write ports width + write ports width + read ports width + end transistor gate connections + metal spacing necessary for tiling the bitcell # leftmost position = storage width + read/write ports width + write ports width + read ports width + end transistor gate connections + metal spacing necessary for tiling the bitcell
self.leftmost_xpos = -self.inverter_tile_width \ self.leftmost_xpos = -self.inverter_tile_width \
- self.inverter_to_write_spacing \ - self.inverter_to_write_spacing \
- self.readwrite_port_flag*(self.readwrite_nmos.active_height + (self.num_readwrite-1)*self.readwrite_tile_width) \ - self.readwrite_port_flag*(self.readwrite_nmos.active_height + (self.num_rw_ports-1)*self.readwrite_tile_width) \
- self.write_port_flag*self.readwrite_port_flag*self.write_to_write_spacing \ - self.write_port_flag*self.readwrite_port_flag*self.write_to_write_spacing \
- self.write_port_flag*(self.write_nmos.active_height + (self.num_write-1)*self.write_tile_width) \ - self.write_port_flag*(self.write_nmos.active_height + (self.num_w_ports-1)*self.write_tile_width) \
- self.read_port_flag*self.write_to_read_spacing \ - self.read_port_flag*self.write_to_read_spacing \
- self.read_port_flag*(self.read_nmos.active_height + (self.num_read-1)*self.read_tile_width) \ - self.read_port_flag*(self.read_nmos.active_height + (self.num_r_ports-1)*self.read_tile_width) \
- end_connection \ - end_connection \
- 0.5*drc["minwidth_metal2"] - 0.5*drc["poly_to_polycontact"]
self.rightmost_xpos = -self.leftmost_xpos self.rightmost_xpos = -self.leftmost_xpos
# bottommost position = gnd height + rwwl height + wwl height + rwl height + space needed between tiled bitcells # bottommost position = gnd height + rwwl height + wwl height + rwl height + space needed between tiled bitcells
array_tiling_offset = 0.5*drc["minwidth_metal2"] array_tiling_offset = 0.5*drc["minwidth_metal2"]
self.botmost_ypos = -self.rail_tile_height \ self.botmost_ypos = -self.rail_tile_height \
- self.num_readwrite*self.rowline_tile_height \ - self.num_rw_ports*self.rowline_tile_height \
- self.num_write*self.rowline_tile_height \ - self.num_w_ports*self.rowline_tile_height \
- self.num_read*self.rowline_tile_height \ - self.num_r_ports*self.rowline_tile_height \
- array_tiling_offset - array_tiling_offset
# topmost position = height of the inverter + height of vdd # topmost position = height of the inverter + height of vdd
@ -263,11 +254,36 @@ class pbitcell(pgate.pgate):
+ self.rail_tile_height + self.rail_tile_height
# calculations for the cell dimensions # calculations for the cell dimensions
array_vdd_overlap = 0.5*drc["minwidth_metal1"] array_vdd_overlap = 0.5*contact.well.width
self.width = -2*self.leftmost_xpos self.width = -2*self.leftmost_xpos
self.height = self.topmost_ypos - self.botmost_ypos - array_vdd_overlap self.height = self.topmost_ypos - self.botmost_ypos - array_vdd_overlap
def create_storage(self):
"""
Creates the crossed coupled inverters that act as storage for the bitcell.
The stored value of the cell is denoted as "Q", and the inverted value as "Q_bar".
"""
# create active for nmos
self.inverter_nmos_left = self.add_inst(name="inverter_nmos_left",
mod=self.inverter_nmos)
self.connect_inst(["Q_bar", "Q", "gnd", "gnd"])
self.inverter_nmos_right = self.add_inst(name="inverter_nmos_right",
mod=self.inverter_nmos)
self.connect_inst(["gnd", "Q_bar", "Q", "gnd"])
# create active for pmos
self.inverter_pmos_left = self.add_inst(name="inverter_pmos_left",
mod=self.inverter_pmos)
self.connect_inst(["Q_bar", "Q", "vdd", "vdd"])
self.inverter_pmos_right = self.add_inst(name="inverter_pmos_right",
mod=self.inverter_pmos)
self.connect_inst(["vdd", "Q_bar", "Q", "vdd"])
def place_storage(self): def place_storage(self):
""" """
Places the crossed coupled inverters that act as storage for the bitcell. Places the crossed coupled inverters that act as storage for the bitcell.
@ -320,31 +336,6 @@ class pbitcell(pgate.pgate):
self.right_building_edge = self.inverter_tile_width self.right_building_edge = self.inverter_tile_width
def create_storage(self):
"""
Creates the crossed coupled inverters that act as storage for the bitcell.
The stored value of the cell is denoted as "Q", and the inverted value as "Q_bar".
"""
# create active for nmos
self.inverter_nmos_left = self.add_inst(name="inverter_nmos_left",
mod=self.inverter_nmos)
self.connect_inst(["Q_bar", "Q", "gnd", "gnd"])
self.inverter_nmos_right = self.add_inst(name="inverter_nmos_right",
mod=self.inverter_nmos)
self.connect_inst(["gnd", "Q_bar", "Q", "gnd"])
# create active for pmos
self.inverter_pmos_left = self.add_inst(name="inverter_pmos_left",
mod=self.inverter_pmos)
self.connect_inst(["Q_bar", "Q", "vdd", "vdd"])
self.inverter_pmos_right = self.add_inst(name="inverter_pmos_right",
mod=self.inverter_pmos)
self.connect_inst(["vdd", "Q_bar", "Q", "vdd"])
def route_rails(self): def route_rails(self):
""" """
Add gnd and vdd rails and connects them to the inverters Add gnd and vdd rails and connects them to the inverters
@ -394,11 +385,11 @@ class pbitcell(pgate.pgate):
""" """
# define write transistor variables as empty arrays based on the number of write ports # define write transistor variables as empty arrays based on the number of write ports
self.readwrite_nmos_left = [None] * self.num_readwrite self.readwrite_nmos_left = [None] * self.num_rw_ports
self.readwrite_nmos_right = [None] * self.num_readwrite self.readwrite_nmos_right = [None] * self.num_rw_ports
# iterate over the number of read/write ports # iterate over the number of read/write ports
for k in range(0,self.num_readwrite): for k in range(0,self.num_rw_ports):
# add read/write transistors # add read/write transistors
self.readwrite_nmos_left[k] = self.add_inst(name="readwrite_nmos_left{}".format(k), self.readwrite_nmos_left[k] = self.add_inst(name="readwrite_nmos_left{}".format(k),
mod=self.readwrite_nmos) mod=self.readwrite_nmos)
@ -415,15 +406,15 @@ class pbitcell(pgate.pgate):
""" """
# Define variables relevant to write transistors # Define variables relevant to write transistors
self.rwwl_positions = [None] * self.num_readwrite self.rwwl_positions = [None] * self.num_rw_ports
self.rwbl_positions = [None] * self.num_readwrite self.rwbl_positions = [None] * self.num_rw_ports
self.rwbl_bar_positions = [None] * self.num_readwrite self.rwbl_bar_positions = [None] * self.num_rw_ports
# define offset correction due to rotation of the ptx module # define offset correction due to rotation of the ptx module
readwrite_rotation_correct = self.readwrite_nmos.active_height readwrite_rotation_correct = self.readwrite_nmos.active_height
# iterate over the number of read/write ports # iterate over the number of read/write ports
for k in range(0,self.num_readwrite): for k in range(0,self.num_rw_ports):
# Add transistors # Add transistors
# calculate read/write transistor offsets # calculate read/write transistor offsets
left_readwrite_transistor_xpos = self.left_building_edge \ left_readwrite_transistor_xpos = self.left_building_edge \
@ -533,14 +524,14 @@ class pbitcell(pgate.pgate):
# Drain/Storage connections # Drain/Storage connections
# this path only needs to be drawn once on the last iteration of the loop # this path only needs to be drawn once on the last iteration of the loop
if(k == self.num_readwrite-1): if(k == self.num_rw_ports-1):
# add contacts to connect gate of inverters to drain of read/write transistors # add contacts to connect gate of inverters to drain of read/write transistors
left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x - drc["poly_to_field_poly"] - 0.5*contact.poly.width, self.cross_couple_lower_ypos) left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x - drc["poly_to_polycontact"] - 0.5*contact.poly.width, self.cross_couple_lower_ypos)
self.add_contact_center(layers=("poly", "contact", "metal1"), self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=left_storage_contact, offset=left_storage_contact,
rotate=90) rotate=90)
right_storage_contact = vector(self.inverter_nmos_right.get_pin("G").rc().x + drc["poly_to_field_poly"] + 0.5*contact.poly.width, self.cross_couple_lower_ypos) right_storage_contact = vector(self.inverter_nmos_right.get_pin("G").rc().x + drc["poly_to_polycontact"] + 0.5*contact.poly.width, self.cross_couple_lower_ypos)
self.add_contact_center(layers=("poly", "contact", "metal1"), self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=right_storage_contact, offset=right_storage_contact,
rotate=90) rotate=90)
@ -584,11 +575,11 @@ class pbitcell(pgate.pgate):
write_rotation_correct = self.write_nmos.active_height write_rotation_correct = self.write_nmos.active_height
# define write transistor variables as empty arrays based on the number of write ports # define write transistor variables as empty arrays based on the number of write ports
self.write_nmos_left = [None] * self.num_write self.write_nmos_left = [None] * self.num_w_ports
self.write_nmos_right = [None] * self.num_write self.write_nmos_right = [None] * self.num_w_ports
# iterate over the number of write ports # iterate over the number of write ports
for k in range(0,self.num_write): for k in range(0,self.num_w_ports):
# add write transistors # add write transistors
self.write_nmos_left[k] = self.add_inst(name="write_nmos_left{}".format(k), self.write_nmos_left[k] = self.add_inst(name="write_nmos_left{}".format(k),
mod=self.write_nmos) mod=self.write_nmos)
@ -605,15 +596,15 @@ class pbitcell(pgate.pgate):
""" """
# Define variables relevant to write transistors # Define variables relevant to write transistors
self.wwl_positions = [None] * self.num_write self.wwl_positions = [None] * self.num_w_ports
self.wbl_positions = [None] * self.num_write self.wbl_positions = [None] * self.num_w_ports
self.wbl_bar_positions = [None] * self.num_write self.wbl_bar_positions = [None] * self.num_w_ports
# define offset correction due to rotation of the ptx module # define offset correction due to rotation of the ptx module
write_rotation_correct = self.write_nmos.active_height write_rotation_correct = self.write_nmos.active_height
# iterate over the number of write ports # iterate over the number of write ports
for k in range(0,self.num_write): for k in range(0,self.num_w_ports):
# Add transistors # Add transistors
# calculate write transistor offsets # calculate write transistor offsets
left_write_transistor_xpos = self.left_building_edge \ left_write_transistor_xpos = self.left_building_edge \
@ -638,7 +629,7 @@ class pbitcell(pgate.pgate):
# Add WWL lines # Add WWL lines
# calculate WWL position # calculate WWL position
wwl_ypos = self.gnd_position.y \ wwl_ypos = self.gnd_position.y \
- self.num_readwrite*self.rowline_tile_height \ - self.num_rw_ports*self.rowline_tile_height \
- (k+1)*self.rowline_tile_height - (k+1)*self.rowline_tile_height
self.wwl_positions[k] = vector(self.leftmost_xpos, wwl_ypos) self.wwl_positions[k] = vector(self.leftmost_xpos, wwl_ypos)
@ -727,14 +718,14 @@ class pbitcell(pgate.pgate):
# Drain/Storage connections # Drain/Storage connections
# this path only needs to be drawn once on the last iteration of the loop # this path only needs to be drawn once on the last iteration of the loop
if(k == self.num_write-1): if(k == self.num_w_ports-1):
# add contacts to connect gate of inverters to drain of write transistors # add contacts to connect gate of inverters to drain of write transistors
left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x - drc["poly_to_field_poly"] - 0.5*contact.poly.width, self.cross_couple_lower_ypos) left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x - drc["poly_to_polycontact"] - 0.5*contact.poly.width, self.cross_couple_lower_ypos)
self.add_contact_center(layers=("poly", "contact", "metal1"), self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=left_storage_contact, offset=left_storage_contact,
rotate=90) rotate=90)
right_storage_contact = vector(self.inverter_nmos_right.get_pin("G").rc().x + drc["poly_to_field_poly"] + 0.5*contact.poly.width, self.cross_couple_lower_ypos) right_storage_contact = vector(self.inverter_nmos_right.get_pin("G").rc().x + drc["poly_to_polycontact"] + 0.5*contact.poly.width, self.cross_couple_lower_ypos)
self.add_contact_center(layers=("poly", "contact", "metal1"), self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=right_storage_contact, offset=right_storage_contact,
rotate=90) rotate=90)
@ -775,13 +766,13 @@ class pbitcell(pgate.pgate):
""" """
# define read transistor variables as empty arrays based on the number of read ports # define read transistor variables as empty arrays based on the number of read ports
self.read_nmos_left = [None] * self.num_read self.read_nmos_left = [None] * self.num_r_ports
self.read_nmos_right = [None] * self.num_read self.read_nmos_right = [None] * self.num_r_ports
self.read_access_nmos_left = [None] * self.num_read self.read_access_nmos_left = [None] * self.num_r_ports
self.read_access_nmos_right = [None] * self.num_read self.read_access_nmos_right = [None] * self.num_r_ports
# iterate over the number of read ports # iterate over the number of read ports
for k in range(0,self.num_read): for k in range(0,self.num_r_ports):
# add read-access transistors # add read-access transistors
self.read_access_nmos_left[k] = self.add_inst(name="read_access_nmos_left{}".format(k), self.read_access_nmos_left[k] = self.add_inst(name="read_access_nmos_left{}".format(k),
mod=self.read_nmos) mod=self.read_nmos)
@ -806,9 +797,9 @@ class pbitcell(pgate.pgate):
""" """
# Define variables relevant to read transistors # Define variables relevant to read transistors
self.rwl_positions = [None] * self.num_read self.rwl_positions = [None] * self.num_r_ports
self.rbl_positions = [None] * self.num_read self.rbl_positions = [None] * self.num_r_ports
self.rbl_bar_positions = [None] * self.num_read self.rbl_bar_positions = [None] * self.num_r_ports
# define offset correction due to rotation of the ptx module # define offset correction due to rotation of the ptx module
read_rotation_correct = self.read_nmos.active_height read_rotation_correct = self.read_nmos.active_height
@ -816,17 +807,8 @@ class pbitcell(pgate.pgate):
# calculate offset to overlap the drain of the read-access transistor with the source of the read transistor # calculate offset to overlap the drain of the read-access transistor with the source of the read transistor
overlap_offset = self.read_nmos.get_pin("D").ll() - self.read_nmos.get_pin("S").ll() overlap_offset = self.read_nmos.get_pin("D").ll() - self.read_nmos.get_pin("S").ll()
# define read transistor variables as empty arrays based on the number of read ports
self.read_nmos_left = [None] * self.num_read
self.read_nmos_right = [None] * self.num_read
self.read_access_nmos_left = [None] * self.num_read
self.read_access_nmos_right = [None] * self.num_read
self.rwl_positions = [None] * self.num_read
self.rbl_positions = [None] * self.num_read
self.rbl_bar_positions = [None] * self.num_read
# iterate over the number of read ports # iterate over the number of read ports
for k in range(0,self.num_read): for k in range(0,self.num_r_ports):
# Add transistors # Add transistors
# calculate transistor offsets # calculate transistor offsets
left_read_transistor_xpos = self.left_building_edge \ left_read_transistor_xpos = self.left_building_edge \
@ -840,36 +822,24 @@ class pbitcell(pgate.pgate):
+ read_rotation_correct + read_rotation_correct
# add read-access transistors # add read-access transistors
self.read_access_nmos_left[k] = self.add_inst(name="read_access_nmos_left{}".format(k), self.read_access_nmos_left[k].place(offset=[left_read_transistor_xpos,0],
mod=self.read_nmos, rotate=90)
offset=[left_read_transistor_xpos,0],
rotate=90)
self.connect_inst(["RA_to_R_left{}".format(k), " Q_bar", "gnd", "gnd"])
self.read_access_nmos_right[k] = self.add_inst(name="read_access_nmos_right{}".format(k), self.read_access_nmos_right[k].place(offset=[right_read_transistor_xpos,0],
mod=self.read_nmos, rotate=90)
offset=[right_read_transistor_xpos,0],
rotate=90)
self.connect_inst(["RA_to_R_right{}".format(k), "Q", "gnd", "gnd"])
# add read transistors # add read transistors
self.read_nmos_left[k] = self.add_inst(name="read_nmos_left{}".format(k), self.read_nmos_left[k].place(offset=[left_read_transistor_xpos,overlap_offset.x],
mod=self.read_nmos, rotate=90)
offset=[left_read_transistor_xpos,overlap_offset.x],
rotate=90)
self.connect_inst(["rbl{}".format(k), "rwl{}".format(k), "RA_to_R_left{}".format(k), "gnd"])
self.read_nmos_right[k] = self.add_inst(name="read_nmos_right{}".format(k), self.read_nmos_right[k].place(offset=[right_read_transistor_xpos,overlap_offset.x],
mod=self.read_nmos, rotate=90)
offset=[right_read_transistor_xpos,overlap_offset.x],
rotate=90)
self.connect_inst(["rbl_bar{}".format(k), "rwl{}".format(k), "RA_to_R_right{}".format(k), "gnd"])
# Add RWL lines # Add RWL lines
# calculate RWL position # calculate RWL position
rwl_ypos = self.gnd_position.y \ rwl_ypos = self.gnd_position.y \
- self.num_readwrite*self.rowline_tile_height \ - self.num_rw_ports*self.rowline_tile_height \
- self.num_write*self.rowline_tile_height \ - self.num_w_ports*self.rowline_tile_height \
- (k+1)*self.rowline_tile_height - (k+1)*self.rowline_tile_height
self.rwl_positions[k] = vector(self.leftmost_xpos, rwl_ypos) self.rwl_positions[k] = vector(self.leftmost_xpos, rwl_ypos)
@ -1028,7 +998,7 @@ class pbitcell(pgate.pgate):
# extend pwell over read/write and write transistors to the # extend pwell over read/write and write transistors to the
# height of the write transistor well (read/write and write # height of the write transistor well (read/write and write
# transistors are the same height) # transistors are the same height)
if(self.num_write > 0): if(self.num_w_ports > 0):
# calculate the edge of the write transistor well closest to the center # calculate the edge of the write transistor well closest to the center
left_write_well_xpos = self.write_nmos_left[0].offset.x + drc["well_enclosure_active"] left_write_well_xpos = self.write_nmos_left[0].offset.x + drc["well_enclosure_active"]
right_write_well_xpos = self.write_nmos_right[0].offset.x - self.write_nmos.active_height - drc["well_enclosure_active"] right_write_well_xpos = self.write_nmos_right[0].offset.x - self.write_nmos.active_height - drc["well_enclosure_active"]
@ -1054,7 +1024,7 @@ class pbitcell(pgate.pgate):
height=write_well_height) height=write_well_height)
# extend pwell over the read transistors to the height of the bitcell # extend pwell over the read transistors to the height of the bitcell
if(self.num_read > 0): if(self.num_r_ports > 0):
# calculate the edge of the read transistor well clostest to the center # calculate the edge of the read transistor well clostest to the center
left_read_well_xpos = self.read_nmos_left[0].offset.x + drc["well_enclosure_active"] left_read_well_xpos = self.read_nmos_left[0].offset.x + drc["well_enclosure_active"]
right_read_well_xpos = self.read_nmos_right[0].offset.x - self.read_nmos.active_height - drc["well_enclosure_active"] right_read_well_xpos = self.read_nmos_right[0].offset.x - self.read_nmos.active_height - drc["well_enclosure_active"]
@ -1097,42 +1067,36 @@ class pbitcell(pgate.pgate):
offset = vector(0, self.gnd_position.y + 0.5*contact.well.second_layer_width) offset = vector(0, self.gnd_position.y + 0.5*contact.well.second_layer_width)
self.add_contact_center(layers=("active", "contact", "metal1"), self.add_contact_center(layers=("active", "contact", "metal1"),
offset=offset, offset=offset,
rotate=90) rotate=90,
implant_type="p",
self.add_rect_center(layer="pimplant", well_type="p")
offset=offset,
width=drc["minwidth_tx"],
height=drc["minwidth_tx"])
# connect nimplants to vdd # connect nimplants to vdd
offset = vector(0, self.vdd_position.y + 0.5*drc["minwidth_metal1"]) offset = vector(0, self.vdd_position.y + 0.5*drc["minwidth_metal1"])
self.add_contact_center(layers=("active", "contact", "metal1"), self.add_contact_center(layers=("active", "contact", "metal1"),
offset=offset, offset=offset,
rotate=90) rotate=90,
implant_type="n",
self.add_rect_center(layer="nimplant", well_type="n")
offset=offset,
width=drc["minwidth_tx"],
height=drc["minwidth_tx"])
def list_bitcell_pins(self, col, row): def list_bitcell_pins(self, col, row):
""" Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """ """ Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """
bitcell_pins = [] bitcell_pins = []
for k in range(self.num_readwrite): for k in range(self.num_rw_ports):
bitcell_pins.append("rwbl{0}[{1}]".format(k,col)) bitcell_pins.append("rwbl{0}[{1}]".format(k,col))
bitcell_pins.append("rwbl_bar{0}[{1}]".format(k,col)) bitcell_pins.append("rwbl_bar{0}[{1}]".format(k,col))
for k in range(self.num_write): for k in range(self.num_w_ports):
bitcell_pins.append("wbl{0}[{1}]".format(k,col)) bitcell_pins.append("wbl{0}[{1}]".format(k,col))
bitcell_pins.append("wbl_bar{0}[{1}]".format(k,col)) bitcell_pins.append("wbl_bar{0}[{1}]".format(k,col))
for k in range(self.num_read): for k in range(self.num_r_ports):
bitcell_pins.append("rbl{0}[{1}]".format(k,col)) bitcell_pins.append("rbl{0}[{1}]".format(k,col))
bitcell_pins.append("rbl_bar{0}[{1}]".format(k,col)) bitcell_pins.append("rbl_bar{0}[{1}]".format(k,col))
for k in range(self.num_readwrite): for k in range(self.num_rw_ports):
bitcell_pins.append("rwwl{0}[{1}]".format(k,row)) bitcell_pins.append("rwwl{0}[{1}]".format(k,row))
for k in range(self.num_write): for k in range(self.num_w_ports):
bitcell_pins.append("wwl{0}[{1}]".format(k,row)) bitcell_pins.append("wwl{0}[{1}]".format(k,row))
for k in range(self.num_read): for k in range(self.num_r_ports):
bitcell_pins.append("rwl{0}[{1}]".format(k,row)) bitcell_pins.append("rwl{0}[{1}]".format(k,row))
bitcell_pins.append("vdd") bitcell_pins.append("vdd")
bitcell_pins.append("gnd") bitcell_pins.append("gnd")
@ -1142,11 +1106,11 @@ class pbitcell(pgate.pgate):
def list_all_wl_names(self): def list_all_wl_names(self):
""" Creates a list of all wordline pin names """ """ Creates a list of all wordline pin names """
row_pins = [] row_pins = []
for k in range(self.num_readwrite): for k in range(self.num_rw_ports):
row_pins.append("rwwl{0}".format(k)) row_pins.append("rwwl{0}".format(k))
for k in range(self.num_write): for k in range(self.num_w_ports):
row_pins.append("wwl{0}".format(k)) row_pins.append("wwl{0}".format(k))
for k in range(self.num_read): for k in range(self.num_r_ports):
row_pins.append("rwl{0}".format(k)) row_pins.append("rwl{0}".format(k))
return row_pins return row_pins
@ -1154,9 +1118,9 @@ class pbitcell(pgate.pgate):
def list_read_wl_names(self): def list_read_wl_names(self):
""" Creates a list of wordline pin names associated with read ports """ """ Creates a list of wordline pin names associated with read ports """
row_pins = [] row_pins = []
for k in range(self.num_readwrite): for k in range(self.num_rw_ports):
row_pins.append("rwwl{0}".format(k)) row_pins.append("rwwl{0}".format(k))
for k in range(self.num_read): for k in range(self.num_r_ports):
row_pins.append("rwl{0}".format(k)) row_pins.append("rwl{0}".format(k))
return row_pins return row_pins
@ -1164,9 +1128,9 @@ class pbitcell(pgate.pgate):
def list_write_wl_names(self): def list_write_wl_names(self):
""" Creates a list of wordline pin names associated with write ports """ """ Creates a list of wordline pin names associated with write ports """
row_pins = [] row_pins = []
for k in range(self.num_readwrite): for k in range(self.num_rw_ports):
row_pins.append("rwwl{0}".format(k)) row_pins.append("rwwl{0}".format(k))
for k in range(self.num_write): for k in range(self.num_w_ports):
row_pins.append("wwl{0}".format(k)) row_pins.append("wwl{0}".format(k))
return row_pins return row_pins
@ -1175,13 +1139,13 @@ class pbitcell(pgate.pgate):
def list_all_bitline_names(self): def list_all_bitline_names(self):
""" Creates a list of all bitline pin names (both bl and br) """ """ Creates a list of all bitline pin names (both bl and br) """
column_pins = [] column_pins = []
for k in range(self.num_readwrite): for k in range(self.num_rw_ports):
column_pins.append("rwbl{0}".format(k)) column_pins.append("rwbl{0}".format(k))
column_pins.append("rwbl_bar{0}".format(k)) column_pins.append("rwbl_bar{0}".format(k))
for k in range(self.num_write): for k in range(self.num_w_ports):
column_pins.append("wbl{0}".format(k)) column_pins.append("wbl{0}".format(k))
column_pins.append("wbl_bar{0}".format(k)) column_pins.append("wbl_bar{0}".format(k))
for k in range(self.num_read): for k in range(self.num_r_ports):
column_pins.append("rbl{0}".format(k)) column_pins.append("rbl{0}".format(k))
column_pins.append("rbl_bar{0}".format(k)) column_pins.append("rbl_bar{0}".format(k))
@ -1190,11 +1154,11 @@ class pbitcell(pgate.pgate):
def list_all_bl_names(self): def list_all_bl_names(self):
""" Creates a list of all bl pins names """ """ Creates a list of all bl pins names """
column_pins = [] column_pins = []
for k in range(self.num_readwrite): for k in range(self.num_rw_ports):
column_pins.append("rwbl{0}".format(k)) column_pins.append("rwbl{0}".format(k))
for k in range(self.num_write): for k in range(self.num_w_ports):
column_pins.append("wbl{0}".format(k)) column_pins.append("wbl{0}".format(k))
for k in range(self.num_read): for k in range(self.num_r_ports):
column_pins.append("rbl{0}".format(k)) column_pins.append("rbl{0}".format(k))
return column_pins return column_pins
@ -1202,11 +1166,11 @@ class pbitcell(pgate.pgate):
def list_all_br_names(self): def list_all_br_names(self):
""" Creates a list of all br pins names """ """ Creates a list of all br pins names """
column_pins = [] column_pins = []
for k in range(self.num_readwrite): for k in range(self.num_rw_ports):
column_pins.append("rwbl_bar{0}".format(k)) column_pins.append("rwbl_bar{0}".format(k))
for k in range(self.num_write): for k in range(self.num_w_ports):
column_pins.append("wbl_bar{0}".format(k)) column_pins.append("wbl_bar{0}".format(k))
for k in range(self.num_read): for k in range(self.num_r_ports):
column_pins.append("rbl_bar{0}".format(k)) column_pins.append("rbl_bar{0}".format(k))
return column_pins return column_pins
@ -1214,9 +1178,9 @@ class pbitcell(pgate.pgate):
def list_read_bl_names(self): def list_read_bl_names(self):
""" Creates a list of bl pin names associated with read ports """ """ Creates a list of bl pin names associated with read ports """
column_pins = [] column_pins = []
for k in range(self.num_readwrite): for k in range(self.num_rw_ports):
column_pins.append("rwbl{0}".format(k)) column_pins.append("rwbl{0}".format(k))
for k in range(self.num_read): for k in range(self.num_r_ports):
column_pins.append("rbl{0}".format(k)) column_pins.append("rbl{0}".format(k))
return column_pins return column_pins
@ -1224,9 +1188,9 @@ class pbitcell(pgate.pgate):
def list_read_br_names(self): def list_read_br_names(self):
""" Creates a list of br pin names associated with read ports """ """ Creates a list of br pin names associated with read ports """
column_pins = [] column_pins = []
for k in range(self.num_readwrite): for k in range(self.num_rw_ports):
column_pins.append("rwbl_bar{0}".format(k)) column_pins.append("rwbl_bar{0}".format(k))
for k in range(self.num_read): for k in range(self.num_r_ports):
column_pins.append("rbl_bar{0}".format(k)) column_pins.append("rbl_bar{0}".format(k))
return column_pins return column_pins
@ -1234,9 +1198,9 @@ class pbitcell(pgate.pgate):
def list_write_bl_names(self): def list_write_bl_names(self):
""" Creates a list of bl pin names associated with write ports """ """ Creates a list of bl pin names associated with write ports """
column_pins = [] column_pins = []
for k in range(self.num_readwrite): for k in range(self.num_rw_ports):
column_pins.append("rwbl{0}".format(k)) column_pins.append("rwbl{0}".format(k))
for k in range(self.num_write): for k in range(self.num_w_ports):
column_pins.append("wbl{0}".format(k)) column_pins.append("wbl{0}".format(k))
return column_pins return column_pins
@ -1244,9 +1208,9 @@ class pbitcell(pgate.pgate):
def list_write_br_names(self): def list_write_br_names(self):
""" Creates a list of br pin names asscociated with write ports""" """ Creates a list of br pin names asscociated with write ports"""
column_pins = [] column_pins = []
for k in range(self.num_readwrite): for k in range(self.num_rw_ports):
column_pins.append("rwbl_bar{0}".format(k)) column_pins.append("rwbl_bar{0}".format(k))
for k in range(self.num_write): for k in range(self.num_w_ports):
column_pins.append("wbl_bar{0}".format(k)) column_pins.append("wbl_bar{0}".format(k))
return column_pins return column_pins

View File

@ -11,10 +11,19 @@ class pgate(design.design):
This is a module that implements some shared functions for parameterized gates. This is a module that implements some shared functions for parameterized gates.
""" """
def __init__(self, name): def __init__(self, name, height=None):
""" Creates a generic cell """ """ Creates a generic cell """
design.design.__init__(self, name) design.design.__init__(self, name)
if height:
self.height = height
elif not height:
from importlib import reload
c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.bitcell)
b = bitcell()
self.height = b.height
def connect_pin_to_rail(self,inst,pin,supply): def connect_pin_to_rail(self,inst,pin,supply):
""" Conencts a ptx pin to a supply rail. """ """ Conencts a ptx pin to a supply rail. """

View File

@ -17,26 +17,22 @@ class pinv(pgate.pgate):
from center of rail to rail.. The route_output will route the from center of rail to rail.. The route_output will route the
output to the right side of the cell for easier access. output to the right side of the cell for easier access.
""" """
from importlib import reload
c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.bitcell)
unique_id = 1 unique_id = 1
def __init__(self, size=1, beta=parameter["beta"], height=bitcell.height, route_output=True): def __init__(self, size=1, beta=parameter["beta"], height=None, route_output=True):
# We need to keep unique names because outputting to GDSII # We need to keep unique names because outputting to GDSII
# will use the last record with a given name. I.e., you will # will use the last record with a given name. I.e., you will
# over-write a design in GDS if one has and the other doesn't # over-write a design in GDS if one has and the other doesn't
# have poly connected, for example. # have poly connected, for example.
name = "pinv_{}".format(pinv.unique_id) name = "pinv_{}".format(pinv.unique_id)
pinv.unique_id += 1 pinv.unique_id += 1
pgate.pgate.__init__(self, name) pgate.pgate.__init__(self, name, height)
debug.info(2, "create pinv structure {0} with size of {1}".format(name, size)) debug.info(2, "create pinv structure {0} with size of {1}".format(name, size))
self.nmos_size = size self.nmos_size = size
self.pmos_size = beta*size self.pmos_size = beta*size
self.beta = beta self.beta = beta
self.height = height # Maybe minimize height if not defined in future?
self.route_output = False self.route_output = False
@ -175,6 +171,8 @@ class pinv(pgate.pgate):
offset=vector(0.5*self.width,self.height), offset=vector(0.5*self.width,self.height),
width=self.width) width=self.width)
def create_ptx(self): def create_ptx(self):
""" """
Create the PMOS and NMOS netlist. Create the PMOS and NMOS netlist.

View File

@ -11,13 +11,9 @@ class pinvbuf(design.design):
This is a simple inverter/buffer used for driving loads. It is This is a simple inverter/buffer used for driving loads. It is
used in the column decoder for 1:2 decoding and as the clock buffer. used in the column decoder for 1:2 decoding and as the clock buffer.
""" """
from importlib import reload
c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.bitcell)
unique_id = 1 unique_id = 1
def __init__(self, driver_size=4, height=bitcell.height, name=""): def __init__(self, driver_size=4, height=None, name=""):
self.stage_effort = 4 self.stage_effort = 4
self.row_height = height self.row_height = height

View File

@ -12,24 +12,19 @@ class pnand2(pgate.pgate):
This model use ptx to generate a 2-input nand within a cetrain height. This model use ptx to generate a 2-input nand within a cetrain height.
""" """
from importlib import reload
c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.bitcell)
unique_id = 1 unique_id = 1
def __init__(self, size=1, height=bitcell.height): def __init__(self, size=1, height=None):
""" Creates a cell for a simple 2 input nand """ """ Creates a cell for a simple 2 input nand """
name = "pnand2_{0}".format(pnand2.unique_id) name = "pnand2_{0}".format(pnand2.unique_id)
pnand2.unique_id += 1 pnand2.unique_id += 1
pgate.pgate.__init__(self, name) pgate.pgate.__init__(self, name, height)
debug.info(2, "create pnand2 structure {0} with size of {1}".format(name, size)) debug.info(2, "create pnand2 structure {0} with size of {1}".format(name, size))
self.nmos_size = 2*size self.nmos_size = 2*size
self.pmos_size = parameter["beta"]*size self.pmos_size = parameter["beta"]*size
self.nmos_width = self.nmos_size*drc["minwidth_tx"] self.nmos_width = self.nmos_size*drc["minwidth_tx"]
self.pmos_width = self.pmos_size*drc["minwidth_tx"] self.pmos_width = self.pmos_size*drc["minwidth_tx"]
self.height = height
# FIXME: Allow these to be sized # FIXME: Allow these to be sized
debug.check(size==1,"Size 1 pnand2 is only supported now.") debug.check(size==1,"Size 1 pnand2 is only supported now.")

View File

@ -12,18 +12,13 @@ class pnand3(pgate.pgate):
This model use ptx to generate a 2-input nand within a cetrain height. This model use ptx to generate a 2-input nand within a cetrain height.
""" """
from importlib import reload
c = reload(__import__(OPTS.bitcell))
mod_bitcell = getattr(c, OPTS.bitcell)
bitcell = mod_bitcell()
unique_id = 1 unique_id = 1
def __init__(self, size=1, height=bitcell.height): def __init__(self, size=1, height=None):
""" Creates a cell for a simple 3 input nand """ """ Creates a cell for a simple 3 input nand """
name = "pnand3_{0}".format(pnand3.unique_id) name = "pnand3_{0}".format(pnand3.unique_id)
pnand3.unique_id += 1 pnand3.unique_id += 1
pgate.pgate.__init__(self, name) pgate.pgate.__init__(self, name, height)
debug.info(2, "create pnand3 structure {0} with size of {1}".format(name, size)) debug.info(2, "create pnand3 structure {0} with size of {1}".format(name, size))
# We have trouble pitch matching a 3x sizes to the bitcell... # We have trouble pitch matching a 3x sizes to the bitcell...
@ -32,7 +27,6 @@ class pnand3(pgate.pgate):
self.pmos_size = parameter["beta"]*size self.pmos_size = parameter["beta"]*size
self.nmos_width = self.nmos_size*drc["minwidth_tx"] self.nmos_width = self.nmos_size*drc["minwidth_tx"]
self.pmos_width = self.pmos_size*drc["minwidth_tx"] self.pmos_width = self.pmos_size*drc["minwidth_tx"]
self.height = height
# FIXME: Allow these to be sized # FIXME: Allow these to be sized
debug.check(size==1,"Size 1 pnand3 is only supported now.") debug.check(size==1,"Size 1 pnand3 is only supported now.")

View File

@ -12,17 +12,13 @@ class pnor2(pgate.pgate):
This model use ptx to generate a 2-input nor within a cetrain height. This model use ptx to generate a 2-input nor within a cetrain height.
""" """
from importlib import reload
c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.bitcell)
unique_id = 1 unique_id = 1
def __init__(self, size=1, height=bitcell.height): def __init__(self, size=1, height=None):
""" Creates a cell for a simple 2 input nor """ """ Creates a cell for a simple 2 input nor """
name = "pnor2_{0}".format(pnor2.unique_id) name = "pnor2_{0}".format(pnor2.unique_id)
pnor2.unique_id += 1 pnor2.unique_id += 1
pgate.pgate.__init__(self, name) pgate.pgate.__init__(self, name, height)
debug.info(2, "create pnor2 structure {0} with size of {1}".format(name, size)) debug.info(2, "create pnor2 structure {0} with size of {1}".format(name, size))
self.nmos_size = size self.nmos_size = size
@ -30,7 +26,6 @@ class pnor2(pgate.pgate):
self.pmos_size = 1.5*parameter["beta"]*size self.pmos_size = 1.5*parameter["beta"]*size
self.nmos_width = self.nmos_size*drc["minwidth_tx"] self.nmos_width = self.nmos_size*drc["minwidth_tx"]
self.pmos_width = self.pmos_size*drc["minwidth_tx"] self.pmos_width = self.pmos_size*drc["minwidth_tx"]
self.height = height
# FIXME: Allow these to be sized # FIXME: Allow these to be sized
debug.check(size==1,"Size 1 pnor2 is only supported now.") debug.check(size==1,"Size 1 pnor2 is only supported now.")

View File

@ -39,6 +39,8 @@ class single_level_column_mux(design.design):
self.add_wells() self.add_wells()
def add_modules(self): def add_modules(self):
# This is just used for measurements,
# so don't add the module
from importlib import reload from importlib import reload
c = reload(__import__(OPTS.bitcell)) c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell) self.mod_bitcell = getattr(c, OPTS.bitcell)

View File

@ -36,9 +36,6 @@ class grid:
def add_blockage_shape(self,ll,ur,z): def add_blockage_shape(self,ll,ur,z):
debug.info(3,"Adding blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z)) debug.info(3,"Adding blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z))
if ll[0]<42 and ll[0]>38 and ll[1]<3 and ll[1]>0:
debug.info(0,"Adding blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z))
block_list = [] block_list = []
for x in range(int(ll[0]),int(ur[0])+1): for x in range(int(ll[0]),int(ur[0])+1):
for y in range(int(ll[1]),int(ur[1])+1): for y in range(int(ll[1]),int(ur[1])+1):

View File

@ -49,6 +49,12 @@ class router:
""" If we want to route something besides the top-level cell.""" """ If we want to route something besides the top-level cell."""
self.top_name = top_name self.top_name = top_name
def get_zindex(self,layer_num):
if layer_num==self.horiz_layer_number:
return 0
else:
return 1
def set_layers(self, layers): def set_layers(self, layers):
"""Allows us to change the layers that we are routing on. First layer """Allows us to change the layers that we are routing on. First layer
is always horizontal, middle is via, and last is always is always horizontal, middle is via, and last is always
@ -84,19 +90,19 @@ class router:
def find_pin(self,pin): def find_pin(self,pin_name):
""" """
Finds the pin shapes and converts to tracks. Finds the pin shapes and converts to tracks.
Pin can either be a label or a location,layer pair: [[x,y],layer]. Pin can either be a label or a location,layer pair: [[x,y],layer].
""" """
label_list=self.layout.getPinShapeByLabel(str(pin)) shape_list=self.layout.getPinShapeByLabel(str(pin_name))
pin_list = [] pin_list = []
for label in label_list: for shape in shape_list:
(name,layer,boundary)=label (name,layer,boundary)=shape
rect = [vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])] rect = [vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])]
# this is a list because other cells/designs may have must-connect pins pin = pin_layout(pin_name, rect, layer)
pin_list.append(pin_layout(pin, rect, layer)) pin_list.append(pin)
debug.check(len(pin_list)>0,"Did not find any pin shapes for {0}.".format(str(pin))) debug.check(len(pin_list)>0,"Did not find any pin shapes for {0}.".format(str(pin)))
@ -202,17 +208,30 @@ class router:
def add_blockages(self): def add_blockages(self):
""" Add the blockages except the pin shapes """ """ Add the blockages except the pin shapes. Also remove the pin shapes from the blockages list. """
# Join all the pin shapes into one big list
all_pins = [item for sublist in list(self.pins.values()) for item in sublist]
# Do an n^2 check to see if any shapes are the same, otherwise add them
# FIXME: Make faster, but number of pins won't be *that* large
real_blockages = []
for blockage in self.blockages: for blockage in self.blockages:
# Skip pin shapes
all_pins = [x[0] for x in list(self.pins.values())]
for pin in all_pins: for pin in all_pins:
if blockage.overlaps(pin): # If the blockage overlaps the pin and is on the same layer,
# it must be connected, so skip it.
if blockage==pin:
debug.info(1,"Removing blockage for pin {}".format(str(pin)))
break break
else: else:
[ll,ur]=self.convert_blockage_to_tracks(blockage.rect) debug.info(2,"Adding blockage {}".format(str(blockage)))
zlayer = 0 if blockage.layer_num==self.horiz_layer_number else 1 # Inflate the blockage by spacing rule
[ll,ur]=self.convert_blockage_to_tracks(blockage.inflate())
zlayer = self.get_zindex(blockage.layer_num)
self.rg.add_blockage_shape(ll,ur,zlayer) self.rg.add_blockage_shape(ll,ur,zlayer)
real_blockages.append(blockage)
# Remember the filtered blockages
self.blockages = real_blockages
def get_blockages(self, layer_num): def get_blockages(self, layer_num):
@ -228,37 +247,6 @@ class router:
new_pin = pin_layout("blockage{}".format(len(self.blockages)),rect,layer_num) new_pin = pin_layout("blockage{}".format(len(self.blockages)),rect,layer_num)
self.blockages.append(new_pin) self.blockages.append(new_pin)
# for boundary in self.layout.structures[sref].boundaries:
# coord_trans = self.translate_coordinates(boundary.coordinates, mirr, angle, xyShift)
# shape_coords = self.min_max_coord(coord_trans)
# shape = self.convert_shape_to_units(shape_coords)
# # only consider the two layers that we are routing on
# if boundary.drawingLayer in [self.vert_layer_number,self.horiz_layer_number]:
# # store the blockages as pin layouts so they are easy to compare etc.
# new_pin = pin_layout("blockage",shape,boundary.drawingLayer)
# # avoid repeated blockage pins
# if new_pin not in self.blockages:
# self.blockages.append(new_pin)
# # recurse given the mirror, angle, etc.
# for cur_sref in self.layout.structures[sref].srefs:
# sMirr = 1
# if cur_sref.transFlags[0] == True:
# sMirr = -1
# sAngle = math.radians(float(0))
# if cur_sref.rotateAngle:
# sAngle = math.radians(float(cur_sref.rotateAngle))
# sAngle += angle
# x = cur_sref.coordinates[0]
# y = cur_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.get_blockages(cur_sref.sName, sMirr, sAngle, sxyShift)
def convert_point_to_units(self,p): def convert_point_to_units(self,p):
""" """
@ -282,11 +270,15 @@ class router:
old_ur = ur old_ur = ur
ll=ll.scale(self.track_factor) ll=ll.scale(self.track_factor)
ur=ur.scale(self.track_factor) ur=ur.scale(self.track_factor)
ll = ll.floor() # We can round since we are using inflated shapes
ur = ur.ceil() # and the track points are at the center
if ll[0]<45 and ll[0]>35 and ll[1]<10 and ll[1]>0: ll = ll.round()
debug.info(0,"Converting [ {0} , {1} ]".format(old_ll,old_ur)) ur = ur.round()
debug.info(0,"Converted [ {0} , {1} ]".format(ll,ur)) # if ll[0]<45 and ll[0]>35 and ll[1]<5 and ll[1]>-5:
# debug.info(0,"Converting [ {0} , {1} ]".format(old_ll,old_ur))
# debug.info(0,"Converted [ {0} , {1} ]".format(ll,ur))
# pin=self.convert_track_to_shape(ll)
# debug.info(0,"Pin {}".format(pin))
return [ll,ur] return [ll,ur]
def convert_pin_to_tracks(self, pin): def convert_pin_to_tracks(self, pin):
@ -296,9 +288,6 @@ class router:
If a pin has insufficent overlap, it returns the blockage list to avoid it. If a pin has insufficent overlap, it returns the blockage list to avoid it.
""" """
(ll,ur) = pin.rect (ll,ur) = pin.rect
#ll = snap_to_grid(ll)
#ur = snap_to_grid(ur)
#debug.info(1,"Converting [ {0} , {1} ]".format(ll,ur)) #debug.info(1,"Converting [ {0} , {1} ]".format(ll,ur))
# scale the size bigger to include neaby tracks # scale the size bigger to include neaby tracks
@ -306,37 +295,40 @@ class router:
ur=ur.scale(self.track_factor).ceil() ur=ur.scale(self.track_factor).ceil()
# width depends on which layer it is # width depends on which layer it is
zindex = 0 if pin.layer_num==self.horiz_layer_number else 1 zindex=self.get_zindex(pin.layer_num)
if zindex==0: if zindex:
width = self.horiz_layer_width
else:
width = self.vert_layer_width width = self.vert_layer_width
else:
width = self.horiz_layer_width
track_list = [] track_list = []
block_list = [] block_list = []
# include +- 1 so when a shape is less than one grid
for x in range(ll[0]-1,ur[0]+1): track_area = self.track_width*self.track_width
for y in range(ll[1]-1,ur[1]+1): for x in range(ll[0],ur[0]):
for y in range(ll[1],ur[1]):
#debug.info(1,"Converting [ {0} , {1} ]".format(x,y)) #debug.info(1,"Converting [ {0} , {1} ]".format(x,y))
# get the rectangular pin at a track location
# if dimension of overlap is greater than min width in any dimension,
# it will be an on-grid pin
rect = self.convert_track_to_pin(vector3d(x,y,zindex))
max_overlap=max(self.compute_overlap(pin.rect,rect))
# however, if there is not enough overlap, then if there is any overlap at all, # however, if there is not enough overlap, then if there is any overlap at all,
# we need to block it to prevent routes coming in on that grid # we need to block it to prevent routes coming in on that grid
full_rect = self.convert_full_track_to_shape(vector3d(x,y,zindex)) full_rect = self.convert_track_to_shape(vector3d(x,y,zindex))
full_overlap=max(self.compute_overlap(pin.rect,full_rect)) overlap_rect=self.compute_overlap(pin.rect,full_rect)
overlap_area = overlap_rect[0]*overlap_rect[1]
#debug.info(1,"Check overlap: {0} {1} max={2}".format(shape,rect,max_overlap)) #debug.info(1,"Check overlap: {0} {1} max={2}".format(shape,rect,max_overlap))
if max_overlap >= width:
# Assume if more than half the area, it is occupied
overlap_ratio = overlap_area/track_area
if overlap_ratio > 0.5:
track_list.append(vector3d(x,y,zindex)) track_list.append(vector3d(x,y,zindex))
elif full_overlap>0: # otherwise, the pin may not be accessible, so block it
elif overlap_ratio > 0:
block_list.append(vector3d(x,y,zindex)) block_list.append(vector3d(x,y,zindex))
else: else:
debug.info(4,"No overlap: {0} {1} max={2}".format(pin.rect,rect,max_overlap)) debug.info(4,"No overlap: {0} {1} max={2}".format(pin.rect,rect,max_overlap))
print("H:",x,y)
if x>38 and x<42 and y>42 and y<45:
print(pin)
print(full_rect, overlap_rect, overlap_ratio)
#debug.warning("Off-grid pin for {0}.".format(str(pin))) #debug.warning("Off-grid pin for {0}.".format(str(pin)))
#debug.info(1,"Converted [ {0} , {1} ]".format(ll,ur)) #debug.info(1,"Converted [ {0} , {1} ]".format(ll,ur))
return (track_list,block_list) return (track_list,block_list)
@ -381,7 +373,7 @@ class router:
return [ll,ur] return [ll,ur]
def convert_full_track_to_shape(self,track): def convert_track_to_shape(self,track):
""" """
Convert a grid point into a rectangle shape that occupies the entire centered Convert a grid point into a rectangle shape that occupies the entire centered
track. track.
@ -447,9 +439,8 @@ class router:
grid_keys=self.rg.map.keys() grid_keys=self.rg.map.keys()
partial_track=vector(0,self.track_width/6.0) partial_track=vector(0,self.track_width/6.0)
for g in grid_keys: for g in grid_keys:
continue # for now... shape = self.convert_track_to_shape(g)
shape = self.convert_full_track_to_shape(g) self.cell.add_rect(layer="text",
self.cell.add_rect(layer="boundary",
offset=shape[0], offset=shape[0],
width=shape[1].x-shape[0].x, width=shape[1].x-shape[0].x,
height=shape[1].y-shape[0].y) height=shape[1].y-shape[0].y)
@ -481,10 +472,12 @@ class router:
zoom=0.05) zoom=0.05)
for blockage in self.blockages: for blockage in self.blockages:
self.cell.add_rect(layer="boundary", # Display the inflated blockage
offset=blockage.ll(), (ll,ur) = blockage.inflate()
width=blockage.width(), self.cell.add_rect(layer="blockage",
height=blockage.height()) offset=ll,
width=ur.x-ll.x,
height=ur.y-ll.y)
# FIXME: This should be replaced with vector.snap_to_grid at some point # FIXME: This should be replaced with vector.snap_to_grid at some point

View File

@ -32,12 +32,14 @@ class no_blockages_test(openram_test):
globals.setup_paths() globals.setup_paths()
from control_logic import control_logic from control_logic import control_logic
cell = control_logic(16) cell = control_logic(16)
#from pinv import pinv
#cell = pinv()
#gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),"control_logic") #gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),"control_logic")
#cell = gds_cell(name, gds_file) #cell = gds_cell(name, gds_file)
self.add_inst(name=name, self.add_inst(name=name,
mod=cell, mod=cell,
offset=[0,0]) offset=[0,0])
self.connect_inst(["csb","web","clk","s_en","w_en","clk_buf_bar","clk_buf","vdd","gnd"]) self.connect_inst(cell.pin_map.keys())
r=router(module=cell) r=router(module=cell)
layer_stack =("metal3","via2","metal2") layer_stack =("metal3","via2","metal2")

View File

@ -3,7 +3,7 @@ import datetime
import getpass import getpass
import debug import debug
from globals import OPTS, print_time from globals import OPTS, print_time
from sram_config import sram_config
class sram(): class sram():
""" """
@ -12,31 +12,34 @@ class sram():
results. results.
We can later add visualizer and other high-level functions as needed. We can later add visualizer and other high-level functions as needed.
""" """
def __init__(self, word_size, num_words, num_banks, name): def __init__(self, sram_config, name):
sram_config.compute_sizes()
sram_config.set_local_config(self)
# reset the static duplicate name checker for unit tests # reset the static duplicate name checker for unit tests
# in case we create more than one SRAM # in case we create more than one SRAM
from design import design from design import design
design.name_map=[] design.name_map=[]
debug.info(2, "create sram of size {0} with {1} num of words".format(word_size, debug.info(2, "create sram of size {0} with {1} num of words {2} banks".format(self.word_size,
num_words)) self.num_words,
self.num_banks))
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
self.name = name self.name = name
if num_banks == 1:
from sram_1bank import sram_1bank if self.num_banks == 1:
self.s=sram_1bank(word_size, num_words, name) from sram_1bank import sram_1bank as sram
elif num_banks == 2: elif self.num_banks == 2:
from sram_2bank import sram_2bank from sram_2bank import sram_2bank as sram
self.s=sram_2bank(word_size, num_words, name) elif self.num_banks == 4:
elif num_banks == 4: from sram_4bank import sram_4bank as sram
from sram_4bank import sram_4bank
self.s=sram_4bank(word_size, num_words, name)
else: else:
debug.error("Invalid number of banks.",-1) debug.error("Invalid number of banks.",-1)
self.s = sram(name, sram_config)
self.s.create_netlist() self.s.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.s.create_layout() self.s.create_layout()

View File

@ -18,11 +18,11 @@ class sram_1bank(sram_base):
""" """
Procedures specific to a one bank SRAM. Procedures specific to a one bank SRAM.
""" """
def __init__(self, word_size, num_words, name): def __init__(self, name, sram_config):
sram_base.__init__(self, word_size, num_words, 1, name) sram_base.__init__(self, name, sram_config)
def create_netlist(self): def create_netlist(self):
self.compute_sizes()
sram_base.create_netlist(self) sram_base.create_netlist(self)
self.create_modules() self.create_modules()
@ -99,18 +99,18 @@ class sram_1bank(sram_base):
for i in range(self.word_size): for i in range(self.word_size):
dout_name = "dout0[{}]".format(i) dout_name = "dout0[{}]".format(i)
self.copy_layout_pin(self.bank_inst, dout_name, "DOUT[{}]".format(i)) self.copy_layout_pin(self.bank_inst, dout_name, "DOUT0[{}]".format(i))
# Lower address bits # Lower address bits
for i in range(self.col_addr_size): for i in range(self.col_addr_size):
self.copy_layout_pin(self.col_addr_dff_inst, "din[{}]".format(i),"ADDR[{}]".format(i)) self.copy_layout_pin(self.col_addr_dff_inst, "din[{}]".format(i),"ADDR0[{}]".format(i))
# Upper address bits # Upper address bits
for i in range(self.row_addr_size): for i in range(self.row_addr_size):
self.copy_layout_pin(self.row_addr_dff_inst, "din[{}]".format(i),"ADDR[{}]".format(i+self.col_addr_size)) self.copy_layout_pin(self.row_addr_dff_inst, "din[{}]".format(i),"ADDR0[{}]".format(i+self.col_addr_size))
for i in range(self.word_size): for i in range(self.word_size):
din_name = "din[{}]".format(i) din_name = "din[{}]".format(i)
self.copy_layout_pin(self.data_dff_inst, din_name, din_name.upper()) self.copy_layout_pin(self.data_dff_inst, din_name, "DIN0[{}]".format(i))
def route(self): def route(self):
""" Route a single bank SRAM """ """ Route a single bank SRAM """

View File

@ -16,8 +16,8 @@ class sram_2bank(sram_base):
""" """
Procedures specific to a two bank SRAM. Procedures specific to a two bank SRAM.
""" """
def __init__(self, word_size, num_words, name): def __init__(self, name, sram_config):
sram_base.__init__(self, word_size, num_words, 2, name) sram_base.__init__(self, name, sram_config)
def compute_bank_offsets(self): def compute_bank_offsets(self):
""" Compute the overall offsets for a two bank SRAM """ """ Compute the overall offsets for a two bank SRAM """

View File

@ -16,8 +16,8 @@ class sram_4bank(sram_base):
""" """
Procedures specific to a four bank SRAM. Procedures specific to a four bank SRAM.
""" """
def __init__(self, word_size, num_words, name): def __init__(self, name, sram_config):
sram_base.__init__(self, word_size, num_words, 4, name) sram_base.__init__(self, name, sram_config)
def compute_bank_offsets(self): def compute_bank_offsets(self):
""" Compute the overall offsets for a four bank SRAM """ """ Compute the overall offsets for a four bank SRAM """

View File

@ -2,7 +2,7 @@ import sys
import datetime import datetime
import getpass import getpass
import debug import debug
from math import log,sqrt,ceil from importlib import reload
from vector import vector from vector import vector
from globals import OPTS, print_time from globals import OPTS, print_time
@ -13,95 +13,29 @@ class sram_base(design):
Dynamically generated SRAM by connecting banks to control logic. The Dynamically generated SRAM by connecting banks to control logic. The
number of banks should be 1 , 2 or 4 number of banks should be 1 , 2 or 4
""" """
def __init__(self, word_size, num_words, num_banks, name): def __init__(self, name, sram_config):
design.__init__(self, name) design.__init__(self, name)
from importlib import reload self.sram_config = sram_config
c = reload(__import__(OPTS.control_logic)) sram_config.set_local_config(self)
self.mod_control_logic = getattr(c, OPTS.control_logic)
c = reload(__import__(OPTS.bitcell)) self.total_write = OPTS.num_rw_ports + OPTS.num_w_ports
self.mod_bitcell = getattr(c, OPTS.bitcell) self.total_read = OPTS.num_rw_ports + OPTS.num_r_ports
self.bitcell = self.mod_bitcell() self.total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
c = reload(__import__(OPTS.ms_flop))
self.mod_ms_flop = getattr(c, OPTS.ms_flop)
self.ms_flop = self.mod_ms_flop()
self.word_size = word_size
self.num_words = num_words
self.num_banks = num_banks
self.bank_insts = [] self.bank_insts = []
def compute_sizes(self):
""" Computes the organization of the memory using bitcell size by trying to make it square."""
debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.")
self.num_words_per_bank = self.num_words/self.num_banks
self.num_bits_per_bank = self.word_size*self.num_words_per_bank
# Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry)
self.bank_area = self.bitcell.width*self.bitcell.height*self.num_bits_per_bank
self.bank_side_length = sqrt(self.bank_area)
# Estimate the words per row given the height of the bitcell and the square side length
self.tentative_num_cols = int(self.bank_side_length/self.bitcell.width)
self.words_per_row = self.estimate_words_per_row(self.tentative_num_cols, self.word_size)
# Estimate the number of rows given the tentative words per row
self.tentative_num_rows = self.num_bits_per_bank / (self.words_per_row*self.word_size)
self.words_per_row = self.amend_words_per_row(self.tentative_num_rows, self.words_per_row)
# Fix the number of columns and rows
self.num_cols = int(self.words_per_row*self.word_size)
self.num_rows = int(self.num_words_per_bank/self.words_per_row)
# Compute the address and bank sizes
self.row_addr_size = int(log(self.num_rows, 2))
self.col_addr_size = int(log(self.words_per_row, 2))
self.bank_addr_size = self.col_addr_size + self.row_addr_size
self.addr_size = self.bank_addr_size + int(log(self.num_banks, 2))
debug.info(1,"Words per row: {}".format(self.words_per_row))
def estimate_words_per_row(self,tentative_num_cols, word_size):
"""
This provides a heuristic rounded estimate for the number of words
per row.
"""
if tentative_num_cols < 1.5*word_size:
return 1
elif tentative_num_cols > 3*word_size:
return 4
else:
return 2
def amend_words_per_row(self,tentative_num_rows, words_per_row):
"""
This picks the number of words per row more accurately by limiting
it to a minimum and maximum.
"""
# Recompute the words per row given a hard max
if(tentative_num_rows > 512):
debug.check(tentative_num_rows*words_per_row <= 2048, "Number of words exceeds 2048")
return int(words_per_row*tentative_num_rows/512)
# Recompute the words per row given a hard min
if(tentative_num_rows < 16):
debug.check(tentative_num_rows*words_per_row >= 16, "Minimum number of rows is 16, but given {0}".format(tentative_num_rows))
return int(words_per_row*tentative_num_rows/16)
return words_per_row
def add_pins(self): def add_pins(self):
""" Add pins for entire SRAM. """ """ Add pins for entire SRAM. """
for i in range(self.word_size): for port in range(self.total_write):
self.add_pin("DIN[{0}]".format(i),"INPUT") for bit in range(self.word_size):
for i in range(self.addr_size): self.add_pin("DIN{0}[{1}]".format(port,bit),"INPUT")
self.add_pin("ADDR[{0}]".format(i),"INPUT")
for port in range(self.total_ports):
for bit in range(self.addr_size):
self.add_pin("ADDR{0}[{1}]".format(port,bit),"INPUT")
# These are used to create the physical pins too # These are used to create the physical pins too
self.control_logic_inputs=self.control_logic.get_inputs() self.control_logic_inputs=self.control_logic.get_inputs()
@ -109,8 +43,9 @@ class sram_base(design):
self.add_pin_list(self.control_logic_inputs,"INPUT") self.add_pin_list(self.control_logic_inputs,"INPUT")
for i in range(self.word_size): for port in range(self.total_read):
self.add_pin("DOUT[{0}]".format(i),"OUTPUT") for bit in range(self.word_size):
self.add_pin("DOUT{0}[{1}]".format(port,bit),"OUTPUT")
self.add_pin("vdd","POWER") self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND") self.add_pin("gnd","GROUND")
@ -271,6 +206,17 @@ class sram_base(design):
def add_modules(self): def add_modules(self):
""" Create all the modules that will be used """ """ Create all the modules that will be used """
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
c = reload(__import__(OPTS.control_logic))
self.mod_control_logic = getattr(c, OPTS.control_logic)
c = reload(__import__(OPTS.ms_flop))
self.mod_ms_flop = getattr(c, OPTS.ms_flop)
self.ms_flop = self.mod_ms_flop()
from control_logic import control_logic from control_logic import control_logic
# Create the control logic module # Create the control logic module
@ -279,24 +225,21 @@ class sram_base(design):
# Create the address and control flops (but not the clk) # Create the address and control flops (but not the clk)
from dff_array import dff_array from dff_array import dff_array
self.row_addr_dff = dff_array(name="row_addr_dff", rows=self.row_addr_size, columns=1) self.row_addr_dff = dff_array(name="row_addr_dff", rows=self.row_addr_size*self.total_ports, columns=1)
self.add_mod(self.row_addr_dff) self.add_mod(self.row_addr_dff)
if self.col_addr_size > 0: if self.col_addr_size > 0:
self.col_addr_dff = dff_array(name="col_addr_dff", rows=1, columns=self.col_addr_size) self.col_addr_dff = dff_array(name="col_addr_dff", rows=1, columns=self.col_addr_size*self.total_ports)
self.add_mod(self.col_addr_dff) self.add_mod(self.col_addr_dff)
else: else:
self.col_addr_dff = None self.col_addr_dff = None
self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size) self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size*self.total_ports)
self.add_mod(self.data_dff) self.add_mod(self.data_dff)
# Create the bank module (up to four are instantiated) # Create the bank module (up to four are instantiated)
from bank import bank from bank import bank
self.bank = bank(word_size=self.word_size, self.bank = bank(self.sram_config,
num_words=self.num_words_per_bank,
words_per_row=self.words_per_row,
num_banks=self.num_banks,
name="bank") name="bank")
self.add_mod(self.bank) self.add_mod(self.bank)
@ -317,15 +260,23 @@ class sram_base(design):
mod=self.bank)) mod=self.bank))
temp = [] temp = []
for i in range(self.word_size): for port in range(self.total_read):
temp.append("DOUT[{0}]".format(i)) for bit in range(self.word_size):
for i in range(self.word_size): temp.append("DOUT{0}[{1}]".format(port,bit))
temp.append("BANK_DIN[{0}]".format(i)) for port in range(self.total_write):
for i in range(self.bank_addr_size): for bit in range(self.word_size):
temp.append("A[{0}]".format(i)) temp.append("BANK_DIN{0}[{1}]".format(port,bit))
for port in range(self.total_ports):
for bit in range(self.bank_addr_size):
temp.append("A{0}[{1}]".format(port,bit))
if(self.num_banks > 1): if(self.num_banks > 1):
temp.append("bank_sel[{0}]".format(bank_num)) for port in range(self.total_ports):
temp.extend(["s_en0", "w_en0", "clk_buf_bar","clk_buf" , "vdd", "gnd"]) temp.append("bank_sel{0}[{1}]".format(port,bank_num))
for port in range(self.total_read):
temp.append("s_en{0}".format(port))
for port in range(self.total_write):
temp.append("w_en{0}".format(port))
temp.extend(["clk_buf_bar","clk_buf" , "vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
return self.bank_insts[-1] return self.bank_insts[-1]
@ -370,9 +321,10 @@ class sram_base(design):
# inputs, outputs/output/bar # inputs, outputs/output/bar
inputs = [] inputs = []
outputs = [] outputs = []
for i in range(self.row_addr_size): for k in range(self.total_ports):
inputs.append("ADDR[{}]".format(i+self.col_addr_size)) for i in range(self.row_addr_size):
outputs.append("A[{}]".format(i+self.col_addr_size)) inputs.append("ADDR{}[{}]".format(k,i+self.col_addr_size))
outputs.append("A{}[{}]".format(k,i+self.col_addr_size))
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"]) self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
return inst return inst
@ -385,9 +337,10 @@ class sram_base(design):
# inputs, outputs/output/bar # inputs, outputs/output/bar
inputs = [] inputs = []
outputs = [] outputs = []
for i in range(self.col_addr_size): for k in range(self.total_ports):
inputs.append("ADDR[{}]".format(i)) for i in range(self.col_addr_size):
outputs.append("A[{}]".format(i)) inputs.append("ADDR{}[{}]".format(k,i))
outputs.append("A{}[{}]".format(k,i))
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"]) self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
return inst return inst
@ -400,9 +353,10 @@ class sram_base(design):
# inputs, outputs/output/bar # inputs, outputs/output/bar
inputs = [] inputs = []
outputs = [] outputs = []
for i in range(self.word_size): for k in range(self.total_write):
inputs.append("DIN[{}]".format(i)) for i in range(self.word_size):
outputs.append("BANK_DIN[{}]".format(i)) inputs.append("DIN{}[{}]".format(k,i))
outputs.append("BANK_DIN{}[{}]".format(k,i))
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"]) self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
return inst return inst

96
compiler/sram_config.py Normal file
View File

@ -0,0 +1,96 @@
import debug
from math import log,sqrt,ceil
from importlib import reload
from globals import OPTS
class sram_config:
""" This is a structure that is used to hold the SRAM configuration options. """
def __init__(self, word_size, num_words, num_banks=1):
self.word_size = word_size
self.num_words = num_words
self.num_banks = num_banks
# This will get over-written when we determine the organization
self.words_per_row = None
# Move the module names to this?
def set_local_config(self, module):
""" Copy all of the member variables to the given module for convenience """
members = [attr for attr in dir(self) if not callable(getattr(self, attr)) and not attr.startswith("__")]
# Copy all the variables to the local module
for member in members:
setattr(module,member,getattr(self,member))
def compute_sizes(self):
""" Computes the organization of the memory using bitcell size by trying to make it square."""
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
# pass a copy of myself for the port numbers
self.bitcell = self.mod_bitcell()
debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.")
self.num_words_per_bank = self.num_words/self.num_banks
self.num_bits_per_bank = self.word_size*self.num_words_per_bank
# If this was hard coded, don't dynamically compute it!
if not self.words_per_row:
# Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry)
self.bank_area = self.bitcell.width*self.bitcell.height*self.num_bits_per_bank
self.bank_side_length = sqrt(self.bank_area)
# Estimate the words per row given the height of the bitcell and the square side length
self.tentative_num_cols = int(self.bank_side_length/self.bitcell.width)
self.words_per_row = self.estimate_words_per_row(self.tentative_num_cols, self.word_size)
# Estimate the number of rows given the tentative words per row
self.tentative_num_rows = self.num_bits_per_bank / (self.words_per_row*self.word_size)
self.words_per_row = self.amend_words_per_row(self.tentative_num_rows, self.words_per_row)
# Fix the number of columns and rows
self.num_cols = int(self.words_per_row*self.word_size)
self.num_rows = int(self.num_words_per_bank/self.words_per_row)
# Compute the address and bank sizes
self.row_addr_size = int(log(self.num_rows, 2))
self.col_addr_size = int(log(self.words_per_row, 2))
self.bank_addr_size = self.col_addr_size + self.row_addr_size
self.addr_size = self.bank_addr_size + int(log(self.num_banks, 2))
debug.info(1,"Words per row: {}".format(self.words_per_row))
def estimate_words_per_row(self,tentative_num_cols, word_size):
"""
This provides a heuristic rounded estimate for the number of words
per row.
"""
if tentative_num_cols < 1.5*word_size:
return 1
elif tentative_num_cols > 3*word_size:
return 4
else:
return 2
def amend_words_per_row(self,tentative_num_rows, words_per_row):
"""
This picks the number of words per row more accurately by limiting
it to a minimum and maximum.
"""
# Recompute the words per row given a hard max
if(not OPTS.is_unit_test and tentative_num_rows > 512):
debug.check(tentative_num_rows*words_per_row <= 2048, "Number of words exceeds 2048")
return int(words_per_row*tentative_num_rows/512)
# Recompute the words per row given a hard min
if(not OPTS.is_unit_test and tentative_num_rows < 16):
debug.check(tentative_num_rows*words_per_row >= 16, "Minimum number of rows is 16, but given {0}".format(tentative_num_rows))
return int(words_per_row*tentative_num_rows/16)
return words_per_row

View File

@ -13,52 +13,81 @@ import debug
OPTS = globals.OPTS OPTS = globals.OPTS
@unittest.skip("SKIPPING 04_pbitcell_test") #@unittest.skip("SKIPPING 04_pbitcell_test")
class pbitcell_test(openram_test): class pbitcell_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import pbitcell from pbitcell import pbitcell
import tech import tech
OPTS.num_rw_ports=1
OPTS.num_w_ports=1
OPTS.num_r_ports=1
debug.info(2, "Bitcell with 1 of each port: read/write, write, and read") debug.info(2, "Bitcell with 1 of each port: read/write, write, and read")
tx = pbitcell.pbitcell(num_readwrite=1,num_write=1,num_read=1) tx = pbitcell()
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports=0
OPTS.num_w_ports=1
OPTS.num_r_ports=1
debug.info(2, "Bitcell with 0 read/write ports") debug.info(2, "Bitcell with 0 read/write ports")
tx = pbitcell.pbitcell(num_readwrite=0,num_write=1,num_read=1) tx = pbitcell()
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports=1
OPTS.num_w_ports=0
OPTS.num_r_ports=1
debug.info(2, "Bitcell with 0 write ports") debug.info(2, "Bitcell with 0 write ports")
tx = pbitcell.pbitcell(num_readwrite=1,num_write=0,num_read=1) tx = pbitcell()
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports=1
OPTS.num_w_ports=1
OPTS.num_r_ports=0
debug.info(2, "Bitcell with 0 read ports") debug.info(2, "Bitcell with 0 read ports")
tx = pbitcell.pbitcell(num_readwrite=1,num_write=1,num_read=0) tx = pbitcell()
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports=1
OPTS.num_w_ports=0
OPTS.num_r_ports=0
debug.info(2, "Bitcell with 0 read ports and 0 write ports") debug.info(2, "Bitcell with 0 read ports and 0 write ports")
tx = pbitcell.pbitcell(num_readwrite=1,num_write=0,num_read=0) tx = pbitcell()
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports=2
OPTS.num_w_ports=2
OPTS.num_r_ports=2
debug.info(2, "Bitcell with 2 of each port: read/write, write, and read") debug.info(2, "Bitcell with 2 of each port: read/write, write, and read")
tx = pbitcell.pbitcell(num_readwrite=2,num_write=2,num_read=2) tx = pbitcell()
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports=0
OPTS.num_w_ports=2
OPTS.num_r_ports=2
debug.info(2, "Bitcell with 0 read/write ports") debug.info(2, "Bitcell with 0 read/write ports")
tx = pbitcell.pbitcell(num_readwrite=0,num_write=2,num_read=2) tx = pbitcell()
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports=2
OPTS.num_w_ports=0
OPTS.num_r_ports=2
debug.info(2, "Bitcell with 0 write ports") debug.info(2, "Bitcell with 0 write ports")
tx = pbitcell.pbitcell(num_readwrite=2,num_write=0,num_read=2) tx = pbitcell()
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports=2
OPTS.num_w_ports=2
OPTS.num_r_ports=0
debug.info(2, "Bitcell with 0 read ports") debug.info(2, "Bitcell with 0 read ports")
tx = pbitcell.pbitcell(num_readwrite=2,num_write=2,num_read=0) tx = pbitcell()
self.local_check(tx) self.local_check(tx)
OPTS.num_rw_ports=2
OPTS.num_w_ports=0
OPTS.num_r_ports=0
debug.info(2, "Bitcell with 0 read ports and 0 write ports") debug.info(2, "Bitcell with 0 read ports and 0 write ports")
tx = pbitcell.pbitcell(num_readwrite=2,num_write=0,num_read=0) tx = pbitcell()
self.local_check(tx) self.local_check(tx)
globals.end_openram() globals.end_openram()

View File

@ -24,9 +24,9 @@ class precharge_test(openram_test):
debug.info(2, "Checking precharge for pbitcell") debug.info(2, "Checking precharge for pbitcell")
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.rw_ports = 2 OPTS.num_rw_ports = 2
OPTS.r_ports = 2 OPTS.num_r_ports = 2
OPTS.w_ports = 2 OPTS.num_w_ports = 2
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="rwbl0", bitcell_br="rwbl_bar0") tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="rwbl0", bitcell_br="rwbl_bar0")
self.local_check(tx) self.local_check(tx)

View File

@ -11,7 +11,7 @@ import globals
from globals import OPTS from globals import OPTS
import debug import debug
@unittest.skip("SKIPPING 05_pbitcell_array_test") #@unittest.skip("SKIPPING 05_pbitcell_array_test")
class pbitcell_array_test(openram_test): class pbitcell_array_test(openram_test):
def runTest(self): def runTest(self):
@ -20,26 +20,26 @@ class pbitcell_array_test(openram_test):
debug.info(2, "Testing 4x4 array for multiport bitcell, with read ports at the edge of the bit cell") debug.info(2, "Testing 4x4 array for multiport bitcell, with read ports at the edge of the bit cell")
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.rw_ports = 2 OPTS.num_rw_ports = 2
OPTS.r_ports = 2 OPTS.num_r_ports = 2
OPTS.w_ports = 2 OPTS.num_w_ports = 2
a = bitcell_array.bitcell_array(name="pbitcell_array", cols=4, rows=4) a = bitcell_array.bitcell_array(name="pbitcell_array_Rport_edge", cols=4, rows=4)
self.local_check(a) self.local_check(a)
debug.info(2, "Testing 4x4 array for multiport bitcell, with write ports at the edge of the bit cell") debug.info(2, "Testing 4x4 array for multiport bitcell, with write ports at the edge of the bit cell")
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.rw_ports = 2 OPTS.num_rw_ports = 2
OPTS.r_ports = 0 OPTS.num_r_ports = 0
OPTS.w_ports = 2 OPTS.num_w_ports = 2
a = bitcell_array.bitcell_array(name="pbitcell_array", cols=4, rows=4) a = bitcell_array.bitcell_array(name="pbitcell_array_Wport_edge", cols=4, rows=4)
self.local_check(a) self.local_check(a)
debug.info(2, "Testing 4x4 array for multiport bitcell, with read/write ports at the edge of the bit cell") debug.info(2, "Testing 4x4 array for multiport bitcell, with read/write ports at the edge of the bit cell")
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.rw_ports = 2 OPTS.num_rw_ports = 2
OPTS.r_ports = 0 OPTS.num_r_ports = 0
OPTS.w_ports = 0 OPTS.num_w_ports = 0
a = bitcell_array.bitcell_array(name="pbitcell_array", cols=4, rows=4) a = bitcell_array.bitcell_array(name="pbitcell_array_RWport_edge", cols=4, rows=4)
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -24,9 +24,9 @@ class precharge_test(openram_test):
debug.info(2, "Checking precharge for pbitcell") debug.info(2, "Checking precharge for pbitcell")
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.rw_ports = 2 OPTS.num_rw_ports = 2
OPTS.r_ports = 2 OPTS.num_r_ports = 2
OPTS.w_ports = 2 OPTS.num_w_ports = 2
pc = precharge_array.precharge_array(columns=3, bitcell_bl="rwbl0", bitcell_br="rwbl_bar0") pc = precharge_array.precharge_array(columns=3, bitcell_bl="rwbl0", bitcell_br="rwbl_bar0")
self.local_check(pc) self.local_check(pc)

View File

@ -20,10 +20,21 @@ class wordline_driver_test(openram_test):
import wordline_driver import wordline_driver
import tech import tech
# check wordline driver array in single port
debug.info(2, "Checking driver") debug.info(2, "Checking driver")
tx = wordline_driver.wordline_driver(rows=8) tx = wordline_driver.wordline_driver(rows=8)
self.local_check(tx) self.local_check(tx)
# check wordline driver array in multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
debug.info(2, "Checking driver (multi-port case)")
tx = wordline_driver.wordline_driver(rows=8)
self.local_check(tx)
globals.end_openram() globals.end_openram()
# instantiate a copy of the class to actually run the test # instantiate a copy of the class to actually run the test

View File

@ -17,7 +17,7 @@ class sense_amp_test(openram_test):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import sense_amp_array import sense_amp_array
# check sense amp array in single port
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2") debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2")
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2) a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2)
self.local_check(a) self.local_check(a)
@ -26,6 +26,20 @@ class sense_amp_test(openram_test):
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4) a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4)
self.local_check(a) self.local_check(a)
# check sense amp array in multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2 (multi-port case)")
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2)
self.local_check(a)
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4 (multi-port case)")
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4)
self.local_check(a)
globals.end_openram() globals.end_openram()
# instantiate a copy of the class to actually run the test # instantiate a copy of the class to actually run the test

View File

@ -17,6 +17,7 @@ class write_driver_test(openram_test):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import write_driver_array import write_driver_array
# check write driver array in single port
debug.info(2, "Testing write_driver_array for columns=8, word_size=8") debug.info(2, "Testing write_driver_array for columns=8, word_size=8")
a = write_driver_array.write_driver_array(columns=8, word_size=8) a = write_driver_array.write_driver_array(columns=8, word_size=8)
self.local_check(a) self.local_check(a)
@ -25,6 +26,20 @@ class write_driver_test(openram_test):
a = write_driver_array.write_driver_array(columns=16, word_size=8) a = write_driver_array.write_driver_array(columns=16, word_size=8)
self.local_check(a) self.local_check(a)
# check write driver array in multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
debug.info(2, "Testing write_driver_array for columns=8, word_size=8 (multi-port case)")
a = write_driver_array.write_driver_array(columns=8, word_size=8)
self.local_check(a)
debug.info(2, "Testing write_driver_array for columns=16, word_size=8 (multi-port case)")
a = write_driver_array.write_driver_array(columns=16, word_size=8)
self.local_check(a)
globals.end_openram() globals.end_openram()
# instantiate a copy of the class to actually run the test # instantiate a copy of the class to actually run the test

View File

@ -16,21 +16,34 @@ class multi_bank_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
from bank import bank from bank import bank
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=16)
c.num_banks=2
c.words_per_row=1
debug.info(1, "No column mux") debug.info(1, "No column mux")
a = bank(word_size=4, num_words=16, words_per_row=1, num_banks=2, name="bank1_multi") a = bank(c, name="bank1_multi")
self.local_check(a) self.local_check(a)
c.num_words=32
c.words_per_row=2
debug.info(1, "Two way column mux") debug.info(1, "Two way column mux")
a = bank(word_size=4, num_words=32, words_per_row=2, num_banks=2, name="bank2_multi") a = bank(c, name="bank2_multi")
self.local_check(a) self.local_check(a)
c.num_words=64
c.words_per_row=4
debug.info(1, "Four way column mux") debug.info(1, "Four way column mux")
a = bank(word_size=4, num_words=64, words_per_row=4, num_banks=2, name="bank3_multi") a = bank(c, name="bank3_multi")
self.local_check(a) self.local_check(a)
c.word_size=2
c.num_words=128
c.words_per_row=8
debug.info(1, "Eight way column mux") debug.info(1, "Eight way column mux")
a = bank(word_size=2, num_words=128, words_per_row=8, num_banks=2, name="bank4_multi") a = bank(c, name="bank4_multi")
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -11,7 +11,7 @@ import globals
from globals import OPTS from globals import OPTS
import debug import debug
@unittest.skip("SKIPPING 19_psingle_bank_test") #@unittest.skip("SKIPPING 19_psingle_bank_test")
class psingle_bank_test(openram_test): class psingle_bank_test(openram_test):
def runTest(self): def runTest(self):
@ -20,65 +20,103 @@ class psingle_bank_test(openram_test):
import verify import verify
from bank import bank from bank import bank
from sram_config import sram_config
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
# testing all port configurations (with no column mux) to verify layout between bitcell array and peripheral circuitry # testing layout of bank using pbitcell with 1 RW port (a 6T-cell equivalent)
OPTS.rw_ports = 2 OPTS.num_rw_ports = 1
OPTS.w_ports = 2 OPTS.num_w_ports = 0
OPTS.r_ports = 2 OPTS.num_r_ports = 0
c = sram_config(word_size=4,
num_words=16)
c.words_per_row=1
debug.info(1, "No column mux") debug.info(1, "No column mux")
a = bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="bank1_2rw_2w_2r_single") a = bank(c, name="bank1_1rw_0w_0r_single")
self.local_check(a) self.local_check(a)
""" """
OPTS.rw_ports = 0 # multiport can't generate layout yet on the bank level
OPTS.w_ports = 2 OPTS.netlist_only = True
OPTS.r_ports = 2
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 1
OPTS.num_r_ports = 1
debug.info(1, "No column mux") debug.info(1, "No column mux")
a = bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="bank1_0rw_2w_2r_single") name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
a = bank(c, name=name)
self.local_check(a) self.local_check(a)
OPTS.rw_ports = 2 OPTS.num_rw_ports = c.num_rw_ports = 2
OPTS.w_ports = 0 OPTS.num_w_ports = c.num_w_ports = 2
OPTS.r_ports = 2 OPTS.num_r_ports = c.num_r_ports = 2
debug.info(1, "No column mux") debug.info(1, "No column mux")
a = bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="bank1_2rw_0w_2r_single") name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
a = bank(c, name=name)
self.local_check(a) self.local_check(a)
OPTS.rw_ports = 2 OPTS.num_rw_ports = c.num_rw_ports = 0
OPTS.w_ports = 2 OPTS.num_w_ports = c.num_w_ports = 2
OPTS.r_ports = 0 OPTS.num_r_ports = c.num_r_ports = 2
debug.info(1, "No column mux") debug.info(1, "No column mux")
a = bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="bank1_2rw_2w_0r_single") name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
a = bank(c, name=name)
self.local_check(a) self.local_check(a)
OPTS.rw_ports = 2 OPTS.num_rw_ports = c.num_rw_ports = 2
OPTS.w_ports = 0 OPTS.num_w_ports = c.num_w_ports = 0
OPTS.r_ports = 0 OPTS.num_r_ports = c.num_r_ports = 2
debug.info(1, "No column mux") debug.info(1, "No column mux")
a = bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="bank1_2rw_0w_0r_single") name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
a = bank(c, name=name)
self.local_check(a)
OPTS.num_rw_ports = c.num_rw_ports = 2
OPTS.num_w_ports = c.num_w_ports = 2
OPTS.num_r_ports = c.num_r_ports = 0
debug.info(1, "No column mux")
name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
a = bank(c, name=name)
self.local_check(a)
OPTS.num_rw_ports = c.num_rw_ports = 2
OPTS.num_w_ports = c.num_w_ports = 0
OPTS.num_r_ports = c.num_r_ports = 0
debug.info(1, "No column mux")
name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
a = bank(c, name=name)
self.local_check(a) self.local_check(a)
# testing with various column muxes # testing with various column muxes
OPTS.rw_ports = 2 OPTS.num_rw_ports = c.num_rw_ports = 2
OPTS.w_ports = 2 OPTS.num_w_ports = c.num_w_ports = 2
OPTS.r_ports = 2 OPTS.num_r_ports = c.num_r_ports = 2
c.num_words=32
c.words_per_row=2
debug.info(1, "Two way column mux") debug.info(1, "Two way column mux")
a = bank(word_size=4, num_words=32, words_per_row=2, num_banks=1, name="bank2_single") name = "bank2_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
a = bank(c, name=name)
self.local_check(a) self.local_check(a)
c.num_words=64
c.words_per_row=4
debug.info(1, "Four way column mux") debug.info(1, "Four way column mux")
a = bank(word_size=4, num_words=64, words_per_row=4, num_banks=1, name="bank3_single") name = "bank3_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
a = bank(c, name=name)
self.local_check(a) self.local_check(a)
# Eight way has a short circuit of one column mux select to gnd rail # Eight way has a short circuit of one column mux select to gnd rail
c.word_size=2
c.num_words=128
c.words_per_row=8
debug.info(1, "Eight way column mux") debug.info(1, "Eight way column mux")
a = bank(word_size=2, num_words=128, words_per_row=8, num_banks=1, name="bank4_single") name = "bank4_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
a = bank(c, name=name)
self.local_check(a) self.local_check(a)
""" """

View File

@ -16,22 +16,34 @@ class single_bank_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
from bank import bank from bank import bank
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=16)
c.words_per_row=1
debug.info(1, "No column mux") debug.info(1, "No column mux")
a = bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="bank1_single") a = bank(c, name="bank1_single")
self.local_check(a) self.local_check(a)
c.num_words=32
c.words_per_row=2
debug.info(1, "Two way column mux") debug.info(1, "Two way column mux")
a = bank(word_size=4, num_words=32, words_per_row=2, num_banks=1, name="bank2_single") a = bank(c, name="bank2_single")
self.local_check(a) self.local_check(a)
c.num_words=64
c.words_per_row=4
debug.info(1, "Four way column mux") debug.info(1, "Four way column mux")
a = bank(word_size=4, num_words=64, words_per_row=4, num_banks=1, name="bank3_single") a = bank(c, name="bank3_single")
self.local_check(a) self.local_check(a)
# Eight way has a short circuit of one column mux select to gnd rail # Eight way has a short circuit of one column mux select to gnd rail
c.word_size=2
c.num_words=128
c.words_per_row=8
debug.info(1, "Eight way column mux") debug.info(1, "Eight way column mux")
a = bank(word_size=2, num_words=128, words_per_row=8, num_banks=1, name="bank4_single") a = bank(c, name="bank4_single")
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -16,22 +16,34 @@ class sram_1bank_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
from sram import sram from sram import sram
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=16,
num_banks=1)
c.words_per_row=1
debug.info(1, "Single bank, no column mux with control logic") debug.info(1, "Single bank, no column mux with control logic")
a = sram(word_size=4, num_words=16, num_banks=1, name="sram1") a = sram(c, "sram1")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)
# debug.info(1, "Single bank two way column mux with control logic") c.num_words=32
# a = sram(word_size=4, num_words=32, num_banks=1, name="sram2") c.words_per_row=2
# self.local_check(a, final_verification=True) debug.info(1, "Single bank two way column mux with control logic")
a = sram(c, "sram2")
self.local_check(a, final_verification=True)
# debug.info(1, "Single bank, four way column mux with control logic") c.num_words=64
# a = sram(word_size=4, num_words=64, num_banks=1, name="sram3") c.words_per_row=4
# self.local_check(a, final_verification=True) debug.info(1, "Single bank, four way column mux with control logic")
a = sram(c, "sram3")
self.local_check(a, final_verification=True)
# debug.info(1, "Single bank, eight way column mux with control logic") c.word_size=2
# a = sram(word_size=2, num_words=128, num_banks=1, name="sram4") c.num_words=128
# self.local_check(a, final_verification=True) c.words_per_row=8
debug.info(1, "Single bank, eight way column mux with control logic")
a = sram(c, "sram4")
self.local_check(a, final_verification=True)
globals.end_openram() globals.end_openram()

View File

@ -17,21 +17,33 @@ class sram_2bank_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
from sram import sram from sram import sram
from sram_config import sram_config
c = sram_config(word_size=16,
num_words=32,
num_banks=2)
c.words_per_row=1
debug.info(1, "Two bank, no column mux with control logic") debug.info(1, "Two bank, no column mux with control logic")
a = sram(word_size=16, num_words=32, num_banks=2, name="sram1") a = sram(c, "sram1")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)
c.num_words=64
c.words_per_row=2
debug.info(1, "Two bank two way column mux with control logic") debug.info(1, "Two bank two way column mux with control logic")
a = sram(word_size=16, num_words=64, num_banks=2, name="sram2") a = sram(c, "sram2")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)
c.num_words=128
c.words_per_row=4
debug.info(1, "Two bank, four way column mux with control logic") debug.info(1, "Two bank, four way column mux with control logic")
a = sram(word_size=16, num_words=128, num_banks=2, name="sram3") a = sram(c, "sram3")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)
c.word_size=2
c.num_words=256
c.words_per_row=8
debug.info(1, "Two bank, eight way column mux with control logic") debug.info(1, "Two bank, eight way column mux with control logic")
a = sram(word_size=2, num_words=256, num_banks=2, name="sram4") a = sram(c, "sram4")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)
globals.end_openram() globals.end_openram()

View File

@ -17,21 +17,32 @@ class sram_4bank_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
from sram import sram from sram import sram
from sram_config import sram_config
c = sram_config(word_size=16,
num_words=64,
num_banks=4)
debug.info(1, "Four bank, no column mux with control logic") debug.info(1, "Four bank, no column mux with control logic")
a = sram(word_size=16, num_words=64, num_banks=4, name="sram1") a = sram(c, "sram1")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)
c.num_words=128
c.words_per_row=2
debug.info(1, "Four bank two way column mux with control logic") debug.info(1, "Four bank two way column mux with control logic")
a = sram(word_size=16, num_words=128, num_banks=4, name="sram2") a = sram(c, "sram2")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)
c.num_words=256
c.words_per_row=4
debug.info(1, "Four bank, four way column mux with control logic") debug.info(1, "Four bank, four way column mux with control logic")
a = sram(word_size=16, num_words=256, num_banks=4, name="sram3") a = sram(c, "sram3")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)
c.word_size=2
c.num_words=256
c.words_per_row=8
debug.info(1, "Four bank, eight way column mux with control logic") debug.info(1, "Four bank, eight way column mux with control logic")
a = sram.sram(word_size=2, num_words=256, num_banks=4, name="sram4") a = sram.sram(c, "sram4")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)
globals.end_openram() globals.end_openram()

View File

@ -27,14 +27,14 @@ class timing_sram_test(openram_test):
if not OPTS.spice_exe: if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
import sram from sram import sram
import tech from sram_config import sram_config
c = sram_config(word_size=1,
num_words=16,
num_banks=1)
c.words_per_row=1
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
s = sram.sram(word_size=OPTS.word_size, s = sram(c, name="sram1")
num_words=OPTS.num_words,
num_banks=OPTS.num_banks,
name="sram1")
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice) s.sp_write(tempspice)

View File

@ -27,13 +27,14 @@ class timing_sram_test(openram_test):
if not OPTS.spice_exe: if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
import sram from sram import sram
import tech from sram_config import sram_config
c = sram_config(word_size=1,
num_words=16,
num_banks=1)
c.words_per_row=1
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
s = sram.sram(word_size=OPTS.word_size, s = sram(c, name="sram1")
num_words=OPTS.num_words,
num_banks=OPTS.num_banks,
name="sram1")
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice) s.sp_write(tempspice)

View File

@ -16,15 +16,15 @@ class lib_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import sram
from characterizer import lib from characterizer import lib
from sram import sram
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank") from sram_config import sram_config
s = sram.sram(word_size=2, c = sram_config(word_size=2,
num_words=16, num_words=16,
num_banks=1, num_banks=1)
name="sram_2_16_1_{0}".format(OPTS.tech_name)) c.words_per_row=1
debug.info(1, "Testing analytical timing for sample 2 bit, 16 words SRAM with 1 bank")
s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice) s.sp_write(tempspice)

View File

@ -26,13 +26,14 @@ class lib_test(openram_test):
if not OPTS.spice_exe: if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
import sram from sram import sram
from sram_config import sram_config
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank") c = sram_config(word_size=2,
s = sram.sram(word_size=2, num_words=16,
num_words=16, num_banks=1)
num_banks=1, c.words_per_row=1
name="sram_2_16_1_{0}".format(OPTS.tech_name)) debug.info(1, "Testing pruned timing for sample 2 bit, 16 words SRAM with 1 bank")
s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice) s.sp_write(tempspice)

View File

@ -26,13 +26,14 @@ class lib_test(openram_test):
if not OPTS.spice_exe: if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
import sram from sram import sram
from sram_config import sram_config
c = sram_config(word_size=2,
num_words=16,
num_banks=1)
c.words_per_row=1
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank") debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank")
s = sram.sram(word_size=2, s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
num_words=16,
num_banks=1,
name="sram_2_16_1_{0}".format(OPTS.tech_name))
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice) s.sp_write(tempspice)

View File

@ -17,13 +17,14 @@ class lef_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import sram from sram import sram
from sram_config import sram_config
c = sram_config(word_size=2,
num_words=16,
num_banks=1)
c.words_per_row=1
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(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
num_words=OPTS.num_words,
num_banks=OPTS.num_banks,
name="sram_2_16_1_{0}".format(OPTS.tech_name))
gdsfile = s.name + ".gds" gdsfile = s.name + ".gds"
leffile = s.name + ".lef" leffile = s.name + ".lef"

View File

@ -16,13 +16,14 @@ class verilog_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import sram from sram import sram
from sram_config import sram_config
c = sram_config(word_size=2,
num_words=16,
num_banks=1)
c.words_per_row=1
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(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
num_words=OPTS.num_words,
num_banks=OPTS.num_banks,
name="sram_2_16_1_{0}".format(OPTS.tech_name))
vfile = s.name + ".v" vfile = s.name + ".v"
vname = OPTS.openram_temp + vfile vname = OPTS.openram_temp + vfile

View File

@ -56,6 +56,7 @@ layer["via9"] = 28
layer["metal10"] = 29 layer["metal10"] = 29
layer["text"] = 239 layer["text"] = 239
layer["boundary"]= 239 layer["boundary"]= 239
layer["blockage"]= 239
################################################### ###################################################
##END GDS Layer Map ##END GDS Layer Map
@ -98,6 +99,8 @@ drc["minwidth_poly"] = 0.05
drc["poly_to_poly"] = 0.14 drc["poly_to_poly"] = 0.14
# POLY.3 Minimum poly extension beyond active # POLY.3 Minimum poly extension beyond active
drc["poly_extend_active"] = 0.055 drc["poly_extend_active"] = 0.055
# Not a rule
drc["poly_to_polycontact"] = 0.075
# POLY.4 Minimum enclosure of active around gate # POLY.4 Minimum enclosure of active around gate
drc["active_enclosure_gate"] = 0.07 drc["active_enclosure_gate"] = 0.07
# POLY.5 Minimum spacing of field poly to active # POLY.5 Minimum spacing of field poly to active

View File

@ -1,6 +1,6 @@
magic magic
tech scmos tech scmos
timestamp 1521677056 timestamp 1536091415
<< nwell >> << nwell >>
rect -8 29 42 51 rect -8 29 42 51
<< pwell >> << pwell >>
@ -105,13 +105,13 @@ rect 6 2 10 48
rect 24 -2 28 48 rect 24 -2 28 48
rect 32 33 36 48 rect 32 33 36 48
rect 32 -2 36 29 rect 32 -2 36 29
<< m3p >> << bb >>
rect 0 0 34 46 rect 0 0 34 46
<< labels >> << labels >>
rlabel metal2 0 0 0 0 1 gnd rlabel metal2 0 0 0 0 1 gnd
rlabel metal2 34 0 34 0 1 gnd rlabel metal2 34 0 34 0 1 gnd
rlabel m2contact 17 46 17 46 5 vdd rlabel m2contact 17 46 17 46 5 vdd
rlabel metal1 4 7 4 7 1 WL rlabel metal2 8 43 8 43 1 bl
rlabel metal2 8 43 8 43 1 BL rlabel metal2 26 43 26 43 1 br
rlabel metal2 26 43 26 43 1 BR rlabel metal1 4 7 4 7 1 wl
<< end >> << end >>

View File

@ -1,6 +1,6 @@
magic magic
tech scmos tech scmos
timestamp 1518823399 timestamp 1536089597
<< nwell >> << nwell >>
rect 0 48 109 103 rect 0 48 109 103
<< pwell >> << pwell >>
@ -266,7 +266,7 @@ rect 6 30 10 50
rect 22 20 26 57 rect 22 20 26 57
rect 70 44 74 70 rect 70 44 74 70
rect 70 20 74 40 rect 70 20 74 40
<< m3p >> << bb >>
rect 0 0 109 100 rect 0 0 109 100
<< labels >> << labels >>
rlabel m2contact 15 34 15 34 4 clk rlabel m2contact 15 34 15 34 4 clk

View File

@ -1,6 +1,6 @@
magic magic
tech scmos tech scmos
timestamp 1523479368 timestamp 1536089622
<< nwell >> << nwell >>
rect -2 0 18 200 rect -2 0 18 200
<< pwell >> << pwell >>
@ -280,7 +280,7 @@ rect 14 8 20 9
rect 14 4 15 8 rect 14 4 15 8
rect 19 4 20 8 rect 19 4 20 8
rect 14 3 20 4 rect 14 3 20 4
<< m3p >> << bb >>
rect 0 0 34 200 rect 0 0 34 200
<< labels >> << labels >>
rlabel metal1 0 8 0 8 2 clk rlabel metal1 0 8 0 8 2 clk

View File

@ -1,6 +1,6 @@
magic magic
tech scmos tech scmos
timestamp 1521677136 timestamp 1536091380
<< nwell >> << nwell >>
rect -8 29 42 51 rect -8 29 42 51
<< pwell >> << pwell >>
@ -106,13 +106,13 @@ rect 6 2 10 48
rect 24 -2 28 48 rect 24 -2 28 48
rect 32 33 36 48 rect 32 33 36 48
rect 32 -2 36 29 rect 32 -2 36 29
<< m3p >> << bb >>
rect 0 0 34 46 rect 0 0 34 46
<< labels >> << labels >>
rlabel metal2 0 0 0 0 1 gnd rlabel metal2 0 0 0 0 1 gnd
rlabel metal2 34 0 34 0 1 gnd rlabel metal2 34 0 34 0 1 gnd
rlabel m2contact 17 46 17 46 5 vdd rlabel m2contact 17 46 17 46 5 vdd
rlabel metal1 4 7 4 7 1 WL rlabel metal2 8 43 8 43 1 bl
rlabel metal2 8 43 8 43 1 BL rlabel metal2 26 43 26 43 1 br
rlabel metal2 26 43 26 43 1 BR rlabel metal1 4 7 4 7 1 wl
<< end >> << end >>

View File

@ -1,6 +1,6 @@
magic magic
tech scmos tech scmos
timestamp 1524065550 timestamp 1536089670
<< nwell >> << nwell >>
rect 0 0 40 102 rect 0 0 40 102
<< pwell >> << pwell >>
@ -122,7 +122,7 @@ rect 20 44 22 48
rect 3 0 7 11 rect 3 0 7 11
rect 10 0 14 44 rect 10 0 14 44
rect 20 0 24 44 rect 20 0 24 44
<< m3p >> << bb >>
rect 0 0 34 163 rect 0 0 34 163
<< labels >> << labels >>
flabel metal1 0 149 0 149 4 FreeSans 26 0 0 0 en flabel metal1 0 149 0 149 4 FreeSans 26 0 0 0 en

View File

@ -1,6 +1,6 @@
magic magic
tech scmos tech scmos
timestamp 1524499924 timestamp 1536089695
<< nwell >> << nwell >>
rect -2 45 38 73 rect -2 45 38 73
<< pwell >> << pwell >>
@ -86,7 +86,7 @@ rect 24 19 28 23
<< metal2 >> << metal2 >>
rect 15 34 25 38 rect 15 34 25 38
rect 15 0 19 34 rect 15 0 19 34
<< m3p >> << bb >>
rect 0 0 34 73 rect 0 0 34 73
<< labels >> << labels >>
rlabel metal1 0 12 0 12 3 en rlabel metal1 0 12 0 12 3 en

View File

@ -1,6 +1,6 @@
magic magic
tech scmos tech scmos
timestamp 1524499497 timestamp 1536089714
<< nwell >> << nwell >>
rect -3 101 37 138 rect -3 101 37 138
rect -3 0 37 51 rect -3 0 37 51
@ -209,7 +209,7 @@ rect 10 196 14 202
rect 20 193 24 202 rect 20 193 24 202
rect 20 177 24 189 rect 20 177 24 189
rect 15 0 19 6 rect 15 0 19 6
<< m3p >> << bb >>
rect 0 0 34 202 rect 0 0 34 202
<< labels >> << labels >>
rlabel metal2 15 1 15 1 1 din rlabel metal2 15 1 15 1 1 din

View File

@ -276,6 +276,11 @@ cifoutput
style lambda=0.30(p) style lambda=0.30(p)
scalefactor 30 15 scalefactor 30 15
# This is a custom section to add bounding boxes in OpenRAM
layer BB bb
labels bb
calma 63 0
layer CWN nwell,rnw layer CWN nwell,rnw
bloat-or pdiff,rpd,pdc/a,pfet * 180 bloat-or pdiff,rpd,pdc/a,pfet * 180
bloat-or nsd,nsc/a * 90 bloat-or nsd,nsc/a * 90
@ -1506,7 +1511,12 @@ cifinput
style lambda=0.30(p) style lambda=0.30(p)
scalefactor 30 scalefactor 30
layer nwell CWN # This is a custom section to add bounding boxes in OpenRAM
layer bb BB
labels BB
calma 63 0
layer nwell CWN
and-not CWNR and-not CWNR
and-not CTA and-not CTA
labels CWN labels CWN

View File

@ -39,8 +39,9 @@ layer["via1"] = 50
layer["metal2"] = 51 layer["metal2"] = 51
layer["via2"] = 61 layer["via2"] = 61
layer["metal3"] = 62 layer["metal3"] = 62
layer["text"] = 83 layer["text"] = 63
layer["boundary"] = 83 layer["boundary"] = 63
layer["blockage"] = 83
################################################### ###################################################
##END GDS Layer Map ##END GDS Layer Map
@ -83,14 +84,14 @@ drc["minwidth_poly"] = 0.6
drc["poly_to_poly"] = 0.9 drc["poly_to_poly"] = 0.9
# 3.3 Minimum gate extension of active # 3.3 Minimum gate extension of active
drc["poly_extend_active"] = 0.6 drc["poly_extend_active"] = 0.6
# ?? # 5.5.b Minimum spacing between poly contact and other poly (alternative rules)
drc["poly_to_polycontact"] = 1.2 drc["poly_to_polycontact"] = 1.2
# ?? # ??
drc["active_enclosure_gate"] = 0.0 drc["active_enclosure_gate"] = 0.0
# 3.2.a Minimum spacing over field poly
drc["poly_to_field_poly"] = 0.9
# 3.5 Minimum field poly to active # 3.5 Minimum field poly to active
drc["poly_to_active"] = 0.3 drc["poly_to_active"] = 0.3
# 3.2.a Minimum spacing over field poly
drc["poly_to_field_poly"] = 0.9
# Not a rule # Not a rule
drc["minarea_poly"] = 0.0 drc["minarea_poly"] = 0.0

View File

@ -625,7 +625,7 @@ drDefinePacket(
( display deviceAnt stipple0 solid yellow yellow solid ) ( display deviceAnt stipple0 solid yellow yellow solid )
( display winBottomShadow solid solid winColor1 winColor1 solid ) ( display winBottomShadow solid solid winColor1 winColor1 solid )
( display PselectNet dots4 solid brown brown outlineStipple) ( display PselectNet dots4 solid brown brown outlineStipple)
( display comment stipple0 lineStyle0 winBack winBack solid ) ( display comment stipple0 lineStyle0 winBack winBack outline )
( display Poly1 dots lineStyle0 red red outlineStipple) ( display Poly1 dots lineStyle0 red red outlineStipple)
( display Unrouted stipple0 lineStyle1 winColor5 winColor5 solid ) ( display Unrouted stipple0 lineStyle1 winColor5 winColor5 solid )
( display stretch stipple0 solid yellow yellow solid ) ( display stretch stipple0 solid yellow yellow solid )

View File

@ -13,4 +13,4 @@ Metal2 drawing 51 0
Via2 drawing 61 0 Via2 drawing 61 0
Metal3 drawing 62 0 Metal3 drawing 62 0
Glass drawing 52 0 Glass drawing 52 0
text drawing 83 0 comment drawing 63 0