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 # 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 set of blocked grids due to this pin
# 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
@ -421,16 +418,16 @@ class pin_group:
while True: while True:
next_cell = row[-1] + offset1 next_cell = row[-1] + offset1
# Can't move if not in the pin shape # 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) row.append(next_cell)
else: else:
break break
# Move in dir2 while we can # Move in dir2 while we can
while True: while True:
next_row = [x+offset2 for x in row] next_row = [x + offset2 for x in row]
for cell in next_row: for cell in next_row:
# Can't move if any cell is not in the pin shape # 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 break
else: else:
row = next_row row = next_row
@ -606,9 +603,10 @@ class pin_group:
The secondary set of grids are "optional" pin shapes that 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.
""" """
# Set of tracks that overlap a pin
pin_set = set() pin_set = set()
# Set of track adjacent to or paritally overlap a pin (not full DRC connection)
partial_set = set() partial_set = set()
blockage_set = set()
for pin in self.pins: for pin in self.pins:
debug.info(4, " Converting {0}".format(pin)) debug.info(4, " Converting {0}".format(pin))
@ -621,25 +619,20 @@ class pin_group:
# 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)
blockage_set.update(blockage_in_tracks) self.blockages.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 & self.router.blocked_grids shared_set = pin_set & self.router.get_blocked_grids()
if len(shared_set) > 0: if len(shared_set) > 0:
debug.info(4, "Removing pins {}".format(shared_set)) debug.info(4, "Removing pins {}".format(shared_set))
pin_set.difference_update(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: if len(shared_set) > 0:
debug.info(4, "Removing pins {}".format(shared_set)) 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 # 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)) # 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:
@ -656,8 +649,11 @@ class pin_group:
self.pins)) self.pins))
self.router.write_debug_gds("blocked_pin.gds") self.router.write_debug_gds("blocked_pin.gds")
# Consider all the grids that would be blocked # Consider the fully connected set first and if not the partial set
self.grids = pin_set | partial_set if len(pin_set) > 0:
self.grids = pin_set
else:
self.grids = partial_set
if len(self.grids) < 0: if len(self.grids) < 0:
debug.error("Did not find any unblocked grids: {}".format(str(self.pins))) debug.error("Did not find any unblocked grids: {}".format(str(self.pins)))
self.router.write_debug_gds("blocked_pin.gds") self.router.write_debug_gds("blocked_pin.gds")

View File

@ -69,9 +69,12 @@ class router(router_tech):
# The blockage data structures # The blockage data structures
# A list of metal shapes (using the same pin_layout structure) # 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 = [] 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() self.blocked_grids = set()
# The routed data structures # The routed data structures
@ -345,15 +348,14 @@ class router(router_tech):
# This is just a virtual function # This is just a virtual function
pass pass
def prepare_blockages(self, pin_name): def prepare_blockages(self):
""" """
Reset and add all of the blockages in the design. 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.") debug.info(3, "Preparing blockages.")
# Start fresh. Not the best for run-time, but simpler. # 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 # This adds the initial blockges of the design
# print("BLOCKING:", self.blocked_grids) # print("BLOCKING:", self.blocked_grids)
self.set_blockages(self.blocked_grids, True) 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) # (some will be unblocked if they're a source/target)
# Also block the previous routes # Also block the previous routes
for name in self.pin_groups: for name in self.pin_groups:
blockage_grids = {y for x in self.pin_groups[name] for y in x.grids} # This should be a superset of the grids...
self.set_blockages(blockage_grids, True)
blockage_grids = {y for x in self.pin_groups[name] for y in x.blockages} blockage_grids = {y for x in self.pin_groups[name] for y in x.blockages}
self.set_blockages(blockage_grids, True) 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 # FIXME: These duplicate a bit of work
# These are the paths that have already been routed. # These are the paths that have already been routed.
self.set_blockages(self.path_blockages) 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): def convert_shape_to_units(self, shape):
""" """
Scale a shape (two vector list) to user units Scale a shape (two vector list) to user units
@ -421,7 +418,18 @@ class router(router_tech):
# z direction # z direction
return 2 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. Clear all blockages on the grid.
""" """
@ -432,24 +440,24 @@ class router(router_tech):
""" Flag the blockages in the grid """ """ Flag the blockages in the grid """
self.rg.set_blocked(blockages, value) self.rg.set_blocked(blockages, value)
def get_blockage_tracks(self, ll, ur, z): def convert_to_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 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 x in range(int(ll[0]), int(ur[0])+1):
for y in range(int(ll[1]), int(ur[1])+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): def convert_blockage(self, blockage):
""" """
Convert a pin layout blockage shape to routing grid tracks. Convert a pin layout blockage shape to routing grid tracks.
""" """
# 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_shape_to_tracks(blockage.inflate())
zlayer = self.get_zindex(blockage.lpp) 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 return blockage_tracks
def convert_blockages(self): def convert_blockages(self):
@ -460,6 +468,12 @@ 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 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): def retrieve_blockages(self, lpp):
""" """
Recursive find boundaries as blockages to the routing grid. 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)), new_pin = pin_layout("blockage{}".format(len(self.blockages)),
rect, rect,
lpp) lpp)
self.blockages.append(new_pin)
# 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)
def convert_point_to_units(self, p): def convert_point_to_units(self, p):
""" """
@ -493,9 +503,9 @@ class router(router_tech):
""" """
return [self.convert_point_to_units(i) for i in wave] 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, ur) = shape
ll = snap_to_grid(ll) ll = snap_to_grid(ll)
@ -531,8 +541,8 @@ class router(router_tech):
insufficient_list = set() insufficient_list = set()
zindex = self.get_zindex(pin.lpp) 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,
vector3d(x, vector3d(x,
y, y,
@ -813,6 +823,7 @@ class router(router_tech):
for pin_name in self.pin_groups: for pin_name in self.pin_groups:
debug.info(2, "Enclosing pins for {}".format(pin_name)) debug.info(2, "Enclosing pins for {}".format(pin_name))
for pg in self.pin_groups[pin_name]: for pg in self.pin_groups[pin_name]:
self.clear_blockages(pin_name)
pg.enclose_pin() pg.enclose_pin()
pg.add_enclosure(self.cell) pg.add_enclosure(self.cell)
@ -824,6 +835,9 @@ class router(router_tech):
for i in range(self.num_pin_components(pin_name)): for i in range(self.num_pin_components(pin_name)):
self.add_pin_component_source(pin_name, i) 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): def add_target(self, pin_name):
""" """
This will mark the grids for all pin components as a target. 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)): for i in range(self.num_pin_components(pin_name)):
self.add_pin_component_target(pin_name, i) 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"): def add_perimeter_target(self, side="all"):
""" """
This will mark all the cells on the perimeter of the original layout as a target. 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() start_time = datetime.now()
for pin_name in ordered_pin_names: for pin_name in ordered_pin_names:
self.route_signal(pin_name) 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) 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 # This is inefficient since it is non-incremental, but it was
# easier to debug. # 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 # Add the single component of the pin as the source
# which unmarks it as a blockage too # 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 # Marks the grid cells all along the perimeter as a target
self.add_perimeter_target(side) self.add_perimeter_target(side)
#if pin_name == "dout1[1]":
# self.write_debug_gds("preroute.gds", False)
# Actually run the A* router # Actually run the A* router
if self.run_router(detour_scale=detour_scale): if self.run_router(detour_scale=detour_scale):
new_pin = self.get_perimeter_pin() 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 # 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
self.prepare_blockages(self.gnd_name) self.prepare_blockages()
self.clear_blockages(self.gnd_name)
# Determine the rail locations # Determine the rail locations
self.route_supply_rails(self.gnd_name, 0) self.route_supply_rails(self.gnd_name, 0)
# Block everything # Block everything
self.prepare_blockages(self.vdd_name) self.prepare_blockages()
self.clear_blockages(self.vdd_name)
# Determine the rail locations # Determine the rail locations
self.route_supply_rails(self.vdd_name, 1) self.route_supply_rails(self.vdd_name, 1)
print_time("Routing supply rails", datetime.now(), start_time, 3) 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]) 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
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 the supply pins to the supply rails
# Route vdd first since we want it to be shorter # Route vdd first since we want it to be shorter
start_time = datetime.now() start_time = datetime.now()
@ -136,7 +130,8 @@ class supply_tree_router(router):
# This is inefficient since it is non-incremental, but it was # This is inefficient since it is non-incremental, but it was
# easier to debug. # 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 # Add the single component of the pin as the source
# which unmarks it as a blockage too # which unmarks it as a blockage too