mirror of https://github.com/VLSIDA/OpenRAM.git
Added workaround to import layouts into Magic. Select and well layers in active contacts. Fixed missing implant enclose active DRC rule in parameterized cells.
This commit is contained in:
parent
f028436156
commit
1701eac1a9
|
|
@ -11,19 +11,34 @@ class contact(design.design):
|
|||
Creates a contact array minimum active or poly enclosure and metal1 enclosure.
|
||||
This class has enclosure on multiple sides of the contact whereas a via may
|
||||
have extension on two or four sides.
|
||||
The well/implant_type is an option to add a select/implant layer enclosing the contact. This is
|
||||
necessary to import layouts into Magic which requires the select to be in the same GDS
|
||||
hierarchy as the contact.
|
||||
"""
|
||||
def __init__(self, layer_stack, dimensions=[1,1]):
|
||||
name = "{0}_{1}_{2}_{3}x{4}".format(layer_stack[0],
|
||||
layer_stack[1],
|
||||
layer_stack[2],
|
||||
dimensions[0],
|
||||
dimensions[1])
|
||||
def __init__(self, layer_stack, dimensions=[1,1], implant_type=None, well_type=None):
|
||||
if implant_type or well_type:
|
||||
name = "{0}_{1}_{2}_{3}x{4}_{5}{6}".format(layer_stack[0],
|
||||
layer_stack[1],
|
||||
layer_stack[2],
|
||||
dimensions[0],
|
||||
dimensions[1],
|
||||
implant_type,
|
||||
well_type)
|
||||
else:
|
||||
name = "{0}_{1}_{2}_{3}x{4}".format(layer_stack[0],
|
||||
layer_stack[1],
|
||||
layer_stack[2],
|
||||
dimensions[0],
|
||||
dimensions[1])
|
||||
|
||||
design.design.__init__(self, name)
|
||||
debug.info(4, "create contact object {0}".format(name))
|
||||
|
||||
self.layer_stack = layer_stack
|
||||
self.dimensions = dimensions
|
||||
self.offset = vector(0,0)
|
||||
self.implant_type = implant_type
|
||||
self.well_type = well_type
|
||||
self.pins = [] # used for matching parm lengths
|
||||
self.create_layout()
|
||||
|
||||
|
|
@ -37,74 +52,112 @@ class contact(design.design):
|
|||
self.height = max(obj.offset.y + obj.height for obj in self.objs)
|
||||
self.width = max(obj.offset.x + obj.width for obj in self.objs)
|
||||
|
||||
# Do not include the select layer in the height/width
|
||||
if self.implant_type and self.well_type:
|
||||
self.create_implant_well_enclosures()
|
||||
elif self.implant_type or self.well_type:
|
||||
debug.error(-1,"Must define both implant and well type or none at all.")
|
||||
|
||||
def setup_layers(self):
|
||||
(first_layer, via_layer, second_layer) = self.layer_stack
|
||||
self.first_layer_name = first_layer
|
||||
self.via_layer_name = via_layer
|
||||
# Some technologies have a separate active contact from the poly contact
|
||||
# We will use contact for DRC, but active_contact for output
|
||||
if first_layer=="active" or second_layer=="active":
|
||||
self.via_layer_name_expanded = "active_"+via_layer
|
||||
else:
|
||||
self.via_layer_name_expanded = via_layer
|
||||
self.second_layer_name = second_layer
|
||||
|
||||
def setup_layout_constants(self):
|
||||
self.contact_width = drc["minwidth_{0}". format(self.via_layer_name)]
|
||||
self.contact_to_contact = drc["{0}_to_{0}".format(self.via_layer_name)]
|
||||
self.contact_pitch = self.contact_width + self.contact_to_contact
|
||||
contact_to_contact = drc["{0}_to_{0}".format(self.via_layer_name)]
|
||||
self.contact_pitch = self.contact_width + contact_to_contact
|
||||
self.contact_array_width = self.contact_width + (self.dimensions[0] - 1) * self.contact_pitch
|
||||
self.contact_array_height = self.contact_width + (self.dimensions[1] - 1) * self.contact_pitch
|
||||
|
||||
# FIME break this up
|
||||
self.first_layer_horizontal_enclosure = max((drc["minwidth_{0}".format(self.first_layer_name)] - self.contact_array_width) / 2,
|
||||
drc["{0}_enclosure_{1}".format(self.first_layer_name, self.via_layer_name)])
|
||||
self.first_layer_vertical_enclosure = max(utils.ceil((drc["minarea_{0}".format(self.first_layer_name)]
|
||||
/ (self.contact_array_width + 2 * self.first_layer_horizontal_enclosure) - self.contact_array_height) / 2),
|
||||
(drc["minwidth_{0}".format(self.first_layer_name)] - self.contact_array_height) / 2,
|
||||
drc["{0}_extend_{1}".format(self.first_layer_name, self.via_layer_name)])
|
||||
# DRC rules
|
||||
first_layer_minwidth = drc["minwidth_{0}".format(self.first_layer_name)]
|
||||
first_layer_minarea = drc["minarea_{0}".format(self.first_layer_name)]
|
||||
first_layer_enclosure = drc["{0}_enclosure_{1}".format(self.first_layer_name, self.via_layer_name)]
|
||||
first_layer_extend = drc["{0}_extend_{1}".format(self.first_layer_name, self.via_layer_name)]
|
||||
second_layer_minwidth = drc["minwidth_{0}".format(self.second_layer_name)]
|
||||
second_layer_minarea = drc["minarea_{0}".format(self.second_layer_name)]
|
||||
second_layer_enclosure = drc["{0}_enclosure_{1}".format(self.second_layer_name, self.via_layer_name)]
|
||||
second_layer_extend = drc["{0}_extend_{1}".format(self.second_layer_name, self.via_layer_name)]
|
||||
|
||||
self.second_layer_horizontal_enclosure = max((drc["minwidth_{0}".format(self.second_layer_name)] - self.contact_array_width) / 2,
|
||||
drc["{0}_enclosure_{1}".format(self.second_layer_name, self.via_layer_name)])
|
||||
self.second_layer_vertical_enclosure = max(utils.ceil((drc["minarea_{0}".format(self.second_layer_name)]
|
||||
/ (self.contact_array_width + 2 * self.second_layer_horizontal_enclosure) - self.contact_array_height) / 2),
|
||||
(drc["minwidth_{0}".format(self.second_layer_name)] - self.contact_array_height) / 2,
|
||||
drc["{0}_extend_{1}".format(self.second_layer_name, self.via_layer_name)])
|
||||
self.first_layer_horizontal_enclosure = max((first_layer_minwidth - self.contact_array_width) / 2,
|
||||
first_layer_enclosure)
|
||||
self.first_layer_vertical_enclosure = max(utils.ceil((first_layer_minarea
|
||||
/ (self.contact_array_width + 2*self.first_layer_horizontal_enclosure)
|
||||
- self.contact_array_height)/2),
|
||||
(first_layer_minwidth - self.contact_array_height)/2,
|
||||
first_layer_extend)
|
||||
|
||||
self.second_layer_horizontal_enclosure = max((second_layer_minwidth - self.contact_array_width)/2,
|
||||
second_layer_enclosure)
|
||||
self.second_layer_vertical_enclosure = max(utils.ceil((second_layer_minarea
|
||||
/ (self.contact_array_width + 2*self.second_layer_horizontal_enclosure)
|
||||
- self.contact_array_height)/2),
|
||||
(second_layer_minwidth - self.contact_array_height)/2,
|
||||
second_layer_extend)
|
||||
|
||||
def create_contact_array(self):
|
||||
""" Create the contact array at the origin"""
|
||||
# offset for the via array
|
||||
self.via_layer_position =vector(max(self.first_layer_horizontal_enclosure,self.second_layer_horizontal_enclosure),
|
||||
max(self.first_layer_vertical_enclosure,self.second_layer_vertical_enclosure))
|
||||
# this is if the first and second layers are different
|
||||
self.first_layer_position = vector(max(self.second_layer_horizontal_enclosure - self.first_layer_horizontal_enclosure,0),
|
||||
max(self.second_layer_vertical_enclosure - self.first_layer_vertical_enclosure,0))
|
||||
self.second_layer_position = vector(max(self.first_layer_horizontal_enclosure - self.second_layer_horizontal_enclosure,0),
|
||||
max(self.first_layer_vertical_enclosure - self.second_layer_vertical_enclosure,0))
|
||||
|
||||
def create_contact_array(self):
|
||||
""" Create the contact array at the origin"""
|
||||
for i in range(self.dimensions[1]):
|
||||
offset = self.via_layer_position + vector(0, self.contact_pitch * i)
|
||||
for j in range(self.dimensions[0]):
|
||||
self.add_rect(layer=self.via_layer_name,
|
||||
self.add_rect(layer=self.via_layer_name_expanded,
|
||||
offset=offset,
|
||||
width=self.contact_width,
|
||||
height=self.contact_width)
|
||||
offset = offset + vector(self.contact_pitch,0)
|
||||
|
||||
def create_first_layer_enclosure(self):
|
||||
width = self.first_layer_width = self.contact_array_width \
|
||||
+ 2 * self.first_layer_horizontal_enclosure
|
||||
height = self.first_layer_height = self.contact_array_height \
|
||||
+ 2 * self.first_layer_vertical_enclosure
|
||||
# this is if the first and second layers are different
|
||||
self.first_layer_position = vector(max(self.second_layer_horizontal_enclosure - self.first_layer_horizontal_enclosure,0),
|
||||
max(self.second_layer_vertical_enclosure - self.first_layer_vertical_enclosure,0))
|
||||
|
||||
self.first_layer_width = self.contact_array_width + 2*self.first_layer_horizontal_enclosure
|
||||
self.first_layer_height = self.contact_array_height + 2*self.first_layer_vertical_enclosure
|
||||
self.add_rect(layer=self.first_layer_name,
|
||||
offset=self.first_layer_position,
|
||||
width=width,
|
||||
height=height)
|
||||
width=self.first_layer_width,
|
||||
height=self.first_layer_height)
|
||||
|
||||
def create_second_layer_enclosure(self):
|
||||
width = self.second_layer_width = self.contact_array_width \
|
||||
+ 2 * self.second_layer_horizontal_enclosure
|
||||
height = self.second_layer_height = self.contact_array_height \
|
||||
+ 2 * self.second_layer_vertical_enclosure
|
||||
# this is if the first and second layers are different
|
||||
self.second_layer_position = vector(max(self.first_layer_horizontal_enclosure - self.second_layer_horizontal_enclosure,0),
|
||||
max(self.first_layer_vertical_enclosure - self.second_layer_vertical_enclosure,0))
|
||||
|
||||
self.second_layer_width = self.contact_array_width + 2*self.second_layer_horizontal_enclosure
|
||||
self.second_layer_height = self.contact_array_height + 2*self.second_layer_vertical_enclosure
|
||||
self.add_rect(layer=self.second_layer_name,
|
||||
offset=self.second_layer_position,
|
||||
width=width,
|
||||
height=height)
|
||||
width=self.second_layer_width,
|
||||
height=self.second_layer_height)
|
||||
|
||||
def create_implant_well_enclosures(self):
|
||||
implant_position = self.first_layer_position - [drc["implant_enclosure_active"]]*2
|
||||
implant_width = self.first_layer_width + 2*drc["implant_enclosure_active"]
|
||||
implant_height = self.first_layer_height + 2*drc["implant_enclosure_active"]
|
||||
self.add_rect(layer="{}implant".format(self.implant_type),
|
||||
offset=implant_position,
|
||||
width=implant_width,
|
||||
height=implant_height)
|
||||
well_position = self.first_layer_position - [drc["well_enclosure_active"]]*2
|
||||
well_width = self.first_layer_width + 2*drc["well_enclosure_active"]
|
||||
well_height = self.first_layer_height + 2*drc["well_enclosure_active"]
|
||||
self.add_rect(layer="{}well".format(self.well_type),
|
||||
offset=well_position,
|
||||
width=well_width,
|
||||
height=well_height)
|
||||
|
||||
|
||||
|
||||
# This is not instantiated and used for calculations only.
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
word_size = 2
|
||||
num_words = 128
|
||||
num_words = 16
|
||||
num_banks = 1
|
||||
|
||||
tech_name = "freepdk45"
|
||||
|
||||
output_path = "/tmp/mysram"
|
||||
output_path = "./temp"
|
||||
output_name = "sram_2_16_1_freepdk45"
|
||||
|
||||
decoder = "hierarchical_decoder"
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
word_size = 1
|
||||
word_size = 2
|
||||
num_words = 16
|
||||
num_banks = 1
|
||||
|
||||
tech_name = "scn3me_subm"
|
||||
|
||||
output_path = "/tmp/mysram"
|
||||
output_path = "./temp"
|
||||
output_name = "sram_2_16_1_scn3me_subm"
|
||||
|
||||
decoder = "hierarchical_decoder"
|
||||
|
|
|
|||
|
|
@ -65,7 +65,10 @@ def parse_args():
|
|||
# This may be overridden when we read a config file though...
|
||||
if OPTS.tech_name == "":
|
||||
OPTS.tech_name = "freepdk45"
|
||||
|
||||
# Alias SCMOS to AMI 0.5um
|
||||
if OPTS.tech_name == "scmos":
|
||||
OPTS.tech_name = "scn3me_subm"
|
||||
|
||||
return (options, args)
|
||||
|
||||
def print_banner():
|
||||
|
|
|
|||
|
|
@ -308,27 +308,33 @@ class layout(lef.lef):
|
|||
layer_stack=layers,
|
||||
position_list=coordinates)
|
||||
|
||||
def add_contact(self, layers, offset, size=[1,1], mirror="R0", rotate=0):
|
||||
def add_contact(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
|
||||
""" This is just an alias for a via."""
|
||||
return self.add_via(layers=layers,
|
||||
offset=offset,
|
||||
size=size,
|
||||
mirror=mirror,
|
||||
rotate=rotate)
|
||||
rotate=rotate,
|
||||
implant_type=implant_type,
|
||||
well_type=well_type)
|
||||
|
||||
def add_contact_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0):
|
||||
def add_contact_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
|
||||
""" This is just an alias for a via."""
|
||||
return self.add_via_center(layers=layers,
|
||||
offset=offset,
|
||||
size=size,
|
||||
mirror=mirror,
|
||||
rotate=rotate)
|
||||
rotate=rotate,
|
||||
implant_type=implant_type,
|
||||
well_type=well_type)
|
||||
|
||||
def add_via(self, layers, offset, size=[1,1], mirror="R0", rotate=0):
|
||||
def add_via(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
|
||||
""" Add a three layer via structure. """
|
||||
import contact
|
||||
via = contact.contact(layer_stack=layers,
|
||||
dimensions=size)
|
||||
dimensions=size,
|
||||
implant_type=implant_type,
|
||||
well_type=well_type)
|
||||
self.add_mod(via)
|
||||
self.add_inst(name=via.name,
|
||||
mod=via,
|
||||
|
|
@ -339,11 +345,13 @@ class layout(lef.lef):
|
|||
self.connect_inst([])
|
||||
return via
|
||||
|
||||
def add_via_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0):
|
||||
def add_via_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
|
||||
""" Add a three layer via structure by the center coordinate accounting for mirroring and rotation. """
|
||||
import contact
|
||||
via = contact.contact(layer_stack=layers,
|
||||
dimensions=size)
|
||||
dimensions=size,
|
||||
implant_type=implant_type,
|
||||
well_type=well_type)
|
||||
|
||||
debug.check(mirror=="R0","Use rotate to rotate vias instead of mirror.")
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ class options(optparse.Values):
|
|||
tech_name = ""
|
||||
# This is the temp directory where all intermediate results are stored.
|
||||
openram_temp = "/tmp/openram_{0}_{1}_temp/".format(getpass.getuser(),os.getpid())
|
||||
#openram_temp = "/tmp/openram_temp/"
|
||||
# This is the verbosity level to control debug information. 0 is none, 1
|
||||
# is minimal, etc.
|
||||
debug_level = 0
|
||||
|
|
|
|||
|
|
@ -97,93 +97,114 @@ class pgate(design.design):
|
|||
def extend_wells(self, middle_position):
|
||||
""" Extend the n/p wells to cover whole cell """
|
||||
|
||||
nwell_height = self.height - middle_position.y
|
||||
# Add a rail width to extend the well to the top of the rail
|
||||
self.max_y_offset = self.height + 0.5*drc["minwidth_metal1"]
|
||||
self.nwell_position = middle_position
|
||||
nwell_height = self.max_y_offset - middle_position.y
|
||||
if info["has_nwell"]:
|
||||
self.add_rect(layer="nwell",
|
||||
offset=middle_position,
|
||||
width=self.well_width,
|
||||
height=nwell_height)
|
||||
self.add_rect(layer="vtg",
|
||||
offset=middle_position,
|
||||
offset=self.nwell_position,
|
||||
width=self.well_width,
|
||||
height=nwell_height)
|
||||
|
||||
self.pwell_position = vector(0,-0.5*drc["minwidth_metal1"])
|
||||
pwell_height = middle_position.y-self.pwell_position.y
|
||||
if info["has_pwell"]:
|
||||
self.add_rect(layer="pwell",
|
||||
offset=vector(0,0),
|
||||
offset=self.pwell_position,
|
||||
width=self.well_width,
|
||||
height=middle_position.y)
|
||||
height=pwell_height)
|
||||
self.add_rect(layer="vtg",
|
||||
offset=vector(0,0),
|
||||
offset=self.pwell_position,
|
||||
width=self.well_width,
|
||||
height=middle_position.y)
|
||||
height=pwell_height)
|
||||
|
||||
def add_nwell_contact(self, nmos, nmos_pos):
|
||||
""" Add an nwell contact next to the given nmos device. """
|
||||
def add_nwell_contact(self, pmos, pmos_pos):
|
||||
""" Add an nwell contact next to the given pmos device. """
|
||||
|
||||
layer_stack = ("active", "contact", "metal1")
|
||||
|
||||
# To the right a spacing away from the nmos right active edge
|
||||
nwell_contact_xoffset = nmos_pos.x + nmos.active_width + drc["active_to_body_active"]
|
||||
nwell_contact_yoffset = nmos_pos.y
|
||||
nwell_offset = vector(nwell_contact_xoffset, nwell_contact_yoffset)
|
||||
# Offset by half a contact in x and y
|
||||
nwell_offset += vector(0.5*nmos.active_contact.first_layer_width,
|
||||
0.5*nmos.active_contact.first_layer_height)
|
||||
self.nwell_contact=self.add_contact_center(layers=layer_stack,
|
||||
offset=nwell_offset)
|
||||
self.add_rect_center(layer="metal1",
|
||||
offset=nwell_offset.scale(1,0.5),
|
||||
width=self.nwell_contact.second_layer_width,
|
||||
height=nwell_offset.y)
|
||||
# Now add the full active and implant for the NMOS
|
||||
nwell_offset = nmos_pos + vector(nmos.active_width,0)
|
||||
nwell_contact_width = drc["active_to_body_active"] + nmos.active_contact.width
|
||||
self.add_rect(layer="active",
|
||||
offset=nwell_offset,
|
||||
width=nwell_contact_width,
|
||||
height=nmos.active_height)
|
||||
|
||||
implant_offset = nwell_offset + vector(drc["implant_to_implant"],0)
|
||||
implant_width = nwell_contact_width - drc["implant_to_implant"]
|
||||
self.add_rect(layer="pimplant",
|
||||
offset=implant_offset,
|
||||
width=implant_width,
|
||||
height=nmos.active_height)
|
||||
|
||||
|
||||
def add_pwell_contact(self, pmos, pmos_pos):
|
||||
""" Add an pwell contact next to the given pmos device. """
|
||||
|
||||
layer_stack = ("active", "contact", "metal1")
|
||||
|
||||
|
||||
# To the right a spacing away from the pmos right active edge
|
||||
pwell_contact_xoffset = pmos_pos.x + pmos.active_width + drc["active_to_body_active"]
|
||||
pwell_contact_yoffset = pmos_pos.y + pmos.active_height - pmos.active_contact.height
|
||||
pwell_offset = vector(pwell_contact_xoffset, pwell_contact_yoffset)
|
||||
# Offset by half a contact
|
||||
pwell_offset += vector(0.5*pmos.active_contact.first_layer_width,
|
||||
contact_xoffset = pmos_pos.x + pmos.active_width + drc["active_to_body_active"]
|
||||
# Must be at least an well enclosure of active down from the top of the well
|
||||
# OR align the active with the top of PMOS active.
|
||||
contact_yoffset = min(pmos_pos.y + pmos.active_height - pmos.active_contact.first_layer_height,
|
||||
self.max_y_offset - pmos.active_contact.first_layer_height/2 - drc["well_enclosure_active"])
|
||||
contact_offset = vector(contact_xoffset, contact_yoffset)
|
||||
# Offset by half a contact in x and y
|
||||
contact_offset += vector(0.5*pmos.active_contact.first_layer_width,
|
||||
0.5*pmos.active_contact.first_layer_height)
|
||||
self.pwell_contact=self.add_contact_center(layers=layer_stack,
|
||||
offset=pwell_offset)
|
||||
self.nwell_contact=self.add_contact_center(layers=layer_stack,
|
||||
offset=contact_offset,
|
||||
implant_type="n",
|
||||
well_type="n")
|
||||
self.add_rect_center(layer="metal1",
|
||||
offset=pwell_offset + vector(0,0.5*(self.height-pwell_offset.y)),
|
||||
width=self.pwell_contact.second_layer_width,
|
||||
height=self.height - pwell_offset.y)
|
||||
# Now add the full active and implant for the PMOS
|
||||
pwell_offset = pmos_pos + vector(pmos.active_width,0)
|
||||
pwell_contact_width = drc["active_to_body_active"] + pmos.active_contact.width
|
||||
self.add_rect(layer="active",
|
||||
offset=pwell_offset,
|
||||
width=pwell_contact_width,
|
||||
height=pmos.active_height)
|
||||
|
||||
|
||||
implant_offset = pwell_offset + vector(drc["implant_to_implant"],0)
|
||||
implant_width = pwell_contact_width - drc["implant_to_implant"]
|
||||
self.add_rect(layer="nimplant",
|
||||
offset=implant_offset,
|
||||
width=implant_width,
|
||||
height=pmos.active_height)
|
||||
offset=contact_offset + vector(0,0.5*(self.height-contact_offset.y)),
|
||||
width=self.nwell_contact.second_layer_width,
|
||||
height=self.height - contact_offset.y)
|
||||
|
||||
# Now add the full active and implant for the PMOS
|
||||
active_offset = pmos_pos + vector(pmos.active_width,0)
|
||||
# This might be needed if the spacing between the actives is not satisifed
|
||||
# self.add_rect(layer="active",
|
||||
# offset=active_offset,
|
||||
# width=pmos.active_contact.width,
|
||||
# height=pmos.active_height)
|
||||
|
||||
# we need to ensure implants don't overlap and are spaced far enough apart
|
||||
implant_spacing = drc["implant_to_implant"]+drc["implant_enclosure_active"]
|
||||
implant_offset = active_offset + vector(implant_spacing,0) - vector(0,drc["implant_enclosure_active"])
|
||||
implant_width = pmos.active_contact.width + 2*drc["implant_enclosure_active"]
|
||||
implant_height = pmos.active_height + 2*drc["implant_enclosure_active"]
|
||||
# self.add_rect(layer="nimplant",
|
||||
# offset=implant_offset,
|
||||
# width=implant_width,
|
||||
# height=implant_height)
|
||||
|
||||
|
||||
def add_pwell_contact(self, nmos, nmos_pos):
|
||||
""" Add an pwell contact next to the given nmos device. """
|
||||
|
||||
layer_stack = ("active", "contact", "metal1")
|
||||
|
||||
|
||||
# To the right a spacing away from the nmos right active edge
|
||||
contact_xoffset = nmos_pos.x + nmos.active_width + drc["active_to_body_active"]
|
||||
# Must be at least an well enclosure of active up from the bottom of the well
|
||||
contact_yoffset = max(nmos_pos.y,
|
||||
drc["well_enclosure_active"] - nmos.active_contact.first_layer_height/2 - self.pwell_position.y)
|
||||
contact_offset = vector(contact_xoffset, contact_yoffset)
|
||||
|
||||
# Offset by half a contact
|
||||
contact_offset += vector(0.5*nmos.active_contact.first_layer_width,
|
||||
0.5*nmos.active_contact.first_layer_height)
|
||||
self.pwell_contact=self.add_contact_center(layers=layer_stack,
|
||||
offset=contact_offset,
|
||||
implant_type="p",
|
||||
well_type="p")
|
||||
self.add_rect_center(layer="metal1",
|
||||
offset=contact_offset.scale(1,0.5),
|
||||
width=self.pwell_contact.second_layer_width,
|
||||
height=contact_offset.y)
|
||||
|
||||
# Now add the full active and implant for the NMOS
|
||||
active_offset = nmos_pos + vector(nmos.active_width,0)
|
||||
# This might be needed if the spacing between the actives is not satisifed
|
||||
# self.add_rect(layer="active",
|
||||
# offset=active_offset,
|
||||
# width=nmos.active_contact.width,
|
||||
# height=nmos.active_height)
|
||||
|
||||
implant_spacing = drc["implant_to_implant"]+drc["implant_enclosure_active"]
|
||||
implant_offset = active_offset + vector(implant_spacing,0) - vector(0,drc["implant_enclosure_active"])
|
||||
implant_width = nmos.active_contact.width + 2*drc["implant_enclosure_active"]
|
||||
implant_height = nmos.active_height + 2*drc["implant_enclosure_active"]
|
||||
# self.add_rect(layer="pimplant",
|
||||
# offset=implant_offset,
|
||||
# width=implant_width,
|
||||
# height=implant_height)
|
||||
|
||||
|
|
|
|||
|
|
@ -220,9 +220,9 @@ class pinv(pgate.pgate):
|
|||
def add_well_contacts(self):
|
||||
""" Add n/p well taps to the layout and connect to supplies """
|
||||
|
||||
self.add_nwell_contact(self.nmos, self.nmos_pos)
|
||||
self.add_nwell_contact(self.pmos, self.pmos_pos)
|
||||
|
||||
self.add_pwell_contact(self.pmos, self.pmos_pos)
|
||||
self.add_pwell_contact(self.nmos, self.nmos_pos)
|
||||
|
||||
def connect_rails(self):
|
||||
""" Connect the nmos and pmos to its respective power rails """
|
||||
|
|
|
|||
|
|
@ -50,9 +50,9 @@ class pnand2(pgate.pgate):
|
|||
self.setup_layout_constants()
|
||||
self.add_supply_rails()
|
||||
self.add_ptx()
|
||||
self.add_well_contacts()
|
||||
self.connect_rails()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.add_well_contacts()
|
||||
self.route_inputs()
|
||||
self.route_output()
|
||||
|
||||
|
|
@ -151,10 +151,10 @@ class pnand2(pgate.pgate):
|
|||
self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height))
|
||||
|
||||
def add_well_contacts(self):
|
||||
""" Add n/p well taps to the layout and connect to supplies """
|
||||
""" Add n/p well taps to the layout and connect to supplies AFTER the wells are created """
|
||||
|
||||
self.add_nwell_contact(self.nmos, self.nmos2_pos)
|
||||
self.add_pwell_contact(self.pmos, self.pmos2_pos)
|
||||
self.add_nwell_contact(self.pmos, self.pmos2_pos)
|
||||
self.add_pwell_contact(self.nmos, self.nmos2_pos)
|
||||
|
||||
|
||||
def connect_rails(self):
|
||||
|
|
|
|||
|
|
@ -50,9 +50,9 @@ class pnand3(pgate.pgate):
|
|||
self.setup_layout_constants()
|
||||
self.add_supply_rails()
|
||||
self.add_ptx()
|
||||
self.add_well_contacts()
|
||||
self.connect_rails()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.add_well_contacts()
|
||||
self.route_inputs()
|
||||
self.route_output()
|
||||
|
||||
|
|
@ -157,8 +157,8 @@ class pnand3(pgate.pgate):
|
|||
def add_well_contacts(self):
|
||||
""" Add n/p well taps to the layout and connect to supplies """
|
||||
|
||||
self.add_nwell_contact(self.nmos, self.nmos3_pos)
|
||||
self.add_pwell_contact(self.pmos, self.pmos3_pos)
|
||||
self.add_nwell_contact(self.pmos, self.pmos3_pos)
|
||||
self.add_pwell_contact(self.nmos, self.nmos3_pos)
|
||||
|
||||
|
||||
def connect_rails(self):
|
||||
|
|
|
|||
|
|
@ -51,9 +51,9 @@ class pnor2(pgate.pgate):
|
|||
self.setup_layout_constants()
|
||||
self.add_supply_rails()
|
||||
self.add_ptx()
|
||||
self.add_well_contacts()
|
||||
self.connect_rails()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.add_well_contacts()
|
||||
self.route_inputs()
|
||||
self.route_output()
|
||||
|
||||
|
|
@ -157,8 +157,8 @@ class pnor2(pgate.pgate):
|
|||
def add_well_contacts(self):
|
||||
""" Add n/p well taps to the layout and connect to supplies """
|
||||
|
||||
self.add_nwell_contact(self.nmos, self.nmos2_pos)
|
||||
self.add_pwell_contact(self.pmos, self.pmos2_pos)
|
||||
self.add_nwell_contact(self.pmos, self.pmos2_pos)
|
||||
self.add_pwell_contact(self.nmos, self.nmos2_pos)
|
||||
|
||||
|
||||
def connect_rails(self):
|
||||
|
|
|
|||
|
|
@ -130,13 +130,10 @@ class precharge(pgate.pgate):
|
|||
well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1,0) \
|
||||
+ vector(0, self.upper_pmos1_pos.y + self.pmos.height + drc["well_extend_active"])
|
||||
self.add_contact_center(layers=("active", "contact", "metal1"),
|
||||
offset=well_contact_pos)
|
||||
offset=well_contact_pos,
|
||||
implant_type="n",
|
||||
well_type="n")
|
||||
|
||||
# adds the implant to turn the contact into a nwell tap
|
||||
self.add_rect_center(layer="nimplant",
|
||||
offset=well_contact_pos,
|
||||
width=contact.well.first_layer_width,
|
||||
height=contact.well.first_layer_height)
|
||||
|
||||
self.height = well_contact_pos.y + contact.well.height
|
||||
|
||||
|
|
@ -175,19 +172,19 @@ class precharge(pgate.pgate):
|
|||
def add_bitline_contacts(self):
|
||||
"""Adds contacts/via from metal1 to metal2 for bit-lines"""
|
||||
|
||||
for stack in [("active","contact","metal1"),("metal1", "via1", "metal2")]:
|
||||
pos = self.lower_pmos_inst.get_pin("S").center()
|
||||
self.add_contact_center(layers=stack,
|
||||
offset=pos)
|
||||
pos = self.lower_pmos_inst.get_pin("D").center()
|
||||
self.add_contact_center(layers=stack,
|
||||
offset=pos)
|
||||
pos = self.upper_pmos1_inst.get_pin("S").center()
|
||||
self.add_contact_center(layers=stack,
|
||||
offset=pos)
|
||||
pos = self.upper_pmos2_inst.get_pin("D").center()
|
||||
self.add_contact_center(layers=stack,
|
||||
offset=pos)
|
||||
stack=("metal1", "via1", "metal2")
|
||||
pos = self.lower_pmos_inst.get_pin("S").center()
|
||||
self.add_contact_center(layers=stack,
|
||||
offset=pos)
|
||||
pos = self.lower_pmos_inst.get_pin("D").center()
|
||||
self.add_contact_center(layers=stack,
|
||||
offset=pos)
|
||||
pos = self.upper_pmos1_inst.get_pin("S").center()
|
||||
self.add_contact_center(layers=stack,
|
||||
offset=pos)
|
||||
pos = self.upper_pmos2_inst.get_pin("D").center()
|
||||
self.add_contact_center(layers=stack,
|
||||
offset=pos)
|
||||
|
||||
def connect_pmos(self, pmos_pin, bit_pin):
|
||||
""" Connect pmos pin to bitline pin """
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class precharge_array(design.design):
|
|||
|
||||
self.columns = columns
|
||||
|
||||
self.pc_cell = precharge(name="precharge_cell", size=size)
|
||||
self.pc_cell = precharge(name="precharge", size=size)
|
||||
self.add_mod(self.pc_cell)
|
||||
|
||||
self.width = self.columns * self.pc_cell.width
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ class ptx(design.design):
|
|||
height=self.active_height)
|
||||
# If the implant must enclose the active, shift offset
|
||||
# and increase width/height
|
||||
enclose_width = drc["implant_enclose_active"]
|
||||
enclose_width = drc["implant_enclosure_active"]
|
||||
enclose_offset = [enclose_width]*2
|
||||
self.add_rect(layer="{}implant".format(self.implant_type),
|
||||
offset=self.active_offset - enclose_offset,
|
||||
|
|
@ -325,7 +325,9 @@ class ptx(design.design):
|
|||
for pos in source_positions:
|
||||
contact=self.add_contact_center(layers=("active", "contact", "metal1"),
|
||||
offset=pos,
|
||||
size=(1, self.num_contacts))
|
||||
size=(1, self.num_contacts),
|
||||
implant_type=self.implant_type,
|
||||
well_type=self.well_type)
|
||||
self.add_layout_pin_center_rect(text="S",
|
||||
layer="metal1",
|
||||
offset=pos,
|
||||
|
|
@ -336,7 +338,9 @@ class ptx(design.design):
|
|||
for pos in drain_positions:
|
||||
contact=self.add_contact_center(layers=("active", "contact", "metal1"),
|
||||
offset=pos,
|
||||
size=(1, self.num_contacts))
|
||||
size=(1, self.num_contacts),
|
||||
implant_type=self.implant_type,
|
||||
well_type=self.well_type)
|
||||
self.add_layout_pin_center_rect(text="D",
|
||||
layer="metal1",
|
||||
offset=pos,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -34,6 +34,7 @@ layer["vth"] = 7
|
|||
layer["thkox"] = 8
|
||||
layer["poly"] = 9
|
||||
layer["contact"] = 10
|
||||
layer["active_contact"] = 10
|
||||
layer["metal1"] = 11
|
||||
layer["via1"] = 12
|
||||
layer["metal2"] = 13
|
||||
|
|
@ -120,9 +121,9 @@ drc["minarea_active"] = 0
|
|||
# IMPLANT.1 Minimum spacing of nimplant/ pimplant to channel
|
||||
drc["implant_to_channel"] = 0.07
|
||||
# Not a rule
|
||||
drc["implant_enclose_active"] = 0
|
||||
drc["implant_enclosure_active"] = 0
|
||||
# Not a rule
|
||||
drc["implant_enclose_contact"] = 0
|
||||
drc["implant_enclosure_contact"] = 0
|
||||
# IMPLANT.2 Minimum spacing of nimplant/ pimplant to contact
|
||||
drc["implant_to_contact"] = 0.025
|
||||
# IMPLANT.3 Minimum width/ spacing of nimplant/ pimplant
|
||||
|
|
|
|||
|
|
@ -26,14 +26,13 @@ GDS["zoom"] = 0.5
|
|||
layer={}
|
||||
layer["vtg"] = -1
|
||||
layer["vth"] = -1
|
||||
layer["contact"] = 25
|
||||
layer["contact"] = 47
|
||||
layer["pwell"] = 41
|
||||
layer["nwell"] = 42
|
||||
layer["active"] = 43
|
||||
layer["pimplant"] = 44
|
||||
layer["nimplant"] = 45
|
||||
layer["poly"] = 46
|
||||
layer["poly_contact"] = 47
|
||||
layer["active_contact"] = 48
|
||||
layer["metal1"] = 49
|
||||
layer["via1"] = 50
|
||||
|
|
@ -106,9 +105,9 @@ drc["minarea_active"] = 0.0
|
|||
# 4.1 Minimum select spacing to channel of transistor to ensure adequate source/drain width
|
||||
drc["implant_to_channel"] = 0.9
|
||||
# 4.2 Minimum select overlap of active
|
||||
drc["implant_enclose_active"] = 0.6
|
||||
drc["implant_enclosure_active"] = 0.6
|
||||
# 4.3 Minimum select overlap of contact
|
||||
drc["implant_enclose_contact"] = 0.3
|
||||
drc["implant_enclosure_contact"] = 0.3
|
||||
# Not a rule
|
||||
drc["implant_to_contact"] = 0
|
||||
# Not a rule
|
||||
|
|
|
|||
Loading…
Reference in New Issue