This commit is contained in:
Matthew Guthaus 2019-12-23 21:16:08 +00:00
parent 4ad920eaf7
commit bec12f5b94
2 changed files with 395 additions and 329 deletions

File diff suppressed because it is too large Load Diff

View File

@ -62,7 +62,7 @@ class ptx(design.design):
#ur = self.find_highest_coords()
#self.add_boundary(ll, ur)
# (0,0) will be the corner ofthe active area (not the larger well)
# (0,0) will be the corner of the active area (not the larger well)
self.translate_all(self.active_offset)
def create_layout(self):
@ -108,8 +108,8 @@ class ptx(design.design):
Pre-compute some handy layout parameters.
"""
if self.num_contacts==None:
self.num_contacts=self.calculate_num_contacts()
if not self.num_contacts:
self.num_contacts = self.calculate_num_contacts()
# Determine layer types needed
if self.tx_type == "nmos":
@ -119,8 +119,7 @@ class ptx(design.design):
self.implant_type = "p"
self.well_type = "n"
else:
self.error("Invalid transitor type.",-1)
self.error("Invalid transitor type.", -1)
# This is not actually instantiated but used for calculations
self.active_contact = factory.create(module_type="contact",
@ -128,28 +127,30 @@ class ptx(design.design):
directions = ("V", "V"),
dimensions=(1, self.num_contacts))
# The contacted poly pitch (or uncontacted in an odd technology)
self.poly_pitch = max(2 * self.contact_to_gate + self.contact_width + self.poly_width,
self.poly_space)
# The contacted poly pitch (or uncontacted in an odd technology)
self.contact_pitch = 2 * self.contact_to_gate + self.contact_width + self.poly_width
self.contact_pitch = 2 * self.contact_to_gate + \
self.contact_width + self.poly_width
# The enclosure of an active contact. Not sure about second term.
active_enclose_contact = max(self.active_enclose_contact,
(self.active_width - self.contact_width) / 2)
# This is the distance from the edge of poly to the contacted end of active
self.end_to_poly = active_enclose_contact + self.contact_width + self.contact_to_gate
# This is the distance from the edge of
# poly to the contacted end of active
self.end_to_poly = active_enclose_contact + \
self.contact_width + self.contact_to_gate
# Active width is determined by enclosure on both ends and contacted pitch,
# at least one poly and n-1 poly pitches
self.active_width = 2 * self.end_to_poly + self.poly_width + (self.mults - 1) * self.poly_pitch
self.ptx_active_width = 2 * self.end_to_poly + self.poly_width + \
(self.mults - 1) * self.poly_pitch
# Active height is just the transistor width
self.active_height = self.tx_width
self.ptx_active_height = self.tx_width
# Poly height must include poly extension over active
self.poly_height = self.tx_width + 2 * self.poly_extend_active
@ -177,11 +178,11 @@ class ptx(design.design):
# This is the center of the first active contact offset (centered vertically)
self.contact_offset = self.active_offset + vector(active_enclose_contact + 0.5 * self.contact_width,
0.5 * self.active_height)
0.5 * self.ptx_active_height)
# Min area results are just flagged for now.
debug.check(self.active_width * self.active_height >= self.minarea_active,
debug.check(self.ptx_active_width * self.ptx_active_height >= self.minarea_active,
"Minimum active area violated.")
# We do not want to increase the poly dimensions to fix
# an area problem as it would cause an LVS issue.
@ -215,14 +216,14 @@ class ptx(design.design):
poly_offset = poly_positions[0] + vector(-0.5 * self.poly_width,
distance_above_active)
# Remove the old pin and add the new one
self.remove_layout_pin("G") # only keep the main pin
# only keep the main pin
self.remove_layout_pin("G")
self.add_layout_pin(text="G",
layer="poly",
offset=poly_offset,
width=poly_width,
height=self.poly_width)
def connect_fingered_active(self, drain_positions, source_positions):
"""
Connect each contact up/down to a source or drain pin
@ -230,10 +231,10 @@ class ptx(design.design):
# This is the distance that we must route up or down from the center
# of the contacts to avoid DRC violations to the other contacts
pin_offset = vector(0, 0.5 * self.active_contact.second_layer_height \
pin_offset = vector(0, 0.5 * self.active_contact.second_layer_height
+ self.m1_space + 0.5 * self.m1_width)
# This is the width of a m1 extend the ends of the pin
end_offset = vector(self.m1_width/2,0)
end_offset = vector(self.m1_width / 2.0, 0)
# drains always go to the MIDDLE of the cell,
# so top of NMOS, bottom of PMOS
@ -246,8 +247,9 @@ class ptx(design.design):
source_dir = -1
if len(source_positions) > 1:
source_offset = pin_offset.scale(source_dir,source_dir)
self.remove_layout_pin("S") # remove the individual connections
source_offset = pin_offset.scale(source_dir, source_dir)
# remove the individual connections
self.remove_layout_pin("S")
# Add each vertical segment
for a in source_positions:
self.add_path(("m1"),
@ -310,16 +312,16 @@ class ptx(design.design):
"""
self.add_rect(layer="active",
offset=self.active_offset,
width=self.active_width,
height=self.active_height)
width=self.ptx_active_width,
height=self.ptx_active_height)
# If the implant must enclose the active, shift offset
# and increase width/height
enclose_width = self.implant_enclose_active
enclose_offset = [enclose_width] * 2
self.add_rect(layer="{}implant".format(self.implant_type),
offset=self.active_offset - enclose_offset,
width=self.active_width + 2 * enclose_width,
height=self.active_height + 2 * enclose_width)
width=self.ptx_active_width + 2 * enclose_width,
height=self.ptx_active_height + 2 * enclose_width)
def add_well_implant(self):
"""