mirror of https://github.com/VLSIDA/OpenRAM.git
158 lines
5.2 KiB
Python
158 lines
5.2 KiB
Python
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):
|
|
"""
|
|
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! {}".format(self.path))
|
|
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)
|
|
|
|
|