Skip to content
Snippets Groups Projects
Commit 4b137bdd authored by David Lanzendörfer's avatar David Lanzendörfer
Browse files

Adding FET to LibrePDK

parent b495e249
No related branches found
No related tags found
No related merge requests found
fet.py 0 → 100644
import gdsfactory as gf
from librepdk.structure import LibrePDKStructure
from librepdk.contact import ViaStripe
from librepdk.types import ChannelType
class FET(LibrePDKStructure):
gate_tap = None
source_tap = None
drain_tap = None
bulk_tap = None
def __init__(self, config, name, mtype, dims, contact_to=None, have_bulk_tap=False):
LibrePDKStructure.__init__(self, config, name)
self.have_bulk_tap = have_bulk_tap # enable tap for bulk
self.W = dims[0]
self.L = dims[1]
self.conlayer_name = config.get_pad_connection_layer() if contact_to is None else contact_to # Alternative contact layer
# select well and implant
if mtype == ChannelType.PMOS:
self.well_layer_name = "nwell"
self.implant_layer_name = 'pdiffusion'
self.diff_contact_name = "pdiff_contact"
elif mtype == ChannelType.NMOS:
self.well_layer_name = "pwell"
self.implant_layer_name = 'ndiffusion'
self.diff_contact_name = "ndiff_contact"
else:
raise Exception("It has to be either NMOS or PMOS! This should NEVER happen!")
self.implant_layer = config.get_layer_id(self.implant_layer_name)
self.well_layer = config.get_layer_id(self.well_layer_name)
self.pdiff_contact_layer = config.get_layer_id(self.diff_contact_name)
via_size = self.config.get_via_size(self.diff_contact_name)
# those are LCLayout standard:
self.gate_layer = config.get_layer_id("poly")
self.poly_contact_layer = config.get_layer_id("poly_contact")
# name "poly" is an lclayout standard
w = config.get_min_width("poly")
self.polyw = config.get_lambda() if w is None else w
#self.generate_mos(mtype, dims)
self.actual_transistor()
'''
Build transistor structure and place the taps
c1: drain tap
c2: gate tap
c3: source
c4: drain
w/l: width and length of the channel
'''
def update_taps(self, coordinates):
self.gate_tap = self.gate_tap if self.gate_tap is None else self.gate_tap.move(coordinates)
self.source_tap = self.source_tap if self.source_tap is None else self.source_tap.move(coordinates)
self.drain_tap = self.drain_tap if self.drain_tap is None else self.drain_tap.move(coordinates)
self.bulk_tap = self.bulk_tap if self.bulk_tap is None else self.bulk_tap.move(coordinates)
def move(self, coordinates):
LibrePDKStructure.move(self, coordinates)
for ref in self.references:
ref.move(coordinates)
self.update_taps(coordinates)
return self
def actual_transistor(self):
# spacing of the metal interconnect layer
sp = self.config.get_min_spacing((self.conlayer_name, self.conlayer_name))
w = self.polyw*self.W
l = self.polyw*self.L
# minimum enclosure
me = self.config.get_min_enclosure((self.well_layer_name, self.implant_layer_name))
if me is None:
me = self.config.get_lambda()
# adding taps
via_name = self.name+"_TAP"
ws = self.config.get_min_width(self.conlayer_name)
self.drain_tap = ViaStripe(self.config, via_name+"_drain", self.implant_layer_name, l, ws, self.conlayer_name, less_vias=True) # drain
self.gate_tap = ViaStripe(self.config, via_name+"_gate", "poly", ws, w, self.conlayer_name, less_vias=True) # gate
self.source_tap = ViaStripe(self.config, via_name+"_source", self.implant_layer_name, l, ws, self.conlayer_name, less_vias=True) # source
# determine implant width/height
wi = self.to_nm(l)
hi = self.to_nm(w if sp < w else sp)
# determine gate width/height
wp = self.drain_tap.xsize+self.to_nm(sp)
hp = self.to_nm(w)
# place implant and taps
implant = gf.components.rectangle(size=(wi,hi), layer=self.implant_layer)
self.drain_tap = self.drain_tap.move([0,self.source_tap.ysize+hi])
# add them
self << self.source_tap
self << implant.move([0,self.source_tap.ysize])
self << self.drain_tap
if self.have_bulk_tap:
# add bulk contact
bw = (wp+self.gate_tap.xsize)*self.ureg.nm
self.bulk_tap = ViaStripe(self.config, via_name+"_bulk", self.well_layer_name, bw, ws, self.conlayer_name, less_vias=True) # bulk
by = -self.source_tap.ysize-self.to_nm(sp)
self.bulk_tap = self.bulk_tap.move([0,by])
self << self.bulk_tap
# place gate and tap
gy = self.drain_tap.ysize+(hi-hp)/2
gate = gf.components.rectangle(size=(wp,hp), layer=self.gate_layer)
self.gate_tap = self.gate_tap.move([gate.xsize,gy])
# add them
self << gate.move([0,gy])
self << self.gate_tap
# determine well width/height
ww = self.gate_tap.xsize+wp+self.to_nm(2*me)
hw = self.drain_tap.ysize+self.source_tap.ysize+hi+self.to_nm(2*me)
if self.have_bulk_tap:
hw += self.to_nm(sp)+self.bulk_tap.ysize
# Calculate the well width
well = gf.components.rectangle(size=(ww,hw), layer=self.well_layer)
yw = -self.to_nm(me)
if self.have_bulk_tap:
yw -= self.to_nm(sp)+self.bulk_tap.ysize
self << well.move([self.to_nm(-me),yw])
for ref in self.references:
ref.move([-self.xmin,-self.ymin])
self.update_taps([-self.xmin,-self.ymin])
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment