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.grids = pg1.grids | pg2.grids # OR the set of grid locations
self.secondary_grids = pg1.secondary_grids | pg2.secondary_grids 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): def add_enclosure(self, cell):
""" """
Add the enclosure shape to the given 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 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 from globals import OPTS,print_time
from pprint import pformat from pprint import pformat
import grid_utils import grid_utils
from datetime import datetime
class router(router_tech): 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 # If didn't specify a gds blockage file, write it out to read the gds
# This isn't efficient, but easy for now # This isn't efficient, but easy for now
#start_time = datetime.now()
if not gds_filename: if not gds_filename:
gds_filename = OPTS.openram_temp+"temp.gds" gds_filename = OPTS.openram_temp+"temp.gds"
self.cell.gds_write(gds_filename) self.cell.gds_write(gds_filename)
# Load the gds file and read in all the shapes # Load the gds file and read in all the shapes
self.layout = gdsMill.VlsiLayout(units=GDS["unit"]) self.layout = gdsMill.VlsiLayout(units=GDS["unit"])
self.reader = gdsMill.Gds2reader(self.layout) self.reader = gdsMill.Gds2reader(self.layout)
self.reader.loadFromFile(gds_filename) self.reader.loadFromFile(gds_filename)
self.top_name = self.layout.rootStructureName self.top_name = self.layout.rootStructureName
#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
self.pins = {} self.pins = {}
@ -127,8 +130,12 @@ class router(router_tech):
Pin can either be a label or a location,layer pair: [[x,y],layer]. Pin can either be a label or a location,layer pair: [[x,y],layer].
""" """
debug.info(1,"Finding pins for {}.".format(pin_name)) debug.info(1,"Finding pins for {}.".format(pin_name))
#start_time = datetime.now()
self.retrieve_pins(pin_name) self.retrieve_pins(pin_name)
#print_time("Retrieved pins",datetime.now(), start_time)
#start_time = datetime.now()
self.analyze_pins(pin_name) self.analyze_pins(pin_name)
#print_time("Analyzed pins",datetime.now(), start_time)
def find_blockages(self): def find_blockages(self):
""" """
@ -152,97 +159,98 @@ class router(router_tech):
self.find_pins(pin) self.find_pins(pin)
# This will get all shapes as blockages and convert to grid units # 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() self.find_blockages()
#print_time("Find blockags",datetime.now(), start_time)
# Convert the blockages to grid units # Convert the blockages to grid units
#start_time = datetime.now()
self.convert_blockages() self.convert_blockages()
#print_time("Find blockags",datetime.now(), start_time)
# 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()
for pin in pin_list: for pin in pin_list:
self.convert_pins(pin) self.convert_pins(pin)
#print_time("Convert pins",datetime.now(), start_time)
#start_time = datetime.now()
for pin in pin_list: for pin in pin_list:
self.combine_adjacent_pins(pin) self.combine_adjacent_pins(pin)
#print_time("Combine pins",datetime.now(), start_time)
#self.write_debug_gds("debug_combine_pins.gds",stop_program=True) #self.write_debug_gds("debug_combine_pins.gds",stop_program=True)
# Separate any adjacent grids of differing net names to prevent wide metal DRC violations # Separate any adjacent grids of differing net names to prevent wide metal DRC violations
# Must be done before enclosing pins # Must be done before enclosing pins
#start_time = datetime.now()
self.separate_adjacent_pins(self.supply_rail_space_width) self.separate_adjacent_pins(self.supply_rail_space_width)
#print_time("Separate pins",datetime.now(), start_time)
# For debug # For debug
#self.separate_adjacent_pins(1) #self.separate_adjacent_pins(1)
# Enclose the continguous grid units in a metal rectangle to fix some DRCs # Enclose the continguous grid units in a metal rectangle to fix some DRCs
#start_time = datetime.now()
self.enclose_pins() self.enclose_pins()
#print_time("Enclose pins",datetime.now(), start_time)
#self.write_debug_gds("debug_enclose_pins.gds",stop_program=True) #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 Find pins that have adjacent routing tracks and merge them into a
single pin_group. The pins themselves may not be touching, but single pin_group. The pins themselves may not be touching, but
enclose_pis in the next step will ensure they are touching. enclose_pis in the next step will ensure they are touching.
""" """
debug.info(1,"Combining adjacent pins for {}.".format(pin_name))
# Make a copy since we are going to add to (and then reduce) this list # Find all adjacencies
pin_groups = self.pin_groups[pin_name].copy() adjacent_pins = {}
# Start as None to signal the first iteration
remove_indices = set()
for index1,pg1 in enumerate(self.pin_groups[pin_name]): 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]): for index2,pg2 in enumerate(self.pin_groups[pin_name]):
# Cannot combine with yourself # Cannot combine with yourself, also don't repeat
if index1==index2: if index1<=index2:
continue continue
# Cannot combine more than once
if index2 in remove_indices:
continue
# Combine if at least 1 grid cell is adjacent # Combine if at least 1 grid cell is adjacent
if pg1.adjacent(pg2): if pg1.adjacent(pg2):
combined = pin_group(pin_name, [], self) if not index1 in adjacent_pins.keys():
combined.combine_groups(pg1, pg2) adjacent_pins[index1] = set([index2])
debug.info(3,"Combining {0} {1} {2}:".format(pin_name, index1, index2)) else:
debug.info(3, " {0}\n {1}".format(pg1.pins, pg2.pins)) adjacent_pins[index1].add(index2)
debug.info(3," --> {0}\n {1}".format(combined.pins,combined.grids))
remove_indices.update([index1,index2])
pin_groups.append(combined)
break
# Remove them in decreasing order to not invalidate the indices # Make a list of indices to ensure every group gets in the new set
debug.info(4,"Removing {}".format(sorted(remove_indices))) all_indices = set([x for x in range(len(self.pin_groups[pin_name]))])
for i in sorted(remove_indices, reverse=True):
del pin_groups[i]
# Use the new pin group!
self.pin_groups[pin_name] = pin_groups
removed_pairs = int(len(remove_indices)/2) # Now reconstruct the new groups
debug.info(1, "Combined {0} pin pairs for {1}".format(removed_pairs,pin_name)) 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 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): 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)) debug.info(1,"Comparing {0} and {1} adjacency".format(pin_name1, pin_name2))
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]):
# 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) grids_g1, grids_g2 = pg1.adjacent_grids(pg2, separation)
# These should have the same length, so... # These should have the same length, so...
if len(grids_g1)>0: if len(grids_g1)>0:

View File

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