mirror of https://github.com/VLSIDA/OpenRAM.git
Add remove adjacent feature for wide metal spacing
This commit is contained in:
parent
c4163d3401
commit
1344a8f7f1
|
|
@ -30,3 +30,10 @@ class direction(Enum):
|
||||||
debug.error("Invalid direction {}".format(dirct))
|
debug.error("Invalid direction {}".format(dirct))
|
||||||
|
|
||||||
return offset
|
return offset
|
||||||
|
|
||||||
|
def cardinal_directions():
|
||||||
|
return [direction.NORTH, direction.EAST, direction.SOUTH, direction.WEST]
|
||||||
|
|
||||||
|
def cardinal_offsets():
|
||||||
|
return [direction.get_offset(d) for d in direction.cardinal_directions()]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -172,20 +172,7 @@ class grid_path:
|
||||||
return neighbors
|
return neighbors
|
||||||
|
|
||||||
def neighbor(self, d):
|
def neighbor(self, d):
|
||||||
if d==direction.EAST:
|
offset = direction.get_offset(d)
|
||||||
offset = vector3d(1,0,0)
|
|
||||||
elif d==direction.WEST:
|
|
||||||
offset = vector3d(-1,0,0)
|
|
||||||
elif d==direction.NORTH:
|
|
||||||
offset = vector3d(0,1,0)
|
|
||||||
elif d==direction.SOUTH:
|
|
||||||
offset = vector3d(0,-1,0)
|
|
||||||
elif d==direction.UP:
|
|
||||||
offset = vector3d(0,0,1)
|
|
||||||
elif d==direction.DOWN:
|
|
||||||
offset = vector3d(0,0,-1)
|
|
||||||
else:
|
|
||||||
debug.error("Invalid direction {}".format(d),-1)
|
|
||||||
|
|
||||||
newwave = [point + offset for point in self.pathlist[-1]]
|
newwave = [point + offset for point in self.pathlist[-1]]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,9 @@ class pin_group:
|
||||||
self.name = name
|
self.name = name
|
||||||
# Flag for when it is routed
|
# Flag for when it is routed
|
||||||
self.routed = False
|
self.routed = False
|
||||||
|
# Flag for when it is enclosed
|
||||||
|
self.enclosed = False
|
||||||
|
|
||||||
# This is a list because we can have a pin group of disconnected sets of pins
|
# This is a list because we can have a pin group of disconnected sets of pins
|
||||||
# and these are represented by separate lists
|
# and these are represented by separate lists
|
||||||
if pin_shapes:
|
if pin_shapes:
|
||||||
|
|
@ -25,10 +28,40 @@ class pin_group:
|
||||||
self.router = router
|
self.router = router
|
||||||
# These are the corresponding pin grids for each pin group.
|
# These are the corresponding pin grids for each pin group.
|
||||||
self.grids = set()
|
self.grids = set()
|
||||||
|
# These are the secondary grids that could or could not be part of the pin
|
||||||
|
self.secondary_grids = set()
|
||||||
|
|
||||||
# The corresponding set of partially blocked grids for each pin group.
|
# The corresponding set of partially blocked grids for each pin group.
|
||||||
# These are blockages for other nets but unblocked for routing this group.
|
# These are blockages for other nets but unblocked for routing this group.
|
||||||
self.blockages = set()
|
self.blockages = set()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
""" override print function output """
|
||||||
|
total_string = "(pg {} ".format(self.name)
|
||||||
|
|
||||||
|
pin_string = "\n pins={}".format(self.pins)
|
||||||
|
total_string += pin_string
|
||||||
|
|
||||||
|
grids_string = "\n grids={}".format(self.grids)
|
||||||
|
total_string += grids_string
|
||||||
|
|
||||||
|
grids_string = "\n secondary={}".format(self.secondary_grids)
|
||||||
|
total_string += grids_string
|
||||||
|
|
||||||
|
if self.enclosed:
|
||||||
|
enlosure_string = "\n enclose={}".format(self.enclosures)
|
||||||
|
total_string += enclosure_string
|
||||||
|
|
||||||
|
total_string += ")"
|
||||||
|
return total_string
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
""" override repr function output """
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
def size(self):
|
||||||
|
return len(self.grids)
|
||||||
|
|
||||||
def set_routed(self, value=True):
|
def set_routed(self, value=True):
|
||||||
self.routed = value
|
self.routed = value
|
||||||
|
|
||||||
|
|
@ -277,22 +310,41 @@ class pin_group:
|
||||||
this will find the smallest rectangle enclosure that overlaps with any pin.
|
this will find the smallest rectangle enclosure that overlaps with any pin.
|
||||||
If there is not, it simply returns all the enclosures.
|
If there is not, it simply returns all the enclosures.
|
||||||
"""
|
"""
|
||||||
|
self.enclosed = True
|
||||||
|
|
||||||
# Compute the enclosure pin_layout list of the set of tracks
|
# Compute the enclosure pin_layout list of the set of tracks
|
||||||
self.enclosures = self.compute_enclosures()
|
self.enclosures = self.compute_enclosures()
|
||||||
|
|
||||||
# A single set of connected pins is easy, so use the optimized set
|
# A single set of connected pins is easy, so use the optimized set
|
||||||
if len(self.pins)==1:
|
# if len(self.pins)==1:
|
||||||
enclosure_list = self.enclosures
|
# enclosure_list = self.enclosures
|
||||||
smallest = self.find_smallest_overlapping(self.pins[0],enclosure_list)
|
# smallest = self.find_smallest_overlapping(self.pins[0],enclosure_list)
|
||||||
if smallest:
|
# if smallest:
|
||||||
self.enclosures=[smallest]
|
# self.enclosures=[smallest]
|
||||||
|
|
||||||
debug.info(2,"Computed enclosure(s) {0}\n {1}\n {2}\n {3}".format(self.name,
|
# Save the list of all grids
|
||||||
|
#self.all_grids = self.grids.copy()
|
||||||
|
|
||||||
|
# Remove the grids that are not covered by the enclosures
|
||||||
|
# FIXME: We could probably just store what grids each enclosure overlaps when
|
||||||
|
# it was created.
|
||||||
|
#for enclosure in self.enclosures:
|
||||||
|
# enclosure_in_tracks=router.convert_pin_to_tracks(self.name, enclosure)
|
||||||
|
# self.grids.difference_update(enclosure_in_tracks)
|
||||||
|
|
||||||
|
debug.info(3,"Computed enclosure(s) {0}\n {1}\n {2}\n {3}".format(self.name,
|
||||||
self.pins,
|
self.pins,
|
||||||
self.grids,
|
self.grids,
|
||||||
self.enclosures))
|
self.enclosures))
|
||||||
|
|
||||||
|
def combine_pins(self, pg1, pg2):
|
||||||
|
"""
|
||||||
|
Combine two pin groups into one.
|
||||||
|
"""
|
||||||
|
self.pins = [*pg1.pins, *pg2.pins] # Join the two lists of pins
|
||||||
|
self.grids = pg1.grids | pg2.grids # OR the set of grid locations
|
||||||
|
self.secondary_grids = pg1.secondary_grids | pg2.secondary_grids
|
||||||
|
|
||||||
def add_enclosure(self, cell):
|
def add_enclosure(self, cell):
|
||||||
"""
|
"""
|
||||||
Add the enclosure shape to the given cell.
|
Add the enclosure shape to the given cell.
|
||||||
|
|
@ -305,23 +357,57 @@ class pin_group:
|
||||||
height=enclosure.height())
|
height=enclosure.height())
|
||||||
|
|
||||||
|
|
||||||
|
def perimeter_grids(self):
|
||||||
|
"""
|
||||||
|
Return a list of the grids on the perimeter.
|
||||||
|
This assumes that we have a single contiguous shape.
|
||||||
|
"""
|
||||||
|
perimeter_set = set()
|
||||||
|
cardinal_offsets = direction.cardinal_offsets()
|
||||||
|
for g1 in self.grids:
|
||||||
|
neighbor_grids = [g1 + offset for offset in cardinal_offsets]
|
||||||
|
neighbor_count = sum([x in self.grids for x in neighbor_grids])
|
||||||
|
# If we aren't completely enclosed, we are on the perimeter
|
||||||
|
if neighbor_count < 4:
|
||||||
|
perimeter_set.add(g1)
|
||||||
|
|
||||||
|
return perimeter_set
|
||||||
|
|
||||||
def adjacent(self, other):
|
def adjacent(self, other):
|
||||||
"""
|
"""
|
||||||
Chck if the two pin groups have at least one adjacent pin grid.
|
Chck if the two pin groups have at least one adjacent pin grid.
|
||||||
"""
|
"""
|
||||||
# We could optimize this to just check the boundaries
|
# We could optimize this to just check the boundaries
|
||||||
for g1 in self.grids:
|
for g1 in self.perimeter_grids():
|
||||||
for g2 in other.grids:
|
for g2 in other.perimeter_grids():
|
||||||
if g1.adjacent(g2):
|
if g1.adjacent(g2):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def adjacent_grids(self, other, separation):
|
||||||
|
"""
|
||||||
|
Determine the sets of grids that are within a separation distance
|
||||||
|
of any grid in the other set.
|
||||||
|
"""
|
||||||
|
# We could optimize this to just check the boundaries
|
||||||
|
g1_grids = set()
|
||||||
|
g2_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)
|
||||||
|
|
||||||
|
return g1_grids,g2_grids
|
||||||
|
|
||||||
def convert_pin(self, router):
|
def convert_pin(self, router):
|
||||||
#print("PG ",pg)
|
"""
|
||||||
# Keep the same groups for each pin
|
Convert the list of pin shapes into sets of routing grids.
|
||||||
|
The secondary set of grids are "optional" pin shapes that could be
|
||||||
|
should be either blocked or part of the pin.
|
||||||
|
"""
|
||||||
pin_set = set()
|
pin_set = set()
|
||||||
blockage_set = set()
|
blockage_set = set()
|
||||||
|
|
||||||
|
|
@ -334,19 +420,6 @@ class pin_group:
|
||||||
# Blockages will be a super-set of pins since it uses the inflated pin shape.
|
# Blockages will be a super-set of pins since it uses the inflated pin shape.
|
||||||
blockage_in_tracks = router.convert_blockage(pin)
|
blockage_in_tracks = router.convert_blockage(pin)
|
||||||
blockage_set.update(blockage_in_tracks)
|
blockage_set.update(blockage_in_tracks)
|
||||||
|
|
||||||
# If we have a blockage, we must remove the grids
|
|
||||||
# Remember, this excludes the pin blockages already
|
|
||||||
shared_set = pin_set & router.blocked_grids
|
|
||||||
if len(shared_set)>0:
|
|
||||||
debug.info(2,"Removing pins {}".format(shared_set))
|
|
||||||
shared_set = blockage_set & router.blocked_grids
|
|
||||||
if len(shared_set)>0:
|
|
||||||
debug.info(2,"Removing blocks {}".format(shared_set))
|
|
||||||
pin_set.difference_update(router.blocked_grids)
|
|
||||||
blockage_set.difference_update(router.blocked_grids)
|
|
||||||
debug.info(2," pins {}".format(pin_set))
|
|
||||||
debug.info(2," blocks {}".format(blockage_set))
|
|
||||||
|
|
||||||
# At least one of the groups must have some valid tracks
|
# 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(blockage_set)==0):
|
||||||
|
|
@ -355,14 +428,9 @@ class pin_group:
|
||||||
|
|
||||||
# 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.grids = pin_set | blockage_set
|
self.grids = pin_set | blockage_set
|
||||||
|
# Remember the secondary grids for removing adjacent pins in wide metal spacing
|
||||||
|
self.secondary_grids = blockage_set - pin_set
|
||||||
|
|
||||||
# Add all of the partial blocked grids to the set for the design
|
debug.info(2," pins {}".format(self.grids))
|
||||||
# if they are not blocked by other metal
|
debug.info(2," secondary {}".format(self.secondary_grids))
|
||||||
#partial_set = blockage_set - pin_set
|
|
||||||
#self.blockages = partial_set
|
|
||||||
|
|
||||||
# We should not have added the pins to the blockages,
|
|
||||||
# but remove them just in case
|
|
||||||
# Partial set may still be in the blockages if there were
|
|
||||||
# other shapes disconnected from the pins that were also overlapping
|
|
||||||
#route.blocked_grids.difference_update(pin_set)
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@ class router(router_tech):
|
||||||
self.all_pins = set()
|
self.all_pins = set()
|
||||||
|
|
||||||
# A map of pin names to a list of pin groups
|
# 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 = {}
|
||||||
|
|
||||||
### The blockage data structures
|
### The blockage data structures
|
||||||
|
|
@ -157,10 +156,14 @@ class router(router_tech):
|
||||||
#self.write_debug_gds("debug_combine_pins.gds",stop_program=True)
|
#self.write_debug_gds("debug_combine_pins.gds",stop_program=True)
|
||||||
|
|
||||||
# Separate any adjacent grids of differing net names to prevent wide metal DRC violations
|
# Separate any adjacent grids of differing net names to prevent wide metal DRC violations
|
||||||
self.separate_adjacent_pins(pin)
|
# Must be done before enclosing pins
|
||||||
|
self.separate_adjacent_pins(self.supply_rail_space_width)
|
||||||
|
# For debug
|
||||||
|
#self.separate_adjacent_pins(1)
|
||||||
|
|
||||||
# Enclose the continguous grid units in a metal rectangle to fix some DRCs
|
# Enclose the continguous grid units in a metal rectangle to fix some DRCs
|
||||||
self.enclose_pins()
|
self.enclose_pins()
|
||||||
|
#self.write_debug_gds("debug_enclose_pins.gds",stop_program=True)
|
||||||
|
|
||||||
|
|
||||||
def combine_adjacent_pins_pass(self, pin_name):
|
def combine_adjacent_pins_pass(self, pin_name):
|
||||||
|
|
@ -191,13 +194,13 @@ class router(router_tech):
|
||||||
# Combine if at least 1 grid cell is adjacent
|
# Combine if at least 1 grid cell is adjacent
|
||||||
if pg1.adjacent(pg2):
|
if pg1.adjacent(pg2):
|
||||||
combined = pin_group(pin_name, [], self)
|
combined = pin_group(pin_name, [], self)
|
||||||
combined.pins = [*pg1.pins, *pg2.pins] # Join the two lists of pins
|
combined.combine_pins(pg1, pg2)
|
||||||
combined.grids = pg1.grids | pg2.grids # OR the set of grid locations
|
debug.info(2,"Combining {0} {1} {2}:".format(pin_name, index1, index2))
|
||||||
debug.info(2,"Combining {0}:\n {1}\n {2}".format(pin_name, pg1.pins, pg2.pins))
|
debug.info(2, " {0}\n {1}".format(pg1.pins, pg2.pins))
|
||||||
debug.info(2," --> {0}\n {1}\n".format(combined.pins,combined.grids))
|
debug.info(2," --> {0}\n {1}".format(combined.pins,combined.grids))
|
||||||
remove_indices.update([index1,index2])
|
remove_indices.update([index1,index2])
|
||||||
pin_groups.append(combined)
|
pin_groups.append(combined)
|
||||||
|
break
|
||||||
|
|
||||||
# Remove them in decreasing order to not invalidate the indices
|
# Remove them in decreasing order to not invalidate the indices
|
||||||
debug.info(2,"Removing {}".format(sorted(remove_indices)))
|
debug.info(2,"Removing {}".format(sorted(remove_indices)))
|
||||||
|
|
@ -207,7 +210,7 @@ class router(router_tech):
|
||||||
# Use the new pin group!
|
# Use the new pin group!
|
||||||
self.pin_groups[pin_name] = pin_groups
|
self.pin_groups[pin_name] = pin_groups
|
||||||
|
|
||||||
removed_pairs = len(remove_indices)/2
|
removed_pairs = int(len(remove_indices)/2)
|
||||||
debug.info(1, "Combined {0} pin pairs for {1}".format(removed_pairs,pin_name))
|
debug.info(1, "Combined {0} pin pairs for {1}".format(removed_pairs,pin_name))
|
||||||
|
|
||||||
return removed_pairs
|
return removed_pairs
|
||||||
|
|
@ -229,17 +232,77 @@ class router(router_tech):
|
||||||
else:
|
else:
|
||||||
debug.warning("Did not converge combining adjacent pins in supply router.")
|
debug.warning("Did not converge combining adjacent pins in supply router.")
|
||||||
|
|
||||||
def separate_adjacent_pins(self, pin_name, separation=1):
|
def separate_adjacent_pins(self, separation):
|
||||||
"""
|
"""
|
||||||
This will try to separate all grid pins by the supplied number of separation
|
This will try to separate all grid pins by the supplied number of separation
|
||||||
tracks (default is to prevent adjacency).
|
tracks (default is to prevent adjacency).
|
||||||
|
"""
|
||||||
|
# Commented out to debug with SCMOS
|
||||||
|
#if separation==0:
|
||||||
|
# return
|
||||||
|
|
||||||
|
pin_names = self.pin_groups.keys()
|
||||||
|
for pin_name1 in pin_names:
|
||||||
|
for pin_name2 in pin_names:
|
||||||
|
if pin_name1==pin_name2:
|
||||||
|
continue
|
||||||
|
self.separate_adjacent_pin(pin_name1, pin_name2, separation)
|
||||||
|
|
||||||
|
def separate_adjacent_pin(self, pin_name1, pin_name2, separation):
|
||||||
|
"""
|
||||||
Go through all of the pin groups and check if any other pin group is
|
Go through all of the pin groups and check if any other pin group is
|
||||||
within a separation of it.
|
within a separation of it.
|
||||||
If so, reduce the pin group grid to not include the adjacent grid.
|
If so, reduce the pin group grid to not include the adjacent grid.
|
||||||
Try to do this intelligently to keep th pins enclosed.
|
Try to do this intelligently to keep th pins enclosed.
|
||||||
"""
|
"""
|
||||||
pass
|
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]):
|
||||||
|
# FIXME: Use separation distance and edge grids only
|
||||||
|
grids_g1, grids_g2 = pg1.adjacent_grids(pg2, separation)
|
||||||
|
# These should have the same length, so...
|
||||||
|
if len(grids_g1)>0:
|
||||||
|
debug.info(1,"Adjacent grids {0} {1} {2} {3}".format(index1,grids_g1,index2,grids_g2))
|
||||||
|
self.remove_adjacent_grid(pg1, grids_g1, pg2, grids_g2)
|
||||||
|
|
||||||
|
def remove_adjacent_grid(self, pg1, grids1, pg2, grids2):
|
||||||
|
"""
|
||||||
|
Remove one of the adjacent grids in a heuristic manner.
|
||||||
|
"""
|
||||||
|
# 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(1,"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(1,"Removing {} from smaller {}".format(str(smaller_grids), smaller))
|
||||||
|
smaller.grids.difference_update(smaller_grids)
|
||||||
|
self.blocked_grids.update(smaller_grids)
|
||||||
|
return
|
||||||
|
|
||||||
|
# If that fails, just randomly remove from the bigger one and give a warning.
|
||||||
|
# This might fail later.
|
||||||
|
debug.warning("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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def prepare_blockages(self, pin_name):
|
def prepare_blockages(self, pin_name):
|
||||||
"""
|
"""
|
||||||
Reset and add all of the blockages in the design.
|
Reset and add all of the blockages in the design.
|
||||||
|
|
@ -975,6 +1038,8 @@ class router(router_tech):
|
||||||
if show_enclosures:
|
if show_enclosures:
|
||||||
for key in self.pin_groups.keys():
|
for key in self.pin_groups.keys():
|
||||||
for pg in self.pin_groups[key]:
|
for pg in self.pin_groups[key]:
|
||||||
|
if not pg.enclosed:
|
||||||
|
continue
|
||||||
for pin in pg.enclosures:
|
for pin in pg.enclosures:
|
||||||
#print("enclosure: ",pin.name,pin.ll(),pin.width(),pin.height())
|
#print("enclosure: ",pin.name,pin.ll(),pin.width(),pin.height())
|
||||||
self.cell.add_rect(layer="text",
|
self.cell.add_rect(layer="text",
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ class supply_router(router):
|
||||||
# Power rail width in grid units.
|
# Power rail width in grid units.
|
||||||
self.rail_track_width = 2
|
self.rail_track_width = 2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_routing_grid(self):
|
def create_routing_grid(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -69,6 +70,9 @@ class supply_router(router):
|
||||||
# but this is simplest for now.
|
# but this is simplest for now.
|
||||||
self.create_routing_grid()
|
self.create_routing_grid()
|
||||||
|
|
||||||
|
# Compute the grid dimensions
|
||||||
|
self.compute_supply_rail_dimensions()
|
||||||
|
|
||||||
# Get the pin shapes
|
# Get the pin shapes
|
||||||
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
|
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
|
||||||
#self.write_debug_gds("pin_enclosures.gds",stop_program=True)
|
#self.write_debug_gds("pin_enclosures.gds",stop_program=True)
|
||||||
|
|
@ -87,7 +91,7 @@ class supply_router(router):
|
||||||
|
|
||||||
self.route_simple_overlaps(vdd_name)
|
self.route_simple_overlaps(vdd_name)
|
||||||
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=False)
|
||||||
|
|
||||||
# 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
|
||||||
|
|
@ -436,9 +440,6 @@ class supply_router(router):
|
||||||
Must be done with lower left at 0,0
|
Must be done with lower left at 0,0
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Compute the grid dimensions
|
|
||||||
self.compute_supply_rail_dimensions()
|
|
||||||
|
|
||||||
# Compute the grid locations of the supply rails
|
# Compute the grid locations of the supply rails
|
||||||
self.compute_supply_rails(name, supply_number)
|
self.compute_supply_rails(name, supply_number)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,10 @@ class vector3d():
|
||||||
""" Min of both values """
|
""" Min of both values """
|
||||||
return vector3d(min(self.x,other.x),min(self.y,other.y),min(self.z,other.z))
|
return vector3d(min(self.x,other.x),min(self.y,other.y),min(self.z,other.z))
|
||||||
|
|
||||||
|
def distance(self, other):
|
||||||
|
""" Return the planar distance between two values """
|
||||||
|
return abs(self.x-other.x)+abs(self.y-other.y)
|
||||||
|
|
||||||
|
|
||||||
def adjacent(self, other):
|
def adjacent(self, other):
|
||||||
""" Is the one grid adjacent in any planar direction to the other """
|
""" Is the one grid adjacent in any planar direction to the other """
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue