mirror of https://github.com/VLSIDA/OpenRAM.git
Refactor how blocked_grids work. Must still calculate blockages based on enclosed pins.
This commit is contained in:
parent
504f9aa892
commit
7506ba81be
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue