Fix run-time bug in combine adjacent pins for supply router

This commit is contained in:
Matt Guthaus 2018-11-14 17:06:12 -08:00
parent 2f6300c7a0
commit 3cfefa784f
3 changed files with 85 additions and 58 deletions

View File

@ -495,6 +495,16 @@ class pin_group:
self.grids = pg1.grids | pg2.grids # OR the set of grid locations
self.secondary_grids = pg1.secondary_grids | pg2.secondary_grids
def add_group(self, pg):
"""
Combine the pin group into this one. This will add to the first item in the pins
so this should be used before there are disconnected pins.
"""
debug.check(len(self.pins)==1,"Don't know which group to add pins to.")
self.pins[0].update(*pg.pins) # Join the two lists of pins
self.grids |= pg.grids # OR the set of grid locations
self.secondary_grids |= pg.secondary_grids
def add_enclosure(self, cell):
"""
Add the enclosure shape to the given cell.

View File

@ -9,9 +9,10 @@ from pin_layout import pin_layout
from pin_group import pin_group
from vector import vector
from vector3d import vector3d
from globals import OPTS
from globals import OPTS,print_time
from pprint import pformat
import grid_utils
from datetime import datetime
class router(router_tech):
"""
@ -31,16 +32,18 @@ class router(router_tech):
# If didn't specify a gds blockage file, write it out to read the gds
# This isn't efficient, but easy for now
#start_time = datetime.now()
if not gds_filename:
gds_filename = OPTS.openram_temp+"temp.gds"
self.cell.gds_write(gds_filename)
# Load the gds file and read in all the shapes
self.layout = gdsMill.VlsiLayout(units=GDS["unit"])
self.reader = gdsMill.Gds2reader(self.layout)
self.reader.loadFromFile(gds_filename)
self.top_name = self.layout.rootStructureName
#print_time("GDS read",datetime.now(), start_time)
### The pin data structures
# A map of pin names to a set of pin_layout structures
self.pins = {}
@ -127,8 +130,12 @@ class router(router_tech):
Pin can either be a label or a location,layer pair: [[x,y],layer].
"""
debug.info(1,"Finding pins for {}.".format(pin_name))
#start_time = datetime.now()
self.retrieve_pins(pin_name)
#print_time("Retrieved pins",datetime.now(), start_time)
#start_time = datetime.now()
self.analyze_pins(pin_name)
#print_time("Analyzed pins",datetime.now(), start_time)
def find_blockages(self):
"""
@ -152,97 +159,98 @@ class router(router_tech):
self.find_pins(pin)
# This will get all shapes as blockages and convert to grid units
# This ignores shapes that were pins
# This ignores shapes that were pins
#start_time = datetime.now()
self.find_blockages()
#print_time("Find blockags",datetime.now(), start_time)
# Convert the blockages to grid units
#start_time = datetime.now()
self.convert_blockages()
#print_time("Find blockags",datetime.now(), start_time)
# This will convert the pins to grid units
# It must be done after blockages to ensure no DRCs between expanded pins and blocked grids
#start_time = datetime.now()
for pin in pin_list:
self.convert_pins(pin)
#print_time("Convert pins",datetime.now(), start_time)
#start_time = datetime.now()
for pin in pin_list:
self.combine_adjacent_pins(pin)
#print_time("Combine pins",datetime.now(), start_time)
#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
# Must be done before enclosing pins
#start_time = datetime.now()
self.separate_adjacent_pins(self.supply_rail_space_width)
#print_time("Separate pins",datetime.now(), start_time)
# For debug
#self.separate_adjacent_pins(1)
# Enclose the continguous grid units in a metal rectangle to fix some DRCs
#start_time = datetime.now()
self.enclose_pins()
#print_time("Enclose pins",datetime.now(), start_time)
#self.write_debug_gds("debug_enclose_pins.gds",stop_program=True)
def combine_adjacent_pins_pass(self, pin_name):
def combine_adjacent_pins(self, pin_name):
"""
Find pins that have adjacent routing tracks and merge them into a
single pin_group. The pins themselves may not be touching, but
enclose_pis in the next step will ensure they are touching.
"""
# Make a copy since we are going to add to (and then reduce) this list
pin_groups = self.pin_groups[pin_name].copy()
# Start as None to signal the first iteration
remove_indices = set()
debug.info(1,"Combining adjacent pins for {}.".format(pin_name))
# Find all adjacencies
adjacent_pins = {}
for index1,pg1 in enumerate(self.pin_groups[pin_name]):
# Cannot combine more than once
if index1 in remove_indices:
continue
for index2,pg2 in enumerate(self.pin_groups[pin_name]):
# Cannot combine with yourself
if index1==index2:
# Cannot combine with yourself, also don't repeat
if index1<=index2:
continue
# Cannot combine more than once
if index2 in remove_indices:
continue
# Combine if at least 1 grid cell is adjacent
if pg1.adjacent(pg2):
combined = pin_group(pin_name, [], self)
combined.combine_groups(pg1, pg2)
debug.info(3,"Combining {0} {1} {2}:".format(pin_name, index1, index2))
debug.info(3, " {0}\n {1}".format(pg1.pins, pg2.pins))
debug.info(3," --> {0}\n {1}".format(combined.pins,combined.grids))
remove_indices.update([index1,index2])
pin_groups.append(combined)
break
if not index1 in adjacent_pins.keys():
adjacent_pins[index1] = set([index2])
else:
adjacent_pins[index1].add(index2)
# Remove them in decreasing order to not invalidate the indices
debug.info(4,"Removing {}".format(sorted(remove_indices)))
for i in sorted(remove_indices, reverse=True):
del pin_groups[i]
# Use the new pin group!
self.pin_groups[pin_name] = pin_groups
# Make a list of indices to ensure every group gets in the new set
all_indices = set([x for x in range(len(self.pin_groups[pin_name]))])
removed_pairs = int(len(remove_indices)/2)
debug.info(1, "Combined {0} pin pairs for {1}".format(removed_pairs,pin_name))
# Now reconstruct the new groups
new_pin_groups = []
for index1,index2_set in adjacent_pins.items():
# Remove the indices if they are added to the new set
all_indices.discard(index1)
all_indices.difference_update(index2_set)
# Create the combined group starting with the first item
combined = self.pin_groups[pin_name][index1]
# Add all of the other items that overlapped
for index2 in index2_set:
pg = self.pin_groups[pin_name][index2]
combined.add_group(pg)
debug.info(3,"Combining {0} {1}:".format(pin_name, index2))
debug.info(3, " {0}\n {1}".format(combined.pins, pg.pins))
debug.info(3," --> {0}\n {1}".format(combined.pins,combined.grids))
new_pin_groups.append(combined)
# Add the pin groups that weren't added to the new set
for index in all_indices:
new_pin_groups.append(self.pin_groups[pin_name][index])
old_size = len(self.pin_groups[pin_name])
# Use the new pin group!
self.pin_groups[pin_name] = 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))
return removed_pairs
def combine_adjacent_pins(self, pin_name):
"""
Make multiple passes of the combine adjacent pins until we have no
more combinations or hit an iteration limit.
"""
debug.info(1,"Combining adjacent pins for {}.".format(pin_name))
# Start as None to signal the first iteration
num_removed_pairs = None
# Just used in case there's a circular combination or something weird
for iteration_count in range(10):
num_removed_pairs = self.combine_adjacent_pins_pass(pin_name)
if num_removed_pairs==0:
break
else:
debug.warning("Did not converge combining adjacent pins in supply router.")
def separate_adjacent_pins(self, separation):
"""
@ -271,7 +279,7 @@ class router(router_tech):
debug.info(1,"Comparing {0} and {1} adjacency".format(pin_name1, pin_name2))
for index1,pg1 in enumerate(self.pin_groups[pin_name1]):
for index2,pg2 in enumerate(self.pin_groups[pin_name2]):
# FIXME: Use separation distance and edge grids only
# FIgXME: 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:

View File

@ -2,13 +2,14 @@ import gdsMill
import tech
import math
import debug
from globals import OPTS
from globals import OPTS,print_time
from contact import contact
from pin_group import pin_group
from pin_layout import pin_layout
from vector3d import vector3d
from router import router
from direction import direction
from datetime import datetime
import grid
import grid_utils
@ -68,10 +69,13 @@ class supply_router(router):
self.compute_supply_rail_dimensions()
# Get the pin shapes
#start_time = datetime.now()
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
#print_time("Pins and blockages",datetime.now(), start_time)
#self.write_debug_gds("pin_enclosures.gds",stop_program=True)
# Add the supply rails in a mesh network and connect H/V with vias
#start_time = datetime.now()
# Block everything
self.prepare_blockages(self.gnd_name)
# Determine the rail locations
@ -82,15 +86,20 @@ class supply_router(router):
# Determine the rail locations
self.route_supply_rails(self.vdd_name,1)
#self.write_debug_gds("debug_rails.gds",stop_program=True)
#print_time("Supply rails",datetime.now(), start_time)
#start_time = datetime.now()
self.route_simple_overlaps(vdd_name)
self.route_simple_overlaps(gnd_name)
#print_time("Simple overlaps",datetime.now(), start_time)
#self.write_debug_gds("debug_simple_route.gds",stop_program=False)
# Route the supply pins to the supply rails
# Route vdd first since we want it to be shorter
#start_time = datetime.now()
self.route_pins_to_rails(vdd_name)
self.route_pins_to_rails(gnd_name)
#print_time("Routing",datetime.now(), start_time)
#self.write_debug_gds("debug_pin_routes.gds",stop_program=True)
#self.write_debug_gds("final.gds",False)