mirror of https://github.com/VLSIDA/OpenRAM.git
Fix instersection bug. Improve primary and secondary pin algo.
This commit is contained in:
parent
7ce75398a8
commit
126d4a8d10
|
|
@ -441,10 +441,10 @@ class pin_layout:
|
|||
"""
|
||||
Given three co-linear points, determine if q lies on segment pr
|
||||
"""
|
||||
if q[0] <= max(p[0], r[0]) and \
|
||||
q[0] >= min(p[0], r[0]) and \
|
||||
q[1] <= max(p[1], r[1]) and \
|
||||
q[1] >= min(p[1], r[1]):
|
||||
if q.x <= max(p.x, r.x) and \
|
||||
q.x >= min(p.x, r.x) and \
|
||||
q.y <= max(p.y, r.y) and \
|
||||
q.y >= min(p.y, r.y):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
|
@ -473,8 +473,8 @@ class pin_layout:
|
|||
x = (b2*c1 - b1*c2)/determinant
|
||||
y = (a1*c2 - a2*c1)/determinant
|
||||
|
||||
r = [x,y]
|
||||
r = vector(x,y).snap_to_grid()
|
||||
if self.on_segment(a, r, b) and self.on_segment(c, r, d):
|
||||
return [x, y]
|
||||
return r
|
||||
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -561,15 +561,13 @@ class pin_group:
|
|||
of any grid in the other set.
|
||||
"""
|
||||
# We could optimize this to just check the boundaries
|
||||
g1_grids = set()
|
||||
g2_grids = set()
|
||||
adj_grids = set()
|
||||
for g1 in self.grids:
|
||||
for g2 in other.grids:
|
||||
if g1.distance(g2) <= separation:
|
||||
g1_grids.add(g1)
|
||||
g2_grids.add(g2)
|
||||
adj_grids.add(g1)
|
||||
|
||||
return g1_grids,g2_grids
|
||||
return adj_grids
|
||||
|
||||
def convert_pin(self):
|
||||
"""
|
||||
|
|
@ -578,14 +576,16 @@ class pin_group:
|
|||
should be either blocked or part of the pin.
|
||||
"""
|
||||
pin_set = set()
|
||||
partial_set = set()
|
||||
blockage_set = set()
|
||||
|
||||
for pin_list in self.pins:
|
||||
for pin in pin_list:
|
||||
debug.info(2," Converting {0}".format(pin))
|
||||
# Determine which tracks the pin overlaps
|
||||
pin_in_tracks=self.router.convert_pin_to_tracks(self.name, pin)
|
||||
pin_set.update(pin_in_tracks)
|
||||
(sufficient,insufficient)=self.router.convert_pin_to_tracks(self.name, pin)
|
||||
pin_set.update(sufficient)
|
||||
partial_set.update(insufficient)
|
||||
|
||||
# Blockages will be a super-set of pins since it uses the inflated pin shape.
|
||||
blockage_in_tracks = self.router.convert_blockage(pin)
|
||||
|
|
@ -597,30 +597,35 @@ class pin_group:
|
|||
if len(shared_set)>0:
|
||||
debug.info(2,"Removing pins {}".format(shared_set))
|
||||
pin_set.difference_update(shared_set)
|
||||
shared_set = partial_set & self.router.blocked_grids
|
||||
if len(shared_set)>0:
|
||||
debug.info(2,"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(2,"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(blockage_set)==0):
|
||||
if (len(pin_set)==0 and len(partial_set)==0 and len(blockage_set)==0):
|
||||
#debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins))
|
||||
|
||||
for pin_list in self.pins:
|
||||
for pin in pin_list:
|
||||
debug.warning(" Expanding conversion {0}".format(pin))
|
||||
# Determine which tracks the pin overlaps
|
||||
pin_in_tracks=self.router.convert_pin_to_tracks(self.name, pin, expansion=1)
|
||||
pin_set.update(pin_in_tracks)
|
||||
(sufficient,insufficient)=self.router.convert_pin_to_tracks(self.name, pin, expansion=1)
|
||||
pin_set.update(sufficient)
|
||||
partial_set.update(insufficient)
|
||||
|
||||
if len(pin_set)==0:
|
||||
if len(pin_set)==0 and len(partial_set)==0:
|
||||
debug.error("Unable to find unblocked pin {} {}".format(self.name, self.pins))
|
||||
self.router.write_debug_gds("blocked_pin.gds")
|
||||
|
||||
# We need to route each of the components, so don't combine the groups
|
||||
self.grids = pin_set
|
||||
# Remember the secondary grids for removing adjacent pins in wide metal spacing
|
||||
self.secondary_grids = blockage_set - pin_set
|
||||
# Consider all the grids that would be blocked
|
||||
self.grids = pin_set | partial_set
|
||||
# Remember the secondary grids for removing adjacent pins
|
||||
self.secondary_grids = partial_set
|
||||
|
||||
debug.info(2," pins {}".format(self.grids))
|
||||
debug.info(2," secondary {}".format(self.secondary_grids))
|
||||
|
|
|
|||
|
|
@ -279,48 +279,55 @@ class router(router_tech):
|
|||
debug.info(1,"Comparing {0} and {1} adjacency".format(pin_name1, pin_name2))
|
||||
for index1,pg1 in enumerate(self.pin_groups[pin_name1]):
|
||||
for index2,pg2 in enumerate(self.pin_groups[pin_name2]):
|
||||
# FIgXME: Use separation distance and edge grids only
|
||||
grids_g1, grids_g2 = pg1.adjacent_grids(pg2, separation)
|
||||
adj_grids = pg1.adjacent_grids(pg2, separation)
|
||||
# These should have the same length, so...
|
||||
if len(grids_g1)>0:
|
||||
debug.info(3,"Adjacent grids {0} {1} {2} {3}".format(index1,grids_g1,index2,grids_g2))
|
||||
self.remove_adjacent_grid(pg1, grids_g1, pg2, grids_g2)
|
||||
if len(adj_grids)>0:
|
||||
debug.info(2,"Adjacent grids {0} {1} adj={2}".format(index1,index2,adj_grids))
|
||||
self.remove_adjacent_grid(pg1, pg2, adj_grids)
|
||||
|
||||
def remove_adjacent_grid(self, pg1, grids1, pg2, grids2):
|
||||
def remove_adjacent_grid(self, pg1, pg2, adj_grids):
|
||||
"""
|
||||
Remove one of the adjacent grids in a heuristic manner.
|
||||
This will try to keep the groups similar sized by removing from the bigger group.
|
||||
"""
|
||||
# Determine the bigger and smaller group
|
||||
|
||||
if pg1.size()>pg2.size():
|
||||
bigger = pg1
|
||||
bigger_grids = grids1
|
||||
smaller = pg2
|
||||
smaller_grids = grids2
|
||||
else:
|
||||
bigger = pg2
|
||||
bigger_grids = grids2
|
||||
smaller = pg1
|
||||
smaller_grids = grids1
|
||||
|
||||
# First, see if we can remove grids that are in the secondary grids
|
||||
# i.e. they aren't necessary to the pin grids
|
||||
if bigger_grids.issubset(bigger.secondary_grids):
|
||||
debug.info(3,"Removing {} from bigger {}".format(str(bigger_grids), bigger))
|
||||
bigger.grids.difference_update(bigger_grids)
|
||||
self.blocked_grids.update(bigger_grids)
|
||||
return
|
||||
elif smaller_grids.issubset(smaller.secondary_grids):
|
||||
debug.info(3,"Removing {} from smaller {}".format(str(smaller_grids), smaller))
|
||||
smaller.grids.difference_update(smaller_grids)
|
||||
self.blocked_grids.update(smaller_grids)
|
||||
return
|
||||
for adj in adj_grids:
|
||||
|
||||
# If that fails, just randomly remove from the bigger one and give a warning.
|
||||
# This might fail later.
|
||||
debug.info(1,"Removing arbitrary grids from a pin group {} {}".format(bigger, bigger_grids))
|
||||
debug.check(len(bigger.grids)>len(bigger_grids),"Zero size pin group after adjacency removal {} {}".format(bigger, bigger_grids))
|
||||
bigger.grids.difference_update(bigger_grids)
|
||||
self.blocked_grids.update(bigger_grids)
|
||||
|
||||
# If the adjacent grids are a subset of the secondary grids (i.e. not necessary)
|
||||
# remove them from each
|
||||
removed_flag = False
|
||||
if adj in bigger.secondary_grids:
|
||||
debug.info(2,"Removing {} from bigger secondary {}".format(adj, bigger))
|
||||
bigger.grids.remove(adj)
|
||||
bigger.secondary_grids.remove(adj)
|
||||
self.blocked_grids.add(adj)
|
||||
removed_flag=True
|
||||
|
||||
if adj in smaller.secondary_grids:
|
||||
debug.info(2,"Removing {} from smaller secondary {}".format(adj, smaller))
|
||||
smaller.gris.remove(adj)
|
||||
secondary.secondary_grids.remove(adj)
|
||||
self.blocked_grids.add(adj)
|
||||
removed_flag=True
|
||||
|
||||
# If we couldn't remove from a secondary grid, we must remove from the primary
|
||||
# grid of at least one pin
|
||||
if not removed_flag:
|
||||
if adj in bigger.grids:
|
||||
debug.info(2,"Removing {} from bigger primary {}".format(adj, bigger))
|
||||
bigger.grids.remove(adj)
|
||||
elif adj in smaller.grids:
|
||||
debug.info(2,"Removing {} from smaller primary {}".format(adj, smaller))
|
||||
smaller.grids.remove(adj)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -523,31 +530,16 @@ class router(router_tech):
|
|||
zindex=self.get_zindex(pin.layer_num)
|
||||
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,zindex))
|
||||
(full_overlap, partial_overlap) = self.convert_pin_coord_to_tracks(pin, vector3d(x,y,zindex))
|
||||
if full_overlap:
|
||||
sufficient_list.update([full_overlap])
|
||||
if partial_overlap:
|
||||
insufficient_list.update([partial_overlap])
|
||||
debug.info(2,"Converting [ {0} , {1} ] full={2} partial={3}".format(x,y, full_overlap, partial_overlap))
|
||||
debug.info(2,"Converting [ {0} , {1} ] full={2}".format(x,y, full_overlap))
|
||||
|
||||
# Return all grids with any potential overlap (sufficient or not)
|
||||
return sufficient_list|insufficient_list
|
||||
return (sufficient_list,insufficient_list)
|
||||
|
||||
# # Remove the blocked grids
|
||||
# sufficient_list.difference_update(self.blocked_grids)
|
||||
# insufficient_list.difference_update(self.blocked_grids)
|
||||
|
||||
# if len(sufficient_list)>0:
|
||||
# return sufficient_list
|
||||
# elif expansion==0 and len(insufficient_list)>0:
|
||||
# best_pin = self.get_all_offgrid_pin(pin, insufficient_list)
|
||||
# #print(best_pin)
|
||||
# return best_pin
|
||||
# elif expansion>0:
|
||||
# nearest_pin = self.get_furthest_offgrid_pin(pin, insufficient_list)
|
||||
# return nearest_pin
|
||||
# else:
|
||||
# return set()
|
||||
|
||||
def get_all_offgrid_pin(self, pin, insufficient_list):
|
||||
"""
|
||||
|
|
@ -623,47 +615,34 @@ class router(router_tech):
|
|||
return set([best_coord])
|
||||
|
||||
|
||||
def convert_pin_coord_to_minimal_tracks(self, pin, coord):
|
||||
"""
|
||||
Given a pin and a track coordinate, determine if the pin overlaps enough.
|
||||
If it does, add additional metal to make the pin "on grid".
|
||||
If it doesn't, add it to the blocked grid list.
|
||||
"""
|
||||
|
||||
(width, spacing) = self.get_layer_width_space(coord.z)
|
||||
|
||||
# This is the rectangle if we put a pin in the center of the track
|
||||
track_pin = self.convert_track_to_pin(coord)
|
||||
overlap_length = pin.overlap_length(track_pin)
|
||||
|
||||
debug.info(3,"Check overlap: {0} {1} . {2} = {3}".format(coord, pin.rect, track_pin, overlap_length))
|
||||
# If it overlaps by more than the min width DRC, we can just use the track
|
||||
if overlap_length==math.inf or snap_val_to_grid(overlap_length) >= snap_val_to_grid(width):
|
||||
debug.info(3," Overlap: {0} >? {1}".format(overlap_length,spacing))
|
||||
return (coord, None)
|
||||
# Otherwise, keep track of the partial overlap grids in case we need to patch it later.
|
||||
else:
|
||||
debug.info(3," Partial/no overlap: {0} >? {1}".format(overlap_length,spacing))
|
||||
return (None, coord)
|
||||
|
||||
def convert_pin_coord_to_tracks(self, pin, coord):
|
||||
"""
|
||||
Return all tracks that an inflated pin overlaps
|
||||
"""
|
||||
|
||||
# This is the rectangle if we put a pin in the center of the track
|
||||
track_pin = self.convert_track_to_inflated_pin(coord)
|
||||
overlap_length = pin.overlap_length(track_pin)
|
||||
# This is using the full track shape rather than a single track pin shape
|
||||
# because we will later patch a connector if there isn't overlap.
|
||||
track_pin = self.convert_track_to_shape_pin(coord)
|
||||
|
||||
# This is the normal pin inflated by a minimum design rule
|
||||
inflated_pin = pin_layout(pin.name, pin.inflate(0.5*self.track_space), pin.layer)
|
||||
|
||||
debug.info(3,"Check overlap: {0} {1} . {2} = {3}".format(coord, pin.rect, track_pin, overlap_length))
|
||||
# If it overlaps by more than the min width DRC, we can just use the track
|
||||
if overlap_length==math.inf or snap_val_to_grid(overlap_length) > 0:
|
||||
debug.info(3," Overlap: {0} >? {1}".format(overlap_length,0))
|
||||
return (coord, None)
|
||||
# Otherwise, keep track of the partial overlap grids in case we need to patch it later.
|
||||
overlap_length = pin.overlap_length(track_pin)
|
||||
debug.info(2,"Check overlap: {0} {1} . {2} = {3}".format(coord, pin.rect, track_pin, overlap_length))
|
||||
inflated_overlap_length = inflated_pin.overlap_length(track_pin)
|
||||
debug.info(2,"Check overlap: {0} {1} . {2} = {3}".format(coord, inflated_pin.rect, track_pin, inflated_overlap_length))
|
||||
|
||||
# If it overlaps with the pin, it is sufficient
|
||||
if overlap_length==math.inf or overlap_length > 0:
|
||||
debug.info(2," Overlap: {0} >? {1}".format(overlap_length,0))
|
||||
return (coord,None)
|
||||
# If it overlaps with the inflated pin, it is partial
|
||||
elif inflated_overlap_length==math.inf or inflated_overlap_length > 0:
|
||||
debug.info(2," Partial overlap: {0} >? {1}".format(inflated_overlap_length,0))
|
||||
return (None,coord)
|
||||
else:
|
||||
debug.info(3," Partial/no overlap: {0} >? {1}".format(overlap_length,0))
|
||||
return (None, coord)
|
||||
debug.info(2," No overlap: {0} {1}".format(overlap_length,0))
|
||||
return (None,None)
|
||||
|
||||
|
||||
|
||||
|
|
@ -688,6 +667,21 @@ class router(router_tech):
|
|||
p = pin_layout("", [ll, ur], self.get_layer(track[2]))
|
||||
return p
|
||||
|
||||
def convert_track_to_shape_pin(self, track):
|
||||
"""
|
||||
Convert a grid point into a rectangle shape that occupies the entire centered
|
||||
track.
|
||||
"""
|
||||
# to scale coordinates to tracks
|
||||
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))
|
||||
|
||||
p = pin_layout("", [ll, ur], self.get_layer(track[2]))
|
||||
return p
|
||||
|
||||
def convert_track_to_shape(self, track):
|
||||
"""
|
||||
Convert a grid point into a rectangle shape that occupies the entire centered
|
||||
|
|
@ -701,7 +695,7 @@ class router(router_tech):
|
|||
ur = snap_to_grid(ll + vector(self.track_width,self.track_width))
|
||||
|
||||
return [ll,ur]
|
||||
|
||||
|
||||
def convert_track_to_inflated_pin(self, track):
|
||||
"""
|
||||
Convert a grid point into a rectangle shape that is inflated by a half DRC space.
|
||||
|
|
|
|||
Loading…
Reference in New Issue