mirror of https://github.com/VLSIDA/OpenRAM.git
Add expanded blockages for paths an enclosures to handle wide metal spacing rules.
This commit is contained in:
parent
b24c8a42a1
commit
4d30f214da
|
|
@ -8,6 +8,10 @@ class direction(Enum):
|
||||||
WEST = 4
|
WEST = 4
|
||||||
UP = 5
|
UP = 5
|
||||||
DOWN = 6
|
DOWN = 6
|
||||||
|
NORTHEAST = 7
|
||||||
|
NORTHWEST = 8
|
||||||
|
SOUTHEAST = 9
|
||||||
|
SOUTHWEST = 10
|
||||||
|
|
||||||
|
|
||||||
def get_offset(direct):
|
def get_offset(direct):
|
||||||
|
|
@ -26,8 +30,16 @@ class direction(Enum):
|
||||||
offset = vector3d(0,0,1)
|
offset = vector3d(0,0,1)
|
||||||
elif direct==direction.DOWN:
|
elif direct==direction.DOWN:
|
||||||
offset = vector3d(0,0,-1)
|
offset = vector3d(0,0,-1)
|
||||||
|
elif direct==direction.NORTHEAST:
|
||||||
|
offset = vector3d(1,1,0)
|
||||||
|
elif direct==direction.NORTHWEST:
|
||||||
|
offset = vector3d(-1,1,0)
|
||||||
|
elif direct==direction.SOUTHEAST:
|
||||||
|
offset = vector3d(1,-1,0)
|
||||||
|
elif direct==direction.SOUTHWEST:
|
||||||
|
offset = vector3d(-1,-1,0)
|
||||||
else:
|
else:
|
||||||
debug.error("Invalid direction {}".format(dirct))
|
debug.error("Invalid direction {}".format(direct))
|
||||||
|
|
||||||
return offset
|
return offset
|
||||||
|
|
||||||
|
|
@ -37,3 +49,16 @@ class direction(Enum):
|
||||||
def cardinal_offsets():
|
def cardinal_offsets():
|
||||||
return [direction.get_offset(d) for d in direction.cardinal_directions()]
|
return [direction.get_offset(d) for d in direction.cardinal_directions()]
|
||||||
|
|
||||||
|
def all_directions():
|
||||||
|
return [direction.NORTH, direction.EAST, direction.SOUTH, direction.WEST,
|
||||||
|
direction.NORTHEAST, direction.NORTHWEST, direction.SOUTHEAST, direction.SOUTHWEST]
|
||||||
|
|
||||||
|
def all_offsets():
|
||||||
|
return [direction.get_offset(d) for d in direction.all_directions()]
|
||||||
|
|
||||||
|
def all_neighbors(cell):
|
||||||
|
return [cell+x for x in direction.all_offsets()]
|
||||||
|
|
||||||
|
def cardinal_neighbors(cell):
|
||||||
|
return [cell+x for x in direction.cardinal_offsets()]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,17 +8,18 @@ from vector3d import vector3d
|
||||||
|
|
||||||
|
|
||||||
def increment_set(curset, direct):
|
def increment_set(curset, direct):
|
||||||
"""
|
"""
|
||||||
Return the cells incremented in given direction
|
Return the cells incremented in given direction
|
||||||
"""
|
"""
|
||||||
offset = direction.get_offset(direct)
|
offset = direction.get_offset(direct)
|
||||||
|
|
||||||
|
newset = set()
|
||||||
|
for c in curset:
|
||||||
|
newc = c+offset
|
||||||
|
newset.add(newc)
|
||||||
|
|
||||||
|
return newset
|
||||||
|
|
||||||
newset = set()
|
|
||||||
for c in curset:
|
|
||||||
newc = c+offset
|
|
||||||
newset.add(newc)
|
|
||||||
|
|
||||||
return newset
|
|
||||||
|
|
||||||
def remove_border(curset, direct):
|
def remove_border(curset, direct):
|
||||||
"""
|
"""
|
||||||
|
|
@ -26,7 +27,7 @@ def remove_border(curset, direct):
|
||||||
"""
|
"""
|
||||||
border = get_border(curset, direct)
|
border = get_border(curset, direct)
|
||||||
curset.difference_update(border)
|
curset.difference_update(border)
|
||||||
|
|
||||||
|
|
||||||
def get_upper_right(curset):
|
def get_upper_right(curset):
|
||||||
ur = None
|
ur = None
|
||||||
|
|
@ -43,48 +44,48 @@ def get_lower_left(curset):
|
||||||
return ll
|
return ll
|
||||||
|
|
||||||
def get_border( curset, direct):
|
def get_border( curset, direct):
|
||||||
"""
|
"""
|
||||||
Return the furthest cell(s) in a given direction.
|
Return the furthest cell(s) in a given direction.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# find direction-most cell(s)
|
# find direction-most cell(s)
|
||||||
maxc = []
|
maxc = []
|
||||||
if direct==direction.NORTH:
|
if direct==direction.NORTH:
|
||||||
for c in curset:
|
for c in curset:
|
||||||
if len(maxc)==0 or c.y>maxc[0].y:
|
if len(maxc)==0 or c.y>maxc[0].y:
|
||||||
maxc = [c]
|
maxc = [c]
|
||||||
elif c.y==maxc[0].y:
|
elif c.y==maxc[0].y:
|
||||||
maxc.append(c)
|
maxc.append(c)
|
||||||
elif direct==direct.SOUTH:
|
elif direct==direct.SOUTH:
|
||||||
for c in curset:
|
for c in curset:
|
||||||
if len(maxc)==0 or c.y<maxc[0].y:
|
if len(maxc)==0 or c.y<maxc[0].y:
|
||||||
maxc = [c]
|
maxc = [c]
|
||||||
elif c.y==maxc[0].y:
|
elif c.y==maxc[0].y:
|
||||||
maxc.append(c)
|
maxc.append(c)
|
||||||
elif direct==direct.EAST:
|
elif direct==direct.EAST:
|
||||||
for c in curset:
|
for c in curset:
|
||||||
if len(maxc)==0 or c.x>maxc[0].x:
|
if len(maxc)==0 or c.x>maxc[0].x:
|
||||||
maxc = [c]
|
maxc = [c]
|
||||||
elif c.x==maxc[0].x:
|
elif c.x==maxc[0].x:
|
||||||
maxc.append(c)
|
maxc.append(c)
|
||||||
elif direct==direct.WEST:
|
elif direct==direct.WEST:
|
||||||
for c in curset:
|
for c in curset:
|
||||||
if len(maxc)==0 or c.x<maxc[0].x:
|
if len(maxc)==0 or c.x<maxc[0].x:
|
||||||
maxc = [c]
|
maxc = [c]
|
||||||
elif c.x==maxc[0].x:
|
elif c.x==maxc[0].x:
|
||||||
maxc.append(c)
|
maxc.append(c)
|
||||||
|
|
||||||
newset = set(maxc)
|
newset = set(maxc)
|
||||||
return newset
|
return newset
|
||||||
|
|
||||||
def expand_border(curset, direct):
|
def expand_border(curset, direct):
|
||||||
"""
|
"""
|
||||||
Expand the current set of sells in a given direction.
|
Expand the current set of sells in a given direction.
|
||||||
Only return the contiguous cells.
|
Only return the contiguous cells.
|
||||||
"""
|
"""
|
||||||
border_set = get_border(curset, direct)
|
border_set = get_border(curset, direct)
|
||||||
next_border_set = increment_set(border_set, direct)
|
next_border_set = increment_set(border_set, direct)
|
||||||
return next_border_set
|
return next_border_set
|
||||||
|
|
||||||
def expand_borders(curset):
|
def expand_borders(curset):
|
||||||
"""
|
"""
|
||||||
|
|
@ -94,6 +95,47 @@ def expand_borders(curset):
|
||||||
south_set=expand_border(curset,direction.SOUTH)
|
south_set=expand_border(curset,direction.SOUTH)
|
||||||
east_set=expand_border(curset,direction.EAST)
|
east_set=expand_border(curset,direction.EAST)
|
||||||
west_set=expand_border(curset,direction.WEST)
|
west_set=expand_border(curset,direction.WEST)
|
||||||
|
|
||||||
return(north_set, east_set, south_set, west_set)
|
return(north_set, east_set, south_set, west_set)
|
||||||
|
|
||||||
|
def inflate_cell(cell, distance):
|
||||||
|
"""
|
||||||
|
Expand the current cell in all directions and return the set.
|
||||||
|
"""
|
||||||
|
newset = set(cell)
|
||||||
|
|
||||||
|
if distance==0:
|
||||||
|
return(newset)
|
||||||
|
|
||||||
|
# recursively call this based on the distance
|
||||||
|
for offset in direction.all_offsets():
|
||||||
|
# FIXME: If distance is large this will be inefficient, but it is like 1 or 2
|
||||||
|
newset.update(inflate_cell(cell+offset,distance-1))
|
||||||
|
|
||||||
|
return newset
|
||||||
|
|
||||||
|
def inflate_set(curset, distance):
|
||||||
|
"""
|
||||||
|
Expand the set in all directions by the given number of grids.
|
||||||
|
"""
|
||||||
|
if distance<=0:
|
||||||
|
return curset
|
||||||
|
|
||||||
|
newset = curset.copy()
|
||||||
|
# Add all my neighbors
|
||||||
|
for c in curset:
|
||||||
|
newset.update(direction.all_neighbors(c))
|
||||||
|
# Recurse with less depth
|
||||||
|
return inflate_set(newset,distance-1)
|
||||||
|
|
||||||
|
def flatten_set(curset):
|
||||||
|
"""
|
||||||
|
Flatten until we have a set of vector3d objects.
|
||||||
|
"""
|
||||||
|
newset = set()
|
||||||
|
for c in curset:
|
||||||
|
if isinstance(c,vector3d):
|
||||||
|
newset.add(c)
|
||||||
|
else:
|
||||||
|
newset.update(flatten_set(c))
|
||||||
|
return newset
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ from direction import direction
|
||||||
from pin_layout import pin_layout
|
from pin_layout import pin_layout
|
||||||
from vector3d import vector3d
|
from vector3d import vector3d
|
||||||
from vector import vector
|
from vector import vector
|
||||||
|
import grid_utils
|
||||||
from tech import drc
|
from tech import drc
|
||||||
import debug
|
import debug
|
||||||
|
|
||||||
|
|
@ -34,6 +35,7 @@ class pin_group:
|
||||||
|
|
||||||
# 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 for routing this group.
|
# These are blockages for other nets but unblocked for routing this group.
|
||||||
|
# These are also blockages if we used a simple enclosure to route to a rail.
|
||||||
self.blockages = set()
|
self.blockages = set()
|
||||||
|
|
||||||
# This is a set of pin_layout shapes to cover the grids
|
# This is a set of pin_layout shapes to cover the grids
|
||||||
|
|
@ -65,7 +67,7 @@ class pin_group:
|
||||||
|
|
||||||
def size(self):
|
def size(self):
|
||||||
return len(self.grids)
|
return len(self.grids)
|
||||||
|
|
||||||
def set_routed(self, value=True):
|
def set_routed(self, value=True):
|
||||||
self.routed = value
|
self.routed = value
|
||||||
|
|
||||||
|
|
@ -550,7 +552,7 @@ class pin_group:
|
||||||
|
|
||||||
return g1_grids,g2_grids
|
return g1_grids,g2_grids
|
||||||
|
|
||||||
def convert_pin(self, router):
|
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 could be
|
||||||
|
|
@ -563,25 +565,25 @@ class pin_group:
|
||||||
for pin in pin_list:
|
for pin in pin_list:
|
||||||
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
|
||||||
pin_in_tracks=router.convert_pin_to_tracks(self.name, pin)
|
pin_in_tracks=self.router.convert_pin_to_tracks(self.name, pin)
|
||||||
|
|
||||||
pin_set.update(pin_in_tracks)
|
pin_set.update(pin_in_tracks)
|
||||||
# Blockages will be a super-set of pins since it uses the inflated pin shape.
|
# Blockages will be a super-set of pins since it uses the inflated pin shape.
|
||||||
blockage_in_tracks = router.convert_blockage(pin)
|
blockage_in_tracks = self.router.convert_blockage(pin)
|
||||||
|
|
||||||
blockage_set.update(blockage_in_tracks)
|
blockage_set.update(blockage_in_tracks)
|
||||||
|
|
||||||
# If we have a blockage, we must remove the grids
|
# If we have a blockage, we must remove the grids
|
||||||
# Remember, this excludes the pin blockages already
|
# Remember, this excludes the pin blockages already
|
||||||
shared_set = pin_set & router.blocked_grids
|
shared_set = pin_set & self.router.blocked_grids
|
||||||
if len(shared_set)>0:
|
if len(shared_set)>0:
|
||||||
debug.info(2,"Removing pins {}".format(shared_set))
|
debug.info(2,"Removing pins {}".format(shared_set))
|
||||||
pin_set.difference_update(router.blocked_grids)
|
pin_set.difference_update(self.router.blocked_grids)
|
||||||
|
|
||||||
shared_set = blockage_set & router.blocked_grids
|
shared_set = blockage_set & self.router.blocked_grids
|
||||||
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(router.blocked_grids)
|
blockage_set.difference_update(self.router.blocked_grids)
|
||||||
|
|
||||||
# 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(blockage_set)==0):
|
if (len(pin_set)==0 and len(blockage_set)==0):
|
||||||
|
|
@ -596,3 +598,60 @@ class pin_group:
|
||||||
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))
|
||||||
|
|
||||||
|
def recurse_simple_overlap_enclosure(self, start_set, direct):
|
||||||
|
"""
|
||||||
|
Recursive function to return set of tracks that connects to
|
||||||
|
the actual supply rail wire in a given direction (or terminating
|
||||||
|
when any track is no longer in the supply rail.
|
||||||
|
"""
|
||||||
|
next_set = grid_utils.expand_border(start_set, direct)
|
||||||
|
|
||||||
|
supply_tracks = self.router.supply_rail_tracks[self.name]
|
||||||
|
supply_wire_tracks = self.router.supply_rail_wire_tracks[self.name]
|
||||||
|
|
||||||
|
supply_overlap = next_set & supply_tracks
|
||||||
|
wire_overlap = next_set & supply_wire_tracks
|
||||||
|
|
||||||
|
# If the rail overlap is the same, we are done, since we connected to the actual wire
|
||||||
|
if len(wire_overlap)==len(start_set):
|
||||||
|
new_set = start_set | wire_overlap
|
||||||
|
# If the supply overlap is the same, keep expanding unti we hit the wire or move out of the rail region
|
||||||
|
elif len(supply_overlap)==len(start_set):
|
||||||
|
recurse_set = self.recurse_simple_overlap_enclosure(supply_overlap, direct)
|
||||||
|
new_set = start_set | supply_overlap | recurse_set
|
||||||
|
else:
|
||||||
|
# If we got no next set, we are done, can't expand!
|
||||||
|
new_set = set()
|
||||||
|
|
||||||
|
return new_set
|
||||||
|
|
||||||
|
def create_simple_overlap_enclosure(self, start_set):
|
||||||
|
"""
|
||||||
|
This takes a set of tracks that overlap a supply rail and creates an enclosure
|
||||||
|
that is ensured to overlap the supply rail wire.
|
||||||
|
It then adds rectangle(s) for the enclosure.
|
||||||
|
"""
|
||||||
|
|
||||||
|
additional_set = set()
|
||||||
|
# Check the layer of any element in the pin to determine which direction to route it
|
||||||
|
e = next(iter(start_set))
|
||||||
|
new_set = start_set.copy()
|
||||||
|
if e.z==0:
|
||||||
|
new_set = self.recurse_simple_overlap_enclosure(start_set, direction.NORTH)
|
||||||
|
if not new_set:
|
||||||
|
new_set = self.recurse_simple_overlap_enclosure(start_set, direction.SOUTH)
|
||||||
|
else:
|
||||||
|
new_set = self.recurse_simple_overlap_enclosure(start_set, direction.EAST)
|
||||||
|
if not new_set:
|
||||||
|
new_set = self.recurse_simple_overlap_enclosure(start_set, direction.WEST)
|
||||||
|
|
||||||
|
# Expand the pin grid set to include some extra grids that connect the supply rail
|
||||||
|
self.grids.update(new_set)
|
||||||
|
|
||||||
|
# Add the inflated set so we don't get wide metal spacing issues (if it exists)
|
||||||
|
self.blockages.update(grid_utils.inflate_set(new_set,self.router.supply_rail_space_width))
|
||||||
|
|
||||||
|
# Add the polygon enclosures and set this pin group as routed
|
||||||
|
self.set_routed()
|
||||||
|
self.enclosures = self.compute_enclosures()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,8 @@ class router(router_tech):
|
||||||
### The routed data structures
|
### The routed data structures
|
||||||
# A list of paths that have been "routed"
|
# A list of paths that have been "routed"
|
||||||
self.paths = []
|
self.paths = []
|
||||||
|
# A list of path blockages (they might be expanded for wide metal DRC)
|
||||||
|
self.path_blockages = []
|
||||||
|
|
||||||
# The boundary will determine the limits to the size of the routing grid
|
# The boundary will determine the limits to the size of the routing grid
|
||||||
self.boundary = self.layout.measureBoundary(self.top_name)
|
self.boundary = self.layout.measureBoundary(self.top_name)
|
||||||
|
|
@ -326,10 +328,16 @@ class router(router_tech):
|
||||||
self.set_supply_rail_blocked(True)
|
self.set_supply_rail_blocked(True)
|
||||||
|
|
||||||
# Block all of the pin components (some will be unblocked if they're a source/target)
|
# Block all of the pin components (some will be unblocked if they're a source/target)
|
||||||
|
# Also block the previous routes
|
||||||
for name in self.pin_groups.keys():
|
for name in self.pin_groups.keys():
|
||||||
blockage_grids = {y for x in self.pin_groups[name] for y in x.grids}
|
blockage_grids = {y for x in self.pin_groups[name] for y in x.grids}
|
||||||
self.set_blockages(blockage_grids,True)
|
self.set_blockages(blockage_grids,True)
|
||||||
|
blockage_grids = {y for x in self.pin_groups[name] for y in x.blockages}
|
||||||
|
self.set_blockages(blockage_grids,True)
|
||||||
|
|
||||||
|
# FIXME: These duplicate a bit of work
|
||||||
|
# These are the paths that have already been routed.
|
||||||
|
self.set_path_blockages()
|
||||||
|
|
||||||
# Don't mark the other components as targets since we want to route
|
# Don't mark the other components as targets since we want to route
|
||||||
# directly to a rail, but unblock all the source components so we can
|
# directly to a rail, but unblock all the source components so we can
|
||||||
|
|
@ -337,8 +345,6 @@ class router(router_tech):
|
||||||
blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids}
|
blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids}
|
||||||
self.set_blockages(blockage_grids,False)
|
self.set_blockages(blockage_grids,False)
|
||||||
|
|
||||||
# These are the paths that have already been routed.
|
|
||||||
self.set_path_blockages()
|
|
||||||
|
|
||||||
# def translate_coordinates(self, coord, mirr, angle, xyShift):
|
# def translate_coordinates(self, coord, mirr, angle, xyShift):
|
||||||
# """
|
# """
|
||||||
|
|
@ -387,16 +393,6 @@ class router(router_tech):
|
||||||
# z direction
|
# z direction
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
|
|
||||||
def add_path_blockages(self):
|
|
||||||
"""
|
|
||||||
Go through all of the past paths and add them as blockages.
|
|
||||||
This is so we don't have to write/reload the GDS.
|
|
||||||
"""
|
|
||||||
for path in self.paths:
|
|
||||||
for grid in path:
|
|
||||||
self.rg.set_blocked(grid)
|
|
||||||
|
|
||||||
def clear_blockages(self):
|
def clear_blockages(self):
|
||||||
"""
|
"""
|
||||||
Clear all blockages on the grid.
|
Clear all blockages on the grid.
|
||||||
|
|
@ -411,9 +407,9 @@ class router(router_tech):
|
||||||
def set_path_blockages(self,value=True):
|
def set_path_blockages(self,value=True):
|
||||||
""" Flag the paths as blockages """
|
""" Flag the paths as blockages """
|
||||||
# These are the paths that have already been routed.
|
# These are the paths that have already been routed.
|
||||||
# This adds the initial blockges of the design
|
for path_set in self.path_blockages:
|
||||||
for p in self.paths:
|
for c in path_set:
|
||||||
p.set_blocked(value)
|
self.rg.set_blocked(c,value)
|
||||||
|
|
||||||
def get_blockage_tracks(self, ll, ur, z):
|
def get_blockage_tracks(self, ll, ur, z):
|
||||||
debug.info(3,"Converting blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z))
|
debug.info(3,"Converting blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z))
|
||||||
|
|
@ -696,7 +692,7 @@ class router(router_tech):
|
||||||
Convert the pin groups into pin tracks and blockage tracks.
|
Convert the pin groups into pin tracks and blockage tracks.
|
||||||
"""
|
"""
|
||||||
for pg in self.pin_groups[pin_name]:
|
for pg in self.pin_groups[pin_name]:
|
||||||
pg.convert_pin(self)
|
pg.convert_pin()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -918,13 +914,6 @@ class router(router_tech):
|
||||||
return newpath
|
return newpath
|
||||||
|
|
||||||
|
|
||||||
def add_path_blockages(self):
|
|
||||||
"""
|
|
||||||
Go through all of the past paths and add them as blockages.
|
|
||||||
This is so we don't have to write/reload the GDS.
|
|
||||||
"""
|
|
||||||
for path in self.paths:
|
|
||||||
self.rg.block_path(path)
|
|
||||||
|
|
||||||
def run_router(self, detour_scale):
|
def run_router(self, detour_scale):
|
||||||
"""
|
"""
|
||||||
|
|
@ -936,6 +925,9 @@ class router(router_tech):
|
||||||
debug.info(2,"Found path: cost={0} ".format(cost))
|
debug.info(2,"Found path: cost={0} ".format(cost))
|
||||||
debug.info(3,str(path))
|
debug.info(3,str(path))
|
||||||
self.paths.append(path)
|
self.paths.append(path)
|
||||||
|
path_set = grid_utils.flatten_set(path)
|
||||||
|
inflated_path = grid_utils.inflate_set(path_set,self.supply_rail_space_width)
|
||||||
|
self.path_blockages.append(inflated_path)
|
||||||
self.add_route(path)
|
self.add_route(path)
|
||||||
else:
|
else:
|
||||||
self.write_debug_gds("failed_route.gds")
|
self.write_debug_gds("failed_route.gds")
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ class supply_router(router):
|
||||||
self.route_pins_to_rails(gnd_name)
|
self.route_pins_to_rails(gnd_name)
|
||||||
#self.write_debug_gds("debug_pin_routes.gds",stop_program=True)
|
#self.write_debug_gds("debug_pin_routes.gds",stop_program=True)
|
||||||
|
|
||||||
#self.write_debug_gds("final.gds")
|
#self.write_debug_gds("final.gds",False)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
@ -110,77 +110,31 @@ class supply_router(router):
|
||||||
This checks for simple cases where a pin component already overlaps a supply rail.
|
This checks for simple cases where a pin component already overlaps a supply rail.
|
||||||
It will add an enclosure to ensure the overlap in wide DRC rule cases.
|
It will add an enclosure to ensure the overlap in wide DRC rule cases.
|
||||||
"""
|
"""
|
||||||
|
debug.info(1,"Routing simple overlap pins for {0}".format(pin_name))
|
||||||
|
|
||||||
|
# These are the wire tracks
|
||||||
|
wire_tracks = self.supply_rail_wire_tracks[pin_name]
|
||||||
|
# These are the wire and space tracks
|
||||||
supply_tracks = self.supply_rail_tracks[pin_name]
|
supply_tracks = self.supply_rail_tracks[pin_name]
|
||||||
|
|
||||||
for pg in self.pin_groups[pin_name]:
|
for pg in self.pin_groups[pin_name]:
|
||||||
if pg.is_routed():
|
if pg.is_routed():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
common_set = supply_tracks & pg.grids
|
# First, check if we just overlap, if so, we are done.
|
||||||
|
overlap_grids = wire_tracks & pg.grids
|
||||||
if len(common_set)>0:
|
if len(overlap_grids)>0:
|
||||||
self.create_simple_overlap_enclosure(pin_name, common_set)
|
|
||||||
pg.set_routed()
|
pg.set_routed()
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Else, if we overlap some of the space track, we can patch it with an enclosure
|
||||||
|
common_set = supply_tracks & pg.grids
|
||||||
|
if len(common_set)>0:
|
||||||
|
pg.create_simple_overlap_enclosure(common_set)
|
||||||
|
pg.add_enclosure(self.cell)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def recurse_simple_overlap_enclosure(self, pin_name, start_set, direct):
|
|
||||||
"""
|
|
||||||
Recursive function to return set of tracks that connects to
|
|
||||||
the actual supply rail wire in a given direction (or terminating
|
|
||||||
when any track is no longer in the supply rail.
|
|
||||||
"""
|
|
||||||
next_set = grid_utils.expand_border(start_set, direct)
|
|
||||||
|
|
||||||
supply_tracks = self.supply_rail_tracks[pin_name]
|
|
||||||
supply_wire_tracks = self.supply_rail_wire_tracks[pin_name]
|
|
||||||
|
|
||||||
supply_overlap = next_set & supply_tracks
|
|
||||||
wire_overlap = next_set & supply_wire_tracks
|
|
||||||
|
|
||||||
# If the rail overlap is the same, we are done, since we connected to the actual wire
|
|
||||||
if len(wire_overlap)==len(start_set):
|
|
||||||
new_set = start_set | wire_overlap
|
|
||||||
# If the supply overlap is the same, keep expanding unti we hit the wire or move out of the rail region
|
|
||||||
elif len(supply_overlap)==len(start_set):
|
|
||||||
recurse_set = self.recurse_simple_overlap_enclosure(pin_name, supply_overlap, direct)
|
|
||||||
new_set = start_set | supply_overlap | recurse_set
|
|
||||||
else:
|
|
||||||
# If we got no next set, we are done, can't expand!
|
|
||||||
new_set = set()
|
|
||||||
|
|
||||||
return new_set
|
|
||||||
|
|
||||||
def create_simple_overlap_enclosure(self, pin_name, start_set):
|
|
||||||
"""
|
|
||||||
This takes a set of tracks that overlap a supply rail and creates an enclosure
|
|
||||||
that is ensured to overlap the supply rail wire.
|
|
||||||
It then adds rectangle(s) for the enclosure.
|
|
||||||
"""
|
|
||||||
additional_set = set()
|
|
||||||
# Check the layer of any element in the pin to determine which direction to route it
|
|
||||||
e = next(iter(start_set))
|
|
||||||
new_set = start_set.copy()
|
|
||||||
if e.z==0:
|
|
||||||
new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.NORTH)
|
|
||||||
if not new_set:
|
|
||||||
new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.SOUTH)
|
|
||||||
else:
|
|
||||||
new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.EAST)
|
|
||||||
if not new_set:
|
|
||||||
new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.WEST)
|
|
||||||
|
|
||||||
pg = pin_group(name=pin_name, pin_set=[], router=self)
|
|
||||||
pg.grids=new_set
|
|
||||||
enclosure_list = pg.compute_enclosures()
|
|
||||||
for pin in enclosure_list:
|
|
||||||
debug.info(2,"Adding simple overlap enclosure {0} {1}".format(pin_name, pin))
|
|
||||||
self.cell.add_rect(layer=pin.layer,
|
|
||||||
offset=pin.ll(),
|
|
||||||
width=pin.width(),
|
|
||||||
height=pin.height())
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def finalize_supply_rails(self, name):
|
def finalize_supply_rails(self, name):
|
||||||
"""
|
"""
|
||||||
|
|
@ -478,6 +432,7 @@ class supply_router(router):
|
||||||
for index,pg in enumerate(self.pin_groups[pin_name]):
|
for index,pg in enumerate(self.pin_groups[pin_name]):
|
||||||
if pg.is_routed():
|
if pg.is_routed():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
debug.info(2,"Routing component {0} {1}".format(pin_name, index))
|
debug.info(2,"Routing component {0} {1}".format(pin_name, index))
|
||||||
|
|
||||||
# Clear everything in the routing grid.
|
# Clear everything in the routing grid.
|
||||||
|
|
@ -498,7 +453,6 @@ class supply_router(router):
|
||||||
# Actually run the A* router
|
# Actually run the A* router
|
||||||
if not self.run_router(detour_scale=5):
|
if not self.run_router(detour_scale=5):
|
||||||
self.write_debug_gds()
|
self.write_debug_gds()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_supply_rail_target(self, pin_name):
|
def add_supply_rail_target(self, pin_name):
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue