diff --git a/compiler/router/router.py b/compiler/router/router.py index c1d4e763..84728811 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -56,7 +56,7 @@ class router: self.blocked_grids = set() # The corresponding set of partially blocked grids for each component. # These are blockages for other nets but unblocked for this component. - #self.pin_component_blockages = {} + self.pin_component_blockages = {} ### The routed data structures # A list of paths that have been "routed" @@ -152,13 +152,16 @@ class router: (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_set.add(pin) 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.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): """ @@ -197,6 +200,7 @@ class router: Find the pins and blockages in the design """ # 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: self.find_pins(pin) @@ -233,8 +237,8 @@ class router: self.set_blockages(self.pin_components[name],True) # Block all of the pin component partial blockages - #for name in self.pin_component_blockages.keys(): - # self.set_blockages(self.pin_component_blockages[name],True) + for name in self.pin_component_blockages.keys(): + self.set_blockages(self.pin_component_blockages[name],True) # These are the paths that have already been routed. self.set_path_blockages() @@ -354,6 +358,7 @@ class router: ur = vector(boundary[2],boundary[3]) rect = [ll,ur] 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 new_pin not in self.all_pins: self.blockages.append(new_pin) @@ -732,10 +737,10 @@ class router: except: self.pin_components[pin_name] = [] - # try: - # self.pin_component_blockages[pin_name] - # except: - # self.pin_component_blockages[pin_name] = [] + try: + self.pin_component_blockages[pin_name] + except: + self.pin_component_blockages[pin_name] = [] found_pin = False for pg in self.pin_groups[pin_name]: @@ -761,37 +766,41 @@ class router: 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 | blockage_set) + self.pin_components[pin_name].append(pin_set) - # Add all of the blocked grids to the set for the design - #partial_set = blockage_set - pin_set - #self.pin_component_blockages[pin_name].append(partial_set) + # Add all of the partial blocked grids to the set for the design + # if they are not blocked by other metal + 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 - # will either be pins or partial pin blockges - self.blocked_grids.difference_update(blockage_set) + # We should not have added the pins to the blockages, + # but remove them just in case + # 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. - It returns the set of the unenclosed pins. + This encloses a single pin component with a rectangle + starting with the seed and expanding right until blocked + and then up until blocked. """ # We may have started with an empty set if not grids: return - # Start with lowest left element - ll = min(grids) - grids.remove(ll) + # Start with the seed + ll = seed + # Start with the ll and make the widest row row = [ll] # Move right while we can while True: right = row[-1] + vector3d(1,0,0) - # Can't move if not in the pin shape or blocked - if right in grids and right not in self.blocked_grids: - grids.remove(right) + # Can't move if not in the pin shape + if right in grids: row.append(right) else: break @@ -799,11 +808,10 @@ class router: while True: next_row = [x+vector3d(0,1,0) for x in row] for cell in next_row: - # Can't move if any cell is not in the pin shape or blocked - if cell not in grids or cell in self.blocked_grids: + # Can't move if any cell is not in the pin shape + if cell not in grids: break else: - grids.difference_update(set(next_row)) row = next_row # Skips the second break continue @@ -814,8 +822,6 @@ class router: ur = row[-1] self.add_enclosure(ll, ur, ll.z) - # Return the remaining grid set - return grids def enclose_pins(self): """ @@ -826,15 +832,15 @@ class router: # FIXME: This could be optimized, but we just do a simple greedy biggest shape # for now. 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]): - # total_pin_grids = pin_set | partial_set - for pin_grids in self.pin_components[pin_name]: - # Must duplicate so we don't destroy the original - total_pin_grids=set(pin_grids) - while self.enclose_pin_grids(total_pin_grids): - pass + 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 + # Starting with each pin, add the max enclosure + # This will result in redundant overlaps, but it is easy. + for seed in total_pin_grids: + self.enclose_pin_grids(total_pin_grids, seed) - self.write_debug_gds("pin_debug.gds", False) + + #self.write_debug_gds("pin_debug.gds", True) def add_source(self, pin_name): diff --git a/compiler/router/supply_router.py b/compiler/router/supply_router.py index 6743bc49..d15dbb24 100644 --- a/compiler/router/supply_router.py +++ b/compiler/router/supply_router.py @@ -73,12 +73,11 @@ class supply_router(router): # 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.write_debug_gds(stop_program=False) + #self.write_debug_gds(stop_program=False) return True @@ -219,6 +218,12 @@ class supply_router(router): 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 # which unmarks it as a blockage too 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? 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 if not self.run_router(detour_scale=5): self.write_debug_gds() diff --git a/compiler/router/tests/10_supply_grid_test.py b/compiler/router/tests/10_supply_grid_test.py index a14e185c..ef9a1be3 100755 --- a/compiler/router/tests/10_supply_grid_test.py +++ b/compiler/router/tests/10_supply_grid_test.py @@ -32,7 +32,7 @@ class no_blockages_test(openram_test): c.words_per_row=1 sram = sram(c, "sram1") cell = sram.s - + layer_stack =("metal3","via3","metal4") rtr=router(layer_stack, cell) self.assertTrue(rtr.route()) diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index 4cc3a093..7510b340 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -70,7 +70,7 @@ num_drc_runs = 0 num_lvs_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 implemented in gds_name.""" @@ -175,18 +175,21 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): 'cmnFDIUseLayerMap': 1, 'cmnTranscriptFile': './lvs.log', 'cmnTranscriptEchoToFile': 1, - '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 + '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 # This should be removed for final verification if not final_verification: lvs_runset['cmnVConnectReport']=1 lvs_runset['cmnVConnectNamesState']='SOME' lvs_runset['cmnVConnectNames']='vdd gnd' + else: + lvs_runset['lvsAbortOnSupplyError']=1 + # write the runset file diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 3d48cf7b..bb116da3 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -26,7 +26,7 @@ num_drc_runs = 0 num_lvs_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. """ global OPTS @@ -41,10 +41,10 @@ def write_magic_script(cell_name, gds_name, extract=False): f.write("load {}\n".format(cell_name)) # Flatten the cell to get rid of DRCs spanning multiple layers # (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("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\n") f.write("drc check\n") f.write("drc catchup\n") @@ -54,7 +54,9 @@ def write_magic_script(cell_name, gds_name, extract=False): pre = "#" else: 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 scale off\n") # 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)) -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.""" global num_drc_runs @@ -111,7 +113,7 @@ def run_drc(cell_name, gds_name, extract=False): else: 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 cwd = os.getcwd() @@ -164,7 +166,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): global num_lvs_runs 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) # run LVS