From 73289a60901bf6bdc622c9305ceecd82f80e1ce0 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 29 Aug 2018 15:32:45 -0700 Subject: [PATCH] Clean up GdsMill. Fix rotate bug I introduced in transFlags! --- compiler/base/hierarchy_layout.py | 2 +- compiler/gdsMill/gdsMill/gdsPrimitives.py | 8 +- compiler/gdsMill/gdsMill/vlsiLayout.py | 91 ++++++++------------ compiler/router/router.py | 26 ++++-- compiler/router/signal_router.py | 5 +- compiler/router/supply_router.py | 6 +- compiler/router/tests/10_supply_grid_test.py | 12 +-- compiler/router/tests/config_freepdk45.py | 21 +---- compiler/router/tests/config_scn3me_subm.py | 20 +---- 9 files changed, 81 insertions(+), 110 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 2e7a7761..01a48f89 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -845,7 +845,7 @@ class layout(lef.lef): def add_power_pin(self, name, loc, rotate=90): """ - Add a single power pin from M3 own to M1 at the given center location + Add a single power pin from M3 down to M1 at the given center location """ self.add_via_center(layers=("metal1", "via1", "metal2"), offset=loc, diff --git a/compiler/gdsMill/gdsMill/gdsPrimitives.py b/compiler/gdsMill/gdsMill/gdsPrimitives.py index c0981acd..9b148dce 100644 --- a/compiler/gdsMill/gdsMill/gdsPrimitives.py +++ b/compiler/gdsMill/gdsMill/gdsPrimitives.py @@ -118,7 +118,7 @@ class GdsSref: self.elementFlags="" self.plex="" self.sName="" - self.transFlags=(False,False,False) + self.transFlags=[0,0,0] self.magFactor="" self.rotateAngle="" self.coordinates="" @@ -129,7 +129,7 @@ class GdsAref: self.elementFlags="" self.plex="" self.aName="" - self.transFlags=(False,False,False) + self.transFlags=[0,0,0] self.magFactor="" self.rotateAngle="" self.coordinates="" @@ -141,7 +141,7 @@ class GdsText: self.plex="" self.drawingLayer="" self.purposeLayer = None - self.transFlags=(False,False,False) + self.transFlags=[0,00] self.magFactor="" self.rotateAngle="" self.pathType="" @@ -167,4 +167,4 @@ class GdsBox: self.drawingLayer="" self.purposeLayer = None self.boxValue="" - self.coordinates="" \ No newline at end of file + self.coordinates="" diff --git a/compiler/gdsMill/gdsMill/vlsiLayout.py b/compiler/gdsMill/gdsMill/vlsiLayout.py index 4b498bb8..3a97c0c0 100644 --- a/compiler/gdsMill/gdsMill/vlsiLayout.py +++ b/compiler/gdsMill/gdsMill/vlsiLayout.py @@ -70,7 +70,7 @@ class VlsiLayout: for coordinate in coordinatesToRotate: newX = coordinate[0]*math.cos(angle) - coordinate[1]*math.sin(angle) newY = coordinate[0]*math.sin(angle) + coordinate[1]*math.cos(angle) - coordinatesRotate += [(newX,newY)] + coordinatesRotate.extend((newX,newY)) return coordinatesRotate def rename(self,newName): @@ -141,7 +141,7 @@ class VlsiLayout: contained by any other structure. this is the root.""" structureNames=[] for name in self.structures: - structureNames+=[name] + structureNames.append(name) for name in self.structures: if(len(self.structures[name].srefs)>0): #does this structure reference any others? @@ -162,7 +162,8 @@ class VlsiLayout: if(rotateAngle == None or rotateAngle == ""): angle = 0 else: - angle = math.radians(float(rotateAngle)) + # MRG: Added negative to make CCW rotate 8/29/18 + angle = math.radians(-1.0*float(rotateAngle)) mRotate = matrix([[math.cos(angle),-math.sin(angle),0.0], [math.sin(angle),math.cos(angle),0.0], [0.0,0.0,1.0]]) @@ -180,7 +181,7 @@ class VlsiLayout: #we need to keep track of all transforms in the hierarchy #when we add an element to the xy tree, we apply all transforms from the bottom up - transformPath += [(mRotate,mScale,mTranslate)] + transformPath.append((mRotate,mScale,mTranslate)) if delegateFunction != None: delegateFunction(startingStructureName, transformPath) #starting with a particular structure, we will recursively traverse the tree @@ -226,8 +227,10 @@ class VlsiLayout: vVector = transform[1] * vVector #scale origin = transform[2] * origin #translate #we don't need to do a translation on the basis vectors - self.xyTree+=[(startingStructureName,origin,uVector,vVector)] #populate the xyTree with each - #structureName and coordinate space + #uVector = transform[2] * uVector #translate + #vVector = transform[2] * vVector #translate + #populate the xyTree with each structureName and coordinate space + self.xyTree.append((startingStructureName,origin,uVector,vVector)) self.traverseTheHierarchy(delegateFunction = addToXyTree) def microns(self,userUnits): @@ -303,7 +306,7 @@ class VlsiLayout: #also combine the "layers in use" list for layerNumber in layoutToAdd.layerNumbersInUse: if layerNumber not in self.layerNumbersInUse: - self.layerNumbersInUse += [layerNumber] + self.layerNumbersInUse.append(layerNumber) # if debug: print("DEBUG: vlsilayout: Using %d layers") @@ -314,7 +317,9 @@ class VlsiLayout: layoutToAddSref.coordinates = offsetInLayoutUnits if mirror or rotate: - # transFlags = (mirror around x-axis, magnification, rotation) + # 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) # If magnification or rotation is true, it is the flags are then # followed by an amount in the record if mirror=="R90": @@ -326,19 +331,20 @@ class VlsiLayout: layoutToAddSref.transFlags = [0,0,0] if rotate: - layoutToAddSref.transFlags = [0,0,1] + layoutToAddSref.transFlags = [0,1,0] layoutToAddSref.rotateAngle = rotate if mirror == "x" or mirror == "MX": layoutToAddSref.transFlags = [1,0,0] if mirror == "y" or mirror == "MY": #NOTE: "MY" option will override specified rotate angle - layoutToAddSref.transFlags = [1,0,1] + layoutToAddSref.transFlags = [1,1,0] + #layoutToAddSref.transFlags = [1,0,0] layoutToAddSref.rotateAngle = 180.0 if mirror == "xy" or mirror == "XY": #NOTE: "XY" option will override specified rotate angle - layoutToAddSref.transFlags = [0,0,1] + layoutToAddSref.transFlags = [0,1,0] layoutToAddSref.rotateAngle = 180.0 #add the sref to the root structure - self.structures[self.rootStructureName].srefs+=[layoutToAddSref] + 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): """ @@ -356,11 +362,7 @@ class VlsiLayout: (offsetInLayoutUnits[0],offsetInLayoutUnits[1]+heightInLayoutUnits), offsetInLayoutUnits] else: - - #is there where gdsmill is halving the coordinates??? - #if you printGDS of temp.gds, the header says 1 user unit = .0005 database units. By default user units = .001. - #something to do with the ieeedouble in gdswriter.py???? - startPoint = (offsetInLayoutUnits[0]-widthInLayoutUnits/2, offsetInLayoutUnits[1]-heightInLayoutUnits/2) #width/2 height/2 + startPoint = (offsetInLayoutUnits[0]-widthInLayoutUnits/2.0, offsetInLayoutUnits[1]-heightInLayoutUnits/2.0) coordinates=[startPoint, (startPoint[0]+widthInLayoutUnits,startPoint[1]), (startPoint[0]+widthInLayoutUnits,startPoint[1]+heightInLayoutUnits), @@ -373,7 +375,7 @@ class VlsiLayout: boundaryToAdd.coordinates = coordinates boundaryToAdd.purposeLayer = purposeNumber #add the sref to the root structure - self.structures[self.rootStructureName].boundaries+=[boundaryToAdd] + self.structures[self.rootStructureName].boundaries.append(boundaryToAdd) def addPath(self, layerNumber=0, purposeNumber = None, coordinates=[(0,0)], width=1.0): """ @@ -385,14 +387,14 @@ class VlsiLayout: for coordinate in coordinates: cX = self.userUnits(coordinate[0]) cY = self.userUnits(coordinate[1]) - layoutUnitCoordinates += [(cX,cY)] + layoutUnitCoordinates.append((cX,cY)) pathToAdd = GdsPath() pathToAdd.drawingLayer=layerNumber pathToAdd.purposeLayer = purposeNumber pathToAdd.pathWidth=widthInLayoutUnits pathToAdd.coordinates=layoutUnitCoordinates #add the sref to the root structure - self.structures[self.rootStructureName].paths+=[pathToAdd] + self.structures[self.rootStructureName].paths.append(pathToAdd) def addText(self, text, layerNumber=0, purposeNumber = None, offsetInMicrons=(0,0), magnification=0.1, rotate = None): offsetInLayoutUnits = (self.userUnits(offsetInMicrons[0]),self.userUnits(offsetInMicrons[1])) @@ -411,7 +413,7 @@ class VlsiLayout: textToAdd.transFlags[2] = 1 textToAdd.rotateAngle = rotate #add the sref to the root structure - self.structures[self.rootStructureName].texts+=[textToAdd] + self.structures[self.rootStructureName].texts.append(textToAdd) def isBounded(self,testPoint,startPoint,endPoint): #these arguments are touples of (x,y) coordinates @@ -523,7 +525,7 @@ class VlsiLayout: #remap coordinates shiftedBoundaryCoordinates = [] for shapeCoordinate in boundary.rotatedCoordinates(rotateAngle): - shiftedBoundaryCoordinates+=[(shapeCoordinate[0]+coordinates[0],shapeCoordinate[1]+coordinates[1])] + shiftedBoundaryCoordinates.append((shapeCoordinate[0]+coordinates[0],shapeCoordinate[1]+coordinates[1])) joint = self.doShapesIntersect(self.tempCoordinates, shiftedBoundaryCoordinates) if joint: self.tempPassFail = False @@ -536,7 +538,7 @@ class VlsiLayout: #remap coordinates shiftedBoundaryCoordinates = [] for shapeCoordinate in path.equivalentBoundaryCoordinates(rotateAngle): - shiftedBoundaryCoordinates+=[(shapeCoordinate[0]+coordinates[0],shapeCoordinate[1]+coordinates[1])] + shiftedBoundaryCoordinates.append((shapeCoordinate[0]+coordinates[0],shapeCoordinate[1]+coordinates[1])) joint = self.doShapesIntersect(self.tempCoordinates, shiftedBoundaryCoordinates) if joint: self.tempPassFail = False @@ -559,7 +561,7 @@ class VlsiLayout: self.traverseTheHierarchy(delegateFunction = isThisBlockOk) #if its bad, this global tempPassFail will be false #if true, we can add the block - passFailRecord+=[self.tempPassFail] + passFailRecord.append(self.tempPassFail) print("Percent Complete:"+str(percentDone)) @@ -570,7 +572,7 @@ class VlsiLayout: blockY = (yIndex*effectiveBlock)+offsetInMicrons[1] if passFailRecord[passFailIndex]: self.addBox(layerToFill, (blockX,blockY), width=blockSize, height=blockSize) - passFailIndex+=1 + passFailIndex += 1 print("Done\n\n") def getLayoutBorder(self,borderlayer): @@ -606,19 +608,15 @@ class VlsiLayout: return [[self.units[0]*cellBoundary[0],self.units[0]*cellBoundary[1]], [self.units[0]*cellBoundary[2],self.units[0]*cellBoundary[3]]] - def measureSizeInStructure(self,Structure,cellBoundary): - StructureName=Structure[0] - StructureOrigin=[Structure[1][0],Structure[1][1]] - StructureuVector=[Structure[2][0],Structure[2][1],Structure[2][2]] - StructurevVector=[Structure[3][0],Structure[3][1],Structure[3][2]] - - for boundary in self.structures[str(StructureName)].boundaries: + def measureSizeInStructure(self,structure,cellBoundary): + (structureName,structureOrigin,structureuVector,structurevVector)=structure + for boundary in self.structures[str(structureName)].boundaries: left_bottom=boundary.coordinates[0] right_top=boundary.coordinates[2] thisBoundary=[left_bottom[0],left_bottom[1],right_top[0],right_top[1]] - thisBoundary=self.transformRectangle(thisBoundary,StructureuVector,StructurevVector) - thisBoundary=[thisBoundary[0]+StructureOrigin[0],thisBoundary[1]+StructureOrigin[1], - thisBoundary[2]+StructureOrigin[0],thisBoundary[3]+StructureOrigin[1]] + thisBoundary=self.transformRectangle(thisBoundary,structureuVector,structurevVector) + thisBoundary=[thisBoundary[0]+structureOrigin[0],thisBoundary[1]+structureOrigin[1], + thisBoundary[2]+structureOrigin[0],thisBoundary[3]+structureOrigin[1]] cellBoundary=self.updateBoundary(thisBoundary,cellBoundary) return cellBoundary @@ -755,9 +753,8 @@ class VlsiLayout: Return all pin shapes. """ boundaries = [] - for TreeUnit in self.xyTree: - boundaries += self.getPinInStructure(coordinates,layer,TreeUnit) + boundaries.extend(self.getPinInStructure(coordinates,layer,TreeUnit)) return boundaries @@ -768,14 +765,8 @@ class VlsiLayout: that the label coordinates are inside. """ - # check if this is a rectangle - structureName=structure[0] - structureOrigin=[structure[1][0],structure[1][1]] - structureuVector=[structure[2][0],structure[2][1],structure[2][2]] - structurevVector=[structure[3][0],structure[3][1],structure[3][2]] - + (structureName,structureOrigin,structureuVector,structurevVector)=structure 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. @@ -789,7 +780,7 @@ class VlsiLayout: boundaryRect=self.transformRectangle(boundaryRect,structureuVector,structurevVector) boundaryRect=[boundaryRect[0]+structureOrigin[0].item(),boundaryRect[1]+structureOrigin[1].item(), boundaryRect[2]+structureOrigin[0].item(),boundaryRect[3]+structureOrigin[1].item()] - + if self.labelInRectangle(coordinates,boundaryRect): boundaries.append(boundaryRect) @@ -803,7 +794,7 @@ class VlsiLayout: boundaries = [] for TreeUnit in self.xyTree: #print(TreeUnit[0]) - boundaries += self.getShapesInStructure(layer,TreeUnit) + boundaries.extend(self.getShapesInStructure(layer,TreeUnit)) # Remove duplicates without defining a hash # (could be sped up by creating hash and using list(set()) @@ -826,14 +817,8 @@ class VlsiLayout: Go through all the shapes in a structure and return the list of shapes. """ - # check if this is a rectangle - structureName=structure[0] - structureOrigin=[structure[1][0],structure[1][1]] - structureuVector=[structure[2][0],structure[2][1],structure[2][2]] - structurevVector=[structure[3][0],structure[3][1],structure[3][2]] - + (structureName,structureOrigin,structureuVector,structurevVector)=structure 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. diff --git a/compiler/router/router.py b/compiler/router/router.py index 40e93df1..d049976b 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -15,12 +15,21 @@ class router: It populates blockages on a grid class. """ - def __init__(self, gds_name): - """Use the gds file for the blockages with the top module topName and + def __init__(self, gds_name=None, module=None): + """Use the gds file or the cell for the blockages with the top module topName and layers for the layers to route on """ - # Load the gds file and read in all the shapes self.gds_name = gds_name + self.module = module + debug.check(not (gds_name and module), "Specify only a GDS file or module") + + # If we specified a module instead, write it out to read the gds + # This isn't efficient, but easy for now + if module: + gds_name = OPTS.openram_temp+"temp.gds" + module.gds_write(gds_name) + + # Load the gds file and read in all the shapes self.layout = gdsMill.VlsiLayout(units=tech.GDS["unit"]) self.reader = gdsMill.Gds2reader(self.layout) self.reader.loadFromFile(gds_name) @@ -212,12 +221,14 @@ class router: """ shapes = self.layout.getAllShapesInStructureList(layer_num) - + for boundary in shapes: - rect = [vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])] - new_pin = pin_layout("blockage",rect,layer_num) + ll = vector(boundary[0],boundary[1]) + ur = vector(boundary[2],boundary[3]) + 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) @@ -470,7 +481,6 @@ class router: layer="text", offset=shape[0], zoom=0.05) - for blockage in self.blockages: self.cell.add_rect(layer="boundary", offset=blockage.ll(), diff --git a/compiler/router/signal_router.py b/compiler/router/signal_router.py index 3358d75f..ebc85eb6 100644 --- a/compiler/router/signal_router.py +++ b/compiler/router/signal_router.py @@ -14,11 +14,11 @@ class signal_router(router): route on a given layer. This is limited to two layer routes. """ - def __init__(self, gds_name): + def __init__(self, gds_name=None, module=None): """Use the gds file for the blockages with the top module topName and layers for the layers to route on """ - router.__init__(self, gds_name) + router.__init__(self, gds_name, module) # all the paths we've routed so far (to supplement the blockages) self.paths = [] @@ -43,6 +43,7 @@ class signal_router(router): the simplified rectilinear path. Cost factor is how sub-optimal to explore for a feasible route. This is used to speed up the routing when there is not much detouring needed. """ + debug.info(1,"Running signal router from {0} to {1}...".format(src,dest)) self.cell = cell self.source_pin_name = src self.target_pin_name = dest diff --git a/compiler/router/supply_router.py b/compiler/router/supply_router.py index ff505a78..908e8686 100644 --- a/compiler/router/supply_router.py +++ b/compiler/router/supply_router.py @@ -16,12 +16,11 @@ class supply_router(router): routes a grid to connect the supply on the two layers. """ - def __init__(self, gds_name): + def __init__(self, gds_name=None, module=None): """Use the gds file for the blockages with the top module topName and layers for the layers to route on """ - - router.__init__(self, gds_name) + router.__init__(self, gds_name, module) self.pins = {} @@ -40,6 +39,7 @@ class supply_router(router): Route a single source-destination net and return the simplified rectilinear path. """ + debug.info(1,"Running supply router on {0} and {1}...".format(vdd_name, gnd_name)) self.cell = cell self.pins[vdd_name] = [] self.pins[gnd_name] = [] diff --git a/compiler/router/tests/10_supply_grid_test.py b/compiler/router/tests/10_supply_grid_test.py index 91c892b0..485d925c 100755 --- a/compiler/router/tests/10_supply_grid_test.py +++ b/compiler/router/tests/10_supply_grid_test.py @@ -4,7 +4,6 @@ import unittest from testutils import header,openram_test import sys,os -sys.path.append(os.path.join(sys.path[0],"../..")) sys.path.append(os.path.join(sys.path[0],"..")) import globals import debug @@ -30,14 +29,17 @@ class no_blockages_test(openram_test): design.__init__(self, "top") # Instantiate a GDS cell with the design - gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) - cell = gds_cell(name, gds_file) + globals.setup_paths() + from control_logic import control_logic + cell = control_logic(16) + #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([]) + self.connect_inst(["csb","web","clk","s_en","w_en","clk_buf_bar","clk_buf","vdd","gnd"]) - r=router(gds_file) + r=router(module=cell) layer_stack =("metal3","via2","metal2") self.assertTrue(r.route(self,layer_stack)) diff --git a/compiler/router/tests/config_freepdk45.py b/compiler/router/tests/config_freepdk45.py index 1217a677..d7e1880e 100755 --- a/compiler/router/tests/config_freepdk45.py +++ b/compiler/router/tests/config_freepdk45.py @@ -3,21 +3,8 @@ num_words = 16 num_banks = 1 tech_name = "freepdk45" +process_corners = ["TT"] +supply_voltages = [1.0] +temperatures = [25] + -decoder = "hierarchical_decoder" -ms_flop = "ms_flop" -ms_flop_array = "ms_flop_array" -control_logic = "control_logic" -bitcell_array = "bitcell_array" -sense_amp = "sense_amp" -sense_amp_array = "sense_amp_array" -precharge_array = "precharge_array" -column_mux_array = "single_level_column_mux_array" -write_driver = "write_driver" -write_driver_array = "write_driver_array" -tri_gate = "tri_gate" -tri_gate_array = "tri_gate_array" -wordline_driver = "wordline_driver" -replica_bitcell = "replica_bitcell" -bitcell = "bitcell" -delay_chain = "logic_effort_dc" diff --git a/compiler/router/tests/config_scn3me_subm.py b/compiler/router/tests/config_scn3me_subm.py index d7618847..40addd69 100755 --- a/compiler/router/tests/config_scn3me_subm.py +++ b/compiler/router/tests/config_scn3me_subm.py @@ -3,21 +3,7 @@ num_words = 16 num_banks = 1 tech_name = "scn3me_subm" +process_corners = ["TT"] +supply_voltages = [5.0] +temperatures = [25] -decoder = "hierarchical_decoder" -ms_flop = "ms_flop" -ms_flop_array = "ms_flop_array" -control_logic = "control_logic" -bitcell_array = "bitcell_array" -sense_amp = "sense_amp" -sense_amp_array = "sense_amp_array" -precharge_array = "precharge_array" -column_mux_array = "single_level_column_mux_array" -write_driver = "write_driver" -write_driver_array = "write_driver_array" -tri_gate = "tri_gate" -tri_gate_array = "tri_gate_array" -wordline_driver = "wordline_driver" -replica_bitcell = "replica_bitcell" -bitcell = "bitcell" -delay_chain = "logic_effort_dc"