Refactor how blocked_grids work. Must still calculate blockages based on enclosed pins.

This commit is contained in:
mrg 2021-01-11 11:12:45 -08:00
parent 504f9aa892
commit 7506ba81be
5 changed files with 78 additions and 61 deletions

View File

@ -41,10 +41,7 @@ class pin_group:
# or could not be part of the pin
self.secondary_grids = set()
# 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 also blockages if we
# used a simple enclosure to route to a rail.
# The set of blocked grids due to this pin
self.blockages = set()
# This is a set of pin_layout shapes to cover the grids
@ -421,16 +418,16 @@ class pin_group:
while True:
next_cell = row[-1] + offset1
# Can't move if not in the pin shape
if next_cell in self.grids and next_cell not in self.router.blocked_grids:
if next_cell in self.grids and next_cell not in self.router.get_blocked_grids():
row.append(next_cell)
else:
break
# Move in dir2 while we can
while True:
next_row = [x+offset2 for x in row]
next_row = [x + offset2 for x in row]
for cell in next_row:
# Can't move if any cell is not in the pin shape
if cell not in self.grids or cell in self.router.blocked_grids:
if cell not in self.grids or cell in self.router.get_blocked_grids():
break
else:
row = next_row
@ -606,9 +603,10 @@ class pin_group:
The secondary set of grids are "optional" pin shapes that
should be either blocked or part of the pin.
"""
# Set of tracks that overlap a pin
pin_set = set()
# Set of track adjacent to or paritally overlap a pin (not full DRC connection)
partial_set = set()
blockage_set = set()
for pin in self.pins:
debug.info(4, " Converting {0}".format(pin))
@ -621,25 +619,20 @@ class pin_group:
# Blockages will be a super-set of pins since
# it uses the inflated pin shape.
blockage_in_tracks = self.router.convert_blockage(pin)
blockage_set.update(blockage_in_tracks)
self.blockages.update(blockage_in_tracks)
# If we have a blockage, we must remove the grids
# Remember, this excludes the pin blockages already
shared_set = pin_set & self.router.blocked_grids
shared_set = pin_set & self.router.get_blocked_grids()
if len(shared_set) > 0:
debug.info(4, "Removing pins {}".format(shared_set))
pin_set.difference_update(shared_set)
shared_set = partial_set & self.router.blocked_grids
shared_set = partial_set & self.router.get_blocked_grids()
if len(shared_set) > 0:
debug.info(4, "Removing pins {}".format(shared_set))
partial_set.difference_update(shared_set)
shared_set = blockage_set & self.router.blocked_grids
if len(shared_set) > 0:
debug.info(4, "Removing blocks {}".format(shared_set))
blockage_set.difference_update(shared_set)
# 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):
# debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins))
for pin in self.pins:
@ -656,8 +649,11 @@ class pin_group:
self.pins))
self.router.write_debug_gds("blocked_pin.gds")
# Consider all the grids that would be blocked
self.grids = pin_set | partial_set
# Consider the fully connected set first and if not the partial set
if len(pin_set) > 0:
self.grids = pin_set
else:
self.grids = 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")

View File

@ -69,9 +69,12 @@ class router(router_tech):
# The blockage data structures
# A list of metal shapes (using the same pin_layout structure)
# that are not pins but blockages.
# that could be blockages.
# This will include the pins above as well.
self.blockages = []
# The corresponding set of blocked grids for above pin shapes
# The corresponding set of blocked grids for above blockage pin_layout shapes
# It is a cached set of grids that *could* be blocked, but may be unblocked
# depending on which pin we are routing.
self.blocked_grids = set()
# The routed data structures
@ -345,15 +348,14 @@ class router(router_tech):
# This is just a virtual function
pass
def prepare_blockages(self, pin_name):
def prepare_blockages(self):
"""
Reset and add all of the blockages in the design.
Names is a list of pins to add as a blockage.
"""
debug.info(3, "Preparing blockages.")
# Start fresh. Not the best for run-time, but simpler.
self.clear_blockages()
self.clear_all_blockages()
# This adds the initial blockges of the design
# print("BLOCKING:", self.blocked_grids)
self.set_blockages(self.blocked_grids, True)
@ -370,22 +372,17 @@ class router(router_tech):
# (some will be unblocked if they're a source/target)
# Also block the previous routes
for name in self.pin_groups:
blockage_grids = {y for x in self.pin_groups[name] for y in x.grids}
self.set_blockages(blockage_grids, True)
# This should be a superset of the grids...
blockage_grids = {y for x in self.pin_groups[name] for y in x.blockages}
self.set_blockages(blockage_grids, True)
# But do the grids just in case
blockage_grids = {y for x in self.pin_groups[name] for y in x.grids}
self.set_blockages(blockage_grids, True)
# FIXME: These duplicate a bit of work
# These are the paths that have already been routed.
self.set_blockages(self.path_blockages)
# 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
# route over them
# 1/6/21: This would cause things that looked like loops in the supply tree router
# blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids}
# self.set_blockages(blockage_grids, False)
def convert_shape_to_units(self, shape):
"""
Scale a shape (two vector list) to user units
@ -421,7 +418,18 @@ class router(router_tech):
# z direction
return 2
def clear_blockages(self):
def clear_blockages(self, pin_name):
"""
This function clears a given pin and all of its components from being blockages.
"""
# This should be a superset of the grids...
blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.blockages}
self.set_blockages(blockage_grids, False)
# But do the grids just in case
blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids}
self.set_blockages(blockage_grids, False)
def clear_all_blockages(self):
"""
Clear all blockages on the grid.
"""
@ -432,24 +440,24 @@ class router(router_tech):
""" Flag the blockages in the grid """
self.rg.set_blocked(blockages, value)
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))
def convert_to_tracks(self, ll, ur, z):
debug.info(3, "Converting ll={0} ur={1} z={2}".format(str(ll),str(ur),z))
block_list = []
grid_list = []
for x in range(int(ll[0]), int(ur[0])+1):
for y in range(int(ll[1]), int(ur[1])+1):
block_list.append(vector3d(x, y, z))
grid_list.append(vector3d(x, y, z))
return set(block_list)
return set(grid_list)
def convert_blockage(self, blockage):
"""
Convert a pin layout blockage shape to routing grid tracks.
"""
# Inflate the blockage by half a spacing rule
[ll, ur] = self.convert_blockage_to_tracks(blockage.inflate())
[ll, ur] = self.convert_shape_to_tracks(blockage.inflate())
zlayer = self.get_zindex(blockage.lpp)
blockage_tracks = self.get_blockage_tracks(ll, ur, zlayer)
blockage_tracks = self.convert_to_tracks(ll, ur, zlayer)
return blockage_tracks
def convert_blockages(self):
@ -460,6 +468,12 @@ class router(router_tech):
blockage_list = self.convert_blockage(blockage)
self.blocked_grids.update(blockage_list)
def get_blocked_grids(self):
"""
Return the blocked grids with their flag set
"""
return set([x for x in self.blocked_grids if self.rg.is_blocked(x)])
def retrieve_blockages(self, lpp):
"""
Recursive find boundaries as blockages to the routing grid.
@ -473,11 +487,7 @@ class router(router_tech):
new_pin = pin_layout("blockage{}".format(len(self.blockages)),
rect,
lpp)
# If there is a rectangle that is the same in the pins,
# it isn't a blockage!
if new_pin not in self.all_pins:
self.blockages.append(new_pin)
self.blockages.append(new_pin)
def convert_point_to_units(self, p):
"""
@ -492,10 +502,10 @@ class router(router_tech):
Convert a wave to a set of center points
"""
return [self.convert_point_to_units(i) for i in wave]
def convert_blockage_to_tracks(self, shape):
def convert_shape_to_tracks(self, shape):
"""
Convert a rectangular blockage shape into track units.
Convert a rectangular shape into track units.
"""
(ll, ur) = shape
ll = snap_to_grid(ll)
@ -531,8 +541,8 @@ class router(router_tech):
insufficient_list = set()
zindex = self.get_zindex(pin.lpp)
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 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):
(full_overlap, partial_overlap) = self.convert_pin_coord_to_tracks(pin,
vector3d(x,
y,
@ -813,6 +823,7 @@ class router(router_tech):
for pin_name in self.pin_groups:
debug.info(2, "Enclosing pins for {}".format(pin_name))
for pg in self.pin_groups[pin_name]:
self.clear_blockages(pin_name)
pg.enclose_pin()
pg.add_enclosure(self.cell)
@ -824,6 +835,9 @@ class router(router_tech):
for i in range(self.num_pin_components(pin_name)):
self.add_pin_component_source(pin_name, i)
# Clearing the blockage of this pin requires the inflated pins
self.clear_blockages(pin_name)
def add_target(self, pin_name):
"""
This will mark the grids for all pin components as a target.
@ -832,6 +846,9 @@ class router(router_tech):
for i in range(self.num_pin_components(pin_name)):
self.add_pin_component_target(pin_name, i)
# Clearing the blockage of this pin requires the inflated pins
self.clear_blockages(pin_name)
def add_perimeter_target(self, side="all"):
"""
This will mark all the cells on the perimeter of the original layout as a target.

View File

@ -62,6 +62,8 @@ class signal_escape_router(router):
start_time = datetime.now()
for pin_name in ordered_pin_names:
self.route_signal(pin_name)
#if pin_name == "dout1[1]":
# self.write_debug_gds("postroute.gds", False)
print_time("Maze routing pins",datetime.now(), start_time, 3)
@ -79,7 +81,8 @@ class signal_escape_router(router):
# This is inefficient since it is non-incremental, but it was
# easier to debug.
self.prepare_blockages(pin_name)
self.prepare_blockages()
self.clear_blockages(pin_name)
# Add the single component of the pin as the source
# which unmarks it as a blockage too
@ -88,6 +91,9 @@ class signal_escape_router(router):
# Marks the grid cells all along the perimeter as a target
self.add_perimeter_target(side)
#if pin_name == "dout1[1]":
# self.write_debug_gds("preroute.gds", False)
# Actually run the A* router
if self.run_router(detour_scale=detour_scale):
new_pin = self.get_perimeter_pin()

View File

@ -73,13 +73,16 @@ class supply_grid_router(router):
# Add the supply rails in a mesh network and connect H/V with vias
start_time = datetime.now()
# Block everything
self.prepare_blockages(self.gnd_name)
self.prepare_blockages()
self.clear_blockages(self.gnd_name)
# Determine the rail locations
self.route_supply_rails(self.gnd_name, 0)
# Block everything
self.prepare_blockages(self.vdd_name)
self.prepare_blockages()
self.clear_blockages(self.vdd_name)
# Determine the rail locations
self.route_supply_rails(self.vdd_name, 1)
print_time("Routing supply rails", datetime.now(), start_time, 3)

View File

@ -61,12 +61,6 @@ class supply_tree_router(router):
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
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
start_time = datetime.now()
# Block everything
self.prepare_blockages(self.gnd_name)
self.prepare_blockages(self.vdd_name)
# Route the supply pins to the supply rails
# Route vdd first since we want it to be shorter
start_time = datetime.now()
@ -136,7 +130,8 @@ class supply_tree_router(router):
# This is inefficient since it is non-incremental, but it was
# easier to debug.
self.prepare_blockages(pin_name)
self.prepare_blockages()
self.clear_blockages(pin_name)
# Add the single component of the pin as the source
# which unmarks it as a blockage too