Skip to content

Commit 7805332

Browse files
feat(rfcmim Pycell): initial version (#305, #324)
Signed-off-by: Sergei Andreev <[email protected]>
1 parent 087fd5c commit 7805332

File tree

2 files changed

+227
-1
lines changed

2 files changed

+227
-1
lines changed

ihp-sg13g2/libs.tech/klayout/python/sg13g2_pycell_lib/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@
6060
'dpantenna_code',
6161
'via_stack_code',
6262
'ptap1_code',
63-
'bondpad_code'
63+
'bondpad_code',
64+
'rfcmim_code'
6465
]
6566

6667
def getProcessNames():
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
########################################################################
2+
#
3+
# Copyright 2025 IHP PDK Authors
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# https://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
########################################################################
18+
19+
__version__ = '$Revision: #3 $'
20+
21+
from cni.dlo import *
22+
from .geometry import *
23+
from .utility_functions import *
24+
25+
import math
26+
27+
class rfcmim(DloGen):
28+
29+
@classmethod
30+
def defineParamSpecs(self, specs):
31+
techparams = specs.tech.getTechParams()
32+
33+
model = techparams['rfcmim_model']
34+
minLW = techparams['rfcmim_minLW']
35+
maxLW = techparams['rfcmim_maxLW']
36+
defLW = techparams['rfcmim_defLW']
37+
caspec = techparams['rfcmim_caspec']
38+
cmax = eng_string(CbCapCalc('C', 0, Numeric(maxLW), Numeric(maxLW), 'rfcmim'))
39+
40+
C = CbCapCalc('C', 0, Numeric(defLW), Numeric(defLW), 'rfcmim')
41+
42+
#ifdef KLAYOUT
43+
specs('Calculate', 'C', 'Calculate', ChoiceConstraint(['C', 'w', 'l', 'w&l']))
44+
specs('model', model, 'Model name')
45+
46+
specs('C', eng_string(C), 'C')
47+
48+
specs('w', defLW, 'Width')
49+
specs('l', defLW, 'Length')
50+
51+
specs('wfeed', '3u', 'Feed width')
52+
specs('Cspec', caspec, 'Cspec [F/sqm]')
53+
specs('Wmin', minLW, 'Wmin')
54+
specs('Lmin', minLW, 'Lmin')
55+
specs('Cmax', cmax, 'Cmax')
56+
#else
57+
CDFVersion = techparams['CDFVersion']
58+
specs('cdf_version', CDFVersion, 'CDF Version')
59+
specs('Display', 'Selected', 'Display', ChoiceConstraint(['All', 'Selected']))
60+
specs('Calculate', 'C', 'Calculate', ChoiceConstraint(['C', 'w', 'l', 'w&l']))
61+
specs('model', model, 'Model name')
62+
63+
specs('C', eng_string(C), 'C')
64+
65+
specs('l', defLW, 'Length')
66+
specs('w', defLW, 'Width')
67+
68+
specs('wfeed', '3u', 'Feed width')
69+
specs('Cspec', caspec, 'Cspec [F/sqm]')
70+
specs('Wmin', minLW, 'Wmin')
71+
specs('Lmin', minLW, 'Lmin')
72+
specs('Cmax', cmax, 'Cmax')
73+
74+
specs('ic', '', 'Initial condition')
75+
specs('m', '1', 'Multiplier')
76+
specs('trise', '', 'Temp rise from ambient')
77+
#endif
78+
79+
def setupParams(self, params):
80+
# process parameter values entered by user
81+
self.params = params
82+
self.w = Numeric(self.params['w'])
83+
self.l = Numeric(self.params['l'])
84+
self.wfeed = Numeric(self.params['wfeed'])
85+
self.C = eng_string(CbCapCalc('C', 0, self.l, self.w, 'rfcmim'))
86+
87+
def genLayout(self):
88+
self.grid = self.tech.getGridResolution()
89+
self.techparams = self.tech.getTechParams()
90+
self.epsilon = self.techparams['epsilon1']
91+
92+
w = self.w
93+
l = self.l
94+
wfeed = self.wfeed
95+
96+
lu = GridFix(l*1e6)
97+
wu = GridFix(w*1e6)
98+
wf = GridFix(wfeed*1e6)
99+
100+
#########################################################
101+
#
102+
# Layer Definitions
103+
#
104+
#########################################################
105+
106+
textlayer = Layer('TEXT', 'drawing') # TEXT
107+
gndlayer = Layer('Metal1') # Metal1 used for ground ring
108+
tmlayer = Layer('TopMetal1') # Top Metal above MIM is TopMetal1
109+
bmlayer = Layer('Metal5') # Bottom metal below MIM is Metal5
110+
caplayer = Layer('MIM')
111+
vialayer = Layer('Vmim')
112+
pwellblock = Layer('PWell', 'block')
113+
cont = Layer('Cont')
114+
activ = Layer('Activ')
115+
psd = Layer('pSD')
116+
117+
nolayer = 0
118+
119+
#########################################################
120+
#
121+
# Generic Design Rule Definitions
122+
#
123+
#########################################################
124+
125+
via_size = self.techparams['TV1_a']
126+
via_dist = self.techparams['TV1_b']
127+
cont_size = self.techparams['Cnt_a']
128+
cont_dist = self.techparams['Cnt_b']
129+
tm_over = self.techparams['TV1_d']
130+
131+
#########################################################
132+
#
133+
# Device Specific Design Rule Definitions
134+
#
135+
#########################################################
136+
137+
mim_over = self.techparams['Mim_c']
138+
via_over = self.techparams['Mim_d']
139+
140+
#########################################################
141+
#
142+
# Main body of code
143+
#
144+
#########################################################
145+
146+
#########################################################
147+
# Special dimensions for rfcmim
148+
#########################################################
149+
gnd_width = 2 # um, ground frame width
150+
gnd_over_bm = 3+gnd_width/2 # um, distance from ground frame to bottom plate
151+
feedox = GridFix((lu-wf)/2)
152+
feedoy = GridFix((wu-wf)/2)
153+
154+
contactArray(self, nolayer, vialayer, 0, 0, lu, wu, via_over+tm_over, via_over+tm_over, via_size, via_dist)
155+
dbCreateRect(self, caplayer, Box(0, 0, lu, wu))
156+
dbCreateRect(self, tmlayer, Box(via_over, via_over, lu-via_over, wu-via_over))
157+
dbCreateRect(self, bmlayer, Box(-mim_over, -mim_over, lu+mim_over, wu+mim_over))
158+
dbCreateRect(self, bmlayer, Box(-mim_over, -mim_over, lu+mim_over, wu+mim_over))
159+
dbCreateRect(self, pwellblock, Box(-3, -3, lu+3, wu+3))
160+
dbCreateRect(self, tmlayer, Box(-5.6, feedoy, via_over, feedoy+wf))
161+
id1 = dbCreateRect(self, Layer('TopMetal1', 'pin'), Box(-5.6, feedoy, -3.6, feedoy+wf))
162+
MkPin(self, 'PLUS', 0, id1.bbox, id1.layer)
163+
dbCreateLabel(self, textlayer, Point(-4.6, feedoy+wf/2), 'PLUS', 'centerCenter', 'R90', Font.EURO_STYLE, 0.8)
164+
165+
# no QRC up to Metal3 in entire device area
166+
dbCreateRect(self, Layer('Activ', 'noqrc'), Box(-5.6, -5.6, lu+5.6, wu+5.6))
167+
dbCreateRect(self, Layer('Metal1', 'noqrc'), Box(-5.6, -5.6, lu+5.6, wu+5.6))
168+
dbCreateRect(self, Layer('Metal2', 'noqrc'), Box(-5.6, -5.6, lu+5.6, wu+5.6))
169+
dbCreateRect(self, Layer('Metal3', 'noqrc'), Box(-5.6, -5.6, lu+5.6, wu+5.6))
170+
171+
dbCreateRect(self, Layer('Metal4', 'noqrc'), Box(-5.6, -5.6, lu+5.6, wu+5.6))
172+
dbCreateRect(self, Layer('Metal5', 'noqrc'), Box(-5.6, -5.6, lu+5.6, wu+5.6))
173+
dbCreateRect(self, Layer('TopMetal1', 'noqrc'), Box(-5.6, -5.6, lu+5.6, wu+5.6))
174+
175+
# the ring
176+
id1 = dbCreateRect(self, activ, Box(-3.6, -3.6, lu+3.6, wu+3.6))
177+
id2 = dbCreateRect(self, activ, Box(-5.6, -5.6, lu+5.6, wu+5.6))
178+
idlist = dbLayerXor(activ, id1, id2)
179+
dbDeleteObject(id1)
180+
dbDeleteObject(id2)
181+
182+
id1 = idlist.getComp(0)
183+
184+
dbCreateRect(self, bmlayer, Box(lu+5.6, feedoy, lu+0.6, feedoy+wf))
185+
id2 = dbCreateRect(self, Layer('Metal5', 'pin'), Box(lu+5.6, feedoy, lu+3.6, feedoy+wf))
186+
187+
idlist = dbLayerXor(activ, id1, id2)
188+
dbDeleteObject(id1)
189+
MkPin(self, 'MINUS', 0, id2.bbox, id2.layer)
190+
x = (nth(0, id2.bbox) + nth(2, id2.bbox)) / 2
191+
y = (nth(1, id2.bbox) + nth(3, id2.bbox)) / 2
192+
193+
dbCreateLabel(self, textlayer, Point(x, y), 'MINUS', 'centerCenter', 'R90', Font.EURO_STYLE, 0.8)
194+
195+
# pSD ring
196+
ps_cutarea = dbCreateRect(self, psd, Box(-3.57, -3.57, lu+3.57, wu+3.57))
197+
ps_guardarea = dbCreateRect(self, psd, Box(-5.63, -5.63, lu+5.63, wu+5.63))
198+
psd_guardring = dbLayerXor(psd, ps_cutarea, ps_guardarea)
199+
dbDeleteObject(ps_cutarea)
200+
dbDeleteObject(ps_guardarea)
201+
202+
# Metal1 ring
203+
id1 = dbCreateRect(self, gndlayer, Box(-3.6, -3.6, lu+3.6, wu+3.6))
204+
id3 = dbCreateRect(self, gndlayer, Box(-5.6, -5.6, lu+5.6, wu+5.6))
205+
id4 = dbLayerXor(gndlayer, id1, id3)
206+
dbLayerXor(gndlayer, id4, id2)
207+
dbDeleteObject(id1)
208+
dbDeleteObject(id3)
209+
dbDeleteObject(id4)
210+
211+
# ring contacts
212+
contactArray(self, nolayer, cont, lu+3.6, -3.6, lu+5.6, feedoy, 0.36, 0.36, cont_size, cont_dist)
213+
contactArray(self, nolayer, cont, lu+3.6, feedoy+wf, lu+5.6, wu+3.6, 0.36, 0.36, cont_size, cont_dist)
214+
215+
contactArray(self, nolayer, cont, -5.6, -3.6, -3.6, wu+3.6, 0.36, 0.36, cont_size, cont_dist)
216+
contactArray(self, nolayer, cont, -5.6, wu+3.6, lu+5.6, wu+5.6, 0.36, 0.36, cont_size, cont_dist)
217+
contactArray(self, nolayer, cont, -5.6, -5.6, lu+5.6, -3.6, 0.36, 0.36, cont_size, cont_dist)
218+
219+
id1 = dbCreateRect(self, Layer('Metal1', 'pin'), Box(-5.6, -5.6, lu+5.6, -3.6))
220+
y = -4.6
221+
222+
MkPin(self, 'TIE', 0, id1.bbox, id1.layer)
223+
dbCreateLabel(self, textlayer, Point(lu/2, y), 'TIE', 'centerCenter', 'R0', Font.EURO_STYLE, 1)
224+
dbCreateLabel(self, textlayer, Point(lu/2, wu+2), 'rfcmim', 'centerCenter', 'R0', Font.EURO_STYLE, 0.8)
225+
dbCreateLabel(self, textlayer, Point(lu/2, -2), 'C='+self.C, 'centerCenter', 'R0', Font.EURO_STYLE, 0.8)

0 commit comments

Comments
 (0)