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 8a7fd5f4..57928eac 100644 Binary files a/compiler/router/tests/04_diff_layer_pins_test.gds and b/compiler/router/tests/04_diff_layer_pins_test.gds differ diff --git a/compiler/router/tests/05_two_nets_test.gds b/compiler/router/tests/05_two_nets_test.gds index 736bdb91..a93e92bf 100644 Binary files a/compiler/router/tests/05_two_nets_test.gds and b/compiler/router/tests/05_two_nets_test.gds differ 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