Updates to gdsMill/tech layers

Create active and poly contact types.
Define standard cell boundary option.
DataType and PurposeLayer are the same. Text must have type 0.
Remove vector from vlsiLayout. More debug in reader.
This commit is contained in:
Matt Guthaus
2019-12-04 16:12:53 -08:00
parent 0d35941241
commit 69bb245f28
13 changed files with 148 additions and 82 deletions
+7 -9
View File
@@ -48,7 +48,8 @@ class contact(hierarchy_design.hierarchy_design):
# Module does not have pins, but has empty pin list.
self.pins = []
self.create_layout()
self.add_boundary()
def create_layout(self):
self.setup_layers()
@@ -71,14 +72,11 @@ class contact(hierarchy_design.hierarchy_design):
(first_layer, via_layer, second_layer) = self.layer_stack
self.first_layer_name = first_layer
self.via_layer_name = via_layer
# Some technologies have a separate active
# contact from the poly contact
# We will use contact for DRC, but active_contact for output
if first_layer == "active" or second_layer == "active":
self.via_layer_name_expanded = "active_" + via_layer
# Contacts will have unique per first layer
if via_layer == "contact":
self.via_layer_name = first_layer + "_" + via_layer
else:
self.via_layer_name_expanded = via_layer
self.via_layer_name = via_layer
self.second_layer_name = second_layer
def setup_layout_constants(self):
@@ -144,7 +142,7 @@ class contact(hierarchy_design.hierarchy_design):
for i in range(self.dimensions[1]):
offset = self.via_layer_position + vector(0, self.contact_pitch * i)
for j in range(self.dimensions[0]):
self.add_rect(layer=self.via_layer_name_expanded,
self.add_rect(layer=self.via_layer_name,
offset=offset,
width=self.contact_width,
height=self.contact_width)
+3 -3
View File
@@ -48,12 +48,12 @@ class design(hierarchy_design):
self.m4_space = drc("metal4_to_metal4")
self.active_width = drc("minwidth_active")
self.active_space = drc("active_to_body_active")
self.contact_width = drc("minwidth_contact")
self.contact_width = drc("minwidth_active_contact")
self.poly_to_active = drc("poly_to_active")
self.poly_extend_active = drc("poly_extend_active")
self.poly_to_polycontact = drc("poly_to_polycontact")
self.contact_to_gate = drc("contact_to_gate")
self.poly_to_poly_contact = drc("poly_to_poly_contact")
self.active_contact_to_gate = drc("active_contact_to_gate")
self.well_enclose_active = drc("well_enclosure_active")
self.implant_enclose_active = drc("implant_enclosure_active")
self.implant_space = drc("implant_to_implant")
+1 -2
View File
@@ -193,7 +193,7 @@ class instance(geometry):
blockages = []
blockages = self.mod.gds.getBlockages(lpp)
for b in blockages:
new_blockages.append(self.transform_coords(b,self.offset, mirr, angle))
new_blockages.append(self.transform_coords(vector(b),self.offset, mirr, angle))
else:
blockages = self.mod.get_blockages(lpp)
for b in blockages:
@@ -327,7 +327,6 @@ class label(geometry):
debug.info(4, "writing label (" + str(self.layerNumber) + "): " + self.text)
new_layout.addText(text=self.text,
layerNumber=self.layerNumber,
purposeNumber=self.layerPurpose,
offsetInMicrons=self.offset,
magnification=self.zoom,
rotate=None)
+5 -1
View File
@@ -939,7 +939,11 @@ class layout():
def add_boundary(self, offset=vector(0,0)):
""" Add boundary for debugging dimensions """
self.add_rect(layer="boundary",
if "stdc" in techlayer.keys():
boundary_layer = "stdc"
else:
boundary_layer = "boundary"
self.add_rect(layer=boundary_layer,
offset=offset,
height=self.height,
width=self.width)
-1
View File
@@ -344,7 +344,6 @@ class pin_layout:
# imported into Magic.
newLayout.addText(text=self.name,
layerNumber=layer_num,
purposeNumber=purpose,
offsetInMicrons=self.center(),
magnification=GDS["zoom"],
rotate=None)
+4 -4
View File
@@ -243,7 +243,7 @@ class pbitcell(bitcell_base.bitcell_base):
(self.inverter_nmos.active_contact.height - self.inverter_nmos.active_height)
self.inverter_gap = max(self.poly_to_active,
self.m1_space + inverter_nmos_contact_extension) \
+ self.poly_to_polycontact + 2 * contact.poly.width \
+ self.poly_to_poly_contact + 2 * contact.poly.width \
+ self.m1_space + inverter_pmos_contact_extension
self.cross_couple_lower_ypos = self.inverter_nmos_ypos \
+ self.inverter_nmos.active_height \
@@ -254,7 +254,7 @@ class pbitcell(bitcell_base.bitcell_base):
+ self.inverter_nmos.active_height \
+ max(self.poly_to_active,
self.m1_space + inverter_nmos_contact_extension) \
+ self.poly_to_polycontact \
+ self.poly_to_poly_contact \
+ 1.5 * contact.poly.width
# spacing between wordlines (and gnd)
@@ -926,14 +926,14 @@ class pbitcell(bitcell_base.bitcell_base):
"""
# add poly to metal1 contacts for gates of the inverters
left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x \
- self.poly_to_polycontact - 0.5*contact.poly.width,
- self.poly_to_poly_contact - 0.5*contact.poly.width,
self.cross_couple_upper_ypos)
self.add_via_center(layers=("poly", "contact", "metal1"),
offset=left_storage_contact,
directions=("H", "H"))
right_storage_contact = vector(self.inverter_nmos_right.get_pin("G").rc().x \
+ self.poly_to_polycontact + 0.5*contact.poly.width,
+ self.poly_to_poly_contact + 0.5*contact.poly.width,
self.cross_couple_upper_ypos)
self.add_via_center(layers=("poly", "contact", "metal1"),
offset=right_storage_contact,
+39 -6
View File
@@ -175,6 +175,8 @@ class Gds2reader:
def readBoundary(self):
##reads in a boundary type structure = a filled polygon
if(self.debugToTerminal==1):
print("\t\t\tBeginBoundary")
thisBoundary=GdsBoundary()
while 1:
record = self.readNextRecord()
@@ -201,11 +203,6 @@ class Gds2reader:
thisBoundary.purposeLayer=purposeLayer
if(self.debugToTerminal==1):
print("\t\tPurpose Layer: "+str(purposeLayer))
elif(idBits==b'\x0E\x02'): #DataType
dataType = struct.unpack(">h",record[2:4])[0]
thisBoundary.dataType=dataType
if(self.debugToTerminal==1):
print("\t\t\tData Type: "+str(dataType))
elif(idBits==b'\x10\x03'): #XY Data Points
numDataPoints = len(record)-2 #packed as XY coordinates 4 bytes each
thisBoundary.coordinates=[]
@@ -216,10 +213,15 @@ class Gds2reader:
if(self.debugToTerminal==1):
print("\t\t\tXY Point: "+str(x)+","+str(y))
elif(idBits==b'\x11\x00'): #End Of Element
if(self.debugToTerminal==1):
print("\t\t\tEndBoundary")
break;
return thisBoundary
def readPath(self): #reads in a path structure
if(self.debugToTerminal==1):
print("\t\t\tBeginPath")
thisPath=GdsPath()
while 1:
record = self.readNextRecord()
@@ -266,10 +268,15 @@ class Gds2reader:
if(self.debugToTerminal==1):
print("\t\t\tXY Point: "+str(x)+","+str(y))
elif(idBits==b'\x11\x00'): #End Of Element
if(self.debugToTerminal==1):
print("\t\t\tEndPath")
break;
return thisPath
def readSref(self): #reads in a reference to another structure
if(self.debugToTerminal==1):
print("\t\t\tBeginSref")
thisSref=GdsSref()
while 1:
record = self.readNextRecord()
@@ -317,10 +324,15 @@ class Gds2reader:
if(self.debugToTerminal==1):
print("\t\t\tXY Point: "+str(x)+","+str(y))
elif(idBits==b'\x11\x00'): #End Of Element
if(self.debugToTerminal==1):
print("\t\t\tEndSref")
break;
return thisSref
def readAref(self): #an array of references
if(self.debugToTerminal==1):
print("\t\t\tBeginAref")
thisAref = GdsAref()
while 1:
record = self.readNextRecord()
@@ -372,11 +384,15 @@ class Gds2reader:
print("\t\t\t\tArray Width: "+str(rightMostX-topLeftX))
print("\t\t\t\tArray Height: "+str(topLeftY-bottomMostY))
elif(idBits==b'\x11\x00'): #End Of Element
if(self.debugToTerminal==1):
print("\t\t\tEndAref")
break;
return thisAref
def readText(self):
##reads in a text structure
if(self.debugToTerminal==1):
print("\t\t\tBeginText")
thisText=GdsText()
while 1:
record = self.readNextRecord()
@@ -472,10 +488,15 @@ class Gds2reader:
if(self.debugToTerminal==1):
print("\t\t\tText String: "+textString)
elif(idBits==b'\x11\x00'): #End Of Element
if(self.debugToTerminal==1):
print("\t\t\tEndText")
break;
return thisText
def readNode(self):
if(self.debugToTerminal==1):
print("\t\t\tBeginNode")
##reads in a node type structure = an electrical net
thisNode = GdsNode()
while 1:
@@ -513,10 +534,15 @@ class Gds2reader:
if(self.debugToTerminal==1):
print("\t\t\tXY Point: "+str(x)+","+str(y))
elif(idBits==b'\x11\x00'): #End Of Element
if(self.debugToTerminal==1):
print("\t\t\tEndNode")
break;
return thisNode
def readBox(self):
if(self.debugToTerminal==1):
print("\t\t\tBeginBox")
##reads in a gds BOX structure
thisBox = GdsBox()
while 1:
@@ -559,6 +585,8 @@ class Gds2reader:
if(self.debugToTerminal==1):
print("\t\t\tXY Point: "+str(x)+","+str(y))
elif(idBits==b'\x11\x00'): #End Of Element
if(self.debugToTerminal==1):
print("\t\t\tEndBox")
break;
return thisBox
@@ -566,6 +594,7 @@ class Gds2reader:
thisStructure = GdsStructure()
record = self.readNextRecord()
idBits = record[0:2]
# Begin structure
if(idBits==b'\x05\x02' and len(record)==26):
createYear = struct.unpack(">h",record[2:4])[0]
createMonth = struct.unpack(">h",record[4:6])[0]
@@ -581,6 +610,10 @@ class Gds2reader:
modSecond = struct.unpack(">h",record[24:26])[0]
thisStructure.createDate=(createYear,createMonth,createDay,createHour,createMinute,createSecond)
thisStructure.modDate=(modYear,modMonth,modDay,modHour,modMinute,modSecond)
if(self.debugToTerminal==1):
print("Date Created:"+str(createYear)+","+str(createMonth)+","+str(createDay)+\
","+str(createHour)+","+str(createMinute)+","+str(createSecond))
print("Date Modified:"+str(modYear)+","+str(modMonth)+","+str(modDay)+","+str(modHour)+","+str(modMinute)+","+str(modSecond))
else:
#means we have hit the last structure, so return the record
#to whoever called us to do something with it
+11 -13
View File
@@ -187,27 +187,25 @@ class Gds2writer:
idBits=b'\x08\x00' #record Type
self.writeRecord(idBits)
if(thisBoundary.elementFlags!=""):
idBits=b'\x26\x01' #ELFLAGS
idBits=b'\x26\x01' # ELFLAGS
elementFlags = struct.pack(">h",thisBoundary.elementFlags)
self.writeRecord(idBits+elementFlags)
if(thisBoundary.plex!=""):
idBits=b'\x2F\x03' #PLEX
idBits=b'\x2F\x03' # PLEX
plex = struct.pack(">i",thisBoundary.plex)
self.writeRecord(idBits+plex)
if(thisBoundary.drawingLayer!=""):
idBits=b'\x0D\x02' #drawig layer
idBits=b'\x0D\x02' # drawing layer
drawingLayer = struct.pack(">h",thisBoundary.drawingLayer)
self.writeRecord(idBits+drawingLayer)
if(thisBoundary.purposeLayer):
idBits=b'\x16\x02' #purpose layer
purposeLayer = struct.pack(">h",thisBoundary.purposeLayer)
self.writeRecord(idBits+purposeLayer)
if(thisBoundary.dataType!=""):
idBits=b'\x0E\x02'#DataType
dataType = struct.pack(">h",thisBoundary.dataType)
if(thisBoundary.purposeLayer!=""):
idBits=b'\x0E\x02' # DataType
if type(thisBoundary.purposeLayer)!=int:
import pdb; pdb.set_trace()
dataType = struct.pack(">h",thisBoundary.purposeLayer)
self.writeRecord(idBits+dataType)
if(thisBoundary.coordinates!=""):
idBits=b'\x10\x03' #XY Data Points
idBits=b'\x10\x03' # XY Data Points
coordinateRecord = idBits
for coordinate in thisBoundary.coordinates:
x=struct.pack(">i",int(coordinate[0]))
@@ -377,9 +375,9 @@ class Gds2writer:
idBits=b'\x0D\x02' #drawing layer
drawingLayer = struct.pack(">h",thisText.drawingLayer)
self.writeRecord(idBits+drawingLayer)
#if(thisText.purposeLayer):
# TextType is always a 0 per GDS specification
idBits=b'\x16\x02' #purpose layer
purposeLayer = struct.pack(">h",thisText.purposeLayer)
purposeLayer = struct.pack(">h",0)
self.writeRecord(idBits+purposeLayer)
if(thisText.transFlags != ""):
idBits=b'\x1A\x01'
+4 -5
View File
@@ -21,8 +21,7 @@ class GdsBoundary:
self.elementFlags=""
self.plex=""
self.drawingLayer=""
self.purposeLayer = None
self.dataType=""
self.purposeLayer=0
self.coordinates=""
class GdsPath:
@@ -31,7 +30,7 @@ class GdsPath:
self.elementFlags=""
self.plex=""
self.drawingLayer=""
self.purposeLayer = None
self.purposeLayer=0
self.pathType=""
self.pathWidth=""
self.coordinates=""
@@ -140,7 +139,7 @@ class GdsText:
self.elementFlags=""
self.plex=""
self.drawingLayer=""
self.purposeLayer = None
self.purposeLayer=0
self.transFlags=[0,0,0]
self.magFactor=""
self.rotateAngle=""
@@ -165,6 +164,6 @@ class GdsBox:
self.elementFlags=""
self.plex=""
self.drawingLayer=""
self.purposeLayer = None
self.purposeLayer=0
self.boxValue=""
self.coordinates=""
+4 -8
View File
@@ -2,7 +2,6 @@ from .gdsPrimitives import *
from datetime import *
#from mpmath import matrix
#from numpy import matrix
from vector import vector
import numpy as np
#import gdsPrimitives
import debug
@@ -358,7 +357,7 @@ class VlsiLayout:
#add the sref to the root structure
self.structures[self.rootStructureName].srefs.append(layoutToAddSref)
def addBox(self,layerNumber=0, purposeNumber=None, offsetInMicrons=(0,0), width=1.0, height=1.0,center=False):
def addBox(self,layerNumber=0, purposeNumber=0, offsetInMicrons=(0,0), width=1.0, height=1.0,center=False):
"""
Method to add a box to a layout
"""
@@ -383,13 +382,12 @@ class VlsiLayout:
boundaryToAdd = GdsBoundary()
boundaryToAdd.drawingLayer = layerNumber
boundaryToAdd.dataType = 0
boundaryToAdd.coordinates = coordinates
boundaryToAdd.purposeLayer = purposeNumber
#add the sref to the root structure
self.structures[self.rootStructureName].boundaries.append(boundaryToAdd)
def addPath(self, layerNumber=0, purposeNumber=None, coordinates=[(0,0)], width=1.0):
def addPath(self, layerNumber=0, purposeNumber=0, coordinates=[(0,0)], width=1.0):
"""
Method to add a path to a layout
"""
@@ -408,12 +406,10 @@ class VlsiLayout:
#add the sref to the root structure
self.structures[self.rootStructureName].paths.append(pathToAdd)
def addText(self, text, layerNumber=0, purposeNumber=None, offsetInMicrons=(0,0), magnification=0.1, rotate = None):
def addText(self, text, layerNumber=0, offsetInMicrons=(0,0), magnification=0.1, rotate = None):
offsetInLayoutUnits = (self.userUnits(offsetInMicrons[0]),self.userUnits(offsetInMicrons[1]))
textToAdd = GdsText()
textToAdd.drawingLayer = layerNumber
textToAdd.purposeLayer = purposeNumber
textToAdd.dataType = 0
textToAdd.coordinates = [offsetInLayoutUnits]
textToAdd.transFlags = [0,0,0]
textToAdd.textString = self.padText(text)
@@ -757,7 +753,7 @@ class VlsiLayout:
for boundary in shapes:
vectors = []
for i in range(0, len(boundary), 2):
vectors.append(vector(boundary[i], boundary[i+1]))
vectors.append((boundary[i], boundary[i+1]))
blockages.append(vectors)
return blockages
+4 -4
View File
@@ -124,18 +124,18 @@ class ptx(design.design):
# The contacted poly pitch (or uncontacted in an odd technology)
self.poly_pitch = max(2 * self.contact_to_gate + self.contact_width + self.poly_width,
self.poly_pitch = max(2 * self.active_contact_to_gate + self.contact_width + self.poly_width,
self.poly_space)
# The contacted poly pitch (or uncontacted in an odd technology)
self.contact_pitch = 2 * self.contact_to_gate + self.contact_width + self.poly_width
self.contact_pitch = 2 * self.active_contact_to_gate + self.contact_width + self.poly_width
# The enclosure of an active contact. Not sure about second term.
active_enclose_contact = max(drc("active_enclosure_contact"),
active_enclose_contact = max(drc("active_enclosure_active_contact"),
(self.active_width - self.contact_width) / 2)
# This is the distance from the edge of poly to the contacted end of active
self.end_to_poly = active_enclose_contact + self.contact_width + self.contact_to_gate
self.end_to_poly = active_enclose_contact + self.contact_width + self.active_contact_to_gate
# Active width is determined by enclosure on both ends and contacted pitch,