mirror of https://github.com/VLSIDA/OpenRAM.git
Supply router working, perhaps not efficiently though.
This commit is contained in:
parent
eb2304944b
commit
94ab69ea16
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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."""
|
||||||
|
|
||||||
|
|
@ -176,17 +176,20 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
|
||||||
'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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue