Add layer-purpose GDS support. Various PEP8 fixes.

This commit is contained in:
Matthew Guthaus 2019-11-14 18:17:20 +00:00
parent bba6995653
commit 131f4bda4a
11 changed files with 267 additions and 198 deletions

View File

@ -28,8 +28,8 @@ class pin_layout:
# snap the rect to the grid # snap the rect to the grid
self.rect = [x.snap_to_grid() for x in self.rect] self.rect = [x.snap_to_grid() for x in self.rect]
debug.check(self.width() > 0,"Zero width pin.") debug.check(self.width() > 0, "Zero width pin.")
debug.check(self.height() > 0,"Zero height pin.") debug.check(self.height() > 0, "Zero height pin.")
# if it's a string, use the name # if it's a string, use the name
if type(layer_name_pp) == str: if type(layer_name_pp) == str:
@ -37,7 +37,7 @@ class pin_layout:
# else it is required to be a lpp # else it is required to be a lpp
else: else:
for (layer_name, lpp) in layer.items(): for (layer_name, lpp) in layer.items():
if layer_name_pp[0] == lpp[0] and (not layer_name_pp[1] or layer_name_pp[1]==lpp[1]): if self.same_lpp(layer_name_pp, lpp):
self.layer = layer_name self.layer = layer_name
break break
else: else:
@ -78,7 +78,7 @@ class pin_layout:
def __eq__(self, other): def __eq__(self, other):
""" Check if these are the same pins for duplicate checks """ """ Check if these are the same pins for duplicate checks """
if isinstance(other, self.__class__): if isinstance(other, self.__class__):
return (self.layer == other.layer and self.rect == other.rect) return (self.lpp == other.lpp and self.rect == other.rect)
else: else:
return False return False
@ -177,7 +177,7 @@ class pin_layout:
return True return True
# Can only overlap on the same layer # Can only overlap on the same layer
if self.layer != other.layer: if not self.same_lpp(self.lpp, other.lpp):
return False return False
if not self.xcontains(other): if not self.xcontains(other):
@ -198,7 +198,7 @@ class pin_layout:
def overlaps(self, other): def overlaps(self, other):
""" Check if a shape overlaps with a rectangle """ """ Check if a shape overlaps with a rectangle """
# Can only overlap on the same layer # Can only overlap on the same layer
if self.layer != other.layer: if not self.same_lpp(self.lpp, other.lpp):
return False return False
x_overlaps = self.xoverlaps(other) x_overlaps = self.xoverlaps(other)
@ -506,3 +506,13 @@ class pin_layout:
return r return r
return None return None
def same_lpp(self, lpp1, lpp2):
"""
Check if the layers and purposes are the same.
Ignore if purpose is a None.
"""
if lpp1[1] == None or lpp2[1] == None:
return lpp1[0] == lpp2[0]
return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1]

View File

@ -5,7 +5,6 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import os
import gdsMill import gdsMill
import tech import tech
import math import math
@ -16,6 +15,7 @@ from pin_layout import pin_layout
OPTS = globals.OPTS OPTS = globals.OPTS
def ceil(decimal): def ceil(decimal):
""" """
Performs a ceiling function on the decimal place specified by the DRC grid. Performs a ceiling function on the decimal place specified by the DRC grid.
@ -23,27 +23,33 @@ def ceil(decimal):
grid = tech.drc["grid"] grid = tech.drc["grid"]
return math.ceil(decimal * 1 / grid) / (1 / grid) return math.ceil(decimal * 1 / grid) / (1 / grid)
def round_to_grid(number): def round_to_grid(number):
""" """
Rounds an arbitrary number to the grid. Rounds an arbitrary number to the grid.
""" """
grid = tech.drc["grid"] grid = tech.drc["grid"]
# this gets the nearest integer value # this gets the nearest integer value
number_grid = int(round(round((number / grid), 2), 0)) number_grid = int(round(round((number / grid), 2), 0))
number_off = number_grid * grid number_off = number_grid * grid
return number_off return number_off
def snap_to_grid(offset): def snap_to_grid(offset):
""" """
Changes the coodrinate to match the grid settings Changes the coodrinate to match the grid settings
""" """
return [round_to_grid(offset[0]),round_to_grid(offset[1])] return [round_to_grid(offset[0]),
round_to_grid(offset[1])]
def pin_center(boundary): def pin_center(boundary):
""" """
This returns the center of a pin shape in the vlsiLayout border format. This returns the center of a pin shape in the vlsiLayout border format.
""" """
return [0.5 * (boundary[0] + boundary[2]), 0.5 * (boundary[1] + boundary[3])] return [0.5 * (boundary[0] + boundary[2]),
0.5 * (boundary[1] + boundary[3])]
def auto_measure_libcell(pin_list, name, units, lpp): def auto_measure_libcell(pin_list, name, units, lpp):
""" """
@ -57,35 +63,34 @@ def auto_measure_libcell(pin_list, name, units, lpp):
cell = {} cell = {}
measure_result = cell_vlsi.getLayoutBorder(lpp[0]) measure_result = cell_vlsi.getLayoutBorder(lpp[0])
if measure_result == None: if measure_result:
measure_result = cell_vlsi.measureSize(name) measure_result = cell_vlsi.measureSize(name)
[cell["width"], cell["height"]] = measure_result [cell["width"], cell["height"]] = measure_result
for pin in pin_list: for pin in pin_list:
(name,lpp,boundary)=cell_vlsi.getPinShapeByLabel(str(pin)) (name, lpp, boundary) = cell_vlsi.getPinShapeByLabel(str(pin))
cell[str(pin)] = pin_center(boundary) cell[str(pin)] = pin_center(boundary)
return cell return cell
def get_gds_size(name, gds_filename, units, lpp): def get_gds_size(name, gds_filename, units, lpp):
""" """
Open a GDS file and return the size from either the Open a GDS file and return the size from either the
bounding box or a border layer. bounding box or a border layer.
""" """
debug.info(4,"Creating VLSI layout for {}".format(name)) debug.info(4, "Creating VLSI layout for {}".format(name))
cell_vlsi = gdsMill.VlsiLayout(units=units) cell_vlsi = gdsMill.VlsiLayout(units=units)
reader = gdsMill.Gds2reader(cell_vlsi) reader = gdsMill.Gds2reader(cell_vlsi)
reader.loadFromFile(gds_filename) reader.loadFromFile(gds_filename)
cell = {}
measure_result = cell_vlsi.getLayoutBorder(lpp) measure_result = cell_vlsi.getLayoutBorder(lpp)
if measure_result == None: if not measure_result:
debug.info(2,"Layout border failed. Trying to measure size for {}".format(name)) debug.info(2, "Layout border failed. Trying to measure size for {}".format(name))
measure_result = cell_vlsi.measureSize(name) measure_result = cell_vlsi.measureSize(name)
# returns width,height # returns width,height
return measure_result return measure_result
def get_libcell_size(name, units, lpp): def get_libcell_size(name, units, lpp):
""" """
Open a GDS file and return the library cell size from either the Open a GDS file and return the library cell size from either the
@ -106,15 +111,18 @@ def get_gds_pins(pin_names, name, gds_filename, units):
cell = {} cell = {}
for pin_name in pin_names: for pin_name in pin_names:
cell[str(pin_name)]=[] cell[str(pin_name)] = []
pin_list=cell_vlsi.getPinShape(str(pin_name)) pin_list = cell_vlsi.getPinShape(str(pin_name))
for pin_shape in pin_list: for pin_shape in pin_list:
(lpp,boundary)=pin_shape (lpp, boundary) = pin_shape
rect=[vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])] rect = [vector(boundary[0], boundary[1]),
# this is a list because other cells/designs may have must-connect pins vector(boundary[2], boundary[3])]
# this is a list because other cells/designs
# may have must-connect pins
cell[str(pin_name)].append(pin_layout(pin_name, rect, lpp)) cell[str(pin_name)].append(pin_layout(pin_name, rect, lpp))
return cell return cell
def get_libcell_pins(pin_list, name, units): def get_libcell_pins(pin_list, name, units):
""" """
Open a GDS file and find the pins in pin_list as text on a given layer. Open a GDS file and find the pins in pin_list as text on a given layer.

View File

@ -27,9 +27,9 @@ def check(check, str):
os.path.basename(filename), line_number, str)) os.path.basename(filename), line_number, str))
if globals.OPTS.debug_level > 0: if globals.OPTS.debug_level > 0:
import pdb; pdb.set_trace() import pdb
else: pdb.set_trace()
assert 0 assert 0
def error(str, return_value=0): def error(str, return_value=0):
@ -41,9 +41,9 @@ def error(str, return_value=0):
os.path.basename(filename), line_number, str)) os.path.basename(filename), line_number, str))
if globals.OPTS.debug_level > 0: if globals.OPTS.debug_level > 0:
import pdb; pdb.set_trace() import pdb
else: pdb.set_trace()
assert return_value == 0 assert return_value == 0
def warning(str): def warning(str):

View File

@ -213,11 +213,11 @@ class VlsiLayout:
def initialize(self): def initialize(self):
self.deduceHierarchy() self.deduceHierarchy()
#self.traverseTheHierarchy() # self.traverseTheHierarchy()
self.populateCoordinateMap() self.populateCoordinateMap()
for layerNumber in self.layerNumbersInUse: for layerNumber in self.layerNumbersInUse:
self.processLabelPins((layerNumber,None)) self.processLabelPins((layerNumber, None))
def populateCoordinateMap(self): def populateCoordinateMap(self):
@ -245,21 +245,24 @@ class VlsiLayout:
self.xyTree.append((startingStructureName,origin,uVector,vVector)) self.xyTree.append((startingStructureName,origin,uVector,vVector))
self.traverseTheHierarchy(delegateFunction = addToXyTree) self.traverseTheHierarchy(delegateFunction = addToXyTree)
def microns(self,userUnits): def microns(self, userUnits):
"""Utility function to convert user units to microns""" """Utility function to convert user units to microns"""
userUnit = self.units[1]/self.units[0] userUnit = self.units[1]/self.units[0]
userUnitsPerMicron = userUnit / (userunit) userUnitsPerMicron = userUnit / userunit
layoutUnitsPerMicron = userUnitsPerMicron / self.units[0] layoutUnitsPerMicron = userUnitsPerMicron / self.units[0]
return userUnits / layoutUnitsPerMicron return userUnits / layoutUnitsPerMicron
def userUnits(self,microns): def userUnits(self, microns):
"""Utility function to convert microns to user units""" """Utility function to convert microns to user units"""
userUnit = self.units[1]/self.units[0] userUnit = self.units[1]/self.units[0]
#userUnitsPerMicron = userUnit / 1e-6 # userUnitsPerMicron = userUnit / 1e-6
userUnitsPerMicron = userUnit / (userUnit) userUnitsPerMicron = userUnit / (userUnit)
layoutUnitsPerMicron = userUnitsPerMicron / self.units[0] layoutUnitsPerMicron = userUnitsPerMicron / self.units[0]
#print("userUnit:",userUnit,"userUnitsPerMicron",userUnitsPerMicron,"layoutUnitsPerMicron",layoutUnitsPerMicron,[microns,microns*layoutUnitsPerMicron]) # print("userUnit:",userUnit,
return round(microns*layoutUnitsPerMicron,0) # "userUnitsPerMicron",userUnitsPerMicron,
# "layoutUnitsPerMicron",layoutUnitsPerMicron,
# [microns,microns*layoutUnitsPerMicron])
return round(microns*layoutUnitsPerMicron, 0)
def changeRoot(self,newRoot, create=False): def changeRoot(self,newRoot, create=False):
""" """
@ -386,7 +389,7 @@ class VlsiLayout:
#add the sref to the root structure #add the sref to the root structure
self.structures[self.rootStructureName].boundaries.append(boundaryToAdd) 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=None, coordinates=[(0,0)], width=1.0):
""" """
Method to add a path to a layout Method to add a path to a layout
""" """
@ -405,7 +408,7 @@ class VlsiLayout:
#add the sref to the root structure #add the sref to the root structure
self.structures[self.rootStructureName].paths.append(pathToAdd) 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, purposeNumber=None, offsetInMicrons=(0,0), magnification=0.1, rotate = None):
offsetInLayoutUnits = (self.userUnits(offsetInMicrons[0]),self.userUnits(offsetInMicrons[1])) offsetInLayoutUnits = (self.userUnits(offsetInMicrons[0]),self.userUnits(offsetInMicrons[1]))
textToAdd = GdsText() textToAdd = GdsText()
textToAdd.drawingLayer = layerNumber textToAdd.drawingLayer = layerNumber
@ -593,42 +596,50 @@ class VlsiLayout:
passFailIndex += 1 passFailIndex += 1
print("Done\n\n") print("Done\n\n")
def getLayoutBorder(self,lpp): def getLayoutBorder(self, lpp):
cellSizeMicron=None cellSizeMicron = None
for boundary in self.structures[self.rootStructureName].boundaries: for boundary in self.structures[self.rootStructureName].boundaries:
if boundary.drawingLayer==lpp[0] and \ if sameLPP((boundary.drawingLayer, boundary.purposeLayer),
(lpp[1]==None or boundary.purposeLayer==None or boundary.purposeLayer==lpp[1]): lpp):
if self.debug: if self.debug:
debug.info(1,"Find border "+str(boundary.coordinates)) debug.info(1, "Find border "+str(boundary.coordinates))
left_bottom=boundary.coordinates[0] left_bottom = boundary.coordinates[0]
right_top=boundary.coordinates[2] right_top = boundary.coordinates[2]
cellSize=[right_top[0]-left_bottom[0],right_top[1]-left_bottom[1]] cellSize = [right_top[0]-left_bottom[0],
cellSizeMicron=[cellSize[0]*self.units[0],cellSize[1]*self.units[0]] right_top[1]-left_bottom[1]]
cellSizeMicron = [cellSize[0]*self.units[0],
cellSize[1]*self.units[0]]
debug.check(cellSizeMicron, debug.check(cellSizeMicron,
"Error: "+str(self.rootStructureName)+".cell_size information not found yet") "Error: "+str(self.rootStructureName)+".cell_size information not found yet")
return cellSizeMicron return cellSizeMicron
def measureSize(self,startStructure): def measureSize(self, startStructure):
self.rootStructureName=self.padText(startStructure) self.rootStructureName = self.padText(startStructure)
self.populateCoordinateMap() self.populateCoordinateMap()
cellBoundary = [None, None, None, None] cellBoundary = [None, None, None, None]
for TreeUnit in self.xyTree: for TreeUnit in self.xyTree:
cellBoundary=self.measureSizeInStructure(TreeUnit,cellBoundary) cellBoundary = self.measureSizeInStructure(TreeUnit, cellBoundary)
cellSize=[cellBoundary[2]-cellBoundary[0],cellBoundary[3]-cellBoundary[1]] cellSize = [cellBoundary[2]-cellBoundary[0],
cellSizeMicron=[cellSize[0]*self.units[0],cellSize[1]*self.units[0]] cellBoundary[3]-cellBoundary[1]]
cellSizeMicron = [cellSize[0]*self.units[0],
cellSize[1]*self.units[0]]
return cellSizeMicron return cellSizeMicron
def measureBoundary(self,startStructure): def measureBoundary(self, startStructure):
self.rootStructureName=self.padText(startStructure) self.rootStructureName = self.padText(startStructure)
self.populateCoordinateMap() self.populateCoordinateMap()
cellBoundary = [None, None, None, None] cellBoundary = [None, None, None, None]
for TreeUnit in self.xyTree: for TreeUnit in self.xyTree:
cellBoundary=self.measureSizeInStructure(TreeUnit,cellBoundary) cellBoundary = self.measureSizeInStructure(TreeUnit, cellBoundary)
return [[self.units[0]*cellBoundary[0],self.units[0]*cellBoundary[1]], return [[self.units[0]*cellBoundary[0],
[self.units[0]*cellBoundary[2],self.units[0]*cellBoundary[3]]] self.units[0]*cellBoundary[1]],
[self.units[0]*cellBoundary[2],
self.units[0]*cellBoundary[3]]]
def measureSizeInStructure(self,structure,cellBoundary): def measureSizeInStructure(self, structure, cellBoundary):
(structureName,structureOrigin,structureuVector,structurevVector)=structure (structureName, structureOrigin,
structureuVector, structurevVector) = structure
for boundary in self.structures[str(structureName)].boundaries: for boundary in self.structures[str(structureName)].boundaries:
left_bottom=boundary.coordinates[0] left_bottom=boundary.coordinates[0]
right_top=boundary.coordinates[2] right_top=boundary.coordinates[2]
@ -655,14 +666,14 @@ class VlsiLayout:
cellBoundary[3]=right_top_Y cellBoundary[3]=right_top_Y
return cellBoundary return cellBoundary
def getTexts(self, lpp): def getTexts(self, lpp):
""" """
Get all of the labels on a given layer only at the root level. Get all of the labels on a given layer only at the root level.
""" """
text_list = [] text_list = []
for Text in self.structures[self.rootStructureName].texts: for Text in self.structures[self.rootStructureName].texts:
if Text.drawingLayer==lpp[0] and (lpp[1]==None or Text.purposeLayer==lpp[1]): if sameLPP((Text.drawingLayer, Text.purposeLayer),
lpp):
text_list.append(Text) text_list.append(Text)
return text_list return text_list
@ -678,9 +689,9 @@ class VlsiLayout:
max_pin = None max_pin = None
max_area = 0 max_area = 0
for pin in pin_list: for pin in pin_list:
(layer,boundary) = pin (layer, boundary) = pin
new_area = boundaryArea(boundary) new_area = boundaryArea(boundary)
if max_pin == None or new_area>max_area: if not max_pin or new_area > max_area:
max_pin = pin max_pin = pin
max_area = new_area max_area = new_area
max_pins.append(max_pin) max_pins.append(max_pin)
@ -697,11 +708,10 @@ class VlsiLayout:
pin_map = self.pins[pin_name] pin_map = self.pins[pin_name]
for pin_list in pin_map: for pin_list in pin_map:
for pin in pin_list: for pin in pin_list:
(pin_layer, boundary) = pin (pin_layer, boundary) = pin
shape_list.append(pin) shape_list.append(pin)
return shape_list return shape_list
def processLabelPins(self, lpp): def processLabelPins(self, lpp):
""" """
@ -710,19 +720,21 @@ class VlsiLayout:
""" """
# Get the labels on a layer in the root level # Get the labels on a layer in the root level
labels = self.getTexts(lpp) labels = self.getTexts(lpp)
# Get all of the shapes on the layer at all levels # Get all of the shapes on the layer at all levels
# and transform them to the current level # and transform them to the current level
shapes = self.getAllShapes(lpp) shapes = self.getAllShapes(lpp)
for label in labels: for label in labels:
label_coordinate = label.coordinates[0] label_coordinate = label.coordinates[0]
user_coordinate = [x*self.units[0] for x in label_coordinate] user_coordinate = [x*self.units[0] for x in label_coordinate]
pin_shapes = [] pin_shapes = []
for boundary in shapes: for boundary in shapes:
if self.labelInRectangle(user_coordinate,boundary): if self.labelInRectangle(user_coordinate, boundary):
pin_shapes.append((lpp, boundary)) pin_shapes.append((lpp, boundary))
label_text = label.textString label_text = label.textString
# Remove the padding if it exists # Remove the padding if it exists
if label_text[-1] == "\x00": if label_text[-1] == "\x00":
label_text = label_text[0:-1] label_text = label_text[0:-1]
@ -732,11 +744,11 @@ class VlsiLayout:
except KeyError: except KeyError:
self.pins[label_text] = [] self.pins[label_text] = []
self.pins[label_text].append(pin_shapes) self.pins[label_text].append(pin_shapes)
def getBlockages(self, lpp): def getBlockages(self, lpp):
""" """
Return all blockages on a given layer in [coordinate 1, coordinate 2,...] format and Return all blockages on a given layer in
[coordinate 1, coordinate 2,...] format and
user units. user units.
""" """
blockages = [] blockages = []
@ -744,69 +756,85 @@ class VlsiLayout:
shapes = self.getAllShapes(lpp) shapes = self.getAllShapes(lpp)
for boundary in shapes: for boundary in shapes:
vectors = [] vectors = []
for i in range(0,len(boundary),2): for i in range(0, len(boundary), 2):
vectors.append(vector(boundary[i],boundary[i+1])) vectors.append(vector(boundary[i], boundary[i+1]))
blockages.append(vectors) blockages.append(vectors)
return blockages
return blockages
def getAllShapes(self, lpp): def getAllShapes(self, lpp):
""" """
Return all shapes on a given layer in [llx, lly, urx, ury] format and user units for rectangles Return all shapes on a given layer in [llx, lly, urx, ury]
and [coordinate 1, coordinate 2,...] format and user units for polygons. format and user units for rectangles
and [coordinate 1, coordinate 2,...] format and user
units for polygons.
""" """
boundaries = set() boundaries = set()
for TreeUnit in self.xyTree: for TreeUnit in self.xyTree:
#print(TreeUnit[0]) # print(TreeUnit[0])
boundaries.update(self.getShapesInStructure(lpp,TreeUnit)) boundaries.update(self.getShapesInStructure(lpp, TreeUnit))
# Convert to user units # Convert to user units
user_boundaries = [] user_boundaries = []
for boundary in boundaries: for boundary in boundaries:
boundaries_list = [] boundaries_list = []
for i in range(0,len(boundary)): for i in range(0, len(boundary)):
boundaries_list.append(boundary[i]*self.units[0]) boundaries_list.append(boundary[i]*self.units[0])
user_boundaries.append(boundaries_list) user_boundaries.append(boundaries_list)
return user_boundaries return user_boundaries
def getShapesInStructure(self, lpp, structure): def getShapesInStructure(self, lpp, structure):
"""
Go through all the shapes in a structure and return the list of shapes in
the form [llx, lly, urx, ury] for rectangles and [coordinate 1, coordinate 2,...] for polygons.
""" """
(structureName,structureOrigin,structureuVector,structurevVector)=structure Go through all the shapes in a structure and
#print(structureName,"u",structureuVector.transpose(),"v",structurevVector.transpose(),"o",structureOrigin.transpose()) return the list of shapes in
the form [llx, lly, urx, ury] for rectangles
and [coordinate 1, coordinate 2,...] for polygons.
"""
(structureName, structureOrigin,
structureuVector, structurevVector) = structure
# print(structureName,
# "u", structureuVector.transpose(),
# "v",structurevVector.transpose(),
# "o",structureOrigin.transpose())
boundaries = [] boundaries = []
for boundary in self.structures[str(structureName)].boundaries: for boundary in self.structures[str(structureName)].boundaries:
if boundary.drawingLayer==lpp[0] and (lpp[1]==None or boundary.purposeLayer==lpp[1]): if sameLPP((boundary.drawingLayer, boundary.purposeLayer),
if len(boundary.coordinates)!=5: lpp):
if len(boundary.coordinates) != 5:
# if shape is a polygon (used in DFF) # if shape is a polygon (used in DFF)
boundaryPolygon = [] boundaryPolygon = []
# Polygon is a list of coordinates going ccw # Polygon is a list of coordinates going ccw
for coord in range(0,len(boundary.coordinates)): for coord in range(0, len(boundary.coordinates)):
boundaryPolygon.append(boundary.coordinates[coord][0]) boundaryPolygon.append(boundary.coordinates[coord][0])
boundaryPolygon.append(boundary.coordinates[coord][1]) boundaryPolygon.append(boundary.coordinates[coord][1])
# perform the rotation # perform the rotation
boundaryPolygon=self.transformPolygon(boundaryPolygon,structureuVector,structurevVector) boundaryPolygon = self.transformPolygon(boundaryPolygon,
# add the offset structureuVector,
structurevVector)
# add the offset
polygon = [] polygon = []
for i in range(0,len(boundaryPolygon),2): for i in range(0, len(boundaryPolygon), 2):
polygon.append(boundaryPolygon[i]+structureOrigin[0].item()) polygon.append(boundaryPolygon[i] + structureOrigin[0].item())
polygon.append(boundaryPolygon[i+1]+structureOrigin[1].item()) polygon.append(boundaryPolygon[i+1] + structureOrigin[1].item())
# make it a tuple # make it a tuple
polygon = tuple(polygon) polygon = tuple(polygon)
boundaries.append(polygon) boundaries.append(polygon)
else: else:
# else shape is a rectangle # else shape is a rectangle
left_bottom=boundary.coordinates[0] left_bottom = boundary.coordinates[0]
right_top=boundary.coordinates[2] right_top = boundary.coordinates[2]
# Rectangle is [leftx, bottomy, rightx, topy]. # Rectangle is [leftx, bottomy, rightx, topy].
boundaryRect=[left_bottom[0],left_bottom[1],right_top[0],right_top[1]] boundaryRect = [left_bottom[0], left_bottom[1],
right_top[0], right_top[1]]
# perform the rotation # perform the rotation
boundaryRect=self.transformRectangle(boundaryRect,structureuVector,structurevVector) boundaryRect = self.transformRectangle(boundaryRect,
structureuVector,
structurevVector)
# add the offset and make it a tuple # add the offset and make it a tuple
boundaryRect=(boundaryRect[0]+structureOrigin[0].item(),boundaryRect[1]+structureOrigin[1].item(), boundaryRect = (boundaryRect[0]+structureOrigin[0].item(),
boundaryRect[2]+structureOrigin[0].item(),boundaryRect[3]+structureOrigin[1].item()) boundaryRect[1]+structureOrigin[1].item(),
boundaryRect[2]+structureOrigin[0].item(),
boundaryRect[3]+structureOrigin[1].item())
boundaries.append(boundaryRect) boundaries.append(boundaryRect)
return boundaries return boundaries
@ -868,6 +896,17 @@ class VlsiLayout:
else: else:
return False return False
def sameLPP(lpp1, lpp2):
"""
Check if the layers and purposes are the same.
Ignore if purpose is a None.
"""
if lpp1[1] == None or lpp2[1] == None:
return lpp1[0] == lpp2[0]
return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1]
def boundaryArea(A): def boundaryArea(A):
""" """

View File

@ -5,13 +5,11 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import globals
import design import design
from math import log from tech import GDS, layer, spice, parameter
import design
from tech import GDS,layer,spice,parameter
import utils import utils
class dff(design.design): class dff(design.design):
""" """
Memory address flip-flop Memory address flip-flop
@ -19,7 +17,9 @@ class dff(design.design):
pin_names = ["D", "Q", "clk", "vdd", "gnd"] pin_names = ["D", "Q", "clk", "vdd", "gnd"]
type_list = ["INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] type_list = ["INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("dff", GDS["unit"], layer["boundary"]) (width, height) = utils.get_libcell_size("dff",
GDS["unit"],
layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "dff", GDS["unit"]) pin_map = utils.get_libcell_pins(pin_names, "dff", GDS["unit"])
def __init__(self, name="dff"): def __init__(self, name="dff"):

View File

@ -18,16 +18,17 @@ class pin_group:
determine how pin shapes get mapped to tracks. determine how pin shapes get mapped to tracks.
It is initially constructed with a single set of (touching) pins. It is initially constructed with a single set of (touching) pins.
""" """
def __init__(self, name, pin_set, router): def __init__(self, name, pin_set, router):
self.name = name self.name = name
# Flag for when it is routed # Flag for when it is routed
self.routed = False self.routed = False
# Flag for when it is enclosed # Flag for when it is enclosed
self.enclosed = False self.enclosed = False
# Remove any redundant pins (i.e. contained in other pins) # Remove any redundant pins (i.e. contained in other pins)
irredundant_pin_set = self.remove_redundant_shapes(list(pin_set)) irredundant_pin_set = self.remove_redundant_shapes(list(pin_set))
# This is a list because we can have a pin # This is a list because we can have a pin
# group of disconnected sets of pins # group of disconnected sets of pins
# and these are represented by separate lists # and these are represented by separate lists
@ -39,7 +40,7 @@ class pin_group:
# These are the secondary grids that could # These are the secondary grids that could
# or could not be part of the pin # or could not be part of the pin
self.secondary_grids = set() self.secondary_grids = set()
# The corresponding set of partially blocked grids for each pin group. # The corresponding set of partially blocked grids for each pin group.
# These are blockages for other nets but unblocked # These are blockages for other nets but unblocked
# for routing this group. These are also blockages if we # for routing this group. These are also blockages if we
@ -52,16 +53,16 @@ class pin_group:
def __str__(self): def __str__(self):
""" override print function output """ """ override print function output """
total_string = "(pg {} ".format(self.name) total_string = "(pg {} ".format(self.name)
pin_string = "\n pins={}".format(self.pins) pin_string = "\n pins={}".format(self.pins)
total_string += pin_string total_string += pin_string
grids_string = "\n grids={}".format(self.grids) grids_string = "\n grids={}".format(self.grids)
total_string += grids_string total_string += grids_string
grids_string = "\n secondary={}".format(self.secondary_grids) grids_string = "\n secondary={}".format(self.secondary_grids)
total_string += grids_string total_string += grids_string
if self.enclosed: if self.enclosed:
enclosure_string = "\n enclose={}".format(self.enclosures) enclosure_string = "\n enclose={}".format(self.enclosures)
total_string += enclosure_string total_string += enclosure_string
@ -72,7 +73,7 @@ class pin_group:
def __repr__(self): def __repr__(self):
""" override repr function output """ """ override repr function output """
return str(self) return str(self)
def size(self): def size(self):
return len(self.grids) return len(self.grids)
@ -81,7 +82,7 @@ class pin_group:
def is_routed(self): def is_routed(self):
return self.routed return self.routed
def remove_redundant_shapes(self, pin_list): def remove_redundant_shapes(self, pin_list):
""" """
Remove any pin layout that is contained within another. Remove any pin layout that is contained within another.
@ -90,7 +91,7 @@ class pin_group:
local_debug = False local_debug = False
if local_debug: if local_debug:
debug.info(0, "INITIAL: {}".format(pin_list)) debug.info(0, "INITIAL: {}".format(pin_list))
# Make a copy of the list to start # Make a copy of the list to start
new_pin_list = pin_list.copy() new_pin_list = pin_list.copy()
@ -100,7 +101,7 @@ class pin_group:
# If we remove this pin, it can't contain other pins # If we remove this pin, it can't contain other pins
if index1 in remove_indices: if index1 in remove_indices:
continue continue
for index2, pin2 in enumerate(pin_list): for index2, pin2 in enumerate(pin_list):
# Can't contain yourself, # Can't contain yourself,
# but compare the indices and not the pins # but compare the indices and not the pins
@ -110,7 +111,7 @@ class pin_group:
# If we already removed it, can't remove it again... # If we already removed it, can't remove it again...
if index2 in remove_indices: if index2 in remove_indices:
continue continue
if pin1.contains(pin2): if pin1.contains(pin2):
if local_debug: if local_debug:
debug.info(0, "{0} contains {1}".format(pin1, pin2)) debug.info(0, "{0} contains {1}".format(pin1, pin2))
@ -119,10 +120,10 @@ class pin_group:
# Remove them in decreasing order to not invalidate the indices # Remove them in decreasing order to not invalidate the indices
for i in sorted(remove_indices, reverse=True): for i in sorted(remove_indices, reverse=True):
del new_pin_list[i] del new_pin_list[i]
if local_debug: if local_debug:
debug.info(0, "FINAL : {}".format(new_pin_list)) debug.info(0, "FINAL : {}".format(new_pin_list))
return new_pin_list return new_pin_list
def compute_enclosures(self): def compute_enclosures(self):
@ -144,11 +145,17 @@ class pin_group:
enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z) enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z)
pin_list.append(enclosure) pin_list.append(enclosure)
# Now simplify the enclosure list debug.check(len(pin_list) > 0,
"Did not find any enclosures.")
# Now simplify the enclosure list
new_pin_list = self.remove_redundant_shapes(pin_list) new_pin_list = self.remove_redundant_shapes(pin_list)
return new_pin_list debug.check(len(new_pin_list) > 0,
"Did not find any enclosures.")
return new_pin_list
def compute_connector(self, pin, enclosure): def compute_connector(self, pin, enclosure):
""" """
Compute a shape to connect the pin to the enclosure shape. Compute a shape to connect the pin to the enclosure shape.
@ -200,7 +207,7 @@ class pin_group:
for shape in enclosures: for shape in enclosures:
if shape.xcontains(pin): if shape.xcontains(pin):
edge_list.append(shape) edge_list.append(shape)
# Sort them by their bottom edge # Sort them by their bottom edge
edge_list.sort(key=lambda x: x.by(), reverse=True) edge_list.sort(key=lambda x: x.by(), reverse=True)
@ -233,7 +240,7 @@ class pin_group:
for shape in enclosures: for shape in enclosures:
if shape.xcontains(pin): if shape.xcontains(pin):
edge_list.append(shape) edge_list.append(shape)
# Sort them by their upper edge # Sort them by their upper edge
edge_list.sort(key=lambda x: x.uy()) edge_list.sort(key=lambda x: x.uy())
@ -251,13 +258,13 @@ class pin_group:
# If it already overlaps, no connector needed # If it already overlaps, no connector needed
if bottom_item.overlaps(pin): if bottom_item.overlaps(pin):
return None return None
# Otherwise, make a connector to the item # Otherwise, make a connector to the item
p = self.compute_connector(pin, bottom_item) p = self.compute_connector(pin, bottom_item)
return p return p
def find_left_connector(self, pin, enclosures): def find_left_connector(self, pin, enclosures):
""" """
Find the enclosure that is to the left of the pin Find the enclosure that is to the left of the pin
and make a connector to it's right edge. and make a connector to it's right edge.
""" """
@ -266,14 +273,14 @@ class pin_group:
for shape in enclosures: for shape in enclosures:
if shape.ycontains(pin): if shape.ycontains(pin):
edge_list.append(shape) edge_list.append(shape)
# Sort them by their right edge # Sort them by their right edge
edge_list.sort(key=lambda x: x.rx()) edge_list.sort(key=lambda x: x.rx())
# Find the right edge that is to the pin's left edge # Find the right edge that is to the pin's left edge
left_item = None left_item = None
for item in edge_list: for item in edge_list:
if item.rx()<=pin.lx(): if item.rx() <= pin.lx():
left_item = item left_item = item
else: else:
break break
@ -284,13 +291,13 @@ class pin_group:
# If it already overlaps, no connector needed # If it already overlaps, no connector needed
if left_item.overlaps(pin): if left_item.overlaps(pin):
return None return None
# Otherwise, make a connector to the item # Otherwise, make a connector to the item
p = self.compute_connector(pin, left_item) p = self.compute_connector(pin, left_item)
return p return p
def find_right_connector(self, pin, enclosures): def find_right_connector(self, pin, enclosures):
""" """
Find the enclosure that is to the right of the pin Find the enclosure that is to the right of the pin
and make a connector to it's left edge. and make a connector to it's left edge.
""" """
@ -299,7 +306,7 @@ class pin_group:
for shape in enclosures: for shape in enclosures:
if shape.ycontains(pin): if shape.ycontains(pin):
edge_list.append(shape) edge_list.append(shape)
# Sort them by their right edge # Sort them by their right edge
edge_list.sort(key=lambda x: x.lx(), reverse=True) edge_list.sort(key=lambda x: x.lx(), reverse=True)
@ -317,11 +324,11 @@ class pin_group:
# If it already overlaps, no connector needed # If it already overlaps, no connector needed
if right_item.overlaps(pin): if right_item.overlaps(pin):
return None return None
# Otherwise, make a connector to the item # Otherwise, make a connector to the item
p = self.compute_connector(pin, right_item) p = self.compute_connector(pin, right_item)
return p return p
def find_smallest_connector(self, pin_list, shape_list): def find_smallest_connector(self, pin_list, shape_list):
""" """
Compute all of the connectors between the overlapping Compute all of the connectors between the overlapping
@ -334,7 +341,7 @@ class pin_group:
new_enclosure = self.compute_connector(pin, enclosure) new_enclosure = self.compute_connector(pin, enclosure)
if not smallest or new_enclosure.area() < smallest.area(): if not smallest or new_enclosure.area() < smallest.area():
smallest = new_enclosure smallest = new_enclosure
return smallest return smallest
def find_smallest_overlapping(self, pin_list, shape_list): def find_smallest_overlapping(self, pin_list, shape_list):
@ -350,7 +357,7 @@ class pin_group:
# overlap_length = pin.overlap_length(overlap_shape) # overlap_length = pin.overlap_length(overlap_shape)
if not smallest_shape or overlap_shape.area() < smallest_shape.area(): if not smallest_shape or overlap_shape.area() < smallest_shape.area():
smallest_shape = overlap_shape smallest_shape = overlap_shape
return smallest_shape return smallest_shape
def find_smallest_overlapping_pin(self, pin, shape_list): def find_smallest_overlapping_pin(self, pin, shape_list):
@ -369,9 +376,9 @@ class pin_group:
if overlap_length > min_width: if overlap_length > min_width:
if not smallest_shape or other.area() < smallest_shape.area(): if not smallest_shape or other.area() < smallest_shape.area():
smallest_shape = other smallest_shape = other
return smallest_shape return smallest_shape
def overlap_any_shape(self, pin_list, shape_list): def overlap_any_shape(self, pin_list, shape_list):
""" """
Does the given pin overlap any of the shapes in the pin list. Does the given pin overlap any of the shapes in the pin list.
@ -391,7 +398,7 @@ class pin_group:
for pin in pin_list: for pin in pin_list:
if pin.area() > biggest.area(): if pin.area() > biggest.area():
biggest = pin biggest = pin
return pin return pin
def enclose_pin_grids(self, ll, dir1=direction.NORTH, dir2=direction.EAST): def enclose_pin_grids(self, ll, dir1=direction.NORTH, dir2=direction.EAST):
@ -406,8 +413,7 @@ class pin_group:
offset2 = direction.get_offset(dir2) offset2 = direction.get_offset(dir2)
# We may have started with an empty set # We may have started with an empty set
if not self.grids: debug.check(len(self.grids) > 0, "Cannot seed an grid empty set.")
return None
# Start with the ll and make the widest row # Start with the ll and make the widest row
row = [ll] row = [ll]
@ -436,7 +442,7 @@ class pin_group:
# Add a shape from ll to ur # Add a shape from ll to ur
ur = row[-1] ur = row[-1]
return (ll, ur) return (ll, ur)
def enclose_pin(self): def enclose_pin(self):
""" """
If there is one set of connected pin shapes, If there is one set of connected pin shapes,
@ -445,13 +451,13 @@ class pin_group:
If there is not, it simply returns all the enclosures. If there is not, it simply returns all the enclosures.
""" """
self.enclosed = True self.enclosed = True
# Compute the enclosure pin_layout list of the set of tracks # Compute the enclosure pin_layout list of the set of tracks
self.enclosures = self.compute_enclosures() self.enclosures = self.compute_enclosures()
# Find a connector to every pin and add it to the enclosures # Find a connector to every pin and add it to the enclosures
for pin in self.pins: for pin in self.pins:
# If it is contained, it won't need a connector # If it is contained, it won't need a connector
if pin.contained_by_any(self.enclosures): if pin.contained_by_any(self.enclosures):
continue continue
@ -469,7 +475,7 @@ class pin_group:
right_connector, right_connector,
above_connector, above_connector,
below_connector] below_connector]
filtered_list = list(filter(lambda x: x!=None, connector_list)) filtered_list = list(filter(lambda x: x != None, connector_list))
if (len(filtered_list) > 0): if (len(filtered_list) > 0):
import copy import copy
bbox_connector = copy.copy(pin) bbox_connector = copy.copy(pin)
@ -487,8 +493,9 @@ class pin_group:
debug.error("Could not find a connector for {} with {}".format(self.pins, debug.error("Could not find a connector for {} with {}".format(self.pins,
self.enclosures)) self.enclosures))
self.router.write_debug_gds("no_connector.gds") self.router.write_debug_gds("no_connector.gds")
import pdb; pdb.set_trace()
self.enclosures.append(connector) self.enclosures.append(connector)
# At this point, the pins are overlapping, # At this point, the pins are overlapping,
# but there might be more than one! # but there might be more than one!
overlap_set = set() overlap_set = set()
@ -505,12 +512,11 @@ class pin_group:
(sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name, (sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name,
enclosure) enclosure)
self.grids.update(sufficient) self.grids.update(sufficient)
debug.info(3, "Computed enclosure(s) {0}\n {1}\n {2}\n {3}".format(self.name,
debug.info(3,"Computed enclosure(s) {0}\n {1}\n {2}\n {3}".format(self.name, self.pins,
self.pins, self.grids,
self.grids, self.enclosures))
self.enclosures))
def transitive_overlap(self, shape, shape_list): def transitive_overlap(self, shape, shape_list):
""" """
@ -532,22 +538,22 @@ class pin_group:
# Remove the original shape # Remove the original shape
connected_set.remove(shape) connected_set.remove(shape)
# if len(connected_set)<len(shape_list): # if len(connected_set)<len(shape_list):
# import pprint # import pprint
# print("S: ",shape) # print("S: ",shape)
# pprint.pprint(shape_list) # pprint.pprint(shape_list)
# pprint.pprint(connected_set) # pprint.pprint(connected_set)
return connected_set return connected_set
def add_enclosure(self, cell): def add_enclosure(self, cell):
""" """
Add the enclosure shape to the given cell. Add the enclosure shape to the given cell.
""" """
for enclosure in self.enclosures: for enclosure in self.enclosures:
debug.info(2, "Adding enclosure {0} {1}".format(self.name, debug.info(2, "Adding enclosure {0} {1}".format(self.name,
enclosure)) enclosure))
cell.add_rect(layer=enclosure.layer, cell.add_rect(layer=enclosure.layer,
offset=enclosure.ll(), offset=enclosure.ll(),
width=enclosure.width(), width=enclosure.width(),
@ -566,9 +572,9 @@ class pin_group:
# If we aren't completely enclosed, we are on the perimeter # If we aren't completely enclosed, we are on the perimeter
if neighbor_count < 4: if neighbor_count < 4:
perimeter_set.add(g1) perimeter_set.add(g1)
return perimeter_set return perimeter_set
def adjacent(self, other): def adjacent(self, other):
""" """
Chck if the two pin groups have at least one adjacent pin grid. Chck if the two pin groups have at least one adjacent pin grid.
@ -594,11 +600,11 @@ class pin_group:
adj_grids.add(g1) adj_grids.add(g1)
return adj_grids return adj_grids
def convert_pin(self): def convert_pin(self):
""" """
Convert the list of pin shapes into sets of routing grids. Convert the list of pin shapes into sets of routing grids.
The secondary set of grids are "optional" pin shapes that could be The secondary set of grids are "optional" pin shapes that
should be either blocked or part of the pin. should be either blocked or part of the pin.
""" """
pin_set = set() pin_set = set()
@ -608,11 +614,11 @@ class pin_group:
for pin in self.pins: for pin in self.pins:
debug.info(2, " Converting {0}".format(pin)) debug.info(2, " Converting {0}".format(pin))
# Determine which tracks the pin overlaps # Determine which tracks the pin overlaps
(sufficient, insufficient)=self.router.convert_pin_to_tracks(self.name, (sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name,
pin) pin)
pin_set.update(sufficient) pin_set.update(sufficient)
partial_set.update(insufficient) partial_set.update(insufficient)
# Blockages will be a super-set of pins since # Blockages will be a super-set of pins since
# it uses the inflated pin shape. # it uses the inflated pin shape.
blockage_in_tracks = self.router.convert_blockage(pin) blockage_in_tracks = self.router.convert_blockage(pin)
@ -632,20 +638,20 @@ class pin_group:
if len(shared_set) > 0: if len(shared_set) > 0:
debug.info(2, "Removing blocks {}".format(shared_set)) debug.info(2, "Removing blocks {}".format(shared_set))
blockage_set.difference_update(shared_set) blockage_set.difference_update(shared_set)
# At least one of the groups must have some valid tracks # At least one of the groups must have some valid tracks
if (len(pin_set) == 0 and len(partial_set) == 0 and len(blockage_set) == 0): if (len(pin_set) == 0 and len(partial_set) == 0 and len(blockage_set) == 0):
# debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins)) # debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins))
for pin in self.pins: for pin in self.pins:
debug.warning(" Expanding conversion {0}".format(pin)) debug.warning(" Expanding conversion {0}".format(pin))
# Determine which tracks the pin overlaps # Determine which tracks the pin overlaps
(sufficient,insufficient)=self.router.convert_pin_to_tracks(self.name, (sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name,
pin, pin,
expansion=1) expansion=1)
pin_set.update(sufficient) pin_set.update(sufficient)
partial_set.update(insufficient) partial_set.update(insufficient)
if len(pin_set) == 0 and len(partial_set) == 0: if len(pin_set) == 0 and len(partial_set) == 0:
debug.error("Unable to find unblocked pin {} {}".format(self.name, debug.error("Unable to find unblocked pin {} {}".format(self.name,
self.pins)) self.pins))
@ -653,11 +659,12 @@ class pin_group:
# Consider all the grids that would be blocked # Consider all the grids that would be blocked
self.grids = pin_set | partial_set self.grids = pin_set | partial_set
if len(self.grids) < 0:
debug.error("Did not find any unblocked grids: {}".format(str(self.pins)))
self.router.write_debug_gds("blocked_pin.gds")
# Remember the secondary grids for removing adjacent pins # Remember the secondary grids for removing adjacent pins
self.secondary_grids = partial_set self.secondary_grids = partial_set
debug.info(2, " pins {}".format(self.grids)) debug.info(2, " pins {}".format(self.grids))
debug.info(2, " secondary {}".format(self.secondary_grids)) debug.info(2, " secondary {}".format(self.secondary_grids))

View File

@ -27,11 +27,10 @@ class router(router_tech):
route on a given layer. This is limited to two layer routes. route on a given layer. This is limited to two layer routes.
It populates blockages on a grid class. It populates blockages on a grid class.
""" """
def __init__(self, layers, design, gds_filename=None, rail_track_width=1): def __init__(self, layers, design, gds_filename=None, rail_track_width=1):
""" """
This will instantiate a copy of the gds file or the module at (0,0) and This will instantiate a copy of the gds file or the module at (0,0) and
route on top of this. The blockages from the gds/module will be route on top of this. The blockages from the gds/module will be
considered. considered.
""" """
router_tech.__init__(self, layers, rail_track_width) router_tech.__init__(self, layers, rail_track_width)
@ -84,7 +83,7 @@ class router(router_tech):
self.boundary = self.layout.measureBoundary(self.top_name) self.boundary = self.layout.measureBoundary(self.top_name)
# These must be un-indexed to get rid of the matrix type # These must be un-indexed to get rid of the matrix type
self.ll = vector(self.boundary[0][0], self.boundary[0][1]) self.ll = vector(self.boundary[0][0], self.boundary[0][1])
self.ur = vector(self.boundary[1][0], self.boundary[1][1]) self.ur = vector(self.boundary[1][0], self.boundary[1][1])
def clear_pins(self): def clear_pins(self):
""" """
@ -93,7 +92,7 @@ class router(router_tech):
""" """
self.pins = {} self.pins = {}
self.all_pins = set() self.all_pins = set()
self.pin_groups = {} self.pin_groups = {}
# DO NOT clear the blockages as these don't change # DO NOT clear the blockages as these don't change
self.rg.reinit() self.rg.reinit()
@ -112,7 +111,7 @@ class router(router_tech):
""" """
Retrieve the pin shapes on metal 3 from the layout. Retrieve the pin shapes on metal 3 from the layout.
""" """
debug.info(2, "Retrieving pins for {}.".format(pin_name)) debug.info(2, "Retrieving pins for {}.".format(pin_name))
shape_list = self.layout.getAllPinShapes(str(pin_name)) shape_list = self.layout.getAllPinShapes(str(pin_name))
pin_set = set() pin_set = set()
for shape in shape_list: for shape in shape_list:
@ -140,13 +139,13 @@ class router(router_tech):
This doesn't consider whether the obstacles will be pins or not. This doesn't consider whether the obstacles will be pins or not.
They get reset later if they are not actually a blockage. They get reset later if they are not actually a blockage.
""" """
debug.info(1, "Finding blockages.") debug.info(1, "Finding blockages.")
for layer in [self.vert_layer_number, self.horiz_layer_number]: for lpp in [self.vert_lpp, self.horiz_lpp]:
self.retrieve_blockages(layer) self.retrieve_blockages(lpp)
def find_pins_and_blockages(self, pin_list): def find_pins_and_blockages(self, pin_list):
""" """
Find the pins and blockages in the design Find the pins and blockages in the design
""" """
# This finds the pin shapes and sorts them into "groups" that # This finds the pin shapes and sorts them into "groups" that
# are connected. This must come before the blockages, so we # are connected. This must come before the blockages, so we
@ -447,7 +446,7 @@ class router(router_tech):
""" """
# Inflate the blockage by half a spacing rule # Inflate the blockage by half a spacing rule
[ll, ur] = self.convert_blockage_to_tracks(blockage.inflate()) [ll, ur] = self.convert_blockage_to_tracks(blockage.inflate())
zlayer = self.get_zindex(blockage.lpp[0]) zlayer = self.get_zindex(blockage.lpp)
blockage_tracks = self.get_blockage_tracks(ll, ur, zlayer) blockage_tracks = self.get_blockage_tracks(ll, ur, zlayer)
return blockage_tracks return blockage_tracks
@ -459,19 +458,19 @@ class router(router_tech):
blockage_list = self.convert_blockage(blockage) blockage_list = self.convert_blockage(blockage)
self.blocked_grids.update(blockage_list) self.blocked_grids.update(blockage_list)
def retrieve_blockages(self, layer_num): def retrieve_blockages(self, lpp):
""" """
Recursive find boundaries as blockages to the routing grid. Recursive find boundaries as blockages to the routing grid.
""" """
shapes = self.layout.getAllShapes(layer_num) shapes = self.layout.getAllShapes(lpp)
for boundary in shapes: for boundary in shapes:
ll = vector(boundary[0], boundary[1]) ll = vector(boundary[0], boundary[1])
ur = vector(boundary[2], boundary[3]) ur = vector(boundary[2], boundary[3])
rect = [ll, ur] rect = [ll, ur]
new_pin = pin_layout("blockage{}".format(len(self.blockages)), new_pin = pin_layout("blockage{}".format(len(self.blockages)),
rect, rect,
layer_num) lpp)
# If there is a rectangle that is the same in the pins, # If there is a rectangle that is the same in the pins,
# it isn't a blockage! # it isn't a blockage!
@ -529,7 +528,7 @@ class router(router_tech):
sufficient_list = set() sufficient_list = set()
insufficient_list = set() insufficient_list = set()
zindex = self.get_zindex(pin.lpp[0]) zindex = self.get_zindex(pin.lpp)
for x in range(int(ll[0]) + expansion, int(ur[0]) + 1 + expansion): for x in range(int(ll[0]) + expansion, int(ur[0]) + 1 + expansion):
for y in range(int(ll[1] + expansion), int(ur[1]) + 1 + expansion): for y in range(int(ll[1] + expansion), int(ur[1]) + 1 + expansion):
(full_overlap, partial_overlap) = self.convert_pin_coord_to_tracks(pin, (full_overlap, partial_overlap) = self.convert_pin_coord_to_tracks(pin,
@ -622,7 +621,6 @@ class router(router_tech):
""" """
Return all tracks that an inflated pin overlaps Return all tracks that an inflated pin overlaps
""" """
# This is using the full track shape rather # This is using the full track shape rather
# than a single track pin shape # than a single track pin shape
# because we will later patch a connector if there isn't overlap. # because we will later patch a connector if there isn't overlap.
@ -807,8 +805,8 @@ class router(router_tech):
def enclose_pins(self): def enclose_pins(self):
""" """
This will find the biggest rectangle enclosing some grid squares and This will find the biggest rectangle enclosing some grid squares and
put a rectangle over it. It does not enclose grid squares that are blocked put a rectangle over it. It does not enclose grid squares
by other shapes. that are blocked by other shapes.
""" """
for pin_name in self.pin_groups: for pin_name in self.pin_groups:
debug.info(1, "Enclosing pins for {}".format(pin_name)) debug.info(1, "Enclosing pins for {}".format(pin_name))

View File

@ -5,13 +5,13 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
from tech import drc,layer from tech import drc, layer
from contact import contact from contact import contact
from pin_group import pin_group
from vector import vector from vector import vector
import debug import debug
import math import math
class router_tech: class router_tech:
""" """
This is a class to hold the router tech constants. This is a class to hold the router tech constants.
@ -25,9 +25,9 @@ class router_tech:
self.layers = layers self.layers = layers
self.rail_track_width = rail_track_width self.rail_track_width = rail_track_width
if len(self.layers)==1: if len(self.layers) == 1:
self.horiz_layer_name = self.vert_layer_name = self.layers[0] self.horiz_layer_name = self.vert_layer_name = self.layers[0]
self.horiz_layer_number = self.vert_layer_number = layer[self.layers[0]] self.horiz_lpp = self.vert_lpp = layer[self.layers[0]]
(self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1) (self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1)
(self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0) (self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0)
@ -40,8 +40,8 @@ class router_tech:
via_connect = contact(self.layers, (1, 1)) via_connect = contact(self.layers, (1, 1))
max_via_size = max(via_connect.width,via_connect.height) max_via_size = max(via_connect.width,via_connect.height)
self.horiz_layer_number = layer[self.horiz_layer_name] self.horiz_lpp = layer[self.horiz_layer_name]
self.vert_layer_number = layer[self.vert_layer_name] self.vert_lpp = layer[self.vert_layer_name]
(self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1) (self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1)
(self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0) (self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0)
@ -68,8 +68,18 @@ class router_tech:
# When we actually create the routes, make them the width of the track (minus 1/2 spacing on each side) # When we actually create the routes, make them the width of the track (minus 1/2 spacing on each side)
self.layer_widths = [self.track_wire, 1, self.track_wire] self.layer_widths = [self.track_wire, 1, self.track_wire]
def get_zindex(self,layer_num): def same_lpp(self, lpp1, lpp2):
if layer_num==self.horiz_layer_number: """
Check if the layers and purposes are the same.
Ignore if purpose is a None.
"""
if lpp1[1] == None or lpp2[1] == None:
return lpp1[0] == lpp2[0]
return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1]
def get_zindex(self, lpp):
if self.same_lpp(lpp, self.horiz_lpp):
return 0 return 0
else: else:
return 1 return 1

View File

@ -55,7 +55,7 @@ class supply_grid_router(router):
self.rg = supply_grid.supply_grid(self.ll, self.ur, self.track_width) self.rg = supply_grid.supply_grid(self.ll, self.ur, self.track_width)
def route(self, vdd_name="vdd", gnd_name="gnd"): def route(self, vdd_name="vdd", gnd_name="gnd"):
""" """
Add power supply rails and connect all pins to these rails. Add power supply rails and connect all pins to these rails.
""" """
debug.info(1,"Running supply router on {0} and {1}...".format(vdd_name, gnd_name)) debug.info(1,"Running supply router on {0} and {1}...".format(vdd_name, gnd_name))
@ -75,7 +75,6 @@ class supply_grid_router(router):
start_time = datetime.now() start_time = datetime.now()
self.find_pins_and_blockages([self.vdd_name, self.gnd_name]) self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
print_time("Finding pins and blockages",datetime.now(), start_time, 3) print_time("Finding pins and blockages",datetime.now(), start_time, 3)
# Add the supply rails in a mesh network and connect H/V with vias # Add the supply rails in a mesh network and connect H/V with vias
start_time = datetime.now() start_time = datetime.now()
# Block everything # Block everything

View File

@ -67,7 +67,6 @@ layer["via9"] = (28, 0)
layer["metal10"] = (29, 0) layer["metal10"] = (29, 0)
layer["text"] = (239, 0) layer["text"] = (239, 0)
layer["boundary"]= (239, 0) layer["boundary"]= (239, 0)
#layer["blockage"]= (239, 0)
################################################### ###################################################
##END GDS Layer Map ##END GDS Layer Map

View File

@ -54,7 +54,6 @@ layer["via3"] = (30, 0)
layer["metal4"] = (31, 0) layer["metal4"] = (31, 0)
layer["text"] = (63, 0) layer["text"] = (63, 0)
layer["boundary"] = (63, 0) layer["boundary"] = (63, 0)
#layer["blockage"] = (83, 0)
################################################### ###################################################
##END GDS Layer Map ##END GDS Layer Map