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.
|
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
|
This class has enclosure on multiple sides of the contact whereas a via may
|
||||||
have extension on two or four sides.
|
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]):
|
def __init__(self, layer_stack, dimensions=[1,1], implant_type=None, well_type=None):
|
||||||
name = "{0}_{1}_{2}_{3}x{4}".format(layer_stack[0],
|
if implant_type or well_type:
|
||||||
layer_stack[1],
|
name = "{0}_{1}_{2}_{3}x{4}_{5}{6}".format(layer_stack[0],
|
||||||
layer_stack[2],
|
layer_stack[1],
|
||||||
dimensions[0],
|
layer_stack[2],
|
||||||
dimensions[1])
|
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)
|
design.design.__init__(self, name)
|
||||||
debug.info(4, "create contact object {0}".format(name))
|
debug.info(4, "create contact object {0}".format(name))
|
||||||
|
|
||||||
self.layer_stack = layer_stack
|
self.layer_stack = layer_stack
|
||||||
self.dimensions = dimensions
|
self.dimensions = dimensions
|
||||||
self.offset = vector(0,0)
|
self.offset = vector(0,0)
|
||||||
|
self.implant_type = implant_type
|
||||||
|
self.well_type = well_type
|
||||||
self.pins = [] # used for matching parm lengths
|
self.pins = [] # used for matching parm lengths
|
||||||
self.create_layout()
|
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.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)
|
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):
|
def setup_layers(self):
|
||||||
(first_layer, via_layer, second_layer) = self.layer_stack
|
(first_layer, via_layer, second_layer) = self.layer_stack
|
||||||
self.first_layer_name = first_layer
|
self.first_layer_name = first_layer
|
||||||
self.via_layer_name = via_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
|
self.second_layer_name = second_layer
|
||||||
|
|
||||||
def setup_layout_constants(self):
|
def setup_layout_constants(self):
|
||||||
self.contact_width = drc["minwidth_{0}". format(self.via_layer_name)]
|
self.contact_width = drc["minwidth_{0}". format(self.via_layer_name)]
|
||||||
self.contact_to_contact = drc["{0}_to_{0}".format(self.via_layer_name)]
|
contact_to_contact = drc["{0}_to_{0}".format(self.via_layer_name)]
|
||||||
self.contact_pitch = self.contact_width + self.contact_to_contact
|
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_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
|
self.contact_array_height = self.contact_width + (self.dimensions[1] - 1) * self.contact_pitch
|
||||||
|
|
||||||
# FIME break this up
|
# DRC rules
|
||||||
self.first_layer_horizontal_enclosure = max((drc["minwidth_{0}".format(self.first_layer_name)] - self.contact_array_width) / 2,
|
first_layer_minwidth = drc["minwidth_{0}".format(self.first_layer_name)]
|
||||||
drc["{0}_enclosure_{1}".format(self.first_layer_name, self.via_layer_name)])
|
first_layer_minarea = drc["minarea_{0}".format(self.first_layer_name)]
|
||||||
self.first_layer_vertical_enclosure = max(utils.ceil((drc["minarea_{0}".format(self.first_layer_name)]
|
first_layer_enclosure = drc["{0}_enclosure_{1}".format(self.first_layer_name, self.via_layer_name)]
|
||||||
/ (self.contact_array_width + 2 * self.first_layer_horizontal_enclosure) - self.contact_array_height) / 2),
|
first_layer_extend = drc["{0}_extend_{1}".format(self.first_layer_name, self.via_layer_name)]
|
||||||
(drc["minwidth_{0}".format(self.first_layer_name)] - self.contact_array_height) / 2,
|
second_layer_minwidth = drc["minwidth_{0}".format(self.second_layer_name)]
|
||||||
drc["{0}_extend_{1}".format(self.first_layer_name, self.via_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,
|
self.first_layer_horizontal_enclosure = max((first_layer_minwidth - self.contact_array_width) / 2,
|
||||||
drc["{0}_enclosure_{1}".format(self.second_layer_name, self.via_layer_name)])
|
first_layer_enclosure)
|
||||||
self.second_layer_vertical_enclosure = max(utils.ceil((drc["minarea_{0}".format(self.second_layer_name)]
|
self.first_layer_vertical_enclosure = max(utils.ceil((first_layer_minarea
|
||||||
/ (self.contact_array_width + 2 * self.second_layer_horizontal_enclosure) - self.contact_array_height) / 2),
|
/ (self.contact_array_width + 2*self.first_layer_horizontal_enclosure)
|
||||||
(drc["minwidth_{0}".format(self.second_layer_name)] - self.contact_array_height) / 2,
|
- self.contact_array_height)/2),
|
||||||
drc["{0}_extend_{1}".format(self.second_layer_name, self.via_layer_name)])
|
(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
|
# offset for the via array
|
||||||
self.via_layer_position =vector(max(self.first_layer_horizontal_enclosure,self.second_layer_horizontal_enclosure),
|
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))
|
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]):
|
for i in range(self.dimensions[1]):
|
||||||
offset = self.via_layer_position + vector(0, self.contact_pitch * i)
|
offset = self.via_layer_position + vector(0, self.contact_pitch * i)
|
||||||
for j in range(self.dimensions[0]):
|
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,
|
offset=offset,
|
||||||
width=self.contact_width,
|
width=self.contact_width,
|
||||||
height=self.contact_width)
|
height=self.contact_width)
|
||||||
offset = offset + vector(self.contact_pitch,0)
|
offset = offset + vector(self.contact_pitch,0)
|
||||||
|
|
||||||
def create_first_layer_enclosure(self):
|
def create_first_layer_enclosure(self):
|
||||||
width = self.first_layer_width = self.contact_array_width \
|
# this is if the first and second layers are different
|
||||||
+ 2 * self.first_layer_horizontal_enclosure
|
self.first_layer_position = vector(max(self.second_layer_horizontal_enclosure - self.first_layer_horizontal_enclosure,0),
|
||||||
height = self.first_layer_height = self.contact_array_height \
|
max(self.second_layer_vertical_enclosure - self.first_layer_vertical_enclosure,0))
|
||||||
+ 2 * self.first_layer_vertical_enclosure
|
|
||||||
|
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,
|
self.add_rect(layer=self.first_layer_name,
|
||||||
offset=self.first_layer_position,
|
offset=self.first_layer_position,
|
||||||
width=width,
|
width=self.first_layer_width,
|
||||||
height=height)
|
height=self.first_layer_height)
|
||||||
|
|
||||||
def create_second_layer_enclosure(self):
|
def create_second_layer_enclosure(self):
|
||||||
width = self.second_layer_width = self.contact_array_width \
|
# this is if the first and second layers are different
|
||||||
+ 2 * self.second_layer_horizontal_enclosure
|
self.second_layer_position = vector(max(self.first_layer_horizontal_enclosure - self.second_layer_horizontal_enclosure,0),
|
||||||
height = self.second_layer_height = self.contact_array_height \
|
max(self.first_layer_vertical_enclosure - self.second_layer_vertical_enclosure,0))
|
||||||
+ 2 * self.second_layer_vertical_enclosure
|
|
||||||
|
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,
|
self.add_rect(layer=self.second_layer_name,
|
||||||
offset=self.second_layer_position,
|
offset=self.second_layer_position,
|
||||||
width=width,
|
width=self.second_layer_width,
|
||||||
height=height)
|
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.
|
# This is not instantiated and used for calculations only.
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
word_size = 2
|
word_size = 2
|
||||||
num_words = 128
|
num_words = 16
|
||||||
num_banks = 1
|
num_banks = 1
|
||||||
|
|
||||||
tech_name = "freepdk45"
|
tech_name = "freepdk45"
|
||||||
|
|
||||||
output_path = "/tmp/mysram"
|
output_path = "./temp"
|
||||||
output_name = "sram_2_16_1_freepdk45"
|
output_name = "sram_2_16_1_freepdk45"
|
||||||
|
|
||||||
decoder = "hierarchical_decoder"
|
decoder = "hierarchical_decoder"
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
word_size = 1
|
word_size = 2
|
||||||
num_words = 16
|
num_words = 16
|
||||||
num_banks = 1
|
num_banks = 1
|
||||||
|
|
||||||
tech_name = "scn3me_subm"
|
tech_name = "scn3me_subm"
|
||||||
|
|
||||||
output_path = "/tmp/mysram"
|
output_path = "./temp"
|
||||||
output_name = "sram_2_16_1_scn3me_subm"
|
output_name = "sram_2_16_1_scn3me_subm"
|
||||||
|
|
||||||
decoder = "hierarchical_decoder"
|
decoder = "hierarchical_decoder"
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,10 @@ def parse_args():
|
||||||
# This may be overridden when we read a config file though...
|
# This may be overridden when we read a config file though...
|
||||||
if OPTS.tech_name == "":
|
if OPTS.tech_name == "":
|
||||||
OPTS.tech_name = "freepdk45"
|
OPTS.tech_name = "freepdk45"
|
||||||
|
# Alias SCMOS to AMI 0.5um
|
||||||
|
if OPTS.tech_name == "scmos":
|
||||||
|
OPTS.tech_name = "scn3me_subm"
|
||||||
|
|
||||||
return (options, args)
|
return (options, args)
|
||||||
|
|
||||||
def print_banner():
|
def print_banner():
|
||||||
|
|
|
||||||
|
|
@ -308,27 +308,33 @@ class layout(lef.lef):
|
||||||
layer_stack=layers,
|
layer_stack=layers,
|
||||||
position_list=coordinates)
|
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."""
|
""" This is just an alias for a via."""
|
||||||
return self.add_via(layers=layers,
|
return self.add_via(layers=layers,
|
||||||
offset=offset,
|
offset=offset,
|
||||||
size=size,
|
size=size,
|
||||||
mirror=mirror,
|
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."""
|
""" This is just an alias for a via."""
|
||||||
return self.add_via_center(layers=layers,
|
return self.add_via_center(layers=layers,
|
||||||
offset=offset,
|
offset=offset,
|
||||||
size=size,
|
size=size,
|
||||||
mirror=mirror,
|
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. """
|
""" Add a three layer via structure. """
|
||||||
import contact
|
import contact
|
||||||
via = contact.contact(layer_stack=layers,
|
via = contact.contact(layer_stack=layers,
|
||||||
dimensions=size)
|
dimensions=size,
|
||||||
|
implant_type=implant_type,
|
||||||
|
well_type=well_type)
|
||||||
self.add_mod(via)
|
self.add_mod(via)
|
||||||
self.add_inst(name=via.name,
|
self.add_inst(name=via.name,
|
||||||
mod=via,
|
mod=via,
|
||||||
|
|
@ -339,11 +345,13 @@ class layout(lef.lef):
|
||||||
self.connect_inst([])
|
self.connect_inst([])
|
||||||
return via
|
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. """
|
""" Add a three layer via structure by the center coordinate accounting for mirroring and rotation. """
|
||||||
import contact
|
import contact
|
||||||
via = contact.contact(layer_stack=layers,
|
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.")
|
debug.check(mirror=="R0","Use rotate to rotate vias instead of mirror.")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ class options(optparse.Values):
|
||||||
tech_name = ""
|
tech_name = ""
|
||||||
# This is the temp directory where all intermediate results are stored.
|
# 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_{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
|
# This is the verbosity level to control debug information. 0 is none, 1
|
||||||
# is minimal, etc.
|
# is minimal, etc.
|
||||||
debug_level = 0
|
debug_level = 0
|
||||||
|
|
|
||||||
|
|
@ -97,93 +97,114 @@ class pgate(design.design):
|
||||||
def extend_wells(self, middle_position):
|
def extend_wells(self, middle_position):
|
||||||
""" Extend the n/p wells to cover whole cell """
|
""" 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"]:
|
if info["has_nwell"]:
|
||||||
self.add_rect(layer="nwell",
|
self.add_rect(layer="nwell",
|
||||||
offset=middle_position,
|
offset=middle_position,
|
||||||
width=self.well_width,
|
width=self.well_width,
|
||||||
height=nwell_height)
|
height=nwell_height)
|
||||||
self.add_rect(layer="vtg",
|
self.add_rect(layer="vtg",
|
||||||
offset=middle_position,
|
offset=self.nwell_position,
|
||||||
width=self.well_width,
|
width=self.well_width,
|
||||||
height=nwell_height)
|
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"]:
|
if info["has_pwell"]:
|
||||||
self.add_rect(layer="pwell",
|
self.add_rect(layer="pwell",
|
||||||
offset=vector(0,0),
|
offset=self.pwell_position,
|
||||||
width=self.well_width,
|
width=self.well_width,
|
||||||
height=middle_position.y)
|
height=pwell_height)
|
||||||
self.add_rect(layer="vtg",
|
self.add_rect(layer="vtg",
|
||||||
offset=vector(0,0),
|
offset=self.pwell_position,
|
||||||
width=self.well_width,
|
width=self.well_width,
|
||||||
height=middle_position.y)
|
height=pwell_height)
|
||||||
|
|
||||||
def add_nwell_contact(self, nmos, nmos_pos):
|
def add_nwell_contact(self, pmos, pmos_pos):
|
||||||
""" Add an nwell contact next to the given nmos device. """
|
""" Add an nwell contact next to the given pmos device. """
|
||||||
|
|
||||||
layer_stack = ("active", "contact", "metal1")
|
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
|
# 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"]
|
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
|
# Must be at least an well enclosure of active down from the top of the well
|
||||||
pwell_offset = vector(pwell_contact_xoffset, pwell_contact_yoffset)
|
# OR align the active with the top of PMOS active.
|
||||||
# Offset by half a contact
|
contact_yoffset = min(pmos_pos.y + pmos.active_height - pmos.active_contact.first_layer_height,
|
||||||
pwell_offset += vector(0.5*pmos.active_contact.first_layer_width,
|
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)
|
0.5*pmos.active_contact.first_layer_height)
|
||||||
self.pwell_contact=self.add_contact_center(layers=layer_stack,
|
self.nwell_contact=self.add_contact_center(layers=layer_stack,
|
||||||
offset=pwell_offset)
|
offset=contact_offset,
|
||||||
|
implant_type="n",
|
||||||
|
well_type="n")
|
||||||
self.add_rect_center(layer="metal1",
|
self.add_rect_center(layer="metal1",
|
||||||
offset=pwell_offset + vector(0,0.5*(self.height-pwell_offset.y)),
|
offset=contact_offset + vector(0,0.5*(self.height-contact_offset.y)),
|
||||||
width=self.pwell_contact.second_layer_width,
|
width=self.nwell_contact.second_layer_width,
|
||||||
height=self.height - pwell_offset.y)
|
height=self.height - contact_offset.y)
|
||||||
# Now add the full active and implant for the PMOS
|
|
||||||
pwell_offset = pmos_pos + vector(pmos.active_width,0)
|
# Now add the full active and implant for the PMOS
|
||||||
pwell_contact_width = drc["active_to_body_active"] + pmos.active_contact.width
|
active_offset = pmos_pos + vector(pmos.active_width,0)
|
||||||
self.add_rect(layer="active",
|
# This might be needed if the spacing between the actives is not satisifed
|
||||||
offset=pwell_offset,
|
# self.add_rect(layer="active",
|
||||||
width=pwell_contact_width,
|
# offset=active_offset,
|
||||||
height=pmos.active_height)
|
# width=pmos.active_contact.width,
|
||||||
|
# height=pmos.active_height)
|
||||||
|
|
||||||
implant_offset = pwell_offset + vector(drc["implant_to_implant"],0)
|
# we need to ensure implants don't overlap and are spaced far enough apart
|
||||||
implant_width = pwell_contact_width - drc["implant_to_implant"]
|
implant_spacing = drc["implant_to_implant"]+drc["implant_enclosure_active"]
|
||||||
self.add_rect(layer="nimplant",
|
implant_offset = active_offset + vector(implant_spacing,0) - vector(0,drc["implant_enclosure_active"])
|
||||||
offset=implant_offset,
|
implant_width = pmos.active_contact.width + 2*drc["implant_enclosure_active"]
|
||||||
width=implant_width,
|
implant_height = pmos.active_height + 2*drc["implant_enclosure_active"]
|
||||||
height=pmos.active_height)
|
# 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):
|
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 """
|
||||||
|
|
||||||
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):
|
def connect_rails(self):
|
||||||
""" Connect the nmos and pmos to its respective power rails """
|
""" Connect the nmos and pmos to its respective power rails """
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,9 @@ class pnand2(pgate.pgate):
|
||||||
self.setup_layout_constants()
|
self.setup_layout_constants()
|
||||||
self.add_supply_rails()
|
self.add_supply_rails()
|
||||||
self.add_ptx()
|
self.add_ptx()
|
||||||
self.add_well_contacts()
|
|
||||||
self.connect_rails()
|
self.connect_rails()
|
||||||
self.extend_wells(self.well_pos)
|
self.extend_wells(self.well_pos)
|
||||||
|
self.add_well_contacts()
|
||||||
self.route_inputs()
|
self.route_inputs()
|
||||||
self.route_output()
|
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))
|
self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height))
|
||||||
|
|
||||||
def add_well_contacts(self):
|
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_nwell_contact(self.pmos, self.pmos2_pos)
|
||||||
self.add_pwell_contact(self.pmos, self.pmos2_pos)
|
self.add_pwell_contact(self.nmos, self.nmos2_pos)
|
||||||
|
|
||||||
|
|
||||||
def connect_rails(self):
|
def connect_rails(self):
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,9 @@ class pnand3(pgate.pgate):
|
||||||
self.setup_layout_constants()
|
self.setup_layout_constants()
|
||||||
self.add_supply_rails()
|
self.add_supply_rails()
|
||||||
self.add_ptx()
|
self.add_ptx()
|
||||||
self.add_well_contacts()
|
|
||||||
self.connect_rails()
|
self.connect_rails()
|
||||||
self.extend_wells(self.well_pos)
|
self.extend_wells(self.well_pos)
|
||||||
|
self.add_well_contacts()
|
||||||
self.route_inputs()
|
self.route_inputs()
|
||||||
self.route_output()
|
self.route_output()
|
||||||
|
|
||||||
|
|
@ -157,8 +157,8 @@ class pnand3(pgate.pgate):
|
||||||
def add_well_contacts(self):
|
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 """
|
||||||
|
|
||||||
self.add_nwell_contact(self.nmos, self.nmos3_pos)
|
self.add_nwell_contact(self.pmos, self.pmos3_pos)
|
||||||
self.add_pwell_contact(self.pmos, self.pmos3_pos)
|
self.add_pwell_contact(self.nmos, self.nmos3_pos)
|
||||||
|
|
||||||
|
|
||||||
def connect_rails(self):
|
def connect_rails(self):
|
||||||
|
|
|
||||||
|
|
@ -51,9 +51,9 @@ class pnor2(pgate.pgate):
|
||||||
self.setup_layout_constants()
|
self.setup_layout_constants()
|
||||||
self.add_supply_rails()
|
self.add_supply_rails()
|
||||||
self.add_ptx()
|
self.add_ptx()
|
||||||
self.add_well_contacts()
|
|
||||||
self.connect_rails()
|
self.connect_rails()
|
||||||
self.extend_wells(self.well_pos)
|
self.extend_wells(self.well_pos)
|
||||||
|
self.add_well_contacts()
|
||||||
self.route_inputs()
|
self.route_inputs()
|
||||||
self.route_output()
|
self.route_output()
|
||||||
|
|
||||||
|
|
@ -157,8 +157,8 @@ class pnor2(pgate.pgate):
|
||||||
def add_well_contacts(self):
|
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 """
|
||||||
|
|
||||||
self.add_nwell_contact(self.nmos, self.nmos2_pos)
|
self.add_nwell_contact(self.pmos, self.pmos2_pos)
|
||||||
self.add_pwell_contact(self.pmos, self.pmos2_pos)
|
self.add_pwell_contact(self.nmos, self.nmos2_pos)
|
||||||
|
|
||||||
|
|
||||||
def connect_rails(self):
|
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) \
|
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"])
|
+ vector(0, self.upper_pmos1_pos.y + self.pmos.height + drc["well_extend_active"])
|
||||||
self.add_contact_center(layers=("active", "contact", "metal1"),
|
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
|
self.height = well_contact_pos.y + contact.well.height
|
||||||
|
|
||||||
|
|
@ -175,19 +172,19 @@ class precharge(pgate.pgate):
|
||||||
def add_bitline_contacts(self):
|
def add_bitline_contacts(self):
|
||||||
"""Adds contacts/via from metal1 to metal2 for bit-lines"""
|
"""Adds contacts/via from metal1 to metal2 for bit-lines"""
|
||||||
|
|
||||||
for stack in [("active","contact","metal1"),("metal1", "via1", "metal2")]:
|
stack=("metal1", "via1", "metal2")
|
||||||
pos = self.lower_pmos_inst.get_pin("S").center()
|
pos = self.lower_pmos_inst.get_pin("S").center()
|
||||||
self.add_contact_center(layers=stack,
|
self.add_contact_center(layers=stack,
|
||||||
offset=pos)
|
offset=pos)
|
||||||
pos = self.lower_pmos_inst.get_pin("D").center()
|
pos = self.lower_pmos_inst.get_pin("D").center()
|
||||||
self.add_contact_center(layers=stack,
|
self.add_contact_center(layers=stack,
|
||||||
offset=pos)
|
offset=pos)
|
||||||
pos = self.upper_pmos1_inst.get_pin("S").center()
|
pos = self.upper_pmos1_inst.get_pin("S").center()
|
||||||
self.add_contact_center(layers=stack,
|
self.add_contact_center(layers=stack,
|
||||||
offset=pos)
|
offset=pos)
|
||||||
pos = self.upper_pmos2_inst.get_pin("D").center()
|
pos = self.upper_pmos2_inst.get_pin("D").center()
|
||||||
self.add_contact_center(layers=stack,
|
self.add_contact_center(layers=stack,
|
||||||
offset=pos)
|
offset=pos)
|
||||||
|
|
||||||
def connect_pmos(self, pmos_pin, bit_pin):
|
def connect_pmos(self, pmos_pin, bit_pin):
|
||||||
""" Connect pmos pin to bitline pin """
|
""" Connect pmos pin to bitline pin """
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ class precharge_array(design.design):
|
||||||
|
|
||||||
self.columns = columns
|
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.add_mod(self.pc_cell)
|
||||||
|
|
||||||
self.width = self.columns * self.pc_cell.width
|
self.width = self.columns * self.pc_cell.width
|
||||||
|
|
|
||||||
|
|
@ -266,7 +266,7 @@ class ptx(design.design):
|
||||||
height=self.active_height)
|
height=self.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 = drc["implant_enclose_active"]
|
enclose_width = drc["implant_enclosure_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,
|
||||||
|
|
@ -325,7 +325,9 @@ class ptx(design.design):
|
||||||
for pos in source_positions:
|
for pos in source_positions:
|
||||||
contact=self.add_contact_center(layers=("active", "contact", "metal1"),
|
contact=self.add_contact_center(layers=("active", "contact", "metal1"),
|
||||||
offset=pos,
|
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",
|
self.add_layout_pin_center_rect(text="S",
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
offset=pos,
|
offset=pos,
|
||||||
|
|
@ -336,7 +338,9 @@ class ptx(design.design):
|
||||||
for pos in drain_positions:
|
for pos in drain_positions:
|
||||||
contact=self.add_contact_center(layers=("active", "contact", "metal1"),
|
contact=self.add_contact_center(layers=("active", "contact", "metal1"),
|
||||||
offset=pos,
|
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",
|
self.add_layout_pin_center_rect(text="D",
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
offset=pos,
|
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["thkox"] = 8
|
||||||
layer["poly"] = 9
|
layer["poly"] = 9
|
||||||
layer["contact"] = 10
|
layer["contact"] = 10
|
||||||
|
layer["active_contact"] = 10
|
||||||
layer["metal1"] = 11
|
layer["metal1"] = 11
|
||||||
layer["via1"] = 12
|
layer["via1"] = 12
|
||||||
layer["metal2"] = 13
|
layer["metal2"] = 13
|
||||||
|
|
@ -120,9 +121,9 @@ drc["minarea_active"] = 0
|
||||||
# IMPLANT.1 Minimum spacing of nimplant/ pimplant to channel
|
# IMPLANT.1 Minimum spacing of nimplant/ pimplant to channel
|
||||||
drc["implant_to_channel"] = 0.07
|
drc["implant_to_channel"] = 0.07
|
||||||
# Not a rule
|
# Not a rule
|
||||||
drc["implant_enclose_active"] = 0
|
drc["implant_enclosure_active"] = 0
|
||||||
# Not a rule
|
# Not a rule
|
||||||
drc["implant_enclose_contact"] = 0
|
drc["implant_enclosure_contact"] = 0
|
||||||
# IMPLANT.2 Minimum spacing of nimplant/ pimplant to contact
|
# IMPLANT.2 Minimum spacing of nimplant/ pimplant to contact
|
||||||
drc["implant_to_contact"] = 0.025
|
drc["implant_to_contact"] = 0.025
|
||||||
# IMPLANT.3 Minimum width/ spacing of nimplant/ pimplant
|
# IMPLANT.3 Minimum width/ spacing of nimplant/ pimplant
|
||||||
|
|
|
||||||
|
|
@ -26,14 +26,13 @@ GDS["zoom"] = 0.5
|
||||||
layer={}
|
layer={}
|
||||||
layer["vtg"] = -1
|
layer["vtg"] = -1
|
||||||
layer["vth"] = -1
|
layer["vth"] = -1
|
||||||
layer["contact"] = 25
|
layer["contact"] = 47
|
||||||
layer["pwell"] = 41
|
layer["pwell"] = 41
|
||||||
layer["nwell"] = 42
|
layer["nwell"] = 42
|
||||||
layer["active"] = 43
|
layer["active"] = 43
|
||||||
layer["pimplant"] = 44
|
layer["pimplant"] = 44
|
||||||
layer["nimplant"] = 45
|
layer["nimplant"] = 45
|
||||||
layer["poly"] = 46
|
layer["poly"] = 46
|
||||||
layer["poly_contact"] = 47
|
|
||||||
layer["active_contact"] = 48
|
layer["active_contact"] = 48
|
||||||
layer["metal1"] = 49
|
layer["metal1"] = 49
|
||||||
layer["via1"] = 50
|
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
|
# 4.1 Minimum select spacing to channel of transistor to ensure adequate source/drain width
|
||||||
drc["implant_to_channel"] = 0.9
|
drc["implant_to_channel"] = 0.9
|
||||||
# 4.2 Minimum select overlap of active
|
# 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
|
# 4.3 Minimum select overlap of contact
|
||||||
drc["implant_enclose_contact"] = 0.3
|
drc["implant_enclosure_contact"] = 0.3
|
||||||
# Not a rule
|
# Not a rule
|
||||||
drc["implant_to_contact"] = 0
|
drc["implant_to_contact"] = 0
|
||||||
# Not a rule
|
# Not a rule
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue