2019-04-26 21:21:50 +02:00
|
|
|
# See LICENSE for licensing information.
|
|
|
|
|
#
|
2021-01-22 20:23:28 +01:00
|
|
|
# Copyright (c) 2016-2021 Regents of the University of California and The Board
|
2019-06-14 17:43:41 +02:00
|
|
|
# of Regents for the Oklahoma Agricultural and Mechanical College
|
|
|
|
|
# (acting for and on behalf of Oklahoma State University)
|
|
|
|
|
# All rights reserved.
|
2019-04-26 21:21:50 +02:00
|
|
|
#
|
2020-01-28 11:53:36 +01:00
|
|
|
from tech import drc, layer, preferred_directions
|
2022-07-13 19:57:56 +02:00
|
|
|
from base.contact import contact
|
|
|
|
|
from base.vector import vector
|
2018-10-25 22:36:35 +02:00
|
|
|
import debug
|
2018-12-03 20:09:17 +01:00
|
|
|
import math
|
2018-10-25 22:36:35 +02:00
|
|
|
|
2019-11-14 19:17:20 +01:00
|
|
|
|
2018-10-25 22:36:35 +02:00
|
|
|
class router_tech:
|
|
|
|
|
"""
|
|
|
|
|
This is a class to hold the router tech constants.
|
|
|
|
|
"""
|
2020-12-21 22:51:50 +01:00
|
|
|
def __init__(self, layers, route_track_width):
|
2018-10-25 22:36:35 +02:00
|
|
|
"""
|
2020-05-07 21:35:21 +02:00
|
|
|
Allows us to change the layers that we are routing on.
|
|
|
|
|
This uses the preferreed directions.
|
2018-10-25 22:36:35 +02:00
|
|
|
"""
|
|
|
|
|
self.layers = layers
|
2020-12-21 22:51:50 +01:00
|
|
|
self.route_track_width = route_track_width
|
2019-05-31 17:43:37 +02:00
|
|
|
|
2019-11-14 19:17:20 +01:00
|
|
|
if len(self.layers) == 1:
|
2019-05-28 02:38:59 +02:00
|
|
|
self.horiz_layer_name = self.vert_layer_name = self.layers[0]
|
2019-11-14 19:17:20 +01:00
|
|
|
self.horiz_lpp = self.vert_lpp = layer[self.layers[0]]
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2020-12-23 19:49:47 +01:00
|
|
|
(self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_layer_width_space(1)
|
|
|
|
|
(self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_layer_width_space(0)
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2019-05-28 02:38:59 +02:00
|
|
|
self.horiz_track_width = self.horiz_layer_minwidth + self.horiz_layer_spacing
|
|
|
|
|
self.vert_track_width = self.vert_layer_minwidth + self.vert_layer_spacing
|
|
|
|
|
else:
|
2020-01-28 11:53:36 +01:00
|
|
|
(try_horiz_layer, self.via_layer_name, try_vert_layer) = self.layers
|
|
|
|
|
|
|
|
|
|
# figure out wich of the two layers prefers horizontal/vertical
|
|
|
|
|
# routing
|
2020-05-07 21:35:21 +02:00
|
|
|
self.horiz_layer_name = None
|
|
|
|
|
self.vert_layer_name = None
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2020-05-07 21:35:21 +02:00
|
|
|
if preferred_directions[try_horiz_layer] == "H":
|
2020-01-28 11:53:36 +01:00
|
|
|
self.horiz_layer_name = try_horiz_layer
|
2020-05-07 21:35:21 +02:00
|
|
|
else:
|
|
|
|
|
self.horiz_layer_name = try_vert_layer
|
|
|
|
|
if preferred_directions[try_vert_layer] == "V":
|
2020-01-28 11:53:36 +01:00
|
|
|
self.vert_layer_name = try_vert_layer
|
|
|
|
|
else:
|
2020-05-07 21:35:21 +02:00
|
|
|
self.vert_layer_name = try_horiz_layer
|
|
|
|
|
|
|
|
|
|
if not self.horiz_layer_name or not self.vert_layer_name:
|
|
|
|
|
raise ValueError("Layer '{}' and '{}' are using the wrong "
|
|
|
|
|
"preferred_directions '{}' and '{}'.")
|
2019-05-28 02:38:59 +02:00
|
|
|
|
|
|
|
|
via_connect = contact(self.layers, (1, 1))
|
2020-12-21 22:51:50 +01:00
|
|
|
max_via_size = max(via_connect.width, via_connect.height)
|
2018-12-03 20:09:17 +01:00
|
|
|
|
2019-11-14 19:17:20 +01:00
|
|
|
self.horiz_lpp = layer[self.horiz_layer_name]
|
|
|
|
|
self.vert_lpp = layer[self.vert_layer_name]
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2020-12-23 19:49:47 +01:00
|
|
|
(self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_layer_width_space(1)
|
|
|
|
|
(self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_layer_width_space(0)
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-12-03 20:09:17 +01:00
|
|
|
# For supplies, we will make the wire wider than the vias
|
|
|
|
|
self.vert_layer_minwidth = max(self.vert_layer_minwidth, max_via_size)
|
|
|
|
|
self.horiz_layer_minwidth = max(self.horiz_layer_minwidth, max_via_size)
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-12-03 20:09:17 +01:00
|
|
|
self.horiz_track_width = self.horiz_layer_minwidth + self.horiz_layer_spacing
|
|
|
|
|
self.vert_track_width = self.vert_layer_minwidth + self.vert_layer_spacing
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-10-25 22:36:35 +02:00
|
|
|
# We'll keep horizontal and vertical tracks the same for simplicity.
|
2020-12-21 22:51:50 +01:00
|
|
|
self.track_width = max(self.horiz_track_width, self.vert_track_width)
|
2020-12-23 19:49:47 +01:00
|
|
|
debug.info(1, "Minimum track width: {:.3f}".format(self.track_width))
|
2020-12-21 22:51:50 +01:00
|
|
|
self.track_space = max(self.horiz_layer_spacing, self.vert_layer_spacing)
|
2020-12-23 19:49:47 +01:00
|
|
|
debug.info(1, "Minimum track space: {:.3f}".format(self.track_space))
|
2018-12-04 17:41:57 +01:00
|
|
|
self.track_wire = self.track_width - self.track_space
|
2020-12-23 19:49:47 +01:00
|
|
|
debug.info(1, "Minimum track wire width: {:.3f}".format(self.track_wire))
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-11-03 01:35:35 +01:00
|
|
|
self.track_widths = vector([self.track_width] * 2)
|
|
|
|
|
self.track_factor = vector([1/self.track_width] * 2)
|
2020-12-21 22:51:50 +01:00
|
|
|
debug.info(2, "Track factor: {}".format(self.track_factor))
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-10-25 22:36:35 +02:00
|
|
|
# When we actually create the routes, make them the width of the track (minus 1/2 spacing on each side)
|
2018-12-04 17:41:57 +01:00
|
|
|
self.layer_widths = [self.track_wire, 1, self.track_wire]
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2019-11-14 19:17:20 +01:00
|
|
|
def same_lpp(self, lpp1, lpp2):
|
|
|
|
|
"""
|
|
|
|
|
Check if the layers and purposes are the same.
|
|
|
|
|
Ignore if purpose is a None.
|
|
|
|
|
"""
|
|
|
|
|
if lpp1[1] == None or lpp2[1] == None:
|
|
|
|
|
return lpp1[0] == lpp2[0]
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2019-11-14 19:17:20 +01:00
|
|
|
return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1]
|
|
|
|
|
|
|
|
|
|
def get_zindex(self, lpp):
|
|
|
|
|
if self.same_lpp(lpp, self.horiz_lpp):
|
2018-10-25 22:36:35 +02:00
|
|
|
return 0
|
|
|
|
|
else:
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
def get_layer(self, zindex):
|
|
|
|
|
if zindex==1:
|
|
|
|
|
return self.vert_layer_name
|
|
|
|
|
elif zindex==0:
|
|
|
|
|
return self.horiz_layer_name
|
|
|
|
|
else:
|
2020-12-21 22:51:50 +01:00
|
|
|
debug.error("Invalid zindex {}".format(zindex), -1)
|
2018-10-25 22:36:35 +02:00
|
|
|
|
2020-12-23 19:49:47 +01:00
|
|
|
def get_layer_width_space(self, zindex):
|
2018-12-03 20:09:17 +01:00
|
|
|
"""
|
|
|
|
|
These are the width and spacing of a supply layer given a supply rail
|
|
|
|
|
of the given number of min wire widths.
|
|
|
|
|
"""
|
|
|
|
|
if zindex==1:
|
|
|
|
|
layer_name = self.vert_layer_name
|
|
|
|
|
elif zindex==0:
|
|
|
|
|
layer_name = self.horiz_layer_name
|
|
|
|
|
else:
|
|
|
|
|
debug.error("Invalid zindex for track", -1)
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-12-04 17:41:57 +01:00
|
|
|
min_wire_width = drc("minwidth_{0}".format(layer_name), 0, math.inf)
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2021-05-05 22:45:12 +02:00
|
|
|
min_width = self.route_track_width * drc("minwidth_{0}".format(layer_name), self.route_track_width * min_wire_width, math.inf)
|
2020-12-21 22:51:50 +01:00
|
|
|
min_spacing = drc(str(layer_name)+"_to_"+str(layer_name), self.route_track_width * min_wire_width, math.inf)
|
2018-12-03 20:09:17 +01:00
|
|
|
|
2020-12-21 22:51:50 +01:00
|
|
|
return (min_width, min_spacing)
|
2018-12-03 20:09:17 +01:00
|
|
|
|
2020-11-03 15:29:17 +01:00
|
|
|
|