From 55ed6212a1ec67ff3f1be7c9ccc1e3c8d478153b Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 19 Apr 2017 12:41:13 -0700 Subject: [PATCH] Created route and add_route for layer assigned wires. It will replace add_wire/wire eventually. --- compiler/hierarchy_layout.py | 18 +++ compiler/route.py | 119 ++++++++++++++++++ compiler/router/router.py | 24 ++-- .../router/tests/03_same_layer_pins_test.py | 1 - .../router/tests/04_diff_layer_pins_test.gds | Bin 4096 -> 4096 bytes compiler/router/tests/05_two_nets_test.gds | Bin 4096 -> 4096 bytes compiler/router/tests/05_two_nets_test.py | 6 +- 7 files changed, 154 insertions(+), 14 deletions(-) create mode 100644 compiler/route.py diff --git a/compiler/hierarchy_layout.py b/compiler/hierarchy_layout.py index 25b40514..a3f98cc6 100644 --- a/compiler/hierarchy_layout.py +++ b/compiler/hierarchy_layout.py @@ -168,6 +168,24 @@ class layout: self.connect_inst([]) return route + 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 + the coordinates. + """ + import route + debug.info(3,"add route " + str(layers) + " " + str(coordinates)) + # add an instance of our path that breaks down into rectangles and contacts + route = route.route(layer_stack=layers, + path=coordinates) + self.add_mod(route) + self.add_inst(name=route.name, + mod=route) + # We don't model the logical connectivity of wires/paths + self.connect_inst([]) + return route + def add_wire(self, layers, coordinates, offset=None): """Connects a routing path on given layer,coordinates,width. The layers are the (horizontal, via, vertical). """ diff --git a/compiler/route.py b/compiler/route.py new file mode 100644 index 00000000..69c5796f --- /dev/null +++ b/compiler/route.py @@ -0,0 +1,119 @@ +from tech import drc +import debug +import design +from contact import contact +from itertools import tee +from vector import vector +from vector3d import vector3d + +class route(design.design): + """ + Object route + Add a route of minimium metal width between a set of points. + The wire must be completely rectilinear and the + z-dimension of the points refers to the layers (plus via) + The points are the center of the wire. + This can have non-preferred direction routing. + """ + unique_route_id = 1 + + def __init__(self, layer_stack, path): + name = "route_{0}".format(route.unique_route_id) + route.unique_route_id += 1 + design.design.__init__(self, name) + debug.info(3, "create route obj {0}".format(name)) + + self.layer_stack = layer_stack + self.path = path + + self.setup_layers() + self.create_wires() + + + def setup_layers(self): + (horiz_layer, via_layer, vert_layer) = self.layer_stack + self.via_layer_name = via_layer + + self.vert_layer_name = vert_layer + self.vert_layer_width = drc["minwidth_{0}".format(vert_layer)] + + self.horiz_layer_name = horiz_layer + self.horiz_layer_width = drc["minwidth_{0}".format(horiz_layer)] + # offset this by 1/2 the via size + self.c=contact(self.layer_stack, (1, 1)) + + + def create_wires(self): + """ + Add the wire segments of the route. + """ + + def pairwise(iterable): + "s -> (s0,s1), (s1,s2), (s2, s3), ..." + a, b = tee(iterable) + next(b, None) + return zip(a, b) + + plist = pairwise(self.path) + for p0,p1 in plist: + if p0.z != p1.z: # via + via_offset = vector(p0.x-0.5*self.c.width,p0.y-0.5*self.c.height) + self.add_via(self.layer_stack,via_offset) + elif p0.x != p1.x and p0.y != p1.y: # diagonal! + debug.error("Non-changing direction!") + else: + # this will draw an extra corner at the end but that is ok + self.draw_corner_wire(p1) + # draw the point to point wire + self.draw_wire(p0,p1) + + + + def draw_wire(self, p0, p1): + """ + This draws a straight wire with layer_minwidth + """ + layer_name = self.layer_stack[2*p0.z] + layer_width = drc["minwidth_{0}".format(layer_name)] + + # always route left to right or bottom to top + if p0.z != p1.z: + self.error("Adding a via as a wire!") + elif p0.x < p1.x or p0.y < p1.y: + start = p0 + end = p1 + elif p0.x > p1.x or p0.y > p1.y: + start = p1 + end = p0 + else: + debug.error("Neither horizontal or vertical wire.") + + # now determine the route geometry and offset + if start.x != end.x: # horizontal + offset = start + vector3d(0,-0.5*layer_width,0) + height = layer_width + width = end.x - start.x + elif start.y != end.y: # vertical + offset = start + vector3d(-0.5*layer_width,0,0) + height = end.y - start.y + width = layer_width + + self.add_rect(layer=layer_name, + offset=offset, + width=width, + height=height) + + + def draw_corner_wire(self, p0): + """ This function adds the corner squares since the center + line convention only draws to the center of the corner.""" + + layer_name = self.layer_stack[2*p0.z] + layer_width = drc["minwidth_{0}".format(layer_name)] + offset = vector(p0.x-0.5*layer_width,p0.y-0.5*layer_width) + self.add_rect(layer=layer_name, + offset=offset, + width=layer_width, + height=layer_width) + + diff --git a/compiler/router/router.py b/compiler/router/router.py index 4d0f76b3..d8d5e632 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -3,9 +3,9 @@ import tech from contact import contact import math import debug -from vector import vector import grid - +from vector import vector +from vector3d import vector3d class router: @@ -97,6 +97,7 @@ class router: self.pin_shapes[str(pin)]=[] self.pin_names.append(pin_name) + self.pin_layers[str(pin)] = pin_layer 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))) @@ -104,7 +105,6 @@ class router: shape=[vector(pin_shape[0],pin_shape[1]),vector(pin_shape[2],pin_shape[3])] # convert the pin coordinates to tracks and round the sizes down self.pin_shapes[str(pin)].append(shape) - self.pin_layers[str(pin)] = pin_layer self.all_pin_shapes.append(shape) return self.pin_shapes[str(pin)] @@ -168,7 +168,7 @@ class router: Add the current wire route to the given design instance. """ # First, simplify the path for - debug.info(1,str(self.path)) + #debug.info(1,str(self.path)) contracted_path = self.contract_path(self.path) debug.info(1,str(contracted_path)) @@ -188,17 +188,17 @@ class router: # convert the path back to absolute units from tracks abs_path = map(self.convert_point_to_units,contracted_path) - cell.add_wire(self.layers,abs_path) debug.info(1,str(abs_path)) + cell.add_route(self.layers,abs_path) # Check if a via is needed at the start point - if (contracted_path[0].z!=contracted_path[1].z): + if (contracted_path[0].z!=self.source_pin_layer): # offset this by 1/2 the via size c=contact(self.layers, (1, 1)) via_offset = vector(-0.5*c.width,-0.5*c.height) cell.add_via(self.layers,abs_path[0]+via_offset) # Check if a via is needed at the end point - if (contracted_path[-1].z!=contracted_path[-2].z): + if (contracted_path[-1].z!=self.target_pin_layer): # offset this by 1/2 the via size c=contact(self.layers, (1, 1)) via_offset = vector(-0.5*c.width,-0.5*c.height) @@ -294,8 +294,10 @@ class router: """ Mark the grids that are in the pin rectangle ranges to have the source property. """ + self.source_pin_name = name shapes = self.find_pin(name) zindex = 0 if self.pin_layers[name]==self.horiz_layer_number else 1 + self.source_pin_layer = zindex for shape in shapes: shape_in_tracks=self.convert_shape_to_tracks(shape) debug.info(1,"Set source: " + str(name) + " " + str(shape_in_tracks) + " z=" + str(zindex)) @@ -306,8 +308,10 @@ class router: """ Mark the grids that are in the pin rectangle ranges to have the target property. """ + self.target_pin_name = name shapes = self.find_pin(name) zindex = 0 if self.pin_layers[name]==self.horiz_layer_number else 1 + self.target_pin_layer = zindex for shape in shapes: shape_in_tracks=self.convert_shape_to_tracks(shape) debug.info(1,"Set target: " + str(name) + " " + str(shape_in_tracks) + " z=" + str(zindex)) @@ -353,10 +357,8 @@ class router: """ Convert a path set of tracks to center line path. """ - # we can ignore the layers here - # add_wire will filter out duplicates - pt = vector(p[0],p[1]) - pt=pt.scale(self.track_widths) + pt = vector3d(p) + pt=pt.scale(self.track_widths[0],self.track_widths[1],1) return pt def convert_shape_to_tracks(self,shape,round_bigger=False): diff --git a/compiler/router/tests/03_same_layer_pins_test.py b/compiler/router/tests/03_same_layer_pins_test.py index 79c399bd..a31074d9 100644 --- a/compiler/router/tests/03_same_layer_pins_test.py +++ b/compiler/router/tests/03_same_layer_pins_test.py @@ -53,7 +53,6 @@ class same_layer_pins_test(unittest.TestCase): layer_stack =("metal1","via1","metal2") r.route(layer_stack,src="A",dest="B") r.add_route(self) - self.gds_write("temp.gds") r = routing("test1", "03_same_layer_pins_test") self.local_check(r) diff --git a/compiler/router/tests/04_diff_layer_pins_test.gds b/compiler/router/tests/04_diff_layer_pins_test.gds index 8a7fd5f4844303e3f977a5fa0ed29dab1216074a..57928eacca32cffd84127658c9d7c13a36d48514 100644 GIT binary patch literal 4096 zcmeH|v1=4T6vp4}?T!*Rr#Zx!xP_>d2;m@tULl$yO%Q@Y3Q;Z*a}dxVlBlJf&0%8| zv=Bin8yoQt5V0^I7B)7Ag8l*Vq6x{3-|R>pOeLQh?rug@)CUn1IH49*;W^XS>vi|eP4Tps>#{>3kff^4>| z)a`}2O09CYQd?ZUaf-;_O{4}rjHOB*5uMmq#5q9Y16n9S@5d@}s6Q0*gDKv0vM0kg z91l$#Nj^;RJpLpa>pL`z|3@W0X~*A1T~|Dy)SZP}^R@B6tyJsQ3{i31=_}|L+>1&a zY+|Jer?lRFi~eIyUuxaHfO}Dik9Fg<-fA+Bc9r>9CBD_n;$i#rKgr9emHZli;zi-gBpe$9Iz)k(?2gcsh3yyvrHM5y=@*iKlZX z#kXd#S0ncwZo1lKRN}0uy_e!m%>i$|12|K=j9T74&*H6rc)zV74Jg+Rqh?&=Z@2N+ zs&*VxLmIAj7?rqrPqKEU=D+b2bFO2zLiI7NH2R4nbs(9)PwDZTliN#r zU^I9+7(Ly8vPR_kL~6mo_f_Z+(Un#mqlcFtU@Zi`PEhPX_iVyn$nfAEVfZ#{U^AjJToHi=Dmg(JHw?9O)uQs+MXzp64-G_HOhJ4i52? zf>u3>{$fQVB-K+lvvH<$ilXQ%KG3!J4qWU_35va&(J93z@-Jh3$KqSy7yK6#d#8vG z-^Yf}zL{@O>>ATLXZ(j_%zq;a$KWB*Wi|{rQ0P zD;AHSI`r@b#lDiq$6oQUej1^h(>MBQ6nlYwvQBvZuGOCrd^?}Bf9!SF=)^qMFGMa3 zioHlb#Qn?0&v<0`F>?HRJ}-XEevCoYSzv%SGCti`;!<))irmpAj zqmEw@F*?^!Dwh%zJ1~b2Ey~wR#{UfUGQr0lkR$%il=YI~&rmNDeE62Sn66$@eB`-& zy=3^TKatJD9ixG=D0WzL@@I9!0-Xo&bic9)v(dGHulo$vF>=l5eqoXMc0R|yiJ$kW zbwKUueqmAU_>AV;^N#rc*X?nh4{@$fx!Z48HX2#GJ$YB!yQ1%H+~wWk!Ciq7w-dUB z_F9JL{{}Cdg_m@dGX9#II`gIX+1y07Y!{y1AF}gEp9t*_x3ueO$*Q4Jpi-bxpi-bx Jpi*E`fqy3&QLg|1 diff --git a/compiler/router/tests/05_two_nets_test.gds b/compiler/router/tests/05_two_nets_test.gds index 736bdb91d0c7b0bd71732ad9dd2f6b147002b41f..a93e92bfaf7098b6b9a33407e20d2e09d38ef40f 100644 GIT binary patch literal 4096 zcmeH|v1=4T6vp4(?T!*RXL6`#;uWG+B7}nonnE;6nji!P3sEi+69_~RNz~FpusLi} z1uaBS5Nxy%{{Rt-M8rZ1n?pf6o0y0p+3|Zb^K!cIjLl3<6YVJY$M(Ly|M=_K<)iy9l;59z_Jb;Z zvbLnujmfcUt$M3kyE=2_2$8pyNOk5hmn!Co=ulSyZy${xFjoZcHYst?>u%~hV|p{l zzKp)^^kC$P>Vue`=O032zD2|Q>y-GAoqr3p&A3CUo0HeaYyIQ}>zVH2OjS9@?_Pcf zd;H@)b8`>zlY*{-*1zAO>jkMEbt;}`+^0`khj*X>^&oP5+N8w6Xr2+h)=TGz3jK~R z!7unPlsLXT;&V*D_6Fnov^IQ>Z#jeiLW%da(`&ujU_II;);B5f)kcyY#`Hq}*>de7 z_yl@KiGvB>&pIseh~o#=P}&#;k?!> zs3j$oxchdekDO7^J%aBOmihqn)0ov!;^9QhyO@4)0Bcood#~>Ho}t80-%#T1^yuT7#r&rBuesVclsGeKem-;TICBO;XU-l&iMQAPL+wTUb9qaROU(-< z9p~2O20w(j#(Lq!y zwch*g-mCb7=gB_i-usE`)OR=Q=5?6lJ9O@(O{c>ud`$nH;jCHx)cJ+8Sha)c=Ud*- bt8I0#$n%_O88Qbl2QmjT2Qml#hXa2AYXWmH literal 4096 zcmeHJzl#$=6n@!k#@uFaFDBw88bK^94&e-(pcbO1q!Amn5-}Wj!ubmkPpwiah^@sb z$Q9aYagBwDHiuaHKWJqwXQk`+X67Zc@pes8@51i4yq#~~yl=iYyQIh?MXiEI4XV%# zg*cB;756o&(>^*(p{K4cUt3zed5>sUv2mVn`>+9 zxTTO4s3@YTAEcVn9PT_W=VTsG!7wy3VZZ)nXj~!JGm`eiNsotCKH| ze}BfTdIp0IIB&qQDDkOY2LC%zc^-Vm4Wek%L5a_&@iF#J9LJv+q0=eDHz;w9Df5Rm zEeKw>_{_XV2}-=4o}ZV8`5M8~?-P`GDj#*fL{6@gaRd6zIVkar`lBAkFQ9J5cSJLR zgA#|+wqHNy8J(EVx-s9N#IyA)&*3?*8RpIX!E-PuagC|@naBERWZl8n`ZG#AL%;Yv z#x;xWILRvZ3Lu;0m6Y4H;K z1qZ&9@bL}poiTav?^*EdPCI%&=4ma)&R71W*M9;Y)-4)W7pQ|j7VM}xAO28$UrUx> Ras_e)as_e)as{?m;4f7{XLtYr diff --git a/compiler/router/tests/05_two_nets_test.py b/compiler/router/tests/05_two_nets_test.py index c4661e16..c9b67d2c 100644 --- a/compiler/router/tests/05_two_nets_test.py +++ b/compiler/router/tests/05_two_nets_test.py @@ -56,11 +56,13 @@ class two_nets_test(unittest.TestCase): r.route(layer_stack,src="A",dest="B") r.add_route(self) - r.route(layer_stack,src="A",dest="B") - r.add_route(self) + #r.route(layer_stack,src="C",dest="D") + #r.add_route(self) + r = routing("test1", "05_two_nets_test") + r.gds_write("temp.gds") self.local_check(r) # fails if there are any DRC errors on any cells