Add dnwell

This commit is contained in:
mrg 2021-05-25 13:25:48 -07:00
parent cc91cdf008
commit 6493d1a7f4
2 changed files with 162 additions and 24 deletions

View File

@ -1161,6 +1161,8 @@ class layout():
height=ur.y - ll.y,
width=ur.x - ll.x)
self.bbox = [self.bounding_box.ll(), self.bounding_box.ur()]
def add_enclosure(self, insts, layer="nwell", extend=0, leftx=None, rightx=None, topy=None, boty=None):
"""
Add a layer that surrounds the given instances. Useful
@ -1341,7 +1343,146 @@ class layout():
layer=layer,
offset=peri_pin_loc)
def add_power_ring(self, bbox):
def add_dnwell(self, bbox=None, inflate=1):
""" Create a dnwell, along with nwell moat at border. """
if "dnwell" not in techlayer:
return
if not bbox:
bbox = [self.find_lowest_coords(),
self.find_highest_coords()]
# Find the corners
[ll, ur] = bbox
# Possibly inflate the bbox
nwell_offset = vector(self.nwell_width, self.nwell_width)
ll -= nwell_offset.scale(inflate, inflate)
ur += nwell_offset.scale(inflate, inflate)
# Other corners
ul = vector(ll.x, ur.y)
lr = vector(ur.x, ll.y)
# Add the dnwell
self.add_rect("dnwell",
offset=ll,
height=ur.y - ll.y,
width=ur.x - ll.x)
# Add the moat
self.add_path("nwell", [ll, lr, ur, ul, ll - vector(0, 0.5 * self.nwell_width)])
# Add the taps
layer_stack = self.active_stack
tap_spacing = 2
nwell_offset = vector(self.nwell_width, self.nwell_width)
loc = ll + nwell_offset.scale(tap_spacing, 0)
end_loc = lr - nwell_offset.scale(tap_spacing, 0)
while loc.x < end_loc.x:
self.add_via_center(layers=layer_stack,
offset=loc,
implant_type="n",
well_type="n")
self.add_via_stack_center(from_layer="li",
to_layer="m1",
offset=loc)
loc += nwell_offset.scale(tap_spacing, 0)
loc = ul + nwell_offset.scale(tap_spacing, 0)
end_loc = ur - nwell_offset.scale(tap_spacing, 0)
while loc.x < end_loc.x:
self.add_via_center(layers=layer_stack,
offset=loc,
implant_type="n",
well_type="n")
self.add_via_stack_center(from_layer="li",
to_layer="m2",
offset=loc)
loc += nwell_offset.scale(tap_spacing, 0)
loc = ll + nwell_offset.scale(0, tap_spacing)
end_loc = ul - nwell_offset.scale(0, tap_spacing)
while loc.y < end_loc.y:
self.add_via_center(layers=layer_stack,
offset=loc,
implant_type="n",
well_type="n")
self.add_via_stack_center(from_layer="li",
to_layer="m2",
offset=loc)
loc += nwell_offset.scale(0, tap_spacing)
loc = lr + nwell_offset.scale(0, tap_spacing)
end_loc = ur - nwell_offset.scale(0, tap_spacing)
while loc.y < end_loc.y:
self.add_via_center(layers=layer_stack,
offset=loc,
implant_type="n",
well_type="n")
self.add_via_stack_center(from_layer="li",
to_layer="m2",
offset=loc)
loc += nwell_offset.scale(0, tap_spacing)
# Add the gnd ring
self.add_ring([ll, ur])
def add_ring(self, bbox=None, width_mult=8, offset=0):
"""
Add a ring around the bbox
"""
# Ring size/space/pitch
wire_width = self.m2_width * width_mult
half_width = 0.5 * wire_width
wire_space = self.m2_space
wire_pitch = wire_width + wire_space
# Find the corners
if not bbox:
bbox = [self.find_lowest_coords(),
self.find_highest_coords()]
[ll, ur] = bbox
ul = vector(ll.x, ur.y)
lr = vector(ur.x, ll.y)
ll += vector(-offset * wire_pitch,
-offset * wire_pitch)
lr += vector(offset * wire_pitch,
-offset * wire_pitch)
ur += vector(offset * wire_pitch,
offset * wire_pitch)
ul += vector(-offset * wire_pitch,
offset * wire_pitch)
half_offset = vector(half_width, half_width)
self.add_path("m1", [ll - half_offset.scale(1, 0), lr + half_offset.scale(1, 0)], width=wire_width)
self.add_path("m1", [ul - half_offset.scale(1, 0), ur + half_offset.scale(1, 0)], width=wire_width)
self.add_path("m2", [ll - half_offset.scale(0, 1), ul + half_offset.scale(0, 1)], width=wire_width)
self.add_path("m2", [lr - half_offset.scale(0, 1), ur + half_offset.scale(0, 1)], width=wire_width)
# Find the number of vias for this pitch
supply_vias = 1
from sram_factory import factory
while True:
c = factory.create(module_type="contact",
layer_stack=self.m1_stack,
dimensions=(supply_vias, supply_vias))
if c.second_layer_width < wire_width and c.second_layer_height < wire_width:
supply_vias += 1
else:
supply_vias -= 1
break
via_points = [ll, lr, ur, ul]
for pt in via_points:
self.add_via_center(layers=self.m1_stack,
offset=pt,
size=(supply_vias,
supply_vias))
def add_power_ring(self):
"""
Create vdd and gnd power rings around an area of the bounding box
argument. Must have a supply_rail_width and supply_rail_pitch
@ -1350,7 +1491,7 @@ class layout():
modules..
"""
[ll, ur] = bbox
[ll, ur] = self.bbox
supply_rail_spacing = self.supply_rail_pitch - self.supply_rail_width
height = (ur.y - ll.y) + 3 * self.supply_rail_pitch - supply_rail_spacing

View File

@ -5,9 +5,9 @@
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import debug
import math
class vector3d():
"""
This is the vector3d class to represent a 3D coordinate.
@ -22,20 +22,20 @@ class vector3d():
self.x = x[0]
self.y = x[1]
self.z = x[2]
#will take inputs as the values of a coordinate
# will take inputs as the values of a coordinate
else:
self.x = x
self.y = y
self.z = z
self._hash = hash((self.x,self.y,self.z))
self._hash = hash((self.x, self.y, self.z))
def __str__(self):
""" override print function output """
return "v3d["+str(self.x)+", "+str(self.y)+", "+str(self.z)+"]"
return "v3d[" + str(self.x) + ", " + str(self.y) + ", " + str(self.z) + "]"
def __repr__(self):
""" override print function output """
return "v3d["+str(self.x)+", "+str(self.y)+", "+str(self.z)+"]"
return "v3d[" + str(self.x) + ", " + str(self.y) + ", " + str(self.z) + "]"
def __setitem__(self, index, value):
"""
@ -74,7 +74,6 @@ class vector3d():
"""
return vector3d(self.x + other[0], self.y + other[1], self.z + other[2])
def __radd__(self, other):
"""
Override + function (right add)
@ -98,7 +97,6 @@ class vector3d():
"""
return self._hash
def __rsub__(self, other):
"""
Override - function (right)
@ -107,7 +105,7 @@ class vector3d():
def rotate(self):
""" pass a copy of rotated vector3d, without altering the vector3d! """
return vector3d(self.y,self.x,self.z)
return vector3d(self.y, self.x, self.z)
def scale(self, x_factor, y_factor=None,z_factor=None):
""" pass a copy of scaled vector3d, without altering the vector3d! """
@ -115,7 +113,7 @@ class vector3d():
z_factor=x_factor[2]
y_factor=x_factor[1]
x_factor=x_factor[0]
return vector3d(self.x*x_factor,self.y*y_factor,self.z*z_factor)
return vector3d(self.x * x_factor, self.y * y_factor, self.z * z_factor)
def rotate_scale(self, x_factor, y_factor=None, z_factor=None):
""" pass a copy of scaled vector3d, without altering the vector3d! """
@ -123,25 +121,25 @@ class vector3d():
z_factor=x_factor[2]
y_factor=x_factor[1]
x_factor=x_factor[0]
return vector3d(self.y*x_factor,self.x*y_factor,self.z*z_factor)
return vector3d(self.y * x_factor, self.x * y_factor, self.z * z_factor)
def floor(self):
"""
Override floor function
"""
return vector3d(int(math.floor(self.x)),int(math.floor(self.y)), self.z)
return vector3d(int(math.floor(self.x)), int(math.floor(self.y)), self.z)
def ceil(self):
"""
Override ceil function
"""
return vector3d(int(math.ceil(self.x)),int(math.ceil(self.y)), self.z)
return vector3d(int(math.ceil(self.x)), int(math.ceil(self.y)), self.z)
def round(self):
"""
Override round function
"""
return vector3d(int(round(self.x)),int(round(self.y)), self.z)
return vector3d(int(round(self.x)), int(round(self.y)), self.z)
def __eq__(self, other):
"""Override the default Equals behavior"""
@ -164,30 +162,29 @@ class vector3d():
def max(self, other):
""" Max of both values """
return vector3d(max(self.x,other.x),max(self.y,other.y),max(self.z,other.z))
return vector3d(max(self.x, other.x), max(self.y, other.y), max(self.z, other.z))
def min(self, other):
""" Min of both values """
return vector3d(min(self.x,other.x),min(self.y,other.y),min(self.z,other.z))
return vector3d(min(self.x, other.x), min(self.y, other.y), min(self.z, other.z))
def distance(self, other):
""" Return the manhattan distance between two values """
return abs(self.x-other.x)+abs(self.y-other.y)
return abs(self.x - other.x) + abs(self.y - other.y)
def euclidean_distance(self, other):
""" Return the euclidean distance between two values """
return math.sqrt((self.x-other.x)**2+(self.y-other.y)**2)
return math.sqrt((self.x - other.x)**2 + (self.y - other.y)**2)
def adjacent(self, other):
""" Is the one grid adjacent in any planar direction to the other """
if self == other + vector3d(1,0,0):
if self == other + vector3d(1, 0, 0):
return True
elif self == other + vector3d(-1,0,0):
elif self == other + vector3d(-1, 0, 0):
return True
elif self == other + vector3d(0,1,0):
elif self == other + vector3d(0, 1, 0):
return True
elif self == other + vector3d(0,-1,0):
elif self == other + vector3d(0, -1, 0):
return True
else:
return False