Cleanup and simplify ptx for multiple technologies

This commit is contained in:
mrg 2020-02-25 00:36:22 +00:00
parent 585a708e0c
commit 254e584e35
1 changed files with 84 additions and 69 deletions

View File

@ -10,6 +10,7 @@ import debug
from tech import layer, drc, spice from tech import layer, drc, spice
from vector import vector from vector import vector
from sram_factory import factory from sram_factory import factory
import contact
class ptx(design.design): class ptx(design.design):
@ -28,6 +29,7 @@ class ptx(design.design):
tx_type="nmos", tx_type="nmos",
connect_active=False, connect_active=False,
connect_poly=False, connect_poly=False,
series_devices=False,
num_contacts=None): num_contacts=None):
# We need to keep unique names because outputting to GDSII # We need to keep unique names because outputting to GDSII
# will use the last record with a given name. I.e., you will # will use the last record with a given name. I.e., you will
@ -50,6 +52,7 @@ class ptx(design.design):
self.tx_width = width self.tx_width = width
self.connect_active = connect_active self.connect_active = connect_active
self.connect_poly = connect_poly self.connect_poly = connect_poly
self.series_devices = series_devices
self.num_contacts = num_contacts self.num_contacts = num_contacts
# Since it has variable height, it is not a pgate. # Since it has variable height, it is not a pgate.
@ -127,27 +130,25 @@ class ptx(design.design):
directions=("V", "V"), directions=("V", "V"),
dimensions=(1, self.num_contacts)) dimensions=(1, self.num_contacts))
# The contacted poly pitch # This is the extra poly spacing due to the poly contact to poly contact pitch
self.poly_pitch = max(2 * self.contact_to_gate + self.contact_width + self.poly_width, # of contacted gates
self.poly_space) extra_poly_contact_width = contact.poly_contact.width - self.poly_width
# The contacted poly pitch # This is the spacing between S/D contacts
self.contact_spacing = 2 * self.contact_to_gate + \ # This is the spacing between the poly gates
self.contact_width + self.poly_width self.min_poly_pitch = self.poly_space + self.poly_width
self.contacted_poly_pitch = self.poly_space + contact.poly_contact.width
self.contact_pitch = 2 * self.contact_to_gate + self.poly_width + self.contact_width
self.poly_pitch = max(self.min_poly_pitch,
self.contacted_poly_pitch,
self.contact_pitch)
# This is measured because of asymmetric enclosure rules self.end_to_contact = 0.5 * self.active_contact.width
active_enclose_contact = 0.5*(self.active_contact.width - self.contact_width)
# This is the distance from the side of
# poly gate to the contacted end of active
# (i.e. the "outside" contacted diffusion sizes)
self.end_to_poly = self.active_contact.width - active_enclose_contact + \
self.contact_to_gate
# Active width is determined by enclosure on both ends and contacted pitch, # Active width is determined by enclosure on both ends and contacted pitch,
# at least one poly and n-1 poly pitches # at least one poly and n-1 poly pitches
self.active_width = 2 * self.end_to_poly + self.poly_width + \ self.active_width = 2 * self.end_to_contact + self.active_contact.width \
(self.mults - 1) * self.poly_pitch + 2 * self.contact_to_gate + self.poly_width + (self.mults - 1) * self.poly_pitch
# Active height is just the transistor width # Active height is just the transistor width
self.active_height = self.tx_width self.active_height = self.tx_width
@ -287,12 +288,11 @@ class ptx(design.design):
Add the poly gates(s) and (optionally) connect them. Add the poly gates(s) and (optionally) connect them.
""" """
# poly is one contacted spacing from the end and down an extension # poly is one contacted spacing from the end and down an extension
poly_offset = self.active_offset \ poly_offset = self.contact_offset \
+ vector(self.poly_width, self.poly_height).scale(0.5, 0.5) \ + vector(0.5 * self.active_contact.width + 0.5 * self.poly_width + self.contact_to_gate, 0)
+ vector(self.end_to_poly, -self.poly_extend_active)
# poly_positions are the bottom center of the poly gates # poly_positions are the bottom center of the poly gates
poly_positions = [] self.poly_positions = []
# It is important that these are from left to right, # It is important that these are from left to right,
# so that the pins are in the right # so that the pins are in the right
@ -309,11 +309,11 @@ class ptx(design.design):
offset=poly_offset, offset=poly_offset,
height=self.poly_height, height=self.poly_height,
width=self.poly_width) width=self.poly_width)
poly_positions.append(poly_offset) self.poly_positions.append(poly_offset)
poly_offset = poly_offset + vector(self.poly_pitch,0) poly_offset = poly_offset + vector(self.poly_pitch,0)
if self.connect_poly: if self.connect_poly:
self.connect_fingered_poly(poly_positions) self.connect_fingered_poly(self.poly_positions)
def add_active(self): def add_active(self):
""" """
@ -362,59 +362,74 @@ class ptx(design.design):
""" """
return 1 return 1
def get_contact_positions(self):
"""
Create a list of the centers of drain and source contact positions.
"""
# The first one will always be a source
source_positions = [self.contact_offset]
drain_positions = []
# It is important that these are from left to right,
# so that the pins are in the right
# order for the accessors.
for i in range(self.mults):
if i%2:
# It's a source... so offset from previous drain.
source_positions.append(drain_positions[-1] + vector(self.contact_spacing, 0))
else:
# It's a drain... so offset from previous source.
drain_positions.append(source_positions[-1] + vector(self.contact_spacing, 0))
return [source_positions,drain_positions]
def add_active_contacts(self): def add_active_contacts(self):
""" """
Add the active contacts to the transistor. Add the active contacts to the transistor.
""" """
drain_positions = []
source_positions = []
[source_positions,drain_positions] = self.get_contact_positions() # First one is always a SOURCE
label = "S"
for pos in source_positions: pos = self.contact_offset
contact=self.add_via_center(layers=self.active_stack, contact=self.add_via_center(layers=self.active_stack,
offset=pos,
size=(1, self.num_contacts),
directions=("V","V"),
implant_type=self.implant_type,
well_type=self.well_type)
self.add_layout_pin_rect_center(text=label,
layer="m1",
offset=pos, offset=pos,
size=(1, self.num_contacts), width=contact.mod.second_layer_width,
directions=("V","V"), height=contact.mod.second_layer_height)
implant_type=self.implant_type, source_positions.append(pos)
well_type=self.well_type)
self.add_layout_pin_rect_center(text="S", # Skip these if they are going to be in series
layer="m1", if not self.series_devices:
for (poly1, poly2) in zip(self.poly_positions, self.poly_positions[1:]):
pos = vector(0.5 * (poly1.x + poly2.x),
self.contact_offset.y)
# Alternate source and drains
if label == "S":
label = "D"
drain_positions.append(pos)
else:
label = "S"
source_positions.append(pos)
contact=self.add_via_center(layers=self.active_stack,
offset=pos, offset=pos,
width=contact.mod.second_layer_width, size=(1, self.num_contacts),
height=contact.mod.second_layer_height) directions=("V","V"),
implant_type=self.implant_type,
well_type=self.well_type)
self.add_layout_pin_rect_center(text=label,
layer="m1",
offset=pos,
width=contact.mod.second_layer_width,
height=contact.mod.second_layer_height)
pos = vector(self.active_offset.x + self.active_width - 0.5 * self.active_contact.width,
for pos in drain_positions: self.contact_offset.y)
contact=self.add_via_center(layers=self.active_stack, # Last one is the opposite of previous
if label == "S":
label = "D"
drain_positions.append(pos)
else:
label = "S"
source_positions.append(pos)
contact=self.add_via_center(layers=self.active_stack,
offset=pos,
size=(1, self.num_contacts),
directions=("V","V"),
implant_type=self.implant_type,
well_type=self.well_type)
self.add_layout_pin_rect_center(text=label,
layer="m1",
offset=pos, offset=pos,
size=(1, self.num_contacts), width=contact.mod.second_layer_width,
directions=("V","V"), height=contact.mod.second_layer_height)
implant_type=self.implant_type,
well_type=self.well_type)
self.add_layout_pin_rect_center(text="D",
layer="m1",
offset=pos,
width=contact.mod.second_layer_width,
height=contact.mod.second_layer_height)
if self.connect_active: if self.connect_active:
self.connect_fingered_active(drain_positions, source_positions) self.connect_fingered_active(drain_positions, source_positions)