Converting grid data structures to sets to reduce size.

This commit is contained in:
Matt Guthaus 2018-09-13 09:10:29 -07:00
parent 2d86492d91
commit 849293b95b
4 changed files with 181 additions and 116 deletions

View File

@ -37,7 +37,7 @@ class grid:
self.map={}
def set_blocked(self,n,value=True):
if isinstance(n,list):
if isinstance(n, (list,tuple,set,frozenset)):
for item in n:
self.set_blocked(item,value)
else:
@ -45,7 +45,7 @@ class grid:
self.map[n].blocked=value
def is_blocked(self,n):
if isinstance(n,list):
if isinstance(n, (list,tuple,set,frozenset)):
for item in n:
if self.is_blocked(item):
return True
@ -57,39 +57,33 @@ class grid:
def set_path(self,n,value=True):
if isinstance(n,list):
if isinstance(n, (list,tuple,set,frozenset)):
for item in n:
self.set_path(item,value)
else:
self.add_map(n)
self.map[n].path=value
def set_blockages(self,block_list,value=True):
debug.info(3,"Adding blockage list={0}".format(str(block_list)))
for n in block_list:
self.set_blocked(n,value)
def clear_blockages(self):
debug.info(2,"Clearing all blockages")
for n in self.map.keys():
self.set_blocked(n,False)
self.set_blocked(set(self.map.keys()),False)
def set_source(self,n):
if isinstance(n,list):
def set_source(self,n,value=True):
if isinstance(n, (list,tuple,set,frozenset)):
for item in n:
self.set_source(item)
self.set_source(item,value)
else:
self.add_map(n)
self.map[n].source=True
self.map[n].source=value
self.source.append(n)
def set_target(self,n):
if isinstance(n,list):
def set_target(self,n,value=True):
if isinstance(n, (list,tuple,set,frozenset)):
for item in n:
self.set_target(item)
self.set_target(item,value)
else:
self.add_map(n)
self.map[n].target=True
self.map[n].target=value
self.target.append(n)
@ -101,11 +95,11 @@ class grid:
self.set_blocked(n,False)
def add_target(self,track_list):
def set_target(self,track_list,value=True):
debug.info(3,"Adding target list={0}".format(str(track_list)))
for n in track_list:
debug.info(4,"Adding target ={0}".format(str(n)))
self.set_target(n)
self.set_target(n,value)
self.set_blocked(n,False)
def is_target(self,point):
@ -118,7 +112,7 @@ class grid:
"""
Add a point to the map if it doesn't exist.
"""
if isinstance(n,list):
if isinstance(n, (list,tuple,set,frozenset)):
for item in n:
self.add_map(item)
else:

View File

@ -40,15 +40,17 @@ class router:
self.pins = {}
# A set of connected pin groups
self.pin_groups = {}
# The corresponding sets of grids of the groups
# The corresponding sets of grids for each pin
self.pin_grids = {}
# The set of partially covered pins to avoid
self.pin_blockages = {}
# The set of partially covered pins to avoid for each pin
self.pin_partials = {}
# A set of blocked grids
self.blocked_grids = set()
# A list of blockages
# A list of pin layout shapes that are blocked
self.blockages=[]
# all the paths we've routed so far (to supplement the blockages)
# A list of paths that are blocked
self.paths = []
# The boundary will determine the limits to the size of the routing grid
@ -65,7 +67,7 @@ class router:
self.pins = {}
self.pin_groups = {}
self.pin_grids = {}
self.pin_blockages = {}
self.pin_paritals = {}
self.reinit()
def set_top(self,top_name):
@ -174,7 +176,7 @@ class router:
self.pins = {}
self.pin_groups = {}
self.pin_grids = {}
self.pin_blockages = {}
self.pin_partials = {}
# DO NOT clear the blockages as these don't change
self.rg.reinit()
@ -243,41 +245,44 @@ class router:
"""
self.rg.clear_blockages()
def add_pin_blockages(self, pin_name):
""" Add the blockages except the pin shapes. Also remove the pin shapes from the blockages list. """
self.add_blockages(self.pin_blockages[pin_name])
def add_blockages(self, blockages=None):
def set_blockages(self, blockages, value=True):
""" Flag the blockages in the grid """
if blockages == None:
blockages = self.blockage_grids
self.rg.set_blockages(blockages)
self.rg.set_blocked(blockages, value)
def set_path_blockages(self,value=True):
""" Flag the paths as blockages """
# These are the paths that have already been routed.
# This adds the initial blockges of the design
for p in self.paths:
p.set_blocked(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))
debug.info(4,"Converting 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):
block_list.append(vector3d(x,y,z))
return block_list
return set(block_list)
def convert_blockage(self, blockage):
"""
Convert a pin layout blockage shape to routing grid tracks.
"""
# Inflate the blockage by spacing rule
[ll,ur]=self.convert_blockage_to_tracks(blockage.inflate())
zlayer = self.get_zindex(blockage.layer_num)
blockage_tracks = self.get_blockage_tracks(ll,ur,zlayer)
return blockage_tracks
def convert_blockages(self):
""" Convert blockages to grid tracks. """
blockage_grids = []
for blockage in self.blockages:
debug.info(2,"Converting blockage {}".format(str(blockage)))
# Inflate the blockage by spacing rule
[ll,ur]=self.convert_blockage_to_tracks(blockage.inflate())
zlayer = self.get_zindex(blockage.layer_num)
blockages = self.get_blockage_tracks(ll,ur,zlayer)
blockage_grids.extend(blockages)
# Remember the filtered blockages
self.blockage_grids = blockage_grids
debug.info(3,"Converting blockage {}".format(str(blockage)))
blockage_list = self.convert_blockage(blockage)
self.blocked_grids.update(blockage_list)
def retrieve_blockages(self, layer_num):
@ -341,7 +346,7 @@ class router:
If a pin has insufficent overlap, it returns the blockage list to avoid it.
"""
(ll,ur) = pin.rect
debug.info(1,"Converting [ {0} , {1} ]".format(ll,ur))
debug.info(3,"Converting pin [ {0} , {1} ]".format(ll,ur))
# scale the size bigger to include neaby tracks
ll=ll.scale(self.track_factor).floor()
@ -350,41 +355,36 @@ class router:
# width depends on which layer it is
zindex=self.get_zindex(pin.layer_num)
if zindex:
width = self.vert_layer_width
width = self.vert_layer_width
spacing = self.vert_layer_spacing
else:
width = self.horiz_layer_width
spacing = self.horiz_layer_spacing
track_list = []
block_list = []
for x in range(int(ll[0]),int(ur[0])):
for y in range(int(ll[1]),int(ur[1])):
debug.info(1,"Converting [ {0} , {1} ]".format(x,y))
for x in range(int(ll[0]),int(ur[0])+1):
for y in range(int(ll[1]),int(ur[1])+1):
debug.info(4,"Converting [ {0} , {1} ]".format(x,y))
# however, if there is not enough overlap, then if there is any overlap at all,
# we need to block it to prevent routes coming in on that grid
full_rect = self.convert_track_to_shape(vector3d(x,y,zindex))
track_area = (full_rect[1].x-full_rect[0].x)*(full_rect[1].y-full_rect[0].y)
overlap_rect=self.compute_overlap(pin.rect,full_rect)
overlap_area = overlap_rect[0]*overlap_rect[1]
debug.info(1,"Check overlap: {0} {1} max={2}".format(pin.rect,overlap_rect,overlap_area))
# Assume if more than half the area, it is occupied
overlap_ratio = overlap_area/track_area
if overlap_ratio > 0.25:
min_overlap = min(overlap_rect)
debug.info(3,"Check overlap: {0} . {1} = {2}".format(pin.rect,full_rect,overlap_rect))
if min_overlap > spacing:
debug.info(3," Overlap: {0} {1} >? {2}".format(overlap_rect,min_overlap,spacing))
track_list.append(vector3d(x,y,zindex))
# otherwise, the pin may not be accessible, so block it
elif overlap_ratio > 0:
elif min_overlap > 0:
debug.info(3," Insufficient overlap: {0} {1} >? {2}".format(overlap_rect,min_overlap,spacing))
block_list.append(vector3d(x,y,zindex))
else:
debug.info(4,"No overlap: {0} {1} max={2}".format(pin.rect,overlap_rect,overlap_area))
# print("H:",x,y)
# if x>38 and x<42 and y>42 and y<45:
# print(pin)
# print(full_rect, overlap_rect, overlap_ratio)
#debug.warning("Off-grid pin for {0}.".format(str(pin)))
#debug.info(1,"Converted [ {0} , {1} ]".format(ll,ur))
return (track_list,block_list)
debug.info(4," No overlap: {0} {1} max={2}".format(overlap_rect,min_overlap,spacing))
return (tuple(track_list),tuple(block_list))
def compute_overlap(self, r1, r2):
""" Calculate the rectangular overlap of two rectangles. """
@ -432,8 +432,8 @@ class router:
track.
"""
# to scale coordinates to tracks
x = track.x*self.track_width - 0.5*self.track_width
y = track.y*self.track_width - 0.5*self.track_width
x = track[0]*self.track_width - 0.5*self.track_width
y = track[1]*self.track_width - 0.5*self.track_width
# offset lowest corner object to to (-track halo,-track halo)
ll = snap_to_grid(vector(x,y))
ur = snap_to_grid(ll + vector(self.track_width,self.track_width))
@ -497,20 +497,50 @@ class router:
"""
Convert the pin groups into pin tracks and blockage tracks
"""
self.pin_grids[pin_name] = []
self.pin_blockages[pin_name] = []
try:
self.pin_grids[pin_name]
except:
self.pin_grids[pin_name] = []
try:
self.pin_partials[pin_name]
except:
self.pin_partials[pin_name] = []
found_pin = False
for pg in self.pin_groups[pin_name]:
# Keep the same groups for each pin
self.pin_grids[pin_name].append(set())
self.pin_partials[pin_name].append(set())
pin_set = set()
partial_set = set()
for pin in pg:
(pin_in_tracks,blockage_in_tracks)=self.convert_pin_to_tracks(pin)
debug.info(2,"Converting {0}".format(pin))
(pin_in_tracks,partial_in_tracks)=self.convert_pin_to_tracks(pin)
# In the blockages, what did this shape expand as?
blockage_in_tracks = self.convert_blockage(pin)
# At least one of the groups must have some valid tracks
if (len(pin_in_tracks)>0):
found_pin = True
# We need to route each of the classes, so don't combine the groups
self.pin_grids[pin_name].append(pin_in_tracks)
# However, we can just block all of the partials, so combine the groups
self.pin_blockages[pin_name].extend(blockage_in_tracks)
pin_set.update(pin_in_tracks)
partial_set.update(partial_in_tracks)
partial_set.update(blockage_in_tracks)
debug.info(2," grids {}".format(pin_set))
debug.info(2," parts {}".format(partial_set))
# We can just block all of the partials, so combine the groups
self.pin_partials[pin_name][-1].add(frozenset(partial_set))
# We need to route each of the classes, so don't combine the groups
self.pin_grids[pin_name][-1].add(frozenset(pin_set))
# This happens when a shape is covered partially by one shape and fully by another
self.pin_partials[pin_name][-1].difference_update(pin_set)
# These will be blocked depending on what we are routing
self.blocked_grids.difference_update(pin_set)
self.blocked_grids.difference_update(partial_set)
if not found_pin:
self.write_debug_gds()
@ -528,6 +558,8 @@ class router:
"""
This returns how many disconnected pin components there are.
"""
debug.check(len(self.pin_grids[pin_name]) == len(self.pin_partials[pin_name]),
"Pin grid and partial blockage component sizes don't match.")
return len(self.pin_grids[pin_name])
def add_pin_component(self, pin_name, index, is_source=False):
@ -545,6 +577,7 @@ class router:
debug.info(1,"Set target: " + str(pin_name) + " " + str(pin_in_tracks))
self.rg.add_target(pin_in_tracks)
def add_supply_rail_target(self, pin_name):
"""
Add the supply rails of given name as a routing target.
@ -555,15 +588,14 @@ class router:
for wave_index in range(len(rail)):
pin_in_tracks = rail[wave_index]
#debug.info(1,"Set target: " + str(pin_name) + " " + str(pin_in_tracks))
self.rg.add_target(pin_in_tracks)
self.rg.set_target(pin_in_tracks)
def add_component_blockages(self, pin_name):
def set_component_blockages(self, pin_name, value=True):
"""
Block all of the pin components.
"""
for comp_index in range(self.num_pin_components(pin_name)):
pin_in_tracks = self.pin_grids[pin_name][comp_index]
self.add_blockages(pin_in_tracks)
for component in self.pin_grids[pin_name]:
self.set_blockages(component, value)
def write_debug_gds(self):
@ -633,12 +665,14 @@ class router:
def prepare_path(self,path):
"""
Prepare a path or wave for routing
Prepare a path or wave for routing ebedding.
This tracks the path, simplifies the path and marks it as a path for debug output.
"""
debug.info(3,"Set path: " + str(path))
debug.info(4,"Set path: " + str(path))
# Keep track of path for future blockages
self.paths.append(path)
path.set_blocked()
# This is marked for debug
path.set_path()
@ -650,7 +684,7 @@ class router:
# First, simplify the path for
#debug.info(1,str(self.path))
contracted_path = self.contract_path(path)
debug.info(1,str(contracted_path))
debug.info(3,"Contracted path: " + str(contracted_path))
return contracted_path
@ -659,7 +693,6 @@ class router:
"""
Add the current wire route to the given design instance.
"""
path=self.prepare_path(path)
# convert the path back to absolute units from tracks

View File

@ -66,12 +66,12 @@ class signal_router(router):
self.find_pins(dest)
# Now add the blockages
self.add_blockages()
self.add_pin_blockages(src)
self.add_pin_blockages(dest)
self.set_blockages(self.blocked_grids,True)
self.set_blockages(self.pin_partial[src],True)
self.set_blockages(self.pin_partial[dest],True)
# Add blockages from previous paths
self.add_path_blockages()
self.set_path_blockages()
# Now add the src/tgt if they are not blocked by other shapes

View File

@ -26,7 +26,6 @@ class supply_router(router):
# Power rail width in grid units.
self.rail_track_width = 2
def create_routing_grid(self):
@ -62,30 +61,57 @@ class supply_router(router):
self.find_blockages()
# Get the pin shapes
self.find_pins(vdd_name)
self.find_pins(gnd_name)
self.find_pins(self.vdd_name)
self.find_pins(self.gnd_name)
self.add_blockages()
self.add_pin_blockages(vdd_name)
self.route_supply_rails(gnd_name,0)
self.connect_supply_rail(gnd_name)
self.route_pins_to_rails(gnd_name)
# Start fresh. Not the best for run-time, but simpler.
self.clear_blockages()
# Add the supply rails in a mesh network and connect H/V with vias
self.prepare_blockages(block_names=[self.vdd_name],unblock_names=[self.gnd_name])
self.route_supply_rails(self.gnd_name,0)
self.add_blockages()
self.add_pin_blockages(gnd_name)
self.route_supply_rails(vdd_name,1)
self.connect_supply_rail(vdd_name)
self.route_pins_to_rails(vdd_name)
self.prepare_blockages(block_names=[self.gnd_name],unblock_names=[self.vdd_name])
self.route_supply_rails(self.vdd_name,1)
# Route the supply pins to the supply rails
#self.route_pins_to_rails(gnd_name)
#self.route_pins_to_rails(vdd_name)
self.write_debug_gds()
return False
def prepare_blockages(self, block_names=None, unblock_names=None):
"""
Reset and add all of the blockages in the design.
Names is a list of pins to add as a blockage.
"""
# Start fresh. Not the best for run-time, but simpler.
self.clear_blockages()
# This adds the initial blockges of the design
print("BLOCKING:",self.blocked_grids)
self.set_blockages(self.blocked_grids,True)
# This is conservative to prevent DRC violations on partially blocked tracks
if block_names:
for name in block_names:
# These are the partially blocked tracks around supply pins.
print("BLOCKING PARTIALS:",name,self.pin_partials[name])
self.set_blockages(self.pin_partials[name],True)
# These are the actual supply pins
self.set_blockages(self.pin_grids[name],True)
print("BLOCKING GRIDS:",name,self.pin_grids[name])
# This will unblock
if unblock_names:
for name in unblock_names:
# These are the partially blocked tracks around supply pins.
self.set_blockages(self.pin_partials[name],False)
print("UNBLOCKING PARTIALS:",name,self.pin_partials[name])
# These are the actual supply pins
self.set_blockages(self.pin_grids[name],False)
print("UNBLOCKING GRIDS:",name,self.pin_grids[name])
# These are the paths that have already been routed.
self.set_path_blockages()
def connect_supply_rail(self, name):
def connect_supply_rails(self, name):
"""
Add vias between overlapping supply rails.
"""
@ -100,7 +126,10 @@ class supply_router(router):
for h in horizontal_paths:
overlap = v.overlap(h)
if overlap:
shared_areas.append(overlap)
(ll,ur) = overlap
# Only add if the overlap is wide enough
if ur.x-ll.x >= self.rail_track_width-1 and ur.y-ll.y >= self.rail_track_width-1:
shared_areas.append(overlap)
for (ll,ur) in shared_areas:
@ -140,6 +169,10 @@ class supply_router(router):
# Remember index of path size which is how many rails we had at the start
self.num_rails = len(self.paths)
# Add teh supply rail vias
self.connect_supply_rails(name)
def route_supply_rail(self, name, seed_wave, direct):
"""
This finds the first valid starting location and routes a supply rail
@ -179,20 +212,25 @@ class supply_router(router):
After it is done, the cells are added to the pin blockage list.
"""
# For every component
for index in range(self.num_pin_components(pin_name)):
self.rg.reinit()
self.prepare_blockages(block_names=None,unblock_names=[pin_name])
# Block all the pin components first
self.add_component_blockages(pin_name)
self.set_component_blockages(pin_name, True)
# Add the single component of the pin as the source
# which unmarks it as a blockage too
self.add_pin_component(pin_name,index,is_source=True)
# Add all of the rails as targets
# Don't add the other pins, but we could?
self.add_supply_rail_target(pin_name)
# Actually run the A* router
self.run_router(detour_scale=5)