mirror of https://github.com/VLSIDA/OpenRAM.git
PEP8 formatting
This commit is contained in:
parent
a2422cc8d4
commit
0dea153919
|
|
@ -7,12 +7,10 @@
|
||||||
#
|
#
|
||||||
from direction import direction
|
from direction import direction
|
||||||
from pin_layout import pin_layout
|
from pin_layout import pin_layout
|
||||||
from vector3d import vector3d
|
|
||||||
from vector import vector
|
from vector import vector
|
||||||
import grid_utils
|
|
||||||
from tech import drc
|
|
||||||
import debug
|
import debug
|
||||||
|
|
||||||
|
|
||||||
class pin_group:
|
class pin_group:
|
||||||
"""
|
"""
|
||||||
A class to represent a group of rectangular design pin.
|
A class to represent a group of rectangular design pin.
|
||||||
|
|
@ -30,19 +28,22 @@ class pin_group:
|
||||||
# Remove any redundant pins (i.e. contained in other pins)
|
# Remove any redundant pins (i.e. contained in other pins)
|
||||||
irredundant_pin_set = self.remove_redundant_shapes(list(pin_set))
|
irredundant_pin_set = self.remove_redundant_shapes(list(pin_set))
|
||||||
|
|
||||||
# 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
|
||||||
self.pins = set(irredundant_pin_set)
|
self.pins = set(irredundant_pin_set)
|
||||||
|
|
||||||
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
|
# These are the secondary grids that could
|
||||||
|
# or could not be part of the pin
|
||||||
self.secondary_grids = set()
|
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
|
||||||
# These are also blockages if we used a simple enclosure to route to a rail.
|
# for routing this group. These are also blockages if we
|
||||||
|
# used a simple enclosure to route to a rail.
|
||||||
self.blockages = set()
|
self.blockages = set()
|
||||||
|
|
||||||
# This is a set of pin_layout shapes to cover the grids
|
# This is a set of pin_layout shapes to cover the grids
|
||||||
|
|
@ -101,7 +102,8 @@ class pin_group:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for index2, pin2 in enumerate(pin_list):
|
for index2, pin2 in enumerate(pin_list):
|
||||||
# Can't contain yourself, but compare the indices and not the pins
|
# Can't contain yourself,
|
||||||
|
# but compare the indices and not the pins
|
||||||
# so you can remove duplicate copies.
|
# so you can remove duplicate copies.
|
||||||
if index1 == index2:
|
if index1 == index2:
|
||||||
continue
|
continue
|
||||||
|
|
@ -130,15 +132,18 @@ class pin_group:
|
||||||
# Enumerate every possible enclosure
|
# Enumerate every possible enclosure
|
||||||
pin_list = []
|
pin_list = []
|
||||||
for seed in self.grids:
|
for seed in self.grids:
|
||||||
(ll, ur) = self.enclose_pin_grids(seed, direction.NORTH, direction.EAST)
|
(ll, ur) = self.enclose_pin_grids(seed,
|
||||||
|
direction.NORTH,
|
||||||
|
direction.EAST)
|
||||||
enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z)
|
enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z)
|
||||||
pin_list.append(enclosure)
|
pin_list.append(enclosure)
|
||||||
|
|
||||||
(ll, ur) = self.enclose_pin_grids(seed, direction.EAST, direction.NORTH)
|
(ll, ur) = self.enclose_pin_grids(seed,
|
||||||
|
direction.EAST,
|
||||||
|
direction.NORTH)
|
||||||
enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z)
|
enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z)
|
||||||
pin_list.append(enclosure)
|
pin_list.append(enclosure)
|
||||||
|
|
||||||
|
|
||||||
# Now simplify the enclosure list
|
# Now simplify the enclosure list
|
||||||
new_pin_list = self.remove_redundant_shapes(pin_list)
|
new_pin_list = self.remove_redundant_shapes(pin_list)
|
||||||
|
|
||||||
|
|
@ -154,7 +159,7 @@ class pin_group:
|
||||||
plc = pin.lc()
|
plc = pin.lc()
|
||||||
prc = pin.rc()
|
prc = pin.rc()
|
||||||
elc = enclosure.lc()
|
elc = enclosure.lc()
|
||||||
erc = enclosure.rc()
|
# erc = enclosure.rc()
|
||||||
ymin = min(plc.y, elc.y)
|
ymin = min(plc.y, elc.y)
|
||||||
ymax = max(plc.y, elc.y)
|
ymax = max(plc.y, elc.y)
|
||||||
ll = vector(plc.x, ymin)
|
ll = vector(plc.x, ymin)
|
||||||
|
|
@ -164,7 +169,7 @@ class pin_group:
|
||||||
pbc = pin.bc()
|
pbc = pin.bc()
|
||||||
puc = pin.uc()
|
puc = pin.uc()
|
||||||
ebc = enclosure.bc()
|
ebc = enclosure.bc()
|
||||||
euc = enclosure.uc()
|
# euc = enclosure.uc()
|
||||||
xmin = min(pbc.x, ebc.x)
|
xmin = min(pbc.x, ebc.x)
|
||||||
xmax = max(pbc.x, ebc.x)
|
xmax = max(pbc.x, ebc.x)
|
||||||
ll = vector(xmin, pbc.y)
|
ll = vector(xmin, pbc.y)
|
||||||
|
|
@ -208,7 +213,7 @@ class pin_group:
|
||||||
break
|
break
|
||||||
|
|
||||||
# There was nothing
|
# There was nothing
|
||||||
if above_item==None:
|
if not above_item:
|
||||||
return None
|
return None
|
||||||
# If it already overlaps, no connector needed
|
# If it already overlaps, no connector needed
|
||||||
if above_item.overlaps(pin):
|
if above_item.overlaps(pin):
|
||||||
|
|
@ -241,7 +246,7 @@ class pin_group:
|
||||||
break
|
break
|
||||||
|
|
||||||
# There was nothing to the left
|
# There was nothing to the left
|
||||||
if bottom_item==None:
|
if not bottom_item:
|
||||||
return None
|
return None
|
||||||
# If it already overlaps, no connector needed
|
# If it already overlaps, no connector needed
|
||||||
if bottom_item.overlaps(pin):
|
if bottom_item.overlaps(pin):
|
||||||
|
|
@ -274,7 +279,7 @@ class pin_group:
|
||||||
break
|
break
|
||||||
|
|
||||||
# There was nothing to the left
|
# There was nothing to the left
|
||||||
if left_item==None:
|
if not left_item:
|
||||||
return None
|
return None
|
||||||
# If it already overlaps, no connector needed
|
# If it already overlaps, no connector needed
|
||||||
if left_item.overlaps(pin):
|
if left_item.overlaps(pin):
|
||||||
|
|
@ -307,7 +312,7 @@ class pin_group:
|
||||||
break
|
break
|
||||||
|
|
||||||
# There was nothing to the right
|
# There was nothing to the right
|
||||||
if right_item==None:
|
if not right_item:
|
||||||
return None
|
return None
|
||||||
# If it already overlaps, no connector needed
|
# If it already overlaps, no connector needed
|
||||||
if right_item.overlaps(pin):
|
if right_item.overlaps(pin):
|
||||||
|
|
@ -319,14 +324,15 @@ class pin_group:
|
||||||
|
|
||||||
def find_smallest_connector(self, pin_list, shape_list):
|
def find_smallest_connector(self, pin_list, shape_list):
|
||||||
"""
|
"""
|
||||||
Compute all of the connectors between the overlapping pins and enclosure shape list..
|
Compute all of the connectors between the overlapping
|
||||||
|
pins and enclosure shape list.
|
||||||
Return the smallest.
|
Return the smallest.
|
||||||
"""
|
"""
|
||||||
smallest = None
|
smallest = None
|
||||||
for pin in pin_list:
|
for pin in pin_list:
|
||||||
for enclosure in shape_list:
|
for enclosure in shape_list:
|
||||||
new_enclosure = self.compute_connector(pin, enclosure)
|
new_enclosure = self.compute_connector(pin, enclosure)
|
||||||
if smallest == None or new_enclosure.area()<smallest.area():
|
if not smallest or new_enclosure.area() < smallest.area():
|
||||||
smallest = new_enclosure
|
smallest = new_enclosure
|
||||||
|
|
||||||
return smallest
|
return smallest
|
||||||
|
|
@ -341,13 +347,12 @@ class pin_group:
|
||||||
for pin in pin_list:
|
for pin in pin_list:
|
||||||
overlap_shape = self.find_smallest_overlapping_pin(pin, shape_list)
|
overlap_shape = self.find_smallest_overlapping_pin(pin, shape_list)
|
||||||
if overlap_shape:
|
if overlap_shape:
|
||||||
overlap_length = pin.overlap_length(overlap_shape)
|
# overlap_length = pin.overlap_length(overlap_shape)
|
||||||
if smallest_shape == None or overlap_shape.area()<smallest_shape.area():
|
if not smallest_shape or overlap_shape.area() < smallest_shape.area():
|
||||||
smallest_shape = overlap_shape
|
smallest_shape = overlap_shape
|
||||||
|
|
||||||
return smallest_shape
|
return smallest_shape
|
||||||
|
|
||||||
|
|
||||||
def find_smallest_overlapping_pin(self, pin, shape_list):
|
def find_smallest_overlapping_pin(self, pin, shape_list):
|
||||||
"""
|
"""
|
||||||
Find the smallest area shape in shape_list that overlaps with any
|
Find the smallest area shape in shape_list that overlaps with any
|
||||||
|
|
@ -362,7 +367,7 @@ class pin_group:
|
||||||
for other in shape_list:
|
for other in shape_list:
|
||||||
overlap_length = pin.overlap_length(other)
|
overlap_length = pin.overlap_length(other)
|
||||||
if overlap_length > min_width:
|
if overlap_length > min_width:
|
||||||
if smallest_shape == None or other.area()<smallest_shape.area():
|
if not smallest_shape or other.area() < smallest_shape.area():
|
||||||
smallest_shape = other
|
smallest_shape = other
|
||||||
|
|
||||||
return smallest_shape
|
return smallest_shape
|
||||||
|
|
@ -378,7 +383,6 @@ class pin_group:
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def max_pin_layout(self, pin_list):
|
def max_pin_layout(self, pin_list):
|
||||||
"""
|
"""
|
||||||
Return the max area pin_layout
|
Return the max area pin_layout
|
||||||
|
|
@ -433,11 +437,11 @@ class pin_group:
|
||||||
ur = row[-1]
|
ur = row[-1]
|
||||||
return (ll, ur)
|
return (ll, ur)
|
||||||
|
|
||||||
|
|
||||||
def enclose_pin(self):
|
def enclose_pin(self):
|
||||||
"""
|
"""
|
||||||
If there is one set of connected pin shapes,
|
If there is one set of connected pin shapes,
|
||||||
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
|
self.enclosed = True
|
||||||
|
|
@ -453,40 +457,53 @@ class pin_group:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Find a connector in the cardinal directions
|
# Find a connector in the cardinal directions
|
||||||
# If there is overlap, but it isn't contained, these could all be None
|
# If there is overlap, but it isn't contained,
|
||||||
# These could also be none if the pin is diagonal from the enclosure
|
# these could all be None
|
||||||
|
# These could also be none if the pin is
|
||||||
|
# diagonal from the enclosure
|
||||||
left_connector = self.find_left_connector(pin, self.enclosures)
|
left_connector = self.find_left_connector(pin, self.enclosures)
|
||||||
right_connector = self.find_right_connector(pin, self.enclosures)
|
right_connector = self.find_right_connector(pin, self.enclosures)
|
||||||
above_connector = self.find_above_connector(pin, self.enclosures)
|
above_connector = self.find_above_connector(pin, self.enclosures)
|
||||||
below_connector = self.find_below_connector(pin, self.enclosures)
|
below_connector = self.find_below_connector(pin, self.enclosures)
|
||||||
connector_list = [left_connector, right_connector, above_connector, below_connector]
|
connector_list = [left_connector,
|
||||||
filtered_list = list(filter(lambda x: x!=None, connector_list))
|
right_connector,
|
||||||
|
above_connector,
|
||||||
|
below_connector]
|
||||||
|
filtered_list = list(filter(lambda x: not x, connector_list))
|
||||||
if (len(filtered_list) > 0):
|
if (len(filtered_list) > 0):
|
||||||
import copy
|
import copy
|
||||||
bbox_connector = copy.copy(pin)
|
bbox_connector = copy.copy(pin)
|
||||||
bbox_connector.bbox(filtered_list)
|
bbox_connector.bbox(filtered_list)
|
||||||
self.enclosures.append(bbox_connector)
|
self.enclosures.append(bbox_connector)
|
||||||
|
|
||||||
# Now, make sure each pin touches an enclosure. If not, add another (diagonal) connector.
|
# Now, make sure each pin touches an enclosure.
|
||||||
# This could only happen when there was no enclosure in any cardinal direction from a pin
|
# If not, add another (diagonal) connector.
|
||||||
|
# This could only happen when there was no enclosure
|
||||||
|
# in any cardinal direction from a pin
|
||||||
if not self.overlap_any_shape(self.pins, self.enclosures):
|
if not self.overlap_any_shape(self.pins, self.enclosures):
|
||||||
connector = self.find_smallest_connector(self.pins, self.enclosures)
|
connector = self.find_smallest_connector(self.pins,
|
||||||
if connector==None:
|
self.enclosures)
|
||||||
debug.error("Could not find a connector for {} with {}".format(self.pins, self.enclosures))
|
if not connector:
|
||||||
|
debug.error("Could not find a connector for {} with {}".format(self.pins,
|
||||||
|
self.enclosures))
|
||||||
self.router.write_debug_gds("no_connector.gds")
|
self.router.write_debug_gds("no_connector.gds")
|
||||||
self.enclosures.append(connector)
|
self.enclosures.append(connector)
|
||||||
|
|
||||||
# At this point, the pins are overlapping, but there might be more than one!
|
# At this point, the pins are overlapping,
|
||||||
|
# but there might be more than one!
|
||||||
overlap_set = set()
|
overlap_set = set()
|
||||||
for pin in self.pins:
|
for pin in self.pins:
|
||||||
overlap_set.update(self.transitive_overlap(pin, self.enclosures))
|
overlap_set.update(self.transitive_overlap(pin, self.enclosures))
|
||||||
# Use the new enclosures and recompute the grids that correspond to them
|
# Use the new enclosures and recompute the grids
|
||||||
|
# that correspond to them
|
||||||
if len(overlap_set) < len(self.enclosures):
|
if len(overlap_set) < len(self.enclosures):
|
||||||
self.enclosures = overlap_set
|
self.enclosures = overlap_set
|
||||||
self.grids = set()
|
self.grids = set()
|
||||||
# Also update the grid locations with the new (possibly pruned) enclosures
|
# Also update the grid locations with the new
|
||||||
|
# (possibly pruned) enclosures
|
||||||
for enclosure in self.enclosures:
|
for enclosure in self.enclosures:
|
||||||
(sufficient,insufficient) = self.router.convert_pin_to_tracks(self.name,enclosure)
|
(sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name,
|
||||||
|
enclosure)
|
||||||
self.grids.update(sufficient)
|
self.grids.update(sufficient)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -513,7 +530,6 @@ class pin_group:
|
||||||
if old_shape.overlaps(cur_shape):
|
if old_shape.overlaps(cur_shape):
|
||||||
connected_set.add(cur_shape)
|
connected_set.add(cur_shape)
|
||||||
|
|
||||||
|
|
||||||
# Remove the original shape
|
# Remove the original shape
|
||||||
connected_set.remove(shape)
|
connected_set.remove(shape)
|
||||||
|
|
||||||
|
|
@ -525,19 +541,18 @@ class pin_group:
|
||||||
|
|
||||||
return connected_set
|
return connected_set
|
||||||
|
|
||||||
|
|
||||||
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.
|
||||||
"""
|
"""
|
||||||
for enclosure in self.enclosures:
|
for enclosure in self.enclosures:
|
||||||
debug.info(2,"Adding enclosure {0} {1}".format(self.name, enclosure))
|
debug.info(2, "Adding enclosure {0} {1}".format(self.name,
|
||||||
|
enclosure))
|
||||||
cell.add_rect(layer=enclosure.layer,
|
cell.add_rect(layer=enclosure.layer,
|
||||||
offset=enclosure.ll(),
|
offset=enclosure.ll(),
|
||||||
width=enclosure.width(),
|
width=enclosure.width(),
|
||||||
height=enclosure.height())
|
height=enclosure.height())
|
||||||
|
|
||||||
|
|
||||||
def perimeter_grids(self):
|
def perimeter_grids(self):
|
||||||
"""
|
"""
|
||||||
Return a list of the grids on the perimeter.
|
Return a list of the grids on the perimeter.
|
||||||
|
|
@ -566,7 +581,6 @@ class pin_group:
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def adjacent_grids(self, other, separation):
|
def adjacent_grids(self, other, separation):
|
||||||
"""
|
"""
|
||||||
Determine the sets of grids that are within a separation distance
|
Determine the sets of grids that are within a separation distance
|
||||||
|
|
@ -594,11 +608,13 @@ class pin_group:
|
||||||
for pin in self.pins:
|
for pin in self.pins:
|
||||||
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
|
||||||
(sufficient,insufficient)=self.router.convert_pin_to_tracks(self.name, pin)
|
(sufficient, insufficient)=self.router.convert_pin_to_tracks(self.name,
|
||||||
|
pin)
|
||||||
pin_set.update(sufficient)
|
pin_set.update(sufficient)
|
||||||
partial_set.update(insufficient)
|
partial_set.update(insufficient)
|
||||||
|
|
||||||
# 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 = self.router.convert_blockage(pin)
|
blockage_in_tracks = self.router.convert_blockage(pin)
|
||||||
blockage_set.update(blockage_in_tracks)
|
blockage_set.update(blockage_in_tracks)
|
||||||
|
|
||||||
|
|
@ -624,12 +640,15 @@ class pin_group:
|
||||||
for pin in self.pins:
|
for pin in self.pins:
|
||||||
debug.warning(" Expanding conversion {0}".format(pin))
|
debug.warning(" Expanding conversion {0}".format(pin))
|
||||||
# Determine which tracks the pin overlaps
|
# Determine which tracks the pin overlaps
|
||||||
(sufficient,insufficient)=self.router.convert_pin_to_tracks(self.name, pin, expansion=1)
|
(sufficient,insufficient)=self.router.convert_pin_to_tracks(self.name,
|
||||||
|
pin,
|
||||||
|
expansion=1)
|
||||||
pin_set.update(sufficient)
|
pin_set.update(sufficient)
|
||||||
partial_set.update(insufficient)
|
partial_set.update(insufficient)
|
||||||
|
|
||||||
if len(pin_set) == 0 and len(partial_set) == 0:
|
if len(pin_set) == 0 and len(partial_set) == 0:
|
||||||
debug.error("Unable to find unblocked pin {} {}".format(self.name, self.pins))
|
debug.error("Unable to find unblocked pin {} {}".format(self.name,
|
||||||
|
self.pins))
|
||||||
self.router.write_debug_gds("blocked_pin.gds")
|
self.router.write_debug_gds("blocked_pin.gds")
|
||||||
|
|
||||||
# Consider all the grids that would be blocked
|
# Consider all the grids that would be blocked
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
# (acting for and on behalf of Oklahoma State University)
|
# (acting for and on behalf of Oklahoma State University)
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
import sys
|
|
||||||
import gdsMill
|
import gdsMill
|
||||||
from tech import drc, GDS
|
from tech import drc, GDS
|
||||||
from tech import layer as techlayer
|
from tech import layer as techlayer
|
||||||
|
|
@ -17,10 +17,10 @@ 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, print_time
|
from globals import OPTS, print_time
|
||||||
from pprint import pformat
|
|
||||||
import grid_utils
|
import grid_utils
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
class router(router_tech):
|
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
|
||||||
|
|
@ -31,7 +31,8 @@ class router(router_tech):
|
||||||
def __init__(self, layers, design, gds_filename=None, rail_track_width=1):
|
def __init__(self, layers, design, gds_filename=None, rail_track_width=1):
|
||||||
"""
|
"""
|
||||||
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, rail_track_width)
|
router_tech.__init__(self, layers, rail_track_width)
|
||||||
|
|
||||||
|
|
@ -51,30 +52,35 @@ class router(router_tech):
|
||||||
self.top_name = self.layout.rootStructureName
|
self.top_name = self.layout.rootStructureName
|
||||||
# print_time("GDS read",datetime.now(), start_time)
|
# print_time("GDS read",datetime.now(), start_time)
|
||||||
|
|
||||||
### The pin data structures
|
# The pin data structures
|
||||||
# A map of pin names to a set of pin_layout structures
|
# A map of pin names to a set of pin_layout structures
|
||||||
# (i.e. pins with a given label)
|
# (i.e. pins with a given label)
|
||||||
self.pins = {}
|
self.pins = {}
|
||||||
# This is a set of all pins (ignoring names) so that can quickly not create blockages for pins
|
# This is a set of all pins (ignoring names) so that can quickly
|
||||||
# (They will be blocked when we are routing other nets based on their name.)
|
# not create blockages for pins
|
||||||
|
# (They will be blocked when we are routing other
|
||||||
|
# nets based on their name.)
|
||||||
self.all_pins = set()
|
self.all_pins = set()
|
||||||
|
|
||||||
# The labeled pins above categorized into pin groups that are touching/connected.
|
# The labeled pins above categorized into pin groups
|
||||||
|
# that are touching/connected.
|
||||||
self.pin_groups = {}
|
self.pin_groups = {}
|
||||||
|
|
||||||
### 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.
|
||||||
self.blockages = []
|
self.blockages = []
|
||||||
# The corresponding set of blocked grids for above pin shapes
|
# The corresponding set of blocked grids for above pin shapes
|
||||||
self.blocked_grids = set()
|
self.blocked_grids = set()
|
||||||
|
|
||||||
### The routed data structures
|
# The routed data structures
|
||||||
# A list of paths that have been "routed"
|
# A list of paths that have been "routed"
|
||||||
self.paths = []
|
self.paths = []
|
||||||
# A list of path blockages (they might be expanded for wide metal DRC)
|
# A list of path blockages (they might be expanded for wide metal DRC)
|
||||||
self.path_blockages = []
|
self.path_blockages = []
|
||||||
|
|
||||||
# The boundary will determine the limits to the size of the routing grid
|
# The boundary will determine the limits to the size
|
||||||
|
# of the routing grid
|
||||||
self.boundary = self.layout.measureBoundary(self.top_name)
|
self.boundary = self.layout.measureBoundary(self.top_name)
|
||||||
# These must be un-indexed to get rid of the matrix type
|
# These must be un-indexed to get rid of the matrix type
|
||||||
self.ll = vector(self.boundary[0][0], self.boundary[0][1])
|
self.ll = vector(self.boundary[0][0], self.boundary[0][1])
|
||||||
|
|
@ -91,19 +97,17 @@ class router(router_tech):
|
||||||
# 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()
|
||||||
|
|
||||||
|
|
||||||
def set_top(self, top_name):
|
def set_top(self, top_name):
|
||||||
""" 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 is_wave(self, path):
|
def is_wave(self, path):
|
||||||
"""
|
"""
|
||||||
Determines if this is a multi-track width wave (True) or a normal route (False)
|
Determines if this is a multi-track width wave (True)
|
||||||
|
# or a normal route (False)
|
||||||
"""
|
"""
|
||||||
return len(path[0]) > 1
|
return len(path[0]) > 1
|
||||||
|
|
||||||
|
|
||||||
def retrieve_pins(self, pin_name):
|
def retrieve_pins(self, pin_name):
|
||||||
"""
|
"""
|
||||||
Retrieve the pin shapes on metal 3 from the layout.
|
Retrieve the pin shapes on metal 3 from the layout.
|
||||||
|
|
@ -121,7 +125,8 @@ class router(router_tech):
|
||||||
pin = pin_layout(pin_name, rect, layer)
|
pin = pin_layout(pin_name, rect, layer)
|
||||||
pin_set.add(pin)
|
pin_set.add(pin)
|
||||||
|
|
||||||
debug.check(len(pin_set)>0,"Did not find any pin shapes for {0}.".format(str(pin_name)))
|
debug.check(len(pin_set) > 0,
|
||||||
|
"Did not find any pin shapes for {0}.".format(str(pin_name)))
|
||||||
|
|
||||||
self.pins[pin_name] = pin_set
|
self.pins[pin_name] = pin_set
|
||||||
self.all_pins.update(pin_set)
|
self.all_pins.update(pin_set)
|
||||||
|
|
@ -129,12 +134,11 @@ class router(router_tech):
|
||||||
for pin in self.pins[pin_name]:
|
for pin in self.pins[pin_name]:
|
||||||
debug.info(3, "Retrieved pin {}".format(str(pin)))
|
debug.info(3, "Retrieved pin {}".format(str(pin)))
|
||||||
|
|
||||||
|
|
||||||
def find_blockages(self):
|
def find_blockages(self):
|
||||||
"""
|
"""
|
||||||
Iterate through all the layers and write the obstacles to the routing grid.
|
Iterate through all the layers and write the obstacles to the routing grid.
|
||||||
This doesn't consider whether the obstacles will be pins or not. They get reset later
|
This doesn't consider whether the obstacles will be pins or not.
|
||||||
if they are not actually a blockage.
|
They get reset later if they are not actually a blockage.
|
||||||
"""
|
"""
|
||||||
debug.info(1, "Finding blockages.")
|
debug.info(1, "Finding blockages.")
|
||||||
for layer in [self.vert_layer_number, self.horiz_layer_number]:
|
for layer in [self.vert_layer_number, self.horiz_layer_number]:
|
||||||
|
|
@ -144,8 +148,9 @@ class router(router_tech):
|
||||||
"""
|
"""
|
||||||
Find the pins and blockages in the design
|
Find the pins and blockages in the design
|
||||||
"""
|
"""
|
||||||
# This finds the pin shapes and sorts them into "groups" that are connected
|
# This finds the pin shapes and sorts them into "groups" that
|
||||||
# This must come before the blockages, so we can not count the pins themselves
|
# are connected. This must come before the blockages, so we
|
||||||
|
# can not count the pins themselves
|
||||||
# as blockages.
|
# as blockages.
|
||||||
start_time = datetime.now()
|
start_time = datetime.now()
|
||||||
for pin_name in pin_list:
|
for pin_name in pin_list:
|
||||||
|
|
@ -169,7 +174,8 @@ class router(router_tech):
|
||||||
print_time("Converting blockages", datetime.now(), start_time, 4)
|
print_time("Converting blockages", datetime.now(), start_time, 4)
|
||||||
|
|
||||||
# This will convert the pins to grid units
|
# This will convert the pins to grid units
|
||||||
# It must be done after blockages to ensure no DRCs between expanded pins and blocked grids
|
# It must be done after blockages to ensure no DRCs
|
||||||
|
# between expanded pins and blocked grids
|
||||||
start_time = datetime.now()
|
start_time = datetime.now()
|
||||||
for pin in pin_list:
|
for pin in pin_list:
|
||||||
self.convert_pins(pin)
|
self.convert_pins(pin)
|
||||||
|
|
@ -184,18 +190,19 @@ class router(router_tech):
|
||||||
# print_time("Combining adjacent pins",datetime.now(), start_time, 4)
|
# print_time("Combining adjacent pins",datetime.now(), start_time, 4)
|
||||||
|
|
||||||
|
|
||||||
# Separate any adjacent grids of differing net names that overlap
|
# Separate any adjacent grids of differing net names
|
||||||
|
# that overlap
|
||||||
# Must be done before enclosing pins
|
# Must be done before enclosing pins
|
||||||
start_time = datetime.now()
|
start_time = datetime.now()
|
||||||
self.separate_adjacent_pins(0)
|
self.separate_adjacent_pins(0)
|
||||||
print_time("Separating adjacent pins", datetime.now(), start_time, 4)
|
print_time("Separating adjacent pins", datetime.now(), start_time, 4)
|
||||||
|
|
||||||
# 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
|
||||||
start_time = datetime.now()
|
start_time = datetime.now()
|
||||||
self.enclose_pins()
|
self.enclose_pins()
|
||||||
print_time("Enclosing pins", datetime.now(), start_time, 4)
|
print_time("Enclosing pins", datetime.now(), start_time, 4)
|
||||||
|
|
||||||
|
|
||||||
# MRG: Removing this code for now. The later compute enclosure code
|
# MRG: Removing this code for now. The later compute enclosure code
|
||||||
# assumes that all pins are touching and this may produce sets of pins
|
# assumes that all pins are touching and this may produce sets of pins
|
||||||
# that are not connected.
|
# that are not connected.
|
||||||
|
|
@ -249,15 +256,15 @@ class router(router_tech):
|
||||||
# # Use the new pin group!
|
# # Use the new pin group!
|
||||||
# self.pin_groups[pin_name] = new_pin_groups
|
# self.pin_groups[pin_name] = new_pin_groups
|
||||||
# removed_pairs = old_size - len(new_pin_groups)
|
# removed_pairs = old_size - len(new_pin_groups)
|
||||||
# debug.info(1, "Combined {0} pin groups for {1}".format(removed_pairs,pin_name))
|
# debug.info(1,
|
||||||
|
# "Combined {0} pin groups for {1}".format(removed_pairs,pin_name))
|
||||||
|
|
||||||
# return removed_pairs
|
# return removed_pairs
|
||||||
|
|
||||||
|
|
||||||
def separate_adjacent_pins(self, separation):
|
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
|
||||||
tracks (default is to prevent adjacency).
|
number of separation tracks (default is to prevent adjacency).
|
||||||
"""
|
"""
|
||||||
# Commented out to debug with SCMOS
|
# Commented out to debug with SCMOS
|
||||||
# if separation==0:
|
# if separation==0:
|
||||||
|
|
@ -279,7 +286,9 @@ class router(router_tech):
|
||||||
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.
|
||||||
"""
|
"""
|
||||||
debug.info(1,"Comparing {0} and {1} adjacency".format(pin_name1, pin_name2))
|
debug.info(1,
|
||||||
|
"Comparing {0} and {1} adjacency".format(pin_name1,
|
||||||
|
pin_name2))
|
||||||
removed_grids = 0
|
removed_grids = 0
|
||||||
for index1, pg1 in enumerate(self.pin_groups[pin_name1]):
|
for index1, pg1 in enumerate(self.pin_groups[pin_name1]):
|
||||||
for index2, pg2 in enumerate(self.pin_groups[pin_name2]):
|
for index2, pg2 in enumerate(self.pin_groups[pin_name2]):
|
||||||
|
|
@ -287,7 +296,10 @@ class router(router_tech):
|
||||||
removed_grids += len(adj_grids)
|
removed_grids += len(adj_grids)
|
||||||
# These should have the same length, so...
|
# These should have the same length, so...
|
||||||
if len(adj_grids) > 0:
|
if len(adj_grids) > 0:
|
||||||
debug.info(3,"Adjacent grids {0} {1} adj={2}".format(index1,index2,adj_grids))
|
debug.info(3,
|
||||||
|
"Adjacent grids {0} {1} adj={2}".format(index1,
|
||||||
|
index2,
|
||||||
|
adj_grids))
|
||||||
self.remove_adjacent_grid(pg1, pg2, adj_grids)
|
self.remove_adjacent_grid(pg1, pg2, adj_grids)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -296,7 +308,8 @@ class router(router_tech):
|
||||||
def remove_adjacent_grid(self, pg1, pg2, adj_grids):
|
def remove_adjacent_grid(self, pg1, pg2, adj_grids):
|
||||||
"""
|
"""
|
||||||
Remove one of the adjacent grids in a heuristic manner.
|
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.
|
This will try to keep the groups similar sized by
|
||||||
|
removing from the bigger group.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if pg1.size() > pg2.size():
|
if pg1.size() > pg2.size():
|
||||||
|
|
@ -309,31 +322,33 @@ class router(router_tech):
|
||||||
for adj in adj_grids:
|
for adj in adj_grids:
|
||||||
|
|
||||||
|
|
||||||
# If the adjacent grids are a subset of the secondary grids (i.e. not necessary)
|
# If the adjacent grids are a subset of the secondary
|
||||||
# remove them from each
|
# grids (i.e. not necessary) remove them from each
|
||||||
if adj in bigger.secondary_grids:
|
if adj in bigger.secondary_grids:
|
||||||
debug.info(3,"Removing {} from bigger secondary {}".format(adj, bigger))
|
debug.info(3,"Removing {} from bigger secondary {}".format(adj,
|
||||||
|
bigger))
|
||||||
bigger.grids.remove(adj)
|
bigger.grids.remove(adj)
|
||||||
bigger.secondary_grids.remove(adj)
|
bigger.secondary_grids.remove(adj)
|
||||||
self.blocked_grids.add(adj)
|
self.blocked_grids.add(adj)
|
||||||
elif adj in smaller.secondary_grids:
|
elif adj in smaller.secondary_grids:
|
||||||
debug.info(3,"Removing {} from smaller secondary {}".format(adj, smaller))
|
debug.info(3,"Removing {} from smaller secondary {}".format(adj,
|
||||||
|
smaller))
|
||||||
smaller.grids.remove(adj)
|
smaller.grids.remove(adj)
|
||||||
smaller.secondary_grids.remove(adj)
|
smaller.secondary_grids.remove(adj)
|
||||||
self.blocked_grids.add(adj)
|
self.blocked_grids.add(adj)
|
||||||
else:
|
else:
|
||||||
# If we couldn't remove from a secondary grid, we must remove from the primary
|
# If we couldn't remove from a secondary grid,
|
||||||
|
# we must remove from the primary
|
||||||
# grid of at least one pin
|
# grid of at least one pin
|
||||||
if adj in bigger.grids:
|
if adj in bigger.grids:
|
||||||
debug.info(3,"Removing {} from bigger primary {}".format(adj, bigger))
|
debug.info(3,"Removing {} from bigger primary {}".format(adj,
|
||||||
|
bigger))
|
||||||
bigger.grids.remove(adj)
|
bigger.grids.remove(adj)
|
||||||
elif adj in smaller.grids:
|
elif adj in smaller.grids:
|
||||||
debug.info(3,"Removing {} from smaller primary {}".format(adj, smaller))
|
debug.info(3,"Removing {} from smaller primary {}".format(adj,
|
||||||
|
smaller))
|
||||||
smaller.grids.remove(adj)
|
smaller.grids.remove(adj)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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.
|
||||||
|
|
@ -347,10 +362,12 @@ class router(router_tech):
|
||||||
#print("BLOCKING:", self.blocked_grids)
|
#print("BLOCKING:", self.blocked_grids)
|
||||||
self.set_blockages(self.blocked_grids, True)
|
self.set_blockages(self.blocked_grids, True)
|
||||||
|
|
||||||
# Block all of the supply rails (some will be unblocked if they're a target)
|
# Block all of the supply rails
|
||||||
|
# (some will be unblocked if they're a target)
|
||||||
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)
|
||||||
# Also block the previous routes
|
# Also block the previous routes
|
||||||
for name in self.pin_groups:
|
for name in self.pin_groups:
|
||||||
blockage_grids = {y for x in self.pin_groups[name] for y in x.grids}
|
blockage_grids = {y for x in self.pin_groups[name] for y in x.grids}
|
||||||
|
|
@ -368,7 +385,6 @@ class router(router_tech):
|
||||||
blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids}
|
blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids}
|
||||||
self.set_blockages(blockage_grids, False)
|
self.set_blockages(blockage_grids, False)
|
||||||
|
|
||||||
|
|
||||||
def convert_shape_to_units(self, shape):
|
def convert_shape_to_units(self, shape):
|
||||||
"""
|
"""
|
||||||
Scale a shape (two vector list) to user units
|
Scale a shape (two vector list) to user units
|
||||||
|
|
@ -378,7 +394,6 @@ class router(router_tech):
|
||||||
ur = shape[1].scale(unit_factor)
|
ur = shape[1].scale(unit_factor)
|
||||||
return [ll, ur]
|
return [ll, ur]
|
||||||
|
|
||||||
|
|
||||||
def min_max_coord(self, coord):
|
def min_max_coord(self, coord):
|
||||||
"""
|
"""
|
||||||
Find the lowest and highest corner of a Rectangle
|
Find the lowest and highest corner of a Rectangle
|
||||||
|
|
@ -444,7 +459,6 @@ class router(router_tech):
|
||||||
blockage_list = self.convert_blockage(blockage)
|
blockage_list = self.convert_blockage(blockage)
|
||||||
self.blocked_grids.update(blockage_list)
|
self.blocked_grids.update(blockage_list)
|
||||||
|
|
||||||
|
|
||||||
def retrieve_blockages(self, layer_num):
|
def retrieve_blockages(self, layer_num):
|
||||||
"""
|
"""
|
||||||
Recursive find boundaries as blockages to the routing grid.
|
Recursive find boundaries as blockages to the routing grid.
|
||||||
|
|
@ -455,13 +469,15 @@ class router(router_tech):
|
||||||
ll = vector(boundary[0], boundary[1])
|
ll = vector(boundary[0], boundary[1])
|
||||||
ur = vector(boundary[2], boundary[3])
|
ur = vector(boundary[2], boundary[3])
|
||||||
rect = [ll, ur]
|
rect = [ll, ur]
|
||||||
new_pin = pin_layout("blockage{}".format(len(self.blockages)),rect,layer_num)
|
new_pin = pin_layout("blockage{}".format(len(self.blockages)),
|
||||||
|
rect,
|
||||||
|
layer_num)
|
||||||
|
|
||||||
# If there is a rectangle that is the same in the pins, it isn't a blockage!
|
# If there is a rectangle that is the same in the pins,
|
||||||
|
# it isn't a blockage!
|
||||||
if new_pin not in self.all_pins:
|
if new_pin not in self.all_pins:
|
||||||
self.blockages.append(new_pin)
|
self.blockages.append(new_pin)
|
||||||
|
|
||||||
|
|
||||||
def convert_point_to_units(self, p):
|
def convert_point_to_units(self, p):
|
||||||
"""
|
"""
|
||||||
Convert a path set of tracks to center line path.
|
Convert a path set of tracks to center line path.
|
||||||
|
|
@ -476,7 +492,6 @@ class router(router_tech):
|
||||||
"""
|
"""
|
||||||
return [self.convert_point_to_units(i) for i in wave]
|
return [self.convert_point_to_units(i) for i in wave]
|
||||||
|
|
||||||
|
|
||||||
def convert_blockage_to_tracks(self, shape):
|
def convert_blockage_to_tracks(self, shape):
|
||||||
"""
|
"""
|
||||||
Convert a rectangular blockage shape into track units.
|
Convert a rectangular blockage shape into track units.
|
||||||
|
|
@ -487,8 +502,6 @@ class router(router_tech):
|
||||||
|
|
||||||
# to scale coordinates to tracks
|
# to scale coordinates to tracks
|
||||||
debug.info(3, "Converting [ {0} , {1} ]".format(ll, ur))
|
debug.info(3, "Converting [ {0} , {1} ]".format(ll, ur))
|
||||||
old_ll = ll
|
|
||||||
old_ur = ur
|
|
||||||
ll = ll.scale(self.track_factor)
|
ll = ll.scale(self.track_factor)
|
||||||
ur = ur.scale(self.track_factor)
|
ur = ur.scale(self.track_factor)
|
||||||
# We can round since we are using inflated shapes
|
# We can round since we are using inflated shapes
|
||||||
|
|
@ -500,8 +513,10 @@ class router(router_tech):
|
||||||
def convert_pin_to_tracks(self, pin_name, pin, expansion=0):
|
def convert_pin_to_tracks(self, pin_name, pin, expansion=0):
|
||||||
"""
|
"""
|
||||||
Convert a rectangular pin shape into a list of track locations,layers.
|
Convert a rectangular pin shape into a list of track locations,layers.
|
||||||
If no pins are "on-grid" (i.e. sufficient overlap) it makes the one with most overlap if it is not blocked.
|
If no pins are "on-grid" (i.e. sufficient overlap)
|
||||||
If expansion>0, expamine areas beyond the current pin when it is blocked.
|
it makes the one with most overlap if it is not blocked.
|
||||||
|
If expansion>0, expamine areas beyond the current pin
|
||||||
|
when it is blocked.
|
||||||
"""
|
"""
|
||||||
(ll, ur) = pin.rect
|
(ll, ur) = pin.rect
|
||||||
debug.info(3, "Converting pin [ {0} , {1} ]".format(ll, ur))
|
debug.info(3, "Converting pin [ {0} , {1} ]".format(ll, ur))
|
||||||
|
|
@ -517,17 +532,22 @@ class router(router_tech):
|
||||||
zindex = self.get_zindex(pin.layer_num)
|
zindex = self.get_zindex(pin.layer_num)
|
||||||
for x in range(int(ll[0]) + expansion, int(ur[0]) + 1 + expansion):
|
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):
|
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:
|
if full_overlap:
|
||||||
sufficient_list.update([full_overlap])
|
sufficient_list.update([full_overlap])
|
||||||
if partial_overlap:
|
if partial_overlap:
|
||||||
insufficient_list.update([partial_overlap])
|
insufficient_list.update([partial_overlap])
|
||||||
debug.info(2,"Converting [ {0} , {1} ] full={2}".format(x,y, full_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 all grids with any potential overlap (sufficient or not)
|
||||||
return (sufficient_list, insufficient_list)
|
return (sufficient_list, insufficient_list)
|
||||||
|
|
||||||
|
|
||||||
def get_all_offgrid_pin(self, pin, insufficient_list):
|
def get_all_offgrid_pin(self, pin, insufficient_list):
|
||||||
"""
|
"""
|
||||||
Find a list of all pins with some overlap.
|
Find a list of all pins with some overlap.
|
||||||
|
|
@ -598,23 +618,31 @@ class router(router_tech):
|
||||||
|
|
||||||
return set([best_coord])
|
return set([best_coord])
|
||||||
|
|
||||||
|
|
||||||
def convert_pin_coord_to_tracks(self, pin, coord):
|
def convert_pin_coord_to_tracks(self, pin, coord):
|
||||||
"""
|
"""
|
||||||
Return all tracks that an inflated pin overlaps
|
Return all tracks that an inflated pin overlaps
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# This is using the full track shape rather than a single track pin shape
|
# 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.
|
# because we will later patch a connector if there isn't overlap.
|
||||||
track_pin = self.convert_track_to_shape_pin(coord)
|
track_pin = self.convert_track_to_shape_pin(coord)
|
||||||
|
|
||||||
# This is the normal pin inflated by a minimum design rule
|
# 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)
|
inflated_pin = pin_layout(pin.name,
|
||||||
|
pin.inflate(0.5 * self.track_space),
|
||||||
|
pin.layer)
|
||||||
|
|
||||||
overlap_length = pin.overlap_length(track_pin)
|
overlap_length = pin.overlap_length(track_pin)
|
||||||
debug.info(2,"Check overlap: {0} {1} . {2} = {3}".format(coord, pin.rect, track_pin, overlap_length))
|
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)
|
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))
|
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 it overlaps with the pin, it is sufficient
|
||||||
if overlap_length == math.inf or overlap_length > 0:
|
if overlap_length == math.inf or overlap_length > 0:
|
||||||
|
|
@ -628,7 +656,6 @@ class router(router_tech):
|
||||||
debug.info(2, " No overlap: {0} {1}".format(overlap_length, 0))
|
debug.info(2, " No overlap: {0} {1}".format(overlap_length, 0))
|
||||||
return (None, None)
|
return (None, None)
|
||||||
|
|
||||||
|
|
||||||
def convert_track_to_pin(self, track):
|
def convert_track_to_pin(self, track):
|
||||||
"""
|
"""
|
||||||
Convert a grid point into a rectangle shape that is centered
|
Convert a grid point into a rectangle shape that is centered
|
||||||
|
|
@ -649,8 +676,8 @@ class router(router_tech):
|
||||||
|
|
||||||
def convert_track_to_shape_pin(self, track):
|
def convert_track_to_shape_pin(self, track):
|
||||||
"""
|
"""
|
||||||
Convert a grid point into a rectangle shape that occupies the entire centered
|
Convert a grid point into a rectangle shape
|
||||||
track.
|
that occupies the entire centered track.
|
||||||
"""
|
"""
|
||||||
# to scale coordinates to tracks
|
# to scale coordinates to tracks
|
||||||
x = track[0]*self.track_width - 0.5*self.track_width
|
x = track[0]*self.track_width - 0.5*self.track_width
|
||||||
|
|
@ -664,8 +691,8 @@ class router(router_tech):
|
||||||
|
|
||||||
def convert_track_to_shape(self, track):
|
def convert_track_to_shape(self, track):
|
||||||
"""
|
"""
|
||||||
Convert a grid point into a rectangle shape that occupies the entire centered
|
Convert a grid point into a rectangle shape
|
||||||
track.
|
that occupies the entire centered track.
|
||||||
"""
|
"""
|
||||||
# to scale coordinates to tracks
|
# to scale coordinates to tracks
|
||||||
try:
|
try:
|
||||||
|
|
@ -681,7 +708,8 @@ class router(router_tech):
|
||||||
|
|
||||||
def convert_track_to_inflated_pin(self, track):
|
def convert_track_to_inflated_pin(self, track):
|
||||||
"""
|
"""
|
||||||
Convert a grid point into a rectangle shape that is inflated by a half DRC space.
|
Convert a grid point into a rectangle shape
|
||||||
|
that is inflated by a half DRC space.
|
||||||
"""
|
"""
|
||||||
# calculate lower left
|
# calculate lower left
|
||||||
x = track.x*self.track_width - 0.5*self.track_width - 0.5*self.track_space
|
x = track.x*self.track_width - 0.5*self.track_width - 0.5*self.track_space
|
||||||
|
|
@ -698,7 +726,8 @@ class router(router_tech):
|
||||||
|
|
||||||
def analyze_pins(self, pin_name):
|
def analyze_pins(self, pin_name):
|
||||||
"""
|
"""
|
||||||
Analyze the shapes of a pin and combine them into pin_groups which are connected.
|
Analyze the shapes of a pin and combine
|
||||||
|
them into pin_groups which are connected.
|
||||||
"""
|
"""
|
||||||
debug.info(2, "Analyzing pin groups for {}.".format(pin_name))
|
debug.info(2, "Analyzing pin groups for {}.".format(pin_name))
|
||||||
pin_set = self.pins[pin_name]
|
pin_set = self.pins[pin_name]
|
||||||
|
|
@ -714,7 +743,7 @@ class router(router_tech):
|
||||||
|
|
||||||
# Map the pins to the lower indices
|
# Map the pins to the lower indices
|
||||||
bottom_index_map = {x[1]: i for i, x in enumerate(y_coordinates) if x[2] == "bottom"}
|
bottom_index_map = {x[1]: i for i, x in enumerate(y_coordinates) if x[2] == "bottom"}
|
||||||
top_index_map = {x[1]:i for i,x in enumerate(y_coordinates) if x[2]=="bottom"}
|
# top_index_map = {x[1]: i for i, x in enumerate(y_coordinates) if x[2] == "bottom"}
|
||||||
|
|
||||||
# Sort the pin list by x coordinate
|
# Sort the pin list by x coordinate
|
||||||
pin_list = list(pin_set)
|
pin_list = list(pin_set)
|
||||||
|
|
@ -754,19 +783,19 @@ class router(router_tech):
|
||||||
if group_id[pin] == group_id[p2]:
|
if group_id[pin] == group_id[p2]:
|
||||||
group_id[pin] = group_id[p1]
|
group_id[pin] = group_id[p1]
|
||||||
|
|
||||||
|
|
||||||
# For each pin add it to it's group
|
# For each pin add it to it's group
|
||||||
group_map = {}
|
group_map = {}
|
||||||
for pin in pin_list:
|
for pin in pin_list:
|
||||||
gid = group_id[pin]
|
gid = group_id[pin]
|
||||||
if gid not in group_map:
|
if gid not in group_map:
|
||||||
group_map[gid] = pin_group(name=pin_name, pin_set=[], router=self)
|
group_map[gid] = pin_group(name=pin_name,
|
||||||
|
pin_set=[],
|
||||||
|
router=self)
|
||||||
# We always add it to the first set since they are touching
|
# We always add it to the first set since they are touching
|
||||||
group_map[gid].pins.add(pin)
|
group_map[gid].pins.add(pin)
|
||||||
|
|
||||||
self.pin_groups[pin_name] = list(group_map.values())
|
self.pin_groups[pin_name] = list(group_map.values())
|
||||||
|
|
||||||
|
|
||||||
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.
|
||||||
|
|
@ -775,8 +804,6 @@ class router(router_tech):
|
||||||
for pg in self.pin_groups[pin_name]:
|
for pg in self.pin_groups[pin_name]:
|
||||||
pg.convert_pin()
|
pg.convert_pin()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def enclose_pins(self):
|
def enclose_pins(self):
|
||||||
"""
|
"""
|
||||||
This will find the biggest rectangle enclosing some grid squares and
|
This will find the biggest rectangle enclosing some grid squares and
|
||||||
|
|
@ -813,10 +840,12 @@ class router(router_tech):
|
||||||
|
|
||||||
def add_pin_component_source(self, pin_name, index):
|
def add_pin_component_source(self, pin_name, index):
|
||||||
"""
|
"""
|
||||||
This will mark only the pin tracks from the indexed pin component as a source.
|
This will mark only the pin tracks
|
||||||
|
from the indexed pin component as a source.
|
||||||
It also unsets it as a blockage.
|
It also unsets it as a blockage.
|
||||||
"""
|
"""
|
||||||
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_groups[pin_name][index].grids
|
pin_in_tracks = self.pin_groups[pin_name][index].grids
|
||||||
debug.info(2,"Set source: " + str(pin_name) + " " + str(pin_in_tracks))
|
debug.info(2,"Set source: " + str(pin_name) + " " + str(pin_in_tracks))
|
||||||
|
|
@ -832,7 +861,8 @@ class router(router_tech):
|
||||||
|
|
||||||
def add_pin_component_target(self, pin_name, index):
|
def add_pin_component_target(self, pin_name, index):
|
||||||
"""
|
"""
|
||||||
This will mark only the pin tracks from the indexed pin component as a target.
|
This will mark only the pin tracks
|
||||||
|
from the indexed pin component as a target.
|
||||||
It also unsets it as a blockage.
|
It also unsets it as a blockage.
|
||||||
"""
|
"""
|
||||||
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.")
|
||||||
|
|
@ -841,7 +871,6 @@ class router(router_tech):
|
||||||
debug.info(2, "Set target: " + str(pin_name) + " " + str(pin_in_tracks))
|
debug.info(2, "Set target: " + str(pin_name) + " " + str(pin_in_tracks))
|
||||||
self.rg.add_target(pin_in_tracks)
|
self.rg.add_target(pin_in_tracks)
|
||||||
|
|
||||||
|
|
||||||
def add_pin_component_target_except(self, pin_name, index):
|
def add_pin_component_target_except(self, pin_name, index):
|
||||||
"""
|
"""
|
||||||
This will mark the grids for all *other* pin components as a target.
|
This will mark the grids for all *other* pin components as a target.
|
||||||
|
|
@ -859,11 +888,11 @@ class router(router_tech):
|
||||||
for pg in self.pin_groups[pin_name]:
|
for pg in self.pin_groups[pin_name]:
|
||||||
self.set_blockages(pg.grids, value)
|
self.set_blockages(pg.grids, value)
|
||||||
|
|
||||||
|
|
||||||
def prepare_path(self,path):
|
def prepare_path(self,path):
|
||||||
"""
|
"""
|
||||||
Prepare a path or wave for routing ebedding.
|
Prepare a path or wave for routing ebedding.
|
||||||
This tracks the path, simplifies the path and marks it as a path for debug output.
|
This tracks the path, simplifies the path and
|
||||||
|
marks it as a path for debug output.
|
||||||
"""
|
"""
|
||||||
debug.info(4, "Set path: " + str(path))
|
debug.info(4, "Set path: " + str(path))
|
||||||
|
|
||||||
|
|
@ -871,8 +900,8 @@ class router(router_tech):
|
||||||
path.set_path()
|
path.set_path()
|
||||||
|
|
||||||
# For debugging... if the path failed to route.
|
# For debugging... if the path failed to route.
|
||||||
if False or path==None:
|
# if False or path == None:
|
||||||
self.write_debug_gds()
|
# self.write_debug_gds()
|
||||||
|
|
||||||
# First, simplify the path for
|
# First, simplify the path for
|
||||||
# debug.info(1, str(self.path))
|
# debug.info(1, str(self.path))
|
||||||
|
|
@ -881,7 +910,6 @@ class router(router_tech):
|
||||||
|
|
||||||
return contracted_path
|
return contracted_path
|
||||||
|
|
||||||
|
|
||||||
def add_route(self, path):
|
def add_route(self, path):
|
||||||
"""
|
"""
|
||||||
Add the current wire route to the given design instance.
|
Add the current wire route to the given design instance.
|
||||||
|
|
@ -908,7 +936,8 @@ class router(router_tech):
|
||||||
|
|
||||||
def add_single_enclosure(self, track):
|
def add_single_enclosure(self, track):
|
||||||
"""
|
"""
|
||||||
Add a metal enclosure that is the size of the routing grid minus a spacing on each side.
|
Add a metal enclosure that is the size of
|
||||||
|
the routing grid minus a spacing on each side.
|
||||||
"""
|
"""
|
||||||
pin = self.convert_track_to_pin(track)
|
pin = self.convert_track_to_pin(track)
|
||||||
(ll, ur) = pin.rect
|
(ll, ur) = pin.rect
|
||||||
|
|
@ -917,8 +946,6 @@ class router(router_tech):
|
||||||
width=ur.x-ll.x,
|
width=ur.x-ll.x,
|
||||||
height=ur.y-ll.y)
|
height=ur.y-ll.y)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_via(self, loc, size=1):
|
def add_via(self, loc, size=1):
|
||||||
"""
|
"""
|
||||||
Add a via centered at the current location
|
Add a via centered at the current location
|
||||||
|
|
@ -935,7 +962,8 @@ class router(router_tech):
|
||||||
"""
|
"""
|
||||||
layer = self.get_layer(zindex)
|
layer = self.get_layer(zindex)
|
||||||
|
|
||||||
# This finds the pin shape enclosed by the track with DRC spacing on the sides
|
# This finds the pin shape enclosed by the
|
||||||
|
# track with DRC spacing on the sides
|
||||||
pin = self.convert_track_to_pin(ll)
|
pin = self.convert_track_to_pin(ll)
|
||||||
(abs_ll, unused) = pin.rect
|
(abs_ll, unused) = pin.rect
|
||||||
pin = self.convert_track_to_pin(ur)
|
pin = self.convert_track_to_pin(ur)
|
||||||
|
|
@ -967,8 +995,6 @@ class router(router_tech):
|
||||||
newpath.append(path[-1])
|
newpath.append(path[-1])
|
||||||
return newpath
|
return newpath
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def run_router(self, detour_scale):
|
def run_router(self, detour_scale):
|
||||||
"""
|
"""
|
||||||
This assumes the blockages, source, and target are all set up.
|
This assumes the blockages, source, and target are all set up.
|
||||||
|
|
@ -998,7 +1024,6 @@ class router(router_tech):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def annotate_pin_and_tracks(self, pin, tracks):
|
def annotate_pin_and_tracks(self, pin, tracks):
|
||||||
""""
|
""""
|
||||||
Annotate some shapes for debug purposes
|
Annotate some shapes for debug purposes
|
||||||
|
|
@ -1023,7 +1048,8 @@ class router(router_tech):
|
||||||
|
|
||||||
def write_debug_gds(self, gds_name="debug_route.gds", stop_program=True):
|
def write_debug_gds(self, gds_name="debug_route.gds", stop_program=True):
|
||||||
"""
|
"""
|
||||||
Write out a GDS file with the routing grid and search information annotated on it.
|
Write out a GDS file with the routing grid and
|
||||||
|
search information annotated on it.
|
||||||
"""
|
"""
|
||||||
debug.info(0, "Writing annotated router gds file to {}".format(gds_name))
|
debug.info(0, "Writing annotated router gds file to {}".format(gds_name))
|
||||||
self.del_router_info()
|
self.del_router_info()
|
||||||
|
|
@ -1062,7 +1088,7 @@ class router(router_tech):
|
||||||
|
|
||||||
t = self.rg.map[g].get_cost()
|
t = self.rg.map[g].get_cost()
|
||||||
partial_track = vector(self.track_width/6.0, 0)
|
partial_track = vector(self.track_width/6.0, 0)
|
||||||
if t!=None:
|
if t:
|
||||||
if g[2] == 1:
|
if g[2] == 1:
|
||||||
# Upper layer is right label
|
# Upper layer is right label
|
||||||
type_off = off + partial_track
|
type_off = off + partial_track
|
||||||
|
|
@ -1086,7 +1112,6 @@ class router(router_tech):
|
||||||
layer_num = techlayer["text"]
|
layer_num = techlayer["text"]
|
||||||
self.cell.objs = [x for x in self.cell.objs if x.layerNumber != layer_num]
|
self.cell.objs = [x for x in self.cell.objs if x.layerNumber != layer_num]
|
||||||
|
|
||||||
|
|
||||||
def add_router_info(self):
|
def add_router_info(self):
|
||||||
"""
|
"""
|
||||||
Write the routing grid and router cost, blockage, pins on
|
Write the routing grid and router cost, blockage, pins on
|
||||||
|
|
@ -1125,14 +1150,18 @@ class router(router_tech):
|
||||||
if not pg.enclosed:
|
if not pg.enclosed:
|
||||||
continue
|
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",
|
||||||
offset=pin.ll(),
|
offset=pin.ll(),
|
||||||
width=pin.width(),
|
width=pin.width(),
|
||||||
height=pin.height())
|
height=pin.height())
|
||||||
|
|
||||||
# FIXME: This should be replaced with vector.snap_to_grid at some point
|
|
||||||
|
|
||||||
|
# FIXME: This should be replaced with vector.snap_to_grid at some point
|
||||||
def snap_to_grid(offset):
|
def snap_to_grid(offset):
|
||||||
"""
|
"""
|
||||||
Changes the coodrinate to match the grid settings
|
Changes the coodrinate to match the grid settings
|
||||||
|
|
@ -1141,6 +1170,7 @@ def snap_to_grid(offset):
|
||||||
yoff = snap_val_to_grid(offset[1])
|
yoff = snap_val_to_grid(offset[1])
|
||||||
return vector(xoff, yoff)
|
return vector(xoff, yoff)
|
||||||
|
|
||||||
|
|
||||||
def snap_val_to_grid(x):
|
def snap_val_to_grid(x):
|
||||||
grid = drc("grid")
|
grid = drc("grid")
|
||||||
xgrid = int(round(round((x / grid), 2), 0))
|
xgrid = int(round(round((x / grid), 2), 0))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue