Initial version of donated sources by Avertec, 3.4p5.
[tas-yagle.git] / distrib / sources / avtcmi / mcc_mod_cmi.c
1 /*
2 * mcc_mod_cmi.c
3 * avertec_distrib
4 *
5 * Created by Anthony on 29/04/2008.
6 * Copyright 2008 Avertec SA. All rights reserved.
7 *
8 */
9
10 #include "mcc_mod_cmi_interface.h"
11 #include "mcc_mod_cmi.h"
12
13 static int CMI_DEBUG;
14
15 static mcc_modext AVTCMI = {
16 mcc_initparam_cmi,
17 mcc_clean_cmi,
18 mcc_calcQint_cmi,
19 mcc_calcCGP_cmi,
20 mcc_calcCGD_cmi,
21 mcc_calcCGSI_cmi,
22 mcc_calcVTH_cmi,
23 mcc_calcIDS_cmi,
24 mcc_calcDWCJ_cmi,
25 mcc_calcCDS_cmi,
26 mcc_calcCDP_cmi,
27 mcc_calcCDW_cmi,
28 mcc_calcPA_cmi
29 };
30
31 /* exported */
32 mcc_modext *pAVTCMI = &AVTCMI;
33
34 int
35 mcc_initparam_cmi(mcc_modellist *ptmodel)
36 {
37 static int f=0;
38
39 if (!f) {
40 if (!cmi_initlibrary(ptmodel)) exit(1);
41 if (getenv("CMI_DEBUG") != NULL) CMI_DEBUG = 1;
42 else CMI_DEBUG = 0;
43 f = 1;
44 }
45 cmi_reset_alter_models();
46 return 1;
47 }
48
49 void
50 mcc_clean_cmi(mcc_modellist *ptmodel)
51 {
52 cmi_cleaninstance(ptmodel);
53 cmi_clean_alter_models();
54 cmi_reset_alter_models();
55 }
56
57 void
58 mcc_calcQint_cmi(mcc_modellist *ptmodel,
59 double L,
60 double W,
61 double temp,
62 double vgs,
63 double vbs,
64 double vds,
65 double *ptQg,
66 double *ptQs,
67 double *ptQd,
68 double *ptQb,
69 elp_lotrs_param *lotrsparam)
70 {
71 CMI_VAR slot;
72 alter_param changes[5];
73 double s;
74 int i=0;
75
76
77 if (cmi_set_alter_model(CMI_QINT_MODEL) != 0) {
78 changes[i].name = "cgdo"; changes[i++].value = 0.0;
79 changes[i].name = "cgdl"; changes[i++].value = 0.0;
80 changes[i].name = "cgso"; changes[i++].value = 0.0;
81 changes[i].name = "cgdl"; changes[i++].value = 0.0;
82 changes[i].name = NULL;
83 cmi_initmodel(ptmodel, changes);
84 cmi_initinstance(ptmodel, CMI_QINT_MODEL, lotrsparam, L, W, -1, -1, -1, -1);
85 }
86
87 cmi_evalinstance(ptmodel, &slot, vgs, vds, vbs, 1);
88 s = W*L;
89 if (ptQg) *ptQg = slot.qg/s;
90 if (ptQs) *ptQs = slot.qs/s;
91 if (ptQd) *ptQd = slot.qd/s;
92 if (ptQb) *ptQb = slot.qb/s;
93 if (CMI_DEBUG) printf("[CMI] mcc_calcQint_cmi for \"%s\" (W=%g, L=%g) (Vgs=%g, Vds=%g, Vbs=%g): Qg=%g, Qs=%g, Qd=%g, Qb=%g\n", ptmodel->NAME, W, L, vgs, vds, vbs, ptQg?(*ptQg):-1, ptQs?(*ptQs):-1, ptQd?(*ptQd):-1, ptQb?(*ptQb):-1);
94 }
95
96 /* Perimeter contribution of gate capacitance */
97 double
98 mcc_calcCGP_cmi(mcc_modellist *ptmodel,
99 elp_lotrs_param *lotrsparam,
100 double vgx,
101 double L,
102 double W,
103 double temp,
104 double *ptQov)
105 {
106 double cgp, qgunitint, qgint, qgtot;
107 CMI_VAR slot;
108
109 if (cmi_set_alter_model(CMI_DEFAULT_MODEL) != 0) {
110 cmi_initmodel(ptmodel, NULL);
111 cmi_initinstance(ptmodel, CMI_DEFAULT_MODEL, lotrsparam, L, W, -1, -1, -1, -1);
112 }
113
114 cmi_evalinstance(ptmodel, &slot, vgx, 0, 0, 1);
115 cgp = slot.cgdo/W;
116 if (ptQov) {
117 qgtot = slot.qg;
118 mcc_calcQint_cmi(ptmodel, L, W, temp, vgx, 0, 0, &qgunitint, NULL, NULL, NULL, lotrsparam);
119 qgint = qgunitint*(W*L);
120 *ptQov = (qgtot-qgint)/(2*W);
121 }
122 if (CMI_DEBUG) printf("[CMI] mcc_calcCGP_cmi for \"%s\" (W=%g, L=%g) (Vgs=%g, Vds=%g, Vbs=%g): Cgp=%g, Qov=%g\n", ptmodel->NAME, W, L, vgx, vgx, vgx, cgp, ptQov?(*ptQov):-1);
123 return cgp;
124 }
125
126 /* Surface contribution of gate-drain capacitance */
127 double
128 mcc_calcCGD_cmi(mcc_modellist *ptmodel,
129 double L,
130 double W,
131 double temp,
132 double vgs0,
133 double vgs1,
134 double vbs,
135 double vds,
136 elp_lotrs_param *lotrsparam)
137 {
138 double qinit=0.0, qfinal=0.0, cgd=0.0;
139 CMI_VAR slot;
140
141 if (mcc_getparam_quick(ptmodel,__MCC_QUICK_XPART) < 0.0) return 0.0;
142
143 if (cmi_set_alter_model(CMI_DEFAULT_MODEL) != 0) {
144 cmi_initmodel(ptmodel, NULL);
145 cmi_initinstance(ptmodel, CMI_DEFAULT_MODEL, lotrsparam, L, W, -1, -1, -1, -1);
146 }
147
148 cmi_evalinstance(ptmodel, &slot, vgs0, vds, vbs, 1);
149 qinit = slot.qd;
150 cmi_evalinstance(ptmodel, &slot, vgs1, vds, vbs, 1);
151 qfinal = slot.qd;
152
153 cgd = fabs((qfinal-qinit)/(vgs1-vgs0))/(W*L);
154 if (CMI_DEBUG) printf("[CMI] mcc_calcCGD_cmi for \"%s\" (W=%g, L=%g) (Vgs=[%g:%g], Vds=%g, Vbs=%g): Cgd=%g, Qinit=%g, Qfinal=%g\n", ptmodel->NAME, W, L, vgs0, vgs1, vds, vbs, cgd, qinit, qfinal);
155 return cgd;
156 }
157
158
159 /* Surface contribution of gate-drain capacitance */
160 double
161 mcc_calcCGSI_cmi(mcc_modellist *ptmodel,
162 double L,
163 double W,
164 double temp,
165 double vgs,
166 double vbs,
167 double vds,
168 elp_lotrs_param *lotrsparam)
169 {
170 double qinit=0.0, qfinal=0.0, cgsi=0.0;
171 CMI_VAR slot;
172
173 if (cmi_set_alter_model(CMI_DEFAULT_MODEL) != 0) {
174 cmi_initmodel(ptmodel, NULL);
175 cmi_initinstance(ptmodel, CMI_DEFAULT_MODEL, lotrsparam, L, W, -1, -1, -1, -1);
176 }
177
178 cmi_evalinstance(ptmodel, &slot, 0.0, vds, vbs, 1);
179 qinit = slot.qd;
180 cmi_evalinstance(ptmodel, &slot, vgs, vds, vbs, 1);
181 qfinal = slot.qd;
182
183 cgsi = fabs((qfinal-qinit)/vgs)/(W*L);
184 if (CMI_DEBUG) printf("[CMI] mcc_calcCGSI_cmi for \"%s\" (W=%g, L=%g) (Vgs=[%g:%g], Vds=%g, Vbs=%g): Cgp=%g, Qinit=%g, Qfinal=%g\n", ptmodel->NAME, W, L, 0.0, vgs, vds, vbs, cgsi, qinit, qfinal);
185 return cgsi;
186 }
187
188 double
189 mcc_calcVTH_cmi(mcc_modellist *ptmodel,
190 double L,
191 double W,
192 double temp,
193 double vbs,
194 double vds,
195 elp_lotrs_param *lotrsparam)
196 {
197 double vth;
198 CMI_VAR slot;
199
200 if (cmi_set_alter_model(CMI_DEFAULT_MODEL) != 0) {
201 cmi_initmodel(ptmodel, NULL);
202 cmi_initinstance(ptmodel, CMI_DEFAULT_MODEL, lotrsparam, L, W, -1, -1, -1, -1);
203 }
204
205 cmi_evalinstance(ptmodel, &slot, vds, vds, vbs, 0);
206
207 vth = slot.von;
208 // if (ptmodel->TYPE == MCC_TRANS_P) vth = -vth ;
209 if (CMI_DEBUG) printf("[CMI] mcc_calcVTH_cmi for \"%s\" (W=%g, L=%g) (Vgs=%g, Vds=%g, Vbs=%g): Vth=%g\n", ptmodel->NAME, W, L, vds, vds, vbs, vth);
210 return vth;
211 }
212
213 double
214 mcc_calcIDS_cmi(mcc_modellist *ptmodel,
215 double vbs,
216 double vgs,
217 double vds,
218 double W,
219 double L,
220 double Temp,
221 elp_lotrs_param *lotrsparam)
222 {
223 CMI_VAR slot;
224
225 if (cmi_set_alter_model(CMI_DEFAULT_MODEL) != 0) {
226 cmi_initmodel(ptmodel, NULL);
227 cmi_initinstance(ptmodel, CMI_DEFAULT_MODEL, lotrsparam, L, W, -1, -1, -1, -1);
228 }
229
230 cmi_evalinstance(ptmodel, &slot, vgs, vds, vbs, 0);
231 if (CMI_DEBUG) printf("[CMI] mcc_calcIDS_cmi for \"%s\" (W=%g, L=%g) (Vgs=%g, Vds=%g, Vbs=%g): Ids=%g\n", ptmodel->NAME, W, L, vgs, vds, vbs, slot.ids);
232 return slot.ids;
233 }
234
235 /* Offset for effective drain channel junction width */
236 double mcc_calcDWCJ_cmi( mcc_modellist *ptmodel,
237 elp_lotrs_param *lotrsparam,
238 double temp,
239 double L,
240 double W
241 )
242 {
243 /* OK for Hynix model but we need a general solution */
244 return 0.0;
245 }
246
247 /* Area contribution of channel junction capacitance for drain */
248 double
249 mcc_calcCDS_cmi(mcc_modellist *ptmodel,
250 elp_lotrs_param *lotrsparam,
251 double temp,
252 double vbx0,
253 double vbx1,
254 double L,
255 double W)
256 {
257 CMI_VAR slot;
258 alter_param changes[3];
259 double qinit=0.0, qfinal=0.0, cds=0.0;
260 int i=0;
261
262 if (cmi_set_alter_model(CMI_CDS_MODEL) != 0) {
263 changes[i].name = "cjswd"; changes[i++].value = 0.0;
264 changes[i].name = "cjswgd"; changes[i++].value = 0.0;
265 changes[i].name = NULL;
266 cmi_initmodel(ptmodel, changes);
267 cmi_initinstance(ptmodel, CMI_CDS_MODEL, lotrsparam, L, W, W*W, 0, W*W, 0);
268 }
269
270 cmi_evalinstance(ptmodel, &slot, 0.0, vbx0, 0.0, 1);
271 qinit = slot.qbd;
272 cmi_evalinstance(ptmodel, &slot, 0.0, vbx1, 0.0, 1);
273 qfinal = slot.qbd;
274 cmi_set_alter_model(CMI_DEFAULT_MODEL);
275
276 cds = fabs((qfinal-qinit)/(vbx1-vbx0))/(W*W);
277 if (CMI_DEBUG) printf("[CMI] mcc_calcCDS_cmi for \"%s\" (W=%g, L=%g) (Vgs=%g, Vds=[%g:%g], Vbs=%g): Cgp=%g, Qinit=%g, Qfinal=%g\n", ptmodel->NAME, W, L, 0.0, vbx0, vbx1, 0.0, cds, qinit, qfinal);
278 return cds;
279 }
280
281 /* Sidewall contribution of channel junction capacitance for drain */
282 double
283 mcc_calcCDP_cmi(mcc_modellist *ptmodel,
284 elp_lotrs_param *lotrsparam,
285 double temp,
286 double vbx0,
287 double vbx1,
288 double L,
289 double W)
290 {
291 CMI_VAR slot;
292 alter_param changes[3];
293 double qinit=0.0, qfinal=0.0, cdp=0.0;
294 int i=0;
295
296 if (cmi_set_alter_model(CMI_CDP_MODEL) != 0) {
297 changes[i].name = "cjd"; changes[i++].value = 0.0;
298 changes[i].name = "cjswgd"; changes[i++].value = 0.0;
299 changes[i].name = NULL;
300 cmi_initmodel(ptmodel, changes);
301 cmi_initinstance(ptmodel, CMI_CDP_MODEL, lotrsparam, L, W, 0, W, 0, W);
302 }
303
304 cmi_evalinstance(ptmodel, &slot, 0.0, vbx0, 0.0, 1);
305 qinit = slot.qbd;
306 cmi_evalinstance(ptmodel, &slot, 0.0, vbx1, 0.0, 1);
307 qfinal = slot.qbd;
308 cmi_set_alter_model(CMI_DEFAULT_MODEL);
309
310 cdp = fabs((qfinal-qinit)/(vbx1-vbx0))/W;
311 if (CMI_DEBUG) printf("[CMI] mcc_calcCDP_cmi for \"%s\" (W=%g, L=%g) (Vgs=%g, Vds=[%g:%g], Vbs=%g): Cdp=%g, Qinit=%g, Qfinal=%g\n", ptmodel->NAME, W, L, 0.0, vbx0, vbx1, 0.0, cdp, qinit, qfinal);
312 return cdp;
313 }
314
315 /* Gate sidewall contribution of channel junction capacitance for drain */
316 double
317 mcc_calcCDW_cmi(mcc_modellist *ptmodel,
318 elp_lotrs_param *lotrsparam,
319 double temp,
320 double vbx0,
321 double vbx1,
322 double L,
323 double W)
324 {
325 CMI_VAR slot;
326 alter_param changes[3];
327 double qinit=0.0, qfinal=0.0, cdw=0.0;
328 int i=0;
329
330 if (cmi_set_alter_model(CMI_CDW_MODEL) != 0) {
331 changes[i].name = "cjd"; changes[i++].value = 0.0;
332 changes[i].name = "cjswd"; changes[i++].value = 0.0;
333 changes[i].name = NULL;
334 cmi_initmodel(ptmodel, changes);
335 cmi_initinstance(ptmodel, CMI_CDW_MODEL, lotrsparam, L, W, 0, 0, 0, 0);
336 }
337
338 cmi_evalinstance(ptmodel, &slot, 0.0, vbx0, 0.0, 1);
339 qinit = slot.qbd;
340 cmi_evalinstance(ptmodel, &slot, 0.0, vbx1, 0.0, 1);
341 qfinal = slot.qbd;
342 cmi_set_alter_model(CMI_DEFAULT_MODEL);
343
344 cdw = fabs((qfinal-qinit)/(vbx1-vbx0))/W;
345 if (CMI_DEBUG) printf("[CMI] mcc_calcCDW_cmi for \"%s\" (W=%g, L=%g) (Vgs=%g, Vds=[%g:%g], Vbs=%g): Cdw=%g, Qinit=%g, Qfinal=%g\n", ptmodel->NAME, W, L, 0.0, vbx0, vbx1, 0.0, cdw, qinit, qfinal);
346 return cdw;
347 }
348
349 /* Calculate effective Perimeter & Area if undefined */
350 void
351 mcc_calcPA_cmi(lotrs_list *ptlotrs,
352 mcc_modellist *ptmodel,
353 elp_lotrs_param *lotrsparam,
354 double *as,
355 double *ad,
356 double *ps,
357 double *pd)
358 {
359 mcc_calcPAfromgeomod_bsim4(ptlotrs, ptmodel, lotrsparam, as, ad, ps, pd);
360 }