OpenRAM/compiler/base/route.py

158 lines
5.2 KiB
Python
Raw Normal View History

from tech import drc
import debug
from design import design
from contact import contact
from itertools import tee
from vector import vector
from vector3d import vector3d
class route(design):
"""
2018-02-02 22:04:38 +01:00
Object route (used by the router module)
Add a route of minimium metal width between a set of points.
The widths are the layer widths of the layer stack.
(Vias are in numer of vias.)
The wire must be completely rectilinear and the
z-dimension of the points refers to the layers.
The points are the center of the wire.
This can have non-preferred direction routing.
"""
unique_route_id = 0
def __init__(self, obj, layer_stack, path, layer_widths=[None,1,None]):
name = "route_{0}".format(route.unique_route_id)
route.unique_route_id += 1
design.__init__(self, name)
debug.info(3, "create route obj {0}".format(name))
self.obj = obj
self.layer_stack = layer_stack
self.layer_widths = layer_widths
self.path = path
self.setup_layers()
self.create_wires()
def setup_layers(self):
(self.horiz_layer_name, self.via_layer, self.vert_layer_name) = self.layer_stack
(self.horiz_layer_width, self.num_vias, self.vert_layer_width) = self.layer_widths
if not self.vert_layer_width:
self.vert_layer_width = drc("minwidth_{0}".format(self.vert_layer_name))
if not self.horiz_layer_width:
self.horiz_layer_width = drc("minwidth_{0}".format(self.horiz_layer_name))
# offset this by 1/2 the via size
self.c=contact(self.layer_stack, (self.num_vias, self.num_vias))
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 = list(pairwise(self.path))
for p0,p1 in plist:
if p0.z != p1.z: # via
# offset if not rotated
#via_offset = vector(p0.x+0.5*self.c.width,p0.y+0.5*self.c.height)
# offset if rotated
via_offset = vector(p0.x+0.5*self.c.height,p0.y-0.5*self.c.width)
via_size = [self.num_vias]*2
self.obj.add_via(self.layer_stack,via_offset,size=via_size,rotate=90)
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)
# Draw the layers on the ends of the wires to ensure full width
# connections
self.draw_corner_wire(plist[0][0])
self.draw_corner_wire(plist[-1][1])
def get_layer_width(self, layer_zindex):
"""
Return the layer width
"""
if layer_zindex==0:
return self.horiz_layer_width
elif layer_zindex==1:
return self.vert_layer_width
else:
debug.error("Incorrect layer zindex.",-1)
def get_layer_name(self, layer_zindex):
"""
Return the layer name
"""
if layer_zindex==0:
return self.horiz_layer_name
elif layer_zindex==1:
return self.vert_layer_name
else:
debug.error("Incorrect layer zindex.",-1)
def draw_wire(self, p0, p1):
"""
This draws a straight wire with layer_minwidth
"""
layer_width = self.get_layer_width(p0.z)
layer_name = self.get_layer_name(p0.z)
# 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.obj.add_rect(layer=layer_name,
offset=vector(offset.x,offset.y),
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_width = self.get_layer_width(p0.z)
layer_name = self.get_layer_name(p0.z)
offset = vector(p0.x-0.5*layer_width,p0.y-0.5*layer_width)
self.obj.add_rect(layer=layer_name,
offset=offset,
width=layer_width,
height=layer_width)