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:
Matt Guthaus 2018-01-11 10:24:44 -08:00
parent f028436156
commit 1701eac1a9
18 changed files with 814 additions and 727 deletions

View File

@ -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.

View File

@ -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"

View File

@ -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"

View File

@ -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():

View File

@ -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.")

View File

@ -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

View File

@ -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)

View File

@ -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 """

View File

@ -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):

View File

@ -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):

View File

@ -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):

View File

@ -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 """

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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