mirror of https://github.com/VLSIDA/OpenRAM.git
Convert supply tracks to sets for simpler algorithms.
This commit is contained in:
parent
0aad61892b
commit
a1f2a5befe
|
|
@ -67,12 +67,14 @@ class grid_path:
|
||||||
"""
|
"""
|
||||||
Drop the last item
|
Drop the last item
|
||||||
"""
|
"""
|
||||||
|
if len(self.pathlist)>0:
|
||||||
self.pathlist.pop()
|
self.pathlist.pop()
|
||||||
|
|
||||||
def trim_first(self):
|
def trim_first(self):
|
||||||
"""
|
"""
|
||||||
Drop the first item
|
Drop the first item
|
||||||
"""
|
"""
|
||||||
|
if len(self.pathlist)>0:
|
||||||
self.pathlist.pop(0)
|
self.pathlist.pop(0)
|
||||||
|
|
||||||
def append(self,item):
|
def append(self,item):
|
||||||
|
|
@ -97,6 +99,25 @@ class grid_path:
|
||||||
for p in sublist:
|
for p in sublist:
|
||||||
p.blocked=value
|
p.blocked=value
|
||||||
|
|
||||||
|
def get_grids(self):
|
||||||
|
"""
|
||||||
|
Return a set of all the grids in this path.
|
||||||
|
"""
|
||||||
|
newset = set()
|
||||||
|
for sublist in self.pathlist:
|
||||||
|
newset.update(sublist)
|
||||||
|
return newset
|
||||||
|
|
||||||
|
def get_wire_grids(self, start_index, end_index):
|
||||||
|
"""
|
||||||
|
Return a set of all the wire grids in this path.
|
||||||
|
These are the indices in the wave path in a certain range.
|
||||||
|
"""
|
||||||
|
newset = set()
|
||||||
|
for sublist in self.pathlist:
|
||||||
|
newset.update(sublist[start_index:end_index])
|
||||||
|
return newset
|
||||||
|
|
||||||
def cost(self):
|
def cost(self):
|
||||||
"""
|
"""
|
||||||
The cost of the path is the length plus a penalty for the number
|
The cost of the path is the length plus a penalty for the number
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
"""
|
||||||
|
Some utility functions for sets of grid cells.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import debug
|
||||||
|
from direction import direction
|
||||||
|
from vector3d import vector3d
|
||||||
|
|
||||||
|
def increment_set(curset, direct):
|
||||||
|
"""
|
||||||
|
Return the cells incremented in given direction
|
||||||
|
"""
|
||||||
|
if direct==direction.NORTH:
|
||||||
|
offset = vector3d(0,1,0)
|
||||||
|
elif direct==direction.SOUTH:
|
||||||
|
offset = vector3d(0,-1,0)
|
||||||
|
elif direct==direction.EAST:
|
||||||
|
offset = vector3d(1,0,0)
|
||||||
|
elif direct==direction.WEST:
|
||||||
|
offset = vector3d(-1,0,0)
|
||||||
|
elif direct==direction.UP:
|
||||||
|
offset = vector3d(0,0,1)
|
||||||
|
elif direct==direction.DOWN:
|
||||||
|
offset = vector3d(0,0,-1)
|
||||||
|
else:
|
||||||
|
debug.error("Invalid direction {}".format(dirct))
|
||||||
|
|
||||||
|
newset = set()
|
||||||
|
for c in curset:
|
||||||
|
newc = c+offset
|
||||||
|
newset.add(newc)
|
||||||
|
|
||||||
|
return newset
|
||||||
|
|
||||||
|
def get_upper_right(curset):
|
||||||
|
ur = None
|
||||||
|
for p in curset:
|
||||||
|
if ur == None or (p.x>=ur.x and p.y>=ur.y):
|
||||||
|
ur = p
|
||||||
|
return ur
|
||||||
|
|
||||||
|
def get_lower_left(curset):
|
||||||
|
ll = None
|
||||||
|
for p in curset:
|
||||||
|
if ll == None or (p.x<=ll.x and p.y<=ll.y):
|
||||||
|
ll = p
|
||||||
|
return ll
|
||||||
|
|
||||||
|
def get_border( curset, direct):
|
||||||
|
"""
|
||||||
|
Return the furthest cell(s) in a given direction.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# find direction-most cell(s)
|
||||||
|
maxc = []
|
||||||
|
if direct==direction.NORTH:
|
||||||
|
for c in curset:
|
||||||
|
if len(maxc)==0 or c.y>maxc[0].y:
|
||||||
|
maxc = [c]
|
||||||
|
elif c.y==maxc[0].y:
|
||||||
|
maxc.append(c)
|
||||||
|
elif direct==direct.SOUTH:
|
||||||
|
for c in curset:
|
||||||
|
if len(maxc)==0 or c.y<maxc[0].y:
|
||||||
|
maxc = [c]
|
||||||
|
elif c.y==maxc[0].y:
|
||||||
|
maxc.append(c)
|
||||||
|
elif direct==direct.EAST:
|
||||||
|
for c in curset:
|
||||||
|
if len(maxc)==0 or c.x>maxc[0].x:
|
||||||
|
maxc = [c]
|
||||||
|
elif c.x==maxc[0].x:
|
||||||
|
maxc.append(c)
|
||||||
|
elif direct==direct.WEST:
|
||||||
|
for c in curset:
|
||||||
|
if len(maxc)==0 or c.x<maxc[0].x:
|
||||||
|
maxc = [c]
|
||||||
|
elif c.x==maxc[0].x:
|
||||||
|
maxc.append(c)
|
||||||
|
|
||||||
|
newset = set(maxc)
|
||||||
|
return newset
|
||||||
|
|
||||||
|
def expand_border(curset, direct):
|
||||||
|
"""
|
||||||
|
Expand the current set of sells in a given direction.
|
||||||
|
Only return the contiguous cells.
|
||||||
|
"""
|
||||||
|
border_set = get_border(curset, direct)
|
||||||
|
next_border_set = increment_set(border_set, direct)
|
||||||
|
return next_border_set
|
||||||
|
|
||||||
|
def expand_borders(curset):
|
||||||
|
"""
|
||||||
|
Return the expansions in planar directions.
|
||||||
|
"""
|
||||||
|
north_set=expand_border(curset,direction.NORTH)
|
||||||
|
south_set=expand_border(curset,direction.SOUTH)
|
||||||
|
east_set=expand_border(curset,direction.EAST)
|
||||||
|
west_set=expand_border(curset,direction.WEST)
|
||||||
|
|
||||||
|
return(north_set, east_set, south_set, west_set)
|
||||||
|
|
||||||
|
|
@ -9,6 +9,7 @@ from vector import vector
|
||||||
from vector3d import vector3d
|
from vector3d import vector3d
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
|
import grid_utils
|
||||||
|
|
||||||
class router:
|
class router:
|
||||||
"""
|
"""
|
||||||
|
|
@ -837,8 +838,9 @@ class router:
|
||||||
"""
|
"""
|
||||||
Remove any pin layout that is contained within another.
|
Remove any pin layout that is contained within another.
|
||||||
"""
|
"""
|
||||||
|
local_debug = False
|
||||||
print("INITIAL:",pin_list)
|
if local_debug:
|
||||||
|
debug.info(0,"INITIAL:",pin_list)
|
||||||
|
|
||||||
# Make a copy of the list to start
|
# Make a copy of the list to start
|
||||||
new_pin_list = pin_list.copy()
|
new_pin_list = pin_list.copy()
|
||||||
|
|
@ -854,7 +856,8 @@ class router:
|
||||||
if pin1 in new_pin_list:
|
if pin1 in new_pin_list:
|
||||||
new_pin_list.remove(pin1)
|
new_pin_list.remove(pin1)
|
||||||
|
|
||||||
print("FINAL :",new_pin_list)
|
if local_debug:
|
||||||
|
debug.info(0,"FINAL :",new_pin_list)
|
||||||
return new_pin_list
|
return new_pin_list
|
||||||
|
|
||||||
def compute_enclosures(self, tracks):
|
def compute_enclosures(self, tracks):
|
||||||
|
|
@ -932,7 +935,8 @@ class router:
|
||||||
# If so, we are done.
|
# If so, we are done.
|
||||||
# FIXME: Check if by more than a DRC width
|
# FIXME: Check if by more than a DRC width
|
||||||
if self.overlap_any_shape(pin_group, enclosure_list):
|
if self.overlap_any_shape(pin_group, enclosure_list):
|
||||||
debug.info(2,"Pin overlaps enclosure {0}".format(pin_name))
|
#debug.info(2,"Pin overlaps enclosure {0}".format(pin_name))
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
new_enclosure = self.find_smallest_connector(pin_group, enclosure_list)
|
new_enclosure = self.find_smallest_connector(pin_group, enclosure_list)
|
||||||
debug.info(2,"Adding connector enclosure {0} {1}".format(pin_name, new_enclosure))
|
debug.info(2,"Adding connector enclosure {0} {1}".format(pin_name, new_enclosure))
|
||||||
|
|
@ -1114,29 +1118,6 @@ class router:
|
||||||
offset=vector(loc.x,loc.y),
|
offset=vector(loc.x,loc.y),
|
||||||
size=(size,size))
|
size=(size,size))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_wavepath(self, name, path):
|
|
||||||
"""
|
|
||||||
Add the current wave to the given design instance.
|
|
||||||
This is a single rectangle that is multiple tracks wide.
|
|
||||||
It must pay attention to wide metal spacing rules.
|
|
||||||
"""
|
|
||||||
path=self.prepare_path(path)
|
|
||||||
|
|
||||||
ll = path[0][0]
|
|
||||||
ur = path[-1][-1]
|
|
||||||
z = ll.z
|
|
||||||
pin = self.compute_wide_enclosure(ll, ur, z, name)
|
|
||||||
#print(ll, ur, ll.z, "->",pin)
|
|
||||||
self.cell.add_layout_pin(text=name,
|
|
||||||
layer=pin.layer,
|
|
||||||
offset=pin.ll(),
|
|
||||||
width=pin.width(),
|
|
||||||
height=pin.height())
|
|
||||||
|
|
||||||
return pin
|
|
||||||
|
|
||||||
def compute_pin_enclosure(self, ll, ur, zindex, name=""):
|
def compute_pin_enclosure(self, ll, ur, zindex, name=""):
|
||||||
"""
|
"""
|
||||||
Enclose the tracks from ll to ur in a single rectangle that meets
|
Enclose the tracks from ll to ur in a single rectangle that meets
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ from vector import vector
|
||||||
from vector3d import vector3d
|
from vector3d import vector3d
|
||||||
from router import router
|
from router import router
|
||||||
from direction import direction
|
from direction import direction
|
||||||
|
import grid_utils
|
||||||
|
|
||||||
class supply_router(router):
|
class supply_router(router):
|
||||||
"""
|
"""
|
||||||
|
|
@ -24,9 +25,10 @@ class supply_router(router):
|
||||||
router.__init__(self, layers, design, gds_filename)
|
router.__init__(self, layers, design, gds_filename)
|
||||||
|
|
||||||
|
|
||||||
# The list of supply rails that may be routed
|
# The list of supply rails (grid sets) that may be routed
|
||||||
self.supply_rails = []
|
self.supply_rails = {}
|
||||||
# This is the same as above but the sets of pins
|
self.supply_rail_wires = {}
|
||||||
|
# This is the same as above but as a sigle set for the all the rails
|
||||||
self.supply_rail_tracks = {}
|
self.supply_rail_tracks = {}
|
||||||
self.supply_rail_wire_tracks = {}
|
self.supply_rail_wire_tracks = {}
|
||||||
|
|
||||||
|
|
@ -76,17 +78,17 @@ class supply_router(router):
|
||||||
self.prepare_blockages(self.vdd_name)
|
self.prepare_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)
|
||||||
|
#self.write_debug_gds("debug_rails.gds",stop_program=True)
|
||||||
|
|
||||||
#self.write_debug_gds("pre_pin_debug.gds",stop_program=True)
|
|
||||||
remaining_vdd_pin_indices = self.route_simple_overlaps(vdd_name)
|
remaining_vdd_pin_indices = self.route_simple_overlaps(vdd_name)
|
||||||
remaining_gnd_pin_indices = self.route_simple_overlaps(gnd_name)
|
remaining_gnd_pin_indices = self.route_simple_overlaps(gnd_name)
|
||||||
|
#self.write_debug_gds("debug_simple_route.gds",stop_program=True)
|
||||||
|
|
||||||
# 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
|
||||||
self.route_pins_to_rails(vdd_name, remaining_vdd_pin_indices)
|
self.route_pins_to_rails(vdd_name, remaining_vdd_pin_indices)
|
||||||
self.route_pins_to_rails(gnd_name, remaining_gnd_pin_indices)
|
self.route_pins_to_rails(gnd_name, remaining_gnd_pin_indices)
|
||||||
|
#self.write_debug_gds("debug_pin_routes.gds",stop_program=True)
|
||||||
self.write_debug_gds("post_pin_debug.gds",stop_program=False)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
@ -122,7 +124,6 @@ class supply_router(router):
|
||||||
the actual supply rail wire in a given direction (or terminating
|
the actual supply rail wire in a given direction (or terminating
|
||||||
when any track is no longer in the supply rail.
|
when any track is no longer in the supply rail.
|
||||||
"""
|
"""
|
||||||
import grid_utils
|
|
||||||
next_set = grid_utils.expand_border(start_set, direct)
|
next_set = grid_utils.expand_border(start_set, direct)
|
||||||
|
|
||||||
supply_tracks = self.supply_rail_tracks[pin_name]
|
supply_tracks = self.supply_rail_tracks[pin_name]
|
||||||
|
|
@ -154,8 +155,6 @@ class supply_router(router):
|
||||||
that is ensured to overlap the supply rail wire.
|
that is ensured to overlap the supply rail wire.
|
||||||
It then adds rectangle(s) for the enclosure.
|
It then adds rectangle(s) for the enclosure.
|
||||||
"""
|
"""
|
||||||
import grid_utils
|
|
||||||
|
|
||||||
additional_set = set()
|
additional_set = set()
|
||||||
# Check the layer of any element in the pin to determine which direction to route it
|
# Check the layer of any element in the pin to determine which direction to route it
|
||||||
e = next(iter(start_set))
|
e = next(iter(start_set))
|
||||||
|
|
@ -180,46 +179,52 @@ class supply_router(router):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def connect_supply_rails(self, name):
|
def finalize_supply_rails(self, name):
|
||||||
"""
|
"""
|
||||||
Determine which supply rails overlap and can accomodate a via.
|
Determine which supply rails overlap and can accomodate a via.
|
||||||
Remove any supply rails that do not have a via since they are disconnected.
|
Remove any supply rails that do not have a via since they are disconnected.
|
||||||
NOTE: It is still possible though unlikely that there are disconnected groups of rails.
|
NOTE: It is still possible though unlikely that there are disconnected groups of rails.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Split into horizontal and vertical paths
|
all_rails = self.supply_rail_wires[name]
|
||||||
vertical_rails = [x for x in self.supply_rails if x[0][0].z==1 and x.name==name]
|
|
||||||
horizontal_rails = [x for x in self.supply_rails if x[0][0].z==0 and x.name==name]
|
|
||||||
|
|
||||||
# Flag to see if each supply rail has at least one via (i.e. it is "connected")
|
connections = set()
|
||||||
vertical_flags = [False] * len(vertical_rails)
|
|
||||||
horizontal_flags = [False] * len(horizontal_rails)
|
|
||||||
|
|
||||||
# Compute a list of "shared areas" that are bigger than a via
|
|
||||||
via_areas = []
|
via_areas = []
|
||||||
for vindex,v in enumerate(vertical_rails):
|
for i1,r1 in enumerate(all_rails):
|
||||||
for hindex,h in enumerate(horizontal_rails):
|
# We need to move this rail to the other layer for the intersection to work
|
||||||
# Compute the overlap of the two paths, None if no overlap
|
e = next(iter(r1))
|
||||||
overlap = v.overlap(h)
|
newz = (e.z+1)%2
|
||||||
if overlap:
|
new_r1 = {vector3d(i.x,i.y,newz) for i in r1}
|
||||||
(ll,ur) = overlap
|
for i2,r2 in enumerate(all_rails):
|
||||||
# We can add a via only if it is a full track width in each dimension
|
if i1==i2:
|
||||||
if ur.x-ll.x >= self.rail_track_width-1 and ur.y-ll.y >= self.rail_track_width-1:
|
continue
|
||||||
vertical_flags[vindex]=True
|
overlap = new_r1 & r2
|
||||||
horizontal_flags[hindex]=True
|
if len(overlap) >= self.supply_rail_wire_width**2:
|
||||||
|
connections.add(i1)
|
||||||
|
connections.add(i2)
|
||||||
via_areas.append(overlap)
|
via_areas.append(overlap)
|
||||||
|
|
||||||
# Go through and add the vias at the center of the intersection
|
# Go through and add the vias at the center of the intersection
|
||||||
for (ll,ur) in via_areas:
|
for area in via_areas:
|
||||||
|
ll = grid_utils.get_lower_left(area)
|
||||||
|
ur = grid_utils.get_upper_right(area)
|
||||||
center = (ll + ur).scale(0.5,0.5,0)
|
center = (ll + ur).scale(0.5,0.5,0)
|
||||||
self.add_via(center,self.rail_track_width)
|
self.add_via(center,self.rail_track_width)
|
||||||
|
|
||||||
# Retrieve the original indices into supply_rails for removal
|
all_indices = set([x for x in range(len(self.supply_rails[name]))])
|
||||||
remove_hrails = [rail for flag,rail in zip(horizontal_flags,horizontal_rails) if not flag]
|
missing_indices = all_indices ^ connections
|
||||||
remove_vrails = [rail for flag,rail in zip(vertical_flags,vertical_rails) if not flag]
|
|
||||||
for rail in remove_hrails + remove_vrails:
|
for rail_index in missing_indices:
|
||||||
debug.info(1,"Removing disconnected supply rail {0} .. {1}".format(rail[0][0],rail[-1][-1]))
|
ll = grid_utils.get_lower_left(all_rails[rail_index])
|
||||||
self.supply_rails.remove(rail)
|
ur = grid_utils.get_upper_right(all_rails[rail_index])
|
||||||
|
debug.info(1,"Removing disconnected supply rail {0} .. {1}".format(ll,ur))
|
||||||
|
self.supply_rails[name].pop(rail_index)
|
||||||
|
self.supply_rail_wires[name].pop(rail_index)
|
||||||
|
|
||||||
|
# Make the supply rails into a big giant set of grids
|
||||||
|
# Must be done after determine which ones are connected)
|
||||||
|
self.create_supply_track_set(name)
|
||||||
|
|
||||||
|
|
||||||
def add_supply_rails(self, name):
|
def add_supply_rails(self, name):
|
||||||
"""
|
"""
|
||||||
|
|
@ -227,9 +232,17 @@ class supply_router(router):
|
||||||
This is after the paths have been pruned and only include rails that are
|
This is after the paths have been pruned and only include rails that are
|
||||||
connected with vias.
|
connected with vias.
|
||||||
"""
|
"""
|
||||||
for wave_path in self.supply_rails:
|
for rail in self.supply_rails[name]:
|
||||||
if wave_path.name == name:
|
ll = grid_utils.get_lower_left(rail)
|
||||||
self.add_wavepath(name, wave_path)
|
ur = grid_utils.get_upper_right(rail)
|
||||||
|
z = ll.z
|
||||||
|
pin = self.compute_wide_enclosure(ll, ur, z, name)
|
||||||
|
debug.info(1,"Adding supply rail {0} {1}->{2} {3}".format(name,ll,ur,pin))
|
||||||
|
self.cell.add_layout_pin(text=name,
|
||||||
|
layer=pin.layer,
|
||||||
|
offset=pin.ll(),
|
||||||
|
width=pin.width(),
|
||||||
|
height=pin.height())
|
||||||
|
|
||||||
def compute_supply_rail_dimensions(self):
|
def compute_supply_rail_dimensions(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -275,6 +288,10 @@ class supply_router(router):
|
||||||
Go in a raster order from bottom to the top (for horizontal) and left to right
|
Go in a raster order from bottom to the top (for horizontal) and left to right
|
||||||
(for vertical). Start with an initial start_offset in x and y direction.
|
(for vertical). Start with an initial start_offset in x and y direction.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
self.supply_rails[name]=[]
|
||||||
|
self.supply_rail_wires[name]=[]
|
||||||
|
|
||||||
start_offset = supply_number*self.supply_rail_width
|
start_offset = supply_number*self.supply_rail_width
|
||||||
|
|
||||||
# Horizontal supply rails
|
# Horizontal supply rails
|
||||||
|
|
@ -283,7 +300,11 @@ class supply_router(router):
|
||||||
wave = [vector3d(0,offset+i,0) for i in range(self.supply_rail_width)]
|
wave = [vector3d(0,offset+i,0) for i in range(self.supply_rail_width)]
|
||||||
# While we can keep expanding east in this horizontal track
|
# While we can keep expanding east in this horizontal track
|
||||||
while wave and wave[0].x < self.max_xoffset:
|
while wave and wave[0].x < self.max_xoffset:
|
||||||
wave = self.find_supply_rail(name, wave, direction.EAST)
|
added_rail = self.find_supply_rail(name, wave, direction.EAST)
|
||||||
|
if added_rail:
|
||||||
|
wave = added_rail.neighbor(direction.EAST)
|
||||||
|
else:
|
||||||
|
wave = None
|
||||||
|
|
||||||
|
|
||||||
# Vertical supply rails
|
# Vertical supply rails
|
||||||
|
|
@ -293,10 +314,41 @@ class supply_router(router):
|
||||||
wave = [vector3d(offset+i,0,1) for i in range(self.supply_rail_width)]
|
wave = [vector3d(offset+i,0,1) for i in range(self.supply_rail_width)]
|
||||||
# While we can keep expanding north in this vertical track
|
# While we can keep expanding north in this vertical track
|
||||||
while wave and wave[0].y < self.max_yoffset:
|
while wave and wave[0].y < self.max_yoffset:
|
||||||
wave = self.find_supply_rail(name, wave, direction.NORTH)
|
added_rail = self.find_supply_rail(name, wave, direction.NORTH)
|
||||||
|
if added_rail:
|
||||||
|
wave = added_rail.neighbor(direction.NORTH)
|
||||||
|
else:
|
||||||
|
wave = None
|
||||||
|
|
||||||
def find_supply_rail(self, name, seed_wave, direct):
|
def find_supply_rail(self, name, seed_wave, direct):
|
||||||
|
"""
|
||||||
|
Find a start location, probe in the direction, and see if the rail is big enough
|
||||||
|
to contain a via, and, if so, add it.
|
||||||
|
"""
|
||||||
|
start_wave = self.find_supply_rail_start(name, seed_wave, direct)
|
||||||
|
if not start_wave:
|
||||||
|
return None
|
||||||
|
|
||||||
|
wave_path = self.probe_supply_rail(name, start_wave, direct)
|
||||||
|
|
||||||
|
if self.approve_supply_rail(name, wave_path):
|
||||||
|
return wave_path
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def find_supply_rail_start(self, name, seed_wave, direct):
|
||||||
|
"""
|
||||||
|
This finds the first valid starting location and routes a supply rail
|
||||||
|
in the given direction.
|
||||||
|
It returns the space after the end of the rail to seed another call for multiple
|
||||||
|
supply rails in the same "track" when there is a blockage.
|
||||||
|
"""
|
||||||
|
# Sweep to find an initial unblocked valid wave
|
||||||
|
start_wave = self.rg.find_start_wave(seed_wave, len(seed_wave), direct)
|
||||||
|
|
||||||
|
return start_wave
|
||||||
|
|
||||||
|
def probe_supply_rail(self, name, start_wave, direct):
|
||||||
"""
|
"""
|
||||||
This finds the first valid starting location and routes a supply rail
|
This finds the first valid starting location and routes a supply rail
|
||||||
in the given direction.
|
in the given direction.
|
||||||
|
|
@ -304,33 +356,41 @@ class supply_router(router):
|
||||||
supply rails in the same "track" when there is a blockage.
|
supply rails in the same "track" when there is a blockage.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Sweep to find an initial unblocked valid wave
|
|
||||||
start_wave = self.rg.find_start_wave(seed_wave, len(seed_wave), direct)
|
|
||||||
if not start_wave:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Expand the wave to the right
|
# Expand the wave to the right
|
||||||
wave_path = self.rg.probe(start_wave, direct)
|
wave_path = self.rg.probe(start_wave, direct)
|
||||||
|
|
||||||
if not wave_path:
|
if not wave_path:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# We must have at least 2 tracks to drop plus 2 tracks for a via
|
|
||||||
if len(wave_path)>=4*self.rail_track_width:
|
|
||||||
# drop the first and last steps to leave escape routing room
|
# drop the first and last steps to leave escape routing room
|
||||||
# around the blockage that stopped the probe
|
# around the blockage that stopped the probe
|
||||||
# except, don't drop the first if it is the first in a row/column
|
# except, don't drop the first if it is the first in a row/column
|
||||||
if (direct==direction.NORTH and seed_wave[0].y>0):
|
if (direct==direction.NORTH and start_wave[0].y>0):
|
||||||
wave_path.trim_first()
|
wave_path.trim_first()
|
||||||
elif (direct == direction.EAST and seed_wave[0].x>0):
|
elif (direct == direction.EAST and start_wave[0].x>0):
|
||||||
wave_path.trim_first()
|
wave_path.trim_first()
|
||||||
|
|
||||||
wave_path.trim_last()
|
wave_path.trim_last()
|
||||||
wave_path.name = name
|
|
||||||
self.supply_rails.append(wave_path)
|
|
||||||
|
|
||||||
# seed the next start wave location
|
return wave_path
|
||||||
wave_end = wave_path[-1]
|
|
||||||
return wave_path.neighbor(direct)
|
def approve_supply_rail(self, name, wave_path):
|
||||||
|
"""
|
||||||
|
Check if the supply rail is sufficient (big enough) and add it to the
|
||||||
|
data structure. Return whether it was added or not.
|
||||||
|
"""
|
||||||
|
# We must have at least 2 tracks to drop plus 2 tracks for a via
|
||||||
|
if len(wave_path)>=4*self.rail_track_width:
|
||||||
|
grid_set = wave_path.get_grids()
|
||||||
|
self.supply_rails[name].append(grid_set)
|
||||||
|
start_wire_index = self.supply_rail_space_width
|
||||||
|
end_wire_index = self.supply_rail_width - self.supply_rail_space_width
|
||||||
|
wire_set = wave_path.get_wire_grids(start_wire_index,end_wire_index)
|
||||||
|
self.supply_rail_wires[name].append(wire_set)
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -348,36 +408,25 @@ class supply_router(router):
|
||||||
self.compute_supply_rails(name, supply_number)
|
self.compute_supply_rails(name, supply_number)
|
||||||
|
|
||||||
# Add the supply rail vias (and prune disconnected rails)
|
# Add the supply rail vias (and prune disconnected rails)
|
||||||
self.connect_supply_rails(name)
|
self.finalize_supply_rails(name)
|
||||||
|
|
||||||
# Add the rails themselves
|
# Add the rails themselves
|
||||||
self.add_supply_rails(name)
|
self.add_supply_rails(name)
|
||||||
|
|
||||||
# Make the supply rails into a big giant set of grids
|
|
||||||
self.create_supply_track_set(name)
|
|
||||||
|
|
||||||
|
|
||||||
def create_supply_track_set(self, pin_name):
|
def create_supply_track_set(self, pin_name):
|
||||||
"""
|
"""
|
||||||
Take the remaining supply rails and put the middle grids into a set.
|
Make a single set of all the tracks for the rail and wire itself.
|
||||||
The middle grids will be guaranteed to have the wire.
|
|
||||||
FIXME: Do this instead with the supply_rail_pitch and width
|
|
||||||
"""
|
"""
|
||||||
rail_set = set()
|
rail_set = set()
|
||||||
wire_set = set()
|
for rail in self.supply_rails[pin_name]:
|
||||||
for rail in self.supply_rails:
|
rail_set.update(rail)
|
||||||
if rail.name != pin_name:
|
|
||||||
continue
|
|
||||||
# FIXME: Select based on self.supply_rail_wire_width and self.supply_rail_width
|
|
||||||
start_wire_index = self.supply_rail_space_width
|
|
||||||
end_wire_index = self.supply_rail_width - self.supply_rail_space_width
|
|
||||||
for wave_index in range(len(rail)):
|
|
||||||
rail_set.update(rail[wave_index])
|
|
||||||
wire_set.update(rail[wave_index][start_wire_index:end_wire_index])
|
|
||||||
|
|
||||||
self.supply_rail_tracks[pin_name] = rail_set
|
self.supply_rail_tracks[pin_name] = rail_set
|
||||||
self.supply_rail_wire_tracks[pin_name] = wire_set
|
|
||||||
|
|
||||||
|
wire_set = set()
|
||||||
|
for rail in self.supply_rail_wires[pin_name]:
|
||||||
|
wire_set.update(rail)
|
||||||
|
self.supply_rail_wire_tracks[pin_name] = wire_set
|
||||||
|
|
||||||
|
|
||||||
def route_pins_to_rails(self, pin_name, remaining_component_indices):
|
def route_pins_to_rails(self, pin_name, remaining_component_indices):
|
||||||
|
|
@ -424,17 +473,10 @@ class supply_router(router):
|
||||||
Add the supply rails of given name as a routing target.
|
Add the supply rails of given name as a routing target.
|
||||||
"""
|
"""
|
||||||
debug.info(2,"Add supply rail target {}".format(pin_name))
|
debug.info(2,"Add supply rail target {}".format(pin_name))
|
||||||
for rail in self.supply_rails:
|
# Add the wire itself as the target
|
||||||
if rail.name != pin_name:
|
self.rg.set_target(self.supply_rail_wire_tracks[pin_name])
|
||||||
continue
|
# But unblock all the rail tracks including the space
|
||||||
# Set the middle track only as the target since wide metal
|
self.rg.set_blocked(self.supply_rail_tracks[pin_name],False)
|
||||||
# spacings may mean the other grids are actually empty space
|
|
||||||
middle_index = math.floor(len(rail[0])/2)
|
|
||||||
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.set_target(pin_in_tracks[middle_index])
|
|
||||||
self.rg.set_blocked(pin_in_tracks,False)
|
|
||||||
|
|
||||||
|
|
||||||
def set_supply_rail_blocked(self, value=True):
|
def set_supply_rail_blocked(self, value=True):
|
||||||
|
|
@ -442,9 +484,6 @@ class supply_router(router):
|
||||||
Add the supply rails of given name as a routing target.
|
Add the supply rails of given name as a routing target.
|
||||||
"""
|
"""
|
||||||
debug.info(3,"Blocking supply rail")
|
debug.info(3,"Blocking supply rail")
|
||||||
for rail in self.supply_rails:
|
for rail_name in self.supply_rail_tracks:
|
||||||
for wave_index in range(len(rail)):
|
self.rg.set_blocked(self.supply_rail_tracks[rail_name])
|
||||||
pin_in_tracks = rail[wave_index]
|
|
||||||
#debug.info(1,"Set target: " + str(pin_name) + " " + str(pin_in_tracks))
|
|
||||||
self.rg.set_blocked(pin_in_tracks,value)
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue