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([])
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). """

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

View File

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

View File

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