From 2ae1e0234db5ec74ac8b26926cb1b5b154a8af77 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 22 Aug 2018 11:37:24 -0700 Subject: [PATCH] Update router to work with pin_layout structure. --- compiler/base/geometry.py | 7 +- compiler/base/hierarchy_design.py | 10 +- compiler/base/hierarchy_layout.py | 2 +- compiler/base/hierarchy_spice.py | 2 +- compiler/base/route.py | 25 +++- compiler/base/utils.py | 36 +++-- compiler/gdsMill/gdsMill/vlsiLayout.py | 9 +- {router => compiler/router}/cell.py | 0 {router => compiler/router}/grid.py | 52 +++---- {router => compiler/router}/router.py | 128 ++++++++---------- compiler/router/tests/01_no_blockages_test.py | 55 ++++++++ .../router}/tests/01_no_blockages_test.sp | 0 .../tests/01_no_blockages_test_freepdk45.gds | Bin 2048 -> 2048 bytes .../01_no_blockages_test_scn3me_subm.gds | Bin 2048 -> 2048 bytes compiler/router/tests/02_blockages_test.py | 59 ++++++++ .../router}/tests/02_blockages_test.sp | 0 .../tests/02_blockages_test_freepdk45.gds | Bin 2048 -> 2048 bytes .../tests/02_blockages_test_scn3me_subm.gds | Bin 2048 -> 2048 bytes .../router/tests/03_same_layer_pins_test.py | 54 ++++++++ .../router}/tests/03_same_layer_pins_test.sp | 0 .../03_same_layer_pins_test_freepdk45.gds | Bin .../03_same_layer_pins_test_scn3me_subm.gds | Bin .../router/tests/04_diff_layer_pins_test.py | 56 ++++++++ .../router}/tests/04_diff_layer_pins_test.sp | 0 .../04_diff_layer_pins_test_freepdk45.gds | Bin .../04_diff_layer_pins_test_scn3me_subm.gds | Bin compiler/router/tests/05_two_nets_test.py | 58 ++++++++ .../router}/tests/05_two_nets_test.sp | 0 .../tests/05_two_nets_test_freepdk45.gds | Bin .../tests/05_two_nets_test_scn3me_subm.gds | Bin .../router}/tests/06_pin_location_test.py | 51 ++----- .../tests/06_pin_location_test_freepdk45.gds | Bin .../06_pin_location_test_scn3me_subm.gds | Bin .../router}/tests/07_big_test.py | 51 ++----- .../router}/tests/07_big_test_scn3me_subm.gds | Bin .../router}/tests/08_expand_region_test.py | 50 ++----- .../tests/08_expand_region_test_freepdk45.gds | Bin .../08_expand_region_test_scn3me_subm.gds | Bin .../router}/tests/config_freepdk45.py | 0 .../router}/tests/config_scn3me_subm.py | 0 compiler/router/tests/gds_cell.py | 16 +++ {router => compiler/router}/tests/regress.py | 0 .../router}/tests/testutils.py | 5 +- {router => compiler/router}/vector3d.py | 0 compiler/verify/magic.py | 4 + router/tests/01_no_blockages_test.py | 81 ----------- router/tests/02_blockages_test.py | 80 ----------- router/tests/03_same_layer_pins_test.py | 80 ----------- router/tests/04_diff_layer_pins_test.py | 81 ----------- router/tests/05_two_nets_test.py | 82 ----------- 50 files changed, 493 insertions(+), 641 deletions(-) rename {router => compiler/router}/cell.py (100%) rename {router => compiler/router}/grid.py (88%) rename {router => compiler/router}/router.py (84%) create mode 100755 compiler/router/tests/01_no_blockages_test.py rename {router => compiler/router}/tests/01_no_blockages_test.sp (100%) rename {router => compiler/router}/tests/01_no_blockages_test_freepdk45.gds (75%) rename {router => compiler/router}/tests/01_no_blockages_test_scn3me_subm.gds (75%) create mode 100755 compiler/router/tests/02_blockages_test.py rename {router => compiler/router}/tests/02_blockages_test.sp (100%) rename {router => compiler/router}/tests/02_blockages_test_freepdk45.gds (62%) rename {router => compiler/router}/tests/02_blockages_test_scn3me_subm.gds (59%) create mode 100755 compiler/router/tests/03_same_layer_pins_test.py rename {router => compiler/router}/tests/03_same_layer_pins_test.sp (100%) rename {router => compiler/router}/tests/03_same_layer_pins_test_freepdk45.gds (100%) rename {router => compiler/router}/tests/03_same_layer_pins_test_scn3me_subm.gds (100%) create mode 100755 compiler/router/tests/04_diff_layer_pins_test.py rename {router => compiler/router}/tests/04_diff_layer_pins_test.sp (100%) rename {router => compiler/router}/tests/04_diff_layer_pins_test_freepdk45.gds (100%) rename {router => compiler/router}/tests/04_diff_layer_pins_test_scn3me_subm.gds (100%) create mode 100755 compiler/router/tests/05_two_nets_test.py rename {router => compiler/router}/tests/05_two_nets_test.sp (100%) rename {router => compiler/router}/tests/05_two_nets_test_freepdk45.gds (100%) rename {router => compiler/router}/tests/05_two_nets_test_scn3me_subm.gds (100%) rename {router => compiler/router}/tests/06_pin_location_test.py (54%) rename {router => compiler/router}/tests/06_pin_location_test_freepdk45.gds (100%) rename {router => compiler/router}/tests/06_pin_location_test_scn3me_subm.gds (100%) rename {router => compiler/router}/tests/07_big_test.py (63%) rename {router => compiler/router}/tests/07_big_test_scn3me_subm.gds (100%) rename {router => compiler/router}/tests/08_expand_region_test.py (51%) rename {router => compiler/router}/tests/08_expand_region_test_freepdk45.gds (100%) rename {router => compiler/router}/tests/08_expand_region_test_scn3me_subm.gds (100%) rename {router => compiler/router}/tests/config_freepdk45.py (100%) rename {router => compiler/router}/tests/config_scn3me_subm.py (100%) create mode 100644 compiler/router/tests/gds_cell.py rename {router => compiler/router}/tests/regress.py (100%) rename {router => compiler/router}/tests/testutils.py (98%) rename {router => compiler/router}/vector3d.py (100%) delete mode 100755 router/tests/01_no_blockages_test.py delete mode 100755 router/tests/02_blockages_test.py delete mode 100755 router/tests/03_same_layer_pins_test.py delete mode 100755 router/tests/04_diff_layer_pins_test.py delete mode 100755 router/tests/05_two_nets_test.py diff --git a/compiler/base/geometry.py b/compiler/base/geometry.py index d316e713..2bb7b8df 100644 --- a/compiler/base/geometry.py +++ b/compiler/base/geometry.py @@ -55,9 +55,12 @@ class geometry: self.compute_boundary(self.offset,self.mirror,self.rotate) def compute_boundary(self,offset=vector(0,0),mirror="",rotate=0): - """ Transform with offset, mirror and rotation to get the absolute pin location. - We must then re-find the ll and ur. The master is the cell instance. """ + """ + Transform with offset, mirror and rotation to get the absolute pin location. + We must then re-find the ll and ur. The master is the cell instance. + """ (ll,ur) = [vector(0,0),vector(self.width,self.height)] + if mirror=="MX": ll=ll.scale(1,-1) ur=ur.scale(1,-1) diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py index 87659bd7..320276cc 100644 --- a/compiler/base/hierarchy_design.py +++ b/compiler/base/hierarchy_design.py @@ -16,8 +16,14 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): def __init__(self, name): - self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds" - self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp" + try: + self.gds_file + except AttributeError: + self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds" + try: + self.sp_file + except AttributeError: + self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp" self.name = name hierarchy_layout.layout.__init__(self, name) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 3aa21794..672f4d93 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -322,7 +322,7 @@ class layout(lef.lef): position_list=coordinates, width=width) - def add_route(self, design, layers, coordinates): + def add_route(self, layers, coordinates): """Connects a routing path on given layer,coordinates,width. The layers are the (horizontal, via, vertical). add_wire assumes preferred direction routing whereas this includes layers in diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index 0152a6c8..a82eba1b 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -117,7 +117,7 @@ class spice(verilog.verilog): def sp_read(self): """Reads the sp file (and parse the pins) from the library Otherwise, initialize it to null for dynamic generation""" - if os.path.isfile(self.sp_file): + if self.sp_file and os.path.isfile(self.sp_file): debug.info(3, "opening {0}".format(self.sp_file)) f = open(self.sp_file) self.spice = f.readlines() diff --git a/compiler/base/route.py b/compiler/base/route.py index 03b62cff..beff1a58 100644 --- a/compiler/base/route.py +++ b/compiler/base/route.py @@ -1,11 +1,12 @@ from tech import drc import debug +from design import design from contact import contact from itertools import tee from vector import vector from vector3d import vector3d -class route(): +class route(design): """ Object route (used by the router module) Add a route of minimium metal width between a set of points. @@ -14,10 +15,13 @@ class route(): The points are the center of the wire. This can have non-preferred direction routing. """ + + unique_route_id = 0 + def __init__(self, obj, layer_stack, path): name = "route_{0}".format(route.unique_route_id) route.unique_route_id += 1 - design.design.__init__(self, name) + design.__init__(self, name) debug.info(3, "create route obj {0}".format(name)) self.obj = obj @@ -52,7 +56,7 @@ class route(): next(b, None) return zip(a, b) - plist = pairwise(self.path) + plist = list(pairwise(self.path)) for p0,p1 in plist: if p0.z != p1.z: # via # offset if not rotated @@ -67,6 +71,13 @@ class route(): self.draw_corner_wire(p1) # draw the point to point wire self.draw_wire(p0,p1) + + + # Draw the layers on the ends of the wires to ensure full width + # connections + self.draw_corner_wire(plist[0][0]) + self.draw_corner_wire(plist[-1][1]) + @@ -99,10 +110,10 @@ class route(): height = end.y - start.y width = layer_width - deisgn.add_rect(layer=layer_name, - offset=offset, - width=width, - height=height) + self.obj.add_rect(layer=layer_name, + offset=vector(offset.x,offset.y), + width=width, + height=height) def draw_corner_wire(self, p0): diff --git a/compiler/base/utils.py b/compiler/base/utils.py index cb63b68a..b13f2f7e 100644 --- a/compiler/base/utils.py +++ b/compiler/base/utils.py @@ -37,12 +37,6 @@ def pin_center(boundary): """ return [0.5 * (boundary[0] + boundary[2]), 0.5 * (boundary[1] + boundary[3])] -def pin_rect(boundary): - """ - This returns a LL,UR point pair. - """ - return [vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])] - def auto_measure_libcell(pin_list, name, units, layer): """ Open a GDS file and find the pins in pin_list as text on a given layer. @@ -66,15 +60,14 @@ def auto_measure_libcell(pin_list, name, units, layer): -def get_libcell_size(name, units, layer): +def get_gds_size(name, gds_filename, units, layer): """ - Open a GDS file and return the library cell size from either the + Open a GDS file and return the size from either the bounding box or a border layer. """ - cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds" cell_vlsi = gdsMill.VlsiLayout(units=units) reader = gdsMill.Gds2reader(cell_vlsi) - reader.loadFromFile(cell_gds) + reader.loadFromFile(gds_filename) cell = {} measure_result = cell_vlsi.getLayoutBorder(layer) @@ -83,16 +76,23 @@ def get_libcell_size(name, units, layer): # returns width,height return measure_result +def get_libcell_size(name, units, layer): + """ + Open a GDS file and return the library cell size from either the + bounding box or a border layer. + """ + cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds" + return(get_gds_size(name, cell_gds, units, layer)) -def get_libcell_pins(pin_list, name, units, layer): + +def get_gds_pins(pin_list, name, gds_filename, units, layer): """ Open a GDS file and find the pins in pin_list as text on a given layer. Return these as a rectangle layer pair for each pin. """ - cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds" cell_vlsi = gdsMill.VlsiLayout(units=units) reader = gdsMill.Gds2reader(cell_vlsi) - reader.loadFromFile(cell_gds) + reader.loadFromFile(gds_filename) cell = {} for pin in pin_list: @@ -100,11 +100,19 @@ def get_libcell_pins(pin_list, name, units, layer): label_list=cell_vlsi.getPinShapeByLabel(str(pin)) for label in label_list: (name,layer,boundary)=label - rect = pin_rect(boundary) + rect=[vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])] # this is a list because other cells/designs may have must-connect pins cell[str(pin)].append(pin_layout(pin, rect, layer)) return cell +def get_libcell_pins(pin_list, name, units, layer): + """ + Open a GDS file and find the pins in pin_list as text on a given layer. + Return these as a rectangle layer pair for each pin. + """ + cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds" + return(get_gds_pins(pin_list, name, cell_gds, units, layer)) + diff --git a/compiler/gdsMill/gdsMill/vlsiLayout.py b/compiler/gdsMill/gdsMill/vlsiLayout.py index cd00bfaf..076948bb 100644 --- a/compiler/gdsMill/gdsMill/vlsiLayout.py +++ b/compiler/gdsMill/gdsMill/vlsiLayout.py @@ -583,6 +583,7 @@ class VlsiLayout: print("Done\n\n") def getLayoutBorder(self,borderlayer): + cellSizeMicron=None for boundary in self.structures[self.rootStructureName].boundaries: if boundary.drawingLayer==borderlayer: if self.debug: @@ -722,7 +723,8 @@ class VlsiLayout: def getAllPinShapesByDBLocLayer(self, coordinate, layer): """ Return ALL the enclosing rectangles on the same layer - at the given coordinate. Coordinates should be in DB units. + at the given coordinate. Input coordinates should be in DB units. + Returns user unit shapes. """ pin_boundaries=self.getAllPinShapesInStructureList(coordinate, layer) @@ -732,8 +734,7 @@ class VlsiLayout: new_boundaries.append([pin_boundary[0]*self.units[0],pin_boundary[1]*self.units[0], pin_boundary[2]*self.units[0],pin_boundary[3]*self.units[0]]) - # Make a name if we don't have the pin name - return ["p"+str(coordinate)+"_"+str(layer), layer, new_boundaries] + return new_boundaries def getPinShapeByLabel(self,label_name): """ @@ -758,7 +759,7 @@ class VlsiLayout: shape_list=[] for label in label_list: (label_coordinate,label_layer)=label - shape_list.append(self.getAllPinShapesByDBLocLayer(label_coordinate, label_layer)) + shape_list.extend(self.getAllPinShapesByDBLocLayer(label_coordinate, label_layer)) return shape_list def getAllPinShapesInStructureList(self,coordinates,layer): diff --git a/router/cell.py b/compiler/router/cell.py similarity index 100% rename from router/cell.py rename to compiler/router/cell.py diff --git a/router/grid.py b/compiler/router/grid.py similarity index 88% rename from router/grid.py rename to compiler/router/grid.py index 050826e8..d57be765 100644 --- a/router/grid.py +++ b/compiler/router/grid.py @@ -6,11 +6,7 @@ from vector3d import vector3d from cell import cell import os -try: - import Queue as Q # ver. < 3.0 -except ImportError: - import queue as Q - +from heapq import heappush,heappop class grid: """A two layer routing map. Each cell can be blocked in the vertical @@ -36,7 +32,7 @@ class grid: self.map={} # priority queue for the maze routing - self.q = Q.PriorityQueue() + self.q = [] def set_blocked(self,n): self.add_map(n) @@ -66,30 +62,34 @@ class grid: self.target=[] # clear the queue - while (not self.q.empty()): - self.q.get(False) - + while len(self.q)>0: + heappop(self.q) + self.counter = 0 def add_blockage_shape(self,ll,ur,z): debug.info(3,"Adding blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z)) + + block_list = [] for x in range(int(ll[0]),int(ur[0])+1): for y in range(int(ll[1]),int(ur[1])+1): - n = vector3d(x,y,z) - self.set_blocked(n) + block_list.append(vector3d(x,y,z)) + + self.add_blockage(block_list) def add_blockage(self,block_list): - debug.info(3,"Adding blockage list={0}".format(str(block_list))) + debug.info(2,"Adding blockage list={0}".format(str(block_list))) for n in block_list: self.set_blocked(n) def add_source(self,track_list): - debug.info(3,"Adding source list={0}".format(str(track_list))) + debug.info(2,"Adding source list={0}".format(str(track_list))) for n in track_list: if not self.is_blocked(n): + debug.info(3,"Adding source ={0}".format(str(n))) self.set_source(n) def add_target(self,track_list): - debug.info(3,"Adding target list={0}".format(str(track_list))) + debug.info(2,"Adding target list={0}".format(str(track_list))) for n in track_list: if not self.is_blocked(n): self.set_target(n) @@ -120,8 +120,8 @@ class grid: cost_bound = detour_scale*self.cost_to_target(self.source[0])*self.PREFERRED_COST # Make sure the queue is empty if we run another route - while not self.q.empty(): - self.q.get() + while len(self.q)>0: + heappop(self.q) # Put the source items into the queue self.init_queue() @@ -129,10 +129,10 @@ class grid: cheapest_cost = None # Keep expanding and adding to the priority queue until we are done - while not self.q.empty(): + while len(self.q)>0: # should we keep the path in the queue as well or just the final node? - (cost,path) = self.q.get() - debug.info(2,"Queue size: size=" + str(self.q.qsize()) + " " + str(cost)) + (cost,count,path) = heappop(self.q) + debug.info(2,"Queue size: size=" + str(len(self.q)) + " " + str(cost)) debug.info(3,"Expanding: cost=" + str(cost) + " " + str(path)) # expand the last element @@ -158,7 +158,8 @@ class grid: self.map[n].min_cost = predicted_cost debug.info(3,"Enqueuing: cost=" + str(current_cost) + "+" + str(target_cost) + " " + str(newpath)) # add the cost to get to this point if we haven't reached it yet - self.q.put((predicted_cost,newpath)) + heappush(self.q,(predicted_cost,self.counter,newpath)) + self.counter += 1 debug.warning("Unable to route path. Expand the detour_scale to allow detours.") return (None,None) @@ -227,11 +228,16 @@ class grid: # uniquify the source (and target while we are at it) self.source = list(set(self.source)) self.target = list(set(self.target)) - + + # Counter is used to not require data comparison in Python 3.x + # Items will be returned in order they are added during cost ties + self.counter = 0 for s in self.source: cost = self.cost_to_target(s) - debug.info(4,"Init: cost=" + str(cost) + " " + str([s])) - self.q.put((cost,[s])) + debug.info(1,"Init: cost=" + str(cost) + " " + str([s])) + heappush(self.q,(cost,self.counter,[s])) + self.counter+=1 + def hpwl(self, src, dest): """ diff --git a/router/router.py b/compiler/router/router.py similarity index 84% rename from router/router.py rename to compiler/router/router.py index 43e5af90..6375decd 100644 --- a/router/router.py +++ b/compiler/router/router.py @@ -4,6 +4,7 @@ from contact import contact import math import debug import grid +from pin_layout import pin_layout from vector import vector from vector3d import vector3d from globals import OPTS @@ -24,13 +25,11 @@ class router: self.reader.loadFromFile(gds_name) self.top_name = self.layout.rootStructureName - self.source_pin_shapes = [] - self.source_pin_zindex = None - self.target_pin_shapes = [] - self.target_pin_zindex = None + self.source_pins = [] + self.target_pins = [] # the list of all blockage shapes self.blockages = [] - # all thepaths we've routed so far (to supplement the blockages) + # all the paths we've routed so far (to supplement the blockages) self.paths = [] # The boundary will determine the limits to the size of the routing grid @@ -94,20 +93,18 @@ class router: Pin can either be a label or a location,layer pair: [[x,y],layer]. """ - if type(pin)==str: - (pin_name,pin_layer,pin_shapes) = self.layout.getAllPinShapesByLabel(str(pin)) - else: - (pin_name,pin_layer,pin_shapes) = self.layout.getAllPinShapesByLocLayer(pin[0],pin[1]) + label_list=self.layout.getPinShapeByLabel(str(pin)) + pin_list = [] + for label in label_list: + (name,layer,boundary)=label + rect = [vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])] + # this is a list because other cells/designs may have must-connect pins + pin_list.append(pin_layout(pin, rect, layer)) + + debug.check(len(pin_list)>0,"Did not find any pin shapes for {0}.".format(str(pin))) + + return pin_list - new_pin_shapes = [] - for pin_shape in pin_shapes: - debug.info(2,"Find pin {0} layer {1} shape {2}".format(pin_name,str(pin_layer),str(pin_shape))) - # repack the shape as a pair of vectors rather than four values - new_pin_shapes.append([vector(pin_shape[0],pin_shape[1]),vector(pin_shape[2],pin_shape[3])]) - - debug.check(len(new_pin_shapes)>0,"Did not find any pin shapes for {0}.".format(str(pin))) - - return (pin_layer,new_pin_shapes) def find_blockages(self): """ @@ -126,17 +123,14 @@ class router: Convert the routed path to blockages. Keep the other blockages unchanged. """ - self.source_pin = None - self.source_pin_shapes = [] - self.source_pin_zindex = None - self.target_pin = None - self.target_pin_shapes = [] - self.target_pin_zindex = None - # DO NOT clear the blockages as these don't change + self.source_pin_name = None + self.source_pins = [] + self.target_pin_name = None + self.target_pins = [] # DO NOT clear the blockages as these don't change self.rg.reinit() - def route(self, cell, layers, src, dest, detour_scale=2): + def route(self, cell, layers, src, dest, detour_scale=5): """ Route a single source-destination net and return the simplified rectilinear path. Cost factor is how sub-optimal to explore for a feasible route. @@ -186,7 +180,7 @@ class router: return False - def write_debug_gds(self,): + def write_debug_gds(self): """ Write out a GDS file with the routing grid and search information annotated on it. """ @@ -195,7 +189,7 @@ class router: if OPTS.debug_level==0: return self.add_router_info() - debug.error("Writing debug_route.gds from {0} to {1}".format(self.source_pin,self.target_pin)) + debug.error("Writing debug_route.gds from {0} to {1}".format(self.source_pin_name,self.target_pin_name)) self.cell.gds_write("debug_route.gds") def add_router_info(self): @@ -204,7 +198,7 @@ class router: the boundary layer for debugging purposes. This can only be called once or the labels will overlap. """ - debug.info(0,"Adding router info for {0} to {1}".format(self.source_pin,self.target_pin)) + debug.info(0,"Adding router info for {0} to {1}".format(self.source_pin_name,self.target_pin_name)) grid_keys=self.rg.map.keys() partial_track=vector(0,self.track_width/6.0) for g in grid_keys: @@ -237,7 +231,8 @@ class router: offset=type_off) self.cell.add_label(text="{0},{1}".format(g[0],g[1]), layer="text", - offset=shape[0]) + offset=shape[0], + zoom=0.05) def add_route(self,path): """ @@ -255,7 +250,7 @@ class router: if False or path==None: self.write_debug_gds() - if 'Xout_4_1' in [self.source_pin, self.target_pin]: + if 'Xout_4_1' in [self.source_pin_name, self.target_pin_name]: self.write_debug_gds() @@ -263,12 +258,6 @@ class router: #debug.info(1,str(self.path)) contracted_path = self.contract_path(path) debug.info(1,str(contracted_path)) - - # Make sure there's a pin enclosure on the source and dest - add_src_via = contracted_path[0].z!=self.source_pin_zindex - self.add_grid_pin(contracted_path[0],add_src_via) - add_tgt_via = contracted_path[-1].z!=self.target_pin_zindex - self.add_grid_pin(contracted_path[-1],add_tgt_via) # convert the path back to absolute units from tracks abs_path = map(self.convert_point_to_units,contracted_path) @@ -382,14 +371,12 @@ class router: self.rg.set_blocked(grid) - def get_source(self,pin): + def get_source(self,pin_name): """ Gets the source pin shapes only. Doesn't add to grid. """ - self.source_pin = pin - (self.source_pin_layer,self.source_pin_shapes) = self.find_pin(pin) - zindex = 0 if self.source_pin_layer==self.horiz_layer_number else 1 - self.source_pin_zindex = zindex + self.source_pin_name = pin_name + self.source_pins = self.find_pin(pin_name) def add_source(self): """ @@ -398,10 +385,11 @@ class router: """ found_pin = False - for shape in self.source_pin_shapes: - (pin_in_tracks,blockage_in_tracks)=self.convert_pin_to_tracks(shape,self.source_pin_zindex,self.source_pin) - if (len(pin_in_tracks)>0): found_pin=True - debug.info(1,"Set source: " + str(self.source_pin) + " " + str(pin_in_tracks) + " z=" + str(self.source_pin_zindex)) + for pin in self.source_pins: + (pin_in_tracks,blockage_in_tracks)=self.convert_pin_to_tracks(pin) + if (len(pin_in_tracks)>0): + found_pin=True + debug.info(1,"Set source: " + str(self.source_pin_name) + " " + str(pin_in_tracks)) self.rg.add_source(pin_in_tracks) self.rg.add_blockage(blockage_in_tracks) @@ -409,14 +397,12 @@ class router: self.write_debug_gds() debug.check(found_pin,"Unable to find source pin on grid.") - def get_target(self,pin): + def get_target(self,pin_name): """ Gets the target pin shapes only. Doesn't add to grid. """ - self.target_pin = pin - (self.target_pin_layer,self.target_pin_shapes) = self.find_pin(pin) - zindex = 0 if self.target_pin_layer==self.horiz_layer_number else 1 - self.target_pin_zindex = zindex + self.target_pin_name = pin_name + self.target_pins = self.find_pin(pin_name) def add_target(self): """ @@ -424,10 +410,11 @@ class router: pin can be a location or a label. """ found_pin=False - for shape in self.target_pin_shapes: - (pin_in_tracks,blockage_in_tracks)=self.convert_pin_to_tracks(shape,self.target_pin_zindex,self.target_pin) - if (len(pin_in_tracks)>0): found_pin=True - debug.info(1,"Set target: " + str(self.target_pin) + " " + str(pin_in_tracks) + " z=" + str(self.target_pin_zindex)) + for pin in self.target_pins: + (pin_in_tracks,blockage_in_tracks)=self.convert_pin_to_tracks(pin) + if (len(pin_in_tracks)>0): + found_pin=True + debug.info(1,"Set target: " + str(self.target_pin_name) + " " + str(pin_in_tracks)) self.rg.add_target(pin_in_tracks) self.rg.add_blockage(blockage_in_tracks) @@ -438,15 +425,15 @@ class router: def add_blockages(self): """ Add the blockages except the pin shapes """ for blockage in self.blockages: - (shape,zlayer) = blockage + is_nonpin_blockage = True # Skip source pin shapes - if zlayer==self.source_pin_zindex and shape in self.source_pin_shapes: - continue - # Skip target pin shapes - if zlayer==self.target_pin_zindex and shape in self.target_pin_shapes: - continue - [ll,ur]=self.convert_blockage_to_tracks(shape) - self.rg.add_blockage_shape(ll,ur,zlayer) + for pin in self.source_pins + self.target_pins: + if blockage.overlaps(pin): + break + else: + [ll,ur]=self.convert_blockage_to_tracks(blockage.rect) + zlayer = 0 if blockage.layer_num==self.horiz_layer_number else 1 + self.rg.add_blockage_shape(ll,ur,zlayer) def get_blockages(self, sref, mirr = 1, angle = math.radians(float(0)), xyShift = (0, 0)): @@ -461,8 +448,8 @@ class router: # only consider the two layers that we are routing on if boundary.drawingLayer in [self.vert_layer_number,self.horiz_layer_number]: - zlayer = 0 if boundary.drawingLayer==self.horiz_layer_number else 1 - self.blockages.append((shape,zlayer)) + # store the blockages as pin layouts so they are easy to compare etc. + self.blockages.append(pin_layout("blockage",shape,boundary.drawingLayer)) # recurse given the mirror, angle, etc. @@ -507,13 +494,13 @@ class router: #debug.info(1,"Converted [ {0} , {1} ]".format(ll,ur)) return [ll,ur] - def convert_pin_to_tracks(self,shape,zindex,pin): + def convert_pin_to_tracks(self, pin): """ Convert a rectangular pin shape into a list of track locations,layers. If no on-grid pins are found, it searches for the nearest off-grid pin(s). If a pin has insufficent overlap, it returns the blockage list to avoid it. """ - [ll,ur] = shape + [ll,ur] = pin.rect ll = snap_to_grid(ll) ur = snap_to_grid(ur) @@ -524,6 +511,7 @@ class router: ur=ur.scale(self.track_factor).ceil() # width depends on which layer it is + zindex = 0 if pin.layer_num==self.horiz_layer_number else 1 if zindex==0: width = self.horiz_layer_width else: @@ -539,12 +527,12 @@ class router: # if dimension of overlap is greater than min width in any dimension, # it will be an on-grid pin rect = self.convert_track_to_pin(vector3d(x,y,zindex)) - max_overlap=max(self.compute_overlap(shape,rect)) + max_overlap=max(self.compute_overlap(pin.rect,rect)) # however, if there is not enough overlap, then if there is any overlap at all, # we need to block it to prevent routes coming in on that grid full_rect = self.convert_full_track_to_shape(vector3d(x,y,zindex)) - full_overlap=max(self.compute_overlap(shape,full_rect)) + full_overlap=max(self.compute_overlap(pin.rect,full_rect)) #debug.info(1,"Check overlap: {0} {1} max={2}".format(shape,rect,max_overlap)) if max_overlap >= width: @@ -552,7 +540,7 @@ class router: elif full_overlap>0: block_list.append(vector3d(x,y,zindex)) else: - debug.info(1,"No overlap: {0} {1} max={2}".format(shape,rect,max_overlap)) + debug.info(4,"No overlap: {0} {1} max={2}".format(pin.rect,rect,max_overlap)) #debug.warning("Off-grid pin for {0}.".format(str(pin))) #debug.info(1,"Converted [ {0} , {1} ]".format(ll,ur)) diff --git a/compiler/router/tests/01_no_blockages_test.py b/compiler/router/tests/01_no_blockages_test.py new file mode 100755 index 00000000..60cc6583 --- /dev/null +++ b/compiler/router/tests/01_no_blockages_test.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +"Run a regresion test the library cells for DRC" + +import unittest +from testutils import header,openram_test +import sys,os +sys.path.append(os.path.join(sys.path[0],"../..")) +sys.path.append(os.path.join(sys.path[0],"..")) +import globals +import debug + +OPTS = globals.OPTS + +class no_blockages_test(openram_test): + """ + Simplest two pin route test with no blockages. + """ + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + from gds_cell import gds_cell + from design import design + from router import router + + class routing(design, openram_test): + """ + A generic GDS design that we can route on. + """ + def __init__(self, name): + design.__init__(self, "top") + + # Instantiate a GDS cell with the design + gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) + cell = gds_cell(name, gds_file) + self.add_inst(name=name, + mod=cell, + offset=[0,0]) + self.connect_inst([]) + + r=router(gds_file) + layer_stack =("metal1","via1","metal2") + self.assertTrue(r.route(self,layer_stack,src="A",dest="B")) + + r=routing("01_no_blockages_test_{0}".format(OPTS.tech_name)) + self.local_drc_check(r) + + # fails if there are any DRC errors on any cells + globals.end_openram() + +# instantiate a copy of the class to actually run the test +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main() diff --git a/router/tests/01_no_blockages_test.sp b/compiler/router/tests/01_no_blockages_test.sp similarity index 100% rename from router/tests/01_no_blockages_test.sp rename to compiler/router/tests/01_no_blockages_test.sp diff --git a/router/tests/01_no_blockages_test_freepdk45.gds b/compiler/router/tests/01_no_blockages_test_freepdk45.gds similarity index 75% rename from router/tests/01_no_blockages_test_freepdk45.gds rename to compiler/router/tests/01_no_blockages_test_freepdk45.gds index cbad1838203f2d606bd649fabff854b779162e68..ec3c99d00a0e1d1650c6b27b2ae46b5333ecbd29 100644 GIT binary patch delta 93 zcmZn=Xb_kn?k~i^!63>Y$iT#)&%ndPmXey5SejG9z#ziRYUkK#?tN_e8%viR`U_@9 m-eHhoWnvIu;AY@w5Mhu4>Oj`Z!NyjST3oU*XA1iyCN=9RwA!R*Kn o3^J@tK$YAK{0t%tQVdKC$a?wM*m4b%a`Kb26Vp>SrcGf70GW6bm;e9( diff --git a/router/tests/01_no_blockages_test_scn3me_subm.gds b/compiler/router/tests/01_no_blockages_test_scn3me_subm.gds similarity index 75% rename from router/tests/01_no_blockages_test_scn3me_subm.gds rename to compiler/router/tests/01_no_blockages_test_scn3me_subm.gds index a94ec07c09475a019cc6f05b71c51e6056aff5d5..9d8b540e4fb315b934a3e31d77a606363d970fdc 100644 GIT binary patch delta 93 zcmZn=Xb_kn?k~i^!63>Y$iT$F%)rCMmXey5SejG9z#ziRYUkK#?tN_e8%viR`U_@9 mE?|&hWnvIu;AY@w5Mhu4>Oj`Z!NyjST3oU*XA1iyCN=<86A{z^ delta 96 zcmZn=Xb_kn9xBMd${@iY!obd;!@$GDmXey5SejG9z#ziRYUkK#?tN_e8%viR`U_@9 po?wt+WnvIu;AY?ls+VG5VnEi*$Htaxn3R*BoSm4Sx-o4EI{>Hd6W#y- diff --git a/compiler/router/tests/02_blockages_test.py b/compiler/router/tests/02_blockages_test.py new file mode 100755 index 00000000..7d46f02b --- /dev/null +++ b/compiler/router/tests/02_blockages_test.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +"Run a regresion test the library cells for DRC" + +import unittest +from testutils import header,openram_test +import sys,os +sys.path.append(os.path.join(sys.path[0],"../..")) +sys.path.append(os.path.join(sys.path[0],"..")) +import globals +import debug + +OPTS = globals.OPTS + +class blockages_test(openram_test): + """ + Simple two pin route test with multilayer blockages. + """ + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + from gds_cell import gds_cell + from design import design + from router import router + + class routing(design, openram_test): + """ + A generic GDS design that we can route on. + """ + def __init__(self, name): + design.__init__(self, "top") + + # Instantiate a GDS cell with the design + gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) + cell = gds_cell(name, gds_file) + self.add_inst(name=name, + mod=cell, + offset=[0,0]) + self.connect_inst([]) + + r=router(gds_file) + layer_stack =("metal1","via1","metal2") + self.assertTrue(r.route(self,layer_stack,src="A",dest="B")) + + r=routing("02_blockages_test_{0}".format(OPTS.tech_name)) + self.local_drc_check(r) + + # fails if there are any DRC errors on any cells + globals.end_openram() + + + + + +# instantiate a copy of the class to actually run the test +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main() diff --git a/router/tests/02_blockages_test.sp b/compiler/router/tests/02_blockages_test.sp similarity index 100% rename from router/tests/02_blockages_test.sp rename to compiler/router/tests/02_blockages_test.sp diff --git a/router/tests/02_blockages_test_freepdk45.gds b/compiler/router/tests/02_blockages_test_freepdk45.gds similarity index 62% rename from router/tests/02_blockages_test_freepdk45.gds rename to compiler/router/tests/02_blockages_test_freepdk45.gds index 2e31ba2cff1360a454848edac4368f8ec4f94854..e6f868dc1c849f960fa7355608d9cadb055403a1 100644 GIT binary patch delta 93 zcmZn=Xb_kn?k~i^!63%K%^=EP%)rCMmXey5SejG9z#ziRYUkK#?tN_e8%viR`U_@9 meqfMcWnvHjs^w=8VUS{AVnEi*!NyjST3oU*XA1iyW;OtNMG~O^ delta 96 zcmZn=Xb_kn9xA}V%^<`e&LGR6#lXYFmXey5SejG9z#ziRYUkK#?tN_e8%viR`U_@9 ou`tN6GBJSE^D~GrNHIXzFuiIr+)iiRq~u)26Tk0F43@M*si- diff --git a/router/tests/02_blockages_test_scn3me_subm.gds b/compiler/router/tests/02_blockages_test_scn3me_subm.gds similarity index 59% rename from router/tests/02_blockages_test_scn3me_subm.gds rename to compiler/router/tests/02_blockages_test_scn3me_subm.gds index f9407ee4b4cfd79d8e6368c0b7c8885060dfe322..aec979e4ddb1ff7344358439819055fe43ebabf0 100644 GIT binary patch delta 93 zcmZn=Xb_kn?k~i^!63%K#lXj4%D}_KmXey5SejG9z#ziRYUkK#?tN_e8%viR`U_@9 po?wt+WnvIu;AY@w5MhvFU}8Y%HDlmlV=GB5F4>qfg?$n;8vt=B5^ewh delta 96 zcmZn=Xb_kn9xBMd${@iY!obO(!ob7CmXey5SejG9z#ziRYUkK#?tN_e8%viR`U_@9 p-eHhoWnvIu;AY?ls+VG5VnEi*$Htaxn3R*BoSm4Sx-o4EI{>Lx6XpN_ diff --git a/compiler/router/tests/03_same_layer_pins_test.py b/compiler/router/tests/03_same_layer_pins_test.py new file mode 100755 index 00000000..39a72990 --- /dev/null +++ b/compiler/router/tests/03_same_layer_pins_test.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +"Run a regresion test the library cells for DRC" + +import unittest +from testutils import header,openram_test +import sys,os +sys.path.append(os.path.join(sys.path[0],"../..")) +sys.path.append(os.path.join(sys.path[0],"..")) +import globals +import debug + +OPTS = globals.OPTS + +class same_layer_pins_test(openram_test): + """ + Checks two pins on the same layer with positive and negative coordinates. + """ + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + from gds_cell import gds_cell + from design import design + from router import router + + class routing(design, openram_test): + """ + A generic GDS design that we can route on. + """ + def __init__(self, name): + design.__init__(self, "top") + + # Instantiate a GDS cell with the design + gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) + cell = gds_cell(name, gds_file) + self.add_inst(name=name, + mod=cell, + offset=[0,0]) + self.connect_inst([]) + + r=router(gds_file) + layer_stack =("metal1","via1","metal2") + self.assertTrue(r.route(self,layer_stack,src="A",dest="B")) + + r = routing("03_same_layer_pins_test_{0}".format(OPTS.tech_name)) + self.local_drc_check(r) + + # fails if there are any DRC errors on any cells + globals.end_openram() + +# instantiate a copy of the class to actually run the test +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main() diff --git a/router/tests/03_same_layer_pins_test.sp b/compiler/router/tests/03_same_layer_pins_test.sp similarity index 100% rename from router/tests/03_same_layer_pins_test.sp rename to compiler/router/tests/03_same_layer_pins_test.sp diff --git a/router/tests/03_same_layer_pins_test_freepdk45.gds b/compiler/router/tests/03_same_layer_pins_test_freepdk45.gds similarity index 100% rename from router/tests/03_same_layer_pins_test_freepdk45.gds rename to compiler/router/tests/03_same_layer_pins_test_freepdk45.gds diff --git a/router/tests/03_same_layer_pins_test_scn3me_subm.gds b/compiler/router/tests/03_same_layer_pins_test_scn3me_subm.gds similarity index 100% rename from router/tests/03_same_layer_pins_test_scn3me_subm.gds rename to compiler/router/tests/03_same_layer_pins_test_scn3me_subm.gds diff --git a/compiler/router/tests/04_diff_layer_pins_test.py b/compiler/router/tests/04_diff_layer_pins_test.py new file mode 100755 index 00000000..0390a6b4 --- /dev/null +++ b/compiler/router/tests/04_diff_layer_pins_test.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +"Run a regresion test the library cells for DRC" + +import unittest +from testutils import header,openram_test +import sys,os +sys.path.append(os.path.join(sys.path[0],"../..")) +sys.path.append(os.path.join(sys.path[0],"..")) +import globals +import debug + +OPTS = globals.OPTS + +class diff_layer_pins_test(openram_test): + """ + Two pin route test with pins on different layers and blockages. + Pins are smaller than grid size. + """ + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + from gds_cell import gds_cell + from design import design + from router import router + + class routing(design, openram_test): + """ + A generic GDS design that we can route on. + """ + def __init__(self, name): + design.__init__(self, "top") + + # Instantiate a GDS cell with the design + gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) + cell = gds_cell(name, gds_file) + self.add_inst(name=name, + mod=cell, + offset=[0,0]) + self.connect_inst([]) + + r=router(gds_file) + layer_stack =("metal1","via1","metal2") + self.assertTrue(r.route(self,layer_stack,src="A",dest="B")) + + r = routing("04_diff_layer_pins_test_{0}".format(OPTS.tech_name)) + self.local_drc_check(r) + + # fails if there are any DRC errors on any cells + globals.end_openram() + +# instantiate a copy of the class to actually run the test +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main() diff --git a/router/tests/04_diff_layer_pins_test.sp b/compiler/router/tests/04_diff_layer_pins_test.sp similarity index 100% rename from router/tests/04_diff_layer_pins_test.sp rename to compiler/router/tests/04_diff_layer_pins_test.sp diff --git a/router/tests/04_diff_layer_pins_test_freepdk45.gds b/compiler/router/tests/04_diff_layer_pins_test_freepdk45.gds similarity index 100% rename from router/tests/04_diff_layer_pins_test_freepdk45.gds rename to compiler/router/tests/04_diff_layer_pins_test_freepdk45.gds diff --git a/router/tests/04_diff_layer_pins_test_scn3me_subm.gds b/compiler/router/tests/04_diff_layer_pins_test_scn3me_subm.gds similarity index 100% rename from router/tests/04_diff_layer_pins_test_scn3me_subm.gds rename to compiler/router/tests/04_diff_layer_pins_test_scn3me_subm.gds diff --git a/compiler/router/tests/05_two_nets_test.py b/compiler/router/tests/05_two_nets_test.py new file mode 100755 index 00000000..e19f7d49 --- /dev/null +++ b/compiler/router/tests/05_two_nets_test.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +"Run a regresion test the library cells for DRC" + +import unittest +from testutils import header,openram_test +import sys,os +sys.path.append(os.path.join(sys.path[0],"../..")) +sys.path.append(os.path.join(sys.path[0],"..")) +import globals +import debug + +OPTS = globals.OPTS + +class two_nets_test(openram_test): + """ + Route two nets in the same GDS file. The routes will interact, + so they must block eachother. + """ + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + from gds_cell import gds_cell + from design import design + from router import router + + class routing(design, openram_test): + """ + A generic GDS design that we can route on. + """ + def __init__(self, name): + design.__init__(self, "top") + + # Instantiate a GDS cell with the design + gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) + cell = gds_cell(name, gds_file) + self.add_inst(name=name, + mod=cell, + offset=[0,0]) + self.connect_inst([]) + + r=router(gds_file) + layer_stack =("metal1","via1","metal2") + self.assertTrue(r.route(self,layer_stack,src="A",dest="B")) + self.assertTrue(r.route(self,layer_stack,src="C",dest="D")) + + r = routing("05_two_nets_test_{0}".format(OPTS.tech_name)) + self.local_drc_check(r) + + # fails if there are any DRC errors on any cells + globals.end_openram() + + +# instantiate a copy of the class to actually run the test +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main() diff --git a/router/tests/05_two_nets_test.sp b/compiler/router/tests/05_two_nets_test.sp similarity index 100% rename from router/tests/05_two_nets_test.sp rename to compiler/router/tests/05_two_nets_test.sp diff --git a/router/tests/05_two_nets_test_freepdk45.gds b/compiler/router/tests/05_two_nets_test_freepdk45.gds similarity index 100% rename from router/tests/05_two_nets_test_freepdk45.gds rename to compiler/router/tests/05_two_nets_test_freepdk45.gds diff --git a/router/tests/05_two_nets_test_scn3me_subm.gds b/compiler/router/tests/05_two_nets_test_scn3me_subm.gds similarity index 100% rename from router/tests/05_two_nets_test_scn3me_subm.gds rename to compiler/router/tests/05_two_nets_test_scn3me_subm.gds diff --git a/router/tests/06_pin_location_test.py b/compiler/router/tests/06_pin_location_test.py similarity index 54% rename from router/tests/06_pin_location_test.py rename to compiler/router/tests/06_pin_location_test.py index 10cb854b..c157dcb8 100755 --- a/router/tests/06_pin_location_test.py +++ b/compiler/router/tests/06_pin_location_test.py @@ -1,57 +1,43 @@ -#!/usr/bin/env python2.7 +#!/usr/bin/env python3 "Run a regresion test the library cells for DRC" import unittest -from testutils import header +from testutils import header,openram_test import sys,os sys.path.append(os.path.join(sys.path[0],"../..")) sys.path.append(os.path.join(sys.path[0],"..")) import globals import debug -import calibre OPTS = globals.OPTS -class pin_location_test(unittest.TestCase): +class pin_location_test(openram_test): """ Simplest two pin route test with no blockages using the pin locations instead of labels. """ def runTest(self): globals.init_openram("config_{0}".format(OPTS.tech_name)) + from gds_cell import gds_cell + from design import design + from router import router - import design - import router - - class gdscell(design.design): + class routing(design, openram_test): """ A generic GDS design that we can route on. """ def __init__(self, name): - #design.design.__init__(self, name) - debug.info(2, "Create {0} object".format(name)) - self.name = name - self.gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) - self.sp_file = "{0}/{1}.sp".format(os.path.dirname(os.path.realpath(__file__)),name) - design.hierarchy_layout.layout.__init__(self, name) - design.hierarchy_spice.spice.__init__(self, name) - - class routing(design.design,unittest.TestCase): - """ - A generic GDS design that we can route on. - """ - def __init__(self, name): - design.design.__init__(self, name) - debug.info(2, "Create {0} object".format(name)) + design.__init__(self, "top") - cell = gdscell(name) + # Instantiate a GDS cell with the design + gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) + cell = gds_cell(name, gds_file) self.add_inst(name=name, mod=cell, offset=[0,0]) self.connect_inst([]) - self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) - r=router.router(self.gdsname) + r=router(gds_file) layer_stack =("metal1","via1","metal2") # these are user coordinates and layers src_pin = [[0.52, 4.099],11] @@ -62,21 +48,12 @@ class pin_location_test(unittest.TestCase): # This only works for freepdk45 since the coordinates are hard coded if OPTS.tech_name == "freepdk45": r = routing("06_pin_location_test_{0}".format(OPTS.tech_name)) - self.local_check(r) + self.local_drc_check(r) else: debug.warning("This test does not support technology {0}".format(OPTS.tech_name)) - + # fails if there are any DRC errors on any cells globals.end_openram() - - - def local_check(self, r): - tempgds = OPTS.openram_temp + "temp.gds" - r.gds_write(tempgds) - self.assertFalse(calibre.run_drc(r.name, tempgds)) - os.remove(tempgds) - - diff --git a/router/tests/06_pin_location_test_freepdk45.gds b/compiler/router/tests/06_pin_location_test_freepdk45.gds similarity index 100% rename from router/tests/06_pin_location_test_freepdk45.gds rename to compiler/router/tests/06_pin_location_test_freepdk45.gds diff --git a/router/tests/06_pin_location_test_scn3me_subm.gds b/compiler/router/tests/06_pin_location_test_scn3me_subm.gds similarity index 100% rename from router/tests/06_pin_location_test_scn3me_subm.gds rename to compiler/router/tests/06_pin_location_test_scn3me_subm.gds diff --git a/router/tests/07_big_test.py b/compiler/router/tests/07_big_test.py similarity index 63% rename from router/tests/07_big_test.py rename to compiler/router/tests/07_big_test.py index 4e66c07e..e71e0bf4 100755 --- a/router/tests/07_big_test.py +++ b/compiler/router/tests/07_big_test.py @@ -1,58 +1,44 @@ -#!/usr/bin/env python2.7 +#!/usr/bin/env python3 "Run a regresion test the library cells for DRC" import unittest -from testutils import header +from testutils import header,openram_test import sys,os sys.path.append(os.path.join(sys.path[0],"../..")) sys.path.append(os.path.join(sys.path[0],"..")) import globals import debug -import calibre OPTS = globals.OPTS -class big_test(unittest.TestCase): +class big_test(openram_test): """ Simplest two pin route test with no blockages using the pin locations instead of labels. """ def runTest(self): globals.init_openram("config_{0}".format(OPTS.tech_name)) + from gds_cell import gds_cell + from design import design + from router import router - import design - import router - - class gdscell(design.design): + class routing(design, openram_test): """ A generic GDS design that we can route on. """ def __init__(self, name): - #design.design.__init__(self, name) - debug.info(2, "Create {0} object".format(name)) - self.name = name - self.gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) - self.sp_file = "{0}/{1}.sp".format(os.path.dirname(os.path.realpath(__file__)),name) - design.hierarchy_layout.layout.__init__(self, name) - design.hierarchy_spice.spice.__init__(self, name) - - class routing(design.design,unittest.TestCase): - """ - A generic GDS design that we can route on. - """ - def __init__(self, name): - design.design.__init__(self, name) - debug.info(2, "Create {0} object".format(name)) + design.__init__(self, "top") - cell = gdscell(name) + # Instantiate a GDS cell with the design + gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) + cell = gds_cell(name, gds_file) self.add_inst(name=name, mod=cell, offset=[0,0]) self.connect_inst([]) - self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) - r=router.router(self.gdsname) - layer_stack =("metal3","via2","metal2") + r=router(gds_file) + layer_stack =("metal1","via1","metal2") connections=[('out_0_2', 'a_0_0'), ('out_0_3', 'b_0_0'), ('out_0_0', 'a_0_1'), @@ -80,21 +66,12 @@ class big_test(unittest.TestCase): # This test only runs on scn3me_subm tech if OPTS.tech_name=="scn3me_subm": r = routing("07_big_test_{0}".format(OPTS.tech_name)) - self.local_check(r) + self.local_drc_check(r) else: debug.warning("This test does not support technology {0}".format(OPTS.tech_name)) # fails if there are any DRC errors on any cells globals.end_openram() - - - def local_check(self, r): - tempgds = OPTS.openram_temp + "temp.gds" - r.gds_write(tempgds) - self.assertFalse(calibre.run_drc(r.name, tempgds)) - os.remove(tempgds) - - diff --git a/router/tests/07_big_test_scn3me_subm.gds b/compiler/router/tests/07_big_test_scn3me_subm.gds similarity index 100% rename from router/tests/07_big_test_scn3me_subm.gds rename to compiler/router/tests/07_big_test_scn3me_subm.gds diff --git a/router/tests/08_expand_region_test.py b/compiler/router/tests/08_expand_region_test.py similarity index 51% rename from router/tests/08_expand_region_test.py rename to compiler/router/tests/08_expand_region_test.py index f7d3805b..47941b92 100755 --- a/router/tests/08_expand_region_test.py +++ b/compiler/router/tests/08_expand_region_test.py @@ -1,57 +1,43 @@ -#!/usr/bin/env python2.7 +#!/usr/bin/env python3 "Run a regresion test the library cells for DRC" import unittest -from testutils import header +from testutils import header,openram_test import sys,os sys.path.append(os.path.join(sys.path[0],"../..")) sys.path.append(os.path.join(sys.path[0],"..")) import globals import debug -import calibre OPTS = globals.OPTS -class expand_region_test(unittest.TestCase): +class expand_region_test(openram_test): """ Test an infeasible route followed by a feasible route with an expanded region. """ def runTest(self): globals.init_openram("config_{0}".format(OPTS.tech_name)) + from gds_cell import gds_cell + from design import design + from router import router - import design - import router - - class gdscell(design.design): + class routing(design, openram_test): """ A generic GDS design that we can route on. """ def __init__(self, name): - #design.design.__init__(self, name) - debug.info(2, "Create {0} object".format(name)) - self.name = name - self.gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) - self.sp_file = "{0}/{1}.sp".format(os.path.dirname(os.path.realpath(__file__)),name) - design.hierarchy_layout.layout.__init__(self, name) - design.hierarchy_spice.spice.__init__(self, name) - - class routing(design.design,unittest.TestCase): - """ - A generic GDS design that we can route on. - """ - def __init__(self, name): - design.design.__init__(self, name) - debug.info(2, "Create {0} object".format(name)) + design.__init__(self, "top") - cell = gdscell(name) + # Instantiate a GDS cell with the design + gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) + cell = gds_cell(name, gds_file) self.add_inst(name=name, mod=cell, offset=[0,0]) self.connect_inst([]) - self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) - r=router.router(self.gdsname) + r=router(gds_file) layer_stack =("metal1","via1","metal2") # This should be infeasible because it is blocked without a detour. self.assertFalse(r.route(self,layer_stack,src="A",dest="B",detour_scale=1)) @@ -59,22 +45,12 @@ class expand_region_test(unittest.TestCase): self.assertTrue(r.route(self,layer_stack,src="A",dest="B",detour_scale=3)) r = routing("08_expand_region_test_{0}".format(OPTS.tech_name)) - self.local_check(r) + self.local_drc_check(r) # fails if there are any DRC errors on any cells globals.end_openram() - def local_check(self, r): - tempgds = OPTS.openram_temp + "temp.gds" - r.gds_write(tempgds) - self.assertFalse(calibre.run_drc(r.name, tempgds)) - os.remove(tempgds) - - - - - # instantiate a copy of the class to actually run the test if __name__ == "__main__": (OPTS, args) = globals.parse_args() diff --git a/router/tests/08_expand_region_test_freepdk45.gds b/compiler/router/tests/08_expand_region_test_freepdk45.gds similarity index 100% rename from router/tests/08_expand_region_test_freepdk45.gds rename to compiler/router/tests/08_expand_region_test_freepdk45.gds diff --git a/router/tests/08_expand_region_test_scn3me_subm.gds b/compiler/router/tests/08_expand_region_test_scn3me_subm.gds similarity index 100% rename from router/tests/08_expand_region_test_scn3me_subm.gds rename to compiler/router/tests/08_expand_region_test_scn3me_subm.gds diff --git a/router/tests/config_freepdk45.py b/compiler/router/tests/config_freepdk45.py similarity index 100% rename from router/tests/config_freepdk45.py rename to compiler/router/tests/config_freepdk45.py diff --git a/router/tests/config_scn3me_subm.py b/compiler/router/tests/config_scn3me_subm.py similarity index 100% rename from router/tests/config_scn3me_subm.py rename to compiler/router/tests/config_scn3me_subm.py diff --git a/compiler/router/tests/gds_cell.py b/compiler/router/tests/gds_cell.py new file mode 100644 index 00000000..5c1e0f91 --- /dev/null +++ b/compiler/router/tests/gds_cell.py @@ -0,0 +1,16 @@ +from design import design +class gds_cell(design): + """ + A generic GDS design. + """ + def __init__(self, name, gds_file): + self.name = name + self.gds_file = gds_file + self.sp_file = None + + design.__init__(self, name) + + # The dimensions will not be defined, so do this... + self.width=0 + self.height=0 + diff --git a/router/tests/regress.py b/compiler/router/tests/regress.py similarity index 100% rename from router/tests/regress.py rename to compiler/router/tests/regress.py diff --git a/router/tests/testutils.py b/compiler/router/tests/testutils.py similarity index 98% rename from router/tests/testutils.py rename to compiler/router/tests/testutils.py index 64c1c2b4..4bea5d15 100755 --- a/router/tests/testutils.py +++ b/compiler/router/tests/testutils.py @@ -1,6 +1,6 @@ import unittest,warnings import sys,os,glob,copy -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.path.join(sys.path[0],"../..")) from globals import OPTS import debug @@ -19,7 +19,8 @@ class openram_test(unittest.TestCase): if result != 0: self.fail("DRC failed: {}".format(w.name)) - self.cleanup() + if OPTS.purge_temp: + self.cleanup() def local_check(self, a, final_verification=False): diff --git a/router/vector3d.py b/compiler/router/vector3d.py similarity index 100% rename from router/vector3d.py rename to compiler/router/vector3d.py diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 112b1257..0f025b2b 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -86,6 +86,10 @@ def write_magic_script(cell_name, gds_name, extract=False): f.write("gds warning default\n") f.write("gds read {}\n".format(gds_name)) 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("writeall force\n") f.write("drc check\n") f.write("drc catchup\n") diff --git a/router/tests/01_no_blockages_test.py b/router/tests/01_no_blockages_test.py deleted file mode 100755 index 1d0b4640..00000000 --- a/router/tests/01_no_blockages_test.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env python2.7 -"Run a regresion test the library cells for DRC" - -import unittest -from testutils import header -import sys,os -sys.path.append(os.path.join(sys.path[0],"../..")) -sys.path.append(os.path.join(sys.path[0],"..")) -import globals -import debug - -OPTS = globals.OPTS - -class no_blockages_test(unittest.TestCase): - """ - Simplest two pin route test with no blockages. - """ - - def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) - global verify - import verify - - import design - import router - - class gdscell(design.design): - """ - A generic GDS design that we can route on. - """ - def __init__(self, name): - #design.design.__init__(self, name) - debug.info(2, "Create {0} object".format(name)) - self.name = name - self.gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) - self.sp_file = "{0}/{1}.sp".format(os.path.dirname(os.path.realpath(__file__)),name) - design.hierarchy_layout.layout.__init__(self, name) - design.hierarchy_spice.spice.__init__(self, name) - - class routing(design.design,unittest.TestCase): - """ - A generic GDS design that we can route on. - """ - def __init__(self, name): - design.design.__init__(self, name) - debug.info(2, "Create {0} object".format(name)) - - cell = gdscell(name) - self.add_inst(name=name, - mod=cell, - offset=[0,0]) - self.connect_inst([]) - - self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) - r=router.router(self.gdsname) - layer_stack =("metal1","via1","metal2") - self.assertTrue(r.route(self,layer_stack,src="A",dest="B")) - - r = routing("01_no_blockages_test_{0}".format(OPTS.tech_name)) - self.local_check(r) - - # fails if there are any DRC errors on any cells - globals.end_openram() - - - def local_check(self, r): - tempgds = OPTS.openram_temp + "temp.gds" - r.gds_write(tempgds) - self.assertFalse(calibre.run_drc(r.name, tempgds)) - os.remove(tempgds) - - - - - -# instantiate a copy of the class to actually run the test -if __name__ == "__main__": - (OPTS, args) = globals.parse_args() - del sys.argv[1:] - header(__file__, OPTS.tech_name) - unittest.main() diff --git a/router/tests/02_blockages_test.py b/router/tests/02_blockages_test.py deleted file mode 100755 index 2afefa4a..00000000 --- a/router/tests/02_blockages_test.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python2.7 -"Run a regresion test the library cells for DRC" - -import unittest -from testutils import header -import sys,os -sys.path.append(os.path.join(sys.path[0],"../..")) -sys.path.append(os.path.join(sys.path[0],"..")) -import globals -import debug -import calibre - -OPTS = globals.OPTS - -class blockages_test(unittest.TestCase): - """ - Simple two pin route test with multilayer blockages. - """ - - def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) - - import design - import router - - class gdscell(design.design): - """ - A generic GDS design that we can route on. - """ - def __init__(self, name): - #design.design.__init__(self, name) - debug.info(2, "Create {0} object".format(name)) - self.name = name - self.gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) - self.sp_file = "{0}/{1}.sp".format(os.path.dirname(os.path.realpath(__file__)),name) - design.hierarchy_layout.layout.__init__(self, name) - design.hierarchy_spice.spice.__init__(self, name) - - class routing(design.design,unittest.TestCase): - """ - A generic GDS design that we can route on. - """ - def __init__(self, name): - design.design.__init__(self, name) - debug.info(2, "Create {0} object".format(name)) - - cell = gdscell(name) - self.add_inst(name=name, - mod=cell, - offset=[0,0]) - self.connect_inst([]) - - self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) - r=router.router(self.gdsname) - layer_stack =("metal1","via1","metal2") - self.assertTrue(r.route(self,layer_stack,src="A",dest="B")) - - r = routing("02_blockages_test_{0}".format(OPTS.tech_name)) - self.local_check(r) - - # fails if there are any DRC errors on any cells - globals.end_openram() - - - def local_check(self, r): - tempgds = OPTS.openram_temp + "temp.gds" - r.gds_write(tempgds) - self.assertFalse(calibre.run_drc(r.name, tempgds)) - os.remove(tempgds) - - - - - -# instantiate a copy of the class to actually run the test -if __name__ == "__main__": - (OPTS, args) = globals.parse_args() - del sys.argv[1:] - header(__file__, OPTS.tech_name) - unittest.main() diff --git a/router/tests/03_same_layer_pins_test.py b/router/tests/03_same_layer_pins_test.py deleted file mode 100755 index dfd849c9..00000000 --- a/router/tests/03_same_layer_pins_test.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python2.7 -"Run a regresion test the library cells for DRC" - -import unittest -from testutils import header -import sys,os -sys.path.append(os.path.join(sys.path[0],"../..")) -sys.path.append(os.path.join(sys.path[0],"..")) -import globals -import debug -import calibre - -OPTS = globals.OPTS - -class same_layer_pins_test(unittest.TestCase): - """ - Checks two pins on the same layer with positive and negative coordinates. - """ - def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) - - import design - import router - - class gdscell(design.design): - """ - A generic GDS design that we can route on. - """ - def __init__(self, name): - #design.design.__init__(self, name) - debug.info(2, "Create {0} object".format(name)) - self.name = name - self.gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) - self.sp_file = "{0}/{1}.sp".format(os.path.dirname(os.path.realpath(__file__)),name) - design.hierarchy_layout.layout.__init__(self, name) - design.hierarchy_spice.spice.__init__(self, name) - - class routing(design.design,unittest.TestCase): - """ - A generic GDS design that we can route on. - """ - def __init__(self, name): - design.design.__init__(self, name) - debug.info(2, "Create {0} object".format(name)) - - cell = gdscell(name) - self.add_inst(name=name, - mod=cell, - offset=[0,0]) - self.connect_inst([]) - - self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) - r=router.router(self.gdsname) - layer_stack =("metal1","via1","metal2") - self.assertTrue(r.route(self,layer_stack,src="A",dest="B")) - - r = routing("03_same_layer_pins_test_{0}".format(OPTS.tech_name)) - self.local_check(r) - - - # fails if there are any DRC errors on any cells - globals.end_openram() - - - def local_check(self, r): - tempgds = OPTS.openram_temp + "temp.gds" - r.gds_write(tempgds) - self.assertFalse(calibre.run_drc(r.name, tempgds)) - os.remove(tempgds) - - - - - -# instantiate a copy of the class to actually run the test -if __name__ == "__main__": - (OPTS, args) = globals.parse_args() - del sys.argv[1:] - header(__file__, OPTS.tech_name) - unittest.main() diff --git a/router/tests/04_diff_layer_pins_test.py b/router/tests/04_diff_layer_pins_test.py deleted file mode 100755 index e0a54875..00000000 --- a/router/tests/04_diff_layer_pins_test.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env python2.7 -"Run a regresion test the library cells for DRC" - -import unittest -from testutils import header -import sys,os -sys.path.append(os.path.join(sys.path[0],"../..")) -sys.path.append(os.path.join(sys.path[0],"..")) -import globals -import debug -import calibre - -OPTS = globals.OPTS - -class diff_layer_pins_test(unittest.TestCase): - """ - Two pin route test with pins on different layers and blockages. - Pins are smaller than grid size. - """ - - def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) - - import design - import router - - class gdscell(design.design): - """ - A generic GDS design that we can route on. - """ - def __init__(self, name): - #design.design.__init__(self, name) - debug.info(2, "Create {0} object".format(name)) - self.name = name - self.gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) - self.sp_file = "{0}/{1}.sp".format(os.path.dirname(os.path.realpath(__file__)),name) - design.hierarchy_layout.layout.__init__(self, name) - design.hierarchy_spice.spice.__init__(self, name) - - class routing(design.design,unittest.TestCase): - """ - A generic GDS design that we can route on. - """ - def __init__(self, name): - design.design.__init__(self, name) - debug.info(2, "Create {0} object".format(name)) - - cell = gdscell(name) - self.add_inst(name=name, - mod=cell, - offset=[0,0]) - self.connect_inst([]) - - self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) - r=router.router(self.gdsname) - layer_stack =("metal1","via1","metal2") - self.assertTrue(r.route(self,layer_stack,src="A",dest="B")) - - r = routing("04_diff_layer_pins_test_{0}".format(OPTS.tech_name)) - self.local_check(r) - - # fails if there are any DRC errors on any cells - globals.end_openram() - - - def local_check(self, r): - tempgds = OPTS.openram_temp + "temp.gds" - r.gds_write(tempgds) - self.assertFalse(calibre.run_drc(r.name, tempgds)) - os.remove(tempgds) - - - - - -# instantiate a copy of the class to actually run the test -if __name__ == "__main__": - (OPTS, args) = globals.parse_args() - del sys.argv[1:] - header(__file__, OPTS.tech_name) - unittest.main() diff --git a/router/tests/05_two_nets_test.py b/router/tests/05_two_nets_test.py deleted file mode 100755 index b59dd005..00000000 --- a/router/tests/05_two_nets_test.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python2.7 -"Run a regresion test the library cells for DRC" - -import unittest -from testutils import header -import sys,os -sys.path.append(os.path.join(sys.path[0],"../..")) -sys.path.append(os.path.join(sys.path[0],"..")) -import globals -import debug -import calibre - -OPTS = globals.OPTS - -class two_nets_test(unittest.TestCase): - """ - Route two nets in the same GDS file. The routes will interact, - so they must block eachother. - """ - - def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) - - import design - import router - - class gdscell(design.design): - """ - A generic GDS design that we can route on. - """ - def __init__(self, name): - #design.design.__init__(self, name) - debug.info(2, "Create {0} object".format(name)) - self.name = name - self.gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) - self.sp_file = "{0}/{1}.sp".format(os.path.dirname(os.path.realpath(__file__)),name) - design.hierarchy_layout.layout.__init__(self, name) - design.hierarchy_spice.spice.__init__(self, name) - - class routing(design.design,unittest.TestCase): - """ - A generic GDS design that we can route on. - """ - def __init__(self, name): - design.design.__init__(self, name) - debug.info(2, "Create {0} object".format(name)) - - cell = gdscell(name) - self.add_inst(name=name, - mod=cell, - offset=[0,0]) - self.connect_inst([]) - - self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) - r=router.router(self.gdsname) - layer_stack =("metal1","via1","metal2") - self.assertTrue(r.route(self,layer_stack,src="A",dest="B")) - self.assertTrue(r.route(self,layer_stack,src="C",dest="D")) - - r = routing("05_two_nets_test_{0}".format(OPTS.tech_name)) - self.local_check(r) - - # fails if there are any DRC errors on any cells - globals.end_openram() - - - def local_check(self, r): - tempgds = OPTS.openram_temp + "temp.gds" - r.gds_write(tempgds) - self.assertFalse(calibre.run_drc(r.name, tempgds)) - os.remove(tempgds) - - - - - -# instantiate a copy of the class to actually run the test -if __name__ == "__main__": - (OPTS, args) = globals.parse_args() - del sys.argv[1:] - header(__file__, OPTS.tech_name) - unittest.main()