mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev' into multiport_characterization
This commit is contained in:
commit
f824d039c6
|
|
@ -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
|
||||
hierarchy as the contact.
|
||||
"""
|
||||
|
||||
def __init__(self, layer_stack, dimensions=[1,1], implant_type=None, well_type=None):
|
||||
if implant_type or well_type:
|
||||
name = "{0}_{1}_{2}_{3}x{4}_{5}{6}".format(layer_stack[0],
|
||||
|
|
@ -24,13 +25,14 @@ class contact(hierarchy_design.hierarchy_design):
|
|||
dimensions[1],
|
||||
implant_type,
|
||||
well_type)
|
||||
|
||||
else:
|
||||
name = "{0}_{1}_{2}_{3}x{4}".format(layer_stack[0],
|
||||
layer_stack[1],
|
||||
layer_stack[2],
|
||||
dimensions[0],
|
||||
dimensions[1])
|
||||
|
||||
layer_stack[1],
|
||||
layer_stack[2],
|
||||
dimensions[0],
|
||||
dimensions[1])
|
||||
|
||||
hierarchy_design.hierarchy_design.__init__(self, name)
|
||||
debug.info(4, "create contact object {0}".format(name))
|
||||
|
||||
|
|
|
|||
|
|
@ -379,12 +379,10 @@ class layout(lef.lef):
|
|||
dimensions=size,
|
||||
implant_type=implant_type,
|
||||
well_type=well_type)
|
||||
|
||||
debug.check(mirror=="R0","Use rotate to rotate vias instead of mirror.")
|
||||
|
||||
height = via.height
|
||||
width = via.width
|
||||
|
||||
debug.check(mirror=="R0","Use rotate to rotate vias instead of mirror.")
|
||||
|
||||
if rotate==0:
|
||||
corrected_offset = offset + vector(-0.5*width,-0.5*height)
|
||||
elif rotate==90:
|
||||
|
|
@ -849,10 +847,10 @@ class layout(lef.lef):
|
|||
"""
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=loc,
|
||||
rotate=rotate)
|
||||
rotate=float(rotate))
|
||||
via=self.add_via_center(layers=("metal2", "via2", "metal3"),
|
||||
offset=loc,
|
||||
rotate=rotate)
|
||||
rotate=float(rotate))
|
||||
self.add_layout_pin_rect_center(text=name,
|
||||
layer="metal3",
|
||||
offset=loc,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import debug
|
||||
from tech import GDS
|
||||
from tech import GDS, drc
|
||||
from vector import vector
|
||||
from tech import layer
|
||||
|
||||
|
|
@ -36,16 +36,29 @@ class pin_layout:
|
|||
def __eq__(self, other):
|
||||
""" Check if these are the same pins for duplicate checks """
|
||||
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:
|
||||
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):
|
||||
""" Check if a shape overlaps with a rectangle """
|
||||
ll = self.rect[0]
|
||||
ur = self.rect[1]
|
||||
oll = other.rect[0]
|
||||
our = other.rect[1]
|
||||
(ll,ur) = self.rect
|
||||
(oll,our) = other.rect
|
||||
# Start assuming no overlaps
|
||||
x_overlaps = False
|
||||
y_overlaps = False
|
||||
|
|
|
|||
|
|
@ -294,7 +294,7 @@ class Gds2reader:
|
|||
mirrorFlag = bool(transFlags&0x8000) ##these flags are a bit sketchy
|
||||
rotateFlag = bool(transFlags&0x0002)
|
||||
magnifyFlag = bool(transFlags&0x0004)
|
||||
thisSref.transFlags=[mirrorFlag,rotateFlag,magnifyFlag]
|
||||
thisSref.transFlags=[mirrorFlag,magnifyFlag,rotateFlag]
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tMirror X:"+str(mirrorFlag))
|
||||
print( "\t\t\tRotate:"+str(rotateFlag))
|
||||
|
|
@ -345,7 +345,7 @@ class Gds2reader:
|
|||
mirrorFlag = bool(transFlags&0x8000) ##these flags are a bit sketchy
|
||||
rotateFlag = bool(transFlags&0x0002)
|
||||
magnifyFlag = bool(transFlags&0x0004)
|
||||
thisAref.transFlags=[mirrorFlag,rotateFlag,magnifyFlag]
|
||||
thisAref.transFlags=[mirrorFlag,magnifyFlag,rotateFlag]
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tMirror X:"+str(mirrorFlag))
|
||||
print("\t\t\tRotate:"+str(rotateFlag))
|
||||
|
|
@ -408,7 +408,7 @@ class Gds2reader:
|
|||
mirrorFlag = bool(transFlags&0x8000) ##these flags are a bit sketchy
|
||||
rotateFlag = bool(transFlags&0x0002)
|
||||
magnifyFlag = bool(transFlags&0x0004)
|
||||
thisText.transFlags=[mirrorFlag,rotateFlag,magnifyFlag]
|
||||
thisText.transFlags=[mirrorFlag,magnifyFlag,rotateFlag]
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tMirror X:"+str(mirrorFlag))
|
||||
print("\t\t\tRotate:"+str(rotateFlag))
|
||||
|
|
|
|||
|
|
@ -280,8 +280,13 @@ class Gds2writer:
|
|||
if(thisSref.transFlags!=""):
|
||||
idBits=b'\x1A\x01'
|
||||
mirrorFlag = int(thisSref.transFlags[0])<<15
|
||||
rotateFlag = int(thisSref.transFlags[1])<<1
|
||||
magnifyFlag = int(thisSref.transFlags[2])<<3
|
||||
# The rotate and magnify flags specify "absolute" rotate and magnify.
|
||||
# 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)
|
||||
self.writeRecord(idBits+transFlags)
|
||||
if(thisSref.magFactor!=""):
|
||||
|
|
@ -327,15 +332,20 @@ class Gds2writer:
|
|||
if(thisAref.transFlags):
|
||||
idBits=b'\x1A\x01'
|
||||
mirrorFlag = int(thisAref.transFlags[0])<<15
|
||||
rotateFlag = int(thisAref.transFlags[1])<<1
|
||||
magnifyFlag = int(thisAref.transFlags[0])<<3
|
||||
# The rotate and magnify flags specify "absolute" rotate and magnify.
|
||||
# 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)
|
||||
self.writeRecord(idBits+transFlags)
|
||||
if(thisAref.magFactor):
|
||||
if(thisAref.magFactor!=""):
|
||||
idBits=b'\x1B\x05'
|
||||
magFactor=self.ibmDataFromIeeeDouble(thisAref.magFactor)
|
||||
self.writeRecord(idBits+magFactor)
|
||||
if(thisAref.rotateAngle):
|
||||
if(thisAref.rotateAngle!=""):
|
||||
idBits=b'\x1C\x05'
|
||||
rotateAngle=self.ibmDataFromIeeeDouble(thisAref.rotateAngle)
|
||||
self.writeRecord(idBits+rotateAngle)
|
||||
|
|
@ -374,15 +384,20 @@ class Gds2writer:
|
|||
if(thisText.transFlags != ""):
|
||||
idBits=b'\x1A\x01'
|
||||
mirrorFlag = int(thisText.transFlags[0])<<15
|
||||
rotateFlag = int(thisText.transFlags[1])<<1
|
||||
magnifyFlag = int(thisText.transFlags[0])<<3
|
||||
# The rotate and magnify flags specify "absolute" rotate and magnify.
|
||||
# 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)
|
||||
self.writeRecord(idBits+transFlags)
|
||||
if(thisText.magFactor != ""):
|
||||
if(thisText.magFactor!=""):
|
||||
idBits=b'\x1B\x05'
|
||||
magFactor=self.ibmDataFromIeeeDouble(thisText.magFactor)
|
||||
self.writeRecord(idBits+magFactor)
|
||||
if(thisText.rotateAngle != ""):
|
||||
if(thisText.rotateAngle!=""):
|
||||
idBits=b'\x1C\x05'
|
||||
rotateAngle=self.ibmDataFromIeeeDouble(thisText.rotateAngle)
|
||||
self.writeRecord(idBits+rotateAngle)
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ class GdsText:
|
|||
self.plex=""
|
||||
self.drawingLayer=""
|
||||
self.purposeLayer = None
|
||||
self.transFlags=[0,00]
|
||||
self.transFlags=[0,0,0]
|
||||
self.magFactor=""
|
||||
self.rotateAngle=""
|
||||
self.pathType=""
|
||||
|
|
|
|||
|
|
@ -64,10 +64,11 @@ class VlsiLayout:
|
|||
#helper method to rotate a list of coordinates
|
||||
angle=math.radians(float(0))
|
||||
if(rotateAngle):
|
||||
angle = math.radians(float(repr(rotateAngle)))
|
||||
angle = math.radians(float(rotateAngle))
|
||||
|
||||
coordinatesRotate = [] #this will hold the rotated values
|
||||
for coordinate in coordinatesToRotate:
|
||||
# This is the CCW rotation matrix
|
||||
newX = coordinate[0]*math.cos(angle) - coordinate[1]*math.sin(angle)
|
||||
newY = coordinate[0]*math.sin(angle) + coordinate[1]*math.cos(angle)
|
||||
coordinatesRotate.extend((newX,newY))
|
||||
|
|
@ -274,8 +275,9 @@ class VlsiLayout:
|
|||
Method to insert one layout into another at a particular offset.
|
||||
"""
|
||||
offsetInLayoutUnits = (self.userUnits(offsetInMicrons[0]),self.userUnits(offsetInMicrons[1]))
|
||||
if self.debug==1:
|
||||
debug.info(0,"DEBUG: GdsMill vlsiLayout: addInstance: type %s, nameOfLayout "%type(layoutToAdd),nameOfLayout)
|
||||
if self.debug:
|
||||
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.
|
||||
|
||||
if layoutToAdd != self:
|
||||
|
|
@ -316,9 +318,7 @@ class VlsiLayout:
|
|||
if mirror or rotate:
|
||||
|
||||
layoutToAddSref.transFlags = [0,0,0]
|
||||
# This is NOT the same as the order in the GDS spec!
|
||||
# It gets written out in gds2writer in the right order though.
|
||||
# transFlags = (mirror around x-axis, rotation, magnification)
|
||||
# transFlags = (mirror around x-axis, magnification, rotation)
|
||||
# If magnification or rotation is true, it is the flags are then
|
||||
# followed by an amount in the record
|
||||
if mirror=="R90":
|
||||
|
|
@ -328,17 +328,16 @@ class VlsiLayout:
|
|||
if mirror=="R270":
|
||||
rotate = 270.0
|
||||
if rotate:
|
||||
#layoutToAddSref.transFlags = [0,1,0]
|
||||
#layoutToAddSref.transFlags[2] = 1
|
||||
layoutToAddSref.rotateAngle = rotate
|
||||
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
|
||||
#layoutToAddSref.transFlags = [1,1,0]
|
||||
layoutToAddSref.transFlags = [1,0,0]
|
||||
layoutToAddSref.transFlags[0] = 1
|
||||
#layoutToAddSref.transFlags[2] = 1
|
||||
layoutToAddSref.rotateAngle = 180.0
|
||||
if mirror == "xy" or mirror == "XY": #NOTE: "XY" option will override specified rotate angle
|
||||
#layoutToAddSref.transFlags = [0,1,0]
|
||||
layoutToAddSref.transFlags = [0,0,0]
|
||||
#layoutToAddSref.transFlags[2] = 1
|
||||
layoutToAddSref.rotateAngle = 180.0
|
||||
|
||||
#add the sref to the root structure
|
||||
|
|
@ -405,10 +404,10 @@ class VlsiLayout:
|
|||
if(len(text)%2 == 1):
|
||||
text = text + '\x00'
|
||||
textToAdd.textString = text
|
||||
textToAdd.transFlags = [0,0,1]
|
||||
#textToAdd.transFlags[1] = 1
|
||||
textToAdd.magFactor = magnification
|
||||
if rotate:
|
||||
textToAdd.transFlags = [0,1,1]
|
||||
#textToAdd.transFlags[2] = 1
|
||||
textToAdd.rotateAngle = rotate
|
||||
#add the sref to the root structure
|
||||
self.structures[self.rootStructureName].texts.append(textToAdd)
|
||||
|
|
@ -816,10 +815,10 @@ class VlsiLayout:
|
|||
"""
|
||||
|
||||
(structureName,structureOrigin,structureuVector,structurevVector)=structure
|
||||
#print(structureName,"u",structureuVector.transpose(),"v",structurevVector.transpose(),"o",structureOrigin.transpose())
|
||||
boundaries = []
|
||||
for boundary in self.structures[str(structureName)].boundaries:
|
||||
# Pin enclosures only work on rectangular pins so ignore any non rectangle
|
||||
# This may report not finding pins, but the user should fix this by adding a rectangle.
|
||||
# FIXME: Right now, this only supports rectangular shapes!
|
||||
if len(boundary.coordinates)!=5:
|
||||
continue
|
||||
if layer==boundary.drawingLayer:
|
||||
|
|
@ -827,10 +826,11 @@ class VlsiLayout:
|
|||
right_top=boundary.coordinates[2]
|
||||
# Rectangle is [leftx, bottomy, rightx, topy].
|
||||
boundaryRect=[left_bottom[0],left_bottom[1],right_top[0],right_top[1]]
|
||||
# perform the rotation
|
||||
boundaryRect=self.transformRectangle(boundaryRect,structureuVector,structurevVector)
|
||||
# add the offset
|
||||
boundaryRect=[boundaryRect[0]+structureOrigin[0].item(),boundaryRect[1]+structureOrigin[1].item(),
|
||||
boundaryRect[2]+structureOrigin[0].item(),boundaryRect[3]+structureOrigin[1].item()]
|
||||
|
||||
boundaries.append(boundaryRect)
|
||||
|
||||
return boundaries
|
||||
|
|
@ -858,8 +858,12 @@ class VlsiLayout:
|
|||
"""
|
||||
Rotate a coordinate in space.
|
||||
"""
|
||||
x=coordinate[0]*uVector[0].item()+coordinate[1]*uVector[1].item()
|
||||
y=coordinate[1]*vVector[1].item()+coordinate[0]*vVector[0].item()
|
||||
# MRG: 9/3/18 Incorrect matrixi multiplication!
|
||||
# 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]
|
||||
|
||||
return transformCoordinate
|
||||
|
|
|
|||
|
|
@ -116,6 +116,8 @@ def init_openram(config_file, is_unit_test=True):
|
|||
|
||||
import_tech()
|
||||
|
||||
init_paths()
|
||||
|
||||
# Reset the static duplicate name checker for unit tests.
|
||||
import hierarchy_design
|
||||
hierarchy_design.hierarchy_design.name_map=[]
|
||||
|
|
@ -204,36 +206,31 @@ def read_config(config_file, is_unit_test=True):
|
|||
# Note that if we re-read a config file, nothing will get read again!
|
||||
if not k in OPTS.__dict__ or k=="tech_name":
|
||||
OPTS.__dict__[k]=v
|
||||
|
||||
|
||||
# Massage the output path to be an absolute one
|
||||
if not OPTS.output_path.endswith('/'):
|
||||
OPTS.output_path += "/"
|
||||
if not OPTS.output_path.startswith('/'):
|
||||
OPTS.output_path = os.getcwd() + "/" + 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
|
||||
|
||||
# If we are only generating a netlist, we can't do DRC/LVS
|
||||
if OPTS.netlist_only:
|
||||
OPTS.check_lvsdrc=False
|
||||
|
||||
|
||||
# If config didn't set output name, make a reasonable default.
|
||||
if (OPTS.output_name == ""):
|
||||
OPTS.output_name = "sram_{0}rw_{1}b_{2}w_{3}bank_{4}".format(OPTS.rw_ports,
|
||||
OPTS.word_size,
|
||||
OPTS.num_words,
|
||||
OPTS.num_banks,
|
||||
OPTS.tech_name)
|
||||
OPTS.output_name = "sram_{0}b_{1}w_{2}bank_{3}rw_{4}w_{5}r_{6}".format(OPTS.word_size,
|
||||
OPTS.num_words,
|
||||
OPTS.num_banks,
|
||||
OPTS.num_rw_ports,
|
||||
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():
|
||||
|
|
@ -257,7 +254,8 @@ def cleanup_paths():
|
|||
if not OPTS.purge_temp:
|
||||
debug.info(0,"Preserving temp directory: {}".format(OPTS.openram_temp))
|
||||
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
|
||||
#shutil.rmtree(OPTS.openram_temp, ignore_errors=True)
|
||||
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 += "/"
|
||||
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):
|
||||
|
|
@ -316,7 +306,29 @@ def find_exe(check_exe):
|
|||
if is_exe(exe):
|
||||
return exe
|
||||
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
|
||||
def import_tech():
|
||||
global OPTS
|
||||
|
|
|
|||
|
|
@ -20,22 +20,20 @@ class bank(design.design):
|
|||
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=""):
|
||||
|
||||
if name == "":
|
||||
name = "bank_{0}_{1}".format(word_size, num_words)
|
||||
design.design.__init__(self, name)
|
||||
debug.info(2, "create sram of size {0} with {1} words".format(word_size,num_words))
|
||||
|
||||
self.word_size = word_size
|
||||
self.num_words = num_words
|
||||
self.words_per_row = words_per_row
|
||||
self.num_banks = num_banks
|
||||
sram_config.set_local_config(self)
|
||||
|
||||
self.total_write = OPTS.rw_ports + OPTS.w_ports
|
||||
self.total_read = OPTS.rw_ports + OPTS.r_ports
|
||||
self.total_ports = OPTS.rw_ports + OPTS.w_ports + OPTS.r_ports
|
||||
if name == "":
|
||||
name = "bank_{0}_{1}".format(self.word_size, self.num_words)
|
||||
design.design.__init__(self, name)
|
||||
debug.info(2, "create sram of size {0} with {1} words".format(self.word_size,self.num_words))
|
||||
|
||||
|
||||
self.total_write = OPTS.num_rw_ports + OPTS.num_w_ports
|
||||
self.total_read = OPTS.num_rw_ports + OPTS.num_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,
|
||||
# so this prefix will be added to all of the input signals to create
|
||||
# the internal gated signals.
|
||||
|
|
@ -70,24 +68,25 @@ class bank(design.design):
|
|||
|
||||
def add_pins(self):
|
||||
""" Adding pins for Bank module"""
|
||||
for k in range(self.total_read):
|
||||
for i in range(self.word_size):
|
||||
self.add_pin("dout{0}[{1}]".format(k,i),"OUT")
|
||||
for k in range(self.total_write):
|
||||
for i in range(self.word_size):
|
||||
self.add_pin("din{0}[{1}]".format(k,i),"IN")
|
||||
for k in range(self.total_ports):
|
||||
for i in range(self.addr_size):
|
||||
self.add_pin("addr{0}[{1}]".format(k,i),"INPUT")
|
||||
for port in range(self.total_read):
|
||||
for bit in range(self.word_size):
|
||||
self.add_pin("dout{0}[{1}]".format(port,bit),"OUT")
|
||||
for port in range(self.total_write):
|
||||
for bit in range(self.word_size):
|
||||
self.add_pin("din{0}[{1}]".format(port,bit),"IN")
|
||||
for port in range(self.total_ports):
|
||||
for bit in range(self.addr_size):
|
||||
self.add_pin("addr{0}[{1}]".format(port,bit),"INPUT")
|
||||
|
||||
# For more than one bank, we have a bank select and name
|
||||
# the signals gated_*.
|
||||
if self.num_banks > 1:
|
||||
self.add_pin("bank_sel","INPUT")
|
||||
for k in range(self.total_read):
|
||||
self.add_pin("s_en{0}".format(k), "INPUT")
|
||||
for k in range(self.total_write):
|
||||
self.add_pin("w_en{0}".format(k), "INPUT")
|
||||
for port in range(self.total_ports):
|
||||
self.add_pin("bank_sel{}".format(port),"INPUT")
|
||||
for port in range(self.total_read):
|
||||
self.add_pin("s_en{0}".format(port), "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"]:
|
||||
self.add_pin(pin,"INPUT")
|
||||
self.add_pin("vdd","POWER")
|
||||
|
|
@ -228,9 +227,9 @@ class bank(design.design):
|
|||
self.total_bitline_list = self.bitcell.list_all_bitline_names()
|
||||
|
||||
self.precharge_array = []
|
||||
for k 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.add_mod(self.precharge_array[k])
|
||||
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[port], bitcell_br=self.read_br_list[port]))
|
||||
self.add_mod(self.precharge_array[port])
|
||||
|
||||
if self.col_addr_size > 0:
|
||||
self.column_mux_array = self.mod_column_mux_array(columns=self.num_cols,
|
||||
|
|
@ -287,13 +286,13 @@ class bank(design.design):
|
|||
""" Creating Precharge """
|
||||
|
||||
self.precharge_array_inst = []
|
||||
for k in range(self.total_read):
|
||||
self.precharge_array_inst.append(self.add_inst(name="precharge_array{}".format(k),
|
||||
mod=self.precharge_array[k]))
|
||||
for port in range(self.total_read):
|
||||
self.precharge_array_inst.append(self.add_inst(name="precharge_array{}".format(port),
|
||||
mod=self.precharge_array[port]))
|
||||
temp = []
|
||||
for i in range(self.num_cols):
|
||||
temp.append(self.read_bl_list[k]+"[{0}]".format(i))
|
||||
temp.append(self.read_br_list[k]+"[{0}]".format(i))
|
||||
temp.append(self.read_bl_list[port]+"[{0}]".format(i))
|
||||
temp.append(self.read_br_list[port]+"[{0}]".format(i))
|
||||
temp.extend([self.prefix+"clk_buf_bar", "vdd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
|
@ -301,11 +300,11 @@ class bank(design.design):
|
|||
""" Placing Precharge """
|
||||
|
||||
# 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 enclosure is for the well and the spacing is to the bitcell wells
|
||||
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):
|
||||
""" Creating Column Mux when words_per_row > 1 . """
|
||||
|
|
@ -313,19 +312,19 @@ class bank(design.design):
|
|||
return
|
||||
|
||||
self.col_mux_array_inst = []
|
||||
for k in range(self.total_ports):
|
||||
self.col_mux_array_inst.append(self.add_inst(name="column_mux_array{}".format(k),
|
||||
for port in range(self.total_ports):
|
||||
self.col_mux_array_inst.append(self.add_inst(name="column_mux_array{}".format(port),
|
||||
mod=self.column_mux_array))
|
||||
|
||||
temp = []
|
||||
for i in range(self.num_cols):
|
||||
temp.append(self.total_bl_list[k]+"[{0}]".format(i))
|
||||
temp.append(self.total_br_list[k]+"[{0}]".format(i))
|
||||
for h in range(self.words_per_row):
|
||||
temp.append("sel{0}[{1}]".format(k,h))
|
||||
for j in range(self.word_size):
|
||||
temp.append(self.total_bl_list[k]+"_out[{0}]".format(j))
|
||||
temp.append(self.total_br_list[k]+"_out[{0}]".format(j))
|
||||
for col in range(self.num_cols):
|
||||
temp.append(self.total_bl_list[port]+"[{0}]".format(col))
|
||||
temp.append(self.total_br_list[port]+"[{0}]".format(col))
|
||||
for word in range(self.words_per_row):
|
||||
temp.append("sel{0}[{1}]".format(port,word))
|
||||
for bit in range(self.word_size):
|
||||
temp.append(self.total_bl_list[port]+"_out[{0}]".format(bit))
|
||||
temp.append(self.total_br_list[port]+"_out[{0}]".format(bit))
|
||||
temp.append("gnd")
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
|
@ -337,68 +336,68 @@ class bank(design.design):
|
|||
self.column_mux_height = 0
|
||||
return
|
||||
|
||||
for k in range(self.total_ports):
|
||||
for port in range(self.total_ports):
|
||||
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):
|
||||
""" Creating Sense amp """
|
||||
|
||||
self.sense_amp_array_inst = []
|
||||
for k in range(self.total_read):
|
||||
self.sense_amp_array_inst.append(self.add_inst(name="sense_amp_array{}".format(k),
|
||||
for port in range(self.total_read):
|
||||
self.sense_amp_array_inst.append(self.add_inst(name="sense_amp_array{}".format(port),
|
||||
mod=self.sense_amp_array))
|
||||
|
||||
temp = []
|
||||
for i in range(self.word_size):
|
||||
temp.append("dout{0}[{1}]".format(k,i))
|
||||
for bit in range(self.word_size):
|
||||
temp.append("dout{0}[{1}]".format(port,bit))
|
||||
if self.words_per_row == 1:
|
||||
temp.append(self.read_bl_list[k]+"[{0}]".format(i))
|
||||
temp.append(self.read_br_list[k]+"[{0}]".format(i))
|
||||
temp.append(self.read_bl_list[port]+"[{0}]".format(bit))
|
||||
temp.append(self.read_br_list[port]+"[{0}]".format(bit))
|
||||
else:
|
||||
temp.append(self.read_bl_list[k]+"_out[{0}]".format(i))
|
||||
temp.append(self.read_br_list[k]+"_out[{0}]".format(i))
|
||||
temp.append(self.read_bl_list[port]+"_out[{0}]".format(bit))
|
||||
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)
|
||||
|
||||
def place_sense_amp_array(self):
|
||||
""" Placing Sense amp """
|
||||
|
||||
# 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
|
||||
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):
|
||||
""" Creating Write Driver """
|
||||
|
||||
self.write_driver_array_inst = []
|
||||
for k in range(self.total_write):
|
||||
self.write_driver_array_inst.append(self.add_inst(name="write_driver_array{}".format(k),
|
||||
for port in range(self.total_write):
|
||||
self.write_driver_array_inst.append(self.add_inst(name="write_driver_array{}".format(port),
|
||||
mod=self.write_driver_array))
|
||||
|
||||
temp = []
|
||||
for i in range(self.word_size):
|
||||
temp.append("din{0}[{1}]".format(k,i))
|
||||
for i in range(self.word_size):
|
||||
for bit in range(self.word_size):
|
||||
temp.append("din{0}[{1}]".format(port,bit))
|
||||
for bit in range(self.word_size):
|
||||
if (self.words_per_row == 1):
|
||||
temp.append(self.write_bl_list[k]+"[{0}]".format(i))
|
||||
temp.append(self.write_br_list[k]+"[{0}]".format(i))
|
||||
temp.append(self.write_bl_list[port]+"[{0}]".format(bit))
|
||||
temp.append(self.write_br_list[port]+"[{0}]".format(bit))
|
||||
else:
|
||||
temp.append(self.write_bl_list[k]+"_out[{0}]".format(i))
|
||||
temp.append(self.write_br_list[k]+"_out[{0}]".format(i))
|
||||
temp.extend([self.prefix+"w_en{0}".format(k), "vdd", "gnd"])
|
||||
temp.append(self.write_bl_list[port]+"_out[{0}]".format(bit))
|
||||
temp.append(self.write_br_list[port]+"_out[{0}]".format(bit))
|
||||
temp.extend([self.prefix+"w_en{0}".format(port), "vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
def place_write_driver_array(self):
|
||||
""" Placing Write Driver """
|
||||
|
||||
# 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 \
|
||||
+ 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 """
|
||||
|
||||
self.row_decoder_inst = []
|
||||
for k in range(self.total_ports):
|
||||
self.row_decoder_inst.append(self.add_inst(name="row_decoder{}".format(k),
|
||||
for port in range(self.total_ports):
|
||||
self.row_decoder_inst.append(self.add_inst(name="row_decoder{}".format(port),
|
||||
mod=self.row_decoder))
|
||||
|
||||
temp = []
|
||||
for i in range(self.row_addr_size):
|
||||
temp.append("addr{0}[{1}]".format(k,i+self.col_addr_size))
|
||||
for j in range(self.num_rows):
|
||||
temp.append("dec_out{0}[{1}]".format(k,j))
|
||||
for bit in range(self.row_addr_size):
|
||||
temp.append("addr{0}[{1}]".format(port,bit+self.col_addr_size))
|
||||
for row in range(self.num_rows):
|
||||
temp.append("dec_out{0}[{1}]".format(port,row))
|
||||
temp.extend(["vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
|
@ -428,24 +427,24 @@ class bank(design.design):
|
|||
# The address flop and decoder are aligned in the x coord.
|
||||
|
||||
# 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)
|
||||
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):
|
||||
""" Create the Wordline Driver """
|
||||
|
||||
self.wordline_driver_inst = []
|
||||
for k in range(self.total_ports):
|
||||
self.wordline_driver_inst.append(self.add_inst(name="wordline_driver{}".format(k),
|
||||
for port in range(self.total_ports):
|
||||
self.wordline_driver_inst.append(self.add_inst(name="wordline_driver{}".format(port),
|
||||
mod=self.wordline_driver))
|
||||
|
||||
temp = []
|
||||
for i in range(self.num_rows):
|
||||
temp.append("dec_out{0}[{1}]".format(k,i))
|
||||
for i in range(self.num_rows):
|
||||
temp.append(self.total_wl_list[k]+"[{0}]".format(i))
|
||||
for row in range(self.num_rows):
|
||||
temp.append("dec_out{0}[{1}]".format(port,row))
|
||||
for row in range(self.num_rows):
|
||||
temp.append(self.total_wl_list[port]+"[{0}]".format(row))
|
||||
temp.append(self.prefix+"clk_buf")
|
||||
temp.append("vdd")
|
||||
temp.append("gnd")
|
||||
|
|
@ -455,10 +454,10 @@ class bank(design.design):
|
|||
""" Place the Wordline Driver """
|
||||
|
||||
# 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.
|
||||
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):
|
||||
|
|
@ -480,15 +479,15 @@ class bank(design.design):
|
|||
debug.error("Invalid column decoder?",-1)
|
||||
|
||||
self.col_decoder_inst = []
|
||||
for k in range(self.total_ports):
|
||||
self.col_decoder_inst.append(self.add_inst(name="col_address_decoder{}".format(k),
|
||||
for port in range(self.total_ports):
|
||||
self.col_decoder_inst.append(self.add_inst(name="col_address_decoder{}".format(port),
|
||||
mod=self.col_decoder))
|
||||
|
||||
temp = []
|
||||
for i in range(self.col_addr_size):
|
||||
temp.append("addr{0}[{1}]".format(k,i))
|
||||
for j in range(self.num_col_addr_lines):
|
||||
temp.append("sel{0}[{1}]".format(k,j))
|
||||
for bit in range(self.col_addr_size):
|
||||
temp.append("addr{0}[{1}]".format(port,bit))
|
||||
for bit in range(self.num_col_addr_lines):
|
||||
temp.append("sel{0}[{1}]".format(port,bit))
|
||||
temp.extend(["vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
|
@ -500,11 +499,11 @@ class bank(design.design):
|
|||
return
|
||||
|
||||
# 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
|
||||
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"])
|
||||
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):
|
||||
|
|
@ -514,13 +513,13 @@ class bank(design.design):
|
|||
return
|
||||
|
||||
self.bank_select_inst = []
|
||||
for k in range(self.total_ports):
|
||||
self.bank_select_inst.append(self.add_inst(name="bank_select",
|
||||
for port in range(self.total_ports):
|
||||
self.bank_select_inst.append(self.add_inst(name="bank_select{}".format(port),
|
||||
mod=self.bank_select))
|
||||
|
||||
temp = []
|
||||
temp.extend(self.input_control_signals)
|
||||
temp.append("bank_sel")
|
||||
temp.append("bank_sel{}".format(port))
|
||||
temp.extend(self.control_signals)
|
||||
temp.extend(["vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
|
@ -532,7 +531,7 @@ class bank(design.design):
|
|||
return
|
||||
|
||||
# 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)
|
||||
if self.col_addr_size > 0:
|
||||
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.bank_select.height + drc["well_to_well"])
|
||||
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):
|
||||
|
|
@ -549,19 +548,19 @@ class bank(design.design):
|
|||
# These are the instances that every bank has
|
||||
top_instances = [self.bitcell_array_inst]
|
||||
|
||||
for k in range(self.total_ports):
|
||||
top_instances.extend([self.precharge_array_inst[k],
|
||||
self.sense_amp_array_inst[k],
|
||||
self.write_driver_array_inst[k],
|
||||
self.row_decoder_inst[k],
|
||||
self.wordline_driver_inst[k]])
|
||||
for port in range(self.total_ports):
|
||||
top_instances.extend([self.precharge_array_inst[port],
|
||||
self.sense_amp_array_inst[port],
|
||||
self.write_driver_array_inst[port],
|
||||
self.row_decoder_inst[port],
|
||||
self.wordline_driver_inst[port]])
|
||||
# Add these if we use the part...
|
||||
if self.col_addr_size > 0:
|
||||
top_instances.append(self.col_decoder_inst[k])
|
||||
top_instances.append(self.col_mux_array_inst[k])
|
||||
top_instances.append(self.col_decoder_inst[port])
|
||||
top_instances.append(self.col_mux_array_inst[port])
|
||||
|
||||
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:
|
||||
|
|
@ -575,13 +574,13 @@ class bank(design.design):
|
|||
def route_bank_select(self):
|
||||
""" 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"]:
|
||||
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:
|
||||
# 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)
|
||||
self.add_path("metal3",[out_pos, bus_pos])
|
||||
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 """
|
||||
|
||||
# FIXME: Update for multiport
|
||||
for k in range(self.total_read):
|
||||
for i in range(self.num_cols):
|
||||
precharge_bl = self.precharge_array_inst[k].get_pin("bl[{}]".format(i)).bc()
|
||||
precharge_br = self.precharge_array_inst[k].get_pin("br[{}]".format(i)).bc()
|
||||
bitcell_bl = self.bitcell_array_inst.get_pin(self.read_bl_list[k]+"[{}]".format(i)).uc()
|
||||
bitcell_br = self.bitcell_array_inst.get_pin(self.read_br_list[k]+"[{}]".format(i)).uc()
|
||||
for port in range(self.total_read):
|
||||
for col in range(self.num_cols):
|
||||
precharge_bl = self.precharge_array_inst[port].get_pin("bl[{}]".format(col)).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[port]+"[{}]".format(col)).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)
|
||||
self.add_path("metal2",[precharge_bl, vector(precharge_bl.x,yoffset),
|
||||
|
|
@ -681,12 +680,12 @@ class bank(design.design):
|
|||
return
|
||||
|
||||
# FIXME: Update for multiport
|
||||
for k in range(self.total_ports):
|
||||
for i in range(self.num_cols):
|
||||
col_mux_bl = self.col_mux_array_inst[k].get_pin("bl[{}]".format(i)).uc()
|
||||
col_mux_br = self.col_mux_array_inst[k].get_pin("br[{}]".format(i)).uc()
|
||||
bitcell_bl = self.bitcell_array_inst.get_pin(self.total_bl_list[k]+"[{}]".format(i)).bc()
|
||||
bitcell_br = self.bitcell_array_inst.get_pin(self.total_br_list[k]+"[{}]".format(i)).bc()
|
||||
for port in range(self.total_ports):
|
||||
for col in range(self.num_cols):
|
||||
col_mux_bl = self.col_mux_array_inst[port].get_pin("bl[{}]".format(col)).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[port]+"[{}]".format(col)).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)
|
||||
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):
|
||||
""" Routing of BL and BR between sense_amp and column mux or bitcell array """
|
||||
|
||||
for k in range(self.total_read):
|
||||
for i in range(self.word_size):
|
||||
sense_amp_bl = self.sense_amp_array_inst[k].get_pin("bl[{}]".format(i)).uc()
|
||||
sense_amp_br = self.sense_amp_array_inst[k].get_pin("br[{}]".format(i)).uc()
|
||||
for port in range(self.total_read):
|
||||
for bit in range(self.word_size):
|
||||
sense_amp_bl = self.sense_amp_array_inst[port].get_pin("bl[{}]".format(bit)).uc()
|
||||
sense_amp_br = self.sense_amp_array_inst[port].get_pin("br[{}]".format(bit)).uc()
|
||||
|
||||
if self.col_addr_size>0:
|
||||
# Sense amp is connected to the col mux
|
||||
connect_bl = self.col_mux_array_inst[k].get_pin("bl_out[{}]".format(i)).bc()
|
||||
connect_br = self.col_mux_array_inst[k].get_pin("br_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[port].get_pin("br_out[{}]".format(bit)).bc()
|
||||
else:
|
||||
# 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_br = self.bitcell_array_inst.get_pin(self.read_br_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[port]+"[{}]".format(bit)).bc()
|
||||
|
||||
|
||||
yoffset = 0.5*(sense_amp_bl.y+connect_bl.y)
|
||||
|
|
@ -721,9 +720,11 @@ class bank(design.design):
|
|||
|
||||
def route_sense_amp_out(self):
|
||||
""" 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))
|
||||
self.add_layout_pin_rect_center(text="dout0[{}]".format(i),
|
||||
|
||||
# FIXME: Update for multiport
|
||||
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,
|
||||
offset=data_pin.center(),
|
||||
height=data_pin.height(),
|
||||
|
|
@ -733,10 +734,11 @@ class bank(design.design):
|
|||
def route_row_decoder(self):
|
||||
""" Routes the row decoder inputs and supplies """
|
||||
|
||||
# FIXME: Update for multiport
|
||||
# Create inputs for the row address lines
|
||||
for i in range(self.row_addr_size):
|
||||
addr_idx = i + self.col_addr_size
|
||||
decoder_name = "addr[{}]".format(i)
|
||||
for row in range(self.row_addr_size):
|
||||
addr_idx = row + self.col_addr_size
|
||||
decoder_name = "addr[{}]".format(row)
|
||||
addr_name = "addr0[{}]".format(addr_idx)
|
||||
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):
|
||||
""" Connecting write driver """
|
||||
|
||||
for i in range(self.word_size):
|
||||
data_name = "data[{}]".format(i)
|
||||
din_name = "din0[{}]".format(i)
|
||||
for row in range(self.word_size):
|
||||
data_name = "data[{}]".format(row)
|
||||
din_name = "din0[{}]".format(row)
|
||||
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):
|
||||
""" 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
|
||||
decoder_out_pos = self.row_decoder_inst[0].get_pin("decode[{}]".format(i)).rc()
|
||||
driver_in_pos = self.wordline_driver_inst[0].get_pin("in[{}]".format(i)).lc()
|
||||
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(row)).lc()
|
||||
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)
|
||||
self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos])
|
||||
|
||||
# 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()
|
||||
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_list[0]+"[{}]".format(i)).lc()
|
||||
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(row)).lc()
|
||||
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)
|
||||
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
|
||||
|
|
|
|||
|
|
@ -53,11 +53,6 @@ class delay_chain(design.design):
|
|||
self.add_pin("gnd")
|
||||
|
||||
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.add_mod(self.inv)
|
||||
|
||||
|
|
|
|||
|
|
@ -115,11 +115,11 @@ class dff_inv_array(design.design):
|
|||
def add_layout_pins(self):
|
||||
for row in range(self.rows):
|
||||
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")
|
||||
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")
|
||||
self.add_power_pin("gnd", gnd_pin.lc())
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@ class hierarchical_decoder(design.design):
|
|||
from importlib import reload
|
||||
c = reload(__import__(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.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
|
||||
else:
|
||||
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,
|
||||
if self.no_of_pre3x8 > 0:
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ class replica_bitcell(design.design):
|
|||
is a hand-made cell, so the layout and netlist should be available in
|
||||
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"])
|
||||
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_6t", GDS["unit"], layer["boundary"])
|
||||
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ class replica_bitline(design.design):
|
|||
|
||||
# 3. Route the contact of previous route to the 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)
|
||||
wl_mid1 = vector(xmid_point,contact_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)
|
||||
# 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
|
||||
bl_down_offset = bl_offset - vector(0, self.m2_pitch)
|
||||
self.add_path("metal2",[source_offset, bl_down_offset, bl_offset])
|
||||
|
|
|
|||
|
|
@ -30,7 +30,11 @@ class sense_amp_array(design.design):
|
|||
|
||||
def create_layout(self):
|
||||
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.add_layout_pins()
|
||||
|
|
@ -53,6 +57,11 @@ class sense_amp_array(design.design):
|
|||
self.amp = self.mod_sense_amp("sense_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):
|
||||
self.local_insts = []
|
||||
|
|
@ -68,7 +77,10 @@ class sense_amp_array(design.design):
|
|||
|
||||
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):
|
||||
amp_position = vector(amp_spacing * i, 0)
|
||||
self.local_insts[i].place(amp_position)
|
||||
|
|
|
|||
|
|
@ -50,6 +50,13 @@ class wordline_driver(design.design):
|
|||
|
||||
|
||||
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.add_mod(self.inv)
|
||||
|
||||
|
|
@ -58,6 +65,7 @@ class wordline_driver(design.design):
|
|||
|
||||
self.nand2 = pnand2()
|
||||
self.add_mod(self.nand2)
|
||||
|
||||
|
||||
def route_vdd_gnd(self):
|
||||
""" 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
|
||||
inv2_xoffset = nand2_xoffset + self.nand2.width
|
||||
|
||||
self.width = inv2_xoffset + self.inv.width
|
||||
self.height = self.inv.height * self.rows
|
||||
|
||||
self.width = inv2_xoffset + self.inv.height
|
||||
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):
|
||||
if (row % 2):
|
||||
y_offset = self.inv.height*(row + 1)
|
||||
y_offset = driver_height*(row + 1)
|
||||
inst_mirror = "MX"
|
||||
else:
|
||||
y_offset = self.inv.height*row
|
||||
y_offset = driver_height*row
|
||||
inst_mirror = "R0"
|
||||
|
||||
inv1_offset = [inv1_xoffset, y_offset]
|
||||
|
|
|
|||
|
|
@ -30,7 +30,12 @@ class write_driver_array(design.design):
|
|||
self.create_write_array()
|
||||
|
||||
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.place_write_array()
|
||||
|
|
@ -54,6 +59,12 @@ class write_driver_array(design.design):
|
|||
self.driver = self.mod_write_driver("write_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):
|
||||
self.driver_insts = {}
|
||||
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):
|
||||
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):
|
||||
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)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ report_status()
|
|||
|
||||
# Start importing design modules after we have the config file
|
||||
import verify
|
||||
import sram
|
||||
from sram import sram
|
||||
from sram_config import sram_config
|
||||
|
||||
output_extensions = ["sp","v","lib"]
|
||||
if not OPTS.netlist_only:
|
||||
|
|
@ -51,11 +52,13 @@ print(*output_files,sep="\n")
|
|||
start_time = datetime.datetime.now()
|
||||
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
|
||||
s = sram.sram(word_size=OPTS.word_size,
|
||||
num_words=OPTS.num_words,
|
||||
num_banks=OPTS.num_banks,
|
||||
name=OPTS.output_name)
|
||||
s = sram(sram_config=c,
|
||||
name=OPTS.output_name)
|
||||
|
||||
# Output the files for the resulting SRAM
|
||||
s.save()
|
||||
|
|
|
|||
|
|
@ -52,14 +52,20 @@ class options(optparse.Values):
|
|||
purge_temp = True
|
||||
|
||||
# These are the configuration parameters
|
||||
rw_ports = 1
|
||||
r_ports = 0
|
||||
w_ports = 0
|
||||
num_rw_ports = 1
|
||||
num_r_ports = 0
|
||||
num_w_ports = 0
|
||||
|
||||
# These will get initialized by the the file
|
||||
supply_voltages = ""
|
||||
temperatures = ""
|
||||
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
|
||||
decoder = "hierarchical_decoder"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import contact
|
||||
import pgate
|
||||
import design
|
||||
import debug
|
||||
from tech import drc, parameter, spice
|
||||
|
|
@ -7,47 +6,41 @@ from vector import vector
|
|||
from ptx import ptx
|
||||
from globals import OPTS
|
||||
|
||||
class pbitcell(pgate.pgate):
|
||||
class pbitcell(design.design):
|
||||
"""
|
||||
This module implements a parametrically sized multi-port bitcell,
|
||||
with a variable number of read/write, write, and read ports
|
||||
"""
|
||||
|
||||
width = None
|
||||
height = None
|
||||
|
||||
unique_id = 1
|
||||
|
||||
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_{3}".format(num_readwrite, num_write, num_read, pbitcell.unique_id)
|
||||
pbitcell.unique_id += 1
|
||||
pgate.pgate.__init__(self, name)
|
||||
debug.info(2, "create a multi-port bitcell with {0} write ports and {1} read ports".format(num_write, num_read))
|
||||
def __init__(self):
|
||||
|
||||
self.num_readwrite = num_readwrite
|
||||
self.num_write = num_write
|
||||
self.num_read = num_read
|
||||
self.num_rw_ports = OPTS.num_rw_ports
|
||||
self.num_w_ports = OPTS.num_w_ports
|
||||
self.num_r_ports = OPTS.num_r_ports
|
||||
|
||||
name = "pbitcell_{0}RW_{1}W_{2}R".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports)
|
||||
# This is not a pgate because pgates depend on the bitcell height!
|
||||
design.design.__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,
|
||||
self.num_w_ports,
|
||||
self.num_r_ports))
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
# We must always create the bitcell layout because
|
||||
# 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):
|
||||
self.add_pins()
|
||||
self.add_modules()
|
||||
self.create_storage()
|
||||
|
||||
if(self.num_readwrite > 0):
|
||||
if(self.num_rw_ports > 0):
|
||||
self.create_readwrite_ports()
|
||||
if(self.num_write > 0):
|
||||
if(self.num_w_ports > 0):
|
||||
self.create_write_ports()
|
||||
if(self.num_read > 0):
|
||||
if(self.num_r_ports > 0):
|
||||
self.create_read_ports()
|
||||
|
||||
def create_layout(self):
|
||||
|
|
@ -58,11 +51,11 @@ class pbitcell(pgate.pgate):
|
|||
self.route_storage()
|
||||
self.route_rails()
|
||||
|
||||
if(self.num_readwrite > 0):
|
||||
if(self.num_rw_ports > 0):
|
||||
self.place_readwrite_ports()
|
||||
if(self.num_write > 0):
|
||||
if(self.num_w_ports > 0):
|
||||
self.place_write_ports()
|
||||
if(self.num_read > 0):
|
||||
if(self.num_r_ports > 0):
|
||||
self.place_read_ports()
|
||||
self.extend_well()
|
||||
|
||||
|
|
@ -70,31 +63,30 @@ class pbitcell(pgate.pgate):
|
|||
self.DRC_LVS()
|
||||
|
||||
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_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_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_bar{}".format(k))
|
||||
|
||||
for k in range(self.num_readwrite):
|
||||
for k in range(self.num_rw_ports):
|
||||
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))
|
||||
for k in range(self.num_read):
|
||||
for k in range(self.num_r_ports):
|
||||
self.add_pin("rwl{}".format(k))
|
||||
|
||||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
|
||||
def add_modules(self):
|
||||
# if there are any read/write ports, then the inverter nmos is sized based the number of them
|
||||
if(self.num_readwrite > 0):
|
||||
inverter_nmos_width = self.num_readwrite*3*parameter["min_tx_size"]
|
||||
if(self.num_rw_ports > 0):
|
||||
inverter_nmos_width = self.num_rw_ports*3*parameter["min_tx_size"]
|
||||
inverter_pmos_width = parameter["min_tx_size"]
|
||||
readwrite_nmos_width = 1.5*parameter["min_tx_size"]
|
||||
write_nmos_width = parameter["min_tx_size"]
|
||||
|
|
@ -133,7 +125,6 @@ class pbitcell(pgate.pgate):
|
|||
tx_type="nmos")
|
||||
self.add_mod(self.read_nmos)
|
||||
|
||||
|
||||
def calculate_spacing(self):
|
||||
""" Calculate transistor spacings """
|
||||
|
||||
|
|
@ -153,15 +144,15 @@ class pbitcell(pgate.pgate):
|
|||
|
||||
# readwrite to readwrite transistor spacing (also acts as readwrite to write transistor spacing)
|
||||
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:
|
||||
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
|
||||
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:
|
||||
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
|
||||
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)
|
||||
# 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):
|
||||
write_portion = drc["minwidth_metal2"] + self.write_nmos_contact_extension
|
||||
else:
|
||||
|
|
@ -187,7 +178,7 @@ class pbitcell(pgate.pgate):
|
|||
else:
|
||||
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) """
|
||||
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
|
||||
|
||||
""" 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
|
||||
|
||||
""" 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_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):
|
||||
|
|
@ -210,23 +201,23 @@ class pbitcell(pgate.pgate):
|
|||
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
|
||||
if(self.num_readwrite > 0):
|
||||
if(self.num_rw_ports > 0):
|
||||
self.readwrite_port_flag = True
|
||||
else:
|
||||
self.readwrite_port_flag = False
|
||||
|
||||
if(self.num_write > 0):
|
||||
if(self.num_w_ports > 0):
|
||||
self.write_port_flag = True
|
||||
else:
|
||||
self.write_port_flag = False
|
||||
|
||||
if(self.num_read > 0):
|
||||
if(self.num_r_ports > 0):
|
||||
self.read_port_flag = True
|
||||
else:
|
||||
self.read_port_flag = False
|
||||
|
||||
# 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):
|
||||
end_connection = drc["minwidth_metal2"] + self.read_nmos_contact_extension + contact.m1m2.height
|
||||
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
|
||||
self.leftmost_xpos = -self.inverter_tile_width \
|
||||
- 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.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.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 \
|
||||
- 0.5*drc["minwidth_metal2"]
|
||||
- 0.5*drc["poly_to_polycontact"]
|
||||
|
||||
self.rightmost_xpos = -self.leftmost_xpos
|
||||
|
||||
# bottommost position = gnd height + rwwl height + wwl height + rwl height + space needed between tiled bitcells
|
||||
array_tiling_offset = 0.5*drc["minwidth_metal2"]
|
||||
self.botmost_ypos = -self.rail_tile_height \
|
||||
- self.num_readwrite*self.rowline_tile_height \
|
||||
- self.num_write*self.rowline_tile_height \
|
||||
- self.num_read*self.rowline_tile_height \
|
||||
- self.num_rw_ports*self.rowline_tile_height \
|
||||
- self.num_w_ports*self.rowline_tile_height \
|
||||
- self.num_r_ports*self.rowline_tile_height \
|
||||
- array_tiling_offset
|
||||
|
||||
# topmost position = height of the inverter + height of vdd
|
||||
|
|
@ -263,10 +254,35 @@ class pbitcell(pgate.pgate):
|
|||
+ self.rail_tile_height
|
||||
|
||||
# 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.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):
|
||||
"""
|
||||
|
|
@ -318,31 +334,6 @@ class pbitcell(pgate.pgate):
|
|||
# update furthest left and right transistor edges (this will propagate to further transistor offset calculations)
|
||||
self.left_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):
|
||||
|
|
@ -394,11 +385,11 @@ class pbitcell(pgate.pgate):
|
|||
"""
|
||||
|
||||
# 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_right = [None] * self.num_readwrite
|
||||
self.readwrite_nmos_left = [None] * self.num_rw_ports
|
||||
self.readwrite_nmos_right = [None] * self.num_rw_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
|
||||
self.readwrite_nmos_left[k] = self.add_inst(name="readwrite_nmos_left{}".format(k),
|
||||
mod=self.readwrite_nmos)
|
||||
|
|
@ -415,15 +406,15 @@ class pbitcell(pgate.pgate):
|
|||
"""
|
||||
|
||||
# Define variables relevant to write transistors
|
||||
self.rwwl_positions = [None] * self.num_readwrite
|
||||
self.rwbl_positions = [None] * self.num_readwrite
|
||||
self.rwbl_bar_positions = [None] * self.num_readwrite
|
||||
self.rwwl_positions = [None] * self.num_rw_ports
|
||||
self.rwbl_positions = [None] * self.num_rw_ports
|
||||
self.rwbl_bar_positions = [None] * self.num_rw_ports
|
||||
|
||||
# define offset correction due to rotation of the ptx module
|
||||
readwrite_rotation_correct = self.readwrite_nmos.active_height
|
||||
|
||||
# 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
|
||||
# calculate read/write transistor offsets
|
||||
left_readwrite_transistor_xpos = self.left_building_edge \
|
||||
|
|
@ -533,14 +524,14 @@ class pbitcell(pgate.pgate):
|
|||
|
||||
# Drain/Storage connections
|
||||
# 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
|
||||
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"),
|
||||
offset=left_storage_contact,
|
||||
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"),
|
||||
offset=right_storage_contact,
|
||||
rotate=90)
|
||||
|
|
@ -584,11 +575,11 @@ class pbitcell(pgate.pgate):
|
|||
write_rotation_correct = self.write_nmos.active_height
|
||||
|
||||
# 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_right = [None] * self.num_write
|
||||
self.write_nmos_left = [None] * self.num_w_ports
|
||||
self.write_nmos_right = [None] * self.num_w_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
|
||||
self.write_nmos_left[k] = self.add_inst(name="write_nmos_left{}".format(k),
|
||||
mod=self.write_nmos)
|
||||
|
|
@ -605,15 +596,15 @@ class pbitcell(pgate.pgate):
|
|||
"""
|
||||
|
||||
# Define variables relevant to write transistors
|
||||
self.wwl_positions = [None] * self.num_write
|
||||
self.wbl_positions = [None] * self.num_write
|
||||
self.wbl_bar_positions = [None] * self.num_write
|
||||
self.wwl_positions = [None] * self.num_w_ports
|
||||
self.wbl_positions = [None] * self.num_w_ports
|
||||
self.wbl_bar_positions = [None] * self.num_w_ports
|
||||
|
||||
# define offset correction due to rotation of the ptx module
|
||||
write_rotation_correct = self.write_nmos.active_height
|
||||
|
||||
# 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
|
||||
# calculate write transistor offsets
|
||||
left_write_transistor_xpos = self.left_building_edge \
|
||||
|
|
@ -638,7 +629,7 @@ class pbitcell(pgate.pgate):
|
|||
# Add WWL lines
|
||||
# calculate WWL position
|
||||
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
|
||||
self.wwl_positions[k] = vector(self.leftmost_xpos, wwl_ypos)
|
||||
|
||||
|
|
@ -727,14 +718,14 @@ class pbitcell(pgate.pgate):
|
|||
|
||||
# Drain/Storage connections
|
||||
# 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
|
||||
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"),
|
||||
offset=left_storage_contact,
|
||||
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"),
|
||||
offset=right_storage_contact,
|
||||
rotate=90)
|
||||
|
|
@ -775,13 +766,13 @@ class pbitcell(pgate.pgate):
|
|||
"""
|
||||
|
||||
# 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.read_nmos_left = [None] * self.num_r_ports
|
||||
self.read_nmos_right = [None] * self.num_r_ports
|
||||
self.read_access_nmos_left = [None] * self.num_r_ports
|
||||
self.read_access_nmos_right = [None] * self.num_r_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
|
||||
self.read_access_nmos_left[k] = self.add_inst(name="read_access_nmos_left{}".format(k),
|
||||
mod=self.read_nmos)
|
||||
|
|
@ -806,9 +797,9 @@ class pbitcell(pgate.pgate):
|
|||
"""
|
||||
|
||||
# Define variables relevant to read transistors
|
||||
self.rwl_positions = [None] * self.num_read
|
||||
self.rbl_positions = [None] * self.num_read
|
||||
self.rbl_bar_positions = [None] * self.num_read
|
||||
self.rwl_positions = [None] * self.num_r_ports
|
||||
self.rbl_positions = [None] * self.num_r_ports
|
||||
self.rbl_bar_positions = [None] * self.num_r_ports
|
||||
|
||||
# define offset correction due to rotation of the ptx module
|
||||
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
|
||||
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
|
||||
for k in range(0,self.num_read):
|
||||
for k in range(0,self.num_r_ports):
|
||||
# Add transistors
|
||||
# calculate transistor offsets
|
||||
left_read_transistor_xpos = self.left_building_edge \
|
||||
|
|
@ -840,36 +822,24 @@ class pbitcell(pgate.pgate):
|
|||
+ read_rotation_correct
|
||||
|
||||
# add read-access transistors
|
||||
self.read_access_nmos_left[k] = self.add_inst(name="read_access_nmos_left{}".format(k),
|
||||
mod=self.read_nmos,
|
||||
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_left[k].place(offset=[left_read_transistor_xpos,0],
|
||||
rotate=90)
|
||||
|
||||
self.read_access_nmos_right[k] = self.add_inst(name="read_access_nmos_right{}".format(k),
|
||||
mod=self.read_nmos,
|
||||
offset=[right_read_transistor_xpos,0],
|
||||
rotate=90)
|
||||
self.connect_inst(["RA_to_R_right{}".format(k), "Q", "gnd", "gnd"])
|
||||
self.read_access_nmos_right[k].place(offset=[right_read_transistor_xpos,0],
|
||||
rotate=90)
|
||||
|
||||
# add read transistors
|
||||
self.read_nmos_left[k] = self.add_inst(name="read_nmos_left{}".format(k),
|
||||
mod=self.read_nmos,
|
||||
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_left[k].place(offset=[left_read_transistor_xpos,overlap_offset.x],
|
||||
rotate=90)
|
||||
|
||||
self.read_nmos_right[k] = self.add_inst(name="read_nmos_right{}".format(k),
|
||||
mod=self.read_nmos,
|
||||
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"])
|
||||
self.read_nmos_right[k].place(offset=[right_read_transistor_xpos,overlap_offset.x],
|
||||
rotate=90)
|
||||
|
||||
# Add RWL lines
|
||||
# calculate RWL position
|
||||
rwl_ypos = self.gnd_position.y \
|
||||
- self.num_readwrite*self.rowline_tile_height \
|
||||
- self.num_write*self.rowline_tile_height \
|
||||
- self.num_rw_ports*self.rowline_tile_height \
|
||||
- self.num_w_ports*self.rowline_tile_height \
|
||||
- (k+1)*self.rowline_tile_height
|
||||
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
|
||||
# height of the write transistor well (read/write and write
|
||||
# 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
|
||||
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"]
|
||||
|
|
@ -1054,7 +1024,7 @@ class pbitcell(pgate.pgate):
|
|||
height=write_well_height)
|
||||
|
||||
# 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
|
||||
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"]
|
||||
|
|
@ -1097,42 +1067,36 @@ class pbitcell(pgate.pgate):
|
|||
offset = vector(0, self.gnd_position.y + 0.5*contact.well.second_layer_width)
|
||||
self.add_contact_center(layers=("active", "contact", "metal1"),
|
||||
offset=offset,
|
||||
rotate=90)
|
||||
|
||||
self.add_rect_center(layer="pimplant",
|
||||
offset=offset,
|
||||
width=drc["minwidth_tx"],
|
||||
height=drc["minwidth_tx"])
|
||||
rotate=90,
|
||||
implant_type="p",
|
||||
well_type="p")
|
||||
|
||||
# connect nimplants to vdd
|
||||
offset = vector(0, self.vdd_position.y + 0.5*drc["minwidth_metal1"])
|
||||
self.add_contact_center(layers=("active", "contact", "metal1"),
|
||||
offset=offset,
|
||||
rotate=90)
|
||||
|
||||
self.add_rect_center(layer="nimplant",
|
||||
offset=offset,
|
||||
width=drc["minwidth_tx"],
|
||||
height=drc["minwidth_tx"])
|
||||
rotate=90,
|
||||
implant_type="n",
|
||||
well_type="n")
|
||||
|
||||
|
||||
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 """
|
||||
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_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_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_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))
|
||||
for k in range(self.num_write):
|
||||
for k in range(self.num_w_ports):
|
||||
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("vdd")
|
||||
bitcell_pins.append("gnd")
|
||||
|
|
@ -1142,11 +1106,11 @@ class pbitcell(pgate.pgate):
|
|||
def list_all_wl_names(self):
|
||||
""" Creates a list of all wordline pin names """
|
||||
row_pins = []
|
||||
for k in range(self.num_readwrite):
|
||||
for k in range(self.num_rw_ports):
|
||||
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))
|
||||
for k in range(self.num_read):
|
||||
for k in range(self.num_r_ports):
|
||||
row_pins.append("rwl{0}".format(k))
|
||||
|
||||
return row_pins
|
||||
|
|
@ -1154,9 +1118,9 @@ class pbitcell(pgate.pgate):
|
|||
def list_read_wl_names(self):
|
||||
""" Creates a list of wordline pin names associated with read ports """
|
||||
row_pins = []
|
||||
for k in range(self.num_readwrite):
|
||||
for k in range(self.num_rw_ports):
|
||||
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))
|
||||
|
||||
return row_pins
|
||||
|
|
@ -1164,9 +1128,9 @@ class pbitcell(pgate.pgate):
|
|||
def list_write_wl_names(self):
|
||||
""" Creates a list of wordline pin names associated with write ports """
|
||||
row_pins = []
|
||||
for k in range(self.num_readwrite):
|
||||
for k in range(self.num_rw_ports):
|
||||
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))
|
||||
|
||||
return row_pins
|
||||
|
|
@ -1175,13 +1139,13 @@ class pbitcell(pgate.pgate):
|
|||
def list_all_bitline_names(self):
|
||||
""" Creates a list of all bitline pin names (both bl and br) """
|
||||
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_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_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_bar{0}".format(k))
|
||||
|
||||
|
|
@ -1190,11 +1154,11 @@ class pbitcell(pgate.pgate):
|
|||
def list_all_bl_names(self):
|
||||
""" Creates a list of all bl pins names """
|
||||
column_pins = []
|
||||
for k in range(self.num_readwrite):
|
||||
for k in range(self.num_rw_ports):
|
||||
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))
|
||||
for k in range(self.num_read):
|
||||
for k in range(self.num_r_ports):
|
||||
column_pins.append("rbl{0}".format(k))
|
||||
|
||||
return column_pins
|
||||
|
|
@ -1202,11 +1166,11 @@ class pbitcell(pgate.pgate):
|
|||
def list_all_br_names(self):
|
||||
""" Creates a list of all br pins names """
|
||||
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))
|
||||
for k in range(self.num_write):
|
||||
for k in range(self.num_w_ports):
|
||||
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))
|
||||
|
||||
return column_pins
|
||||
|
|
@ -1214,9 +1178,9 @@ class pbitcell(pgate.pgate):
|
|||
def list_read_bl_names(self):
|
||||
""" Creates a list of bl pin names associated with read ports """
|
||||
column_pins = []
|
||||
for k in range(self.num_readwrite):
|
||||
for k in range(self.num_rw_ports):
|
||||
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))
|
||||
|
||||
return column_pins
|
||||
|
|
@ -1224,9 +1188,9 @@ class pbitcell(pgate.pgate):
|
|||
def list_read_br_names(self):
|
||||
""" Creates a list of br pin names associated with read ports """
|
||||
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))
|
||||
for k in range(self.num_read):
|
||||
for k in range(self.num_r_ports):
|
||||
column_pins.append("rbl_bar{0}".format(k))
|
||||
|
||||
return column_pins
|
||||
|
|
@ -1234,9 +1198,9 @@ class pbitcell(pgate.pgate):
|
|||
def list_write_bl_names(self):
|
||||
""" Creates a list of bl pin names associated with write ports """
|
||||
column_pins = []
|
||||
for k in range(self.num_readwrite):
|
||||
for k in range(self.num_rw_ports):
|
||||
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))
|
||||
|
||||
return column_pins
|
||||
|
|
@ -1244,9 +1208,9 @@ class pbitcell(pgate.pgate):
|
|||
def list_write_br_names(self):
|
||||
""" Creates a list of br pin names asscociated with write ports"""
|
||||
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))
|
||||
for k in range(self.num_write):
|
||||
for k in range(self.num_w_ports):
|
||||
column_pins.append("wbl_bar{0}".format(k))
|
||||
|
||||
return column_pins
|
||||
|
|
|
|||
|
|
@ -11,10 +11,19 @@ class pgate(design.design):
|
|||
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 """
|
||||
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):
|
||||
""" Conencts a ptx pin to a supply rail. """
|
||||
|
|
|
|||
|
|
@ -17,26 +17,22 @@ class pinv(pgate.pgate):
|
|||
from center of rail to rail.. The route_output will route the
|
||||
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
|
||||
|
||||
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
|
||||
# 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
|
||||
# have poly connected, for example.
|
||||
name = "pinv_{}".format(pinv.unique_id)
|
||||
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))
|
||||
|
||||
self.nmos_size = size
|
||||
self.pmos_size = beta*size
|
||||
self.beta = beta
|
||||
self.height = height # Maybe minimize height if not defined in future?
|
||||
self.route_output = False
|
||||
|
||||
|
||||
|
|
@ -175,6 +171,8 @@ class pinv(pgate.pgate):
|
|||
offset=vector(0.5*self.width,self.height),
|
||||
width=self.width)
|
||||
|
||||
|
||||
|
||||
def create_ptx(self):
|
||||
"""
|
||||
Create the PMOS and NMOS netlist.
|
||||
|
|
|
|||
|
|
@ -11,13 +11,9 @@ class pinvbuf(design.design):
|
|||
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.
|
||||
"""
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
bitcell = getattr(c, OPTS.bitcell)
|
||||
|
||||
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.row_height = height
|
||||
|
|
@ -32,7 +28,7 @@ class pinvbuf(design.design):
|
|||
name = "pinvbuf_{0}_{1}_{2}".format(self.predriver_size, self.driver_size, pinvbuf.unique_id)
|
||||
pinvbuf.unique_id += 1
|
||||
|
||||
design.design.__init__(self, name)
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {}".format(self.name))
|
||||
|
||||
self.create_netlist()
|
||||
|
|
|
|||
|
|
@ -12,24 +12,19 @@ class pnand2(pgate.pgate):
|
|||
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
|
||||
|
||||
def __init__(self, size=1, height=bitcell.height):
|
||||
def __init__(self, size=1, height=None):
|
||||
""" Creates a cell for a simple 2 input nand """
|
||||
name = "pnand2_{0}".format(pnand2.unique_id)
|
||||
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))
|
||||
|
||||
self.nmos_size = 2*size
|
||||
self.pmos_size = parameter["beta"]*size
|
||||
self.nmos_width = self.nmos_size*drc["minwidth_tx"]
|
||||
self.pmos_width = self.pmos_size*drc["minwidth_tx"]
|
||||
self.height = height
|
||||
|
||||
# FIXME: Allow these to be sized
|
||||
debug.check(size==1,"Size 1 pnand2 is only supported now.")
|
||||
|
|
|
|||
|
|
@ -12,18 +12,13 @@ class pnand3(pgate.pgate):
|
|||
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
|
||||
|
||||
def __init__(self, size=1, height=bitcell.height):
|
||||
def __init__(self, size=1, height=None):
|
||||
""" Creates a cell for a simple 3 input nand """
|
||||
name = "pnand3_{0}".format(pnand3.unique_id)
|
||||
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))
|
||||
|
||||
# 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.nmos_width = self.nmos_size*drc["minwidth_tx"]
|
||||
self.pmos_width = self.pmos_size*drc["minwidth_tx"]
|
||||
self.height = height
|
||||
|
||||
# FIXME: Allow these to be sized
|
||||
debug.check(size==1,"Size 1 pnand3 is only supported now.")
|
||||
|
|
|
|||
|
|
@ -12,17 +12,13 @@ class pnor2(pgate.pgate):
|
|||
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
|
||||
|
||||
def __init__(self, size=1, height=bitcell.height):
|
||||
def __init__(self, size=1, height=None):
|
||||
""" Creates a cell for a simple 2 input nor """
|
||||
name = "pnor2_{0}".format(pnor2.unique_id)
|
||||
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))
|
||||
|
||||
self.nmos_size = size
|
||||
|
|
@ -30,7 +26,6 @@ class pnor2(pgate.pgate):
|
|||
self.pmos_size = 1.5*parameter["beta"]*size
|
||||
self.nmos_width = self.nmos_size*drc["minwidth_tx"]
|
||||
self.pmos_width = self.pmos_size*drc["minwidth_tx"]
|
||||
self.height = height
|
||||
|
||||
# FIXME: Allow these to be sized
|
||||
debug.check(size==1,"Size 1 pnor2 is only supported now.")
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ class single_level_column_mux(design.design):
|
|||
self.add_wells()
|
||||
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -36,9 +36,6 @@ class grid:
|
|||
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))
|
||||
|
||||
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 = []
|
||||
for x in range(int(ll[0]),int(ur[0])+1):
|
||||
for y in range(int(ll[1]),int(ur[1])+1):
|
||||
|
|
|
|||
|
|
@ -49,6 +49,12 @@ class router:
|
|||
""" If we want to route something besides the top-level cell."""
|
||||
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):
|
||||
"""Allows us to change the layers that we are routing on. First layer
|
||||
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.
|
||||
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 = []
|
||||
for label in label_list:
|
||||
(name,layer,boundary)=label
|
||||
for shape in shape_list:
|
||||
(name,layer,boundary)=shape
|
||||
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_list.append(pin_layout(pin, rect, layer))
|
||||
pin = pin_layout(pin_name, rect, layer)
|
||||
pin_list.append(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):
|
||||
""" 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:
|
||||
# Skip pin shapes
|
||||
all_pins = [x[0] for x in list(self.pins.values())]
|
||||
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
|
||||
else:
|
||||
[ll,ur]=self.convert_blockage_to_tracks(blockage.rect)
|
||||
zlayer = 0 if blockage.layer_num==self.horiz_layer_number else 1
|
||||
debug.info(2,"Adding blockage {}".format(str(blockage)))
|
||||
# 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)
|
||||
real_blockages.append(blockage)
|
||||
|
||||
# Remember the filtered blockages
|
||||
self.blockages = real_blockages
|
||||
|
||||
|
||||
def get_blockages(self, layer_num):
|
||||
|
|
@ -227,37 +246,6 @@ class router:
|
|||
rect = [ll,ur]
|
||||
new_pin = pin_layout("blockage{}".format(len(self.blockages)),rect,layer_num)
|
||||
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):
|
||||
|
|
@ -282,11 +270,15 @@ class router:
|
|||
old_ur = ur
|
||||
ll=ll.scale(self.track_factor)
|
||||
ur=ur.scale(self.track_factor)
|
||||
ll = ll.floor()
|
||||
ur = ur.ceil()
|
||||
if ll[0]<45 and ll[0]>35 and ll[1]<10 and ll[1]>0:
|
||||
debug.info(0,"Converting [ {0} , {1} ]".format(old_ll,old_ur))
|
||||
debug.info(0,"Converted [ {0} , {1} ]".format(ll,ur))
|
||||
# We can round since we are using inflated shapes
|
||||
# and the track points are at the center
|
||||
ll = ll.round()
|
||||
ur = ur.round()
|
||||
# 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]
|
||||
|
||||
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.
|
||||
"""
|
||||
(ll,ur) = pin.rect
|
||||
#ll = snap_to_grid(ll)
|
||||
#ur = snap_to_grid(ur)
|
||||
|
||||
#debug.info(1,"Converting [ {0} , {1} ]".format(ll,ur))
|
||||
|
||||
# scale the size bigger to include neaby tracks
|
||||
|
|
@ -306,37 +295,40 @@ class router:
|
|||
ur=ur.scale(self.track_factor).ceil()
|
||||
|
||||
# width depends on which layer it is
|
||||
zindex = 0 if pin.layer_num==self.horiz_layer_number else 1
|
||||
if zindex==0:
|
||||
width = self.horiz_layer_width
|
||||
else:
|
||||
zindex=self.get_zindex(pin.layer_num)
|
||||
if zindex:
|
||||
width = self.vert_layer_width
|
||||
else:
|
||||
width = self.horiz_layer_width
|
||||
|
||||
track_list = []
|
||||
block_list = []
|
||||
# include +- 1 so when a shape is less than one grid
|
||||
for x in range(ll[0]-1,ur[0]+1):
|
||||
for y in range(ll[1]-1,ur[1]+1):
|
||||
|
||||
track_area = self.track_width*self.track_width
|
||||
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))
|
||||
# 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,
|
||||
# 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_overlap=max(self.compute_overlap(pin.rect,full_rect))
|
||||
|
||||
full_rect = self.convert_track_to_shape(vector3d(x,y,zindex))
|
||||
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))
|
||||
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))
|
||||
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))
|
||||
else:
|
||||
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.info(1,"Converted [ {0} , {1} ]".format(ll,ur))
|
||||
return (track_list,block_list)
|
||||
|
|
@ -381,7 +373,7 @@ class router:
|
|||
|
||||
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
|
||||
track.
|
||||
|
|
@ -447,9 +439,8 @@ class router:
|
|||
grid_keys=self.rg.map.keys()
|
||||
partial_track=vector(0,self.track_width/6.0)
|
||||
for g in grid_keys:
|
||||
continue # for now...
|
||||
shape = self.convert_full_track_to_shape(g)
|
||||
self.cell.add_rect(layer="boundary",
|
||||
shape = self.convert_track_to_shape(g)
|
||||
self.cell.add_rect(layer="text",
|
||||
offset=shape[0],
|
||||
width=shape[1].x-shape[0].x,
|
||||
height=shape[1].y-shape[0].y)
|
||||
|
|
@ -481,10 +472,12 @@ class router:
|
|||
zoom=0.05)
|
||||
|
||||
for blockage in self.blockages:
|
||||
self.cell.add_rect(layer="boundary",
|
||||
offset=blockage.ll(),
|
||||
width=blockage.width(),
|
||||
height=blockage.height())
|
||||
# Display the inflated blockage
|
||||
(ll,ur) = blockage.inflate()
|
||||
self.cell.add_rect(layer="blockage",
|
||||
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
|
||||
|
|
|
|||
|
|
@ -32,12 +32,14 @@ class no_blockages_test(openram_test):
|
|||
globals.setup_paths()
|
||||
from control_logic import control_logic
|
||||
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")
|
||||
#cell = gds_cell(name, gds_file)
|
||||
self.add_inst(name=name,
|
||||
mod=cell,
|
||||
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)
|
||||
layer_stack =("metal3","via2","metal2")
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import datetime
|
|||
import getpass
|
||||
import debug
|
||||
from globals import OPTS, print_time
|
||||
|
||||
from sram_config import sram_config
|
||||
|
||||
class sram():
|
||||
"""
|
||||
|
|
@ -12,31 +12,34 @@ class sram():
|
|||
results.
|
||||
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
|
||||
# in case we create more than one SRAM
|
||||
from design import design
|
||||
design.name_map=[]
|
||||
|
||||
debug.info(2, "create sram of size {0} with {1} num of words".format(word_size,
|
||||
num_words))
|
||||
debug.info(2, "create sram of size {0} with {1} num of words {2} banks".format(self.word_size,
|
||||
self.num_words,
|
||||
self.num_banks))
|
||||
start_time = datetime.datetime.now()
|
||||
|
||||
self.name = name
|
||||
|
||||
|
||||
if num_banks == 1:
|
||||
from sram_1bank import sram_1bank
|
||||
self.s=sram_1bank(word_size, num_words, name)
|
||||
elif num_banks == 2:
|
||||
from sram_2bank import sram_2bank
|
||||
self.s=sram_2bank(word_size, num_words, name)
|
||||
elif num_banks == 4:
|
||||
from sram_4bank import sram_4bank
|
||||
self.s=sram_4bank(word_size, num_words, name)
|
||||
if self.num_banks == 1:
|
||||
from sram_1bank import sram_1bank as sram
|
||||
elif self.num_banks == 2:
|
||||
from sram_2bank import sram_2bank as sram
|
||||
elif self.num_banks == 4:
|
||||
from sram_4bank import sram_4bank as sram
|
||||
else:
|
||||
debug.error("Invalid number of banks.",-1)
|
||||
|
||||
self.s = sram(name, sram_config)
|
||||
self.s.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.s.create_layout()
|
||||
|
|
|
|||
|
|
@ -18,11 +18,11 @@ class sram_1bank(sram_base):
|
|||
"""
|
||||
Procedures specific to a one bank SRAM.
|
||||
"""
|
||||
def __init__(self, word_size, num_words, name):
|
||||
sram_base.__init__(self, word_size, num_words, 1, name)
|
||||
def __init__(self, name, sram_config):
|
||||
sram_base.__init__(self, name, sram_config)
|
||||
|
||||
|
||||
def create_netlist(self):
|
||||
self.compute_sizes()
|
||||
sram_base.create_netlist(self)
|
||||
self.create_modules()
|
||||
|
||||
|
|
@ -99,18 +99,18 @@ class sram_1bank(sram_base):
|
|||
|
||||
for i in range(self.word_size):
|
||||
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
|
||||
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
|
||||
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):
|
||||
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):
|
||||
""" Route a single bank SRAM """
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ class sram_2bank(sram_base):
|
|||
"""
|
||||
Procedures specific to a two bank SRAM.
|
||||
"""
|
||||
def __init__(self, word_size, num_words, name):
|
||||
sram_base.__init__(self, word_size, num_words, 2, name)
|
||||
def __init__(self, name, sram_config):
|
||||
sram_base.__init__(self, name, sram_config)
|
||||
|
||||
def compute_bank_offsets(self):
|
||||
""" Compute the overall offsets for a two bank SRAM """
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ class sram_4bank(sram_base):
|
|||
"""
|
||||
Procedures specific to a four bank SRAM.
|
||||
"""
|
||||
def __init__(self, word_size, num_words, name):
|
||||
sram_base.__init__(self, word_size, num_words, 4, name)
|
||||
def __init__(self, name, sram_config):
|
||||
sram_base.__init__(self, name, sram_config)
|
||||
|
||||
def compute_bank_offsets(self):
|
||||
""" Compute the overall offsets for a four bank SRAM """
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import sys
|
|||
import datetime
|
||||
import getpass
|
||||
import debug
|
||||
from math import log,sqrt,ceil
|
||||
from importlib import reload
|
||||
from vector import vector
|
||||
from globals import OPTS, print_time
|
||||
|
||||
|
|
@ -13,95 +13,29 @@ class sram_base(design):
|
|||
Dynamically generated SRAM by connecting banks to control logic. The
|
||||
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)
|
||||
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.control_logic))
|
||||
self.mod_control_logic = getattr(c, OPTS.control_logic)
|
||||
self.sram_config = sram_config
|
||||
sram_config.set_local_config(self)
|
||||
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
|
||||
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.total_write = OPTS.num_rw_ports + OPTS.num_w_ports
|
||||
self.total_read = OPTS.num_rw_ports + OPTS.num_r_ports
|
||||
self.total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
|
||||
|
||||
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):
|
||||
""" Add pins for entire SRAM. """
|
||||
|
||||
for i in range(self.word_size):
|
||||
self.add_pin("DIN[{0}]".format(i),"INPUT")
|
||||
for i in range(self.addr_size):
|
||||
self.add_pin("ADDR[{0}]".format(i),"INPUT")
|
||||
|
||||
for port in range(self.total_write):
|
||||
for bit in range(self.word_size):
|
||||
self.add_pin("DIN{0}[{1}]".format(port,bit),"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
|
||||
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")
|
||||
|
||||
for i in range(self.word_size):
|
||||
self.add_pin("DOUT[{0}]".format(i),"OUTPUT")
|
||||
for port in range(self.total_read):
|
||||
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("gnd","GROUND")
|
||||
|
|
@ -271,7 +206,18 @@ class sram_base(design):
|
|||
|
||||
def add_modules(self):
|
||||
""" 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
|
||||
# Create the control logic module
|
||||
self.control_logic = self.mod_control_logic(num_rows=self.num_rows)
|
||||
|
|
@ -279,24 +225,21 @@ class sram_base(design):
|
|||
|
||||
# Create the address and control flops (but not the clk)
|
||||
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)
|
||||
|
||||
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)
|
||||
else:
|
||||
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)
|
||||
|
||||
# Create the bank module (up to four are instantiated)
|
||||
from bank import bank
|
||||
self.bank = bank(word_size=self.word_size,
|
||||
num_words=self.num_words_per_bank,
|
||||
words_per_row=self.words_per_row,
|
||||
num_banks=self.num_banks,
|
||||
self.bank = bank(self.sram_config,
|
||||
name="bank")
|
||||
self.add_mod(self.bank)
|
||||
|
||||
|
|
@ -312,20 +255,28 @@ class sram_base(design):
|
|||
|
||||
|
||||
def create_bank(self,bank_num):
|
||||
""" Create a bank """
|
||||
""" Create a bank """
|
||||
self.bank_insts.append(self.add_inst(name="bank{0}".format(bank_num),
|
||||
mod=self.bank))
|
||||
|
||||
temp = []
|
||||
for i in range(self.word_size):
|
||||
temp.append("DOUT[{0}]".format(i))
|
||||
for i in range(self.word_size):
|
||||
temp.append("BANK_DIN[{0}]".format(i))
|
||||
for i in range(self.bank_addr_size):
|
||||
temp.append("A[{0}]".format(i))
|
||||
for port in range(self.total_read):
|
||||
for bit in range(self.word_size):
|
||||
temp.append("DOUT{0}[{1}]".format(port,bit))
|
||||
for port in range(self.total_write):
|
||||
for bit in range(self.word_size):
|
||||
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):
|
||||
temp.append("bank_sel[{0}]".format(bank_num))
|
||||
temp.extend(["s_en0", "w_en0", "clk_buf_bar","clk_buf" , "vdd", "gnd"])
|
||||
for port in range(self.total_ports):
|
||||
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)
|
||||
|
||||
return self.bank_insts[-1]
|
||||
|
|
@ -370,9 +321,10 @@ class sram_base(design):
|
|||
# inputs, outputs/output/bar
|
||||
inputs = []
|
||||
outputs = []
|
||||
for i in range(self.row_addr_size):
|
||||
inputs.append("ADDR[{}]".format(i+self.col_addr_size))
|
||||
outputs.append("A[{}]".format(i+self.col_addr_size))
|
||||
for k in range(self.total_ports):
|
||||
for i in range(self.row_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"])
|
||||
return inst
|
||||
|
|
@ -385,9 +337,10 @@ class sram_base(design):
|
|||
# inputs, outputs/output/bar
|
||||
inputs = []
|
||||
outputs = []
|
||||
for i in range(self.col_addr_size):
|
||||
inputs.append("ADDR[{}]".format(i))
|
||||
outputs.append("A[{}]".format(i))
|
||||
for k in range(self.total_ports):
|
||||
for i in range(self.col_addr_size):
|
||||
inputs.append("ADDR{}[{}]".format(k,i))
|
||||
outputs.append("A{}[{}]".format(k,i))
|
||||
|
||||
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
|
||||
return inst
|
||||
|
|
@ -400,9 +353,10 @@ class sram_base(design):
|
|||
# inputs, outputs/output/bar
|
||||
inputs = []
|
||||
outputs = []
|
||||
for i in range(self.word_size):
|
||||
inputs.append("DIN[{}]".format(i))
|
||||
outputs.append("BANK_DIN[{}]".format(i))
|
||||
for k in range(self.total_write):
|
||||
for i in range(self.word_size):
|
||||
inputs.append("DIN{}[{}]".format(k,i))
|
||||
outputs.append("BANK_DIN{}[{}]".format(k,i))
|
||||
|
||||
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
|
||||
return inst
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -13,52 +13,81 @@ import debug
|
|||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
@unittest.skip("SKIPPING 04_pbitcell_test")
|
||||
#@unittest.skip("SKIPPING 04_pbitcell_test")
|
||||
class pbitcell_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
import pbitcell
|
||||
from pbitcell import pbitcell
|
||||
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")
|
||||
tx = pbitcell.pbitcell(num_readwrite=1,num_write=1,num_read=1)
|
||||
tx = pbitcell()
|
||||
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")
|
||||
tx = pbitcell.pbitcell(num_readwrite=0,num_write=1,num_read=1)
|
||||
tx = pbitcell()
|
||||
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")
|
||||
tx = pbitcell.pbitcell(num_readwrite=1,num_write=0,num_read=1)
|
||||
tx = pbitcell()
|
||||
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")
|
||||
tx = pbitcell.pbitcell(num_readwrite=1,num_write=1,num_read=0)
|
||||
tx = pbitcell()
|
||||
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")
|
||||
tx = pbitcell.pbitcell(num_readwrite=1,num_write=0,num_read=0)
|
||||
tx = pbitcell()
|
||||
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")
|
||||
tx = pbitcell.pbitcell(num_readwrite=2,num_write=2,num_read=2)
|
||||
tx = pbitcell()
|
||||
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")
|
||||
tx = pbitcell.pbitcell(num_readwrite=0,num_write=2,num_read=2)
|
||||
tx = pbitcell()
|
||||
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")
|
||||
tx = pbitcell.pbitcell(num_readwrite=2,num_write=0,num_read=2)
|
||||
tx = pbitcell()
|
||||
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")
|
||||
tx = pbitcell.pbitcell(num_readwrite=2,num_write=2,num_read=0)
|
||||
tx = pbitcell()
|
||||
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")
|
||||
tx = pbitcell.pbitcell(num_readwrite=2,num_write=0,num_read=0)
|
||||
tx = pbitcell()
|
||||
self.local_check(tx)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ class precharge_test(openram_test):
|
|||
|
||||
debug.info(2, "Checking precharge for pbitcell")
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.rw_ports = 2
|
||||
OPTS.r_ports = 2
|
||||
OPTS.w_ports = 2
|
||||
OPTS.num_rw_ports = 2
|
||||
OPTS.num_r_ports = 2
|
||||
OPTS.num_w_ports = 2
|
||||
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="rwbl0", bitcell_br="rwbl_bar0")
|
||||
self.local_check(tx)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import globals
|
|||
from globals import OPTS
|
||||
import debug
|
||||
|
||||
@unittest.skip("SKIPPING 05_pbitcell_array_test")
|
||||
#@unittest.skip("SKIPPING 05_pbitcell_array_test")
|
||||
class pbitcell_array_test(openram_test):
|
||||
|
||||
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")
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.rw_ports = 2
|
||||
OPTS.r_ports = 2
|
||||
OPTS.w_ports = 2
|
||||
a = bitcell_array.bitcell_array(name="pbitcell_array", cols=4, rows=4)
|
||||
OPTS.num_rw_ports = 2
|
||||
OPTS.num_r_ports = 2
|
||||
OPTS.num_w_ports = 2
|
||||
a = bitcell_array.bitcell_array(name="pbitcell_array_Rport_edge", cols=4, rows=4)
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(2, "Testing 4x4 array for multiport bitcell, with write ports at the edge of the bit cell")
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.rw_ports = 2
|
||||
OPTS.r_ports = 0
|
||||
OPTS.w_ports = 2
|
||||
a = bitcell_array.bitcell_array(name="pbitcell_array", cols=4, rows=4)
|
||||
OPTS.num_rw_ports = 2
|
||||
OPTS.num_r_ports = 0
|
||||
OPTS.num_w_ports = 2
|
||||
a = bitcell_array.bitcell_array(name="pbitcell_array_Wport_edge", cols=4, rows=4)
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(2, "Testing 4x4 array for multiport bitcell, with read/write ports at the edge of the bit cell")
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.rw_ports = 2
|
||||
OPTS.r_ports = 0
|
||||
OPTS.w_ports = 0
|
||||
a = bitcell_array.bitcell_array(name="pbitcell_array", cols=4, rows=4)
|
||||
OPTS.num_rw_ports = 2
|
||||
OPTS.num_r_ports = 0
|
||||
OPTS.num_w_ports = 0
|
||||
a = bitcell_array.bitcell_array(name="pbitcell_array_RWport_edge", cols=4, rows=4)
|
||||
self.local_check(a)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ class precharge_test(openram_test):
|
|||
|
||||
debug.info(2, "Checking precharge for pbitcell")
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.rw_ports = 2
|
||||
OPTS.r_ports = 2
|
||||
OPTS.w_ports = 2
|
||||
OPTS.num_rw_ports = 2
|
||||
OPTS.num_r_ports = 2
|
||||
OPTS.num_w_ports = 2
|
||||
|
||||
pc = precharge_array.precharge_array(columns=3, bitcell_bl="rwbl0", bitcell_br="rwbl_bar0")
|
||||
self.local_check(pc)
|
||||
|
|
|
|||
|
|
@ -20,10 +20,21 @@ class wordline_driver_test(openram_test):
|
|||
import wordline_driver
|
||||
import tech
|
||||
|
||||
# check wordline driver array in single port
|
||||
debug.info(2, "Checking driver")
|
||||
tx = wordline_driver.wordline_driver(rows=8)
|
||||
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()
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class sense_amp_test(openram_test):
|
|||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
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")
|
||||
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2)
|
||||
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)
|
||||
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()
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ class write_driver_test(openram_test):
|
|||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
import write_driver_array
|
||||
|
||||
# check write driver array in single port
|
||||
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)
|
||||
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)
|
||||
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()
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
|
|
|
|||
|
|
@ -16,21 +16,34 @@ class multi_bank_test(openram_test):
|
|||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
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")
|
||||
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)
|
||||
|
||||
c.num_words=32
|
||||
c.words_per_row=2
|
||||
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)
|
||||
|
||||
c.num_words=64
|
||||
c.words_per_row=4
|
||||
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)
|
||||
|
||||
c.word_size=2
|
||||
c.num_words=128
|
||||
c.words_per_row=8
|
||||
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)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import globals
|
|||
from globals import OPTS
|
||||
import debug
|
||||
|
||||
@unittest.skip("SKIPPING 19_psingle_bank_test")
|
||||
#@unittest.skip("SKIPPING 19_psingle_bank_test")
|
||||
class psingle_bank_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
|
|
@ -20,65 +20,103 @@ class psingle_bank_test(openram_test):
|
|||
import verify
|
||||
|
||||
from bank import bank
|
||||
from sram_config import sram_config
|
||||
OPTS.bitcell = "pbitcell"
|
||||
|
||||
# testing all port configurations (with no column mux) to verify layout between bitcell array and peripheral circuitry
|
||||
OPTS.rw_ports = 2
|
||||
OPTS.w_ports = 2
|
||||
OPTS.r_ports = 2
|
||||
|
||||
# testing layout of bank using pbitcell with 1 RW port (a 6T-cell equivalent)
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
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")
|
||||
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)
|
||||
"""
|
||||
OPTS.rw_ports = 0
|
||||
OPTS.w_ports = 2
|
||||
OPTS.r_ports = 2
|
||||
|
||||
# multiport can't generate layout yet on the bank level
|
||||
OPTS.netlist_only = True
|
||||
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
|
||||
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)
|
||||
|
||||
OPTS.rw_ports = 2
|
||||
OPTS.w_ports = 0
|
||||
OPTS.r_ports = 2
|
||||
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 = 2
|
||||
|
||||
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)
|
||||
|
||||
OPTS.num_rw_ports = c.num_rw_ports = 0
|
||||
OPTS.num_w_ports = c.num_w_ports = 2
|
||||
OPTS.num_r_ports = c.num_r_ports = 2
|
||||
|
||||
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.rw_ports = 2
|
||||
OPTS.w_ports = 2
|
||||
OPTS.r_ports = 0
|
||||
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 = 2
|
||||
|
||||
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)
|
||||
|
||||
OPTS.rw_ports = 2
|
||||
OPTS.w_ports = 0
|
||||
OPTS.r_ports = 0
|
||||
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")
|
||||
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 = 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)
|
||||
|
||||
# testing with various column muxes
|
||||
OPTS.rw_ports = 2
|
||||
OPTS.w_ports = 2
|
||||
OPTS.r_ports = 2
|
||||
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 = 2
|
||||
|
||||
c.num_words=32
|
||||
c.words_per_row=2
|
||||
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)
|
||||
|
||||
c.num_words=64
|
||||
c.words_per_row=4
|
||||
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)
|
||||
|
||||
# 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")
|
||||
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)
|
||||
"""
|
||||
|
||||
|
|
|
|||
|
|
@ -16,22 +16,34 @@ class single_bank_test(openram_test):
|
|||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
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")
|
||||
a = bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="bank1_single")
|
||||
self.local_check(a)
|
||||
|
||||
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="bank1_single")
|
||||
self.local_check(a)
|
||||
|
||||
c.num_words=32
|
||||
c.words_per_row=2
|
||||
debug.info(1, "Two way column mux")
|
||||
a = bank(c, name="bank2_single")
|
||||
self.local_check(a)
|
||||
|
||||
c.num_words=64
|
||||
c.words_per_row=4
|
||||
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)
|
||||
|
||||
# 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")
|
||||
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)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -16,22 +16,34 @@ class sram_1bank_test(openram_test):
|
|||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
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")
|
||||
a = sram(word_size=4, num_words=16, num_banks=1, name="sram1")
|
||||
a = sram(c, "sram1")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
# debug.info(1, "Single bank two way column mux with control logic")
|
||||
# a = sram(word_size=4, num_words=32, num_banks=1, name="sram2")
|
||||
# self.local_check(a, final_verification=True)
|
||||
c.num_words=32
|
||||
c.words_per_row=2
|
||||
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")
|
||||
# a = sram(word_size=4, num_words=64, num_banks=1, name="sram3")
|
||||
# self.local_check(a, final_verification=True)
|
||||
c.num_words=64
|
||||
c.words_per_row=4
|
||||
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")
|
||||
# a = sram(word_size=2, num_words=128, num_banks=1, name="sram4")
|
||||
# self.local_check(a, final_verification=True)
|
||||
c.word_size=2
|
||||
c.num_words=128
|
||||
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()
|
||||
|
||||
|
|
|
|||
|
|
@ -17,21 +17,33 @@ class sram_2bank_test(openram_test):
|
|||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
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")
|
||||
a = sram(word_size=16, num_words=32, num_banks=2, name="sram1")
|
||||
a = sram(c, "sram1")
|
||||
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")
|
||||
a = sram(word_size=16, num_words=64, num_banks=2, name="sram2")
|
||||
a = sram(c, "sram2")
|
||||
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")
|
||||
a = sram(word_size=16, num_words=128, num_banks=2, name="sram3")
|
||||
a = sram(c, "sram3")
|
||||
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")
|
||||
a = sram(word_size=2, num_words=256, num_banks=2, name="sram4")
|
||||
a = sram(c, "sram4")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -17,21 +17,32 @@ class sram_4bank_test(openram_test):
|
|||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
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")
|
||||
a = sram(word_size=16, num_words=64, num_banks=4, name="sram1")
|
||||
a = sram(c, "sram1")
|
||||
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")
|
||||
a = sram(word_size=16, num_words=128, num_banks=4, name="sram2")
|
||||
a = sram(c, "sram2")
|
||||
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")
|
||||
a = sram(word_size=16, num_words=256, num_banks=4, name="sram3")
|
||||
a = sram(c, "sram3")
|
||||
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")
|
||||
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)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -27,14 +27,14 @@ class timing_sram_test(openram_test):
|
|||
if not OPTS.spice_exe:
|
||||
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
|
||||
|
||||
import sram
|
||||
import tech
|
||||
from sram import sram
|
||||
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")
|
||||
s = sram.sram(word_size=OPTS.word_size,
|
||||
num_words=OPTS.num_words,
|
||||
num_banks=OPTS.num_banks,
|
||||
name="sram1")
|
||||
|
||||
s = sram(c, name="sram1")
|
||||
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
s.sp_write(tempspice)
|
||||
|
|
|
|||
|
|
@ -27,13 +27,14 @@ class timing_sram_test(openram_test):
|
|||
if not OPTS.spice_exe:
|
||||
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
|
||||
|
||||
import sram
|
||||
import tech
|
||||
from sram import sram
|
||||
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")
|
||||
s = sram.sram(word_size=OPTS.word_size,
|
||||
num_words=OPTS.num_words,
|
||||
num_banks=OPTS.num_banks,
|
||||
name="sram1")
|
||||
s = sram(c, name="sram1")
|
||||
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
s.sp_write(tempspice)
|
||||
|
|
|
|||
|
|
@ -16,15 +16,15 @@ class lib_test(openram_test):
|
|||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
|
||||
import sram
|
||||
from characterizer import lib
|
||||
|
||||
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank")
|
||||
s = sram.sram(word_size=2,
|
||||
num_words=16,
|
||||
num_banks=1,
|
||||
name="sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
|
||||
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 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"
|
||||
s.sp_write(tempspice)
|
||||
|
||||
|
|
|
|||
|
|
@ -26,13 +26,14 @@ class lib_test(openram_test):
|
|||
if not OPTS.spice_exe:
|
||||
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
|
||||
|
||||
import sram
|
||||
|
||||
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank")
|
||||
s = sram.sram(word_size=2,
|
||||
num_words=16,
|
||||
num_banks=1,
|
||||
name="sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
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 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"
|
||||
s.sp_write(tempspice)
|
||||
|
|
|
|||
|
|
@ -26,13 +26,14 @@ class lib_test(openram_test):
|
|||
if not OPTS.spice_exe:
|
||||
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")
|
||||
s = sram.sram(word_size=2,
|
||||
num_words=16,
|
||||
num_banks=1,
|
||||
name="sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
s.sp_write(tempspice)
|
||||
|
|
|
|||
|
|
@ -17,13 +17,14 @@ class lef_test(openram_test):
|
|||
def runTest(self):
|
||||
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")
|
||||
s = sram.sram(word_size=2,
|
||||
num_words=OPTS.num_words,
|
||||
num_banks=OPTS.num_banks,
|
||||
name="sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
|
||||
gdsfile = s.name + ".gds"
|
||||
leffile = s.name + ".lef"
|
||||
|
|
|
|||
|
|
@ -16,13 +16,14 @@ class verilog_test(openram_test):
|
|||
def runTest(self):
|
||||
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")
|
||||
s = sram.sram(word_size=2,
|
||||
num_words=OPTS.num_words,
|
||||
num_banks=OPTS.num_banks,
|
||||
name="sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
|
||||
vfile = s.name + ".v"
|
||||
vname = OPTS.openram_temp + vfile
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -56,6 +56,7 @@ layer["via9"] = 28
|
|||
layer["metal10"] = 29
|
||||
layer["text"] = 239
|
||||
layer["boundary"]= 239
|
||||
layer["blockage"]= 239
|
||||
|
||||
###################################################
|
||||
##END GDS Layer Map
|
||||
|
|
@ -98,6 +99,8 @@ drc["minwidth_poly"] = 0.05
|
|||
drc["poly_to_poly"] = 0.14
|
||||
# POLY.3 Minimum poly extension beyond active
|
||||
drc["poly_extend_active"] = 0.055
|
||||
# Not a rule
|
||||
drc["poly_to_polycontact"] = 0.075
|
||||
# POLY.4 Minimum enclosure of active around gate
|
||||
drc["active_enclosure_gate"] = 0.07
|
||||
# POLY.5 Minimum spacing of field poly to active
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1521677056
|
||||
timestamp 1536091415
|
||||
<< nwell >>
|
||||
rect -8 29 42 51
|
||||
<< pwell >>
|
||||
|
|
@ -105,13 +105,13 @@ rect 6 2 10 48
|
|||
rect 24 -2 28 48
|
||||
rect 32 33 36 48
|
||||
rect 32 -2 36 29
|
||||
<< m3p >>
|
||||
<< bb >>
|
||||
rect 0 0 34 46
|
||||
<< labels >>
|
||||
rlabel metal2 0 0 0 0 1 gnd
|
||||
rlabel metal2 34 0 34 0 1 gnd
|
||||
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 26 43 26 43 1 BR
|
||||
rlabel metal2 8 43 8 43 1 bl
|
||||
rlabel metal2 26 43 26 43 1 br
|
||||
rlabel metal1 4 7 4 7 1 wl
|
||||
<< end >>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1518823399
|
||||
timestamp 1536089597
|
||||
<< nwell >>
|
||||
rect 0 48 109 103
|
||||
<< pwell >>
|
||||
|
|
@ -266,7 +266,7 @@ rect 6 30 10 50
|
|||
rect 22 20 26 57
|
||||
rect 70 44 74 70
|
||||
rect 70 20 74 40
|
||||
<< m3p >>
|
||||
<< bb >>
|
||||
rect 0 0 109 100
|
||||
<< labels >>
|
||||
rlabel m2contact 15 34 15 34 4 clk
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1523479368
|
||||
timestamp 1536089622
|
||||
<< nwell >>
|
||||
rect -2 0 18 200
|
||||
<< pwell >>
|
||||
|
|
@ -280,7 +280,7 @@ rect 14 8 20 9
|
|||
rect 14 4 15 8
|
||||
rect 19 4 20 8
|
||||
rect 14 3 20 4
|
||||
<< m3p >>
|
||||
<< bb >>
|
||||
rect 0 0 34 200
|
||||
<< labels >>
|
||||
rlabel metal1 0 8 0 8 2 clk
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1521677136
|
||||
timestamp 1536091380
|
||||
<< nwell >>
|
||||
rect -8 29 42 51
|
||||
<< pwell >>
|
||||
|
|
@ -106,13 +106,13 @@ rect 6 2 10 48
|
|||
rect 24 -2 28 48
|
||||
rect 32 33 36 48
|
||||
rect 32 -2 36 29
|
||||
<< m3p >>
|
||||
<< bb >>
|
||||
rect 0 0 34 46
|
||||
<< labels >>
|
||||
rlabel metal2 0 0 0 0 1 gnd
|
||||
rlabel metal2 34 0 34 0 1 gnd
|
||||
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 26 43 26 43 1 BR
|
||||
rlabel metal2 8 43 8 43 1 bl
|
||||
rlabel metal2 26 43 26 43 1 br
|
||||
rlabel metal1 4 7 4 7 1 wl
|
||||
<< end >>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1524065550
|
||||
timestamp 1536089670
|
||||
<< nwell >>
|
||||
rect 0 0 40 102
|
||||
<< pwell >>
|
||||
|
|
@ -122,7 +122,7 @@ rect 20 44 22 48
|
|||
rect 3 0 7 11
|
||||
rect 10 0 14 44
|
||||
rect 20 0 24 44
|
||||
<< m3p >>
|
||||
<< bb >>
|
||||
rect 0 0 34 163
|
||||
<< labels >>
|
||||
flabel metal1 0 149 0 149 4 FreeSans 26 0 0 0 en
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1524499924
|
||||
timestamp 1536089695
|
||||
<< nwell >>
|
||||
rect -2 45 38 73
|
||||
<< pwell >>
|
||||
|
|
@ -86,7 +86,7 @@ rect 24 19 28 23
|
|||
<< metal2 >>
|
||||
rect 15 34 25 38
|
||||
rect 15 0 19 34
|
||||
<< m3p >>
|
||||
<< bb >>
|
||||
rect 0 0 34 73
|
||||
<< labels >>
|
||||
rlabel metal1 0 12 0 12 3 en
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1524499497
|
||||
timestamp 1536089714
|
||||
<< nwell >>
|
||||
rect -3 101 37 138
|
||||
rect -3 0 37 51
|
||||
|
|
@ -209,7 +209,7 @@ rect 10 196 14 202
|
|||
rect 20 193 24 202
|
||||
rect 20 177 24 189
|
||||
rect 15 0 19 6
|
||||
<< m3p >>
|
||||
<< bb >>
|
||||
rect 0 0 34 202
|
||||
<< labels >>
|
||||
rlabel metal2 15 1 15 1 1 din
|
||||
|
|
|
|||
|
|
@ -276,6 +276,11 @@ cifoutput
|
|||
style lambda=0.30(p)
|
||||
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
|
||||
bloat-or pdiff,rpd,pdc/a,pfet * 180
|
||||
bloat-or nsd,nsc/a * 90
|
||||
|
|
@ -1506,7 +1511,12 @@ cifinput
|
|||
style lambda=0.30(p)
|
||||
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 CTA
|
||||
labels CWN
|
||||
|
|
|
|||
|
|
@ -39,8 +39,9 @@ layer["via1"] = 50
|
|||
layer["metal2"] = 51
|
||||
layer["via2"] = 61
|
||||
layer["metal3"] = 62
|
||||
layer["text"] = 83
|
||||
layer["boundary"] = 83
|
||||
layer["text"] = 63
|
||||
layer["boundary"] = 63
|
||||
layer["blockage"] = 83
|
||||
|
||||
###################################################
|
||||
##END GDS Layer Map
|
||||
|
|
@ -83,14 +84,14 @@ drc["minwidth_poly"] = 0.6
|
|||
drc["poly_to_poly"] = 0.9
|
||||
# 3.3 Minimum gate extension of active
|
||||
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["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
|
||||
drc["poly_to_active"] = 0.3
|
||||
# 3.2.a Minimum spacing over field poly
|
||||
drc["poly_to_field_poly"] = 0.9
|
||||
# Not a rule
|
||||
drc["minarea_poly"] = 0.0
|
||||
|
||||
|
|
|
|||
|
|
@ -625,7 +625,7 @@ drDefinePacket(
|
|||
( display deviceAnt stipple0 solid yellow yellow solid )
|
||||
( display winBottomShadow solid solid winColor1 winColor1 solid )
|
||||
( 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 Unrouted stipple0 lineStyle1 winColor5 winColor5 solid )
|
||||
( display stretch stipple0 solid yellow yellow solid )
|
||||
|
|
|
|||
|
|
@ -13,4 +13,4 @@ Metal2 drawing 51 0
|
|||
Via2 drawing 61 0
|
||||
Metal3 drawing 62 0
|
||||
Glass drawing 52 0
|
||||
text drawing 83 0
|
||||
comment drawing 63 0
|
||||
|
|
|
|||
Loading…
Reference in New Issue