mirror of https://github.com/VLSIDA/OpenRAM.git
Add layer-purpose GDS support. Various PEP8 fixes.
This commit is contained in:
parent
bba6995653
commit
131f4bda4a
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -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"):
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue