Rewrite blockage routines in router. Clean up GdsMill code.

This commit is contained in:
Matt Guthaus
2018-08-29 15:34:45 -07:00
parent 04b7c419f1
commit 27bb1d2ee7
14 changed files with 256 additions and 176 deletions
+1 -1
View File
@@ -89,7 +89,7 @@ class astar_grid(grid.grid):
self.counter+=1
def astar_route(self,detour_scale):
def route(self,detour_scale):
"""
This does the A* maze routing with preferred direction routing.
"""
+3
View File
@@ -36,6 +36,9 @@ class grid:
def add_blockage_shape(self,ll,ur,z):
debug.info(3,"Adding blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z))
if ll[0]<42 and ll[0]>38 and ll[1]<3 and ll[1]>0:
debug.info(0,"Adding blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z))
block_list = []
for x in range(int(ll[0]),int(ur[0])+1):
for y in range(int(ll[1]),int(ur[1])+1):
+118 -41
View File
@@ -27,8 +27,7 @@ class router:
self.top_name = self.layout.rootStructureName
self.pins = {}
# the list of all blockage shapes
self.blockages = []
self.blockages=[]
# all the paths we've routed so far (to supplement the blockages)
self.paths = []
@@ -101,9 +100,9 @@ class router:
This doesn't consider whether the obstacles will be pins or not. They get reset later
if they are not actually a blockage.
"""
for layer in self.layers:
self.get_blockages(self.top_name)
#for layer in [self.vert_layer_number,self.horiz_layer_number]:
# self.get_blockages(layer)
self.get_blockages(self.horiz_layer_number)
def clear_pins(self):
"""
@@ -207,38 +206,50 @@ class router:
self.rg.add_blockage_shape(ll,ur,zlayer)
def get_blockages(self, sref, mirr = 1, angle = math.radians(float(0)), xyShift = (0, 0)):
def get_blockages(self, layer_num):
"""
Recursive find boundaries as blockages to the routing grid.
Recurses for each Structure in GDS.
"""
for boundary in self.layout.structures[sref].boundaries:
coord_trans = self.translate_coordinates(boundary.coordinates, mirr, angle, xyShift)
shape_coords = self.min_max_coord(coord_trans)
shape = self.convert_shape_to_units(shape_coords)
# only consider the two layers that we are routing on
if boundary.drawingLayer in [self.vert_layer_number,self.horiz_layer_number]:
# store the blockages as pin layouts so they are easy to compare etc.
self.blockages.append(pin_layout("blockage",shape,boundary.drawingLayer))
shapes = self.layout.getAllShapesInStructureList(layer_num)
for boundary in shapes:
rect = [vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])]
new_pin = pin_layout("blockage",rect,layer_num)
self.blockages.append(new_pin)
# for boundary in self.layout.structures[sref].boundaries:
# coord_trans = self.translate_coordinates(boundary.coordinates, mirr, angle, xyShift)
# shape_coords = self.min_max_coord(coord_trans)
# shape = self.convert_shape_to_units(shape_coords)
# # only consider the two layers that we are routing on
# if boundary.drawingLayer in [self.vert_layer_number,self.horiz_layer_number]:
# # store the blockages as pin layouts so they are easy to compare etc.
# new_pin = pin_layout("blockage",shape,boundary.drawingLayer)
# # avoid repeated blockage pins
# if new_pin not in self.blockages:
# self.blockages.append(new_pin)
# recurse given the mirror, angle, etc.
for cur_sref in self.layout.structures[sref].srefs:
sMirr = 1
if cur_sref.transFlags[0] == True:
sMirr = -1
sAngle = math.radians(float(0))
if cur_sref.rotateAngle:
sAngle = math.radians(float(cur_sref.rotateAngle))
sAngle += angle
x = cur_sref.coordinates[0]
y = cur_sref.coordinates[1]
newX = (x)*math.cos(angle) - mirr*(y)*math.sin(angle) + xyShift[0]
newY = (x)*math.sin(angle) + mirr*(y)*math.cos(angle) + xyShift[1]
sxyShift = (newX, newY)
# # recurse given the mirror, angle, etc.
# for cur_sref in self.layout.structures[sref].srefs:
# sMirr = 1
# if cur_sref.transFlags[0] == True:
# sMirr = -1
# sAngle = math.radians(float(0))
# if cur_sref.rotateAngle:
# sAngle = math.radians(float(cur_sref.rotateAngle))
# sAngle += angle
# x = cur_sref.coordinates[0]
# y = cur_sref.coordinates[1]
# newX = (x)*math.cos(angle) - mirr*(y)*math.sin(angle) + xyShift[0]
# newY = (x)*math.sin(angle) + mirr*(y)*math.cos(angle) + xyShift[1]
# sxyShift = (newX, newY)
self.get_blockages(cur_sref.sName, sMirr, sAngle, sxyShift)
# self.get_blockages(cur_sref.sName, sMirr, sAngle, sxyShift)
def convert_point_to_units(self,p):
"""
@@ -248,21 +259,25 @@ class router:
pt=pt.scale(self.track_widths[0],self.track_widths[1],1)
return pt
def convert_blockage_to_tracks(self,shape,round_bigger=False):
def convert_blockage_to_tracks(self,shape):
"""
Convert a rectangular blockage shape into track units.
"""
[ll,ur] = shape
ll = snap_to_grid(ll)
ur = snap_to_grid(ur)
(ll,ur) = shape
# ll = snap_to_grid(ll)
# ur = snap_to_grid(ur)
# to scale coordinates to tracks
#debug.info(1,"Converting [ {0} , {1} ]".format(ll,ur))
debug.info(3,"Converting [ {0} , {1} ]".format(ll,ur))
old_ll = ll
old_ur = ur
ll=ll.scale(self.track_factor)
ur=ur.scale(self.track_factor)
ll = ll.floor() if round_bigger else ll.round()
ur = ur.ceil() if round_bigger else ur.round()
#debug.info(1,"Converted [ {0} , {1} ]".format(ll,ur))
ll = ll.floor()
ur = ur.ceil()
if ll[0]<45 and ll[0]>35 and ll[1]<10 and ll[1]>0:
debug.info(0,"Converting [ {0} , {1} ]".format(old_ll,old_ur))
debug.info(0,"Converted [ {0} , {1} ]".format(ll,ur))
return [ll,ur]
def convert_pin_to_tracks(self, pin):
@@ -271,9 +286,9 @@ class router:
If no on-grid pins are found, it searches for the nearest off-grid pin(s).
If a pin has insufficent overlap, it returns the blockage list to avoid it.
"""
[ll,ur] = pin.rect
ll = snap_to_grid(ll)
ur = snap_to_grid(ur)
(ll,ur) = pin.rect
#ll = snap_to_grid(ll)
#ur = snap_to_grid(ur)
#debug.info(1,"Converting [ {0} , {1} ]".format(ll,ur))
@@ -401,6 +416,68 @@ class router:
self.write_debug_gds()
debug.check(found_pin,"Unable to find pin on grid.")
def write_debug_gds(self):
"""
Write out a GDS file with the routing grid and search information annotated on it.
"""
# Only add the debug info to the gds file if we have any debugging on.
# This is because we may reroute a wire with detours and don't want the debug information.
if OPTS.debug_level==0: return
self.add_router_info()
debug.error("Writing debug_route.gds")
self.cell.gds_write("debug_route.gds")
def add_router_info(self):
"""
Write the routing grid and router cost, blockage, pins on
the boundary layer for debugging purposes. This can only be
called once or the labels will overlap.
"""
debug.info(0,"Adding router info")
grid_keys=self.rg.map.keys()
partial_track=vector(0,self.track_width/6.0)
for g in grid_keys:
continue # for now...
shape = self.convert_full_track_to_shape(g)
self.cell.add_rect(layer="boundary",
offset=shape[0],
width=shape[1].x-shape[0].x,
height=shape[1].y-shape[0].y)
# These are the on grid pins
#rect = self.convert_track_to_pin(g)
#self.cell.add_rect(layer="boundary",
# offset=rect[0],
# width=rect[1].x-rect[0].x,
# height=rect[1].y-rect[0].y)
t=self.rg.map[g].get_type()
# midpoint offset
off=vector((shape[1].x+shape[0].x)/2,
(shape[1].y+shape[0].y)/2)
if g[2]==1:
# Upper layer is upper right label
type_off=off+partial_track
else:
# Lower layer is lower left label
type_off=off-partial_track
if t!=None:
self.cell.add_label(text=str(t),
layer="text",
offset=type_off)
self.cell.add_label(text="{0},{1}".format(g[0],g[1]),
layer="text",
offset=shape[0],
zoom=0.05)
for blockage in self.blockages:
self.cell.add_rect(layer="boundary",
offset=blockage.ll(),
width=blockage.width(),
height=blockage.height())
# FIXME: This should be replaced with vector.snap_to_grid at some point
def snap_to_grid(offset):
+4 -58
View File
@@ -26,7 +26,7 @@ class signal_router(router):
def create_routing_grid(self):
"""
Create a routing grid that spans given area. Wires cannot exist outside region.
Create a sprase routing grid with A* expansion functions.
"""
# We will add a halo around the boundary
# of this many tracks
@@ -44,6 +44,8 @@ class signal_router(router):
This is used to speed up the routing when there is not much detouring needed.
"""
self.cell = cell
self.source_pin_name = src
self.target_pin_name = dest
# Clear the pins if we have previously routed
if (hasattr(self,'rg')):
@@ -73,7 +75,7 @@ class signal_router(router):
# returns the path in tracks
(path,cost) = self.rg.astar_route(detour_scale)
(path,cost) = self.rg.route(detour_scale)
if path:
debug.info(1,"Found path: cost={0} ".format(cost))
debug.info(2,str(path))
@@ -158,59 +160,3 @@ class signal_router(router):
def write_debug_gds(self):
"""
Write out a GDS file with the routing grid and search information annotated on it.
"""
# Only add the debug info to the gds file if we have any debugging on.
# This is because we may reroute a wire with detours and don't want the debug information.
if OPTS.debug_level==0: return
self.add_router_info()
pin_names = list(self.pins.keys())
debug.error("Writing debug_route.gds from {0} to {1}".format(self.source_pin_name,self.target_pin_name))
self.cell.gds_write("debug_route.gds")
def add_router_info(self):
"""
Write the routing grid and router cost, blockage, pins on
the boundary layer for debugging purposes. This can only be
called once or the labels will overlap.
"""
debug.info(0,"Adding router info for {0} to {1}".format(self.source_pin_name,self.target_pin_name))
grid_keys=self.rg.map.keys()
partial_track=vector(0,self.track_width/6.0)
for g in grid_keys:
shape = self.convert_full_track_to_shape(g)
self.cell.add_rect(layer="boundary",
offset=shape[0],
width=shape[1].x-shape[0].x,
height=shape[1].y-shape[0].y)
# These are the on grid pins
#rect = self.convert_track_to_pin(g)
#self.cell.add_rect(layer="boundary",
# offset=rect[0],
# width=rect[1].x-rect[0].x,
# height=rect[1].y-rect[0].y)
t=self.rg.map[g].get_type()
# midpoint offset
off=vector((shape[1].x+shape[0].x)/2,
(shape[1].y+shape[0].y)/2)
if g[2]==1:
# Upper layer is upper right label
type_off=off+partial_track
else:
# Lower layer is lower left label
type_off=off-partial_track
if t!=None:
self.cell.add_label(text=str(t),
layer="text",
offset=type_off)
self.cell.add_label(text="{0},{1}".format(g[0],g[1]),
layer="text",
offset=shape[0],
zoom=0.05)
+24 -18
View File
@@ -66,24 +66,22 @@ class supply_router(router):
# Add blockages from previous routes
self.add_path_blockages()
# Now add the src/tgt if they are not blocked by other shapes
self.add_pin(vdd_name,True)
#self.add_pin()
# source pin will be a specific layout pin
# target pin will be the rails only
# returns the path in tracks
(path,cost) = self.rg.route(detour_scale)
if path:
debug.info(1,"Found path: cost={0} ".format(cost))
debug.info(2,str(path))
self.add_route(path)
return True
else:
self.write_debug_gds()
# clean up so we can try a reroute
self.clear_pins()
# (path,cost) = self.rg.route(detour_scale)
# if path:
# debug.info(1,"Found path: cost={0} ".format(cost))
# debug.info(2,str(path))
# self.add_route(path)
# return True
# else:
# self.write_debug_gds()
# # clean up so we can try a reroute
# self.clear_pins()
self.write_debug_gds()
return False
@@ -114,6 +112,17 @@ class supply_router(router):
self.cell.add_route(self.layers,abs_path)
def create_routing_grid(self):
"""
Create a sprase routing grid with A* expansion functions.
"""
# We will add a halo around the boundary
# of this many tracks
size = self.ur - self.ll
debug.info(1,"Size: {0} x {1}".format(size.x,size.y))
import supply_grid
self.rg = supply_grid.supply_grid()
##########################
@@ -135,6 +144,3 @@ class supply_router(router):
""" Create alternating vdd/gnd lines horizontally """
pass
def route(self):
#self.create_grid()
pass
+1 -1
View File
@@ -38,7 +38,7 @@ class no_blockages_test(openram_test):
self.connect_inst([])
r=router(gds_file)
layer_stack =("metal3","via1","metal2")
layer_stack =("metal3","via2","metal2")
self.assertTrue(r.route(self,layer_stack))
r=routing("10_supply_grid_test_{0}".format(OPTS.tech_name))