mirror of https://github.com/VLSIDA/OpenRAM.git
Cleanup.
This commit is contained in:
parent
4ad920eaf7
commit
bec12f5b94
|
|
@ -5,7 +5,6 @@
|
||||||
# (acting for and on behalf of Oklahoma State University)
|
# (acting for and on behalf of Oklahoma State University)
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
import itertools
|
|
||||||
import collections
|
import collections
|
||||||
import geometry
|
import geometry
|
||||||
import gdsMill
|
import gdsMill
|
||||||
|
|
@ -16,7 +15,7 @@ import os
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from pin_layout import pin_layout
|
from pin_layout import pin_layout
|
||||||
import lef
|
|
||||||
|
|
||||||
class layout():
|
class layout():
|
||||||
"""
|
"""
|
||||||
|
|
@ -61,12 +60,13 @@ class layout():
|
||||||
y_dir = 1
|
y_dir = 1
|
||||||
else:
|
else:
|
||||||
# we lose a rail after every 2 gates
|
# we lose a rail after every 2 gates
|
||||||
base_offset=vector(x_offset, (inv_num+1) * height - (inv_num%2)*drc["minwidth_m1"])
|
base_offset = vector(x_offset,
|
||||||
|
(inv_num + 1) * height - \
|
||||||
|
(inv_num % 2) * drc["minwidth_m1"])
|
||||||
y_dir = -1
|
y_dir = -1
|
||||||
|
|
||||||
return (base_offset, y_dir)
|
return (base_offset, y_dir)
|
||||||
|
|
||||||
|
|
||||||
def find_lowest_coords(self):
|
def find_lowest_coords(self):
|
||||||
"""Finds the lowest set of 2d cartesian coordinates within
|
"""Finds the lowest set of 2d cartesian coordinates within
|
||||||
this layout"""
|
this layout"""
|
||||||
|
|
@ -92,9 +92,10 @@ class layout():
|
||||||
return vector(min(lowestx1, lowestx2), min(lowesty1, lowesty2))
|
return vector(min(lowestx1, lowestx2), min(lowesty1, lowesty2))
|
||||||
|
|
||||||
def find_highest_coords(self):
|
def find_highest_coords(self):
|
||||||
"""Finds the highest set of 2d cartesian coordinates within
|
"""
|
||||||
this layout"""
|
Finds the highest set of 2d cartesian coordinates within
|
||||||
|
this layout
|
||||||
|
"""
|
||||||
if len(self.objs) > 0:
|
if len(self.objs) > 0:
|
||||||
highestx1 = max(obj.rx() for obj in self.objs if obj.name != "label")
|
highestx1 = max(obj.rx() for obj in self.objs if obj.name != "label")
|
||||||
highesty1 = max(obj.uy() for obj in self.objs if obj.name != "label")
|
highesty1 = max(obj.uy() for obj in self.objs if obj.name != "label")
|
||||||
|
|
@ -112,8 +113,8 @@ class layout():
|
||||||
elif highestx2 == None:
|
elif highestx2 == None:
|
||||||
return vector(highestx1, highesty1)
|
return vector(highestx1, highesty1)
|
||||||
else:
|
else:
|
||||||
return vector(max(highestx1, highestx2), max(highesty1, highesty2))
|
return vector(max(highestx1, highestx2),
|
||||||
|
max(highesty1, highesty2))
|
||||||
|
|
||||||
def translate_all(self, offset):
|
def translate_all(self, offset):
|
||||||
"""
|
"""
|
||||||
|
|
@ -164,7 +165,8 @@ class layout():
|
||||||
|
|
||||||
def add_rect_center(self, layer, offset, width=None, height=None):
|
def add_rect_center(self, layer, offset, width=None, height=None):
|
||||||
"""
|
"""
|
||||||
Adds a rectangle on a given layer at the center point with width and height
|
Adds a rectangle on a given layer at the center
|
||||||
|
point with width and height
|
||||||
"""
|
"""
|
||||||
if not width:
|
if not width:
|
||||||
width = drc["minwidth_{}".format(layer)]
|
width = drc["minwidth_{}".format(layer)]
|
||||||
|
|
@ -174,26 +176,33 @@ class layout():
|
||||||
lpp = techlayer[layer]
|
lpp = techlayer[layer]
|
||||||
corrected_offset = offset - vector(0.5 * width, 0.5 * height)
|
corrected_offset = offset - vector(0.5 * width, 0.5 * height)
|
||||||
if lpp[0] >= 0:
|
if lpp[0] >= 0:
|
||||||
self.objs.append(geometry.rectangle(lpp, corrected_offset, width, height))
|
self.objs.append(geometry.rectangle(lpp,
|
||||||
|
corrected_offset,
|
||||||
|
width,
|
||||||
|
height))
|
||||||
return self.objs[-1]
|
return self.objs[-1]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def add_segment_center(self, layer, start, end):
|
def add_segment_center(self, layer, start, end):
|
||||||
"""
|
"""
|
||||||
Add a min-width rectanglular segment using center line on the start to end point
|
Add a min-width rectanglular segment using center
|
||||||
|
line on the start to end point
|
||||||
"""
|
"""
|
||||||
minwidth_layer = drc["minwidth_{}".format(layer)]
|
minwidth_layer = drc["minwidth_{}".format(layer)]
|
||||||
if start.x != end.x and start.y != end.y:
|
if start.x != end.x and start.y != end.y:
|
||||||
debug.error("Nonrectilinear center rect!", -1)
|
debug.error("Nonrectilinear center rect!", -1)
|
||||||
elif start.x != end.x:
|
elif start.x != end.x:
|
||||||
offset = vector(0, 0.5 * minwidth_layer)
|
offset = vector(0, 0.5 * minwidth_layer)
|
||||||
return self.add_rect(layer,start-offset,end.x-start.x,minwidth_layer)
|
return self.add_rect(layer,
|
||||||
|
start-offset,
|
||||||
|
end.x-start.x,
|
||||||
|
minwidth_layer)
|
||||||
else:
|
else:
|
||||||
offset = vector(0.5 * minwidth_layer, 0)
|
offset = vector(0.5 * minwidth_layer, 0)
|
||||||
return self.add_rect(layer,start-offset,minwidth_layer,end.y-start.y)
|
return self.add_rect(layer,
|
||||||
|
start-offset,
|
||||||
|
minwidth_layer,
|
||||||
|
end.y-start.y)
|
||||||
|
|
||||||
def get_pin(self, text):
|
def get_pin(self, text):
|
||||||
"""
|
"""
|
||||||
|
|
@ -206,13 +215,10 @@ class layout():
|
||||||
# Otherwise, should use get_pins()
|
# Otherwise, should use get_pins()
|
||||||
any_pin = next(iter(self.pin_map[text]))
|
any_pin = next(iter(self.pin_map[text]))
|
||||||
return any_pin
|
return any_pin
|
||||||
except Exception as e:
|
except Exception:
|
||||||
#print e
|
|
||||||
self.gds_write("missing_pin.gds")
|
self.gds_write("missing_pin.gds")
|
||||||
debug.error("No pin found with name {0} on {1}. Saved as missing_pin.gds.".format(text,self.name),-1)
|
debug.error("No pin found with name {0} on {1}. Saved as missing_pin.gds.".format(text,self.name),-1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_pins(self, text):
|
def get_pins(self, text):
|
||||||
"""
|
"""
|
||||||
Return a pin list (instead of a single pin)
|
Return a pin list (instead of a single pin)
|
||||||
|
|
@ -235,12 +241,17 @@ class layout():
|
||||||
"""
|
"""
|
||||||
pins = instance.get_pins(pin_name)
|
pins = instance.get_pins(pin_name)
|
||||||
|
|
||||||
debug.check(len(pins)>0,"Could not find pin {}".format(pin_name))
|
debug.check(len(pins) > 0,
|
||||||
|
"Could not find pin {}".format(pin_name))
|
||||||
|
|
||||||
for pin in pins:
|
for pin in pins:
|
||||||
if new_name == "":
|
if new_name == "":
|
||||||
new_name = pin.name
|
new_name = pin.name
|
||||||
self.add_layout_pin(new_name, pin.layer, pin.ll(), pin.width(), pin.height())
|
self.add_layout_pin(new_name,
|
||||||
|
pin.layer,
|
||||||
|
pin.ll(),
|
||||||
|
pin.width(),
|
||||||
|
pin.height())
|
||||||
|
|
||||||
def copy_layout_pins(self, instance, prefix=""):
|
def copy_layout_pins(self, instance, prefix=""):
|
||||||
"""
|
"""
|
||||||
|
|
@ -255,7 +266,8 @@ class layout():
|
||||||
Creates a path like pin with center-line convention
|
Creates a path like pin with center-line convention
|
||||||
"""
|
"""
|
||||||
|
|
||||||
debug.check(start.x==end.x or start.y==end.y,"Cannot have a non-manhatten layout pin.")
|
debug.check(start.x == end.x or start.y == end.y,
|
||||||
|
"Cannot have a non-manhatten layout pin.")
|
||||||
|
|
||||||
minwidth_layer = drc["minwidth_{}".format(layer)]
|
minwidth_layer = drc["minwidth_{}".format(layer)]
|
||||||
|
|
||||||
|
|
@ -273,8 +285,11 @@ class layout():
|
||||||
height = max(minwidth_layer, height)
|
height = max(minwidth_layer, height)
|
||||||
width = max(minwidth_layer, width)
|
width = max(minwidth_layer, width)
|
||||||
|
|
||||||
|
return self.add_layout_pin(text,
|
||||||
return self.add_layout_pin(text, layer, ll_offset, width, height)
|
layer,
|
||||||
|
ll_offset,
|
||||||
|
width,
|
||||||
|
height)
|
||||||
|
|
||||||
def add_layout_pin_rect_center(self, text, layer, offset, width=None, height=None):
|
def add_layout_pin_rect_center(self, text, layer, offset, width=None, height=None):
|
||||||
""" Creates a path like pin with center-line convention """
|
""" Creates a path like pin with center-line convention """
|
||||||
|
|
@ -287,7 +302,6 @@ class layout():
|
||||||
|
|
||||||
return self.add_layout_pin(text, layer, ll_offset, width, height)
|
return self.add_layout_pin(text, layer, ll_offset, width, height)
|
||||||
|
|
||||||
|
|
||||||
def remove_layout_pin(self, text):
|
def remove_layout_pin(self, text):
|
||||||
"""
|
"""
|
||||||
Delete a labeled pin (or all pins of the same name)
|
Delete a labeled pin (or all pins of the same name)
|
||||||
|
|
@ -303,7 +317,9 @@ class layout():
|
||||||
if not height:
|
if not height:
|
||||||
height = drc["minwidth_{0}".format(layer)]
|
height = drc["minwidth_{0}".format(layer)]
|
||||||
|
|
||||||
new_pin = pin_layout(text, [offset,offset+vector(width,height)], layer)
|
new_pin = pin_layout(text,
|
||||||
|
[offset, offset+vector(width, height)],
|
||||||
|
layer)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Check if there's a duplicate!
|
# Check if there's a duplicate!
|
||||||
|
|
@ -333,8 +349,8 @@ class layout():
|
||||||
height=height)
|
height=height)
|
||||||
self.add_label(text=text,
|
self.add_label(text=text,
|
||||||
layer=layer,
|
layer=layer,
|
||||||
offset=offset+vector(0.5*width,0.5*height))
|
offset=offset + vector(0.5 * width,
|
||||||
|
0.5 * height))
|
||||||
|
|
||||||
def add_label(self, text, layer, offset=[0, 0], zoom=-1):
|
def add_label(self, text, layer, offset=[0, 0], zoom=-1):
|
||||||
"""Adds a text label on the given layer,offset, and zoom level"""
|
"""Adds a text label on the given layer,offset, and zoom level"""
|
||||||
|
|
@ -346,7 +362,6 @@ class layout():
|
||||||
return self.objs[-1]
|
return self.objs[-1]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def add_path(self, layer, coordinates, width=None):
|
def add_path(self, layer, coordinates, width=None):
|
||||||
"""Connects a routing path on given layer,coordinates,width."""
|
"""Connects a routing path on given layer,coordinates,width."""
|
||||||
debug.info(4, "add path " + str(layer) + " " + str(coordinates))
|
debug.info(4, "add path " + str(layer) + " " + str(coordinates))
|
||||||
|
|
@ -376,12 +391,12 @@ class layout():
|
||||||
path=coordinates,
|
path=coordinates,
|
||||||
layer_widths=layer_widths)
|
layer_widths=layer_widths)
|
||||||
|
|
||||||
|
|
||||||
def add_wire(self, layers, coordinates):
|
def add_wire(self, layers, coordinates):
|
||||||
"""Connects a routing path on given layer,coordinates,width.
|
"""Connects a routing path on given layer,coordinates,width.
|
||||||
The layers are the (horizontal, via, vertical). """
|
The layers are the (horizontal, via, vertical). """
|
||||||
import wire
|
import wire
|
||||||
# add an instance of our path that breaks down into rectangles and contacts
|
# add an instance of our path that breaks down
|
||||||
|
# into rectangles and contacts
|
||||||
wire.wire(obj=self,
|
wire.wire(obj=self,
|
||||||
layer_stack=layers,
|
layer_stack=layers,
|
||||||
position_list=coordinates)
|
position_list=coordinates)
|
||||||
|
|
@ -394,7 +409,7 @@ class layout():
|
||||||
def add_via(self, layers, offset, size=[1,1], directions=None, implant_type=None, well_type=None):
|
def add_via(self, layers, offset, size=[1,1], directions=None, implant_type=None, well_type=None):
|
||||||
""" Add a three layer via structure. """
|
""" Add a three layer via structure. """
|
||||||
|
|
||||||
if directions==None:
|
if not directions:
|
||||||
directions = (self.get_preferred_direction(layers[0]),
|
directions = (self.get_preferred_direction(layers[0]),
|
||||||
self.get_preferred_direction(layers[2]))
|
self.get_preferred_direction(layers[2]))
|
||||||
|
|
||||||
|
|
@ -414,9 +429,12 @@ class layout():
|
||||||
return inst
|
return inst
|
||||||
|
|
||||||
def add_via_center(self, layers, offset, directions=None, size=[1,1], implant_type=None, well_type=None):
|
def add_via_center(self, layers, offset, directions=None, size=[1,1], implant_type=None, well_type=None):
|
||||||
""" Add a three layer via structure by the center coordinate accounting for mirroring and rotation. """
|
"""
|
||||||
|
Add a three layer via structure by the center coordinate
|
||||||
|
accounting for mirroring and rotation.
|
||||||
|
"""
|
||||||
|
|
||||||
if directions==None:
|
if not directions:
|
||||||
directions = (self.get_preferred_direction(layers[0]),
|
directions = (self.get_preferred_direction(layers[0]),
|
||||||
self.get_preferred_direction(layers[2]))
|
self.get_preferred_direction(layers[2]))
|
||||||
|
|
||||||
|
|
@ -430,7 +448,8 @@ class layout():
|
||||||
height = via.height
|
height = via.height
|
||||||
width = via.width
|
width = via.width
|
||||||
|
|
||||||
corrected_offset = offset + vector(-0.5*width,-0.5*height)
|
corrected_offset = offset + vector(-0.5 * width,
|
||||||
|
-0.5 * height)
|
||||||
|
|
||||||
self.add_mod(via)
|
self.add_mod(via)
|
||||||
inst = self.add_inst(name=via.name,
|
inst = self.add_inst(name=via.name,
|
||||||
|
|
@ -454,8 +473,6 @@ class layout():
|
||||||
rotate=rotate)
|
rotate=rotate)
|
||||||
return inst
|
return inst
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def gds_read(self):
|
def gds_read(self):
|
||||||
"""Reads a GDSII file in the library and checks if it exists
|
"""Reads a GDSII file in the library and checks if it exists
|
||||||
Otherwise, start a new layout for dynamic generation."""
|
Otherwise, start a new layout for dynamic generation."""
|
||||||
|
|
@ -480,7 +497,7 @@ class layout():
|
||||||
|
|
||||||
def print_gds(self, gds_file=None):
|
def print_gds(self, gds_file=None):
|
||||||
"""Print the gds file (not the vlsi class) to the terminal """
|
"""Print the gds file (not the vlsi class) to the terminal """
|
||||||
if gds_file == None:
|
if not gds_file:
|
||||||
gds_file = self.gds_file
|
gds_file = self.gds_file
|
||||||
debug.info(4, "Printing {}".format(gds_file))
|
debug.info(4, "Printing {}".format(gds_file))
|
||||||
arrayCellLayout = gdsMill.VlsiLayout(units=GDS["unit"])
|
arrayCellLayout = gdsMill.VlsiLayout(units=GDS["unit"])
|
||||||
|
|
@ -511,10 +528,12 @@ class layout():
|
||||||
# If there is a boundary layer, and we didn't create one, add one.
|
# If there is a boundary layer, and we didn't create one, add one.
|
||||||
if "stdc" in techlayer.keys():
|
if "stdc" in techlayer.keys():
|
||||||
boundary_layer = "stdc"
|
boundary_layer = "stdc"
|
||||||
boundary = [self.find_lowest_coords(), self.find_highest_coords()]
|
boundary = [self.find_lowest_coords(),
|
||||||
|
self.find_highest_coords()]
|
||||||
height = boundary[1][1] - boundary[0][1]
|
height = boundary[1][1] - boundary[0][1]
|
||||||
width = boundary[1][0] - boundary[0][0]
|
width = boundary[1][0] - boundary[0][0]
|
||||||
(layer_number, layer_purpose) = techlayer[boundary_layer]
|
(layer_number, layer_purpose) = techlayer[boundary_layer]
|
||||||
|
print(self.name, boundary, height, width)
|
||||||
gds_layout.addBox(layerNumber=layer_number,
|
gds_layout.addBox(layerNumber=layer_number,
|
||||||
purposeNumber=layer_purpose,
|
purposeNumber=layer_purpose,
|
||||||
offsetInMicrons=boundary[0],
|
offsetInMicrons=boundary[0],
|
||||||
|
|
@ -523,7 +542,6 @@ class layout():
|
||||||
center=False)
|
center=False)
|
||||||
debug.info(2, "Adding {0} boundary {1}".format(self.name, boundary))
|
debug.info(2, "Adding {0} boundary {1}".format(self.name, boundary))
|
||||||
|
|
||||||
|
|
||||||
self.visited.append(self.name)
|
self.visited.append(self.name)
|
||||||
|
|
||||||
def gds_write(self, gds_name):
|
def gds_write(self, gds_name):
|
||||||
|
|
@ -559,7 +577,8 @@ class layout():
|
||||||
|
|
||||||
def get_blockages(self, layer, top_level=False):
|
def get_blockages(self, layer, top_level=False):
|
||||||
"""
|
"""
|
||||||
Write all of the obstacles in the current (and children) modules to the lef file
|
Write all of the obstacles in the current (and children)
|
||||||
|
modules to the lef file.
|
||||||
Do not write the pins since they aren't obstructions.
|
Do not write the pins since they aren't obstructions.
|
||||||
"""
|
"""
|
||||||
if type(layer) == str:
|
if type(layer) == str:
|
||||||
|
|
@ -660,10 +679,12 @@ class layout():
|
||||||
offset=line_offset,
|
offset=line_offset,
|
||||||
height=length)
|
height=length)
|
||||||
# Make this the center of the rail
|
# Make this the center of the rail
|
||||||
line_positions[names[i]]=line_offset+vector(half_minwidth,0.5*length)
|
line_positions[names[i]] = line_offset + vector(half_minwidth,
|
||||||
|
0.5 * length)
|
||||||
else:
|
else:
|
||||||
for i in range(len(names)):
|
for i in range(len(names)):
|
||||||
line_offset = offset + vector(0,i*pitch + half_minwidth)
|
line_offset = offset + vector(0,
|
||||||
|
i * pitch + half_minwidth)
|
||||||
if make_pins:
|
if make_pins:
|
||||||
self.add_layout_pin(text=names[i],
|
self.add_layout_pin(text=names[i],
|
||||||
layer=layer,
|
layer=layer,
|
||||||
|
|
@ -674,7 +695,8 @@ class layout():
|
||||||
offset=line_offset,
|
offset=line_offset,
|
||||||
width=length)
|
width=length)
|
||||||
# Make this the center of the rail
|
# Make this the center of the rail
|
||||||
line_positions[names[i]]=line_offset+vector(0.5*length,half_minwidth)
|
line_positions[names[i]] = line_offset + vector(0.5 * length,
|
||||||
|
half_minwidth)
|
||||||
|
|
||||||
return line_positions
|
return line_positions
|
||||||
|
|
||||||
|
|
@ -692,7 +714,8 @@ class layout():
|
||||||
"""
|
"""
|
||||||
Connect a mapping of pin -> name for a bus. This could be
|
Connect a mapping of pin -> name for a bus. This could be
|
||||||
replaced with a channel router in the future.
|
replaced with a channel router in the future.
|
||||||
NOTE: This has only really been tested with point-to-point connections (not multiple pins on a net).
|
NOTE: This has only really been tested with point-to-point
|
||||||
|
connections (not multiple pins on a net).
|
||||||
"""
|
"""
|
||||||
(horizontal_layer, via_layer, vertical_layer) = layer_stack
|
(horizontal_layer, via_layer, vertical_layer) = layer_stack
|
||||||
if horizontal:
|
if horizontal:
|
||||||
|
|
@ -712,16 +735,16 @@ class layout():
|
||||||
# left/right then up/down
|
# left/right then up/down
|
||||||
mid_pos = vector(bus_pos.x, pin_pos.y)
|
mid_pos = vector(bus_pos.x, pin_pos.y)
|
||||||
|
|
||||||
self.add_wire(layer_stack,[bus_pos, mid_pos, pin_pos])
|
self.add_wire(layer_stack,
|
||||||
|
[bus_pos, mid_pos, pin_pos])
|
||||||
|
|
||||||
# Connect to the pin on the instances with a via if it is
|
# Connect to the pin on the instances with a via if it is
|
||||||
# not on the right layer
|
# not on the right layer
|
||||||
if pin.layer != route_layer:
|
if pin.layer != route_layer:
|
||||||
self.add_via_center(layers=layer_stack,
|
self.add_via_center(layers=layer_stack,
|
||||||
offset=pin_pos)
|
offset=pin_pos)
|
||||||
# FIXME: output pins tend to not be rotate, but supply pins are. Make consistent?
|
# FIXME: output pins tend to not be rotate,
|
||||||
|
# but supply pins are. Make consistent?
|
||||||
|
|
||||||
|
|
||||||
# We only need a via if they happened to align perfectly
|
# We only need a via if they happened to align perfectly
|
||||||
# so the add_wire didn't add a via
|
# so the add_wire didn't add a via
|
||||||
|
|
@ -729,20 +752,31 @@ class layout():
|
||||||
self.add_via_center(layers=layer_stack,
|
self.add_via_center(layers=layer_stack,
|
||||||
offset=bus_pos,
|
offset=bus_pos,
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
def get_layer_pitch(self, layer):
|
def get_layer_pitch(self, layer):
|
||||||
""" Return the track pitch on a given layer """
|
""" Return the track pitch on a given layer """
|
||||||
if layer == "m1":
|
if layer == "m1":
|
||||||
return (self.m1_pitch,self.m1_pitch-self.m1_space,self.m1_space)
|
return (self.m1_pitch,
|
||||||
|
self.m1_pitch - self.m1_space,
|
||||||
|
self.m1_space)
|
||||||
elif layer == "m2":
|
elif layer == "m2":
|
||||||
return (self.m2_pitch,self.m2_pitch-self.m2_space,self.m2_space)
|
return (self.m2_pitch,
|
||||||
|
self.m2_pitch - self.m2_space,
|
||||||
|
self.m2_space)
|
||||||
elif layer == "m3":
|
elif layer == "m3":
|
||||||
return (self.m3_pitch,self.m3_pitch-self.m3_space,self.m3_space)
|
return (self.m3_pitch,
|
||||||
|
self.m3_pitch - self.m3_space,
|
||||||
|
self.m3_space)
|
||||||
elif layer == "m4":
|
elif layer == "m4":
|
||||||
from tech import layer as tech_layer
|
from tech import layer as tech_layer
|
||||||
if "m4" in tech_layer:
|
if "m4" in tech_layer:
|
||||||
return (self.m3_pitch,self.m3_pitch-self.m4_space,self.m4_space)
|
return (self.m3_pitch,
|
||||||
|
self.m3_pitch - self.m4_space,
|
||||||
|
self.m4_space)
|
||||||
else:
|
else:
|
||||||
return (self.m3_pitch,self.m3_pitch-self.m3_space,self.m3_space)
|
return (self.m3_pitch,
|
||||||
|
self.m3_pitch - self.m3_space,
|
||||||
|
self.m3_space)
|
||||||
else:
|
else:
|
||||||
debug.error("Cannot find layer pitch.")
|
debug.error("Cannot find layer pitch.")
|
||||||
|
|
||||||
|
|
@ -752,18 +786,20 @@ class layout():
|
||||||
layer_stack,
|
layer_stack,
|
||||||
pitch):
|
pitch):
|
||||||
"""
|
"""
|
||||||
Create a trunk route for all pins with the trunk located at the given y offset.
|
Create a trunk route for all pins with
|
||||||
|
the trunk located at the given y offset.
|
||||||
"""
|
"""
|
||||||
max_x = max([pin.center().x for pin in pins])
|
max_x = max([pin.center().x for pin in pins])
|
||||||
min_x = min([pin.center().x for pin in pins])
|
min_x = min([pin.center().x for pin in pins])
|
||||||
|
|
||||||
# if we are less than a pitch, just create a non-preferred layer jog
|
# if we are less than a pitch, just create a non-preferred layer jog
|
||||||
if max_x-min_x <= pitch:
|
if max_x-min_x <= pitch:
|
||||||
|
|
||||||
half_layer_width = 0.5 * drc["minwidth_{0}".format(self.vertical_layer)]
|
half_layer_width = 0.5 * drc["minwidth_{0}".format(self.vertical_layer)]
|
||||||
|
|
||||||
# Add the horizontal trunk on the vertical layer!
|
# Add the horizontal trunk on the vertical layer!
|
||||||
self.add_path(self.vertical_layer,[vector(min_x-half_layer_width,trunk_offset.y), vector(max_x+half_layer_width,trunk_offset.y)])
|
self.add_path(self.vertical_layer,
|
||||||
|
[vector(min_x - half_layer_width, trunk_offset.y),
|
||||||
|
vector(max_x + half_layer_width, trunk_offset.y)])
|
||||||
|
|
||||||
# Route each pin to the trunk
|
# Route each pin to the trunk
|
||||||
for pin in pins:
|
for pin in pins:
|
||||||
|
|
@ -772,8 +808,9 @@ class layout():
|
||||||
self.add_path(self.vertical_layer, [pin.center(), mid])
|
self.add_path(self.vertical_layer, [pin.center(), mid])
|
||||||
else:
|
else:
|
||||||
# Add the horizontal trunk
|
# Add the horizontal trunk
|
||||||
self.add_path(self.horizontal_layer,[vector(min_x,trunk_offset.y), vector(max_x,trunk_offset.y)])
|
self.add_path(self.horizontal_layer,
|
||||||
trunk_mid = vector(0.5*(max_x+min_x),trunk_offset.y)
|
[vector(min_x, trunk_offset.y),
|
||||||
|
vector(max_x, trunk_offset.y)])
|
||||||
|
|
||||||
# Route each pin to the trunk
|
# Route each pin to the trunk
|
||||||
for pin in pins:
|
for pin in pins:
|
||||||
|
|
@ -788,7 +825,8 @@ class layout():
|
||||||
layer_stack,
|
layer_stack,
|
||||||
pitch):
|
pitch):
|
||||||
"""
|
"""
|
||||||
Create a trunk route for all pins with the trunk located at the given x offset.
|
Create a trunk route for all pins with the
|
||||||
|
trunk located at the given x offset.
|
||||||
"""
|
"""
|
||||||
max_y = max([pin.center().y for pin in pins])
|
max_y = max([pin.center().y for pin in pins])
|
||||||
min_y = min([pin.center().y for pin in pins])
|
min_y = min([pin.center().y for pin in pins])
|
||||||
|
|
@ -799,7 +837,9 @@ class layout():
|
||||||
half_layer_width = 0.5 * drc["minwidth_{0}".format(self.horizontal_layer)]
|
half_layer_width = 0.5 * drc["minwidth_{0}".format(self.horizontal_layer)]
|
||||||
|
|
||||||
# Add the vertical trunk on the horizontal layer!
|
# Add the vertical trunk on the horizontal layer!
|
||||||
self.add_path(self.horizontal_layer,[vector(trunk_offset.x,min_y-half_layer_width), vector(trunk_offset.x,max_y+half_layer_width)])
|
self.add_path(self.horizontal_layer,
|
||||||
|
[vector(trunk_offset.x, min_y - half_layer_width),
|
||||||
|
vector(trunk_offset.x,max_y + half_layer_width)])
|
||||||
|
|
||||||
# Route each pin to the trunk
|
# Route each pin to the trunk
|
||||||
for pin in pins:
|
for pin in pins:
|
||||||
|
|
@ -808,8 +848,9 @@ class layout():
|
||||||
self.add_path(self.horizontal_layer, [pin.center(), mid])
|
self.add_path(self.horizontal_layer, [pin.center(), mid])
|
||||||
else:
|
else:
|
||||||
# Add the vertical trunk
|
# Add the vertical trunk
|
||||||
self.add_path(self.vertical_layer,[vector(trunk_offset.x,min_y), vector(trunk_offset.x,max_y)])
|
self.add_path(self.vertical_layer,
|
||||||
trunk_mid = vector(trunk_offset.x,0.5*(max_y+min_y),)
|
[vector(trunk_offset.x, min_y),
|
||||||
|
vector(trunk_offset.x, max_y)])
|
||||||
|
|
||||||
# Route each pin to the trunk
|
# Route each pin to the trunk
|
||||||
for pin in pins:
|
for pin in pins:
|
||||||
|
|
@ -818,7 +859,6 @@ class layout():
|
||||||
self.add_via_center(layers=layer_stack,
|
self.add_via_center(layers=layer_stack,
|
||||||
offset=mid)
|
offset=mid)
|
||||||
|
|
||||||
|
|
||||||
def create_channel_route(self, netlist,
|
def create_channel_route(self, netlist,
|
||||||
offset,
|
offset,
|
||||||
layer_stack,
|
layer_stack,
|
||||||
|
|
@ -848,7 +888,7 @@ class layout():
|
||||||
def vcg_nets_overlap(net1, net2, vertical, pitch):
|
def vcg_nets_overlap(net1, net2, vertical, pitch):
|
||||||
"""
|
"""
|
||||||
Check all the pin pairs on two nets and return a pin
|
Check all the pin pairs on two nets and return a pin
|
||||||
overlap if any pin overlaps
|
overlap if any pin overlaps.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for pin1 in net1:
|
for pin1 in net1:
|
||||||
|
|
@ -861,7 +901,8 @@ class layout():
|
||||||
def vcg_pin_overlap(pin1, pin2, vertical, pitch):
|
def vcg_pin_overlap(pin1, pin2, vertical, pitch):
|
||||||
""" Check for vertical or horizontal overlap of the two pins """
|
""" Check for vertical or horizontal overlap of the two pins """
|
||||||
# FIXME: If the pins are not in a row, this may break.
|
# FIXME: If the pins are not in a row, this may break.
|
||||||
# However, a top pin shouldn't overlap another top pin, for example, so the
|
# However, a top pin shouldn't overlap another top pin,
|
||||||
|
# for example, so the
|
||||||
# extra comparison *shouldn't* matter.
|
# extra comparison *shouldn't* matter.
|
||||||
|
|
||||||
# Pin 1 must be in the "BOTTOM" set
|
# Pin 1 must be in the "BOTTOM" set
|
||||||
|
|
@ -879,15 +920,18 @@ class layout():
|
||||||
self.vertical_layer = layer_stack[2]
|
self.vertical_layer = layer_stack[2]
|
||||||
self.horizontal_layer = layer_stack[0]
|
self.horizontal_layer = layer_stack[0]
|
||||||
|
|
||||||
(self.vertical_pitch,self.vertical_width,self.vertical_space) = self.get_layer_pitch(self.vertical_layer)
|
layer_stuff = self.get_layer_pitch(self.vertical_layer)
|
||||||
(self.horizontal_pitch,self.horizontal_width,self.horizontal_space) = self.get_layer_pitch(self.horizontal_layer)
|
(self.vertical_pitch, self.vertical_width, self.vertical_space) = layer_stuff
|
||||||
|
layer_stuff = self.get_layer_pitch(self.horizontal_layer)
|
||||||
|
(self.horizontal_pitch, self.horizontal_width, self.horizontal_space) = layer_stuff
|
||||||
|
|
||||||
|
# FIXME: Must extend this to a horizontal conflict graph
|
||||||
# FIXME: Must extend this to a horizontal conflict graph too if we want to minimize the
|
# too if we want to minimize the
|
||||||
# number of tracks!
|
# number of tracks!
|
||||||
# hcg = {}
|
# hcg = {}
|
||||||
|
|
||||||
# Initialize the vertical conflict graph (vcg) and make a list of all pins
|
# Initialize the vertical conflict graph (vcg)
|
||||||
|
# and make a list of all pins
|
||||||
vcg = collections.OrderedDict()
|
vcg = collections.OrderedDict()
|
||||||
|
|
||||||
# Create names for the nets for the graphs
|
# Create names for the nets for the graphs
|
||||||
|
|
@ -910,9 +954,15 @@ class layout():
|
||||||
# Skip yourself
|
# Skip yourself
|
||||||
if net_name1 == net_name2:
|
if net_name1 == net_name2:
|
||||||
continue
|
continue
|
||||||
if vertical and vcg_nets_overlap(nets[net_name1], nets[net_name2], vertical, self.vertical_pitch):
|
if vertical and vcg_nets_overlap(nets[net_name1],
|
||||||
|
nets[net_name2],
|
||||||
|
vertical,
|
||||||
|
self.vertical_pitch):
|
||||||
vcg[net_name2].append(net_name1)
|
vcg[net_name2].append(net_name1)
|
||||||
elif not vertical and vcg_nets_overlap(nets[net_name1], nets[net_name2], vertical, self.horizontal_pitch):
|
elif not vertical and vcg_nets_overlap(nets[net_name1],
|
||||||
|
nets[net_name2],
|
||||||
|
vertical,
|
||||||
|
self.horizontal_pitch):
|
||||||
vcg[net_name2].append(net_name1)
|
vcg[net_name2].append(net_name1)
|
||||||
|
|
||||||
# list of routes to do
|
# list of routes to do
|
||||||
|
|
@ -929,8 +979,6 @@ class layout():
|
||||||
# FIXME: We don't support cyclic VCGs right now.
|
# FIXME: We don't support cyclic VCGs right now.
|
||||||
debug.error("Cyclic VCG in channel router.", -1)
|
debug.error("Cyclic VCG in channel router.", -1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# These are the pins we'll have to connect
|
# These are the pins we'll have to connect
|
||||||
pin_list = nets[net_name]
|
pin_list = nets[net_name]
|
||||||
# print("Routing:", net_name, [x.name for x in pin_list])
|
# print("Routing:", net_name, [x.name for x in pin_list])
|
||||||
|
|
@ -938,15 +986,21 @@ class layout():
|
||||||
# Remove the net from other constriants in the VCG
|
# Remove the net from other constriants in the VCG
|
||||||
vcg = remove_net_from_graph(net_name, vcg)
|
vcg = remove_net_from_graph(net_name, vcg)
|
||||||
|
|
||||||
# Add the trunk routes from the bottom up for horizontal or the left to right for vertical
|
# Add the trunk routes from the bottom up for
|
||||||
|
# horizontal or the left to right for vertical
|
||||||
if vertical:
|
if vertical:
|
||||||
self.add_vertical_trunk_route(pin_list, offset, layer_stack, self.vertical_pitch)
|
self.add_vertical_trunk_route(pin_list,
|
||||||
|
offset,
|
||||||
|
layer_stack,
|
||||||
|
self.vertical_pitch)
|
||||||
offset += vector(self.vertical_pitch, 0)
|
offset += vector(self.vertical_pitch, 0)
|
||||||
else:
|
else:
|
||||||
self.add_horizontal_trunk_route(pin_list, offset, layer_stack, self.horizontal_pitch)
|
self.add_horizontal_trunk_route(pin_list,
|
||||||
|
offset,
|
||||||
|
layer_stack,
|
||||||
|
self.horizontal_pitch)
|
||||||
offset += vector(0, self.horizontal_pitch)
|
offset += vector(0, self.horizontal_pitch)
|
||||||
|
|
||||||
|
|
||||||
def create_vertical_channel_route(self, netlist, offset, layer_stack):
|
def create_vertical_channel_route(self, netlist, offset, layer_stack):
|
||||||
"""
|
"""
|
||||||
Wrapper to create a vertical channel route
|
Wrapper to create a vertical channel route
|
||||||
|
|
@ -996,15 +1050,19 @@ class layout():
|
||||||
width=xmax-xmin,
|
width=xmax-xmin,
|
||||||
height=ymax-ymin)
|
height=ymax-ymin)
|
||||||
|
|
||||||
|
|
||||||
def copy_power_pins(self, inst, name):
|
def copy_power_pins(self, inst, name):
|
||||||
"""
|
"""
|
||||||
This will copy a power pin if it is on M3. If it is on M1, it will add a power via too.
|
This will copy a power pin if it is on M3.
|
||||||
|
If it is on M1, it will add a power via too.
|
||||||
"""
|
"""
|
||||||
pins = inst.get_pins(name)
|
pins = inst.get_pins(name)
|
||||||
for pin in pins:
|
for pin in pins:
|
||||||
if pin.layer == "m3":
|
if pin.layer == "m3":
|
||||||
self.add_layout_pin(name, pin.layer, pin.ll(), pin.width(), pin.height())
|
self.add_layout_pin(name,
|
||||||
|
pin.layer,
|
||||||
|
pin.ll(),
|
||||||
|
pin.width(),
|
||||||
|
pin.height())
|
||||||
elif pin.layer == "m1":
|
elif pin.layer == "m1":
|
||||||
self.add_power_pin(name, pin.center())
|
self.add_power_pin(name, pin.center())
|
||||||
else:
|
else:
|
||||||
|
|
@ -1028,13 +1086,11 @@ class layout():
|
||||||
offset=loc,
|
offset=loc,
|
||||||
directions=direction)
|
directions=direction)
|
||||||
|
|
||||||
|
|
||||||
if start_layer == "m1" or start_layer == "m2":
|
if start_layer == "m1" or start_layer == "m2":
|
||||||
via = self.add_via_center(layers=self.m2_stack,
|
via = self.add_via_center(layers=self.m2_stack,
|
||||||
size=size,
|
size=size,
|
||||||
offset=loc,
|
offset=loc,
|
||||||
directions=direction)
|
directions=direction)
|
||||||
|
|
||||||
if start_layer == "m3":
|
if start_layer == "m3":
|
||||||
self.add_layout_pin_rect_center(text=name,
|
self.add_layout_pin_rect_center(text=name,
|
||||||
layer="m3",
|
layer="m3",
|
||||||
|
|
@ -1048,10 +1104,11 @@ class layout():
|
||||||
|
|
||||||
def add_power_ring(self, bbox):
|
def add_power_ring(self, bbox):
|
||||||
"""
|
"""
|
||||||
Create vdd and gnd power rings around an area of the bounding box argument. Must
|
Create vdd and gnd power rings around an area of the bounding box
|
||||||
have a supply_rail_width and supply_rail_pitch defined as a member variable.
|
argument. Must have a supply_rail_width and supply_rail_pitch
|
||||||
Defines local variables of the left/right/top/bottom vdd/gnd center offsets
|
defined as a member variable. Defines local variables of the
|
||||||
for use in other modules..
|
left/right/top/bottom vdd/gnd center offsets for use in other
|
||||||
|
modules..
|
||||||
"""
|
"""
|
||||||
|
|
||||||
[ll, ur] = bbox
|
[ll, ur] = bbox
|
||||||
|
|
@ -1061,15 +1118,16 @@ class layout():
|
||||||
width = (ur.x-ll.x) + 3 * self.supply_rail_pitch - supply_rail_spacing
|
width = (ur.x-ll.x) + 3 * self.supply_rail_pitch - supply_rail_spacing
|
||||||
|
|
||||||
# LEFT vertical rails
|
# LEFT vertical rails
|
||||||
offset = ll + vector(-2*self.supply_rail_pitch, -2*self.supply_rail_pitch)
|
offset = ll + vector(-2 * self.supply_rail_pitch,
|
||||||
|
-2 * self.supply_rail_pitch)
|
||||||
left_gnd_pin = self.add_layout_pin(text="gnd",
|
left_gnd_pin = self.add_layout_pin(text="gnd",
|
||||||
layer="m2",
|
layer="m2",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=self.supply_rail_width,
|
width=self.supply_rail_width,
|
||||||
height=height)
|
height=height)
|
||||||
|
|
||||||
|
offset = ll + vector(-1 * self.supply_rail_pitch,
|
||||||
offset = ll + vector(-1*self.supply_rail_pitch, -1*self.supply_rail_pitch)
|
-1 * self.supply_rail_pitch)
|
||||||
left_vdd_pin = self.add_layout_pin(text="vdd",
|
left_vdd_pin = self.add_layout_pin(text="vdd",
|
||||||
layer="m2",
|
layer="m2",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
|
|
@ -1084,7 +1142,8 @@ class layout():
|
||||||
width=self.supply_rail_width,
|
width=self.supply_rail_width,
|
||||||
height=height)
|
height=height)
|
||||||
|
|
||||||
offset = vector(ur.x,ll.y) + vector(self.supply_rail_pitch,-1*self.supply_rail_pitch)
|
offset = vector(ur.x, ll.y) + vector(self.supply_rail_pitch,
|
||||||
|
-1 * self.supply_rail_pitch)
|
||||||
right_vdd_pin = self.add_layout_pin(text="vdd",
|
right_vdd_pin = self.add_layout_pin(text="vdd",
|
||||||
layer="m2",
|
layer="m2",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
|
|
@ -1092,14 +1151,16 @@ class layout():
|
||||||
height=height)
|
height=height)
|
||||||
|
|
||||||
# BOTTOM horizontal rails
|
# BOTTOM horizontal rails
|
||||||
offset = ll + vector(-2*self.supply_rail_pitch, -2*self.supply_rail_pitch)
|
offset = ll + vector(-2 * self.supply_rail_pitch,
|
||||||
|
-2 * self.supply_rail_pitch)
|
||||||
bottom_gnd_pin = self.add_layout_pin(text="gnd",
|
bottom_gnd_pin = self.add_layout_pin(text="gnd",
|
||||||
layer="m1",
|
layer="m1",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=width,
|
width=width,
|
||||||
height=self.supply_rail_width)
|
height=self.supply_rail_width)
|
||||||
|
|
||||||
offset = ll + vector(-1*self.supply_rail_pitch, -1*self.supply_rail_pitch)
|
offset = ll + vector(-1 * self.supply_rail_pitch,
|
||||||
|
-1 * self.supply_rail_pitch)
|
||||||
bottom_vdd_pin = self.add_layout_pin(text="vdd",
|
bottom_vdd_pin = self.add_layout_pin(text="vdd",
|
||||||
layer="m1",
|
layer="m1",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
|
|
@ -1107,14 +1168,16 @@ class layout():
|
||||||
height=self.supply_rail_width)
|
height=self.supply_rail_width)
|
||||||
|
|
||||||
# TOP horizontal rails
|
# TOP horizontal rails
|
||||||
offset = vector(ll.x, ur.y) + vector(-2*self.supply_rail_pitch,0)
|
offset = vector(ll.x, ur.y) + vector(-2 * self.supply_rail_pitch,
|
||||||
|
0)
|
||||||
top_gnd_pin = self.add_layout_pin(text="gnd",
|
top_gnd_pin = self.add_layout_pin(text="gnd",
|
||||||
layer="m1",
|
layer="m1",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=width,
|
width=width,
|
||||||
height=self.supply_rail_width)
|
height=self.supply_rail_width)
|
||||||
|
|
||||||
offset = vector(ll.x, ur.y) + vector(-1*self.supply_rail_pitch, self.supply_rail_pitch)
|
offset = vector(ll.x, ur.y) + vector(-1 * self.supply_rail_pitch,
|
||||||
|
self.supply_rail_pitch)
|
||||||
top_vdd_pin = self.add_layout_pin(text="vdd",
|
top_vdd_pin = self.add_layout_pin(text="vdd",
|
||||||
layer="m1",
|
layer="m1",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
|
|
@ -1132,7 +1195,6 @@ class layout():
|
||||||
self.top_gnd_y_center = top_gnd_pin.cy()
|
self.top_gnd_y_center = top_gnd_pin.cy()
|
||||||
self.top_vdd_y_center = top_vdd_pin.cy()
|
self.top_vdd_y_center = top_vdd_pin.cy()
|
||||||
|
|
||||||
|
|
||||||
# Find the number of vias for this pitch
|
# Find the number of vias for this pitch
|
||||||
self.supply_vias = 1
|
self.supply_vias = 1
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
|
@ -1158,12 +1220,14 @@ class layout():
|
||||||
for pt in via_points:
|
for pt in via_points:
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=pt,
|
offset=pt,
|
||||||
size = (self.supply_vias, self.supply_vias))
|
size=(self.supply_vias,
|
||||||
|
self.supply_vias))
|
||||||
|
|
||||||
|
|
||||||
def pdf_write(self, pdf_name):
|
def pdf_write(self, pdf_name):
|
||||||
# NOTE: Currently does not work (Needs further research)
|
"""
|
||||||
|
Display the layout to a PDF file.
|
||||||
|
"""
|
||||||
|
debug.error("NOTE: Currently does not work (Needs further research)")
|
||||||
# self.pdf_name = self.name + ".pdf"
|
# self.pdf_name = self.name + ".pdf"
|
||||||
debug.info(0, "Writing to {}".format(pdf_name))
|
debug.info(0, "Writing to {}".format(pdf_name))
|
||||||
pdf = gdsMill.pdfLayout(self.gds)
|
pdf = gdsMill.pdfLayout(self.gds)
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ class ptx(design.design):
|
||||||
Pre-compute some handy layout parameters.
|
Pre-compute some handy layout parameters.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.num_contacts==None:
|
if not self.num_contacts:
|
||||||
self.num_contacts = self.calculate_num_contacts()
|
self.num_contacts = self.calculate_num_contacts()
|
||||||
|
|
||||||
# Determine layer types needed
|
# Determine layer types needed
|
||||||
|
|
@ -121,35 +121,36 @@ class ptx(design.design):
|
||||||
else:
|
else:
|
||||||
self.error("Invalid transitor type.", -1)
|
self.error("Invalid transitor type.", -1)
|
||||||
|
|
||||||
|
|
||||||
# This is not actually instantiated but used for calculations
|
# This is not actually instantiated but used for calculations
|
||||||
self.active_contact = factory.create(module_type="contact",
|
self.active_contact = factory.create(module_type="contact",
|
||||||
layer_stack=self.active_stack,
|
layer_stack=self.active_stack,
|
||||||
directions = ("V", "V"),
|
directions = ("V", "V"),
|
||||||
dimensions=(1, self.num_contacts))
|
dimensions=(1, self.num_contacts))
|
||||||
|
|
||||||
|
|
||||||
# The contacted poly pitch (or uncontacted in an odd technology)
|
# The contacted poly pitch (or uncontacted in an odd technology)
|
||||||
self.poly_pitch = max(2 * self.contact_to_gate + self.contact_width + self.poly_width,
|
self.poly_pitch = max(2 * self.contact_to_gate + self.contact_width + self.poly_width,
|
||||||
self.poly_space)
|
self.poly_space)
|
||||||
|
|
||||||
# The contacted poly pitch (or uncontacted in an odd technology)
|
# The contacted poly pitch (or uncontacted in an odd technology)
|
||||||
self.contact_pitch = 2 * self.contact_to_gate + self.contact_width + self.poly_width
|
self.contact_pitch = 2 * self.contact_to_gate + \
|
||||||
|
self.contact_width + self.poly_width
|
||||||
|
|
||||||
# The enclosure of an active contact. Not sure about second term.
|
# The enclosure of an active contact. Not sure about second term.
|
||||||
active_enclose_contact = max(self.active_enclose_contact,
|
active_enclose_contact = max(self.active_enclose_contact,
|
||||||
(self.active_width - self.contact_width) / 2)
|
(self.active_width - self.contact_width) / 2)
|
||||||
|
|
||||||
# This is the distance from the edge of poly to the contacted end of active
|
# This is the distance from the edge of
|
||||||
self.end_to_poly = active_enclose_contact + self.contact_width + self.contact_to_gate
|
# poly to the contacted end of active
|
||||||
|
self.end_to_poly = active_enclose_contact + \
|
||||||
|
self.contact_width + self.contact_to_gate
|
||||||
|
|
||||||
# Active width is determined by enclosure on both ends and contacted pitch,
|
# Active width is determined by enclosure on both ends and contacted pitch,
|
||||||
# at least one poly and n-1 poly pitches
|
# at least one poly and n-1 poly pitches
|
||||||
self.active_width = 2 * self.end_to_poly + self.poly_width + (self.mults - 1) * self.poly_pitch
|
self.ptx_active_width = 2 * self.end_to_poly + self.poly_width + \
|
||||||
|
(self.mults - 1) * self.poly_pitch
|
||||||
|
|
||||||
# Active height is just the transistor width
|
# Active height is just the transistor width
|
||||||
self.active_height = self.tx_width
|
self.ptx_active_height = self.tx_width
|
||||||
|
|
||||||
# Poly height must include poly extension over active
|
# Poly height must include poly extension over active
|
||||||
self.poly_height = self.tx_width + 2 * self.poly_extend_active
|
self.poly_height = self.tx_width + 2 * self.poly_extend_active
|
||||||
|
|
@ -177,11 +178,11 @@ class ptx(design.design):
|
||||||
|
|
||||||
# This is the center of the first active contact offset (centered vertically)
|
# This is the center of the first active contact offset (centered vertically)
|
||||||
self.contact_offset = self.active_offset + vector(active_enclose_contact + 0.5 * self.contact_width,
|
self.contact_offset = self.active_offset + vector(active_enclose_contact + 0.5 * self.contact_width,
|
||||||
0.5 * self.active_height)
|
0.5 * self.ptx_active_height)
|
||||||
|
|
||||||
|
|
||||||
# Min area results are just flagged for now.
|
# Min area results are just flagged for now.
|
||||||
debug.check(self.active_width * self.active_height >= self.minarea_active,
|
debug.check(self.ptx_active_width * self.ptx_active_height >= self.minarea_active,
|
||||||
"Minimum active area violated.")
|
"Minimum active area violated.")
|
||||||
# We do not want to increase the poly dimensions to fix
|
# We do not want to increase the poly dimensions to fix
|
||||||
# an area problem as it would cause an LVS issue.
|
# an area problem as it would cause an LVS issue.
|
||||||
|
|
@ -215,14 +216,14 @@ class ptx(design.design):
|
||||||
poly_offset = poly_positions[0] + vector(-0.5 * self.poly_width,
|
poly_offset = poly_positions[0] + vector(-0.5 * self.poly_width,
|
||||||
distance_above_active)
|
distance_above_active)
|
||||||
# Remove the old pin and add the new one
|
# Remove the old pin and add the new one
|
||||||
self.remove_layout_pin("G") # only keep the main pin
|
# only keep the main pin
|
||||||
|
self.remove_layout_pin("G")
|
||||||
self.add_layout_pin(text="G",
|
self.add_layout_pin(text="G",
|
||||||
layer="poly",
|
layer="poly",
|
||||||
offset=poly_offset,
|
offset=poly_offset,
|
||||||
width=poly_width,
|
width=poly_width,
|
||||||
height=self.poly_width)
|
height=self.poly_width)
|
||||||
|
|
||||||
|
|
||||||
def connect_fingered_active(self, drain_positions, source_positions):
|
def connect_fingered_active(self, drain_positions, source_positions):
|
||||||
"""
|
"""
|
||||||
Connect each contact up/down to a source or drain pin
|
Connect each contact up/down to a source or drain pin
|
||||||
|
|
@ -230,10 +231,10 @@ class ptx(design.design):
|
||||||
|
|
||||||
# This is the distance that we must route up or down from the center
|
# This is the distance that we must route up or down from the center
|
||||||
# of the contacts to avoid DRC violations to the other contacts
|
# of the contacts to avoid DRC violations to the other contacts
|
||||||
pin_offset = vector(0, 0.5 * self.active_contact.second_layer_height \
|
pin_offset = vector(0, 0.5 * self.active_contact.second_layer_height
|
||||||
+ self.m1_space + 0.5 * self.m1_width)
|
+ self.m1_space + 0.5 * self.m1_width)
|
||||||
# This is the width of a m1 extend the ends of the pin
|
# This is the width of a m1 extend the ends of the pin
|
||||||
end_offset = vector(self.m1_width/2,0)
|
end_offset = vector(self.m1_width / 2.0, 0)
|
||||||
|
|
||||||
# drains always go to the MIDDLE of the cell,
|
# drains always go to the MIDDLE of the cell,
|
||||||
# so top of NMOS, bottom of PMOS
|
# so top of NMOS, bottom of PMOS
|
||||||
|
|
@ -247,7 +248,8 @@ class ptx(design.design):
|
||||||
|
|
||||||
if len(source_positions) > 1:
|
if len(source_positions) > 1:
|
||||||
source_offset = pin_offset.scale(source_dir, source_dir)
|
source_offset = pin_offset.scale(source_dir, source_dir)
|
||||||
self.remove_layout_pin("S") # remove the individual connections
|
# remove the individual connections
|
||||||
|
self.remove_layout_pin("S")
|
||||||
# Add each vertical segment
|
# Add each vertical segment
|
||||||
for a in source_positions:
|
for a in source_positions:
|
||||||
self.add_path(("m1"),
|
self.add_path(("m1"),
|
||||||
|
|
@ -310,16 +312,16 @@ class ptx(design.design):
|
||||||
"""
|
"""
|
||||||
self.add_rect(layer="active",
|
self.add_rect(layer="active",
|
||||||
offset=self.active_offset,
|
offset=self.active_offset,
|
||||||
width=self.active_width,
|
width=self.ptx_active_width,
|
||||||
height=self.active_height)
|
height=self.ptx_active_height)
|
||||||
# If the implant must enclose the active, shift offset
|
# If the implant must enclose the active, shift offset
|
||||||
# and increase width/height
|
# and increase width/height
|
||||||
enclose_width = self.implant_enclose_active
|
enclose_width = self.implant_enclose_active
|
||||||
enclose_offset = [enclose_width] * 2
|
enclose_offset = [enclose_width] * 2
|
||||||
self.add_rect(layer="{}implant".format(self.implant_type),
|
self.add_rect(layer="{}implant".format(self.implant_type),
|
||||||
offset=self.active_offset - enclose_offset,
|
offset=self.active_offset - enclose_offset,
|
||||||
width=self.active_width + 2 * enclose_width,
|
width=self.ptx_active_width + 2 * enclose_width,
|
||||||
height=self.active_height + 2 * enclose_width)
|
height=self.ptx_active_height + 2 * enclose_width)
|
||||||
|
|
||||||
def add_well_implant(self):
|
def add_well_implant(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue