Initial version of donated sources by Avertec, 3.4p5.
[tas-yagle.git] / distrib / sources / tas / stm / stm_modscm_dual_eval.c
1 /****************************************************************************/
2 /* */
3 /* Chaine de CAO & VLSI AVERTEC */
4 /* */
5 /* Produit : STM Version 1.00 */
6 /* Fichier : stm_modscm_eval.c */
7 /* */
8 /* (c) copyright 2000 AVERTEC */
9 /* Tous droits reserves */
10 /* */
11 /* Auteur(s) : Gilles Augustins */
12 /* */
13 /****************************************************************************/
14
15 /****************************************************************************/
16 /* includes */
17 /****************************************************************************/
18
19 #include "stm.h"
20
21 double TESTIM = -1.0 ;
22
23 /****************************************************************************/
24 /* functions */
25 /****************************************************************************/
26 float stm_modscm_dual_vf_input (dualparams *params)
27 {
28 double vddin = (double)params->DP[STM_VDDIN];
29 double vt = (double)params->DP[STM_VT];
30 return (float)(vddin + vt);
31 }
32
33 float stm_modscm_dual_vdd_input (dualparams *params)
34 {
35 return params->DP[STM_VDDMAX];
36 }
37
38 /*******************************************************************************/
39 /* sert au calcul de la prise en compte des maillons entre activelink et source*/
40 /*******************************************************************************/
41
42 void stm_modscm_dual_slopei(double k, double B, double U, double IMAX, double Fe, double rsat, double vdd, double threshold, double *imax, double *Fs)
43 {
44 double delta, tm, x;
45 delta = k * k * B * B * U * U + 4.0 * k * (1.0 + B * U);
46 x = (k * B * U + sqrt(delta)) / 2.0 / (1.0 + B * U);
47 tm = Fe * atanh(x);
48 *Fs = tm / k;
49 if( rsat > 0.0 )
50 *imax = IMAX-(vdd-threshold)/rsat;
51 else
52 *imax = IMAX ;
53 }
54
55 /****************************************************************************/
56
57 double stm_modscm_dual_voltage_rc( double t, double rbr, double cbr, double imax, double Fs )
58 {
59 double v;
60
61 if( t > 0.0 )
62 v = rbr * rbr * imax * cbr / Fs * ( 1.0 - exp( -t / (rbr * cbr)) - ( t > Fs ? ( 1.0 - exp(-( t - Fs) / (rbr * cbr))) : 0.0 ) );
63 else
64 v = 0.0 ;
65
66 return v ;
67 }
68
69 /****************************************************************************/
70
71 void stm_modscm_dual_modifslope(double vddin, double vt, double F, double vdd, double rbr, double cbr, double imax, double Fs, double *te, double *Fm)
72 {
73 double Ve;
74
75 cbr /= 1000.0;
76
77 // *te = F * atanh( ( vdd/2 - vt ) / vddin );
78 // Ve = vddin * tanh( *te / F) + vt + rbr * rbr * imax * cbr / Fs * ( 1.0 - exp(-(*te) / (rbr * cbr)) - (*te>Fs?(1.0 - exp(-(*te - Fs) / (rbr * cbr))):0.0));
79
80 /* Instant ou la tension d'entrée passe au millieu de son excursion : (vddin-vt)/2+vt */
81 *te = F * 0.549 ;
82 Ve = vddin * tanh( *te / F) + vt + stm_modscm_dual_voltage_rc( *te, rbr, cbr, imax, Fs );
83 *Fm = *te / atanh( (Ve - vt) / vddin );
84
85 vdd=0.0; /* unused */
86 }
87
88 /****************************************************************************/
89
90 double stm_modscm_dual_get_ir( double t,
91 double A,
92 double B,
93 double vin,
94 double F,
95 double Ur,
96 double Fr,
97 double rbr,
98 double cbr,
99 double imax,
100 double Fs,
101 double vdd,
102 double rnt,
103 double rns,
104 double rni,
105 double vint,
106 double vt,
107 double vout
108 )
109 {
110 double V, Vr ;
111 double b, br ;
112 double ir ;
113 double i ;
114
115 /* Valeurs rapportées */
116 Vr = Ur * tanh( t / Fr );
117
118 /* Valeurs réélles */
119 V = vin * tanh( t / F) ;
120 b = stm_modscm_dual_voltage_rc( t, rbr, cbr, imax, Fs );
121
122 /* Valeur du bruit rapporté proportionnel à Vm / Vr */
123 br = b * Vr / V ;
124
125 if( !finite( br ) )
126 return 0.0 ;
127
128 /* Nouvelle tension d'entrée rapportée */
129 Vr = Vr + br ;
130 ir = A * Vr * Vr / ( 1.0 + B * Vr );
131
132 i = stm_modscm_dual_calc_i( imax, ir, A, B, rnt, rns, rni, vint, vdd, vt, vt+V+b, vout );
133 return i ;
134 }
135
136 /****************************************************************************/
137 double stm_modscm_dual_get_ia( double t,
138 double A,
139 double B,
140 double Ua,
141 double Fa,
142 double vin,
143 double fin,
144 double imax,
145 double vdd,
146 double rnt,
147 double rns,
148 double rni,
149 double vint,
150 double vt,
151 double vout
152 )
153 {
154 double V ;
155 double ia ;
156 double i ;
157
158 V = Ua * tanh(t / Fa);
159 ia = A * V * V / (1.0 + B * V);
160 V = vt + vin * tanh( t/fin );
161 i = stm_modscm_dual_calc_i( imax, ia, A, B, rnt, rns, rni, vint, vdd, vt, V, vout );
162
163 return i ;
164 }
165
166 /****************************************************************************/
167
168 double stm_modscm_dual_get_k4Q( double A,
169 double B,
170 double vin,
171 double Fin,
172 double Ur,
173 double Fr,
174 double Ua,
175 double Fa,
176 double rbr,
177 double cbr,
178 double imax,
179 double Fs,
180 double vdd,
181 double rns,
182 double rnt,
183 double rni,
184 double vint,
185 double vt
186 )
187 {
188 double k, ia, ir ;
189 double vout ;
190
191 cbr /= 1000.0;
192 k = 1.0 ;
193 if( rni>0.0 && vint > 0.0 )
194 vout = vdd/2.0 ;
195 else
196 vout = vdd ;
197
198 do {
199 k = k * 1.2 ;
200 ir = stm_modscm_dual_get_ir( k*Fs, A, B, vin, Fin, Ur, Fr, rbr, cbr, imax, Fs, vdd, rnt, rns, rni, vint, vt, vout );
201 ia = stm_modscm_dual_get_ia( k*Fs, A, B, Ua, Fa, vin, Fin, imax, vdd, rnt, rns, rni, vint, vt, vout );
202 }
203 while ( fabs(ir-ia)/ir > 0.01 );
204
205 return k;
206 }
207
208 /****************************************************************************/
209
210 double stm_modscm_dual_get_Q( double ts,
211 double k,
212 double A,
213 double B,
214 double vin,
215 double Fin,
216 double Ur,
217 double Fr,
218 double Ua,
219 double Fa,
220 double rbr,
221 double cbr,
222 double imax,
223 double Fs,
224 double tm,
225 double vdd,
226 double vt,
227 double rns,
228 double rnt,
229 double rni,
230 double vint,
231 double fout,
232 double threshold
233 )
234 {
235 double s, Q;
236 double ir, ia ;
237 double vout ;
238 double d, dt ;
239
240 cbr /= 1000.0;
241 vout = vdd ;
242
243 if(ts < tm) {
244 Q = 0.0;
245 }
246 else {
247 if((ts >= tm) && (ts < Fs)) {
248 vout = vdd/2.0 ;
249 ia = stm_modscm_dual_get_ia(ts, A, B, Ua, Fa, vin, Fin, imax, vdd, rnt, rns, rni, vint, vt, vout ) ;
250 ir = stm_modscm_dual_get_ir(ts, A, B, vin, Fin, Ur, Fr, rbr, cbr, imax, Fs, vdd, rnt, rns, rni, vint, vt, vout ) ;
251 Q = 0.5 * (ts - tm) * ( ir - ia );
252 }
253 else {
254 dt = fout * atanh((threshold-vt)/(vdd-vt)) ;
255 d = ts - dt ;
256 vout = vdd - ( vt + (vdd-vt)*tanh((Fs-d)/fout) );
257 ia = stm_modscm_dual_get_ia(Fs, A, B, Ua, Fa, vin, Fin, imax, vdd, rnt, rns, rni, vint, vt, vout) ;
258 ir = stm_modscm_dual_get_ir(Fs, A, B, vin, Fin, Ur, Fr, rbr, cbr, imax, Fs, vdd, rnt, rns, rni, vint, vt, vout ) ;
259 s = (k * Fs / 2.0 - tm / 2.0) * ( ir - ia );
260
261 if((ts >= Fs) && (ts < k*Fs)) {
262 vout = vdd/2.0 ;
263 ir = stm_modscm_dual_get_ir(ts, A, B, vin, Fin, Ur, Fr, rbr, cbr, imax, Fs, vdd, rnt, rns, rni, vint, vt, vout ) ;
264 ia = stm_modscm_dual_get_ia(ts, A, B, Ua, Fa, vin, Fin, imax, vdd, rnt, rns, rni, vint, vt, vout) ;
265
266 Q = s - 0.5 * (k * Fs - ts) * ( ir - ia );
267 }
268 else
269 Q = s;
270 }
271 }
272 return Q * 1000.0;
273 }
274
275 /****************************************************************************/
276
277 float stm_modscm_dual_cconf (dualparams *params, float slew)
278 {
279 return params->DP[STM_CAPAI] + (params->DP[STM_PCONF0] + params->DP[STM_PCONF1] * slew)
280 * params->DP[STM_IRAP];
281 }
282
283 /****************************************************************************/
284
285 float stm_modscm_dual_imax (dualparams *params)
286 {
287 return params->DP[STM_IMAX];
288 }
289
290 /****************************************************************************/
291
292 float stm_modscm_dual_vth (dualparams *params)
293 {
294 return params->DP[STM_THRESHOLD];
295 }
296
297 /****************************************************************************/
298 void stm_modscm_dual_cal_UF (double imax,
299 double an,
300 double bn,
301 double vddin,
302 double vx,
303 double fin,
304 double *U,
305 double *F)
306 {
307
308 *U = (imax * bn + sqrt (pow ((imax * bn), 2) + 4.0 * an * imax)) / (2.0 * an);
309
310 *F = fin * *U / vddin;
311
312 *F *= (*U - vx) / *U ;
313 *U -= vx ;
314 }
315 /****************************************************************************/
316
317 double stm_modscm_dual_calculduts (dualparams *params, float slew, float load, stm_pwl *pwl)
318 {
319 double threshold = (double)params->DP[STM_THRESHOLD];
320 double ts ;
321 ts = stm_modscm_dual_calculduts_threshold( params, slew, load, threshold, pwl );
322
323 return ts ;
324
325 }
326 /****************************************************************************/
327
328 char stm_modscm_dual_slew_for_pwl( paramforslewpwl *param, float v, float *t )
329 {
330 *t = stm_modscm_dual_calts_with_param_timing( param->DUALSCM, v );
331 return 1;
332 }
333
334 /****************************************************************************/
335 float stm_modscm_dual_slew (dualparams *params, float slew, stm_pwl *pwl, stm_pwl **ptpwl, float load)
336 {
337 float f ;
338 double vt ;
339 double vdd ;
340 double s1old, s1new, s2old, s2new, seuil1, seuil2, ts1, ts2 ;
341 char oldmode = 0;
342 float tabpwl[30];
343 double vs, ts ;
344 int i;
345
346 if( oldmode ) {
347 f = stm_modscm_dual_slew_old( params, slew, load );
348 }
349 else {
350 vt = (double)params->DP[STM_VT];
351 vdd = (double)params->DP[STM_VDDMAX];
352
353 s1old = vt ;
354 s1new = 0.3*vdd ;
355
356 s2old = 0.75 * (vdd-vt) + vt ;
357 s2new = 0.8*vdd ;
358
359 if( s1old > s1new ) seuil1 = s1old ; else seuil1 = s1new ;
360 if( s2old > s2new ) seuil2 = s2old ; else seuil2 = s2new ;
361
362 ts1 = stm_modscm_dual_calculduts_threshold( params, slew, load, seuil1, pwl );
363 ts2 = stm_modscm_dual_calculduts_threshold( params, slew, load, seuil2, pwl );
364
365 f = stm_thr2scm( ts2-ts1,
366 seuil1/vdd,
367 seuil2/vdd,
368 vt,
369 vdd,
370 vdd,
371 STM_UP
372 );
373
374 if( ptpwl ) {
375 i=0;
376
377 vs = 0.2*vdd ;
378 ts = stm_modscm_dual_calculduts_threshold( params, slew, load, vs, pwl );
379 tabpwl[i++] = ts ; tabpwl[i++]=vs ;
380
381 vs = 0.5*vdd ;
382 ts = stm_modscm_dual_calculduts_threshold( params, slew, load, vs, pwl );
383 tabpwl[i++] = ts ; tabpwl[i++]=vs ;
384
385 vs = 0.8*vdd ;
386 ts = stm_modscm_dual_calculduts_threshold( params, slew, load, vs, pwl );
387 tabpwl[i++] = ts ; tabpwl[i++]=vs ;
388
389 vs = 0.9*vdd ;
390 ts = stm_modscm_dual_calculduts_threshold( params, slew, load, vs, pwl );
391 tabpwl[i++] = ts ; tabpwl[i++]=vs ;
392
393 vs = 0.95*vdd ;
394 ts = stm_modscm_dual_calculduts_threshold( params, slew, load, vs, pwl );
395 tabpwl[i++] = ts ; tabpwl[i++]=vs ;
396 *ptpwl = stm_pwl_create( tabpwl, 5 );
397
398 /*
399 int n, j ;
400 static char printed=0;
401 n=6;
402 j=0;
403 for(i=1;i<=n;i++) {
404 vs = ((float)i)/((float)(n+1))*vdd ;
405 if( vs < vt )
406 continue ;
407 ts = stm_modscm_dual_calculduts_threshold( params, slew, load, vs, pwl );
408 tabpwl[j++] = ts ;
409 tabpwl[j++] = vs ;
410 }
411
412 if( !printed ) {
413 printf( "---> %d points\n", j/2 );
414 printed = 1 ;
415 }
416 *ptpwl = stm_pwl_create( tabpwl, j/2 );
417 */
418 }
419 }
420
421 return f ;
422 }
423
424 float stm_modscm_dual_slew_old (dualparams *params, float slew, float load)
425 {
426 double cconf;
427 double capa, capa0;
428 double pconf0 = (double)params->DP[STM_PCONF0];
429 double pconf1 = (double)params->DP[STM_PCONF1];
430 double capai = (double)params->DP[STM_CAPAI];
431 double irap = (double)params->DP[STM_IRAP];
432 double vddin = (double)params->DP[STM_VDDIN];
433 double vt = (double)params->DP[STM_VT];
434 double threshold = (double)params->DP[STM_THRESHOLD];
435 double imax = (double)params->DP[STM_IMAX];
436 double an = (double)params->DP[STM_AN];
437 double bn = (double)params->DP[STM_BN];
438 double delayrc = (double)params->DP[STM_DRC];
439 double rbr = (double)params->DP[STM_RBR];
440 double cbr = (double)params->DP[STM_CBR];
441 double rsat = (double)params->DP[STM_RSAT];
442 double rlin = (double)params->DP[STM_RLIN];
443 double vddmax = (double)params->DP[STM_VDDMAX];
444 double fout ;
445 double deltat;
446 double U, F, Ur, Fr, im, Fs, tm, Fm, k4Q, t0, Q;
447 double ts1, ts2, seuil1, seuil2 ;
448
449 if( pconf1*slew < 10.0*load )
450 pconf1 = 1.2 * pconf1 ;
451
452 /* Note :
453 On n'appelle pas deux fois la fonction culcule du ts avec deux seuils
454 différents car on souhaite conserver la même caractéristique.
455 */
456
457 if((rbr > 0.0) && (cbr > 0.0)){
458 stm_modscm_dual_cal_UF (imax, an, bn, vddin, 0.0, (double)slew, &Ur, &Fr);
459 stm_modscm_dual_slopei(0.7, bn, Ur, imax, Fr, rsat, vddmax, vddmax, &im, &Fs);
460 stm_modscm_dual_modifslope( vddin, vt, slew, vddmax, rbr, cbr, im, Fs, &tm, &Fm);
461 }
462 else {
463 Fm = (double)slew;
464 }
465 stm_modscm_dual_cal_UF (imax, an, bn, vddin, 0.0, Fm, &U, &F);
466 if((capai > 0.00) && (capai/(load + (pconf0 + pconf1 * slew) * irap) > STM_OVERSHOOT)){
467 deltat = stm_modscm_dual_calts (imax, an, bn, U, threshold, 0.0, F, 0.0, vt, vddin, capai, NULL, NULL, slew, NULL, 0, 0.0, 0.0, 0.0, NULL );
468 }else{
469 deltat = 0.0;
470 }
471 deltat += delayrc ;
472 if(deltat < slew)
473 cconf = pconf0 + pconf1 * (slew - deltat);
474 else
475 cconf = pconf0;
476 capa0 = cconf * irap + (double)load;
477 t0 = stm_modscm_dual_calts (imax, an, bn, U, threshold, capa0, F, 0.0, vt, vddin, capai, NULL, NULL, slew, NULL, 0, 0.0, 0.0, 0.0, NULL );
478 capa = capa0 ;
479 if((rbr > 0.0) && (cbr > 0.0)){
480 fout = stm_modscm_dual_calslew( imax, an, bn, U, vt, vddmax, capa, slew, F, t0);
481 k4Q = stm_modscm_dual_get_k4Q( an, bn, vddin, slew, Ur, Fr, U, F, rbr, cbr, im, Fs, vddmax, rsat, rlin, -1.0, -1.0, vt );
482 Q = stm_modscm_dual_get_Q( t0, k4Q, an, bn, vddin, slew, Ur, Fr, U, F, rbr, cbr, im, Fs, tm, vddmax, rsat, rlin, -1.0, -1.0, vt, fout, threshold);
483 if( 2.0 * Q / vddmax < capa )
484 capa -= 2.0 * Q / vddmax;
485 }
486
487 /*
488 if( STM_DEFAULT_SMINR > 0.0 && STM_DEFAULT_SMAXR < 1.0 ) {
489 seuil1 = STM_DEFAULT_SMINR*vddmax ;
490 seuil2 = STM_DEFAULT_SMAXR*vddmax ;
491 }
492 else {
493 seuil1 = vt ;
494 seuil2 = 0.75 * (vddmax-vt) + vt ;
495 }
496 */
497
498 seuil1 = 0.5*vddmax ;
499 seuil2 = 0.8*vddmax ;
500
501 {
502 double s1old, s1new, s2old, s2new ;
503
504 s1old = vt ;
505 s1new = 0.4*vddmax ;
506
507 s2old = 0.75 * (vddmax-vt) + vt ;
508 s2new = 0.8*vddmax ;
509
510 if( s1old > s1new ) seuil1 = s1old ; else seuil1 = s1new ;
511 if( s2old > s2new ) seuil2 = s2old ; else seuil2 = s2new ;
512
513 }
514
515 if( rsat <= 0.0 ) {
516 ts1 = stm_modscm_dual_calts (imax, an, bn, U, seuil1, capa, F, 0.0, vt, vddin, capai, NULL, NULL, slew, NULL, 0, 0.0, 0.0, 0.0, NULL );
517 ts2 = stm_modscm_dual_calts (imax, an, bn, U, seuil2, capa, F, 0.0, vt, vddin, capai, NULL, NULL, slew, NULL, 0, 0.0, 0.0, 0.0, NULL );
518 }
519 else {
520 ts1 = stm_modscm_dual_calts_rsat_full_range ( capai, imax, an, bn, U, vt, vddmax, threshold, seuil1, rsat, rlin, capa, slew, F, stm_modscm_dual_calte (vddin, vt, vt, (double)slew), t0, vddin, NULL );
521 ts2 = stm_modscm_dual_calts_rsat_full_range ( capai, imax, an, bn, U, vt, vddmax, threshold, seuil2, rsat, rlin, capa, slew, F, stm_modscm_dual_calte (vddin, vt, vt, (double)slew), t0, vddin, NULL );
522 }
523
524 return stm_thr2scm( ts2-ts1,
525 seuil1/vddmax,
526 seuil2/vddmax,
527 vt,
528 vddmax,
529 vddmax,
530 STM_UP
531 );
532 }
533 /****************************************************************************/
534
535 float stm_dv( float t, mbk_pwl *linetanh, float rdriver, float cin, float capai )
536 {
537 float k ;
538 int n, m ;
539 float dv ;
540 float tmax ;
541 float ta ;
542 float a ;
543 float t0 ;
544 static char enable='x' ;
545
546 if( V_BOOL_TAB[ __STM_ENABLE_DV ].VALUE )
547 enable = 'y' ;
548 else
549 enable = 'n' ;
550
551 if( enable == 'n' )
552 return 0.0 ;
553
554 t0=linetanh->DATA[0].X0;
555 if( t < t0 )
556 return 0.0 ;
557
558 for( n = 0 ; n < linetanh->N ; n++ ) {
559
560 if( n==linetanh->N-1 )
561 tmax = linetanh->X1 ;
562 else
563 tmax = linetanh->DATA[n+1].X0 ;
564
565 if( tmax > t )
566 break ;
567 }
568
569 if( n >= linetanh->N )
570 n = linetanh->N - 1 ;
571
572 dv = 0.0 ;
573 k = rdriver * ( cin + capai );
574
575 for( m = 0 ; m <= n ; m++ ) {
576 a = linetanh->DATA[m].A ;
577 ta = linetanh->DATA[m].X0;
578 dv = dv + a*(1.0-exp(-(t-ta)/k)) ;
579 if( m<n ) {
580 ta = linetanh->DATA[m+1].X0 ;
581 dv = dv - a*(1.0-exp(-(t-ta)/k)) ;
582 }
583 }
584 dv = dv*rdriver*capai;
585
586 return dv ;
587 }
588
589 double stm_dv_old( double t, double im, double Fs, double r, double cl, double cin, double ci )
590 {
591 double k1 ;
592 double c1 ;
593 double dv ;
594
595 k1 = r*( cl*cin + cl*ci + cin*ci );
596 c1 = ci + cl ;
597
598 if( t <= Fs )
599 dv = im*r*ci/(Fs*c1)*(t-k1/c1*(1.0-exp(-c1*t/k1))) ;
600 else
601 dv = im*r*ci/(Fs*c1)*(t-k1/c1*(1.0-exp(-c1*t/k1))) -
602 im*r*ci/(Fs*c1)*((t-Fs)-k1/c1*(1.0-exp(-c1*(t-Fs)/k1)));
603
604 return dv ;
605 }
606
607 /****************************************************************************/
608 void stm_estim_output( stm_dual_param_timing *param, double global_t, double v )
609 {
610 double t0 ;
611 double tst0 ;
612 double local_t ;
613 double tslocal_t ;
614 double dtlocal ;
615 double dt ;
616
617 t0 = stm_modscm_dual_calts( param->IMAX,
618 param->AN,
619 param->BN,
620 param->U,
621 param->THRESHOLD,
622 param->CAPA0,
623 param->F,
624 param->DTPWL,
625 param->VT,
626 param->VDDIN,
627 param->CAPAI,
628 NULL,
629 NULL,
630 param->FIN,
631 NULL,
632 0,
633 0,
634 0.0,
635 0.0,
636 NULL
637 );
638
639 param->FOUT = stm_modscm_dual_calslew( param->IMAX,
640 param->AN,
641 param->BN,
642 param->U,
643 param->VT,
644 param->VDDMAX,
645 param->CAPA,
646 param->FIN,
647 param->F,
648 t0
649 );
650
651 if( v > 0.0 ) {
652 tst0 = stm_modscm_dual_calte( param->VDDMAX-param->VT, param->VT, param->THRESHOLD, param->FOUT ) ;
653 tslocal_t = stm_modscm_dual_calte( param->VDDMAX-param->VT, param->VT, v, param->FOUT ) ;
654 dtlocal = t0-tst0 ;
655 local_t = dtlocal+tslocal_t ;
656 dt = global_t - param->DTPWL - local_t ;
657 t0 = t0 + dt ;
658 }
659
660 param->T0 = t0 + param->DTPWL ;
661 }
662
663 void stm_modscm_dual_fill_param( dualparams *params,
664 float fin,
665 stm_pwl *pwlin,
666 stm_driver *driver,
667 float load,
668 stm_dual_param_timing *paramtiming
669 )
670 {
671 double cconf;
672 double capa, capa0;
673 double pconf0 = (double)params->DP[STM_PCONF0];
674 double pconf1 = (double)params->DP[STM_PCONF1];
675 double capai = (double)params->DP[STM_CAPAI];
676 double capao = (double)params->DP[STM_CAPAO];
677 double irap = (double)params->DP[STM_IRAP];
678 double vddin = (double)params->DP[STM_VDDIN];
679 double vt = (double)params->DP[STM_VT];
680 double threshold = (double)params->DP[STM_THRESHOLD];
681 double input_thr = (double)params->DP[STM_INPUT_THR];
682 double imax = (double)params->DP[STM_IMAX];
683 double an = (double)params->DP[STM_AN];
684 double bn = (double)params->DP[STM_BN];
685 double delayrc = (double)params->DP[STM_DRC];
686 double rbr = (double)params->DP[STM_RBR];
687 double cbr = (double)params->DP[STM_CBR];
688 double rsat = (double)params->DP[STM_RSAT];
689 double rlin = (double)params->DP[STM_RLIN];
690 double vddmax = (double)params->DP[STM_VDDMAX];
691 double rint = (double)params->DP[STM_RINT];
692 double vint = (double)params->DP[STM_VINT];
693 double chalf = (double)params->DP[STM_CHALF];
694 double rconf = (double)params->DP[STM_RCONF];
695 double kf = (double)params->DP[STM_KF];
696 double qinit0 = (double)params->DP[STM_QINIT];
697 double vt0 = (double)params->DP[STM_VT0];
698 double vt0c = (double)params->DP[STM_VT0C];
699 double capaie[4] ;
700 double vcap[3] ;
701 char integnumeric ;
702 double deltat=0.0 ;
703 double U, F, Ur, Fr, im, Fs, tm, Fm, k4Q, t0, Q, te, ts, koshoot;
704 double fout ;
705 double vsat ;
706 double rsatsep ;
707 stm_pwl *pwlshrk ;
708 char newswitchmodel ;
709 double qinit ;
710 int n;
711 int nbdv;
712 stm_pwl *pwldv ;
713 float t, v ;
714 stmtanhdata tanhdata;
715 mbk_pwl *linetanh;
716 float lv, dv, tx, tmin, tminin, tmax, tmaxin, tmaxout, dt, tminctk ;
717 static int fordebug = 0 ;
718 mbk_pwl_param *param ;
719 int ctkmodel ;
720 float lt, ldv, s ;
721 int localpwlin ;
722 float rdriver ;
723 float cin ;
724 static char flag='n';
725 double icf0 ;
726 double strans ;
727 int usecapaie ;
728
729 fordebug++;
730
731 capaie[0] = params->DP[STM_CAPAI0] ;
732 capaie[1] = params->DP[STM_CAPAI1] ;
733 capaie[2] = params->DP[STM_CAPAI2] ;
734 capaie[3] = params->DP[STM_CAPAI3] ;
735 if( capaie[0] == capaie[1] &&
736 capaie[0] == capaie[2] &&
737 capaie[3] == capaie[3] )
738 usecapaie = 0 ;
739 else
740 usecapaie = 1 ;
741
742
743 vcap[0] = vt0 ;
744 vcap[1] = vddmax/2.0 ;
745 vcap[2] = vt0c ;
746
747 qsort( vcap, 3, sizeof(double), (int(*)(const void*,const void*))mbk_qsort_dbl_cmp );
748
749 ctkmodel = V_INT_TAB[ __STM_CTK_MODEL ].VALUE ;
750
751 newswitchmodel = 0 ;
752 if( vint > 0.0 && rint > 0.0 )
753 newswitchmodel = 1 ;
754
755 integnumeric = 0 ;
756
757 if( newswitchmodel && ( vint > 0.0 && rint > 0.0 ) )
758 integnumeric = 1 ;
759
760 if( V_BOOL_TAB[ __STM_NUMERICAL_INTEGRATION ].VALUE ) {
761 if( flag=='n' ) {
762 printf( "numerical integration forced !\n" );
763 flag='y';
764 }
765 integnumeric = 1 ;
766 }
767
768 qinit = qinit0 ;
769 icf0 = 0.0 ;
770 strans = 0.0 ;
771 if( rconf > 0.0 && kf > 0.0 && fin > 1.0 ) {
772 tmax = kf*fin ;
773 icf0 = capaie[0]*1e-15/(fin*1e-12)*(vddmax-vt)*(1.0-exp(-tmax*1e-12/(rconf*(capaie[0]+load)*1e-15))) ;
774 if( V_BOOL_TAB[ __STM_NEW_OVERSHOOT ].VALUE ) {
775 double r,k ;
776 r = (vddmax-2*vt)/vddmax ;
777 if( r>0.3 )
778 k=V_FLOAT_TAB[__STM_OVERSHOOT_K_LVT].VALUE ;
779 else
780 k=V_FLOAT_TAB[__STM_OVERSHOOT_K_HVT].VALUE ;
781 qinit = -k * (capai*1e-3)/fin*(vddmax-vt)*(tmax+rconf*(load*1e-3)*(exp(-tmax/(rconf*load*1e-3))-1.0));
782 }
783 else {
784 Q = -(pconf0+load)/1000.0*((-icf0)*rconf)-capaie[0]/1000.0*vt-qinit0 ;
785 qinit = qinit+Q ;
786 }
787 }
788
789 /* fin : front d'entrée réel original.
790 Fr : front d'entrée rapporté sans prendre en compte le cbr.
791 Ur : tension d'entrée rapporté sans prendre en compte le cbr.
792 Fs : instant où on considère que le courant atteint imax.
793 Fm : front d'entrée réel prenant en compte le cbr.
794 F : front d'entrée rapporté prenant en compte cbr.
795 U : tension d'entrée rapporté prenant en compte cbr.
796 t0 : estimation ts sortie en vdd/2
797 fout : estimation f sortie
798
799 */
800
801 capa = load+pconf0+pconf1*fin;
802
803 if( !integnumeric && (rbr > 0.0) && (cbr > 0.0) ) {
804 stm_modscm_dual_cal_UF (imax, an, bn, vddin, 0.0, (double)fin, &Ur, &Fr);
805 stm_modscm_dual_slopei(0.7, bn, Ur, imax, Fr, rsat, vddmax, vddmax, &im, &Fs);
806 stm_modscm_dual_modifslope( vddin, vt, fin, vddmax, rbr, cbr, im, Fs, &tm, &Fm);
807 }
808 else
809 Fm = (double)fin ;
810
811 stm_modscm_dual_cal_UF (imax, an, bn, vddin, 0.0, Fm, &U, &F);
812 t0 = stm_modscm_dual_calts (imax, an, bn, U, threshold, capa, F, 0.0, vt, vddin, capai, NULL, NULL, fin, NULL, 0, 0.0, 0.0, 0.0, NULL );
813 fout = stm_modscm_dual_calslew( imax, an, bn, U, vt, vddmax, capa, fin, F, t0);
814
815 /* Prise en compte de la modification du front d'entree due au capai.
816 Pour l'instant, nous l'appliquons que les technos pour lesquelles le
817 vt est superieur à vdd/2 */
818 paramtiming->NEWCTKMODEL = 0 ;
819 paramtiming->EVTIN = '-' ;
820 paramtiming->VIN = -1.0 ;
821
822 if( driver ) {
823 if( ! V_BOOL_TAB[ __AVT_CTK_ON_INPUT ].VALUE || integnumeric==1 )
824 driver = NULL ;
825 }
826
827 if( driver ) {
828 if( driver->c <= 0.0 ||
829 driver->r <= 0.0 )
830 driver = NULL ;
831 }
832
833 if( driver ) {
834
835 if( V_BOOL_TAB[ __AVT_NEW_CTK_ON_INPUT ].VALUE && V_BOOL_TAB[ __AVT_CTK_ON_INPUT ].VALUE ) {
836 paramtiming->DRIVER.c = driver->c - capai ;
837 if( V_BOOL_TAB[ __STM_RDRIVER_FROM_SLOPE ].VALUE ) {
838 if( V_BOOL_TAB[ __AVT_BUG_RDRIVER ].VALUE )
839 paramtiming->DRIVER.r = 0.693*fin/(driver->c/1000.0)/4.0 ;
840 else
841 paramtiming->DRIVER.r = 0.693*fin/(driver->c/1000.0) ;
842 }
843 else
844 paramtiming->DRIVER.r = driver->r ;
845 paramtiming->DRIVER.v = driver->v ;
846 paramtiming->NEWCTKMODEL = 1 ;
847 }
848
849 if( ! V_BOOL_TAB[ __AVT_CTK_ON_INPUT ].VALUE ||
850 integnumeric==1 ||
851 V_BOOL_TAB[ __AVT_NEW_CTK_ON_INPUT ].VALUE
852 )
853 driver = NULL ;
854 }
855
856 if( driver ) {
857 /* retire la capa de couplage comptée dans la capa d'entrée */
858 cin = driver->c - capao ;
859 }
860 else {
861 cin = -1.0 ;
862 }
863
864 localpwlin = 0 ;
865
866 if( driver ) {
867 if( V_BOOL_TAB[ __STM_RDRIVER_FROM_SLOPE ].VALUE ) {
868 /* resistance du driver du front d'entrée : modèle integrales à
869 l'infinie égales */
870 if( V_BOOL_TAB[ __AVT_BUG_RDRIVER ].VALUE )
871 rdriver = 0.693*fin/(driver->c/1000.0)/4.0 ;
872 else
873 rdriver = 0.693*fin/(driver->c/1000.0) ;
874 }
875 else
876 rdriver = driver->r ;
877 }
878 else
879 rdriver = -1.0 ;
880
881 /* calcul de l'écart entre le référentiel de l'entrée et de la sortie */
882 if( threshold > vt )
883 ts = fout*atanh( (threshold-vt)/(vddmax-vt));
884 else
885 ts = fout*(threshold-vt)/(vddmax-vt);
886 dt = t0-ts ;
887
888 if( !integnumeric && ( (driver && driver->r > 0.0 && driver->c > 0.0 && cin > 0.0 ) || usecapaie ) ) {
889 /* Calcule du dV de tensions sur l'entrée à partir de l'estimation du front de sortie :
890 Comme on ne connait pas la transformée de laplace de la tanh, on passe en pwl */
891 tanhdata.F = fout ;
892 tanhdata.VDD = vddmax ;
893 tanhdata.VT = vt ;
894 tanhdata.T0 = dt ;
895
896 /* calcul du dernier instant : quand les transitions atteignent 95% de leur valeurs finales */
897 tmaxout = dt + fout*atanh( (0.95*vddmax-vt)/(vddmax-vt) );
898 tmaxin = fin*atanh( (0.95*(vddin+vt)-vt)/vddin ) ;
899 if( tmaxout > tmaxin )
900 tmax = 2.0*tmaxout ;
901 else
902 tmax = 2.0*tmaxin ;
903
904 /* calcul du premier instant */
905 tx = -fout*vt/(vddmax-vt);
906 if( tx+dt > 0.0 )
907 tmin = tx+dt ;
908 else
909 tmin = 0.0 ;
910
911 tminctk = tmin ;
912 if( V_BOOL_TAB[ __AVT_RDRIVER_UNDER_VSAT ].VALUE && driver->v > 0.0 ) {
913 vsat = vddmax-driver->v ;
914 if( vsat > vt ) {
915 tminin = fin*atanh( ( vsat - vt )/vddin );
916 if( tminin > tmin )
917 tminctk = tminin ;
918 }
919 }
920
921 if( usecapaie )
922 tmin = 0.0 ;
923
924 param = mbk_pwl_get_default_param( (char (*)(void*, double, double*))stmtanhfn, (void*) &tanhdata, tmin, tmax ) ;
925 /* calcul des pwl : on impose le point vt */
926 mbk_pwl_add_param_point( param, dt );
927
928 linetanh = mbk_pwl_create( (char (*)(void*, double, double*))stmtanhfn, (void*) &tanhdata, tmin, tmax, param ) ;
929 mbk_pwl_free_param( param );
930
931 if( linetanh ) {
932
933 switch( ctkmodel ) {
934
935 case 1 : /* méthode du pwl equivalent */
936 case 2 : /* méthode du pwl equivalent, limite haute */
937 case 3 : /* méthode du pwl equivalent, limite basse */
938
939 /* Determine le stm_pwl de l'entrée en retranchant les dv */
940 pwldv = (stm_pwl*)mbkalloc( sizeof(stm_pwl));
941 pwldv->TAB = (float*)mbkalloc(sizeof(float)*2*V_INT_TAB[ __STM_INPUT_NB_PWL ].VALUE);
942
943 nbdv = 0;
944 lv = 0.0 ;
945 for( n=0 ; n<V_INT_TAB[ __STM_INPUT_NB_PWL ].VALUE ; n++ ) {
946
947 t = ((float)n)/((float)(V_INT_TAB[ __STM_INPUT_NB_PWL ].VALUE-1))*tmax;
948 if( rdriver>0.0 && t>=tminctk )
949 dv = stm_dv( t, linetanh, rdriver, cin/1000.0, capao/1000.0 );
950 else
951 dv = 0.0 ;
952 v = vt+vddin*tanh(t/fin) - dv;
953 switch( ctkmodel ) {
954 case 1 :
955 case 3 :
956 pwldv->TAB[2*nbdv+0] = t ;
957 pwldv->TAB[2*nbdv+1] = v ;
958 nbdv++;
959 break ;
960 case 2 :
961 if( v > lv ) {
962 pwldv->TAB[2*nbdv+0] = t ;
963 pwldv->TAB[2*nbdv+1] = v ;
964 nbdv++;
965 lv = v ;
966 }
967 break ;
968 }
969 }
970 pwldv->N = nbdv ;
971
972 /* ecrasement du pwlin. a faire : calculer la forme de la tension
973 d'entrée en prenant en compte le dv */
974
975 pwlin = pwldv ;
976 localpwlin = 1 ;
977 break ;
978 case 4 : /* méthode du front equivalent */
979 lt = 0.0 ;
980 ldv = 0.0 ;
981 s = 0.0 ;
982
983 for( n=0 ; n<V_INT_TAB[ __STM_INPUT_NB_PWL ].VALUE ; n++ ) {
984 t = ((float)n)/((float)(V_INT_TAB[ __STM_INPUT_NB_PWL ].VALUE-1))*tmax;
985 if( rdriver>0.0 )
986 dv = stm_dv( t, linetanh, rdriver, cin/1000.0, capao/1000.0 );
987 else
988 dv = 0.0 ;
989 s = s + (t-lt)*(dv+ldv)/2.0 ;
990 lt = t ;
991 ldv = dv ;
992 }
993 fin = fin + s/(vddin*0.693);
994 break ;
995 }
996
997 mbk_pwl_free_pwl(linetanh);
998 }
999 }
1000
1001 /* transforme le pwl d'entrée proportionnellement au passage de
1002 vddin, fin -> U, F. */
1003 paramtiming->NTHSHRK = 0;
1004 if( pwlin ) {
1005 pwlshrk = stm_shrink_pwl( pwlin, vddin, fin, U, F, vt );
1006 if( !stm_pwl_to_tanh( pwlshrk, vt, U+vt, paramtiming->PWTHSHRK, &paramtiming->NTHSHRK, F ) )
1007 paramtiming->NTHSHRK = 0;
1008 stm_pwl_destroy( pwlshrk );
1009
1010 if( localpwlin ) {
1011 stm_pwl_destroy( pwlin );
1012 pwlin=NULL;
1013 }
1014 }
1015
1016 if( V_BOOL_TAB[ __STM_QINIT_FOR_DT_CONF ].VALUE && icf0>0.0 ) {
1017 /* calcule l'instant où la sortie vaut 0, après absorbtion de l'overshoot */
1018 strans = stm_modscm_dual_calts (imax, an, bn, U, 0.0, 0.0, F, 0.0, vt, vddin, capaie[0], NULL, NULL, fin, NULL, 0, qinit, 0.0, 0.0, NULL );
1019 /* vérifie si cet instant est inférieur à l'instant où la branche conflictuelle se coupe */
1020 te = stm_modscm_dual_calte (vddin, vt, vt0c, (double)fin);
1021 if( te < strans )
1022 strans = te ;
1023 deltat = stm_modscm_dual_calts_final( imax, an, bn, U, 0.0, 0.0, F, vt, vddin, capaie[0], fin, 0.0, qinit, strans, icf0, NULL );
1024 }
1025 else
1026 {
1027 if(V_BOOL_TAB[__STM_QINIT_FOR_OVERSHOOT_CONF].VALUE)
1028 deltat = stm_modscm_dual_calts (imax, an, bn, U, threshold, 0.0, F, 0.0, vt, vddin, capai, NULL, NULL, fin, NULL, 0, qinit, 0.0, 0.0, NULL );
1029 else
1030 deltat = stm_modscm_dual_calts (imax, an, bn, U, threshold, 0.0, F, 0.0, vt, vddin, capai, NULL, NULL, fin, NULL, 0, 0, 0.0, 0.0, NULL );
1031 }
1032
1033 koshoot = 0.0 ;
1034 if( (capai > 0.00) && (capai/(load + (pconf0 + pconf1 * fin) * irap) > STM_OVERSHOOT) ) {
1035 te = stm_modscm_dual_calte (vddin, vt, input_thr, (double)fin);
1036 koshoot = ( deltat/te ) * (deltat/te );
1037 }else{
1038 deltat = 0.0;
1039 }
1040 deltat += delayrc ;
1041
1042 if( newswitchmodel ) {
1043 if( koshoot < 1.0 )
1044 cconf = pconf0 + irap * pconf1 * fin *( 1.0 - koshoot ) ;
1045 else
1046 cconf = pconf0;
1047 capa0 = cconf ;
1048 }
1049 else {
1050 if( koshoot < 1.0 )
1051 cconf = pconf0 + pconf1 * fin *( 1.0 - koshoot );
1052 else
1053 cconf = pconf0;
1054 capa0 = cconf * irap ;
1055 }
1056
1057 if( capa0 + load < 0.0 )
1058 capa0 = 0.0 ;
1059
1060 capa = capa0 ;
1061
1062 t0 = -1.0 ;
1063 if( integnumeric == 0 )
1064 t0 = stm_modscm_dual_calts (imax, an, bn, U, threshold, capa0+load, F, 0.0, vt, vddin, capai, NULL, NULL, fin, NULL, 0, 0.0, 0.0, 0.0, NULL );
1065
1066 if( integnumeric == 0 && (rbr > 0.0) && (cbr > 0.0)){
1067 // Calcule de la charge supplémentaire due à l'overshoot
1068 fout = stm_modscm_dual_calslew( imax, an, bn, U, vt, vddmax, capa+load, fin, F, t0);
1069 k4Q = stm_modscm_dual_get_k4Q( an, bn, vddin, fin, Ur, Fr, U, F, rbr, cbr, im, Fs, vddmax, rsat, rlin, rint, vint, vt );
1070 Q = stm_modscm_dual_get_Q( t0, k4Q, an, bn, vddin, fin, Ur, Fr, U, F, rbr, cbr, im, Fs, tm, vddmax, vt, rsat, rlin, rint, vint, fout, threshold );
1071 if( 2.0 * Q / vddmax < (capa+load) )
1072 capa -= 2.0 * Q / vddmax;
1073 }
1074
1075 vsat = vddmax ;
1076 fout = 0.0 ;
1077
1078 if( integnumeric==0 && rsat > 0.0 ) {
1079 rsatsep = vddmax/imax ;
1080 if( rsat > rsatsep && rsatsep > rlin ) {
1081 vsat = vddmax - ( imax - vddmax / rsat ) * rlin * rsat / ( rsat - rlin ) ;
1082 if( vsat < 0.0 || vsat > vddmax )
1083 vsat = vddmax ;
1084 else {
1085 fout = stm_modscm_dual_calslew( imax, an, bn, U, vt, vddmax, capa+load, fin, F, t0);
1086 }
1087 }
1088 }
1089
1090
1091 paramtiming->IMAX = imax ;
1092 paramtiming->AN = an ;
1093 paramtiming->BN = bn ;
1094 paramtiming->U = U ;
1095 paramtiming->CAPA = capa ;
1096 paramtiming->CAPA0 = capa0 ;
1097 paramtiming->CHALF = chalf ;
1098 paramtiming->F = F ;
1099 paramtiming->VT = vt ;
1100 paramtiming->VDDIN = vddin ;
1101 paramtiming->VDDMAX = vddmax ;
1102 paramtiming->CAPAI = capai ;
1103 paramtiming->FIN = fin ;
1104 paramtiming->VSAT = vsat ;
1105 paramtiming->VINT = vint ;
1106 paramtiming->RLIN = rlin ;
1107 paramtiming->RINT = rint ;
1108 paramtiming->RSAT = rsat ;
1109 paramtiming->FOUT = fout ;
1110 paramtiming->T0 = t0 ;
1111 paramtiming->TE = stm_modscm_dual_calte (vddin, vt, vt, fin) ;
1112 paramtiming->THRESHOLD = threshold ;
1113 paramtiming->RBR = rbr ;
1114 paramtiming->CBR = cbr ;
1115 paramtiming->QINIT = qinit ;
1116 paramtiming->INTEGNUMERIC = integnumeric ;
1117 paramtiming->DT = deltat ;
1118 paramtiming->QSAT_VE = -1.0 ;
1119 paramtiming->QSAT_TE = -1.0 ;
1120 paramtiming->QSAT_Q0 = -1.0 ;
1121 paramtiming->DTPWL = 0.0 ;
1122 for( n=0 ; n<4 ; n++ )
1123 paramtiming->CAPAIE[n] = capaie[n] ;
1124 for( n=0 ; n<3 ; n++ )
1125 paramtiming->VCAP[n] = vcap[n] ;
1126
1127 if( ! V_BOOL_TAB[ __STM_QSAT_ENHANCED ].VALUE
1128 && V_INT_TAB[ __STM_QSAT_LEVEL ].VALUE == 0 )
1129 paramtiming->COMPAT30P3 = 1 ;
1130 else
1131 paramtiming->COMPAT30P3 = 0 ;
1132 paramtiming->STRANS = strans ;
1133 paramtiming->ICF0 = icf0 ;
1134 }
1135
1136 double stm_modscm_dual_get_qsat2( stm_dual_param_timing *param, double seuil, double ceqrsat )
1137 {
1138 double qsat2 ;
1139 double tout ;
1140 double tst ;
1141 double dt ;
1142
1143 if( param->THRESHOLD > param->VT )
1144 tst = param->FOUT * atanh( (param->THRESHOLD-param->VT)/(param->VDDMAX-param->VT) ) ;
1145 else
1146 tst = param->FOUT * (param->THRESHOLD-param->VT)/(param->VDDMAX-param->VT) ;
1147
1148 dt = (param->T0-param->DTPWL)-tst; // Ecart entre le référentiel de l'entrée et de la sortie
1149
1150 if( seuil > param->VT )
1151 tout = param->FOUT * atanh( (seuil-param->VT)/(param->VDDMAX-param->VT) ) ;
1152 else
1153 tout = param->FOUT * (seuil-param->VT)/(param->VDDMAX-param->VT) ;
1154
1155 tout = tout + dt ;
1156
1157 switch( V_INT_TAB[ __STM_QSAT_LEVEL ].VALUE ) {
1158 case 1 :
1159 qsat2 = ceqrsat*seuil/(tout*tout) ;
1160 break ;
1161 case 2 :
1162 qsat2 = ceqrsat*seuil/((tout-param->DT)*(tout-param->DT)) ;
1163 break ;
1164 case 3 :
1165 qsat2 = ceqrsat*seuil/tout ;
1166 break ;
1167 default :
1168 qsat2 = 0.0 ;
1169 }
1170
1171 return qsat2 ;
1172 }
1173
1174 void evalnewslope( double vt,
1175 double vddin,
1176 double lt,
1177 double lvin,
1178 double t,
1179 double f,
1180 double dvin,
1181 double *dtnew,
1182 double *fnew,
1183 double *vin
1184 )
1185 {
1186 double vin0 ;
1187 double vinmin ;
1188 double t1 ;
1189 double t2 ;
1190 double v1 ;
1191 double v2 ;
1192 double k1 ;
1193 double k2 ;
1194 double fm ;
1195 double dtm ;
1196
1197 vin0 = vt + vddin*tanh(t/f) ;
1198
1199 /* compute minimal slope */
1200 // vinmin = lvin + (vin0-lvin)/100.0 ;
1201 fm = f*100.0 ;
1202 dtm = lt-fm*atanh((lvin-vt)/vddin);
1203 vinmin = vt+vddin*tanh((t-dtm)/fm);
1204
1205 *vin = vin0 - dvin ;
1206 if( *vin < vinmin ) {
1207 *vin = vinmin ;
1208 }
1209
1210 v1 = lvin ;
1211 t1 = lt ;
1212 v2 = *vin ;
1213 t2 = t ;
1214 k1 = atanh((v1-vt)/vddin);
1215 k2 = atanh((v2-vt)/vddin);
1216 *dtnew = (t2*k1-t1*k2)/(k1-k2);
1217 *fnew = (t1-t2)/(k1-k2);
1218 }
1219
1220 /* résolution de q(t)=c.vs+ci.vi+qinit */
1221 double stm_modscm_dual_calts_newctk( stm_dual_param_timing *param,
1222 double threshold,
1223 double capasup,
1224 newctktrace *debug
1225 )
1226 {
1227 /* general */
1228 double capa ;
1229 int onemoretime ;
1230 int findin ;
1231 int findout ;
1232 int ctk ;
1233
1234 /* debug related variables */
1235 static int fordebug=0 ;
1236 int iter;
1237 char* plotname=NULL ;
1238 FILE *file ;
1239 double dvpure=0.0 ;
1240
1241 /* input crosstalk parameter */
1242 double dvin ;
1243 double dvinr ;
1244 /* output slope parameter */
1245 double vout ;
1246 double lvout ;
1247 mbk_pwl *pwlout ;
1248 int n ;
1249 double tout ;
1250 /* interval parameter */
1251 double t ;
1252 double lt ;
1253 double dq ;
1254 double kin ;
1255 double kout ;
1256 int nin ;
1257 int nout ;
1258 double step ;
1259 double qt ;
1260 double qlt ;
1261 double qorg ;
1262 double ltfinal ;
1263 double dqfinal ;
1264 /* input slope parameter */
1265 double f ;
1266 double dt ;
1267 double fr ;
1268 double dtr ;
1269 double fnew ;
1270 double dtnew ;
1271 double frnew ;
1272 double dtrnew ;
1273 double ffinal ;
1274 double dtfinal ;
1275 double frfinal ;
1276 double dtrfinal ;
1277 double vin ;
1278 double vinr ;
1279 double lvin ;
1280 double lvinr ;
1281 double tin ;
1282
1283 fordebug++ ;
1284
1285 if( plotname ) {
1286 file = mbkfopen( plotname, "inout.dat", "w" );
1287 printf( "r = %g\n", param->DRIVER.r );
1288 printf( "ci = %g\n", param->DRIVER.c );
1289 printf( "cc = %g\n", param->CAPAI );
1290 }
1291 else
1292 file = NULL ;
1293
1294 /* general */
1295 capa = param->CAPA + capasup ;
1296
1297 /* interval parameter */
1298 n = V_INT_TAB[ __STM_INPUT_NB_PWL ].VALUE ;
1299 nin = 1 ;
1300 nout = 1 ;
1301 dq = 0.0 ;
1302
1303 /* output slope parameter */
1304 lvout = (-1.0/capa)*(param->CAPAI*param->VT+param->QINIT);
1305 lt = 0.0 ;
1306 pwlout = mbk_pwl_alloc_pwl( 2*((int)(n+0.5)) );
1307 pwlout->N = 0 ;
1308
1309 /* input slope parameter */
1310 f = param->FIN ;
1311 dt = 0.0 ;
1312 fr = param->F ;
1313 dtr = 0.0 ;
1314 lvin = param->VT ;
1315 lvinr = param->VT ;
1316 param->TIN = -1.0 ;
1317
1318 findin = 0 ;
1319 findout = 0 ;
1320 onemoretime = 1 ;
1321
1322 if( threshold <= lvin ) {
1323 param->TIN = f*(threshold-param->VT)/param->VDDIN ;
1324 findin = 1 ;
1325 }
1326
1327 ctk = 1 ;
1328 iter = 0 ;
1329
1330 do
1331 {
1332 iter++ ;
1333
1334 kin = ((double)nin) / ((double)n) ;
1335 kout = ((double)nout) / ((double)n) ;
1336
1337 /* working on interval [lt-t] */
1338
1339 if( nin == n && nout == n ) {
1340 printf( "oups (fordebug=%d, threshold=%g)!\n", fordebug, threshold );
1341 exit(1);
1342 }
1343
1344 /* compute t */
1345 if( nout < n ) {
1346 vout = kout*param->VDDMAX ;
1347 qorg = stm_get_q( param->IMAX, lt - dtr, fr, param->BN, param->U ) ;
1348 tout = stm_modscm_dual_calts_final( param->IMAX,
1349 param->AN,
1350 param->BN,
1351 param->U,
1352 vout,
1353 capa,
1354 fr,
1355 param->VT,
1356 param->VDDIN,
1357 param->CAPAI,
1358 param->FIN,
1359 dtr,
1360 param->QINIT + dq + qorg ,
1361 0.0,
1362 0.0,
1363 NULL
1364 )+dtr ;
1365 }
1366 else
1367 tout = FLT_MAX ;
1368
1369 if( nin < n ) {
1370 vin = param->VT+kin*param->VDDIN;
1371 tin = f*atanh((vin-param->VT)/param->VDDIN)+dt;
1372 }
1373 else
1374 tin = FLT_MAX ;
1375
1376 if( tin < tout ) {
1377 t = tin ;
1378 qt = stm_get_q( param->IMAX, t - dtr, fr, param->BN, param->U ) ;
1379 qorg = stm_get_q( param->IMAX, lt - dtr, fr, param->BN, param->U ) ;
1380 vout = 1.0/(capa/1000.0) * ( qt - qorg
1381 - (param->CAPAI/1000.0) * (param->VT+param->VDDIN*tanh(t/param->FIN))
1382 - param->QINIT
1383 - dq
1384 );
1385 step=1 ;
1386 }
1387 else {
1388 t = tout ;
1389 step = 2 ;
1390 }
1391
1392 if( nin < n && nout < n ) {
1393
1394 /* compute the input voltage variation caused by output voltage variation */
1395 pwlout->DATA[ pwlout->N ].X0 = lt ;
1396 pwlout->DATA[ pwlout->N ].A = (vout-lvout)/(t-lt) ;
1397 pwlout->DATA[ pwlout->N ].B = vout - pwlout->DATA[pwlout->N].A * t ;
1398 pwlout->X1 = t ;
1399 (pwlout->N)++ ;
1400
1401 dvin = stm_dv( t, pwlout, param->DRIVER.r, param->DRIVER.c/1000.0, param->CAPAI/1000.0 ) ;
1402 dvinr = dvin*param->U/param->VDDIN ;
1403
1404 /* compute the new f and dt for input */
1405 evalnewslope( param->VT, param->VDDIN, lt, lvin, t, f, dvin, &dtnew, &fnew, &vin );
1406
1407
1408 /* compute the new fr and dtr for input */
1409 evalnewslope( param->VT, param->U, lt, lvinr, t, fr, dvinr, &dtrnew, &frnew, &vinr );
1410
1411 /* compute charges at lt and t with frnew/dtrnew */
1412 qt = stm_get_q( param->IMAX, t - dtrnew, frnew, param->BN, param->U ) ;
1413 qlt = stm_get_q( param->IMAX, lt - dtrnew, frnew, param->BN, param->U ) ;
1414
1415 /* compute vout and the (dis)charge for this interval */
1416 vout = 1.0/(capa/1000.0) * ( qt
1417 - qlt
1418 - (param->CAPAI/1000.0) * (param->VT+param->VDDIN*tanh(t/param->FIN))
1419 - param->QINIT
1420 - dq
1421 );
1422 }
1423 else {
1424 fnew = f ;
1425 dtnew = dt ;
1426 frnew = fr ;
1427 dtrnew = dtr ;
1428 vout = FLT_MAX ;
1429 vin = FLT_MAX ;
1430 dvin = 0.0 ;
1431 dvinr = 0.0 ;
1432 }
1433
1434 if( vin > threshold && !findin ) {
1435 param->TIN = dtnew + fnew*atanh((threshold-param->VT)/param->VDDIN);
1436 findin = 1 ;
1437 }
1438
1439 if( vout > threshold && !findout ) {
1440 ffinal = fnew ;
1441 dtfinal = dtnew ;
1442 frfinal = frnew ;
1443 dtrfinal = dtrnew ;
1444 dqfinal = dq ;
1445 ltfinal = lt ;
1446 findout = 1 ;
1447 }
1448
1449 if( nin < n && nout < n ) {
1450 pwlout->DATA[ pwlout->N-1 ].A = (vout-lvout)/(t-lt) ;
1451 pwlout->DATA[ pwlout->N-1 ].B = vout - pwlout->DATA[pwlout->N-1].A * t ;
1452 }
1453
1454 /* prepare the next iteration : continue with FIN/F */
1455 if( nin < n ) {
1456 f = param->FIN ;
1457 dt = t - f*atanh((vin-param->VT)/param->VDDIN) ;
1458 fr = param->F ;
1459 //dtr = t - fr*atanh((vin*param->U/param->VDDIN-param->VT)/param->U) ;
1460 dtr = t - fr*atanh((vinr-param->VT)/param->U) ;
1461 }
1462
1463 if( step == 1 )
1464 nin++ ;
1465 else
1466 nout++ ;
1467
1468 if( file ) {
1469 double vin0 ;
1470 vin0 = param->VT + param->U*tanh(t/param->FIN);
1471 dvpure = dvpure + param->CAPAI/(param->CAPAI+param->DRIVER.c)*(vout-lvout);
1472 fprintf( file, "%g %g %g %g %g %g\n", t, vin0, vin, vout, dvin, dvpure );
1473 }
1474
1475 if( debug ) {
1476 if( param->EVTIN == 'U' ) {
1477 fprintf( debug->FIN, "%g %g\n", (t+debug->DT)*1e-12, vin );
1478 fprintf( debug->FOUT, "%g %g\n", (t+debug->DT)*1e-12, param->VDDMAX - vout );
1479 }
1480 else {
1481 fprintf( debug->FIN, "%g %g\n", (t+debug->DT)*1e-12, param->VDDMAX - vin );
1482 fprintf( debug->FOUT, "%g %g\n", (t+debug->DT)*1e-12, vout );
1483 }
1484 }
1485
1486 dq = dq + qlt - qt ;
1487 lt = t ;
1488 lvout = vout ;
1489 lvin = vin ;
1490 lvinr = vinr ;
1491
1492 if( findin && findout )
1493 onemoretime = 0 ;
1494 }
1495 while( onemoretime ) ;
1496
1497 /* qorg = qlt ? */
1498 qorg = stm_get_q( param->IMAX, ltfinal - dtrfinal, frfinal, param->BN, param->U ) ;
1499 t = stm_modscm_dual_calts_final( param->IMAX,
1500 param->AN,
1501 param->BN,
1502 param->U,
1503 threshold,
1504 capa,
1505 frfinal,
1506 param->VT,
1507 param->VDDIN,
1508 param->CAPAI,
1509 param->FIN,
1510 dtrfinal,
1511 param->QINIT + dqfinal + qorg,
1512 0.0,
1513 0.0,
1514 NULL
1515 )+dtrfinal ;
1516 param->VIN = param->VT + param->VDDIN*tanh((t-dtfinal)/ffinal );
1517
1518 if( !findin ) {
1519 param->TIN = dtfinal + ffinal*atanh((threshold-param->VT)/param->VDDIN);
1520 }
1521
1522 mbk_pwl_free_pwl( pwlout );
1523
1524 if( !finite( t ) || !finite( param->TIN ) ) {
1525 printf( "delay calculation error !!! (fordebug=%d,iter=%d)\n", fordebug,iter );
1526 exit(1);
1527 }
1528
1529 if( file )
1530 fclose( file );
1531
1532 return t ;
1533 }
1534
1535 double stm_modscm_dual_calts_with_param_timing_classic( stm_dual_param_timing *paramtiming, double threshold, stm_qsat_v *qsatv )
1536 {
1537 double tf ;
1538 double tsat ;
1539 double ceqrsat=0.0 ;
1540 double ceqrsat0=0.0 ;
1541 stm_qsat qsat ;
1542 double localthreshold ;
1543 char needceqrsat ;
1544
1545 if( threshold >= paramtiming->VSAT ) {
1546 localthreshold = paramtiming->VSAT ;
1547 needceqrsat = 1 ;
1548 }
1549 else {
1550 localthreshold = threshold ;
1551 needceqrsat = 0 ;
1552 }
1553
1554 /* pour assurer la compatibilité avec ancien modèle, on maintient le bug
1555 où l'on calcul ceqrsat à threshold, sans le borner par vsat */
1556 if( paramtiming->COMPAT30P3 /* && ! paramtiming->NEWCTKMODEL */ )
1557 stm_modscm_dual_calts_qsat( paramtiming, threshold, NULL, &qsat, &ceqrsat, needceqrsat ? &ceqrsat0 : NULL );
1558 else
1559 stm_modscm_dual_calts_qsat( paramtiming, localthreshold, qsatv, &qsat, &ceqrsat, needceqrsat ? &ceqrsat0 : NULL );
1560
1561
1562 if( paramtiming->NEWCTKMODEL )
1563 tf = stm_modscm_dual_calts_newctk( paramtiming, localthreshold, ceqrsat, NULL );
1564 else {
1565 TESTIM = paramtiming->T0 ;
1566 tf = stm_modscm_dual_calts( paramtiming->IMAX,
1567 paramtiming->AN,
1568 paramtiming->BN,
1569 paramtiming->U,
1570 localthreshold,
1571 paramtiming->CAPA+ceqrsat,
1572 paramtiming->F,
1573 paramtiming->DTPWL,
1574 paramtiming->VT,
1575 paramtiming->VDDIN,
1576 paramtiming->CAPAI,
1577 paramtiming->CAPAIE,
1578 paramtiming->VCAP,
1579 paramtiming->FIN,
1580 paramtiming->COMPAT30P3 ? paramtiming->PWTHSHRK : NULL,
1581 paramtiming->COMPAT30P3 ? paramtiming->NTHSHRK : 0,
1582 paramtiming->QINIT,
1583 paramtiming->STRANS,
1584 paramtiming->ICF0,
1585 &qsat
1586 );
1587 }
1588
1589 if( threshold > paramtiming->VSAT ) {
1590 tsat = tf ;
1591 /*
1592 tf = tsat - paramtiming->RLIN * paramtiming->CAPA/1000.0 *
1593 log( 1.0 - ( threshold - paramtiming->VSAT ) / ( paramtiming->VDDMAX - paramtiming->VSAT ) );
1594 */
1595 tf = tsat - paramtiming->RLIN * (paramtiming->CAPA+ceqrsat0+paramtiming->CAPAI)/1000.0 *
1596 log( 1.0 - ( threshold - paramtiming->VSAT ) / ( paramtiming->VDDMAX - paramtiming->VSAT ) );
1597 }
1598
1599 if( threshold > 0.0 )
1600 paramtiming->CEQRSAT = ceqrsat/1000.0 + stm_get_qsat(&qsat,tf)/threshold ;
1601 else
1602 paramtiming->CEQRSAT = 0.0 ;
1603
1604 return tf ;
1605 }
1606
1607 double stm_compute_vout( stm_dual_param_timing *param, double *t, double *vqsat, stm_qsat_v *qsat_enh )
1608 {
1609 double qsol ;
1610 double qtot ;
1611 double vout ;
1612 double vmin ;
1613 double vmax ;
1614 double ceqrsat ;
1615 stm_qsat qsat ;
1616 static int fordebug = 0 ;
1617
1618 fordebug++ ;
1619
1620 qsol = stm_get_q( param->IMAX, (*t - param->DTPWL), param->F, param->BN, param->U ) - (param->CAPAI/1000.0)*( param->VT + param->VDDIN*tanh(*t/param->FIN) ) - param->QINIT ;
1621
1622 /* toujours vrai */
1623 vmax = qsol/(param->CAPA/1000.0) ;
1624 if( vmax > param->VDDMAX )
1625 vmax = 0.999*param->VDDMAX ;
1626
1627 /* approximation */
1628 vmin = -((param->CAPAI/1000.0)*param->VT+param->QINIT)/(param->CAPA/1000.0) ;
1629
1630 if( vmin > vmax ) {
1631 vmin = vmax - param->VDDMAX/10.0 ;
1632 }
1633
1634 do {
1635 stm_modscm_dual_calts_qsat( param, vmin, qsat_enh, &qsat, &ceqrsat, NULL );
1636 qtot = ( (param->CAPA/1000.0) + (ceqrsat/1000.0) )*vmin + stm_get_qsat( &qsat, *t - param->DTPWL );
1637 if( qtot > qsol ) {
1638 vmin = vmin - param->VDDMAX/10.0 ;
1639 }
1640 }
1641 while( qtot > qsol );
1642
1643 do {
1644 vout = ( vmin + vmax ) / 2.0 ;
1645
1646 stm_modscm_dual_calts_qsat( param, vout, qsat_enh, &qsat, &ceqrsat, NULL );
1647 qtot = ( (param->CAPA/1000.0) + (ceqrsat/1000.0) )*vout + stm_get_qsat( &qsat, *t - param->DTPWL );
1648
1649 if( qtot > qsol )
1650 vmax = vout ;
1651 else
1652 vmin = vout ;
1653 }
1654 while( (vmax-vmin)>param->VDDMAX/1000.0 );
1655
1656 vout = ( vmin + vmax ) / 2.0 ;
1657
1658 if( vqsat ) {
1659 stm_modscm_dual_calts_qsat( param, vout, qsat_enh, &qsat, &ceqrsat, NULL );
1660 *vqsat = vout * ceqrsat/1000.0 + stm_get_qsat( &qsat, *t - param->DTPWL ) ;
1661 }
1662
1663 return vout ;
1664 }
1665
1666 double stm_compute_vout_old( stm_dual_param_timing *paramtiming, double *t, double *qsat, stm_qsat_v *qsat_enh )
1667 {
1668 double tmin, tmax ;
1669 double vmin, vmax ;
1670 double vout ;
1671 double tx ;
1672 int iter = 20 ;
1673
1674 vmin = 0.1*paramtiming->VDDMAX ;
1675 vmax = paramtiming->VSAT ;
1676 vout = -1.0 ;
1677
1678 tmin = stm_modscm_dual_calts_with_param_timing_classic( paramtiming, vmin, qsat_enh ) ;
1679
1680 if( tmin > *t ) {
1681
1682 *t = tmin ;
1683 vout = vmin ;
1684 if( qsat )
1685 *qsat = paramtiming->CEQRSAT * vout ;
1686
1687 }
1688 else {
1689
1690 tmax = stm_modscm_dual_calts_with_param_timing_classic( paramtiming, vmax, qsat_enh ) ;
1691
1692 if( tmax < *t ) {
1693
1694 vout = -1.0 ;
1695 if( qsat )
1696 *qsat = 0.0 ;
1697
1698 }
1699 else {
1700
1701 do {
1702 iter-- ;
1703
1704 vout = vmin + (*t-tmin)/(tmax-tmin)*(vmax-vmin) ;
1705 tx = stm_modscm_dual_calts_with_param_timing_classic( paramtiming, vout, qsat_enh ) ;
1706 if( tx < *t ) {
1707 tmin = tx ;
1708 vmin = vout ;
1709 }
1710 else {
1711 tmax = tx ;
1712 vmax = vout ;
1713 }
1714 }
1715 while( fabs(tx-*t) / *t > 0.01 && iter );
1716
1717 if( !iter ) {
1718 avt_log( LOGDEBUG, 1, "stm_compute_vout() : convergence failled\n" );
1719 }
1720
1721 *t = tx ;
1722 if( qsat )
1723 *qsat = paramtiming->CEQRSAT * vout ;
1724 }
1725 }
1726
1727 return vout ;
1728 }
1729
1730 void stm_modscm_dual_calts_qsat_v( stm_dual_param_timing *paramtiming, stm_qsat_v *qsat )
1731 {
1732 qsat->A = 1.0/(paramtiming->RSAT*(paramtiming->CAPA/1000.0));
1733 qsat->B = (paramtiming->IMAX-paramtiming->VDDMAX/paramtiming->RSAT)/(paramtiming->CAPA/1000.0) ;
1734 qsat->T0 = paramtiming->QSAT_TE-paramtiming->DTPWL + (1.0/qsat->A)*log((paramtiming->VDDMAX+qsat->B/qsat->A-paramtiming->QSAT_VE)/(paramtiming->VDDMAX+qsat->B/qsat->A));
1735 qsat->TS = paramtiming->QSAT_TE-paramtiming->DTPWL ;
1736 qsat->QSAT0 = paramtiming->QSAT_Q0 ;
1737 }
1738
1739 /* Calcule le modèle de charge de saturation. Rempli la structure qsat suivant la configuration. Si le modèle ceqrsat est retenu,
1740 qsat est configuré de façon à renvoyer 0.
1741 si le pointeur ceqrsat0 est défini, il contiendra le ceqrsat intermédiaire utilisé pour configurer qsat */
1742 void stm_modscm_dual_calts_qsat( stm_dual_param_timing *paramtiming,
1743 double threshold,
1744 stm_qsat_v *qsatv,
1745 stm_qsat *qsat,
1746 double *ceqrsat,
1747 double *ceqrsat0
1748 )
1749 {
1750 double qsat2 ;
1751
1752 if( qsat ) {
1753 qsat->QSAT2 = 0.0 ;
1754 qsat->DT = 0.0 ;
1755 qsat->TSATMAX = 0.0 ;
1756 }
1757 if( ceqrsat )
1758 *ceqrsat = 0.0 ;
1759
1760 if( threshold >= paramtiming->VDDMAX ) {
1761 avt_log( LOGDEBUG, 1, "stm_modscm_dual_calts_qsat() : threshold exceed vdd. set to vdd\n" );
1762 threshold = 0.999*paramtiming->VDDMAX ;
1763 }
1764
1765 if( threshold > 0.0 ) {
1766
1767 if( qsat )
1768 qsat->QSATV = qsatv ;
1769
1770 if( paramtiming->COMPAT30P3 ) {
1771
1772 if( V_BOOL_TAB[ __STM_CEQRSAT_NUMERIC].VALUE ) {
1773 if( ceqrsat )
1774 *ceqrsat = stm_modscm_dual_ceqrsat_numeric( paramtiming, threshold );
1775 }
1776 else {
1777 if( ceqrsat )
1778 *ceqrsat = stm_modscm_dual_ceqrsat( paramtiming->IMAX,
1779 paramtiming->VT,
1780 paramtiming->VDDMAX,
1781 paramtiming->FOUT,
1782 paramtiming->U,
1783 paramtiming->F,
1784 paramtiming->RSAT,
1785 paramtiming->RLIN,
1786 paramtiming->AN,
1787 paramtiming->BN,
1788 threshold,
1789 paramtiming->THRESHOLD,
1790 paramtiming->TE,
1791 paramtiming->T0-paramtiming->DTPWL
1792 );
1793 }
1794 if( ceqrsat0 )
1795 *ceqrsat0 = *ceqrsat ;
1796 }
1797 else {
1798
1799 if( threshold > 0.0 && paramtiming->RSAT && ( !qsat->QSATV || ceqrsat0 ) ) {
1800
1801 if( V_BOOL_TAB[ __STM_CEQRSAT_NUMERIC].VALUE ) {
1802
1803 *ceqrsat = stm_modscm_dual_ceqrsat_numeric( paramtiming, threshold );
1804
1805 }
1806 else {
1807
1808 if( ceqrsat )
1809 *ceqrsat = stm_modscm_dual_ceqrsat( paramtiming->IMAX,
1810 paramtiming->VT,
1811 paramtiming->VDDMAX,
1812 paramtiming->FOUT,
1813 paramtiming->U,
1814 paramtiming->F,
1815 paramtiming->RSAT,
1816 paramtiming->RLIN,
1817 paramtiming->AN,
1818 paramtiming->BN,
1819 threshold,
1820 paramtiming->THRESHOLD,
1821 paramtiming->TE,
1822 paramtiming->T0-paramtiming->DTPWL
1823 );
1824 }
1825
1826 if( ceqrsat0 )
1827 *ceqrsat0 = *ceqrsat ;
1828
1829 if( V_INT_TAB[ __STM_QSAT_LEVEL ].VALUE == 1 ||
1830 V_INT_TAB[ __STM_QSAT_LEVEL ].VALUE == 2 ||
1831 V_INT_TAB[ __STM_QSAT_LEVEL ].VALUE == 3 ) {
1832
1833 qsat2 = stm_modscm_dual_get_qsat2( paramtiming, threshold, (*ceqrsat)/1000.0 );
1834
1835 if( qsat2 > 0.0 ) {
1836 *ceqrsat = 0.0 ;
1837 }
1838 }
1839 else
1840 qsat2 = 0.0 ;
1841
1842 if( qsat->QSATV )
1843 if( ceqrsat )
1844 *ceqrsat = 0.0 ;
1845
1846 if( qsat ) {
1847 qsat->QSAT2 = qsat2 ;
1848 qsat->DT = paramtiming->DT ;
1849 qsat->TSATMAX = paramtiming->IMAX/(2.0*qsat2);
1850 }
1851 }
1852 }
1853 }
1854 else {
1855 if( qsat )
1856 qsat->QSATV = NULL ;
1857 }
1858
1859 if( qsat ) {
1860 qsat->IMAX = paramtiming->IMAX ;
1861 qsat->C = (paramtiming->CAPA+*ceqrsat)/1000.0 ;
1862 qsat->VDD = paramtiming->VDDMAX ;
1863 }
1864 }
1865
1866 double stm_modscm_dual_calts_qbranch( stm_dual_param_timing *param, stm_qsat_v *qsatv, double vout, double t )
1867 {
1868 double q ;
1869 stm_qsat qsat ;
1870 double vqsat ;
1871 double qbr ;
1872 double ceqrsat ;
1873
1874 q = stm_get_q( param->IMAX, t, param->F, param->BN, param->U );
1875 stm_modscm_dual_calts_qsat( param, vout, qsatv, &qsat, &ceqrsat, NULL );
1876 vqsat = stm_get_qsat( &qsat, t ) + ceqrsat*vout/1000.0 ;
1877
1878 qbr = q - vqsat ;
1879
1880 return qbr ;
1881 }
1882
1883 double stm_modscm_dual_calts_with_param_timing( stm_dual_param_timing *paramtiming, double threshold )
1884 {
1885 double tf ;
1886 double te ;
1887 double vout_enh ;
1888 stm_qsat_v qsat ;
1889 stm_qsat_v *ptqsat ;
1890 double vqsat ;
1891 int computed = 0 ;
1892 static int fordebug = 0 ;
1893 double vout ;
1894 double lvout ;
1895 double q ;
1896 double backup_f ;
1897 double backup_dtpwl ;
1898 double backup_qinit ;
1899 double tiabs ;
1900 double ltiabs ;
1901 double localthreshold ;
1902 int i ;
1903
1904 fordebug++;
1905
1906 if( threshold >= paramtiming->VSAT ) {
1907 localthreshold = paramtiming->VSAT ;
1908 }
1909 else {
1910 localthreshold = threshold ;
1911 }
1912
1913 if( paramtiming->NTHSHRK && !paramtiming->COMPAT30P3 ) {
1914
1915 q = 0.0 ;
1916 ltiabs = 0.0 ;
1917 lvout = 0.0 ;
1918
1919 backup_f = paramtiming->F ;
1920 backup_dtpwl = paramtiming->DTPWL ;
1921 backup_qinit = paramtiming->QINIT ;
1922
1923 for( i=0 ; i<paramtiming->NTHSHRK ; i++) {
1924
1925 ptqsat = NULL ;
1926
1927 if( V_BOOL_TAB[ __STM_QSAT_ENHANCED ].VALUE )
1928 te = paramtiming->PWTHSHRK[i].F * atanh( V_FLOAT_TAB[ __STM_QSAT_RATIO ].VALUE ) + paramtiming->PWTHSHRK[i].DT ;
1929 else
1930 te = FLT_MAX ;
1931
1932 if( i==paramtiming->NTHSHRK-1 )
1933 tiabs = FLT_MAX*0.9 ; /* to be sure to get a good comparison with te */
1934 else
1935 tiabs = paramtiming->PWTHSHRK[i].T+paramtiming->PWTHSHRK[i].DT ;
1936
1937 paramtiming->F = paramtiming->PWTHSHRK[i].F ;
1938 paramtiming->DTPWL = paramtiming->PWTHSHRK[i].DT ;
1939
1940 stm_estim_output( paramtiming, ltiabs, lvout );
1941
1942 /* calcule de la charge initiale de l'intervalle courant. le modèle enhanced n'est activé
1943 que sur l'intervalle courant, pas avant */
1944 if( i > 0 )
1945 q = q - stm_modscm_dual_calts_qbranch( paramtiming, NULL, lvout, paramtiming->PWTHSHRK[i-1].T+paramtiming->PWTHSHRK[i-1].DT-paramtiming->PWTHSHRK[i].DT ) ;
1946 paramtiming->QINIT = backup_qinit - q ;
1947
1948 if( te < tiabs ) {
1949
1950 /* détermination de la tension de sortie à partir de laquelle on utilise le modèle enhanced */
1951 if( i>0 && te < paramtiming->PWTHSHRK[i-1].T+paramtiming->PWTHSHRK[i-1].DT )
1952 te = paramtiming->PWTHSHRK[i-1].T+paramtiming->PWTHSHRK[i-1].DT ;
1953 vout_enh = stm_compute_vout( paramtiming, &te, &vqsat, NULL );
1954
1955 if( localthreshold < vout_enh ) {
1956 break ;
1957 }
1958 else {
1959 /* il faut calculer les paramètres enhanced avant le calcul de la charge initiale car ce modèle
1960 peut se déclencher avant l'intervalle courant */
1961 paramtiming->QSAT_TE = te ;
1962 paramtiming->QSAT_VE = vout_enh ;
1963 paramtiming->QSAT_Q0 = vqsat ;
1964 stm_modscm_dual_calts_qsat_v( paramtiming, &qsat );
1965 ptqsat = &qsat ;
1966
1967 /* détermination de la tension de sortie à la fin de l'intervalle courant */
1968 if( i==paramtiming->NTHSHRK-1 )
1969 vout = paramtiming->VDDMAX ;
1970 else
1971 vout = stm_compute_vout( paramtiming, &tiabs, NULL, ptqsat );
1972 if( localthreshold < vout ) {
1973 break ;
1974 }
1975 }
1976 }
1977 else {
1978
1979 /* détermination de la tension de sortie à la fin de l'intervalle courant */
1980 if( i==paramtiming->NTHSHRK-1 )
1981 vout = paramtiming->VDDMAX ;
1982 else
1983 vout = stm_compute_vout( paramtiming, &tiabs, NULL, NULL );
1984 if( localthreshold < vout ) {
1985 break ;
1986 }
1987 }
1988
1989 if( i==paramtiming->NTHSHRK-1 )
1990 avt_log( LOGDEBUG, 1, "stm_modscm_dual_calts_with_param_timing() : last iteration\n" );
1991
1992 q = q + stm_modscm_dual_calts_qbranch( paramtiming, ptqsat, vout, paramtiming->PWTHSHRK[i].T ) ;
1993 lvout = vout ;
1994 ltiabs = tiabs ;
1995 }
1996
1997 paramtiming->QINIT = backup_qinit - q ;
1998 tf = stm_modscm_dual_calts_with_param_timing_classic( paramtiming, threshold, ptqsat );
1999 tf = tf + paramtiming->PWTHSHRK[i].DT ;
2000
2001 paramtiming->F = backup_f ;
2002 paramtiming->DTPWL = backup_dtpwl ;
2003 paramtiming->QINIT = backup_qinit ;
2004
2005 }
2006 else {
2007
2008 if( V_BOOL_TAB[ __STM_QSAT_ENHANCED ].VALUE ) {
2009
2010 if( paramtiming->QSAT_TE < 0.0 ) {
2011 // instant when the input reach x% of vddin.
2012 te = paramtiming->FIN * atanh( V_FLOAT_TAB[ __STM_QSAT_RATIO ].VALUE ) ;
2013 vout_enh = stm_compute_vout( paramtiming, &te, &vqsat, NULL );
2014 if( vout_enh < paramtiming->VSAT ) {
2015 paramtiming->QSAT_TE = te ;
2016 paramtiming->QSAT_VE = vout_enh ;
2017 paramtiming->QSAT_Q0 = vqsat ;
2018 }
2019 }
2020
2021 if( paramtiming->QSAT_VE > 0.0 && threshold > paramtiming->QSAT_VE ) {
2022 stm_modscm_dual_calts_qsat_v( paramtiming, &qsat );
2023 tf = stm_modscm_dual_calts_with_param_timing_classic( paramtiming, threshold, &qsat );
2024 computed = 1 ;
2025 }
2026 }
2027
2028 if( !computed )
2029 tf = stm_modscm_dual_calts_with_param_timing_classic( paramtiming, threshold, NULL );
2030 }
2031
2032 return tf ;
2033 }
2034
2035 /* Renvoie 0 pour le modèle enhanced. Le tsatmax n'est pas pris en compte. */
2036 double stm_get_qsat_derivative( stm_qsat *qsat, double t )
2037 {
2038 double dq ;
2039
2040 if( qsat && t > 0.0 ) {
2041
2042 if( qsat->QSATV ) {
2043 dq = 0.0 ;
2044 }
2045 else {
2046 switch( V_INT_TAB[ __STM_QSAT_LEVEL ].VALUE ) {
2047
2048 case 1 :
2049 case 2 :
2050 dq = 2.0 * qsat->QSAT2 * t ;
2051 break ;
2052
2053 default :
2054 dq = 0.0 ;
2055 }
2056 }
2057 }
2058 else
2059 dq = 0.0 ;
2060
2061 return dq ;
2062 }
2063
2064 inline double stm_get_qsat( stm_qsat *qsat, double t )
2065 {
2066 double q = 0.0 ;
2067 double vi ;
2068 double vf ;
2069 double a ;
2070 double b ;
2071 double c ;
2072 double t0 ;
2073 double ts ;
2074 double vdd ;
2075 double qsat0 ;
2076
2077 if( qsat ) {
2078 if( qsat->QSATV ) {
2079
2080 a = qsat->QSATV->A ;
2081 b = qsat->QSATV->B ;
2082 t0 = qsat->QSATV->T0 ;
2083 ts = qsat->QSATV->TS ;
2084 qsat0 = qsat->QSATV->QSAT0 ;
2085 vdd = qsat->VDD ;
2086 c = qsat->C ;
2087
2088 if( t > ts ) {
2089 vf = vdd-(exp(-a*(t-t0))*(vdd+b/a)-b/a) ;
2090 vi = vdd-(exp(-a*(ts-t0))*(vdd+b/a)-b/a) ;
2091 q = qsat->IMAX*(t-ts) - c*(vf-vi) + qsat0 ;
2092 }
2093 else
2094 q = qsat0 ;
2095 }
2096 else {
2097 if( t > 0.0 ) {
2098 switch( V_INT_TAB[ __STM_QSAT_LEVEL ].VALUE ) {
2099
2100 case 0 :
2101 q = 0.0 ;
2102 break ;
2103
2104 case 1 :
2105 if( t>qsat->TSATMAX )
2106 q = qsat->QSAT2*qsat->TSATMAX*qsat->TSATMAX ;
2107 else
2108 q = qsat->QSAT2*t*t ;
2109 break ;
2110
2111 case 2 :
2112 if( t>qsat->TSATMAX )
2113 q = qsat->QSAT2*(qsat->TSATMAX-qsat->DT)*(qsat->TSATMAX-qsat->DT) ;
2114 else
2115 q = qsat->QSAT2*(t-qsat->DT)*(t-qsat->DT) ;
2116 break ;
2117
2118 case 3 :
2119 q = qsat->QSAT2*t ;
2120 }
2121 }
2122 }
2123 }
2124
2125 return q ;
2126 }
2127
2128 /****************************************************************************/
2129
2130 double stm_modscm_dual_calculduts_threshold (dualparams *params, float slew, float load, double seuil, stm_pwl *pwl)
2131 {
2132 double cconf;
2133 double capa, capa0;
2134 double pconf0 = (double)params->DP[STM_PCONF0];
2135 double pconf1 = (double)params->DP[STM_PCONF1];
2136 double capai = (double)params->DP[STM_CAPAI];
2137 double irap = (double)params->DP[STM_IRAP];
2138 double vddin = (double)params->DP[STM_VDDIN];
2139 double vt = (double)params->DP[STM_VT];
2140 double threshold = (double)params->DP[STM_THRESHOLD];
2141 double input_thr = (double)params->DP[STM_INPUT_THR];
2142 double imax = (double)params->DP[STM_IMAX];
2143 double an = (double)params->DP[STM_AN];
2144 double bn = (double)params->DP[STM_BN];
2145 double delayrc = (double)params->DP[STM_DRC];
2146 double rbr = (double)params->DP[STM_RBR];
2147 double cbr = (double)params->DP[STM_CBR];
2148 double rsat = (double)params->DP[STM_RSAT];
2149 double rlin = (double)params->DP[STM_RLIN];
2150 double rint = (double)params->DP[STM_RINT];
2151 double vint = (double)params->DP[STM_VINT];
2152 double vddmax = (double)params->DP[STM_VDDMAX];
2153 double fout ;
2154 double ts;
2155 double deltat;
2156 double U, F, Ur, Fr, im, Fs, tm, Fm, k4Q, t0, Q, te, koshoot;
2157 char *str;
2158 /*double overshoot = (vt + (vddmax - vt) / 3.0)/vddmax ;*/
2159
2160 if( pconf1*slew < 10.0*load )
2161 pconf1 = 1.2 * pconf1 ;
2162
2163 if ((str = avt_gethashvar ("STM_TRACE_MODE")))
2164 if (!strcmp (str, "yes")) {
2165 fprintf (stdout, "pconf0 = %f\n", pconf0);
2166 fprintf (stdout, "pconf1 = %f\n", pconf1);
2167 fprintf (stdout, "capai = %f\n", capai);
2168 fprintf (stdout, "irap = %f\n", irap);
2169 fprintf (stdout, "vddin = %f\n", vddin);
2170 fprintf (stdout, "vt = %f\n", vt);
2171 fprintf (stdout, "threshold = %f\n", threshold);
2172 fprintf (stdout, "imax = %f\n", imax);
2173 fprintf (stdout, "an = %f\n", an);
2174 fprintf (stdout, "bn = %f\n", bn);
2175 fprintf (stdout, "\n");
2176 }
2177
2178
2179 /* slew : front d'entrée réel original.
2180 Fr : front d'entrée rapporté sans prendre en compte le cbr.
2181 Fs : instant où on considère que le courant atteint imax.
2182 Fm : front d'entrée réel prenant en compte le cbr.
2183 F : front d'entrée rapporté prenant en compte cbr.
2184
2185 Les équations de courant instantané sont :
2186
2187 Le courant avec prise en compte explicite de rbr, cbr :
2188
2189 stm_modscm_dual_get_ir( t, A, B, Vin, Fin, Ur, Fr, rbr, cbr, imax, Fs) <--- eqt approchée
2190
2191 Le courant équivalent :
2192
2193 stm_modscm_dual_get_ia( t, A, B, Ua, Fa )
2194 */
2195
2196
2197 /* A décommenter pour revenir à l'ancienne version */
2198 /* rbr=-1.0 ; cbr = -1.0 ; */
2199
2200 if((rbr > 0.0) && (cbr > 0.0)){
2201 /* Determine une approximation du courant dans la branche complète. Cela revient
2202 à la méthode Amjad : an et bn sont les paramètres équivalent à la branche vers
2203 la source, et U et Fr sont les paramètres rapportés équivalent à la branche vers
2204 le drain.
2205 */
2206 stm_modscm_dual_cal_UF (imax, an, bn, vddin, 0.0, (double)slew, &Ur, &Fr);
2207 stm_modscm_dual_slopei(0.7, bn, Ur, imax, Fr, rsat, vddmax, vddmax, &im, &Fs);
2208
2209 /* Calcule la modification du front d'entrée. */
2210 stm_modscm_dual_modifslope( vddin, vt, slew, vddmax, rbr, cbr, im, Fs, &tm, &Fm);
2211 }
2212 else {
2213 Fm = (double)slew;
2214 }
2215
2216 /* Calcule le front d'entrée rapporté. */
2217 stm_modscm_dual_cal_UF (imax, an, bn, vddin, 0.0, Fm, &U, &F);
2218
2219 koshoot = 0.0 ;
2220 if((capai > 0.00) && (capai/(load + (pconf0 + pconf1 * slew) * irap) > STM_OVERSHOOT)){
2221 deltat = stm_modscm_dual_calts (imax, an, bn, U, threshold, 0.0, F, 0.0, vt, vddin, capai, NULL, NULL, slew, NULL, 0, 0.0, 0.0, 0.0, NULL );
2222 te = stm_modscm_dual_calte (vddin, vt, input_thr, (double)slew);
2223 koshoot = ( deltat/te ) * (deltat/te );
2224 }else{
2225 deltat = 0.0;
2226 }
2227 deltat += delayrc ;
2228 if( koshoot < 1.0 )
2229 cconf = pconf0 + pconf1 * slew *( 1.0 - koshoot );
2230 else
2231 cconf = pconf0;
2232 capa0 = cconf * irap + (double)load;
2233 t0 = stm_modscm_dual_calts (imax, an, bn, U, threshold, capa0, F, 0.0, vt, vddin, capai, NULL, NULL, slew, NULL, 0, 0.0, 0.0, 0.0, NULL );
2234 capa = capa0 ;
2235
2236
2237 if((rbr > 0.0) && (cbr > 0.0)){
2238 // Calcule de la charge supplémentaire due à l'overshoot
2239 fout = stm_modscm_dual_calslew( imax, an, bn, U, vt, vddmax, capa, slew, F, t0);
2240 k4Q = stm_modscm_dual_get_k4Q( an, bn, vddin, slew, Ur, Fr, U, F, rbr, cbr, im, Fs, vddmax, rsat, rlin, rint, vint, vt );
2241 Q = stm_modscm_dual_get_Q( t0, k4Q, an, bn, vddin, slew, Ur, Fr, U, F, rbr, cbr, im, Fs, tm, vddmax, vt, rsat, rlin, rint, vint, fout, threshold );
2242 if( 2.0 * Q / vddmax < capa )
2243 capa -= 2.0 * Q / vddmax;
2244 }
2245 if( rsat <= 0.0 )
2246 ts = stm_modscm_dual_calts (imax, an, bn, U, seuil, capa, F, 0.0, vt, vddin, capai, NULL, NULL, slew, NULL, 0, 0.0, 0.0, 0.0, NULL );
2247 else {
2248 ts = stm_modscm_dual_calts_rsat_full_range(capai, imax, an, bn, U, vt, vddmax, threshold, seuil, rsat, rlin, capa, slew, F, stm_modscm_dual_calte (vddin, vt, vt, (double)slew), t0, vddin, pwl );
2249 }
2250
2251 return (ts);
2252 }
2253
2254 /****************************************************************************/
2255
2256 float stm_modscm_dual_slope (dualparams *params, float slew, float load)
2257 {
2258 double cconf;
2259 double capa;
2260 double pconf0 = (double)params->DP[STM_PCONF0];
2261 double pconf1 = (double)params->DP[STM_PCONF1];
2262 double capai = (double)params->DP[STM_CAPAI];
2263 double irap = (double)params->DP[STM_IRAP];
2264 double vddin = (double)params->DP[STM_VDDIN];
2265 double vt = (double)params->DP[STM_VT];
2266 double threshold = (double)params->DP[STM_THRESHOLD];
2267 double imax = (double)params->DP[STM_IMAX];
2268 double an = (double)params->DP[STM_AN];
2269 double bn = (double)params->DP[STM_BN];
2270
2271 if( pconf1*slew < 10.0*load )
2272 pconf1 = 1.2 * pconf1 ;
2273
2274 cconf = pconf0 + pconf1 * slew;
2275 capa = capai + cconf * irap;
2276 capa += (double)load;
2277
2278 return (float)stm_modscm_dual_calslope (imax, an, bn, vddin, vt, threshold, capa, (double)slew);
2279 }
2280
2281 /****************************************************************************/
2282
2283 void stm_modscm_dual_timing( dualparams *params,
2284 float fin,
2285 stm_pwl *pwlin,
2286 stm_driver *driver,
2287 float r,
2288 float c1,
2289 float c2,
2290 float *delay,
2291 float *fout,
2292 stm_pwl **pwlout,
2293 char *modelname
2294 )
2295 {
2296 stm_dual_param_timing paramtiming ;
2297 float threshold = params->DP[STM_THRESHOLD] ;
2298 float vddin = params->DP[STM_VDDIN] ;
2299 float vt = params->DP[STM_VT] ;
2300 float input_thr = params->DP[STM_INPUT_THR] ;
2301 float delayrc = params->DP[STM_DRC] ;
2302 float vdd = params->DP[STM_VDDMAX];
2303 stm_pwth pwthin[10] ;
2304 int nthin;
2305 stm_pwth *ptthin ;
2306 float s1old ;
2307 float s1new ;
2308 float s2old ;
2309 float s2new ;
2310 float seuil1 ;
2311 float seuil2 ;
2312 float ts;
2313 float ts1 ;
2314 float ts2 ;
2315 float te ;
2316 int oldmode=0 ;
2317 paramforslewpwl parampwltanh;
2318 mbk_pwl *mbkpwlout;
2319 static int fordebug=0 ;
2320 int indextime ;
2321 int indexslope1 ;
2322 int indexslope2 ;
2323 float tabvout[5];
2324 float tabtin[5];
2325 float tabt[5];
2326 int nbval;
2327 int i;
2328 float load;
2329 float capa;
2330 float capa0;
2331
2332
2333 fordebug++;
2334
2335 if( r>0 && c2>0.0 )
2336 load = stm_modscm_dual_capaeq (params, NULL, fin, r, c1, c2, threshold, modelname );
2337 else
2338 load = c1 ;
2339
2340 stm_modscm_dual_fill_param( params, fin, pwlin, driver, load, &paramtiming ) ;
2341 nbval = 0 ;
2342
2343 if( delay ) {
2344 indextime = nbval ;
2345 tabvout[nbval] = threshold ;
2346 nbval++ ;
2347 }
2348
2349 if( fout ) {
2350
2351 if( !oldmode ) {
2352
2353 s1old = vt ;
2354 s1new = 0.3*vdd ;
2355
2356 s2old = 0.75 * (vdd-vt) + vt ;
2357 s2new = 0.8*vdd ;
2358
2359 if( s1old > s1new ) seuil1 = s1old ; else seuil1 = s1new ;
2360 if( s2old > s2new ) seuil2 = s2old ; else seuil2 = s2new ;
2361
2362 if( V_BOOL_TAB[ __STM_NEW_THRESHOLD ].VALUE ) {
2363 seuil1 = vdd * STM_DEFAULT_SMINR ;
2364 seuil2 = vdd * STM_DEFAULT_SMAXR ;
2365 }
2366
2367 indexslope1 = nbval ;
2368 tabvout[nbval] = seuil1 ;
2369 nbval++ ;
2370 indexslope2 = nbval ;
2371 tabvout[nbval] = seuil2 ;
2372 nbval++ ;
2373 }
2374 }
2375
2376 capa = paramtiming.CAPA ;
2377 capa0 = paramtiming.CAPA0 ;
2378
2379 if( paramtiming.INTEGNUMERIC ) {
2380 paramtiming.CAPA = capa + load ;
2381 paramtiming.CAPA0 = capa0 + load ;
2382 stm_modscm_dual_calts_final_numeric( &paramtiming, tabvout, tabt, nbval );
2383 }
2384 else {
2385 if( V_BOOL_TAB[ __AVT_NUMSOL_FOR_PILOAD ].VALUE && c2>0 && r>0.0 ) {
2386 stm_modscm_dual_calts_final_numeric_pi( &paramtiming, r, c1, c2, tabvout, tabt, nbval );
2387 }
2388 else {
2389 for( i=0 ; i<nbval ; i++ ) {
2390 if( r > 0.0 && c2 > 0.0 ) {
2391 paramtiming.CAPA = capa ;
2392 load = stm_modscm_dual_capaeq (params, &paramtiming, fin, r, c1, c2, tabvout[i], modelname );
2393 }
2394 paramtiming.CAPA = capa + load ;
2395 paramtiming.CAPA0 = capa0 + load ;
2396 tabt[i] = stm_modscm_dual_calts_with_param_timing( &paramtiming, tabvout[i] ) ;
2397 if( paramtiming.NEWCTKMODEL )
2398 tabtin[i] = paramtiming.TIN ;
2399 }
2400 }
2401 }
2402
2403 paramtiming.CAPA = capa ;
2404 paramtiming.CAPA0 = capa0 ;
2405
2406 if( delay ) {
2407
2408 ts = tabt[ indextime ] ;
2409
2410 ptthin = NULL ;
2411 if( pwlin ) {
2412 if( stm_pwl_to_tanh( pwlin, vt, vddin+vt, pwthin, &nthin, fin ) )
2413 ptthin = pwthin ;
2414 }
2415
2416 if( ptthin )
2417 te = stm_get_t_pwth( vddin, vt, input_thr, ptthin );
2418 else {
2419 if( paramtiming.NEWCTKMODEL )
2420 te = tabtin[ indextime ] ;
2421 else
2422 te = stm_modscm_dual_calte( vddin, vt, input_thr, fin );
2423 }
2424
2425 *delay = ts - te + delayrc ;
2426
2427 }
2428
2429 if( fout ) {
2430 if( oldmode ) {
2431 *fout = stm_modscm_dual_slew_old( params, fin, load );
2432 }
2433 else {
2434
2435 ts1 = tabt[ indexslope1 ] ;
2436 ts2 = tabt[ indexslope2 ] ;
2437
2438 if( ts2-ts1 > 0.0 ) {
2439 *fout = stm_thr2scm( ts2-ts1,
2440 seuil1/vdd,
2441 seuil2/vdd,
2442 vt,
2443 vdd,
2444 vdd,
2445 STM_UP
2446 );
2447
2448 if( pwlout ) {
2449
2450 parampwltanh.DUALSCM = &paramtiming;
2451
2452 mbkpwlout = mbk_create_pwl_according_tanh( (char (*)(void*, float, float*))stm_modscm_dual_slew_for_pwl,
2453 (void*)&parampwltanh,
2454 vt, 0.95*vdd );
2455 *pwlout = mbk_pwl_to_stm_pwl( mbkpwlout );
2456 mbk_pwl_free_pwl( mbkpwlout );
2457 }
2458 }
2459 else {
2460 *fout = fin ;
2461 }
2462 }
2463 }
2464 }
2465
2466 /****************************************************************************/
2467
2468 float stm_modscm_dual_delay (dualparams *params, float slew, stm_pwl *pwl, float load)
2469 {
2470 double vddin = (double)params->DP[STM_VDDIN];
2471 double vt = (double)params->DP[STM_VT];
2472 double input_thr = (double)params->DP[STM_INPUT_THR];
2473 double delayrc = (double)params->DP[STM_DRC];
2474 double te;
2475 double ts;
2476 stm_pwth pwth[10] ;
2477 int nth ;
2478
2479 if( pwl ) {
2480 if( stm_pwl_to_tanh( pwl, vt, vddin+vt, pwth, &nth, slew ) )
2481 te = stm_get_t_pwth( vddin, vt, input_thr, pwth );
2482 else
2483 te = stm_modscm_dual_calte (vddin, vt, input_thr, (double)slew);
2484 }
2485 else
2486 te = stm_modscm_dual_calte (vddin, vt, input_thr, (double)slew);
2487
2488 ts = stm_modscm_dual_calculduts (params, slew, load, pwl);
2489
2490 return (float)(ts - te + delayrc);
2491 }
2492
2493 /****************************************************************************/
2494
2495 double stm_modscm_dual_calte (double vddin, double VT, double seuil, double fin)
2496 {
2497 double te;
2498
2499 if( seuil > VT )
2500 te = fin * atanh((seuil-VT)/(vddin)) ;
2501 else
2502 te = fin * (seuil-VT)/(vddin) ;
2503
2504 return te;
2505 }
2506
2507 /****************************************************************************/
2508 double stm_modscm_dual_calts_old (double imax,
2509 double an,
2510 double bn,
2511 double U,
2512 double seuil,
2513 double c,
2514 double F)
2515 {
2516 double an1,
2517 bn1,
2518 /* rc, */
2519 sf,
2520 b = 0.0,
2521 z = 0.0,
2522 tt = 0.0,
2523 ttt = 0.0,
2524 /* k = 0.0, */
2525 ti = 0.0,
2526 tmin = 0.0,
2527 tmax = 0.0,
2528 tint = 0.0,
2529 Qmin = 0.0,
2530 Qmax = 0.0,
2531 Qi = 0.0,
2532 BU = bn * U,
2533 BU2 = BU * BU,
2534 c1 = 0.0;
2535 long i = 0, j = 0;
2536 float ltt;
2537
2538 /* calcul de la tension rapportée à partir de :
2539
2540 an.U²
2541 imax = ------
2542 1+bn.U
2543 */
2544
2545 if((U <= 0.0)||(F <= 0.0))
2546 return 0.0;
2547 an1 = an / bn;
2548 bn1 = 1 / (U * bn);
2549 c1 = c;
2550
2551 /* Dans ce qui suit, on a un changement de variable t = t/F
2552
2553 Résolution de :
2554
2555 ( ln(2).b²u²-ln(1+b.u) )
2556 imax.( f.t - f.-------------------- )
2557 ( b²u²-b.u )
2558
2559 ( ( 1-b.u ) )
2560 ( ln( 1 + -----.exp(-2t) ) )
2561 ( ( 1+b.u ) ( 1 ) )
2562 + f.imax.( ------------------------ + ( 1 + --- ).ln( 1+exp(-2t) ) )
2563 ( b²u² - b.u ( b.u ) )
2564
2565 = c.seuil
2566
2567
2568 Solution initiale : on néglige la seconde ligne de l'expression
2569
2570 ln(2).b²u²-ln(1+b.u) c.seuil
2571 t - -------------------- = -------
2572 b²u²-b.u f.imax
2573
2574 | |
2575
2576 sf tt
2577
2578 */
2579 z = ((seuil / 1000.0) * c1) / imax ;
2580 tt = z/F ;
2581 sf = ((1.0 + bn1) * LOG_2) - (bn1 * bn1 * (log (0.5 * ((bn1 + 1.0) / bn1))) / (1.0 - bn1));
2582 tt += sf ;
2583 ti = tt * F;
2584
2585 /* Puis on trouve par convergence :
2586 ( 1-b.u )
2587 ln( 1 + -----.exp(-2t) )
2588 c.seuil ln(2).b²u²-ln(1+b.u) ( 1+b.u )
2589 t = ------- + -------------------- - ------------------------
2590 f.imax b²u²-b.u b²u² - b.u
2591
2592 ( 1 )
2593 - ( 1 + --- ).ln( 1+exp(-2t) )
2594 ( b.u )
2595
2596 */
2597
2598 do {
2599 i++;
2600 ltt = tt;
2601 b = exp (- 2.0 * tt);
2602 // ttt correspond aux trois termes avec les ln.
2603 ttt = (1.0 + bn1) * log (2.0 / (1.0 + b))
2604 - ((bn1 * bn1) / (1.0 - bn1)) * log (1.0 + ((1.0 - bn1) * (1.0 - b) / (2.0 * bn1)));
2605 tt = z/F + ttt;
2606 }
2607 while( (fabs((ltt-tt)/tt) > STM_MCC_EPSILON) && (i < 20) );
2608
2609 /* On défait le changement de variable */
2610 tt *= F;
2611 ti = tt;
2612
2613 if (i >= 20){
2614 Qi = imax * (ti - F * (LOG_2 * BU2 - log(1.0 + BU))/(BU2 - BU))
2615 + F * imax * (1.0/(BU2 - BU) * log(1.0 + (1.0 - BU)/(1.0 + BU) * exp(-2.0 * ti / F))
2616 + (1.0 + 1.0/BU) * log(1.0 + exp(-2.0 * ti / F))) - c1 * seuil / 1000.0;
2617 if(Qi > 0.0){
2618 tmax = ti;
2619 Qmax = Qi;
2620 tmin = ti - 0.1 * ti;
2621 Qmin = imax * (tmin - F * (LOG_2 * BU2 - log(1.0 + BU))/(BU2 - BU))
2622 + F * imax * (1.0/(BU2 - BU) * log(1.0 + (1.0 - BU)/(1.0 + BU) * exp(-2.0 * tmin / F))
2623 + (1.0 + 1.0/BU) * log(1.0 + exp(-2.0 * tmin / F))) - c1 * seuil / 1000.0;
2624 }else if(Qi < 0.0){
2625 tmin = ti;
2626 Qmin = Qi;
2627 tmax = ti + 0.1 * ti;
2628 Qmax = imax * (tmax - F * (LOG_2 * BU2 - log(1.0 + BU))/(BU2 - BU))
2629 + F * imax * (1.0/(BU2 - BU) * log(1.0 + (1.0 - BU)/(1.0 + BU) * exp(-2.0 * tmax / F))
2630 + (1.0 + 1.0/BU) * log(1.0 + exp(-2.0 * tmax / F))) - c1 * seuil / 1000.0;
2631 }else{
2632 return ti;
2633 }
2634 while((((Qmin > 0.0) && (Qmax > 0.0)) || ((Qmin < 0.0) && (Qmax < 0.0))) && (j < 100)){
2635 j++;
2636 Qmax = imax * (tmax - F * (LOG_2 * BU2 - log(1.0 + BU))/(BU2 - BU))
2637 + F * imax * (1.0/(BU2 - BU) * log(1.0 + (1.0 - BU)/(1.0 + BU) * exp(-2.0 * tmax / F))
2638 + (1.0 + 1.0/BU) * log(1.0 + exp(-2.0 * tmax / F))) - c1 * seuil / 1000.0;
2639 Qmin = imax * (tmin - F * (LOG_2 * BU2 - log(1.0 + BU))/(BU2 - BU))
2640 + F * imax * (1.0/(BU2 - BU) * log(1.0 + (1.0 - BU)/(1.0 + BU) * exp(-2.0 * tmin / F))
2641 + (1.0 + 1.0/BU) * log(1.0 + exp(-2.0 * tmin / F))) - c1 * seuil / 1000.0;
2642 if((Qmin > 0.0) && (Qmax > 0.0)){
2643 tint = tmin;
2644 tmin = tmin - (tmax - tmin);
2645 tmax = tint;
2646 }else if((Qmin < 0.0) && (Qmax < 0.0)){
2647 tint = tmax;
2648 tmax = tmax + (tmax - tmin);
2649 tmin = tint;
2650 }
2651 }
2652 ti = tmin + (tmax - tmin) / 2.0;
2653 while((tmax - tmin) > (1000.0 * STM_MCC_EPSILON) && (j < 100)){
2654 j++;
2655 Qi = imax * (ti - F * (LOG_2 * BU2 - log(1.0 + BU))/(BU2 - BU))
2656 + F * imax * (1.0/(BU2 - BU) * log(1.0 + (1.0 - BU)/(1.0 + BU) * exp(-2.0 * ti / F))
2657 + (1.0 + 1.0/BU) * log(1.0 + exp(-2.0 * ti / F))) - c1 * seuil / 1000.0;
2658 if(Qi > 0.0){
2659 tmax = ti;
2660 ti = tmin + (tmax - tmin) / 2.0;
2661 }else if(Qi < 0.0){
2662 tmin = ti;
2663 ti = tmin + (tmax - tmin) / 2.0;
2664 }else{
2665 return ti;
2666 }
2667 }
2668 ti = (tmax + tmin)/2.0;
2669 tt = ti;
2670 }
2671
2672 return tt;
2673 }
2674
2675 void stm_debug( char *fname,
2676 double imax,
2677 double F,
2678 double BN,
2679 double U,
2680 stm_qsat *qsat,
2681 double c,
2682 double threshold,
2683 double dtin,
2684 double qinit,
2685 double ci,
2686 double vt,
2687 double vddin,
2688 double fin,
2689 double tmin,
2690 double tmax,
2691 double tref
2692 )
2693 {
2694 double t ;
2695 double step ;
2696 double q ;
2697 double sol ;
2698 FILE *file ;
2699
2700 file = mbkfopen( fname, NULL, "w" ) ;
2701 if( !file ) {
2702 printf( "can't open file %s\n", fname ) ;
2703 return ;
2704 }
2705
2706 step = (tmax-tmin)/1000.0 ;
2707
2708 for( t=tmin ; t<=tmax ; t=t+step ) {
2709 q = stm_get_q( imax, t, F, BN, U );
2710 sol = stm_get_qsat( qsat, t+dtin ) + (c/1000.0)*threshold + qinit + ci/1000.0 * (vt+vddin * tanh((t+dtin)/fin));
2711 fprintf( file, "%g %g %g %g %g\n", (t+tref)*1e-12, q*1e-12, sol*1e-12, (q-stm_get_qsat(qsat,t+dtin))*1e-12, stm_get_qsat(qsat, t+dtin)*1e-12 );
2712 }
2713
2714 fclose( file );
2715 }
2716
2717 double stm_modscm_dual_calts (double imax,
2718 double an,
2719 double bn,
2720 double U,
2721 double seuil,
2722 double c,
2723 double F,
2724 double dt,
2725 double vt,
2726 double vddin,
2727 double ci,
2728 double *cie,
2729 double *vcap,
2730 double slew,
2731 stm_pwth *pwth,
2732 int nth,
2733 double qinit0,
2734 double strans,
2735 double icf0,
2736 stm_qsat *qsat
2737 )
2738 {
2739 double ts ;
2740 int i ;
2741 double qcc, qprev, qinit, q, qsate ;
2742 double vsmax ;
2743 double vin ;
2744 int k ;
2745 double capai ;
2746 static int fordebug=0 ;
2747 double qcapai ;
2748 double vin0 ;
2749 double t, qconf ;
2750
2751 fordebug++;
2752
2753 if( !nth )
2754 ts = stm_modscm_dual_calts_final( imax, an, bn, U, seuil, c, F,
2755 vt, vddin, ci, slew, dt, qinit0, strans, icf0, qsat );
2756 else {
2757
2758 q = 0.0 ;
2759 qinit = 0.0 ;
2760 qcapai = 0.0 ;
2761 capai = ci ;
2762 k = 0 ;
2763 vin0 = 0.0 ;
2764 qconf = 0.0 ;
2765
2766 for( i=0 ; i<nth-1 ; i++) {
2767
2768 q = q + stm_get_q( imax, pwth[i].T, pwth[i].F, bn , U)
2769 - ( i>0 ? stm_get_q( imax, pwth[i-1].T+pwth[i-1].DT-pwth[i].DT, pwth[i].F, bn , U) : 0.0 );
2770
2771 vin = vt + vddin * tanh( (pwth[i].T+pwth[i].DT) / slew );
2772
2773 if( cie && vcap ) {
2774 while( k<3 && vin > vcap[k] ) {
2775 k++ ;
2776 qcapai = qcapai + vcap[k-1]*(cie[k-1]-cie[k])/1000.0;
2777 }
2778 capai = cie[k];
2779 }
2780
2781 if( strans>0.0 && icf0>0.0 ) {
2782 t = pwth[i].T+pwth[i].DT ;
2783 if( t>strans )
2784 t=strans ;
2785 qconf = -icf0*(t-t*t/(2.0*t ));
2786 }
2787 qcc = (capai/1000.0) * vin ;
2788 qsate = stm_get_qsat( qsat, pwth[i].T+pwth[i].DT );
2789
2790 vsmax = (q-qconf-qcc-qinit0-qsate-qcapai)/(c/1000.0);
2791
2792 if( vsmax > seuil )
2793 break ;
2794
2795 qinit = q ;
2796 vin0 = vin ;
2797 }
2798
2799 if( i>0 )
2800 qprev = qinit0 + stm_get_q( imax, pwth[i-1].T+pwth[i-1].DT-pwth[i].DT, pwth[i].F, bn, U ) + qcapai - qinit;
2801 else
2802 qprev = qinit0 + qinit + qcapai ;
2803
2804 ts = stm_modscm_dual_calts_final( imax,
2805 an,
2806 bn,
2807 U,
2808 seuil,
2809 c,
2810 pwth[i].F,
2811 vt,
2812 vddin,
2813 capai,
2814 slew,
2815 pwth[i].DT,
2816 qprev,
2817 strans,
2818 icf0,
2819 qsat
2820 ) ;
2821
2822 ts = ts + pwth[i].DT ;
2823 }
2824 return ts ;
2825 }
2826
2827 double stm_modscm_dual_calc_i( double imax,
2828 double isat,
2829 double a,
2830 double b,
2831 double rnt,
2832 double rns,
2833 double rni,
2834 double vint,
2835 double vdd,
2836 double vt,
2837 double vgs,
2838 double vds
2839 )
2840 {
2841 double rlin ;
2842 double rint ;
2843 double rsat ;
2844 double vsat ;
2845 double vlin ;
2846 double i ;
2847
2848 i = isat ;
2849 if( rnt > 0.0 && rns > 0.0 ) {
2850 stm_modscm_dual_calc_rsat( imax, isat, a, b, rnt, rns, rni, vint, vdd, vt, vgs, &rsat, &rlin, &rint, &vsat, &vlin );
2851
2852 if( rsat > 0.0 ) {
2853 if( rint > 0.0 ) {
2854 if( vds < vlin )
2855 i = vds/rlin ;
2856 else {
2857 if( vds < vsat )
2858 i = vlin/rlin + (vds-vlin)/rint ;
2859 else
2860 i = isat - (vdd-vds)/rsat ;
2861 }
2862 }
2863 else {
2864 if( vds > vsat )
2865 i = isat - ( vdd - vds ) / rsat ;
2866 else
2867 i = vds / rlin ;
2868 }
2869 }
2870 }
2871
2872 return i ;
2873
2874 }
2875
2876 void stm_plot_final_i( char *filename, param_final_i *p )
2877 {
2878 double isat ;
2879 double ids ;
2880 double save_vout ;
2881 FILE *ptf ;
2882 double u ;
2883
2884 ptf = fopen( filename, "w" );
2885 if( !ptf ) {
2886 perror( "can't open file " );
2887 return ;
2888 }
2889
2890 u = p->VINR - p->VT ;
2891 isat = p->A*u*u / ( 1.0 + p->B*u );
2892 save_vout = p->VOUT ;
2893
2894 for( p->VOUT=0.0 ; p->VOUT <= p->VDDOUT ; p->VOUT = p->VOUT + p->VDDOUT/100.0 ) {
2895 ids = stm_modscm_dual_calts_final_i( p );
2896 fprintf( ptf, "%g %g\n", p->VOUT, ids );
2897 }
2898
2899 fclose( ptf );
2900 p->VOUT = save_vout ;
2901 }
2902
2903 double stm_modscm_dual_calts_final_i( param_final_i *p )
2904 {
2905 double i ;
2906 double isat ;
2907 double vds ;
2908 double u ;
2909
2910 u = p->VINR - p->VT ;
2911 isat = p->A*u*u / ( 1.0 + p->B*u );
2912
2913 vds = p->VDDOUT - p->VOUT ;
2914
2915 i = stm_modscm_dual_calc_i( p->IMAX, isat, p->A, p->B, p->RNT, p->RNS, p->RINT, p->VINT, p->VDDOUT, p->VT, p->VIN, vds );
2916
2917 return i ;
2918 }
2919
2920 int stm_modscm_dual_calts_final_numeric_find_next_seuil( int index, float *tabv, int nbpoint )
2921 {
2922 float seuil ;
2923 int i ;
2924 float vmin ;
2925 int imin ;
2926
2927 if( index >= 0 )
2928 seuil = tabv[index] ;
2929 else
2930 seuil = -1.0 ;
2931
2932 vmin = 1e10 ;
2933 imin = -1 ;
2934
2935 for( i=0 ; i<nbpoint ; i++ ) {
2936 if( tabv[i] > seuil ) {
2937 if( tabv[i] < vmin ) {
2938 vmin = tabv[i] ;
2939 imin = i ;
2940 }
2941 }
2942 }
2943
2944 return imin ;
2945 }
2946
2947 void stm_modscm_dual_calts_final_numeric_pi( stm_dual_param_timing *paramtiming,
2948 float rl,
2949 float cl1,
2950 float cl2,
2951 float *tabv,
2952 float *tabt,
2953 int nbpoint
2954 )
2955 {
2956 int index ;
2957 double step ;
2958 double r ;
2959 double c1 ;
2960 double c2 ;
2961 double ci ;
2962 double v1 ;
2963 double v2 ;
2964 double vi0 ;
2965 double v10 ;
2966 double v20 ;
2967 double t ;
2968 double dt ;
2969 double lt ;
2970 double uin ;
2971 double uinr ;
2972 double ts ;
2973 double k0 ;
2974 double k1 ;
2975 double seuil ;
2976 double i ;
2977 param_final_i param ;
2978
2979 index = -1 ;
2980
2981 step = 100.0 ;
2982
2983 c1 = paramtiming->CAPA/1000.0 + cl1/1000.0 ;
2984 c2 = cl2/1000.0 ;
2985 ci = paramtiming->CAPAI/1000.0 ;
2986 r = rl ;
2987
2988 dt = (c1+c2)*paramtiming->VDDMAX/paramtiming->IMAX/step ;
2989
2990 k1 = 1.0/( c1/dt + c2/(dt+r*c2) );
2991
2992 v1 = 0.0 ; // to do : inclure valeur qinit et ci
2993 v2 = 0.0 ; // to do : inclure valeur qinit et ci
2994 v10 = 0.0 ;
2995 v20 = 0.0 ;
2996 t = 0.0 ;
2997
2998 param.IMAX = paramtiming->IMAX ;
2999 param.A = paramtiming->AN ;
3000 param.B = paramtiming->BN ;
3001 param.U = paramtiming->U ;
3002 param.RNT = paramtiming->RLIN ;
3003 param.RNS = paramtiming->RSAT ;
3004 param.RINT = paramtiming->RINT ;
3005 param.VINT = paramtiming->VINT ;
3006 param.VT = paramtiming->VT ;
3007 param.VDDOUT = paramtiming->VDDMAX ;
3008 param.VIN = paramtiming->VT ;
3009 param.VINR = paramtiming->VT ;
3010
3011 do {
3012 index = stm_modscm_dual_calts_final_numeric_find_next_seuil( index, tabv, nbpoint );
3013 if( index >=0 ) {
3014
3015 seuil = tabv[ index ] ;
3016
3017 if( seuil < v1 )
3018 ts = t ;
3019
3020 do {
3021
3022 v10 = v1 ;
3023 v20 = v2 ;
3024 vi0 = param.VIN ;
3025 lt = t ;
3026
3027 t = t + dt ;
3028 uin = paramtiming->VDDIN * tanh( t / paramtiming->FIN ) ;
3029 uinr = paramtiming->U * tanh( t / paramtiming->F ) ;
3030
3031 param.VOUT = v1 ;
3032 param.VIN = paramtiming->VT + uin ;
3033 param.VINR = paramtiming->VT + uinr ;
3034
3035 i = stm_modscm_dual_calts_final_i( &param );
3036
3037 k0 = c1*v10/dt + c2*v20/(dt+r*c2) + ci*vi0/dt ;
3038 v1 = k1 * ( i - ci*param.VIN/dt + k0 ) ;
3039 v2 = v1 - r*c2*v1/(dt+r*c2) + r*c2*v20/(dt+r*c2) ;
3040
3041 }
3042 while( v1 < seuil );
3043 ts = ( t-lt )/( v1-v10 )*( seuil-v10 ) + lt ;
3044 tabt[index] = ts ;
3045 }
3046 }
3047 while( index > 0 );
3048 }
3049
3050 void stm_modscm_dual_calts_final_numeric( stm_dual_param_timing *paramtiming,
3051 float *tabv,
3052 float *tabt,
3053 int nbpoint
3054 )
3055 {
3056 double lt ;
3057 double li ;
3058 double lv ;
3059 double t ;
3060 double dq ;
3061 double q ;
3062 double v ;
3063 double vr ;
3064 double vrc ;
3065 double lvrc ;
3066 double k ;
3067 double dv ;
3068 double i ;
3069 double dt ;
3070 double ts ;
3071 double seuil ;
3072 double ci ;
3073 double c ;
3074 double chalf ;
3075 double uin ;
3076 double uinr ;
3077 double q0 ;
3078 double v0 ;
3079 double vin0 ;
3080 int iter ;
3081 int index ;
3082 int half_set ;
3083 param_final_i param ;
3084 double step ;
3085
3086 i = 0.0 ;
3087 t = 0.0 ;
3088 q = -paramtiming->QINIT ;
3089 half_set = 0 ;
3090
3091 ci = paramtiming->CAPAI / 1000.0 ;
3092 c = paramtiming->CAPA / 1000.0 ;
3093 chalf = paramtiming->CHALF / 1000.0 ;
3094 iter = 0 ;
3095
3096 step = 100 ;
3097 dt = ((c+fabs(chalf)) * paramtiming->VDDMAX / (2.0 * paramtiming->IMAX) )/ step ;
3098
3099 param.IMAX = paramtiming->IMAX ;
3100 param.A = paramtiming->AN ;
3101 param.B = paramtiming->BN ;
3102 param.U = paramtiming->U ;
3103 param.RNT = paramtiming->RLIN ;
3104 param.RNS = paramtiming->RSAT ;
3105 param.RINT = paramtiming->RINT ;
3106 param.VINT = paramtiming->VINT ;
3107 param.VT = paramtiming->VT ;
3108 param.VDDOUT = paramtiming->VDDMAX ;
3109
3110 index = -1 ;
3111
3112 v = ( q - ci * param.VT )/c ;
3113 lv = v ;
3114 li = i ;
3115 lt = t ;
3116 lvrc = 0.0 ;
3117 vrc = 0.0 ;
3118
3119 do {
3120
3121 index = stm_modscm_dual_calts_final_numeric_find_next_seuil( index, tabv, nbpoint );
3122
3123 if( index >= 0 ) {
3124
3125 seuil = tabv[ index ] ;
3126
3127 if( seuil < v ) {
3128 ts = t ;
3129 }
3130 else {
3131
3132 if( v >= paramtiming->VDDMAX/2.0 && !half_set ) {
3133 half_set = 1 ;
3134 vin0 = param.VIN ;
3135 q0 = q ;
3136 v0 = v ;
3137 }
3138
3139 do {
3140
3141 iter++ ;
3142
3143 lv = v ;
3144 li = i ;
3145 lt = t ;
3146 lvrc = vrc ;
3147 t = t + dt ;
3148
3149 uin = paramtiming->VDDIN * tanh( t / paramtiming->FIN ) ;
3150 uinr = paramtiming->U * tanh( t / paramtiming->F ) ;
3151
3152 param.VOUT = v ;
3153 param.VIN = paramtiming->VT + uin ;
3154 param.VINR = paramtiming->VT + uinr ;
3155
3156 i = stm_modscm_dual_calts_final_i( &param );
3157
3158 if( paramtiming->RBR > 0.0 && paramtiming->CBR > 0.0 && t > lt ) {
3159
3160 vr = i*paramtiming->RBR ;
3161 k = 1.0/( 1.0/paramtiming->RBR + (paramtiming->CBR/1000.0)/(t-lt) );
3162 vrc = k*( i + lvrc * (paramtiming->CBR/1000.0)/(t-lt) );
3163 dv = vr-vrc ;
3164 param.VIN = paramtiming->VT + uin + dv ;
3165 param.VINR = paramtiming->VT + uinr + dv * uinr/uin ;
3166 i = stm_modscm_dual_calts_final_i( &param );
3167 }
3168
3169 dq = (i+li)*(t-lt)/2.0 ;
3170 q = q + dq ;
3171
3172 if( v < paramtiming->VDDMAX/2.0 ) {
3173 half_set = 1 ;
3174 v = ( q - ci * param.VIN )/c ;
3175 q0 = q ;
3176 v0 = v ;
3177 vin0 = param.VIN ;
3178 }
3179 else {
3180 v = v0 + ( (q-q0) - ci*(param.VIN-vin0) )/(c-chalf);
3181 }
3182
3183 }
3184 while( v < seuil && iter < 100*step );
3185
3186 ts = ( t-lt )/( v-lv )*( seuil-lv ) + lt ;
3187 }
3188 tabt[index] = ts ;
3189 }
3190 }
3191 while( index >= 0 );
3192 }
3193
3194 /* valide la solution t pour q(t)-qsat(t) */
3195
3196 int stm_modscm_dual_calts_valid( double imax,
3197 double bn,
3198 double U,
3199 double F,
3200 double dtin,
3201 stm_qsat *qsat,
3202 double t,
3203 char checksol
3204 )
3205 {
3206 double bu ;
3207 double th ;
3208 double dq ;
3209 double dqsat ;
3210
3211 if( !V_BOOL_TAB[ __STM_CHECK_SOLUTION ].VALUE || checksol==NO )
3212 return 1 ;
3213
3214 bu = bn*U ;
3215 th = tanh(t/F);
3216
3217 dq = imax*(1.0+bu)*th*th/(1.0+bu*th);
3218 dqsat = stm_get_qsat_derivative( qsat, t );
3219
3220 if( dq-dqsat <= 0.0 )
3221 return 0 ;
3222
3223 dtin=0.0;
3224 return 1 ;
3225 }
3226
3227 double stm_modscm_dual_calts_final (double imax,
3228 double an,
3229 double bn,
3230 double U,
3231 double seuil,
3232 double c,
3233 double F,
3234 double vt,
3235 double vddin,
3236 double ci,
3237 double slew,
3238 double dtin,
3239 double qinit,
3240 double strans,
3241 double icf0,
3242 stm_qsat *qsat
3243 )
3244 {
3245 double t ;
3246 double tamjad ;
3247 int status1 ;
3248 int status2 ;
3249 int status3 ;
3250 double backup_tsatmax ;
3251 static int fordebug = 0 ;
3252
3253 fordebug++ ;
3254
3255 if( V_BOOL_TAB[ __STM_CHECK_SOLUTION ].VALUE && qsat ) {
3256 backup_tsatmax = qsat->TSATMAX ;
3257 qsat->TSATMAX = FLT_MAX ;
3258 }
3259
3260 status1 = stm_modscm_dual_calts_amjad( imax, bn, U, seuil, c, F, vt, vddin, ci, slew, dtin, qinit, qsat, strans, icf0, &t );
3261 tamjad = t ;
3262 if( status1 == CALTS_AMJAD_OK ) {
3263 if( ! stm_modscm_dual_calts_valid( imax, bn, U, F, dtin, qsat, t, YES ) ) {
3264 status1 = CALTS_AMJAD_NC ;
3265 }
3266 }
3267
3268 if( status1 == CALTS_AMJAD_NC ) {
3269
3270 if( t < 0.0 )
3271 t = (c/1000.0*seuil)/imax ;
3272 status2 = stm_modscm_dual_calts_dichotomie( imax, bn, U, seuil, c, F, vt, vddin, ci, slew, dtin, qinit, qsat, strans, icf0, &t, YES ) ;
3273
3274 switch( status2 ) {
3275
3276 case CALTS_DICHO_NOSOL :
3277
3278 if( V_BOOL_TAB[ __STM_CHECK_SOLUTION ].VALUE && qsat ) {
3279 avt_log( LOGDEBUG, 1, "stm_modscm_dual_calts_final(%d) : no solution found -> fix tsatmax\n", fordebug );
3280 qsat->TSATMAX = t ;
3281 status3 = stm_modscm_dual_calts_dichotomie( imax, bn, U, seuil, c, F, vt, vddin, ci, slew, dtin, qinit, qsat, strans, icf0, &t, NO ) ;
3282 if( status3 != CALTS_DICHO_OK ) {
3283 avt_log( LOGDEBUG, 1, " -> failed !\n" );
3284 t = tamjad ;
3285 }
3286 }
3287 else {
3288 avt_log( LOGDEBUG, 1, "stm_modscm_dual_calts_final(%d) : no solution found -> very strange case !!!\n", fordebug );
3289 }
3290 break ;
3291
3292 case CALTS_DICHO_NC :
3293
3294 if( V_BOOL_TAB[ __STM_CHECK_SOLUTION ].VALUE && qsat ) {
3295 avt_log( LOGDEBUG, 1, "stm_modscm_dual_calts_final(%d) : no convergence -> fix tsatmax\n", fordebug );
3296 qsat->TSATMAX = t ;
3297 status3 = stm_modscm_dual_calts_dichotomie( imax, bn, U, seuil, c, F, vt, vddin, ci, slew, dtin, qinit, qsat, strans, icf0, &t, NO ) ;
3298 if( status3 != CALTS_DICHO_OK ) {
3299 avt_log( LOGDEBUG, 1, " -> failed !\n" );
3300 t = tamjad ;
3301 }
3302 }
3303 else {
3304 avt_log( LOGDEBUG, 1, "stm_modscm_dual_calts_final(%g) : no convergence -> very strange case !!!\n", fordebug );
3305 }
3306 }
3307 }
3308
3309 if( V_BOOL_TAB[ __STM_CHECK_SOLUTION ].VALUE && qsat ) {
3310 qsat->TSATMAX = backup_tsatmax ;
3311 }
3312
3313 an=0.0 ;
3314 /* if status2 == CALTS_DICHO_KO, revenir à modèle ceqrsat */
3315 return t ;
3316 }
3317
3318 int stm_modscm_dual_calts_amjad (double imax,
3319 double bn,
3320 double U,
3321 double seuil,
3322 double c,
3323 double F,
3324 double vt,
3325 double vddin,
3326 double ci,
3327 double slew,
3328 double dtin,
3329 double qinit,
3330 stm_qsat *qsat,
3331 double strans,
3332 double icf0,
3333 double *t
3334 )
3335 {
3336 double bn1,
3337 sf,
3338 b = 0.0,
3339 z = 0.0,
3340 tt = 0.0,
3341 ttt = 0.0,
3342 c1 = 0.0 ;
3343 int i = 0 ;
3344 int ret ;
3345 double ltt;
3346 double tinit;
3347 double tin ;
3348
3349
3350 /* calcul de la tension rapportée à partir de :
3351
3352 an.U²
3353 imax = ------
3354 1+bn.U
3355 */
3356
3357 if((U <= 0.0)||(F <= 0.0))
3358 return 0.0;
3359
3360 bn1 = 1 / (U * bn);
3361 c1 = c;
3362
3363 /* Dans ce qui suit, on a un changement de variable t = t/F
3364
3365 Résolution de :
3366
3367 ( ln(2).b²u²-ln(1+b.u) )
3368 imax.( f.t - f.-------------------- )
3369 ( b²u²-b.u )
3370
3371 ( ( 1-b.u ) )
3372 ( ln( 1 + -----.exp(-2t) ) )
3373 ( ( 1+b.u ) ( 1 ) )
3374 + f.imax.( ------------------------ + ( 1 + --- ).ln( 1+exp(-2t) ) )
3375 ( b²u² - b.u ( b.u ) )
3376
3377 = c.seuil + qsat2*t*t + ci * ( vt + vddin.th(t) ) + qinit + icf0*(t-t*t/(2*strans))
3378
3379
3380 Solution initiale : on néglige la seconde ligne de l'expression
3381
3382 ln(2).b²u²-ln(1+b.u) c.seuil ci.vt qinit
3383 t - -------------------- = ------- + ------ + ------
3384 b²u²-b.u f.imax f.imax f.imax
3385
3386 | |
3387
3388 sf tt
3389
3390 */
3391 z = (seuil * c1/1000.0 + vt * ci/1000.0 + qinit ) / imax ;
3392 tt = z/F ;
3393 sf = ((1.0 + bn1) * LOG_2) - (bn1 * bn1 * (log (0.5 * ((bn1 + 1.0) / bn1))) / (1.0 - bn1));
3394 tt += sf ;
3395
3396 if((TESTIM > 0.0) && (TESTIM > dtin))
3397 tt = (TESTIM-dtin)/F ;
3398 TESTIM = -1.0 ;
3399
3400 tinit = tt ;
3401
3402 /* Puis on trouve par convergence :
3403 ( 1-b.u )
3404 ln( 1 + -----.exp(-2t) )
3405 c.seuil ln(2).b²u²-ln(1+b.u) ( 1+b.u )
3406 t = ------- + -------------------- - ------------------------
3407 f.imax b²u²-b.u b²u² - b.u
3408
3409 ( 1 )
3410 - ( 1 + --- ).ln( 1+exp(-2t) )
3411 ( b.u )
3412
3413 */
3414
3415 /* pas sur que le critère de Lipschitz soit bon suite à l'introduction de qsat2 */
3416 do {
3417 i++;
3418 ltt = tt;
3419 b = exp (- 2.0 * tt);
3420 // ttt correspond aux trois termes avec les ln et le ci.
3421 ttt = (1.0 + bn1) * log (2.0 / (1.0 + b))
3422 - ((bn1 * bn1) / (1.0 - bn1)) * log (1.0 + ((1.0 - bn1) * (1.0 - b) / (2.0 * bn1)))
3423 + ci/1000.0 * vddin * tanh((tt*F+dtin)/slew)/F/imax + stm_get_qsat(qsat,tt*F)/F/imax ;
3424 if( strans>0.0 ) {
3425 tin = tt*F+dtin;
3426 if( tin > strans )
3427 tin = strans ;
3428 ttt = ttt - icf0*(tin-tin*tin/(2.0*strans))/F/imax ;
3429 }
3430 tt = z/F + ttt;
3431 }
3432 while( (fabs((F*ltt-F*tt)/(F*tt+dtin)) > STM_MCC_EPSILON) && tt < 10.0*tinit && (i < 20) );
3433
3434 /* On défait le changement de variable */
3435 *t = tt * F;
3436
3437 if( i>=20 || tt >= 10.0*tinit )
3438 ret = CALTS_AMJAD_NC ;
3439 else
3440 ret = CALTS_AMJAD_OK ;
3441
3442 return ret ;
3443 }
3444
3445 inline double stm_modscm_dual_calts_dicho_q( double imax,
3446 double t,
3447 double f,
3448 double bu,
3449 double bu2,
3450 double c,
3451 double seuil,
3452 double ci,
3453 double vt,
3454 double vddin,
3455 double dtin,
3456 double fin,
3457 double qinit,
3458 double strans,
3459 double icf0,
3460 stm_qsat *qsat
3461 )
3462 {
3463 double q ;
3464 double tin ;
3465
3466 if (bu==1)
3467 q = imax * (t - f * (LOG_2))
3468 + f * imax * (2 * log(1.0 + exp(-2.0 * t / f)));
3469 else
3470 q = imax * (t - f * (LOG_2 * bu2 - log(1.0 + bu))/(bu2 - bu))
3471 + f * imax * (1.0/(bu2 - bu) * log(1.0 + (1.0 - bu)/(1.0 + bu) * exp(-2.0 * t / f))
3472 + (1.0 + 1.0/bu) * log(1.0 + exp(-2.0 * t / f)));
3473
3474 q += - c * seuil / 1000.0 - ci/1000.0 * ( vt + vddin * tanh((t+dtin)/fin)) - qinit - stm_get_qsat(qsat,t);
3475
3476 if( strans > 0.0 ) {
3477 tin = t ;
3478 if( tin>strans )
3479 tin = strans ;
3480 q = q + icf0*(tin-tin*tin/(2.0*strans));
3481 }
3482
3483 return q ;
3484 }
3485
3486 /* une solution estimée doit être donnée dans *t */
3487 int stm_modscm_dual_calts_dichotomie( double imax,
3488 double bn,
3489 double U,
3490 double seuil,
3491 double c,
3492 double F,
3493 double vt,
3494 double vddin,
3495 double ci,
3496 double fin,
3497 double dtin,
3498 double qinit,
3499 stm_qsat *qsat,
3500 double strans,
3501 double icf0,
3502 double *t,
3503 char checksol
3504 )
3505 {
3506 double ti ;
3507 double tmin ;
3508 double tmax ;
3509 double Qmin ;
3510 double Qmax ;
3511 double BU ;
3512 double BU2 ;
3513 int ret = CALTS_DICHO_OK ;
3514 int iter ;
3515 double tvmin ;
3516 double tvmax ;
3517 double tm ;
3518 double qm ;
3519 int validmin ;
3520 int validmax ;
3521 int validm ;
3522
3523 ti = *t;
3524 BU = bn * U,
3525 BU2 = BU * BU ;
3526
3527 /* Etat initial : trouver qmin<0 valide et qmax>0 qui peut etre non valide */
3528
3529 tmax = ti ;
3530 validmax = stm_modscm_dual_calts_valid( imax, bn, U, F, dtin, qsat, tmax, checksol ) ;
3531 if( validmax )
3532 Qmax = stm_modscm_dual_calts_dicho_q( imax, tmax, F, BU, BU2, c, seuil, ci, vt, vddin, dtin, fin, qinit, strans, icf0, qsat ) ;
3533 else
3534 Qmax = 0.0 ;
3535
3536 if( validmax ) {
3537
3538 if( Qmax < 0.0 ) {
3539
3540 iter = 100;
3541 do {
3542
3543 if( Qmax < 0 && validmax ) {
3544 tmin = tmax ;
3545 Qmin = Qmax ;
3546 }
3547
3548 tmax = 1.1 * tmax ;
3549 Qmax = stm_modscm_dual_calts_dicho_q( imax, tmax, F, BU, BU2, c, seuil, ci, vt, vddin, dtin, fin, qinit, strans, icf0, qsat );
3550 validmax = stm_modscm_dual_calts_valid( imax, bn, U, F, dtin, qsat, tmax, checksol ) ;
3551
3552 iter-- ;
3553 }
3554 while( Qmax < 0.0 && validmax && iter );
3555
3556 if( !iter ) {
3557 avt_log( LOGDEBUG, 1, "stm_modscm_dual_calts_dichotomie() : no convergence\n" );
3558 ret = CALTS_DICHO_NOSOL ;
3559 }
3560 }
3561 else {
3562
3563 tmin = 0.0 ;
3564 Qmin = stm_modscm_dual_calts_dicho_q( imax, tmin, F, BU, BU2, c, seuil, ci, vt, vddin, dtin, fin, qinit, strans, icf0, qsat );
3565
3566 }
3567 }
3568 else {
3569
3570 tmin = 0.0 ;
3571 Qmin = stm_modscm_dual_calts_dicho_q( imax, tmin, F, BU, BU2, c, seuil, ci, vt, vddin, dtin, fin, qinit, strans, icf0, qsat );
3572
3573 }
3574
3575 /* converge pour trouver qmax positif et valide */
3576
3577 if( ret == CALTS_DICHO_OK && !validmax ) {
3578 tvmin = tmin ;
3579 validmin = 1 ;
3580 tvmax = tmax ;
3581
3582 iter = 100 ;
3583
3584 do {
3585
3586 tm = ( tvmin + tvmax ) / 2.0 ;
3587 validm = stm_modscm_dual_calts_valid( imax, bn, U, F, dtin, qsat, tm, checksol ) ;
3588 if( validm )
3589 qm = stm_modscm_dual_calts_dicho_q( imax, tm, F, BU, BU2, c, seuil, ci, vt, vddin, dtin, fin, qinit, strans, icf0, qsat );
3590 else
3591 qm = 0.0 ;
3592
3593 if( validm && qm < 0.0 ) {
3594 tvmin = tm ;
3595 validmin = validm ;
3596 }
3597 else {
3598 tvmax = tm ;
3599 validmax = validm ;
3600 }
3601
3602 iter-- ;
3603 }
3604 while( !(validmin && validmax) && iter && (tvmax-tvmin)>0.1 );
3605
3606 tmax = tm ;
3607 Qmax = qm ;
3608 *t = tm ;
3609
3610 if( !validmin || !validmax )
3611 ret = CALTS_DICHO_NOSOL ;
3612 }
3613
3614 /* dichotomie classique d'une fonction croissante à une seule racine, Qmin et Qmax sont valides */
3615
3616 if( ret == CALTS_DICHO_OK ) {
3617
3618 iter = 100 ;
3619
3620 do {
3621
3622 tm = ( tmin + tmax )/2.0 ;
3623 qm = stm_modscm_dual_calts_dicho_q( imax, tm, F, BU, BU2, c, seuil, ci, vt, vddin, dtin, fin, qinit, strans, icf0, qsat );
3624
3625 if( qm > 0.0 )
3626 tmax = tm ;
3627 else
3628 tmin = tm ;
3629
3630 iter-- ;
3631 }
3632 while((tmax - tmin) > (1000.0 * STM_MCC_EPSILON) && iter );
3633
3634 if( !iter )
3635 ret = CALTS_DICHO_NC ;
3636
3637 *t = ( tmin + tmax )/2.0 ;
3638 }
3639
3640 return ret ;
3641 }
3642
3643 /****************************************************************************/
3644
3645 /*
3646 Calcule rsat d'un transistor lorsqu'on a un VGS différent de VDD.
3647 Voir les explications dans mon classeur, chapitre rsat.
3648 */
3649
3650 void stm_modscm_dual_calc_rsat( double imax,
3651 double isat,
3652 double a,
3653 double b,
3654 double rnt,
3655 double rns,
3656 double rni,
3657 double vint,
3658 double vdd,
3659 double vt,
3660 double vgs,
3661 double *rsat_r,
3662 double *rlin_r,
3663 double *rint_r,
3664 double *vsat_r,
3665 double *vlin_r
3666 )
3667 {
3668 double x, kres, ures, rsat, rsatmin, k, rlin, ires ;
3669 double vr, ir, gsep, ire, vre ;
3670 double iint, rint ;
3671
3672 rsatmin = vdd/imax ;
3673
3674 if( rsat_r ) *rsat_r = -1.0 ;
3675 if( rlin_r ) *rlin_r = -1.0 ;
3676 if( rint_r ) *rint_r = -1.0 ;
3677 if( vsat_r ) *vsat_r = -1.0 ;
3678 if( vlin_r ) *vlin_r = -1.0 ;
3679
3680 if( rni < 0.0 && rnt < rsatmin && rns > rsatmin ) {
3681
3682 rsatmin = vdd/isat ;
3683
3684 k = imax*rnt / (vdd-vt) ;
3685 rlin = k * ( 1.0 + b * (vgs-vt) ) / ( a * (vgs-vt) ) ;
3686
3687 if( rlin > rsatmin )
3688 return ;
3689
3690 x = ( imax*rnt - vdd*rnt/rns ) / ( 1.0 - rnt/rns ) ;
3691 kres = x / ( vdd - vt ) ;
3692 ures = kres * ( vgs - vt ) ;
3693 ires = ures / rlin ;
3694 rsat = ( vdd - ures ) / ( isat - ires ) ;
3695
3696 if( rsat < rsatmin )
3697 return ;
3698
3699 if( rsat_r ) *rsat_r = rsat ;
3700 if( rlin_r ) *rlin_r = rlin ;
3701 if( vsat_r ) *vsat_r = ures ;
3702 }
3703 else {
3704
3705 if( rni > 0.0 ) {
3706
3707 /* calcul point 1 vgs=vdd : (vint;iint) */
3708 iint = vint/rnt ;
3709
3710 /* calcul point 2 vgs=vdd : (vr;ir) */
3711 vr = ( imax - iint + vint/rni - vdd/rns ) * ( rns * rni ) / ( rns - rni ) ;
3712 ir = imax - (vdd-vr)/rns ;
3713
3714 /* calcul point 2 vgs<>vdd : (vre;ire) */
3715 ire = ir*(vgs-vt)/(vdd-vt) ;
3716 if( ire > 0.95*isat )
3717 ire = 0.95*isat ;
3718 gsep = ir/(vdd-vr) ;
3719 vre = vr + (ir-ire)/gsep ;
3720
3721 /* calcul rlin vgs<>vdd */
3722 k = ir*rnt/(vdd-vt);
3723 rlin = k*(vgs-vt)/ire ;
3724
3725 /* calcul point 1 vgs<>vdd : (ures;ires) */
3726 kres = vint/(vdd-vt) ;
3727 ures = kres*(vgs-vt) ;
3728 ires = ures/rlin ;
3729
3730 /* calcul rsat et rint */
3731 rsat = (vdd-vre)/(isat-ire) ;
3732 rint = (vre-ures)/(ire-ures/rlin) ;
3733
3734 if( vr < vint )
3735 avt_log( LOGSTM, 3, "warning : vr(%g)<vint(%g)\n", vr, vint );
3736
3737 if( iint > ir )
3738 avt_log( LOGSTM, 3, "warning : iint(%g)>ir(%g)\n", iint, ir );
3739
3740 if( vre < ures )
3741 avt_log( LOGSTM, 3, "warning : vre(%g)<ures(%g)\n", vre, ures );
3742
3743 if( ire < ires )
3744 avt_log( LOGSTM, 3, "warning : ire(%g)<ires(%g)\n", ire, ires );
3745
3746 if( isat < ire )
3747 avt_log( LOGSTM, 3, "warning : isat(%g)<ire(%g)\n", isat, ire );
3748
3749 if( rsat_r ) *rsat_r = rsat ;
3750 if( rlin_r ) *rlin_r = rlin ;
3751 if( rint_r ) *rint_r = rint ;
3752 if( vsat_r ) *vsat_r = vre ;
3753 if( vlin_r ) *vlin_r = ures ;
3754 }
3755 else {
3756 if( rnt > rsatmin && rns < rsatmin ) {
3757 vr = (imax-vdd/rns)*(rns*rnt)/(rns-rnt) ;
3758 ir = vr/rnt ;
3759 gsep = ir/(vdd-vr) ;
3760 ire = ir*(vgs-vt)/(vdd-vt) ;
3761 vre = vr + (ir-ire)/gsep ;
3762 rsat = (vdd-vre)/(isat-ire) ;
3763 rlin = vre/ire ;
3764 if( rsat_r ) *rsat_r = rsat ;
3765 if( rlin_r ) *rlin_r = rlin ;
3766 if( vsat_r ) *vsat_r = vre ;
3767 }
3768 }
3769 }
3770 }
3771
3772 /****************************************************************************/
3773
3774 /*
3775 Calcule le vgs du transistor lorsque la sortie commute.
3776 Pour l'instant, ne prend pas en compte le rbr/cbr.
3777 */
3778
3779 double stm_modscm_dual_calc_vin( double vddin,
3780 double vt,
3781 double slew,
3782 double ts
3783 )
3784 {
3785 double vgs ;
3786
3787 vgs = vddin*tanh( ts/slew ) + vt ;
3788
3789 if( vgs <=0.0 || vgs >= vddin+vt )
3790 EXIT(33);
3791 return vgs ;
3792 }
3793
3794 /****************************************************************************/
3795
3796 double stm_modscm_dual_ceqrsat_numeric( stm_dual_param_timing *param, double seuil )
3797 {
3798 double vt ;
3799 double vdd ;
3800 double f ;
3801 double fin ;
3802 double vddin ;
3803 double a ;
3804 double b ;
3805 double u ;
3806 double imax ;
3807 double capa ;
3808 double dt ;
3809 double rlin ;
3810 double rsat ;
3811 double qinit ;
3812 double capai ;
3813 double isat ;
3814
3815 double q ;
3816 double t ;
3817 double vin ;
3818 double vout ;
3819 double qsat ;
3820 double ceqrsat ;
3821 double rs ;
3822
3823 vt = param->VT ;
3824 vddin = param->VDDIN ;
3825 fin = param->FIN ;
3826 qinit = param->QINIT ;
3827 f = param->F ;
3828 a = param->AN ;
3829 b = param->BN ;
3830 u = param->U ;
3831 imax = param->IMAX ;
3832 vdd = param->VDDMAX ;
3833 rlin = param->RLIN ;
3834 rsat = param->RSAT ;
3835 capai = param->CAPAI / 1000.0 ;
3836 capa = param->CAPA / 1000.0 ;
3837 dt = param->T0 / 100.0 ;
3838
3839 qsat = 0.0 ;
3840
3841 t=dt ;
3842
3843 do {
3844 vin = vt + vddin * tanh( t/fin ) ;
3845 q = stm_get_q( imax, t, f, b, u ) ;
3846 vout = ( q - capai*vin - qinit )/capa ;
3847 isat = a*(vin-vt)*(vin-vt)/(1.0+b*(vin-vt));
3848 stm_modscm_dual_calc_rsat( imax, isat, a, b, rlin, rsat, -1.0, -1.0, vdd, vt, vin, &rs, NULL, NULL, NULL, NULL ) ;
3849
3850 if( rsat < 0.0 )
3851 return 0.0 ;
3852
3853 qsat = qsat + vout/rs ;
3854 t = t + dt ;
3855 }
3856 while( vout < seuil );
3857
3858 ceqrsat = qsat*dt/seuil*1000.0 ;
3859
3860 return ceqrsat ;
3861 }
3862
3863 /****************************************************************************/
3864
3865 /*
3866 Calcule une capacité equivalente à la charge perdue dans rsat lors d'une
3867 transition. La transition est modélisée par une tangente hyperbolique.
3868
3869 vt, vmax, f : paramètres de la tangente hyperbolique de sortie.
3870 rsat : valeur de la résistance.
3871 seuil : tension où l'on réalise la mesure
3872 threshold : seuil logique de la porte : vdd/2
3873 te : instant de commutation de l'entrée minimum à partir duquel
3874 on compte rsat
3875 ts : instant de commutation de la sortie à threshold
3876 fout : estimation du front de sortie.
3877
3878 retour : capacité equivalente.
3879
3880 ATTENTION : cette fonction ne doit pas s'utiliser si on a un modèle de
3881 switch utilisant RINT.
3882 */
3883
3884 double stm_modscm_dual_ceqrsat( double imax,
3885 double vt, // output slope
3886 double vmax,
3887 double f,
3888 double vddin, // input slope normalized
3889 double fin,
3890 double rsat,
3891 double rlin,
3892 double an,
3893 double bn,
3894 double seuil,
3895 double threshold,
3896 double te,
3897 double ts)
3898 {
3899 double ta, // Instant de début de la commutation.
3900 tb, // Instant de fin de la commutation.
3901 qsat, // Charge equivalente.
3902 ceq, // Capacité equivalente.
3903 dt, // Ecart entre les deux référentiels
3904 tee, // Instant de commutation de la sortie
3905 tst;
3906 int i, n ;
3907 double vea, veb ;
3908 double vgsa, vgsb, dve ;
3909 double rsatr ;
3910 double tsa, tsb ;
3911 static int fordebug = 0 ;
3912 double isat, vgs ;
3913
3914 fordebug++ ;
3915
3916 if( seuil > 0.97 * vmax )
3917 seuil = 0.97 * vmax ;
3918
3919 /*
3920 modèle de front :
3921 t>=0 : v=vt+(vdd-vt)*tanh(t/f)
3922 t<0 : v=(vdd-vt)*t/f+vt
3923 */
3924
3925 ta = -f * vt / (vmax-vt);
3926
3927 if( seuil > vt )
3928 tb = f * atanh( (seuil-vt)/(vmax-vt) ) ;
3929 else
3930 tb = f * (seuil-vt)/(vmax-vt) ;
3931
3932 if( threshold > vt )
3933 tst = f * atanh( (threshold-vt)/(vmax-vt) ) ;
3934 else
3935 tst = f * (threshold-vt)/(vmax-vt) ;
3936
3937 // On vérifie si on est bien après l'entrée.
3938 dt = ts-tst; // Ecart entre le référentiel de l'entrée et de la sortie
3939 tee = dt+ta; // Début de commutation de la sortie dans le référentiel de l'entrée
3940 if( tee < te ) {
3941 ta = te-dt; // Début de commutation de la sortie
3942 }
3943
3944 if( ta < tb ) {
3945
3946 n=3;
3947
3948 vea = vddin - vddin*tanh( (ta+dt)/fin ) ;
3949 veb = vddin - vddin*tanh( (tb+dt)/fin ) ;
3950 dve = (veb-vea)/n ;
3951
3952 qsat = 0.0 ;
3953
3954 for( i=0; i < n ; i++ ) {
3955
3956 vgsa = vea + dve*((float)i) ;
3957
3958 if( vgsa < 0.01*vmax ) {
3959
3960 /* lorsque vgsb devient très faible, le calcul de tsb est impossible (atanh(1)=inf).
3961 On considère dans ce cas qu'on est sur la dernière borne qui va jusqu'à tb */
3962 i = n ;
3963 vgsa = 0.0 ;
3964 vgsb = 0.0 ;
3965 tsa = ta ;
3966 tsb = tb ;
3967
3968 }
3969 else {
3970
3971 tsa = fin * atanh( (vddin-vgsa)/vddin ) - dt ;
3972
3973 vgsb = vgsa + dve ;
3974
3975 if( vgsb < 0.01*vmax ) {
3976 /* lorsque vgsb devient très faible, le calcul de tsb est impossible (atanh(1)=inf).
3977 On considère dans ce cas qu'on est sur la dernière borne qui va jusqu'à tb */
3978 i = n ;
3979 vgsb = 0.0 ;
3980 tsb = tb ;
3981 }
3982 else
3983 tsb = fin * atanh( (vddin-vgsb)/vddin ) - dt ;
3984 }
3985
3986 vgs = (vddin+vt)-vgsb ;
3987 isat = an*(vgs-vt)*(vgs-vt)/(1.0+bn*(vgs-vt));
3988 stm_modscm_dual_calc_rsat( imax, isat, an, bn, rlin, rsat, -1.0, -1.0, vmax, vt, vgs, &rsatr, NULL, NULL , NULL, NULL );
3989
3990 if( rsatr < 0.0 ) {
3991 qsat = 0.0 ;
3992 break ;
3993 }
3994
3995 qsat = qsat + ( f*(vmax-vt) * log(cosh(tsb/f)/cosh(tsa/f)) + vt*(tsb-tsa) ) / rsatr ;
3996 }
3997
3998 ceq = qsat / seuil * 1000.0 ;
3999 }
4000 else
4001 ceq = 0.0;
4002
4003 return ceq;
4004 }
4005
4006 /****************************************************************************/
4007
4008 double stm_modscm_dual_calts_rsat_full_range (double capai,
4009 double imax,
4010 double an,
4011 double bn,
4012 double U,
4013 double VT,
4014 double vddmax,
4015 double threshold,
4016 double seuil,
4017 double rsat,
4018 double rlin,
4019 double c,
4020 double fin,
4021 double F,
4022 double te,
4023 double t0,
4024 double vddin,
4025 stm_pwl *pwl
4026 )
4027 {
4028 double vsat ;
4029 double fout ;
4030 double capa ;
4031 double ceqrsat ;
4032 double tf ;
4033 double tsat ;
4034 double rsatmin ;
4035 stm_pwth pwth[10] ;
4036 int npwth;
4037 stm_pwth *ptpwth ;
4038
4039 ptpwth = NULL ;
4040 npwth = 0 ;
4041 if( pwl ) {
4042 if( stm_pwl_to_tanh( pwl, VT, vddin+VT, pwth, &npwth, fin ) )
4043 ptpwth = pwth ;
4044 }
4045
4046 fout = stm_modscm_dual_calslew( imax, an, bn, U, VT, vddmax, c, fin, F, t0);
4047
4048 ceqrsat = stm_modscm_dual_ceqrsat( imax, VT, vddmax, fout, U, F, rsat, rlin, an, bn, seuil, threshold, te, t0 );
4049 capa = c + ceqrsat ;
4050
4051 rsatmin = vddmax/imax ;
4052
4053 if( rsat > rsatmin && rsatmin > rlin ) {
4054 vsat = vddmax - ( imax - vddmax / rsat ) * rlin * rsat / ( rsat - rlin ) ;
4055 if( seuil < vsat )
4056 tf = stm_modscm_dual_calts( imax, an, bn, U, seuil, capa, F, 0.0, VT, vddin, capai, NULL, NULL, fin, ptpwth, npwth, 0.0, 0.0, 0.0, NULL );
4057 else {
4058 tsat = stm_modscm_dual_calts( imax, an, bn, U, vsat, capa, F, 0.0, VT, vddin, capai, NULL, NULL, fin, ptpwth, npwth, 0.0, 0.0, 0.0, NULL );
4059 /* bonne relation, mise en commentaire en attendant que soit résulu le pb de modélisation des slopes
4060 qui rend certains bench d'ifx defectueux
4061 tf = tsat - rlin * c/1000.0 * log( 1.0 - ( seuil - vsat ) / ( vddmax - vsat ) );
4062 */
4063 tf = tsat - rlin * (capa+capai)/1000.0 * log( 1.0 - ( seuil - vsat ) / ( vddmax - vsat ) );
4064 }
4065 }
4066 else
4067 tf = stm_modscm_dual_calts( imax, an, bn, U, seuil, capa, F, 0.0, VT, vddin, capai, NULL, NULL, fin, ptpwth, npwth, 0.0, 0.0, 0.0, NULL );
4068
4069 return tf ;
4070 }
4071
4072 /****************************************************************************/
4073
4074 double stm_modscm_dual_calslew (double imax,
4075 double an,
4076 double bn,
4077 double U,
4078 double VT,
4079 double vddmax,
4080 double c,
4081 double fin,
4082 double F,
4083 double ts)
4084 {
4085 double pente,
4086 fout;
4087
4088 if(c < 0.001)
4089 return fin;
4090
4091 /* pente en vdd/2 et front de sortie */
4092 pente = imax * ((1 + bn * U) * pow (tanh (ts / F), 2)) / (c * (1 + bn * U * tanh (ts / F)));
4093
4094 if( VT < vddmax/2.0 )
4095 fout = ((3 * vddmax - 4 * VT) * vddmax) / (4 * pente * (vddmax - VT)) / 1000;
4096 else
4097 fout = (vddmax-VT)/pente/1000.0 ;
4098
4099 an=0.0;
4100 return fout;
4101 }
4102
4103 /****************************************************************************/
4104
4105 long stm_modscm_dual_calslope (double imax,
4106 double an,
4107 double bn,
4108 double vddin,
4109 double VT,
4110 double seuil,
4111 double c,
4112 double fin)
4113 {
4114 double an1,
4115 bn1,
4116 rc,
4117 sf,
4118 b = 0.0,
4119 z = 0.0,
4120 tt = 0.0,
4121 ttt = 0.0,
4122 k = 0.0,
4123 c1 = 0.0,
4124 U,
4125 F,
4126 slope;
4127 long i = 0;
4128 float ltt;
4129
4130 /* calcul de la tension rapportée */
4131 U = (imax * bn + sqrt (pow ((imax * bn), 2) + 4 * an * imax)) / (2 * an);
4132
4133 /* calcul du front rapporté */
4134 F = fin * U / vddin;
4135
4136 an1 = an / bn;
4137 bn1 = 1 / (U * bn);
4138 c1 = c;
4139
4140 /* calcul des deux premiers termes de l'équation de charge Qn(t) */
4141 z = ((seuil / 1000) * c1) / (F * an1 * U);
4142 tt = (1.0 + bn1) * z;
4143 rc = tt ;
4144 sf = ((1.0 + bn1) * LOG_2) - (bn1 * bn1 * (log (0.5 * ((bn1 + 1.0) / bn1))) / (1.0 - bn1));
4145 tt += sf ;
4146
4147 /* convergence du troisieme terme */
4148 do
4149 {
4150 i++;
4151 ltt = tt;
4152 b = exp (-2.0 * tt);
4153 ttt = (1.0 + bn1) * log (2.0 / (1.0 + b))
4154 - ((bn1 * bn1) / (1.0 - bn1)) * log (1.0 + ((1.0 - bn1) * (1.0 - b) / (2.0 * bn1)));
4155 tt = (1.0 + bn1) * z + ttt;
4156 }
4157 while( (fabs((ltt-tt)/tt) > STM_MCC_EPSILON) && (i < 100) );
4158
4159 k = (seuil - VT) / vddin;
4160 sf = (tt / (rc + sf)) * sf ;
4161 sf -= 0.5 * log ((1.0 + k) / (1.0 - k)) ;
4162 slope = (long)(1000.0 * sf) ;
4163
4164 return slope;
4165 }
4166
4167 /****************************************************************************/
4168
4169 float stm_modscm_dual_capaeq ( dualparams *dual, stm_dual_param_timing *paramtiming, float slew, float r, float c1, float c2, float vth, char *signame )
4170 {
4171 stm_param_isat param ;
4172 float cconf ;
4173 float load ;
4174 stm_qsat qsat ;
4175 float localthreshold ;
4176 float capaadd ;
4177 double ceqrsat ;
4178
4179 cconf = stm_modscm_dual_cconf ( dual, slew );
4180 ceqrsat = 0.0 ;
4181
4182 if( paramtiming && V_BOOL_TAB[ __AVT_CEQRSAT_FOR_PILOAD ].VALUE ) {
4183 if( vth >= paramtiming->VSAT )
4184 localthreshold = paramtiming->VSAT ;
4185 else
4186 localthreshold = vth ;
4187 stm_modscm_dual_calts_qsat( paramtiming, localthreshold, NULL, &qsat, &ceqrsat, NULL );
4188 }
4189
4190 if( paramtiming && V_BOOL_TAB[ __STM_ENHANCED_CAPAEQ_FOR_PILOAD ].VALUE ) {
4191 param.IMAX = paramtiming->IMAX ;
4192 param.A = paramtiming->AN ;
4193 param.B = paramtiming->BN ;
4194 param.VT = paramtiming->VT ;
4195 param.U = paramtiming->U ;
4196 param.F = paramtiming->F ;
4197 param.NTH = paramtiming->NTHSHRK ;
4198 param.PWTH = paramtiming->PWTHSHRK ;
4199 cconf = 2.0*paramtiming->CAPAI + paramtiming->CAPA ;
4200 }
4201 else {
4202
4203 param.IMAX = dual->DP[STM_IMAX] ;
4204 param.B = dual->DP[STM_BN] ;
4205 param.A = -1.0 ;
4206 param.VT = -1.0 ;
4207 stm_modscm_dual_cal_UF( dual->DP[STM_IMAX],
4208 dual->DP[STM_AN],
4209 dual->DP[STM_BN],
4210 dual->DP[STM_VDDIN],
4211 0.0,
4212 slew,
4213 &(param.U),
4214 &(param.F)
4215 );
4216 param.NTH = 0;
4217 param.PWTH = NULL;
4218 }
4219
4220 capaadd = cconf + ceqrsat ;
4221 if( paramtiming && vth > dual->DP[STM_THRESHOLD] && V_BOOL_TAB[ __STM_PILOAD_SATURATION ].VALUE )
4222 load = stm_capaeq_fn( (char (*)(void*,double,double*)) stm_isat, (void*) &param, 10.0*slew, r, c1+capaadd, c2, vth, paramtiming->VSAT, paramtiming->RLIN, paramtiming->VDDMAX, signame );
4223 else
4224 load = stm_capaeq_fn( (char (*)(void*,double,double*)) stm_isat, (void*) &param, 10.0*slew, r, c1+capaadd, c2, vth, -1.0, -1.0, -1.0, signame );
4225 load = load - capaadd ;
4226
4227 return load ;
4228 }
4229
4230 /****************************************************************************/
4231
4232 char stm_isat( stm_param_isat *param, double t, double *i )
4233 {
4234 double uin ;
4235
4236 if( param->NTH ) {
4237 if( t<0.0 )
4238 *i=0.0 ;
4239 else {
4240 uin = stm_get_v_pwth( t, param->VT, param->U+param->VT, STM_UP, param->PWTH )-param->VT;
4241 *i = param->A*uin*uin/(1.0+param->B*uin);
4242 if( *i > param->IMAX ) {
4243 *i = param->IMAX ;
4244 }
4245 }
4246 }
4247 else {
4248 *i = stm_get_ic_imax( t, param->U, param->IMAX, param->F, param->B );
4249 }
4250
4251 return 1;
4252 }
4253
4254 /****************************************************************************/
4255
4256 int stmtanhfn( stmtanhdata *data, double t, double *v )
4257 {
4258 if( t-data->T0>0.0 )
4259 *v = data->VT+(data->VDD-data->VT)*tanh( (t-data->T0)/data->F );
4260 else {
4261 *v = (data->VDD-data->VT)*(t-data->T0)/data->F+data->VT ;
4262 }
4263 if( *v<0.0 )
4264 *v = 0.0 ;
4265
4266 return 1 ;
4267 }
4268
4269 void stm_plot_tanh( char *name, float f, float vt, float vdd, float t0, float vth, char sens )
4270 {
4271 float te ;
4272 float dt ;
4273 float t ;
4274 float vu ;
4275 float v ;
4276 FILE *ptf ;
4277
4278 ptf = mbkfopen( name, NULL, "w" );
4279 if( !ptf ) {
4280 printf( "can't open file for writing\n" );
4281 return ;
4282 }
4283
4284 if( vt > vth )
4285 te = f * (vth-vt)/(vdd-vt);
4286 else
4287 te = f * atanh((vth-vt)/(vdd-vt));
4288
4289 dt = t0-te ;
4290
4291 t = -f*vt/(vdd-vt);
4292 vu = 0.0 ;
4293 if( sens=='U' || sens=='u' || sens=='R' || sens=='r' )
4294 v = vu ;
4295 else
4296 v = vdd-vu ;
4297 fprintf( ptf, "%g %g\n", (t+dt)*1e-12, v );
4298
4299 for( t=0.0 ; t<=3*f ; t++ ) {
4300 vu = vt+(vdd-vt)*tanh(t/f);
4301 if( sens=='U' || sens=='u' || sens=='R' || sens=='r' )
4302 v = vu ;
4303 else
4304 v = vdd-vu ;
4305 fprintf( ptf, "%g %g\n", (t+dt)*1e-12, v );
4306 }
4307
4308 fclose(ptf);
4309 }