mirror of https://github.com/VLSIDA/OpenRAM.git
Supply router working except:
Off grid pins. Some pins do now span enough of the routing track and must be patched. Route track width. Instead of minimum width route, it should be the track width.
This commit is contained in:
parent
bfc8428df7
commit
8d2804b9cb
|
|
@ -30,9 +30,26 @@ class pin_layout:
|
|||
return "({} layer={} ll={} ur={})".format(self.name,self.layer,self.rect[0],self.rect[1])
|
||||
|
||||
def __repr__(self):
|
||||
""" override print function output """
|
||||
return "({} layer={} ll={} ur={})".format(self.name,self.layer,self.rect[0],self.rect[1])
|
||||
"""
|
||||
override repr function output (don't include
|
||||
name since pin shapes could have same shape but diff name e.g. blockage vs A)
|
||||
"""
|
||||
return "(layer={} ll={} ur={})".format(self.layer,self.rect[0],self.rect[1])
|
||||
|
||||
def __hash__(self):
|
||||
""" Implement the hash function for sets etc. """
|
||||
return hash(repr(self))
|
||||
|
||||
def __lt__(self, other):
|
||||
""" Provide a function for ordering items by the ll point """
|
||||
(ll, ur) = self.rect
|
||||
(oll, our) = other.rect
|
||||
|
||||
if ll.x < oll.x and ll.y < oll.y:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def __eq__(self, other):
|
||||
""" Check if these are the same pins for duplicate checks """
|
||||
if isinstance(other, self.__class__):
|
||||
|
|
@ -71,6 +88,10 @@ class pin_layout:
|
|||
""" Check if a shape overlaps with a rectangle """
|
||||
(ll,ur) = self.rect
|
||||
(oll,our) = other.rect
|
||||
|
||||
# Can only overlap on the same layer
|
||||
if self.layer != other.layer:
|
||||
return False
|
||||
|
||||
# Start assuming no overlaps
|
||||
x_overlaps = False
|
||||
|
|
|
|||
|
|
@ -87,15 +87,15 @@ class grid:
|
|||
self.target.append(n)
|
||||
|
||||
|
||||
def add_source(self,track_list):
|
||||
def add_source(self,track_list,value=True):
|
||||
debug.info(3,"Adding source list={0}".format(str(track_list)))
|
||||
for n in track_list:
|
||||
debug.info(4,"Adding source ={0}".format(str(n)))
|
||||
self.set_source(n)
|
||||
self.set_source(n,value)
|
||||
self.set_blocked(n,False)
|
||||
|
||||
|
||||
def set_target(self,track_list,value=True):
|
||||
def add_target(self,track_list,value=True):
|
||||
debug.info(3,"Adding target list={0}".format(str(track_list)))
|
||||
for n in track_list:
|
||||
debug.info(4,"Adding target ={0}".format(str(n)))
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ class grid_cell:
|
|||
visited, etc.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.visited = False
|
||||
self.path = False
|
||||
self.blocked = False
|
||||
self.source = False
|
||||
|
|
@ -17,7 +16,6 @@ class grid_cell:
|
|||
Reset the dynamic info about routing. The pins/blockages are not reset so
|
||||
that they can be reused.
|
||||
"""
|
||||
self.visited=False
|
||||
self.min_cost=-1
|
||||
self.min_path=None
|
||||
self.blocked=False
|
||||
|
|
|
|||
|
|
@ -40,18 +40,18 @@ class router:
|
|||
self.pins = {}
|
||||
# A set of connected pin groups
|
||||
self.pin_groups = {}
|
||||
# The corresponding sets of grids for each pin
|
||||
self.pin_grids = {}
|
||||
# The set of partially covered pins to avoid for each pin
|
||||
self.pin_partials = {}
|
||||
# The corresponding sets (components) of grids for each pin
|
||||
self.pin_components = {}
|
||||
# A set of blocked grids
|
||||
self.blocked_grids = set()
|
||||
|
||||
# A list of pin layout shapes that are blocked
|
||||
self.blockages=[]
|
||||
|
||||
# A list of paths that are blocked
|
||||
# A list of paths that have been "routed"
|
||||
self.paths = []
|
||||
# The list of supply rails that may be routed
|
||||
self.supply_rails = []
|
||||
|
||||
# The boundary will determine the limits to the size of the routing grid
|
||||
self.boundary = self.layout.measureBoundary(self.top_name)
|
||||
|
|
@ -134,16 +134,16 @@ class router:
|
|||
Retrieve the pin shapes from the layout.
|
||||
"""
|
||||
shape_list=self.layout.getAllPinShapesByLabel(str(pin_name))
|
||||
pin_list = []
|
||||
pin_set = set()
|
||||
for shape in shape_list:
|
||||
(name,layer,boundary)=shape
|
||||
rect = [vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])]
|
||||
pin = pin_layout(pin_name, rect, layer)
|
||||
debug.info(2,"Found pin {}".format(str(pin)))
|
||||
pin_list.append(pin)
|
||||
pin_set.add(pin)
|
||||
|
||||
debug.check(len(pin_list)>0,"Did not find any pin shapes for {0}.".format(str(pin)))
|
||||
self.pins[pin_name] = pin_list
|
||||
debug.check(len(pin_set)>0,"Did not find any pin shapes for {0}.".format(str(pin_name)))
|
||||
self.pins[pin_name] = pin_set
|
||||
|
||||
def find_pins(self,pin_name):
|
||||
"""
|
||||
|
|
@ -175,8 +175,7 @@ class router:
|
|||
"""
|
||||
self.pins = {}
|
||||
self.pin_groups = {}
|
||||
self.pin_grids = {}
|
||||
self.pin_partials = {}
|
||||
self.pin_components = {}
|
||||
# DO NOT clear the blockages as these don't change
|
||||
self.rg.reinit()
|
||||
|
||||
|
|
@ -409,7 +408,7 @@ class router:
|
|||
track in the track and leaves half a DRC space in each direction.
|
||||
"""
|
||||
# space depends on which layer it is
|
||||
if track[2]==0:
|
||||
if self.get_layer(track[2])==self.horiz_layer_name:
|
||||
space = 0.5*self.horiz_layer_spacing
|
||||
else:
|
||||
space = 0.5*self.vert_layer_spacing
|
||||
|
|
@ -444,34 +443,40 @@ class router:
|
|||
"""
|
||||
Analyze the shapes of a pin and combine them into groups which are connected.
|
||||
"""
|
||||
pin_list = self.pins[pin_name]
|
||||
|
||||
pin_set = self.pins[pin_name]
|
||||
local_debug=False
|
||||
# Put each pin in an equivalence class of it's own
|
||||
equiv_classes = [[x] for x in pin_list]
|
||||
#print("INITIAL\n",equiv_classes)
|
||||
equiv_classes = [set([x]) for x in pin_set]
|
||||
if local_debug:
|
||||
print("INITIAL\n",equiv_classes)
|
||||
|
||||
def compare_classes(class1, class2):
|
||||
"""
|
||||
Determine if two classes should be combined and if so return
|
||||
the combined set. Otherwise, return None.
|
||||
"""
|
||||
#print("CL1:\n",class1)
|
||||
#print("CL2:\n",class2)
|
||||
if local_debug:
|
||||
print("CLASS1:\n",class1)
|
||||
print("CLASS2:\n",class2)
|
||||
# Compare each pin in each class,
|
||||
# and if any overlap, return the combined the class
|
||||
for p1 in class1:
|
||||
for p2 in class2:
|
||||
if p1.overlaps(p2):
|
||||
combined_class = class1+class2
|
||||
#print("COM:",pformat(combined_class))
|
||||
combined_class = class1 | class2
|
||||
if local_debug:
|
||||
print("COMBINE:",pformat(combined_class))
|
||||
return combined_class
|
||||
|
||||
|
||||
if local_debug:
|
||||
print("NO COMBINE")
|
||||
return None
|
||||
|
||||
|
||||
def combine_classes(equiv_classes):
|
||||
""" Recursive function to combine classes. """
|
||||
#print("\nRECURSE:\n",pformat(equiv_classes))
|
||||
if local_debug:
|
||||
print("\nRECURSE:\n",pformat(equiv_classes))
|
||||
if len(equiv_classes)==1:
|
||||
return(equiv_classes)
|
||||
|
||||
|
|
@ -490,111 +495,128 @@ class router:
|
|||
return(equiv_classes)
|
||||
|
||||
reduced_classes = combine_classes(equiv_classes)
|
||||
#print("FINAL ",reduced_classes)
|
||||
self.pin_groups[pin_name] = reduced_classes
|
||||
if local_debug:
|
||||
print("FINAL ",reduced_classes)
|
||||
self.pin_groups[pin_name]=reduced_classes
|
||||
|
||||
def convert_pins(self, pin_name):
|
||||
"""
|
||||
Convert the pin groups into pin tracks and blockage tracks
|
||||
"""
|
||||
try:
|
||||
self.pin_grids[pin_name]
|
||||
self.pin_components[pin_name]
|
||||
except:
|
||||
self.pin_grids[pin_name] = []
|
||||
try:
|
||||
self.pin_partials[pin_name]
|
||||
except:
|
||||
self.pin_partials[pin_name] = []
|
||||
self.pin_components[pin_name] = []
|
||||
|
||||
found_pin = False
|
||||
for pg in self.pin_groups[pin_name]:
|
||||
print("PG ",pg)
|
||||
# Keep the same groups for each pin
|
||||
self.pin_grids[pin_name].append(set())
|
||||
self.pin_partials[pin_name].append(set())
|
||||
|
||||
pin_set = set()
|
||||
partial_set = set()
|
||||
blockage_set = set()
|
||||
for pin in pg:
|
||||
debug.info(2,"Converting {0}".format(pin))
|
||||
debug.info(2," Converting {0}".format(pin))
|
||||
(pin_in_tracks,partial_in_tracks)=self.convert_pin_to_tracks(pin)
|
||||
# In the blockages, what did this shape expand as?
|
||||
blockage_in_tracks = self.convert_blockage(pin)
|
||||
# At least one of the groups must have some valid tracks
|
||||
if (len(pin_in_tracks)>0):
|
||||
found_pin = True
|
||||
pin_set.update(pin_in_tracks)
|
||||
partial_set.update(partial_in_tracks)
|
||||
partial_set.update(blockage_in_tracks)
|
||||
pin_set.update(partial_in_tracks)
|
||||
|
||||
blockage_set.update(blockage_in_tracks)
|
||||
|
||||
debug.info(2," grids {}".format(pin_set))
|
||||
debug.info(2," parts {}".format(partial_set))
|
||||
debug.info(2," pins {}".format(pin_set))
|
||||
debug.info(2," blocks {}".format(blockage_set))
|
||||
|
||||
# We can just block all of the partials, so combine the groups
|
||||
self.pin_partials[pin_name][-1].add(frozenset(partial_set))
|
||||
# We need to route each of the classes, so don't combine the groups
|
||||
self.pin_grids[pin_name][-1].add(frozenset(pin_set))
|
||||
|
||||
# This happens when a shape is covered partially by one shape and fully by another
|
||||
self.pin_partials[pin_name][-1].difference_update(pin_set)
|
||||
# At least one of the groups must have some valid tracks
|
||||
if (len(pin_set) == 0):
|
||||
self.write_debug_gds()
|
||||
debug.error("Unable to find pin on grid.",-1)
|
||||
|
||||
# We need to route each of the components, so don't combine the groups
|
||||
self.pin_components[pin_name].append(pin_set)
|
||||
|
||||
# These will be blocked depending on what we are routing
|
||||
# Add all of the blocked grids to the set for the design
|
||||
self.blocked_grids.update(blockage_set)
|
||||
|
||||
# Remove the pins from the blockages since we didn't know
|
||||
# they were pins when processing blockages
|
||||
self.blocked_grids.difference_update(pin_set)
|
||||
self.blocked_grids.difference_update(partial_set)
|
||||
|
||||
|
||||
if not found_pin:
|
||||
self.write_debug_gds()
|
||||
debug.error("Unable to find pin on grid.",-1)
|
||||
|
||||
def add_pin(self, pin_name, is_source=False):
|
||||
def add_source(self, pin_name):
|
||||
"""
|
||||
This will mark the grids for all pin components as a source or a target.
|
||||
This will mark the grids for all pin components as a source.
|
||||
Marking as source or target also clears blockage status.
|
||||
"""
|
||||
for i in range(self.num_pin_components(pin_name)):
|
||||
self.add_pin_component(pin_name, i, is_source)
|
||||
self.add_pin_component_source(pin_name, i)
|
||||
|
||||
def add_target(self, pin_name):
|
||||
"""
|
||||
This will mark the grids for all pin components as a target.
|
||||
Marking as source or target also clears blockage status.
|
||||
"""
|
||||
for i in range(self.num_pin_components(pin_name)):
|
||||
self.add_pin_component_target(pin_name, i)
|
||||
|
||||
def num_pin_components(self, pin_name):
|
||||
"""
|
||||
This returns how many disconnected pin components there are.
|
||||
"""
|
||||
debug.check(len(self.pin_grids[pin_name]) == len(self.pin_partials[pin_name]),
|
||||
"Pin grid and partial blockage component sizes don't match.")
|
||||
return len(self.pin_grids[pin_name])
|
||||
return len(self.pin_components[pin_name])
|
||||
|
||||
def add_pin_component(self, pin_name, index, is_source=False):
|
||||
def add_pin_component_source(self, pin_name, index):
|
||||
"""
|
||||
This will mark only the pin tracks from the indexed pin component as a source/target.
|
||||
This will mark only the pin tracks from the indexed pin component as a source.
|
||||
It also unsets it as a blockage.
|
||||
"""
|
||||
debug.check(index<self.num_pin_components(pin_name),"Pin component index too large.")
|
||||
|
||||
pin_in_tracks = self.pin_grids[pin_name][index]
|
||||
if is_source:
|
||||
debug.info(1,"Set source: " + str(pin_name) + " " + str(pin_in_tracks))
|
||||
self.rg.add_source(pin_in_tracks)
|
||||
else:
|
||||
debug.info(1,"Set target: " + str(pin_name) + " " + str(pin_in_tracks))
|
||||
self.rg.add_target(pin_in_tracks)
|
||||
pin_in_tracks = self.pin_components[pin_name][index]
|
||||
debug.info(1,"Set source: " + str(pin_name) + " " + str(pin_in_tracks))
|
||||
self.rg.add_source(pin_in_tracks)
|
||||
|
||||
|
||||
def add_pin_component_target(self, pin_name, index):
|
||||
"""
|
||||
This will mark only the pin tracks from the indexed pin component as a target.
|
||||
It also unsets it as a blockage.
|
||||
"""
|
||||
debug.check(index<self.num_pin_components(pin_name),"Pin component index too large.")
|
||||
|
||||
pin_in_tracks = self.pin_components[pin_name][index]
|
||||
debug.info(1,"Set target: " + str(pin_name) + " " + str(pin_in_tracks))
|
||||
self.rg.add_target(pin_in_tracks)
|
||||
|
||||
|
||||
def add_supply_rail_target(self, pin_name):
|
||||
"""
|
||||
Add the supply rails of given name as a routing target.
|
||||
"""
|
||||
for i in range(self.num_rails):
|
||||
if self.paths[i].name == pin_name:
|
||||
rail = self.paths[i]
|
||||
for wave_index in range(len(rail)):
|
||||
pin_in_tracks = rail[wave_index]
|
||||
#debug.info(1,"Set target: " + str(pin_name) + " " + str(pin_in_tracks))
|
||||
self.rg.set_target(pin_in_tracks)
|
||||
|
||||
for rail in self.supply_rails:
|
||||
if rail.name != pin_name:
|
||||
continue
|
||||
for wave_index in range(len(rail)):
|
||||
pin_in_tracks = rail[wave_index]
|
||||
#debug.info(1,"Set target: " + str(pin_name) + " " + str(pin_in_tracks))
|
||||
self.rg.set_target(pin_in_tracks)
|
||||
self.rg.set_blocked(pin_in_tracks,False)
|
||||
|
||||
def set_supply_rail_blocked(self, value=True):
|
||||
"""
|
||||
Add the supply rails of given name as a routing target.
|
||||
"""
|
||||
for rail in self.supply_rails:
|
||||
for wave_index in range(len(rail)):
|
||||
pin_in_tracks = rail[wave_index]
|
||||
#debug.info(1,"Set target: " + str(pin_name) + " " + str(pin_in_tracks))
|
||||
self.rg.set_blocked(pin_in_tracks,value)
|
||||
|
||||
def set_component_blockages(self, pin_name, value=True):
|
||||
"""
|
||||
Block all of the pin components.
|
||||
"""
|
||||
for component in self.pin_grids[pin_name]:
|
||||
for component in self.pin_components[pin_name]:
|
||||
self.set_blockages(component, value)
|
||||
|
||||
|
||||
|
|
@ -671,8 +693,7 @@ class router:
|
|||
debug.info(4,"Set path: " + str(path))
|
||||
|
||||
# Keep track of path for future blockages
|
||||
self.paths.append(path)
|
||||
path.set_blocked()
|
||||
#path.set_blocked()
|
||||
|
||||
# This is marked for debug
|
||||
path.set_path()
|
||||
|
|
@ -699,8 +720,26 @@ class router:
|
|||
# This assumes 1-track wide again
|
||||
abs_path = [self.convert_point_to_units(x[0]) for x in path]
|
||||
debug.info(1,str(abs_path))
|
||||
self.cell.add_route(self.layers,abs_path)
|
||||
|
||||
# If we had a single grid route (source was equal to target)
|
||||
self.add_enclosure(abs_path[0])
|
||||
# Otherwise, add teh route and final enclosure
|
||||
if len(abs_path)>1:
|
||||
self.cell.add_route(self.layers,abs_path)
|
||||
self.add_enclosure(abs_path[-1])
|
||||
|
||||
def add_enclosure(self, loc):
|
||||
"""
|
||||
Add a metal enclosure that is the size of the routing grid minus a spacing on each side.
|
||||
"""
|
||||
(ll,ur) = self.convert_track_to_pin(loc)
|
||||
self.cell.add_rect_center(layer=self.get_layer(loc.z),
|
||||
offset=vector(loc.x,loc.y),
|
||||
width=ur.x-ll.x,
|
||||
height=ur.y-ll.y)
|
||||
|
||||
|
||||
|
||||
def add_via(self,loc,size=1):
|
||||
"""
|
||||
Add a via centered at the current location
|
||||
|
|
@ -761,8 +800,9 @@ class router:
|
|||
if prev_inertia!=next_inertia:
|
||||
newpath.append(path[i])
|
||||
|
||||
# always add the last path
|
||||
newpath.append(path[-1])
|
||||
# always add the last path unless it was a single point
|
||||
if len(path)>1:
|
||||
newpath.append(path[-1])
|
||||
return newpath
|
||||
|
||||
|
||||
|
|
@ -783,6 +823,7 @@ class router:
|
|||
if path:
|
||||
debug.info(1,"Found path: cost={0} ".format(cost))
|
||||
debug.info(2,str(path))
|
||||
self.paths.append(path)
|
||||
self.add_route(path)
|
||||
else:
|
||||
self.write_debug_gds()
|
||||
|
|
|
|||
|
|
@ -64,15 +64,21 @@ class signal_grid(grid):
|
|||
# over-ridden if the route fails due to pruning a feasible solution.
|
||||
cost_bound = detour_scale*self.cost_to_target(self.source[0])*grid.PREFERRED_COST
|
||||
|
||||
# Check if something in the queue is already a source and a target!
|
||||
for s in self.source:
|
||||
if self.is_target(s):
|
||||
return((grid_path([vector3d(s)]),0))
|
||||
|
||||
# Make sure the queue is empty if we run another route
|
||||
while len(self.q)>0:
|
||||
heappop(self.q)
|
||||
|
||||
|
||||
# Put the source items into the queue
|
||||
self.init_queue()
|
||||
cheapest_path = None
|
||||
cheapest_cost = None
|
||||
|
||||
|
||||
|
||||
# Keep expanding and adding to the priority queue until we are done
|
||||
while len(self.q)>0:
|
||||
# should we keep the path in the queue as well or just the final node?
|
||||
|
|
|
|||
|
|
@ -67,16 +67,16 @@ class signal_router(router):
|
|||
|
||||
# Now add the blockages
|
||||
self.set_blockages(self.blocked_grids,True)
|
||||
self.set_blockages(self.pin_partial[src],True)
|
||||
self.set_blockages(self.pin_partial[dest],True)
|
||||
#self.set_blockages(self.pin_partials[src],True)
|
||||
#self.set_blockages(self.pin_partials[dest],True)
|
||||
|
||||
# Add blockages from previous paths
|
||||
self.set_path_blockages()
|
||||
|
||||
|
||||
# Now add the src/tgt if they are not blocked by other shapes
|
||||
self.add_pin(src,True)
|
||||
self.add_pin(dest,False)
|
||||
self.add_source(src)
|
||||
self.add_target(dest)
|
||||
|
||||
if not self.run_router(detour_scale):
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ class supply_grid(signal_grid):
|
|||
|
||||
def reinit(self):
|
||||
""" Reinitialize everything for a new route. """
|
||||
|
||||
self.source = []
|
||||
self.target = []
|
||||
# Reset all the cells in the map
|
||||
for p in self.map.values():
|
||||
p.reset()
|
||||
|
|
|
|||
|
|
@ -65,21 +65,29 @@ class supply_router(router):
|
|||
self.find_pins(self.gnd_name)
|
||||
|
||||
# Add the supply rails in a mesh network and connect H/V with vias
|
||||
self.prepare_blockages(block_names=[self.vdd_name],unblock_names=[self.gnd_name])
|
||||
# Block everything
|
||||
self.prepare_blockages()
|
||||
# Clear the rail we're routing
|
||||
self.set_blockages(self.pin_components[self.gnd_name],False)
|
||||
# Determine the rail locations
|
||||
self.route_supply_rails(self.gnd_name,0)
|
||||
|
||||
self.prepare_blockages(block_names=[self.gnd_name],unblock_names=[self.vdd_name])
|
||||
# Block everything
|
||||
self.prepare_blockages()
|
||||
# Clear the rail we're routing
|
||||
self.set_blockages(self.pin_components[self.vdd_name],False)
|
||||
# Determine the rail locations
|
||||
self.route_supply_rails(self.vdd_name,1)
|
||||
|
||||
|
||||
# Route the supply pins to the supply rails
|
||||
#self.route_pins_to_rails(gnd_name)
|
||||
#self.route_pins_to_rails(vdd_name)
|
||||
self.route_pins_to_rails(gnd_name)
|
||||
self.route_pins_to_rails(vdd_name)
|
||||
|
||||
self.write_debug_gds()
|
||||
return False
|
||||
return True
|
||||
|
||||
def prepare_blockages(self, block_names=None, unblock_names=None):
|
||||
def prepare_blockages(self):
|
||||
"""
|
||||
Reset and add all of the blockages in the design.
|
||||
Names is a list of pins to add as a blockage.
|
||||
|
|
@ -87,55 +95,72 @@ class supply_router(router):
|
|||
# Start fresh. Not the best for run-time, but simpler.
|
||||
self.clear_blockages()
|
||||
# This adds the initial blockges of the design
|
||||
print("BLOCKING:",self.blocked_grids)
|
||||
#print("BLOCKING:",self.blocked_grids)
|
||||
self.set_blockages(self.blocked_grids,True)
|
||||
# This is conservative to prevent DRC violations on partially blocked tracks
|
||||
if block_names:
|
||||
for name in block_names:
|
||||
# These are the partially blocked tracks around supply pins.
|
||||
print("BLOCKING PARTIALS:",name,self.pin_partials[name])
|
||||
self.set_blockages(self.pin_partials[name],True)
|
||||
# These are the actual supply pins
|
||||
self.set_blockages(self.pin_grids[name],True)
|
||||
print("BLOCKING GRIDS:",name,self.pin_grids[name])
|
||||
# This will unblock
|
||||
if unblock_names:
|
||||
for name in unblock_names:
|
||||
# These are the partially blocked tracks around supply pins.
|
||||
self.set_blockages(self.pin_partials[name],False)
|
||||
print("UNBLOCKING PARTIALS:",name,self.pin_partials[name])
|
||||
# These are the actual supply pins
|
||||
self.set_blockages(self.pin_grids[name],False)
|
||||
print("UNBLOCKING GRIDS:",name,self.pin_grids[name])
|
||||
|
||||
|
||||
# Block all of the supply rails (some will be unblocked if they're a target)
|
||||
self.set_supply_rail_blocked(True)
|
||||
|
||||
# Block all of the pin components (some will be unblocked if they're a source/target)
|
||||
for name in self.pin_components.keys():
|
||||
self.set_blockages(self.pin_components[name],True)
|
||||
|
||||
# These are the paths that have already been routed.
|
||||
self.set_path_blockages()
|
||||
|
||||
def connect_supply_rails(self, name):
|
||||
"""
|
||||
Add vias between overlapping supply rails.
|
||||
Determine which supply rails overlap and can accomodate a via.
|
||||
Remove any paths that do not have a via since they are disconnected.
|
||||
"""
|
||||
paths = [x for x in self.paths if x.name == name]
|
||||
|
||||
|
||||
# Split into horizontal and vertical
|
||||
vertical_paths = [x for x in paths if x[0][0].z==1]
|
||||
horizontal_paths = [x for x in paths if x[0][0].z==0]
|
||||
|
||||
shared_areas = []
|
||||
for v in vertical_paths:
|
||||
for h in horizontal_paths:
|
||||
vertical_paths = [(i,x) for i,x in enumerate(self.supply_rails) if x[0][0].z==1 and x.name==name]
|
||||
horizontal_paths = [(i,x) for i,x in enumerate(self.supply_rails) if x[0][0].z==0 and x.name==name]
|
||||
|
||||
# Flag to see if the paths have a via
|
||||
via_flag = [False] * len(self.supply_rails)
|
||||
# Ignore the other nets that we aren't considering
|
||||
for i,p in enumerate(self.supply_rails):
|
||||
if p.name != name:
|
||||
via_flag[i]=True
|
||||
|
||||
# Compute a list of "shared areas" that are bigger than a via
|
||||
via_areas = []
|
||||
for vindex,v in vertical_paths:
|
||||
for hindex,h in horizontal_paths:
|
||||
# Compute the overlap of the two paths, None if no overlap
|
||||
overlap = v.overlap(h)
|
||||
if overlap:
|
||||
(ll,ur) = overlap
|
||||
# Only add if the overlap is wide enough
|
||||
# We can add a via only if it is a full track width in each dimension
|
||||
if ur.x-ll.x >= self.rail_track_width-1 and ur.y-ll.y >= self.rail_track_width-1:
|
||||
shared_areas.append(overlap)
|
||||
via_flag[vindex]=True
|
||||
via_flag[hindex]=True
|
||||
via_areas.append(overlap)
|
||||
|
||||
|
||||
for (ll,ur) in shared_areas:
|
||||
# Go through and add the vias at the center of the intersection
|
||||
for (ll,ur) in via_areas:
|
||||
center = (ll + ur).scale(0.5,0.5,0)
|
||||
self.add_via(center,self.rail_track_width)
|
||||
|
||||
# Remove the paths that have not been connected by any via
|
||||
remove_indices = [i for i,x in enumerate(via_flag) if not x]
|
||||
for index in remove_indices:
|
||||
debug.info(1,"Removing disconnected supply rail {}".format(self.supply_rails[index]))
|
||||
del self.supply_rails[index]
|
||||
|
||||
def add_supply_rails(self, name):
|
||||
"""
|
||||
Add the shapes that represent the routed supply rails.
|
||||
This is after the paths have been pruned and only include rails that are
|
||||
connected with vias.
|
||||
"""
|
||||
for wave_path in self.supply_rails:
|
||||
if wave_path.name == name:
|
||||
self.add_wavepath(name, wave_path)
|
||||
|
||||
|
||||
|
||||
def route_supply_rails(self, name, supply_number):
|
||||
|
|
@ -154,7 +179,7 @@ class supply_router(router):
|
|||
wave = [vector3d(0,offset+i,0) for i in range(self.rail_track_width)]
|
||||
# While we can keep expanding east in this horizontal track
|
||||
while wave and wave[0].x < max_xoffset:
|
||||
wave = self.route_supply_rail(name, wave, direction.EAST)
|
||||
wave = self.find_supply_rail(name, wave, direction.EAST)
|
||||
|
||||
|
||||
# Vertical supply rails
|
||||
|
|
@ -164,16 +189,14 @@ class supply_router(router):
|
|||
wave = [vector3d(offset+i,0,1) for i in range(self.rail_track_width)]
|
||||
# While we can keep expanding north in this vertical track
|
||||
while wave and wave[0].y < max_yoffset:
|
||||
wave = self.route_supply_rail(name, wave, direction.NORTH)
|
||||
wave = self.find_supply_rail(name, wave, direction.NORTH)
|
||||
|
||||
# Remember index of path size which is how many rails we had at the start
|
||||
self.num_rails = len(self.paths)
|
||||
|
||||
# Add teh supply rail vias
|
||||
# Add the supply rail vias (and prune disconnected rails)
|
||||
self.connect_supply_rails(name)
|
||||
# Add the rails themselves
|
||||
self.add_supply_rails(name)
|
||||
|
||||
|
||||
def route_supply_rail(self, name, seed_wave, direct):
|
||||
def find_supply_rail(self, name, seed_wave, direct):
|
||||
"""
|
||||
This finds the first valid starting location and routes a supply rail
|
||||
in the given direction.
|
||||
|
|
@ -191,12 +214,9 @@ class supply_router(router):
|
|||
if not wave_path:
|
||||
return None
|
||||
|
||||
# Filter any path that won't span 2 rails
|
||||
# so that we can guarantee it is connected
|
||||
if len(wave_path)>=2*self.rail_track_width:
|
||||
self.add_wavepath(name, wave_path)
|
||||
wave_path.name = name
|
||||
self.paths.append(wave_path)
|
||||
self.supply_rails.append(wave_path)
|
||||
|
||||
# seed the next start wave location
|
||||
wave_end = wave_path[-1]
|
||||
|
|
@ -206,26 +226,27 @@ class supply_router(router):
|
|||
|
||||
|
||||
|
||||
def route_pins_to_rails(self,pin_name):
|
||||
def route_pins_to_rails(self, pin_name):
|
||||
"""
|
||||
This will route each of the pin components to the supply rails.
|
||||
After it is done, the cells are added to the pin blockage list.
|
||||
"""
|
||||
|
||||
|
||||
num_components = self.num_pin_components(pin_name)
|
||||
debug.info(0,"Pin {0} has {1} components to route.".format(pin_name, num_components))
|
||||
|
||||
# For every component
|
||||
for index in range(self.num_pin_components(pin_name)):
|
||||
for index in range(num_components):
|
||||
debug.info(0,"Routing component {0} {1}".format(pin_name, index))
|
||||
|
||||
self.rg.reinit()
|
||||
|
||||
self.prepare_blockages(block_names=None,unblock_names=[pin_name])
|
||||
|
||||
# Block all the pin components first
|
||||
self.set_component_blockages(pin_name, True)
|
||||
|
||||
self.prepare_blockages()
|
||||
|
||||
# Add the single component of the pin as the source
|
||||
# which unmarks it as a blockage too
|
||||
self.add_pin_component(pin_name,index,is_source=True)
|
||||
self.add_pin_component_source(pin_name,index)
|
||||
|
||||
# Add all of the rails as targets
|
||||
# Don't add the other pins, but we could?
|
||||
|
|
@ -234,7 +255,10 @@ class supply_router(router):
|
|||
# Actually run the A* router
|
||||
self.run_router(detour_scale=5)
|
||||
|
||||
|
||||
#if index==1:
|
||||
# self.write_debug_gds()
|
||||
# import sys
|
||||
# sys.exit(1)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class no_blockages_test(openram_test):
|
|||
self.connect_inst(cell.pin_map.keys())
|
||||
|
||||
r=router(module=cell)
|
||||
layer_stack =("metal3","via2","metal2")
|
||||
layer_stack =("metal3","via3","metal4")
|
||||
self.assertTrue(r.route(self,layer_stack))
|
||||
|
||||
r=routing("10_supply_grid_test_{0}".format(OPTS.tech_name))
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ word_size = 1
|
|||
num_words = 16
|
||||
num_banks = 1
|
||||
|
||||
tech_name = "scn3me_subm"
|
||||
tech_name = "scn4m_subm"
|
||||
process_corners = ["TT"]
|
||||
supply_voltages = [5.0]
|
||||
temperatures = [25]
|
||||
|
|
|
|||
|
|
@ -43,9 +43,9 @@ def write_magic_script(cell_name, gds_name, extract=False):
|
|||
# (e.g. with routes)
|
||||
f.write("flatten {}_new\n".format(cell_name))
|
||||
f.write("load {}_new\n".format(cell_name))
|
||||
#f.write("cellname rename {0}_new {0}\n".format(cell_name))
|
||||
#f.write("load {}\n".format(cell_name))
|
||||
f.write("writeall force {0}_new\n".format(cell_name))
|
||||
f.write("cellname rename {0}_new {0}\n".format(cell_name))
|
||||
f.write("load {}\n".format(cell_name))
|
||||
f.write("writeall force\n")
|
||||
f.write("drc check\n")
|
||||
f.write("drc catchup\n")
|
||||
f.write("drc count total\n")
|
||||
|
|
|
|||
|
|
@ -546,7 +546,7 @@ drDefinePacket(
|
|||
( display background stipple1 lineStyle0 black black outlineStipple)
|
||||
( display y9 stipple0 solid silver silver solid )
|
||||
( display Metal3Net dots4 solid navy navy outlineStipple)
|
||||
( display Metal3Net dots4 solid tan tan outlineStipple)
|
||||
( display Metal4Net dots4 solid tan tan outlineStipple)
|
||||
( display A1 stipple0 lineStyle0 winBack winBack solid )
|
||||
( display pin solid lineStyle0 red red solid )
|
||||
( display XPNet blank solid yellow yellow outline )
|
||||
|
|
@ -640,6 +640,7 @@ drDefinePacket(
|
|||
( display Canplace blank solid cyan cyan outline )
|
||||
( display annotate7 stipple0 solid red red solid )
|
||||
( display Via2 solid solid navy navy solid )
|
||||
( display Via3 solid solid tan tan solid )
|
||||
( display Metal2Pin stipple0 lineStyle0 magenta magenta solid )
|
||||
( display annotate4 stipple0 solid yellow yellow solid )
|
||||
( display device1 stipple1 lineStyle0 green green outlineStipple)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import os
|
||||
CWD = os.environ.get("OPENRAM_TECH") + "/scn3me_subm/tf"
|
||||
CWD = os.environ.get("OPENRAM_TECH") + "/scn4m_subm/tf"
|
||||
ui().importCds("default", CWD+"/display.drf", CWD+"/mosis.tf", 1000, 1, CWD+"/layers.map")
|
||||
|
||||
|
||||
|
|
@ -147,6 +147,8 @@ layerDefinitions(
|
|||
( Metal2 drawing )
|
||||
( Via2 drawing )
|
||||
( Metal3 drawing )
|
||||
( Via3 drawing )
|
||||
( Metal4 drawing )
|
||||
( annotate drawing )
|
||||
( annotate drawing1 )
|
||||
( annotate drawing2 )
|
||||
|
|
@ -161,6 +163,7 @@ layerDefinitions(
|
|||
( Metal1 pin )
|
||||
( Metal2 pin )
|
||||
( Metal3 pin )
|
||||
( Metal4 pin )
|
||||
( Glass drawing )
|
||||
( XP drawing )
|
||||
( prBoundary drawing )
|
||||
|
|
@ -203,6 +206,8 @@ layerDefinitions(
|
|||
( Via net )
|
||||
( Metal3 net )
|
||||
( Via2 net )
|
||||
( Metal4 net )
|
||||
( Via3 net )
|
||||
( pin label )
|
||||
( text drawing )
|
||||
( pin drawing )
|
||||
|
|
@ -313,11 +318,14 @@ layerDefinitions(
|
|||
( annotate drawing9 annotate9 t t nil t nil )
|
||||
( Via2 drawing Via2 t t t t t )
|
||||
( Metal3 drawing Metal3 t t t t t )
|
||||
( Via3 drawing Via3 t t t t t )
|
||||
( Metal4 drawing Metal4 t t t t t )
|
||||
( Glass drawing Glass t t t nil t )
|
||||
( XP drawing XP t t t nil t )
|
||||
( Metal1 pin Metal1Pin t t t nil t )
|
||||
( Metal2 pin Metal2Pin t t t nil t )
|
||||
( Metal3 pin Metal3Pin t t t nil t )
|
||||
( Metal4 pin Metal4Pin t t t nil t )
|
||||
( Poly1 pin Poly1Pin t t t nil t )
|
||||
( prBoundary drawing prBoundary t t nil t nil )
|
||||
( prBoundary boundary prBoundaryBnd t t nil t nil )
|
||||
|
|
@ -356,6 +364,7 @@ layerDefinitions(
|
|||
( device annotate deviceAnt t t t t nil )
|
||||
( Metal2 net Metal2Net t t t nil nil )
|
||||
( Metal3 net Metal3Net t t t nil nil )
|
||||
( Metal4 net Metal4Net t t t nil nil )
|
||||
( device label deviceLbl t t t t nil )
|
||||
( Via net ViaNet t t t nil nil )
|
||||
( Via2 net Via2Net t t t nil nil )
|
||||
|
|
|
|||
Loading…
Reference in New Issue