From 0a9b326f6acc91fb5e91c4706815011700922f6f Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Thu, 17 Nov 2016 13:26:03 -0800 Subject: [PATCH] Contract path to simplified route --- compiler/hierarchy_layout.py | 5 +- compiler/router/cell.py | 2 +- compiler/router/grid.py | 3 +- compiler/router/router.py | 79 ++++++++++++++++--- compiler/router/tests/01_no_blockages_test.py | 77 ++++++++++++------ .../router/tests/A_to_B_m1m2_blockages.sp | 3 + .../tests/A_to_B_m1m2_diff_layer_pins.sp | 3 + .../tests/A_to_B_m1m2_same_layer_pins.sp | 3 + compiler/router/tests/A_to_B_no_blockages.sp | 3 + 9 files changed, 135 insertions(+), 43 deletions(-) create mode 100644 compiler/router/tests/A_to_B_m1m2_blockages.sp create mode 100644 compiler/router/tests/A_to_B_m1m2_diff_layer_pins.sp create mode 100644 compiler/router/tests/A_to_B_m1m2_same_layer_pins.sp create mode 100644 compiler/router/tests/A_to_B_no_blockages.sp diff --git a/compiler/hierarchy_layout.py b/compiler/hierarchy_layout.py index 2abd591c..506911e0 100644 --- a/compiler/hierarchy_layout.py +++ b/compiler/hierarchy_layout.py @@ -244,12 +244,9 @@ class layout: self.gds = gdsMill.VlsiLayout(units=GDS["unit"]) reader = gdsMill.Gds2reader(self.gds) reader.loadFromFile(self.gds_file) - # TODO: parse the width/height - # TODO: parse the pin locations else: debug.info(3, "creating structure %s" % self.name) - self.gds = gdsMill.VlsiLayout( - name=self.name, units=GDS["unit"]) + self.gds = gdsMill.VlsiLayout(name=self.name, units=GDS["unit"]) def print_gds(self, gds_file=None): """Print the gds file (not the vlsi class) to the terminal """ diff --git a/compiler/router/cell.py b/compiler/router/cell.py index c36c7957..1e5da018 100644 --- a/compiler/router/cell.py +++ b/compiler/router/cell.py @@ -24,7 +24,7 @@ class cell: b+=b1 count+=1 - if self.source or self.target: + if self.source or self.target: [r1,g1,b1] = ImageColor.getrgb("Red") r+=r1 g+=g1 diff --git a/compiler/router/grid.py b/compiler/router/grid.py index d0e17e52..6a22b8ab 100644 --- a/compiler/router/grid.py +++ b/compiler/router/grid.py @@ -154,11 +154,12 @@ class grid: """ # expand from the last point point = path[-1] + neighbors = [] # check z layer for enforced direction routing if point.z==0: east = point + vector3d(1,0,0) - west= point + vector3d(-11,0,0) + west= point + vector3d(-1,0,0) if east.x=0 and not self.map[west].blocked and not self.map[west].visited: diff --git a/compiler/router/router.py b/compiler/router/router.py index 47ba2872..aab2bfe6 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -62,9 +62,6 @@ class router: self.track_width = max(self.horiz_track_width,self.vert_track_width) print "Track width:",self.track_width - # to scale coordinates to tracks - self.track_factor = [1/self.track_width] * 2 - def create_routing_grid(self): @@ -117,15 +114,16 @@ class router: self.set_source(src) self.set_target(dest) self.find_blockages() + # returns the path in tracks path = self.rg.route() debug.info(0,"Found path. ") debug.info(2,str(path)) - return path + self.set_path(path) + # convert the path back to absolute units from tracks + abs_path = self.convert_path_to_units(path) + debug.info(2,str(abs_path)) + return abs_path - def add_route(self,start, end, layerstack): - """ Add a wire route from the start to the end point""" - pass - def create_steiner_routes(self,pins): """Find a set of steiner points and then return the list of point-to-point routes.""" @@ -163,6 +161,41 @@ class router: coordinate += [vector(maxx, maxy)] return coordinate + def get_inertia(self,p0,p1): + # direction (index) of movement + if p0.x==p1.x: + inertia = 1 + elif p0.y==p1.y: + inertia = 0 + else: + inertia = 2 + return inertia + + def contract_path(self,path): + """ + Remove intermediate points in a rectilinear path. + """ + debug.info(0,"Initial path:"+str(path)) + newpath = [path[0]] + for i in range(len(path)-1): + if i==0: + continue + prev_inertia=self.get_inertia(path[i-1],path[i]) + next_inertia=self.get_inertia(path[i],path[i+1]) + + if prev_inertia!=next_inertia: + newpath.append(path[i]) + else: + continue + + newpath.append(path[-1]) + debug.info(0,"Final path:"+str(newpath)) + return newpath + + def set_path(self,path): + debug.info(2,"Set path: " + str(path)) + self.rg.set_path(path) + def set_source(self,name): shape = self.find_pin(name) zindex = 0 if self.pin_layers[name]==self.horiz_layer_number else 1 @@ -215,6 +248,24 @@ class router: self.write_obstacle(cur_sref.sName, sMirr, sAngle, sxyShift) + def convert_path_to_units(self,path): + """ + Convert a path set of tracks to center line path. + """ + # First, simplify the path. + path = self.contract_path(path) + + newpath = [] + track_factor = [self.track_width] * 2 + for p in path: + # we can ignore the layers here + # add_wire will filter out duplicates + pt = vector(p[0],p[1]) + pt=pt.scale(track_factor) + pt=snap_to_grid(pt+self.offset) + newpath.append(pt) + return newpath + def convert_to_tracks(self,shape,round_bigger=True): """ Convert a rectangular shape into track units. @@ -225,14 +276,18 @@ class router: ll = snap_to_grid(ll-self.offset) ur = snap_to_grid(ur-self.offset) + # to scale coordinates to tracks + track_factor = [1/self.track_width] * 2 + + # Always round blockage shapes up. if round_bigger: - ll = ll.scale(self.track_factor).floor() - ur = ur.scale(self.track_factor).ceil() + ll = ll.scale(track_factor).floor() + ur = ur.scale(track_factor).ceil() # Always round pin shapes down else: - ll = ll.scale(self.track_factor).round() - ur = ur.scale(self.track_factor).round() + ll = ll.scale(track_factor).round() + ur = ur.scale(track_factor).round() return [ll,ur] diff --git a/compiler/router/tests/01_no_blockages_test.py b/compiler/router/tests/01_no_blockages_test.py index 89c3019e..2254ba5e 100644 --- a/compiler/router/tests/01_no_blockages_test.py +++ b/compiler/router/tests/01_no_blockages_test.py @@ -10,46 +10,73 @@ import globals import debug import calibre + class no_blockages_test(unittest.TestCase): def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) - + globals.init_openram("config_{0}".format(OPTS.tech_name)) + + import design import router - import wire - import tech - #r=router.router("A_to_B_no_blockages.gds") - #r=router.router("A_to_B_m1m2_blockages.gds") - #r=router.router("A_to_B_m1m2_same_layer_pins.gds") - r=router.router("A_to_B_m1m2_diff_layer_pins.gds") - layer_stack =("metal1","via1","metal2") - path=r.route(layer_stack,src="A",dest="B") - # For debug, to view the result as an image - r.rg.set_path(path) - r.rg.view() - OPTS.check_lvsdrc = False + 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 = name + ".gds" + self.sp_file = name + ".sp" + design.hierarchy_layout.layout.__init__(self, name) + design.hierarchy_spice.spice.__init__(self, name) + + class routing(design.design): + """ + A generic GDS design that we can route on. + """ + def __init__(self, name, gdsname): + design.design.__init__(self, name) + debug.info(2, "Create {0} object".format(name)) - #w = wire.wire(layer_stack, path) - OPTS.check_lvsdrc = True - #self.local_check(w) + cell = gdscell(gdsname) + self.add_inst(name=gdsname, + mod=cell, + offset=[0,0]) + self.connect_inst([]) + + r=router.router(gdsname+".gds") + layer_stack =("metal1","via1","metal2") + path=r.route(layer_stack,src="A",dest="B") + r.rg.view() + + self.add_wire(layer_stack,path) - #drc_errors = calibre.run_drc(name, gds_name) - drc_errors = 1 + + r = routing("test1", "A_to_B_no_blockages") + self.local_check(r) + + r = routing("A_to_B_m1m2_blockages") + self.local_check(r) + + r = routing("A_to_B_m1m2_same_layer_pins") + self.local_check(r) + + r = routing("A_to_B_m1m2_diff_layer_pins") + self.local_check(r) # fails if there are any DRC errors on any cells self.assertEqual(drc_errors, 0) globals.end_openram() - - - def local_check(self, w): + def local_check(self, r): tempgds = OPTS.openram_temp + "temp.gds" - w.gds_write(tempgds) - self.assertFalse(calibre.run_drc(w.name, tempgds)) + r.gds_write(tempgds) + self.assertFalse(calibre.run_drc(r.name, tempgds)) os.remove(tempgds) - + assert(0) diff --git a/compiler/router/tests/A_to_B_m1m2_blockages.sp b/compiler/router/tests/A_to_B_m1m2_blockages.sp new file mode 100644 index 00000000..d0b092ca --- /dev/null +++ b/compiler/router/tests/A_to_B_m1m2_blockages.sp @@ -0,0 +1,3 @@ + +.SUBCKT cell +.ENDS cell diff --git a/compiler/router/tests/A_to_B_m1m2_diff_layer_pins.sp b/compiler/router/tests/A_to_B_m1m2_diff_layer_pins.sp new file mode 100644 index 00000000..d0b092ca --- /dev/null +++ b/compiler/router/tests/A_to_B_m1m2_diff_layer_pins.sp @@ -0,0 +1,3 @@ + +.SUBCKT cell +.ENDS cell diff --git a/compiler/router/tests/A_to_B_m1m2_same_layer_pins.sp b/compiler/router/tests/A_to_B_m1m2_same_layer_pins.sp new file mode 100644 index 00000000..d0b092ca --- /dev/null +++ b/compiler/router/tests/A_to_B_m1m2_same_layer_pins.sp @@ -0,0 +1,3 @@ + +.SUBCKT cell +.ENDS cell diff --git a/compiler/router/tests/A_to_B_no_blockages.sp b/compiler/router/tests/A_to_B_no_blockages.sp new file mode 100644 index 00000000..d0b092ca --- /dev/null +++ b/compiler/router/tests/A_to_B_no_blockages.sp @@ -0,0 +1,3 @@ + +.SUBCKT cell +.ENDS cell