mirror of https://github.com/VLSIDA/OpenRAM.git
Refactor router to have pin_groups for pins and router_tech file
This commit is contained in:
parent
3f17679000
commit
0544d02ca2
|
|
@ -0,0 +1,238 @@
|
||||||
|
from vector3d import vector3d
|
||||||
|
from tech import drc
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class pin_group:
|
||||||
|
"""
|
||||||
|
A class to represent a group of touching rectangular design pin.
|
||||||
|
It requires a router to define the track widths and blockages which
|
||||||
|
determine how pin shapes get mapped to tracks.
|
||||||
|
"""
|
||||||
|
def __init__(self, name, pin_shapes, router):
|
||||||
|
self.name = name
|
||||||
|
# Flag for when it is routed
|
||||||
|
self.routed = False
|
||||||
|
self.shapes = pin_shapes
|
||||||
|
self.router = router
|
||||||
|
# These are the corresponding pin grids for each pin group.
|
||||||
|
self.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.
|
||||||
|
self.blockages = set()
|
||||||
|
|
||||||
|
def set_routed(self, value=True):
|
||||||
|
self.routed = value
|
||||||
|
|
||||||
|
def is_routed(self):
|
||||||
|
return self.routed
|
||||||
|
|
||||||
|
def remove_redundant_shapes(self, pin_list):
|
||||||
|
"""
|
||||||
|
Remove any pin layout that is contained within another.
|
||||||
|
"""
|
||||||
|
local_debug = False
|
||||||
|
if local_debug:
|
||||||
|
debug.info(0,"INITIAL:",pin_list)
|
||||||
|
|
||||||
|
# Make a copy of the list to start
|
||||||
|
new_pin_list = pin_list.copy()
|
||||||
|
|
||||||
|
# This is n^2, but the number is small
|
||||||
|
for pin1 in pin_list:
|
||||||
|
for pin2 in pin_list:
|
||||||
|
# Can't contain yourself
|
||||||
|
if pin1 == pin2:
|
||||||
|
continue
|
||||||
|
if pin2.contains(pin1):
|
||||||
|
# It may have already been removed by being enclosed in another pin
|
||||||
|
if pin1 in new_pin_list:
|
||||||
|
new_pin_list.remove(pin1)
|
||||||
|
|
||||||
|
if local_debug:
|
||||||
|
debug.info(0,"FINAL :",new_pin_list)
|
||||||
|
return new_pin_list
|
||||||
|
|
||||||
|
# FIXME: This relies on some technology parameters from router which is not clearn.
|
||||||
|
def compute_enclosures(self):
|
||||||
|
"""
|
||||||
|
Find the minimum rectangle enclosures of the given tracks.
|
||||||
|
"""
|
||||||
|
# Enumerate every possible enclosure
|
||||||
|
pin_list = []
|
||||||
|
for seed in self.grids:
|
||||||
|
(ll, ur) = self.enclose_pin_grids(seed)
|
||||||
|
enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z)
|
||||||
|
pin_list.append(enclosure)
|
||||||
|
|
||||||
|
#return pin_list
|
||||||
|
# We used to do this, but smaller enclosures can be
|
||||||
|
return self.remove_redundant_shapes(pin_list)
|
||||||
|
|
||||||
|
def compute_enclosure(self, pin, enclosure):
|
||||||
|
"""
|
||||||
|
Compute an enclosure to connect the pin to the enclosure shape.
|
||||||
|
This assumes the shape will be the dimension of the pin.
|
||||||
|
"""
|
||||||
|
if pin.xoverlaps(enclosure):
|
||||||
|
# Is it vertical overlap, extend pin shape to enclosure
|
||||||
|
plc = pin.lc()
|
||||||
|
prc = pin.rc()
|
||||||
|
elc = enclosure.lc()
|
||||||
|
erc = enclosure.rc()
|
||||||
|
ymin = min(plc.y,elc.y)
|
||||||
|
ymax = max(plc.y,elc.y)
|
||||||
|
ll = vector(plc.x, ymin)
|
||||||
|
ur = vector(prc.x, ymax)
|
||||||
|
p = pin_layout(pin.name, [ll, ur], pin.layer)
|
||||||
|
elif pin.yoverlaps(enclosure):
|
||||||
|
# Is it horizontal overlap, extend pin shape to enclosure
|
||||||
|
pbc = pin.bc()
|
||||||
|
puc = pin.uc()
|
||||||
|
ebc = enclosure.bc()
|
||||||
|
euc = enclosure.uc()
|
||||||
|
xmin = min(pbc.x,ebc.x)
|
||||||
|
xmax = max(pbc.x,ebc.x)
|
||||||
|
ll = vector(xmin, pbc.y)
|
||||||
|
ur = vector(xmax, puc.y)
|
||||||
|
p = pin_layout(pin.name, [ll, ur], pin.layer)
|
||||||
|
else:
|
||||||
|
# Neither, so we must do a corner-to corner
|
||||||
|
pc = pin.center()
|
||||||
|
ec = enclosure.center()
|
||||||
|
xmin = min(pc.x, ec.x)
|
||||||
|
xmax = max(pc.x, ec.x)
|
||||||
|
ymin = min(pc.y, ec.y)
|
||||||
|
ymax = max(pc.y, ec.y)
|
||||||
|
ll = vector(xmin, ymin)
|
||||||
|
ur = vector(xmax, ymax)
|
||||||
|
p = pin_layout(pin.name, [ll, ur], pin.layer)
|
||||||
|
|
||||||
|
return p
|
||||||
|
|
||||||
|
def find_smallest_connector(self, enclosure_list):
|
||||||
|
"""
|
||||||
|
Compute all of the connectors between non-overlapping pins and enclosures.
|
||||||
|
Return the smallest.
|
||||||
|
"""
|
||||||
|
smallest = None
|
||||||
|
for pin in self.shapes:
|
||||||
|
for enclosure in enclosure_list:
|
||||||
|
new_enclosure = self.compute_enclosure(pin, enclosure)
|
||||||
|
if smallest == None or new_enclosure.area()<smallest.area():
|
||||||
|
smallest = new_enclosure
|
||||||
|
|
||||||
|
return smallest
|
||||||
|
|
||||||
|
def find_smallest_overlapping(self, shape_list):
|
||||||
|
"""
|
||||||
|
Find the smallest area shape in shape_list that overlaps with any
|
||||||
|
pin in pin_list by a min width.
|
||||||
|
"""
|
||||||
|
|
||||||
|
smallest_shape = None
|
||||||
|
for pin in self.shapes:
|
||||||
|
# They may not be all on the same layer... in the future.
|
||||||
|
zindex=self.router.get_zindex(pin.layer_num)
|
||||||
|
(min_width,min_space) = self.router.get_layer_width_space(zindex)
|
||||||
|
|
||||||
|
# Now compare it with every other shape to check how much they overlap
|
||||||
|
for other in shape_list:
|
||||||
|
overlap_length = pin.overlap_length(other)
|
||||||
|
if overlap_length > min_width:
|
||||||
|
if smallest_shape == None or other.area()<smallest_shape.area():
|
||||||
|
smallest_shape = other
|
||||||
|
|
||||||
|
return smallest_shape
|
||||||
|
|
||||||
|
def overlap_any_shape(self, pin_list, shape_list):
|
||||||
|
"""
|
||||||
|
Does the given pin overlap any of the shapes in the pin list.
|
||||||
|
"""
|
||||||
|
for pin in pin_list:
|
||||||
|
for other in shape_list:
|
||||||
|
if pin.overlaps(other):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def max_pin_layout(self, pin_list):
|
||||||
|
"""
|
||||||
|
Return the max area pin_layout
|
||||||
|
"""
|
||||||
|
biggest = pin_list[0]
|
||||||
|
for pin in pin_list:
|
||||||
|
if pin.area() > biggest.area():
|
||||||
|
biggest = pin
|
||||||
|
|
||||||
|
return pin
|
||||||
|
|
||||||
|
def enclose_pin_grids(self, seed):
|
||||||
|
"""
|
||||||
|
This encloses a single pin component with a rectangle
|
||||||
|
starting with the seed and expanding right until blocked
|
||||||
|
and then up until blocked.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# We may have started with an empty set
|
||||||
|
if not self.grids:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Start with the seed
|
||||||
|
ll = seed
|
||||||
|
|
||||||
|
# Start with the ll and make the widest row
|
||||||
|
row = [ll]
|
||||||
|
# Move right while we can
|
||||||
|
while True:
|
||||||
|
right = row[-1] + vector3d(1,0,0)
|
||||||
|
# Can't move if not in the pin shape
|
||||||
|
if right in self.grids and right not in self.router.blocked_grids:
|
||||||
|
row.append(right)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
# Move up while we can
|
||||||
|
while True:
|
||||||
|
next_row = [x+vector3d(0,1,0) 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:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
row = next_row
|
||||||
|
# Skips the second break
|
||||||
|
continue
|
||||||
|
# Breaks from the nested break
|
||||||
|
break
|
||||||
|
|
||||||
|
# Add a shape from ll to ur
|
||||||
|
ur = row[-1]
|
||||||
|
return (ll,ur)
|
||||||
|
|
||||||
|
|
||||||
|
def enclose_pin(self):
|
||||||
|
"""
|
||||||
|
This will find the biggest rectangle enclosing some grid squares and
|
||||||
|
put a rectangle over it. It does not enclose grid squares that are blocked
|
||||||
|
by other shapes.
|
||||||
|
"""
|
||||||
|
# Compute the enclosure pin_layout list of the set of tracks
|
||||||
|
enclosure_list = self.compute_enclosures()
|
||||||
|
self.enclosure = self.find_smallest_overlapping(enclosure_list)
|
||||||
|
if not self.enclosure:
|
||||||
|
self.enclosure = self.find_smallest_connector(enclosure_list)
|
||||||
|
debug.info(2,"Computed enclosure {0} {1}".format(self.name, self.enclosure))
|
||||||
|
|
||||||
|
def add_enclosure(self, cell):
|
||||||
|
"""
|
||||||
|
Add the enclosure shape to the given cell.
|
||||||
|
"""
|
||||||
|
debug.info(2,"Adding enclosure {0} {1}".format(self.name, self.enclosure))
|
||||||
|
self.router.cell.add_rect(layer=self.enclosure.layer,
|
||||||
|
offset=self.enclosure.ll(),
|
||||||
|
width=self.enclosure.width(),
|
||||||
|
height=self.enclosure.height())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
import sys
|
import sys
|
||||||
import gdsMill
|
import gdsMill
|
||||||
from tech import drc,GDS,layer
|
from tech import drc,GDS
|
||||||
from contact import contact
|
|
||||||
import math
|
import math
|
||||||
import debug
|
import debug
|
||||||
|
from router_tech import router_tech
|
||||||
from pin_layout import pin_layout
|
from pin_layout import pin_layout
|
||||||
|
from pin_group import pin_group
|
||||||
from vector import vector
|
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
|
import grid_utils
|
||||||
|
|
||||||
class router:
|
class router(router_tech):
|
||||||
"""
|
"""
|
||||||
A router class to read an obstruction map from a gds and plan a
|
A router class to read an obstruction map from a gds and plan a
|
||||||
route on a given layer. This is limited to two layer routes.
|
route on a given layer. This is limited to two layer routes.
|
||||||
|
|
@ -23,6 +24,8 @@ class router:
|
||||||
This will instantiate a copy of the gds file or the module at (0,0) and
|
This will instantiate a copy of the gds file or the module at (0,0) and
|
||||||
route on top of this. The blockages from the gds/module will be considered.
|
route on top of this. The blockages from the gds/module will be considered.
|
||||||
"""
|
"""
|
||||||
|
router_tech.__init__(self, layers)
|
||||||
|
|
||||||
self.cell = design
|
self.cell = design
|
||||||
|
|
||||||
# If didn't specify a gds blockage file, write it out to read the gds
|
# If didn't specify a gds blockage file, write it out to read the gds
|
||||||
|
|
@ -37,22 +40,16 @@ class router:
|
||||||
self.reader.loadFromFile(gds_filename)
|
self.reader.loadFromFile(gds_filename)
|
||||||
self.top_name = self.layout.rootStructureName
|
self.top_name = self.layout.rootStructureName
|
||||||
|
|
||||||
# Set up layers and track sizes
|
|
||||||
self.set_layers(layers)
|
|
||||||
|
|
||||||
### The pin data structures
|
### The pin data structures
|
||||||
# A map of pin names to pin structures
|
# A map of pin names to a set of pin_layout structures
|
||||||
self.pins = {}
|
self.pins = {}
|
||||||
# This is a set of all pins so that we don't create blockages for these shapes.
|
# This is a set of all pins (ignoring names) so that can quickly not create blockages for pins
|
||||||
|
# (They will be blocked based on the names we are routing)
|
||||||
self.all_pins = set()
|
self.all_pins = set()
|
||||||
|
|
||||||
# This is a set of pin groups. Each group consists of overlapping pin shapes on the same layer.
|
# A map of pin names to a list of pin groups
|
||||||
|
# A pin group is a set overlapping pin shapes on the same layer.
|
||||||
self.pin_groups = {}
|
self.pin_groups = {}
|
||||||
# These are the corresponding pin grids for each pin group.
|
|
||||||
self.pin_grids = {}
|
|
||||||
# The corresponding set of partially blocked grids for each pin group.
|
|
||||||
# These are blockages for other nets but unblocked for this component.
|
|
||||||
self.pin_blockages = {}
|
|
||||||
|
|
||||||
### The blockage data structures
|
### The blockage data structures
|
||||||
# A list of metal shapes (using the same pin_layout structure) that are not pins but blockages.
|
# A list of metal shapes (using the same pin_layout structure) that are not pins but blockages.
|
||||||
|
|
@ -78,8 +75,6 @@ class router:
|
||||||
self.pins = {}
|
self.pins = {}
|
||||||
self.all_pins = set()
|
self.all_pins = set()
|
||||||
self.pin_groups = {}
|
self.pin_groups = {}
|
||||||
self.pin_grids = {}
|
|
||||||
self.pin_blockages = {}
|
|
||||||
# DO NOT clear the blockages as these don't change
|
# DO NOT clear the blockages as these don't change
|
||||||
self.rg.reinit()
|
self.rg.reinit()
|
||||||
|
|
||||||
|
|
@ -88,19 +83,6 @@ class router:
|
||||||
""" If we want to route something besides the top-level cell."""
|
""" If we want to route something besides the top-level cell."""
|
||||||
self.top_name = top_name
|
self.top_name = top_name
|
||||||
|
|
||||||
def get_zindex(self,layer_num):
|
|
||||||
if layer_num==self.horiz_layer_number:
|
|
||||||
return 0
|
|
||||||
else:
|
|
||||||
return 1
|
|
||||||
|
|
||||||
def get_layer(self, zindex):
|
|
||||||
if zindex==1:
|
|
||||||
return self.vert_layer_name
|
|
||||||
elif zindex==0:
|
|
||||||
return self.horiz_layer_name
|
|
||||||
else:
|
|
||||||
debug.error("Invalid zindex {}".format(zindex),-1)
|
|
||||||
|
|
||||||
def is_wave(self,path):
|
def is_wave(self,path):
|
||||||
"""
|
"""
|
||||||
|
|
@ -108,40 +90,6 @@ class router:
|
||||||
"""
|
"""
|
||||||
return len(path[0])>1
|
return len(path[0])>1
|
||||||
|
|
||||||
def set_layers(self, layers):
|
|
||||||
"""
|
|
||||||
Allows us to change the layers that we are routing on. First layer
|
|
||||||
is always horizontal, middle is via, and last is always
|
|
||||||
vertical.
|
|
||||||
"""
|
|
||||||
self.layers = layers
|
|
||||||
(self.horiz_layer_name, self.via_layer_name, self.vert_layer_name) = self.layers
|
|
||||||
|
|
||||||
# This is the minimum routed track spacing
|
|
||||||
via_connect = contact(self.layers, (1, 1))
|
|
||||||
self.max_via_size = max(via_connect.width,via_connect.height)
|
|
||||||
|
|
||||||
self.vert_layer_minwidth = drc("minwidth_{0}".format(self.vert_layer_name))
|
|
||||||
self.vert_layer_spacing = drc(str(self.vert_layer_name)+"_to_"+str(self.vert_layer_name))
|
|
||||||
self.vert_layer_number = layer[self.vert_layer_name]
|
|
||||||
|
|
||||||
self.horiz_layer_minwidth = drc("minwidth_{0}".format(self.horiz_layer_name))
|
|
||||||
self.horiz_layer_spacing = drc(str(self.horiz_layer_name)+"_to_"+str(self.horiz_layer_name))
|
|
||||||
self.horiz_layer_number = layer[self.horiz_layer_name]
|
|
||||||
|
|
||||||
self.horiz_track_width = self.max_via_size + self.horiz_layer_spacing
|
|
||||||
self.vert_track_width = self.max_via_size + self.vert_layer_spacing
|
|
||||||
|
|
||||||
# We'll keep horizontal and vertical tracks the same for simplicity.
|
|
||||||
self.track_width = max(self.horiz_track_width,self.vert_track_width)
|
|
||||||
debug.info(1,"Track width: "+str(self.track_width))
|
|
||||||
|
|
||||||
self.track_widths = [self.track_width] * 2
|
|
||||||
self.track_factor = [1/self.track_width] * 2
|
|
||||||
debug.info(1,"Track factor: {0}".format(self.track_factor))
|
|
||||||
|
|
||||||
# When we actually create the routes, make them the width of the track (minus 1/2 spacing on each side)
|
|
||||||
self.layer_widths = [self.track_width - self.horiz_layer_spacing, 1, self.track_width - self.vert_layer_spacing]
|
|
||||||
|
|
||||||
def retrieve_pins(self,pin_name):
|
def retrieve_pins(self,pin_name):
|
||||||
"""
|
"""
|
||||||
|
|
@ -224,14 +172,16 @@ class router:
|
||||||
self.set_supply_rail_blocked(True)
|
self.set_supply_rail_blocked(True)
|
||||||
|
|
||||||
# Block all of the pin components (some will be unblocked if they're a source/target)
|
# Block all of the pin components (some will be unblocked if they're a source/target)
|
||||||
for name in self.pin_grids.keys():
|
for name in self.pin_groups.keys():
|
||||||
self.set_blockages(self.pin_grids[name],True)
|
blockage_grids = {y for x in self.pin_groups[name] for y in x.grids}
|
||||||
|
self.set_blockages(blockage_grids,True)
|
||||||
|
|
||||||
|
|
||||||
# Don't mark the other components as targets since we want to route
|
# 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
|
# directly to a rail, but unblock all the source components so we can
|
||||||
# route over them
|
# route over them
|
||||||
self.set_blockages(self.pin_grids[pin_name],False)
|
blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids}
|
||||||
|
self.set_blockages(blockage_grids,False)
|
||||||
|
|
||||||
# These are the paths that have already been routed.
|
# These are the paths that have already been routed.
|
||||||
self.set_path_blockages()
|
self.set_path_blockages()
|
||||||
|
|
@ -458,23 +408,6 @@ class router:
|
||||||
return set([best_coord])
|
return set([best_coord])
|
||||||
|
|
||||||
|
|
||||||
def get_layer_width_space(self, zindex, width=0, length=0):
|
|
||||||
"""
|
|
||||||
Return the width and spacing of a given layer
|
|
||||||
and wire of a given width and length.
|
|
||||||
"""
|
|
||||||
if zindex==1:
|
|
||||||
layer_name = self.vert_layer_name
|
|
||||||
elif zindex==0:
|
|
||||||
layer_name = self.horiz_layer_name
|
|
||||||
else:
|
|
||||||
debug.error("Invalid zindex for track", -1)
|
|
||||||
|
|
||||||
min_width = drc("minwidth_{0}".format(layer_name), width, length)
|
|
||||||
min_spacing = drc(str(layer_name)+"_to_"+str(layer_name), width, length)
|
|
||||||
|
|
||||||
return (min_width,min_spacing)
|
|
||||||
|
|
||||||
def convert_pin_coord_to_tracks(self, pin, coord):
|
def convert_pin_coord_to_tracks(self, pin, coord):
|
||||||
"""
|
"""
|
||||||
Given a pin and a track coordinate, determine if the pin overlaps enough.
|
Given a pin and a track coordinate, determine if the pin overlaps enough.
|
||||||
|
|
@ -599,24 +532,18 @@ class router:
|
||||||
reduced_classes = combine_classes(equiv_classes)
|
reduced_classes = combine_classes(equiv_classes)
|
||||||
if local_debug:
|
if local_debug:
|
||||||
debug.info(0,"FINAL ",reduced_classes)
|
debug.info(0,"FINAL ",reduced_classes)
|
||||||
self.pin_groups[pin_name]=reduced_classes
|
self.pin_groups[pin_name] = [pin_group(name=pin_name, pin_shapes=x, router=self) for x in reduced_classes]
|
||||||
|
|
||||||
def convert_pins(self, pin_name):
|
def convert_pins(self, pin_name):
|
||||||
"""
|
"""
|
||||||
Convert the pin groups into pin tracks and blockage tracks.
|
Convert the pin groups into pin tracks and blockage tracks.
|
||||||
"""
|
"""
|
||||||
try:
|
|
||||||
self.pin_grids[pin_name]
|
|
||||||
except:
|
|
||||||
self.pin_grids[pin_name] = []
|
|
||||||
|
|
||||||
found_pin = False
|
|
||||||
for pg in self.pin_groups[pin_name]:
|
for pg in self.pin_groups[pin_name]:
|
||||||
#print("PG ",pg)
|
#print("PG ",pg)
|
||||||
# Keep the same groups for each pin
|
# Keep the same groups for each pin
|
||||||
pin_set = set()
|
pin_set = set()
|
||||||
blockage_set = set()
|
blockage_set = set()
|
||||||
for pin in pg:
|
for pin in pg.shapes:
|
||||||
debug.info(2," Converting {0}".format(pin))
|
debug.info(2," Converting {0}".format(pin))
|
||||||
# Determine which tracks the pin overlaps
|
# Determine which tracks the pin overlaps
|
||||||
pin_in_tracks=self.convert_pin_to_tracks(pin_name, pin)
|
pin_in_tracks=self.convert_pin_to_tracks(pin_name, pin)
|
||||||
|
|
@ -644,7 +571,7 @@ class router:
|
||||||
debug.error("Unable to find unblocked pin on grid.")
|
debug.error("Unable to find unblocked pin on grid.")
|
||||||
|
|
||||||
# We need to route each of the components, so don't combine the groups
|
# We need to route each of the components, so don't combine the groups
|
||||||
self.pin_grids[pin_name].append(pin_set | blockage_set)
|
pg.grids = pin_set | blockage_set
|
||||||
|
|
||||||
# Add all of the partial blocked grids to the set for the design
|
# Add all of the partial blocked grids to the set for the design
|
||||||
# if they are not blocked by other metal
|
# if they are not blocked by other metal
|
||||||
|
|
@ -658,143 +585,6 @@ class router:
|
||||||
#self.blocked_grids.difference_update(pin_set)
|
#self.blocked_grids.difference_update(pin_set)
|
||||||
|
|
||||||
|
|
||||||
def enclose_pin_grids(self, grids, seed):
|
|
||||||
"""
|
|
||||||
This encloses a single pin component with a rectangle
|
|
||||||
starting with the seed and expanding right until blocked
|
|
||||||
and then up until blocked.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# We may have started with an empty set
|
|
||||||
if not grids:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Start with the seed
|
|
||||||
ll = seed
|
|
||||||
|
|
||||||
# Start with the ll and make the widest row
|
|
||||||
row = [ll]
|
|
||||||
# Move right while we can
|
|
||||||
while True:
|
|
||||||
right = row[-1] + vector3d(1,0,0)
|
|
||||||
# Can't move if not in the pin shape
|
|
||||||
if right in grids and right not in self.blocked_grids:
|
|
||||||
row.append(right)
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
# Move up while we can
|
|
||||||
while True:
|
|
||||||
next_row = [x+vector3d(0,1,0) 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 grids or cell in self.blocked_grids:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
row = next_row
|
|
||||||
# Skips the second break
|
|
||||||
continue
|
|
||||||
# Breaks from the nested break
|
|
||||||
break
|
|
||||||
|
|
||||||
# Add a shape from ll to ur
|
|
||||||
ur = row[-1]
|
|
||||||
return self.compute_pin_enclosure(ll, ur, ll.z)
|
|
||||||
|
|
||||||
def remove_redundant_shapes(self, pin_list):
|
|
||||||
"""
|
|
||||||
Remove any pin layout that is contained within another.
|
|
||||||
"""
|
|
||||||
local_debug = False
|
|
||||||
if local_debug:
|
|
||||||
debug.info(0,"INITIAL:",pin_list)
|
|
||||||
|
|
||||||
# Make a copy of the list to start
|
|
||||||
new_pin_list = pin_list.copy()
|
|
||||||
|
|
||||||
# This is n^2, but the number is small
|
|
||||||
for pin1 in pin_list:
|
|
||||||
for pin2 in pin_list:
|
|
||||||
# Can't contain yourself
|
|
||||||
if pin1 == pin2:
|
|
||||||
continue
|
|
||||||
if pin2.contains(pin1):
|
|
||||||
# It may have already been removed by being enclosed in another pin
|
|
||||||
if pin1 in new_pin_list:
|
|
||||||
new_pin_list.remove(pin1)
|
|
||||||
|
|
||||||
if local_debug:
|
|
||||||
debug.info(0,"FINAL :",new_pin_list)
|
|
||||||
return new_pin_list
|
|
||||||
|
|
||||||
def compute_enclosures(self, tracks):
|
|
||||||
"""
|
|
||||||
Find the minimum rectangle enclosures of the given tracks.
|
|
||||||
"""
|
|
||||||
# Enumerate every possible enclosure
|
|
||||||
pin_list = []
|
|
||||||
for seed in tracks:
|
|
||||||
pin_list.append(self.enclose_pin_grids(tracks, seed))
|
|
||||||
|
|
||||||
#return pin_list
|
|
||||||
# We used to do this, but smaller enclosures can be
|
|
||||||
return self.remove_redundant_shapes(pin_list)
|
|
||||||
|
|
||||||
def overlap_any_shape(self, pin_list, shape_list):
|
|
||||||
"""
|
|
||||||
Does the given pin overlap any of the shapes in the pin list.
|
|
||||||
"""
|
|
||||||
for pin in pin_list:
|
|
||||||
for other in shape_list:
|
|
||||||
if pin.overlaps(other):
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
def find_smallest_overlapping(self, pin_list, shape_list):
|
|
||||||
"""
|
|
||||||
Find the smallest area shape in shape_list that overlaps with any
|
|
||||||
pin in pin_list by a min width.
|
|
||||||
"""
|
|
||||||
|
|
||||||
smallest_shape = None
|
|
||||||
for pin in pin_list:
|
|
||||||
# They may not be all on the same layer... in the future.
|
|
||||||
zindex=self.get_zindex(pin.layer_num)
|
|
||||||
(min_width,min_space) = self.get_layer_width_space(zindex)
|
|
||||||
|
|
||||||
# Now compare it with every other shape to check how much they overlap
|
|
||||||
for other in shape_list:
|
|
||||||
overlap_length = pin.overlap_length(other)
|
|
||||||
if overlap_length > min_width:
|
|
||||||
if smallest_shape == None or other.area()<smallest_shape.area():
|
|
||||||
smallest_shape = other
|
|
||||||
|
|
||||||
return smallest_shape
|
|
||||||
|
|
||||||
def max_pin_layout(self, pin_list):
|
|
||||||
"""
|
|
||||||
Return the max area pin_layout
|
|
||||||
"""
|
|
||||||
biggest = pin_list[0]
|
|
||||||
for pin in pin_list:
|
|
||||||
if pin.area() > biggest.area():
|
|
||||||
biggest = pin
|
|
||||||
|
|
||||||
return pin
|
|
||||||
|
|
||||||
def find_smallest_connector(self, pin_list, enclosure_list):
|
|
||||||
"""
|
|
||||||
Compute all of the connectors between non-overlapping pins and enclosures.
|
|
||||||
Return the smallest.
|
|
||||||
"""
|
|
||||||
smallest = None
|
|
||||||
for pin in pin_list:
|
|
||||||
for enclosure in enclosure_list:
|
|
||||||
new_enclosure = self.compute_enclosure(pin, enclosure)
|
|
||||||
if smallest == None or new_enclosure.area()<smallest.area():
|
|
||||||
smallest = new_enclosure
|
|
||||||
|
|
||||||
return smallest
|
|
||||||
|
|
||||||
def enclose_pins(self):
|
def enclose_pins(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -806,86 +596,20 @@ class router:
|
||||||
self.connector_enclosure = []
|
self.connector_enclosure = []
|
||||||
self.enclosures = []
|
self.enclosures = []
|
||||||
|
|
||||||
for pin_name in self.pin_grids.keys():
|
for pin_name in self.pin_groups.keys():
|
||||||
debug.info(1,"Enclosing pins for {}".format(pin_name))
|
debug.info(1,"Enclosing pins for {}".format(pin_name))
|
||||||
debug.check(len(self.pin_groups[pin_name])==len(self.pin_grids[pin_name]),"Unequal pin_group and pin_grid")
|
for pg in self.pin_groups[pin_name]:
|
||||||
for pin_group,pin_grid_set in zip(self.pin_groups[pin_name],self.pin_grids[pin_name]):
|
pg.enclose_pin()
|
||||||
|
pg.add_enclosure(self.cell)
|
||||||
# Compute the enclosure pin_layout list of the set of tracks
|
|
||||||
enclosure_list = self.compute_enclosures(pin_grid_set)
|
|
||||||
smallest_enclosure = self.find_smallest_overlapping(pin_group, enclosure_list)
|
|
||||||
if smallest_enclosure:
|
|
||||||
#for smallest_enclosure in enclosure_list:
|
|
||||||
debug.info(2,"Adding enclosure {0} {1}".format(pin_name, smallest_enclosure))
|
|
||||||
self.cell.add_rect(layer=smallest_enclosure.layer,
|
|
||||||
offset=smallest_enclosure.ll(),
|
|
||||||
width=smallest_enclosure.width(),
|
|
||||||
height=smallest_enclosure.height())
|
|
||||||
self.enclosures.append(smallest_enclosure)
|
|
||||||
|
|
||||||
#if self.overlap_any_shape(pin_group, enclosure_list):
|
|
||||||
#debug.info(2,"Pin overlaps enclosure {0}".format(pin_name))
|
|
||||||
# pass
|
|
||||||
else:
|
|
||||||
new_enclosure = self.find_smallest_connector(pin_group, enclosure_list)
|
|
||||||
debug.info(2,"Adding connector enclosure {0} {1}".format(pin_name, new_enclosure))
|
|
||||||
self.cell.add_rect(layer=new_enclosure.layer,
|
|
||||||
offset=new_enclosure.ll(),
|
|
||||||
width=new_enclosure.width(),
|
|
||||||
height=new_enclosure.height())
|
|
||||||
self.connector_enclosure.append(new_enclosure)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#self.write_debug_gds("pin_debug.gds", True)
|
#self.write_debug_gds("pin_debug.gds", True)
|
||||||
|
|
||||||
def compute_enclosure(self, pin, enclosure):
|
|
||||||
"""
|
|
||||||
Compute an enclosure to connect the pin to the enclosure shape.
|
|
||||||
This assumes the shape will be the dimension of the pin.
|
|
||||||
"""
|
|
||||||
if pin.xoverlaps(enclosure):
|
|
||||||
# Is it vertical overlap, extend pin shape to enclosure
|
|
||||||
plc = pin.lc()
|
|
||||||
prc = pin.rc()
|
|
||||||
elc = enclosure.lc()
|
|
||||||
erc = enclosure.rc()
|
|
||||||
ymin = min(plc.y,elc.y)
|
|
||||||
ymax = max(plc.y,elc.y)
|
|
||||||
ll = vector(plc.x, ymin)
|
|
||||||
ur = vector(prc.x, ymax)
|
|
||||||
p = pin_layout(pin.name, [ll, ur], pin.layer)
|
|
||||||
elif pin.yoverlaps(enclosure):
|
|
||||||
# Is it horizontal overlap, extend pin shape to enclosure
|
|
||||||
pbc = pin.bc()
|
|
||||||
puc = pin.uc()
|
|
||||||
ebc = enclosure.bc()
|
|
||||||
euc = enclosure.uc()
|
|
||||||
xmin = min(pbc.x,ebc.x)
|
|
||||||
xmax = max(pbc.x,ebc.x)
|
|
||||||
ll = vector(xmin, pbc.y)
|
|
||||||
ur = vector(xmax, puc.y)
|
|
||||||
p = pin_layout(pin.name, [ll, ur], pin.layer)
|
|
||||||
else:
|
|
||||||
# Neither, so we must do a corner-to corner
|
|
||||||
pc = pin.center()
|
|
||||||
ec = enclosure.center()
|
|
||||||
xmin = min(pc.x, ec.x)
|
|
||||||
xmax = max(pc.x, ec.x)
|
|
||||||
ymin = min(pc.y, ec.y)
|
|
||||||
ymax = max(pc.y, ec.y)
|
|
||||||
ll = vector(xmin, ymin)
|
|
||||||
ur = vector(xmax, ymax)
|
|
||||||
p = pin_layout(pin.name, [ll, ur], pin.layer)
|
|
||||||
|
|
||||||
return p
|
|
||||||
|
|
||||||
def add_source(self, pin_name):
|
def add_source(self, pin_name):
|
||||||
"""
|
"""
|
||||||
This will mark the grids for all pin components as a source.
|
This will mark the grids for all pin components as a source.
|
||||||
Marking as source or target also clears blockage status.
|
Marking as source or target also clears blockage status.
|
||||||
"""
|
"""
|
||||||
for i in range(self.num_pin_grids(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)
|
||||||
|
|
||||||
def add_target(self, pin_name):
|
def add_target(self, pin_name):
|
||||||
|
|
@ -893,14 +617,14 @@ class router:
|
||||||
This will mark the grids for all pin components as a target.
|
This will mark the grids for all pin components as a target.
|
||||||
Marking as source or target also clears blockage status.
|
Marking as source or target also clears blockage status.
|
||||||
"""
|
"""
|
||||||
for i in range(self.num_pin_grids(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)
|
||||||
|
|
||||||
def num_pin_components(self, pin_name):
|
def num_pin_components(self, pin_name):
|
||||||
"""
|
"""
|
||||||
This returns how many disconnected pin components there are.
|
This returns how many disconnected pin components there are.
|
||||||
"""
|
"""
|
||||||
return len(self.pin_grids[pin_name])
|
return len(self.pin_groups[pin_name])
|
||||||
|
|
||||||
def add_pin_component_source(self, pin_name, index):
|
def add_pin_component_source(self, pin_name, index):
|
||||||
"""
|
"""
|
||||||
|
|
@ -909,7 +633,7 @@ class router:
|
||||||
"""
|
"""
|
||||||
debug.check(index<self.num_pin_components(pin_name),"Pin component index too large.")
|
debug.check(index<self.num_pin_components(pin_name),"Pin component index too large.")
|
||||||
|
|
||||||
pin_in_tracks = self.pin_grids[pin_name][index]
|
pin_in_tracks = self.pin_groups[pin_name][index].grids
|
||||||
debug.info(1,"Set source: " + str(pin_name) + " " + str(pin_in_tracks))
|
debug.info(1,"Set source: " + str(pin_name) + " " + str(pin_in_tracks))
|
||||||
self.rg.add_source(pin_in_tracks)
|
self.rg.add_source(pin_in_tracks)
|
||||||
|
|
||||||
|
|
@ -928,7 +652,7 @@ class router:
|
||||||
"""
|
"""
|
||||||
debug.check(index<self.num_pin_grids(pin_name),"Pin component index too large.")
|
debug.check(index<self.num_pin_grids(pin_name),"Pin component index too large.")
|
||||||
|
|
||||||
pin_in_tracks = self.pin_grids[pin_name][index]
|
pin_in_tracks = self.pin_groups[pin_name][index].grids
|
||||||
debug.info(1,"Set target: " + str(pin_name) + " " + str(pin_in_tracks))
|
debug.info(1,"Set target: " + str(pin_name) + " " + str(pin_in_tracks))
|
||||||
self.rg.add_target(pin_in_tracks)
|
self.rg.add_target(pin_in_tracks)
|
||||||
|
|
||||||
|
|
@ -938,8 +662,8 @@ class router:
|
||||||
Block all of the pin components.
|
Block all of the pin components.
|
||||||
"""
|
"""
|
||||||
debug.info(2,"Setting blockages {0} {1}".format(pin_name,value))
|
debug.info(2,"Setting blockages {0} {1}".format(pin_name,value))
|
||||||
for component in self.pin_grids[pin_name]:
|
for pg in self.pin_groups[pin_name]:
|
||||||
self.set_blockages(component, value)
|
self.set_blockages(pg.grids, value)
|
||||||
|
|
||||||
|
|
||||||
def prepare_path(self,path):
|
def prepare_path(self,path):
|
||||||
|
|
@ -1011,8 +735,7 @@ class router:
|
||||||
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
|
||||||
the track DRC rules. If name is supplied, it is added as a pin and
|
the track DRC rules.
|
||||||
not just a rectangle.
|
|
||||||
"""
|
"""
|
||||||
# Get the layer information
|
# Get the layer information
|
||||||
(width, space) = self.get_layer_width_space(zindex)
|
(width, space) = self.get_layer_width_space(zindex)
|
||||||
|
|
@ -1034,8 +757,6 @@ class router:
|
||||||
def compute_wide_enclosure(self, ll, ur, zindex, name=""):
|
def compute_wide_enclosure(self, ll, ur, zindex, name=""):
|
||||||
"""
|
"""
|
||||||
Enclose the tracks from ll to ur in a single rectangle that meets the track DRC rules.
|
Enclose the tracks from ll to ur in a single rectangle that meets the track DRC rules.
|
||||||
If name is supplied, it is added as a pin and not just a rectangle.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Find the pin enclosure of the whole track shape (ignoring DRCs)
|
# Find the pin enclosure of the whole track shape (ignoring DRCs)
|
||||||
|
|
@ -1064,19 +785,6 @@ class router:
|
||||||
return pin
|
return pin
|
||||||
|
|
||||||
|
|
||||||
def get_inertia(self,p0,p1):
|
|
||||||
"""
|
|
||||||
Sets the direction based on the previous direction we came from.
|
|
||||||
"""
|
|
||||||
# direction (index) of movement
|
|
||||||
if p0.x!=p1.x:
|
|
||||||
return 0
|
|
||||||
elif p0.y!=p1.y:
|
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
# z direction
|
|
||||||
return 2
|
|
||||||
|
|
||||||
def contract_path(self,path):
|
def contract_path(self,path):
|
||||||
"""
|
"""
|
||||||
Remove intermediate points in a rectilinear path or a wave.
|
Remove intermediate points in a rectilinear path or a wave.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
from tech import drc,layer
|
||||||
|
from contact import contact
|
||||||
|
from pin_group import pin_group
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class router_tech:
|
||||||
|
"""
|
||||||
|
This is a class to hold the router tech constants.
|
||||||
|
"""
|
||||||
|
def __init__(self, layers):
|
||||||
|
"""
|
||||||
|
Allows us to change the layers that we are routing on. First layer
|
||||||
|
is always horizontal, middle is via, and last is always
|
||||||
|
vertical.
|
||||||
|
"""
|
||||||
|
self.layers = layers
|
||||||
|
(self.horiz_layer_name, self.via_layer_name, self.vert_layer_name) = self.layers
|
||||||
|
|
||||||
|
# This is the minimum routed track spacing
|
||||||
|
via_connect = contact(self.layers, (1, 1))
|
||||||
|
self.max_via_size = max(via_connect.width,via_connect.height)
|
||||||
|
|
||||||
|
self.vert_layer_minwidth = drc("minwidth_{0}".format(self.vert_layer_name))
|
||||||
|
self.vert_layer_spacing = drc(str(self.vert_layer_name)+"_to_"+str(self.vert_layer_name))
|
||||||
|
self.vert_layer_number = layer[self.vert_layer_name]
|
||||||
|
|
||||||
|
self.horiz_layer_minwidth = drc("minwidth_{0}".format(self.horiz_layer_name))
|
||||||
|
self.horiz_layer_spacing = drc(str(self.horiz_layer_name)+"_to_"+str(self.horiz_layer_name))
|
||||||
|
self.horiz_layer_number = layer[self.horiz_layer_name]
|
||||||
|
|
||||||
|
self.horiz_track_width = self.max_via_size + self.horiz_layer_spacing
|
||||||
|
self.vert_track_width = self.max_via_size + self.vert_layer_spacing
|
||||||
|
|
||||||
|
# We'll keep horizontal and vertical tracks the same for simplicity.
|
||||||
|
self.track_width = max(self.horiz_track_width,self.vert_track_width)
|
||||||
|
debug.info(1,"Track width: "+str(self.track_width))
|
||||||
|
|
||||||
|
self.track_widths = [self.track_width] * 2
|
||||||
|
self.track_factor = [1/self.track_width] * 2
|
||||||
|
debug.info(1,"Track factor: {0}".format(self.track_factor))
|
||||||
|
|
||||||
|
# When we actually create the routes, make them the width of the track (minus 1/2 spacing on each side)
|
||||||
|
self.layer_widths = [self.track_width - self.horiz_layer_spacing, 1, self.track_width - self.vert_layer_spacing]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_zindex(self,layer_num):
|
||||||
|
if layer_num==self.horiz_layer_number:
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def get_layer(self, zindex):
|
||||||
|
if zindex==1:
|
||||||
|
return self.vert_layer_name
|
||||||
|
elif zindex==0:
|
||||||
|
return self.horiz_layer_name
|
||||||
|
else:
|
||||||
|
debug.error("Invalid zindex {}".format(zindex),-1)
|
||||||
|
|
||||||
|
def get_layer_width_space(self, zindex, width=0, length=0):
|
||||||
|
"""
|
||||||
|
Return the width and spacing of a given layer
|
||||||
|
and wire of a given width and length.
|
||||||
|
"""
|
||||||
|
if zindex==1:
|
||||||
|
layer_name = self.vert_layer_name
|
||||||
|
elif zindex==0:
|
||||||
|
layer_name = self.horiz_layer_name
|
||||||
|
else:
|
||||||
|
debug.error("Invalid zindex for track", -1)
|
||||||
|
|
||||||
|
min_width = drc("minwidth_{0}".format(layer_name), width, length)
|
||||||
|
min_spacing = drc(str(layer_name)+"_to_"+str(layer_name), width, length)
|
||||||
|
|
||||||
|
return (min_width,min_spacing)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import gdsMill
|
import gdsMill
|
||||||
import tech
|
import tech
|
||||||
from contact import contact
|
|
||||||
import math
|
import math
|
||||||
import debug
|
import debug
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
from contact import contact
|
||||||
|
from pin_group import pin_group
|
||||||
from pin_layout import pin_layout
|
from pin_layout import pin_layout
|
||||||
from vector3d import vector3d
|
from vector3d import vector3d
|
||||||
from router import router
|
from router import router
|
||||||
|
|
@ -84,14 +85,14 @@ class supply_router(router):
|
||||||
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("debug_rails.gds",stop_program=True)
|
||||||
|
|
||||||
remaining_vdd_pin_indices = self.route_simple_overlaps(vdd_name)
|
self.route_simple_overlaps(vdd_name)
|
||||||
remaining_gnd_pin_indices = self.route_simple_overlaps(gnd_name)
|
self.route_simple_overlaps(gnd_name)
|
||||||
#self.write_debug_gds("debug_simple_route.gds",stop_program=True)
|
#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)
|
||||||
self.route_pins_to_rails(gnd_name, remaining_gnd_pin_indices)
|
self.route_pins_to_rails(gnd_name)
|
||||||
#self.write_debug_gds("debug_pin_routes.gds",stop_program=True)
|
#self.write_debug_gds("debug_pin_routes.gds",stop_program=True)
|
||||||
|
|
||||||
#self.write_debug_gds("final.gds")
|
#self.write_debug_gds("final.gds")
|
||||||
|
|
@ -105,21 +106,18 @@ class supply_router(router):
|
||||||
This checks for simple cases where a pin component already overlaps a supply rail.
|
This checks for simple cases where a pin component already overlaps a supply rail.
|
||||||
It will add an enclosure to ensure the overlap in wide DRC rule cases.
|
It will add an enclosure to ensure the overlap in wide DRC rule cases.
|
||||||
"""
|
"""
|
||||||
num_components = self.num_pin_components(pin_name)
|
|
||||||
remaining_pins = []
|
|
||||||
supply_tracks = self.supply_rail_tracks[pin_name]
|
supply_tracks = self.supply_rail_tracks[pin_name]
|
||||||
|
for pg in self.pin_groups[pin_name]:
|
||||||
|
if pg.is_routed():
|
||||||
|
continue
|
||||||
|
|
||||||
for index in range(num_components):
|
common_set = supply_tracks & pg.grids
|
||||||
pin_in_tracks = self.pin_grids[pin_name][index]
|
|
||||||
common_set = supply_tracks & pin_in_tracks
|
|
||||||
|
|
||||||
if len(common_set)==0:
|
if len(common_set)>0:
|
||||||
# if no overlap, add it to the complex route pins
|
|
||||||
remaining_pins.append(index)
|
|
||||||
else:
|
|
||||||
self.create_simple_overlap_enclosure(pin_name, common_set)
|
self.create_simple_overlap_enclosure(pin_name, common_set)
|
||||||
|
pg.set_routed()
|
||||||
|
|
||||||
|
|
||||||
return remaining_pins
|
|
||||||
|
|
||||||
def recurse_simple_overlap_enclosure(self, pin_name, start_set, direct):
|
def recurse_simple_overlap_enclosure(self, pin_name, start_set, direct):
|
||||||
"""
|
"""
|
||||||
|
|
@ -167,7 +165,9 @@ class supply_router(router):
|
||||||
if not new_set:
|
if not new_set:
|
||||||
new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.WEST)
|
new_set = self.recurse_simple_overlap_enclosure(pin_name, start_set, direction.WEST)
|
||||||
|
|
||||||
enclosure_list = self.compute_enclosures(new_set)
|
pg = pin_group(name=pin_name, pin_shapes=[], router=self)
|
||||||
|
pg.grids=new_set
|
||||||
|
enclosure_list = pg.compute_enclosures()
|
||||||
for pin in enclosure_list:
|
for pin in enclosure_list:
|
||||||
debug.info(2,"Adding simple overlap enclosure {0} {1}".format(pin_name, pin))
|
debug.info(2,"Adding simple overlap enclosure {0} {1}".format(pin_name, pin))
|
||||||
self.cell.add_rect(layer=pin.layer,
|
self.cell.add_rect(layer=pin.layer,
|
||||||
|
|
@ -464,23 +464,26 @@ class supply_router(router):
|
||||||
self.supply_rail_wire_tracks[pin_name] = wire_set
|
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):
|
||||||
"""
|
"""
|
||||||
This will route each of the remaining pin components to the supply rails.
|
This will route each of the remaining pin components to the supply rails.
|
||||||
After it is done, the cells are added to the pin blockage list.
|
After it is done, the cells are added to the pin blockage list.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
remaining_components = sum(not x.is_routed() for x in self.pin_groups[pin_name])
|
||||||
debug.info(1,"Pin {0} has {1} remaining components to route.".format(pin_name,
|
debug.info(1,"Pin {0} has {1} remaining components to route.".format(pin_name,
|
||||||
len(remaining_component_indices)))
|
remaining_components))
|
||||||
|
|
||||||
recent_paths = []
|
for index,pg in enumerate(self.pin_groups[pin_name]):
|
||||||
# For every component
|
if pg.is_routed():
|
||||||
for index in remaining_component_indices:
|
continue
|
||||||
debug.info(2,"Routing component {0} {1}".format(pin_name, index))
|
debug.info(2,"Routing component {0} {1}".format(pin_name, index))
|
||||||
|
|
||||||
|
# Clear everything in the routing grid.
|
||||||
self.rg.reinit()
|
self.rg.reinit()
|
||||||
|
|
||||||
|
# This is inefficient since it is non-incremental, but it was
|
||||||
|
# easier to debug.
|
||||||
self.prepare_blockages(pin_name)
|
self.prepare_blockages(pin_name)
|
||||||
|
|
||||||
# Add the single component of the pin as the source
|
# Add the single component of the pin as the source
|
||||||
|
|
@ -491,16 +494,10 @@ class supply_router(router):
|
||||||
# Don't add the other pins, but we could?
|
# Don't add the other pins, but we could?
|
||||||
self.add_supply_rail_target(pin_name)
|
self.add_supply_rail_target(pin_name)
|
||||||
|
|
||||||
# Add the previous paths as targets too
|
|
||||||
#self.add_path_target(recent_paths)
|
|
||||||
|
|
||||||
#print(self.rg.target)
|
|
||||||
|
|
||||||
# Actually run the A* router
|
# Actually run the A* router
|
||||||
if not self.run_router(detour_scale=5):
|
if not self.run_router(detour_scale=5):
|
||||||
self.write_debug_gds()
|
self.write_debug_gds()
|
||||||
|
|
||||||
recent_paths.append(self.paths[-1])
|
|
||||||
|
|
||||||
|
|
||||||
def add_supply_rail_target(self, pin_name):
|
def add_supply_rail_target(self, pin_name):
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue