Created route and add_route for layer assigned wires. It will replace add_wire/wire eventually.

This commit is contained in:
Matt Guthaus 2017-04-19 12:41:13 -07:00
parent f51e82e75a
commit 55ed6212a1
7 changed files with 154 additions and 14 deletions

View File

@ -168,6 +168,24 @@ class layout:
self.connect_inst([]) self.connect_inst([])
return route 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): def add_wire(self, layers, coordinates, offset=None):
"""Connects a routing path on given layer,coordinates,width. """Connects a routing path on given layer,coordinates,width.
The layers are the (horizontal, via, vertical). """ The layers are the (horizontal, via, vertical). """

119
compiler/route.py Normal file
View File

@ -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)

View File

@ -3,9 +3,9 @@ import tech
from contact import contact from contact import contact
import math import math
import debug import debug
from vector import vector
import grid import grid
from vector import vector
from vector3d import vector3d
class router: class router:
@ -97,6 +97,7 @@ class router:
self.pin_shapes[str(pin)]=[] self.pin_shapes[str(pin)]=[]
self.pin_names.append(pin_name) self.pin_names.append(pin_name)
self.pin_layers[str(pin)] = pin_layer
for pin_shape in 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))) 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])] 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 # convert the pin coordinates to tracks and round the sizes down
self.pin_shapes[str(pin)].append(shape) self.pin_shapes[str(pin)].append(shape)
self.pin_layers[str(pin)] = pin_layer
self.all_pin_shapes.append(shape) self.all_pin_shapes.append(shape)
return self.pin_shapes[str(pin)] return self.pin_shapes[str(pin)]
@ -168,7 +168,7 @@ class router:
Add the current wire route to the given design instance. Add the current wire route to the given design instance.
""" """
# First, simplify the path for # First, simplify the path for
debug.info(1,str(self.path)) #debug.info(1,str(self.path))
contracted_path = self.contract_path(self.path) contracted_path = self.contract_path(self.path)
debug.info(1,str(contracted_path)) debug.info(1,str(contracted_path))
@ -188,17 +188,17 @@ class router:
# convert the path back to absolute units from tracks # convert the path back to absolute units from tracks
abs_path = map(self.convert_point_to_units,contracted_path) abs_path = map(self.convert_point_to_units,contracted_path)
cell.add_wire(self.layers,abs_path)
debug.info(1,str(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 # 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 # offset this by 1/2 the via size
c=contact(self.layers, (1, 1)) c=contact(self.layers, (1, 1))
via_offset = vector(-0.5*c.width,-0.5*c.height) via_offset = vector(-0.5*c.width,-0.5*c.height)
cell.add_via(self.layers,abs_path[0]+via_offset) cell.add_via(self.layers,abs_path[0]+via_offset)
# Check if a via is needed at the end point # 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 # offset this by 1/2 the via size
c=contact(self.layers, (1, 1)) c=contact(self.layers, (1, 1))
via_offset = vector(-0.5*c.width,-0.5*c.height) 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. 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) shapes = self.find_pin(name)
zindex = 0 if self.pin_layers[name]==self.horiz_layer_number else 1 zindex = 0 if self.pin_layers[name]==self.horiz_layer_number else 1
self.source_pin_layer = zindex
for shape in shapes: for shape in shapes:
shape_in_tracks=self.convert_shape_to_tracks(shape) shape_in_tracks=self.convert_shape_to_tracks(shape)
debug.info(1,"Set source: " + str(name) + " " + str(shape_in_tracks) + " z=" + str(zindex)) 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. 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) shapes = self.find_pin(name)
zindex = 0 if self.pin_layers[name]==self.horiz_layer_number else 1 zindex = 0 if self.pin_layers[name]==self.horiz_layer_number else 1
self.target_pin_layer = zindex
for shape in shapes: for shape in shapes:
shape_in_tracks=self.convert_shape_to_tracks(shape) shape_in_tracks=self.convert_shape_to_tracks(shape)
debug.info(1,"Set target: " + str(name) + " " + str(shape_in_tracks) + " z=" + str(zindex)) 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. Convert a path set of tracks to center line path.
""" """
# we can ignore the layers here pt = vector3d(p)
# add_wire will filter out duplicates pt=pt.scale(self.track_widths[0],self.track_widths[1],1)
pt = vector(p[0],p[1])
pt=pt.scale(self.track_widths)
return pt return pt
def convert_shape_to_tracks(self,shape,round_bigger=False): def convert_shape_to_tracks(self,shape,round_bigger=False):

View File

@ -53,7 +53,6 @@ class same_layer_pins_test(unittest.TestCase):
layer_stack =("metal1","via1","metal2") layer_stack =("metal1","via1","metal2")
r.route(layer_stack,src="A",dest="B") r.route(layer_stack,src="A",dest="B")
r.add_route(self) r.add_route(self)
self.gds_write("temp.gds")
r = routing("test1", "03_same_layer_pins_test") r = routing("test1", "03_same_layer_pins_test")
self.local_check(r) self.local_check(r)

View File

@ -56,11 +56,13 @@ class two_nets_test(unittest.TestCase):
r.route(layer_stack,src="A",dest="B") r.route(layer_stack,src="A",dest="B")
r.add_route(self) r.add_route(self)
r.route(layer_stack,src="A",dest="B") #r.route(layer_stack,src="C",dest="D")
r.add_route(self) #r.add_route(self)
r = routing("test1", "05_two_nets_test") r = routing("test1", "05_two_nets_test")
r.gds_write("temp.gds")
self.local_check(r) self.local_check(r)
# fails if there are any DRC errors on any cells # fails if there are any DRC errors on any cells