Supply router working, perhaps not efficiently though.

This commit is contained in:
Matt Guthaus 2018-10-05 15:57:34 -07:00
parent eb2304944b
commit 94ab69ea16
5 changed files with 75 additions and 55 deletions

View File

@ -56,7 +56,7 @@ class router:
self.blocked_grids = set() self.blocked_grids = set()
# The corresponding set of partially blocked grids for each component. # The corresponding set of partially blocked grids for each component.
# These are blockages for other nets but unblocked for this component. # These are blockages for other nets but unblocked for this component.
#self.pin_component_blockages = {} self.pin_component_blockages = {}
### The routed data structures ### The routed data structures
# A list of paths that have been "routed" # A list of paths that have been "routed"
@ -152,13 +152,16 @@ class router:
(name,layer,boundary)=shape (name,layer,boundary)=shape
rect = [vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])] rect = [vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])]
pin = pin_layout(pin_name, rect, layer) pin = pin_layout(pin_name, rect, layer)
debug.info(2,"Found pin {}".format(str(pin)))
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)
for pin in self.pins[pin_name]:
debug.info(2,"Found pin {}".format(str(pin)))
def find_pins(self,pin_name): def find_pins(self,pin_name):
""" """
@ -197,6 +200,7 @@ class router:
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 are connected
# This must come before the blockages, so we can ignore metal shapes that are blockages.
for pin in pin_list: for pin in pin_list:
self.find_pins(pin) self.find_pins(pin)
@ -233,8 +237,8 @@ class router:
self.set_blockages(self.pin_components[name],True) self.set_blockages(self.pin_components[name],True)
# Block all of the pin component partial blockages # Block all of the pin component partial blockages
#for name in self.pin_component_blockages.keys(): for name in self.pin_component_blockages.keys():
# self.set_blockages(self.pin_component_blockages[name],True) self.set_blockages(self.pin_component_blockages[name],True)
# These are the paths that have already been routed. # These are the paths that have already been routed.
self.set_path_blockages() self.set_path_blockages()
@ -354,6 +358,7 @@ class router:
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)
@ -732,10 +737,10 @@ class router:
except: except:
self.pin_components[pin_name] = [] self.pin_components[pin_name] = []
# try: try:
# self.pin_component_blockages[pin_name] self.pin_component_blockages[pin_name]
# except: except:
# self.pin_component_blockages[pin_name] = [] self.pin_component_blockages[pin_name] = []
found_pin = False found_pin = False
for pg in self.pin_groups[pin_name]: for pg in self.pin_groups[pin_name]:
@ -761,37 +766,41 @@ class router:
debug.error("Unable to find pin on grid.",-1) debug.error("Unable to find pin on grid.",-1)
# We need to route each of the components, so don't combine the groups # We need to route each of the components, so don't combine the groups
self.pin_components[pin_name].append(pin_set | blockage_set) self.pin_components[pin_name].append(pin_set)
# Add all of the blocked grids to the set for the design # Add all of the partial blocked grids to the set for the design
#partial_set = blockage_set - pin_set # if they are not blocked by other metal
#self.pin_component_blockages[pin_name].append(partial_set) partial_set = blockage_set - pin_set - self.blocked_grids
self.pin_component_blockages[pin_name].append(partial_set)
# Remove the blockage set from the blockages since these # We should not have added the pins to the blockages,
# will either be pins or partial pin blockges # but remove them just in case
self.blocked_grids.difference_update(blockage_set) # Partial set may still be in the blockages if there were
# other shapes disconnected from the pins that were also overlapping
self.blocked_grids.difference_update(pin_set)
def enclose_pin_grids(self, grids):
def enclose_pin_grids(self, grids, seed):
""" """
This encloses a single pin component with a rectangle. This encloses a single pin component with a rectangle
It returns the set of the unenclosed pins. starting with the seed and expanding right until blocked
and then up until blocked.
""" """
# We may have started with an empty set # We may have started with an empty set
if not grids: if not grids:
return return
# Start with lowest left element # Start with the seed
ll = min(grids) ll = seed
grids.remove(ll)
# Start with the ll and make the widest row # Start with the ll and make the widest row
row = [ll] row = [ll]
# Move right while we can # Move right while we can
while True: while True:
right = row[-1] + vector3d(1,0,0) right = row[-1] + vector3d(1,0,0)
# Can't move if not in the pin shape or blocked # Can't move if not in the pin shape
if right in grids and right not in self.blocked_grids: if right in grids:
grids.remove(right)
row.append(right) row.append(right)
else: else:
break break
@ -799,11 +808,10 @@ class router:
while True: while True:
next_row = [x+vector3d(0,1,0) for x in row] next_row = [x+vector3d(0,1,0) for x in row]
for cell in next_row: for cell in next_row:
# Can't move if any cell is not in the pin shape or blocked # Can't move if any cell is not in the pin shape
if cell not in grids or cell in self.blocked_grids: if cell not in grids:
break break
else: else:
grids.difference_update(set(next_row))
row = next_row row = next_row
# Skips the second break # Skips the second break
continue continue
@ -814,8 +822,6 @@ class router:
ur = row[-1] ur = row[-1]
self.add_enclosure(ll, ur, ll.z) self.add_enclosure(ll, ur, ll.z)
# Return the remaining grid set
return grids
def enclose_pins(self): def enclose_pins(self):
""" """
@ -826,15 +832,15 @@ class router:
# FIXME: This could be optimized, but we just do a simple greedy biggest shape # FIXME: This could be optimized, but we just do a simple greedy biggest shape
# for now. # for now.
for pin_name in self.pin_components.keys(): for pin_name in self.pin_components.keys():
#for pin_set,partial_set in zip(self.pin_components[pin_name],self.pin_component_blockages[pin_name]): for pin_set,partial_set in zip(self.pin_components[pin_name],self.pin_component_blockages[pin_name]):
# total_pin_grids = pin_set | partial_set total_pin_grids = pin_set | partial_set
for pin_grids in self.pin_components[pin_name]: # Starting with each pin, add the max enclosure
# Must duplicate so we don't destroy the original # This will result in redundant overlaps, but it is easy.
total_pin_grids=set(pin_grids) for seed in total_pin_grids:
while self.enclose_pin_grids(total_pin_grids): self.enclose_pin_grids(total_pin_grids, seed)
pass
self.write_debug_gds("pin_debug.gds", False)
#self.write_debug_gds("pin_debug.gds", True)
def add_source(self, pin_name): def add_source(self, pin_name):

View File

@ -73,12 +73,11 @@ 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)
# Route the supply pins to the supply rails # Route the supply pins to the supply rails
self.route_pins_to_rails(gnd_name) self.route_pins_to_rails(gnd_name)
self.route_pins_to_rails(vdd_name) self.route_pins_to_rails(vdd_name)
self.write_debug_gds(stop_program=False) #self.write_debug_gds(stop_program=False)
return True return True
@ -219,6 +218,12 @@ class supply_router(router):
self.prepare_blockages() self.prepare_blockages()
# Don't mark the other components as targets since we want to route
# directly to a rail, but unblock all the source components so we can
# route over them
self.set_blockages(self.pin_components[pin_name],False)
self.set_blockages(self.pin_component_blockages[pin_name],False)
# Add the single component of the pin as the source # Add the single component of the pin as the source
# which unmarks it as a blockage too # which unmarks it as a blockage too
self.add_pin_component_source(pin_name,index) self.add_pin_component_source(pin_name,index)
@ -227,6 +232,10 @@ class supply_router(router):
# Don't add the other pins, but we could? # Don't add the other pins, but we could?
self.add_supply_rail_target(pin_name) self.add_supply_rail_target(pin_name)
# Add the previous paths as targets too
#self.add_path_target(recent_paths)
# Actually run the A* router # Actually run the A* router
if not self.run_router(detour_scale=5): if not self.run_router(detour_scale=5):
self.write_debug_gds() self.write_debug_gds()

View File

@ -32,7 +32,7 @@ class no_blockages_test(openram_test):
c.words_per_row=1 c.words_per_row=1
sram = sram(c, "sram1") sram = sram(c, "sram1")
cell = sram.s cell = sram.s
layer_stack =("metal3","via3","metal4") layer_stack =("metal3","via3","metal4")
rtr=router(layer_stack, cell) rtr=router(layer_stack, cell)
self.assertTrue(rtr.route()) self.assertTrue(rtr.route())

View File

@ -70,7 +70,7 @@ num_drc_runs = 0
num_lvs_runs = 0 num_lvs_runs = 0
num_pex_runs = 0 num_pex_runs = 0
def run_drc(cell_name, gds_name): def run_drc(cell_name, gds_name, extract=False, final_verification=False):
"""Run DRC check on a given top-level name which is """Run DRC check on a given top-level name which is
implemented in gds_name.""" implemented in gds_name."""
@ -175,18 +175,21 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
'cmnFDIUseLayerMap': 1, 'cmnFDIUseLayerMap': 1,
'cmnTranscriptFile': './lvs.log', 'cmnTranscriptFile': './lvs.log',
'cmnTranscriptEchoToFile': 1, 'cmnTranscriptEchoToFile': 1,
'lvsRecognizeGates': 'NONE', 'lvsRecognizeGates': 'NONE',
# FIXME: Remove when vdd/gnd connected
'cmnVConnectNamesState' : 'ALL', #connects all nets with the same namee
# FIXME: Remove when vdd/gnd connected
'lvsAbortOnSupplyError' : 0
} }
# FIXME: Remove when vdd/gnd connected
#'cmnVConnectNamesState' : 'ALL', #connects all nets with the same namee
# FIXME: Remove when vdd/gnd connected
#'lvsAbortOnSupplyError' : 0
# This should be removed for final verification # This should be removed for final verification
if not final_verification: if not final_verification:
lvs_runset['cmnVConnectReport']=1 lvs_runset['cmnVConnectReport']=1
lvs_runset['cmnVConnectNamesState']='SOME' lvs_runset['cmnVConnectNamesState']='SOME'
lvs_runset['cmnVConnectNames']='vdd gnd' lvs_runset['cmnVConnectNames']='vdd gnd'
else:
lvs_runset['lvsAbortOnSupplyError']=1
# write the runset file # write the runset file

View File

@ -26,7 +26,7 @@ num_drc_runs = 0
num_lvs_runs = 0 num_lvs_runs = 0
num_pex_runs = 0 num_pex_runs = 0
def write_magic_script(cell_name, gds_name, extract=False): def write_magic_script(cell_name, gds_name, extract=False, final_verification=False):
""" Write a magic script to perform DRC and optionally extraction. """ """ Write a magic script to perform DRC and optionally extraction. """
global OPTS global OPTS
@ -41,10 +41,10 @@ def write_magic_script(cell_name, gds_name, extract=False):
f.write("load {}\n".format(cell_name)) f.write("load {}\n".format(cell_name))
# Flatten the cell to get rid of DRCs spanning multiple layers # Flatten the cell to get rid of DRCs spanning multiple layers
# (e.g. with routes) # (e.g. with routes)
f.write("flatten {}_new\n".format(cell_name)) #f.write("flatten {}_new\n".format(cell_name))
f.write("load {}_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("cellname rename {0}_new {0}\n".format(cell_name))
f.write("load {}\n".format(cell_name)) #f.write("load {}\n".format(cell_name))
f.write("writeall force\n") f.write("writeall force\n")
f.write("drc check\n") f.write("drc check\n")
f.write("drc catchup\n") f.write("drc catchup\n")
@ -54,7 +54,9 @@ def write_magic_script(cell_name, gds_name, extract=False):
pre = "#" pre = "#"
else: else:
pre = "" pre = ""
f.write(pre+"extract all\n") if final_verification:
f.write(pre+"extract unique\n")
f.write(pre+"extract\n")
f.write(pre+"ext2spice hierarchy on\n") f.write(pre+"ext2spice hierarchy on\n")
f.write(pre+"ext2spice scale off\n") f.write(pre+"ext2spice scale off\n")
# Can choose hspice, ngspice, or spice3, # Can choose hspice, ngspice, or spice3,
@ -98,7 +100,7 @@ def write_netgen_script(cell_name, sp_name):
os.system("chmod u+x {}".format(run_file)) os.system("chmod u+x {}".format(run_file))
def run_drc(cell_name, gds_name, extract=False): def run_drc(cell_name, gds_name, extract=False, final_verification=False):
"""Run DRC check on a cell which is implemented in gds_name.""" """Run DRC check on a cell which is implemented in gds_name."""
global num_drc_runs global num_drc_runs
@ -111,7 +113,7 @@ def run_drc(cell_name, gds_name, extract=False):
else: else:
debug.warning("Could not locate .magicrc file: {}".format(magic_file)) debug.warning("Could not locate .magicrc file: {}".format(magic_file))
write_magic_script(cell_name, gds_name, extract) write_magic_script(cell_name, gds_name, extract, final_verification)
# run drc # run drc
cwd = os.getcwd() cwd = os.getcwd()
@ -164,7 +166,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
global num_lvs_runs global num_lvs_runs
num_lvs_runs += 1 num_lvs_runs += 1
run_drc(cell_name, gds_name, extract=True) run_drc(cell_name, gds_name, extract=True, final_verification=final_verification)
write_netgen_script(cell_name, sp_name) write_netgen_script(cell_name, sp_name)
# run LVS # run LVS