OpenRAM/compiler/base/wire.py

168 lines
6.7 KiB
Python
Raw Normal View History

# See LICENSE for licensing information.
#
2019-06-14 17:43:41 +02:00
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
2016-11-08 18:57:35 +01:00
from tech import drc
2020-04-15 20:16:45 +02:00
import contact
from wire_path import wire_path
from sram_factory import factory
2016-11-08 18:57:35 +01:00
class wire(wire_path):
"""
2016-11-08 18:57:35 +01:00
Object metal wire; given the layer type
Add a wire of minimium metal width between a set of points.
2016-11-08 18:57:35 +01:00
The points should be rectilinear to control the bend points. If
not, it will always go down first.
The points are the center of the wire.
The layer stack is the vertical, contact/via, and horizontal layers, respectively.
2016-11-08 18:57:35 +01:00
"""
def __init__(self, obj, layer_stack, position_list):
self.obj = obj
2016-11-08 18:57:35 +01:00
self.layer_stack = layer_stack
self.position_list = position_list
self.pins = [] # used for matching parm lengths
self.switch_pos_list = []
self.create_layout()
def create_layout(self):
self.setup_layers()
self.create_rectilinear()
2016-11-08 18:57:35 +01:00
self.create_vias()
self.create_rectangles()
# wires and wire_paths should not be offset to (0,0)
2016-11-08 18:57:35 +01:00
def setup_layers(self):
2016-11-17 23:05:50 +01:00
(horiz_layer, via_layer, vert_layer) = self.layer_stack
self.via_layer_name = via_layer
2016-11-08 18:57:35 +01:00
self.vert_layer_name = vert_layer
self.vert_layer_width = drc("minwidth_{0}".format(vert_layer))
2016-11-08 18:57:35 +01:00
self.horiz_layer_name = horiz_layer
self.horiz_layer_width = drc("minwidth_{0}".format(horiz_layer))
via_connect = factory.create(module_type="contact",
layer_stack=self.layer_stack,
dimensions=(1, 1))
# This is used for short connections to avoid via-to-via spacing errors
self.vert_layer_contact_width = max(via_connect.second_layer_width,
via_connect.first_layer_width)
self.horiz_layer_contact_width = max(via_connect.second_layer_height,
via_connect.first_layer_height)
self.node_to_node = [drc("minwidth_" + str(self.horiz_layer_name)) + via_connect.width,
drc("minwidth_" + str(self.horiz_layer_name)) + via_connect.height]
2020-04-15 20:16:45 +02:00
self.pitch = self.compute_pitch(self.layer_stack)
2016-11-08 18:57:35 +01:00
2020-04-15 20:16:45 +02:00
def compute_pitch(self, layer_stack):
"""
This is contact direction independent pitch,
i.e. we take the maximum contact dimension
"""
(layer1, via, layer2) = layer_stack
if layer1 == "poly" or layer1 == "active":
contact1 = getattr(contact, layer1 + "_contact")
else:
try:
contact1 = getattr(contact, layer1 + "_via")
except AttributeError:
contact1 = getattr(contact, layer2 + "_via")
2020-04-15 20:16:45 +02:00
max_contact = max(contact1.width, contact1.height)
layer1_space = drc("{0}_to_{0}".format(layer1))
layer2_space = drc("{0}_to_{0}".format(layer2))
2020-04-15 20:16:45 +02:00
pitch = max_contact + max(layer1_space, layer2_space)
return pitch
2016-11-08 18:57:35 +01:00
# create a 1x1 contact
def create_vias(self):
""" Add a via and corner square at every corner of the path."""
self.c=factory.create(module_type="contact",
layer_stack=self.layer_stack,
dimensions=(1, 1))
from itertools import tee, islice
nwise = lambda g, n=2: zip(*(islice(g, i, None) for i, g in enumerate(tee(g, n))))
threewise = nwise(self.position_list, 3)
2016-11-08 18:57:35 +01:00
for (a, offset, c) in list(threewise):
# add a exceptions to prevent a via when we don't change directions
if a[0] == c[0]:
continue
if a[1] == c[1]:
continue
self.obj.add_via_center(layers=self.layer_stack,
offset=offset)
2016-11-08 18:57:35 +01:00
def create_rectangles(self):
"""
Create the actual rectangles on the appropriate layers
using the position list of the corners.
"""
2016-11-08 18:57:35 +01:00
pl = self.position_list # position list
for index in range(len(pl) - 1):
# Horizontal wire segment
2016-11-08 18:57:35 +01:00
if pl[index][0] != pl[index + 1][0]:
line_length = pl[index + 1][0] - pl[index][0]
if abs(line_length) < self.pitch:
width = self.horiz_layer_contact_width
else:
width = self.horiz_layer_width
temp_offset = [pl[index][0],
pl[index][1] - 0.5 * width]
# If we go in the negative direction, move the offset
2016-11-08 18:57:35 +01:00
if line_length < 0:
temp_offset = [temp_offset[0] + line_length,
temp_offset[1]]
self.add_line(layer_name=self.horiz_layer_name,
length=abs(line_length),
offset=temp_offset,
orientation="horizontal",
layer_width=width)
# Vertical wire segment
2016-11-08 18:57:35 +01:00
elif pl[index][1] != pl[index + 1][1]:
line_length = pl[index + 1][1] - pl[index][1]
if abs(line_length) < self.pitch:
width = self.vert_layer_contact_width
else:
width = self.vert_layer_width
temp_offset = [pl[index][0] - 0.5 * width,
pl[index][1]]
2016-11-08 18:57:35 +01:00
if line_length < 0:
temp_offset = [temp_offset[0],
temp_offset[1] + line_length]
self.add_line(layer_name=self.vert_layer_name,
length=abs(line_length),
offset=temp_offset,
orientation="vertical",
layer_width=width)
2016-11-08 18:57:35 +01:00
def assert_node(self, A, B):
"""
Check if the node movements are not big enough for the
technology sizes.
"""
2016-11-08 18:57:35 +01:00
X_diff = abs(A[0] - B[0])
Y_diff = abs(A[1] - B[1])
[minX, minY] = self.node_to_node
if X_diff == 0 and Y_diff == 0:
pass
else:
if X_diff == 0:
assert Y_diff >= minY, "node" + \
str(A) + " and node" + str(B) + \
" are too close in Y. Minmum is " + str(minX)
if Y_diff == 0:
assert X_diff >= minX, "node" + \
str(A) + " and node" + str(B) + \
" are too close in X. Minmum is " + str(minY)