Initial version of donated sources by Avertec, 3.4p5.
[tas-yagle.git] / distrib / sources / tas / tas / tas_tpiv.c
1 /****************************************************************************/
2 /* */
3 /* Chaine de CAO & VLSI Alliance */
4 /* */
5 /* Produit : TAS Version 5 */
6 /* Fichier : tas_tpiv.c */
7 /* */
8 /* (c) copyright 1991-1998 Laboratoire LIP6 equipe ASIM */
9 /* Tous droits reserves */
10 /* Support : e-mail alliance-support@asim.lip6.fr */
11 /* */
12 /* Auteur(s) : Grégoire Avot */
13 /* */
14 /****************************************************************************/
15 /* calcul des temps de propagation entre une sortie de cone */
16 /* et toutes ses entrees */
17 /****************************************************************************/
18
19 #include "tas.h"
20
21 int TPIV_DEBUG_IBR = 0 ;
22
23 mcc_trans_mcc* tpiv_addtransmcc( tpiv *br, stm_solver_maillon *stmm, link_list *link )
24 {
25 mcc_trans_mcc *trsmcc ;
26 chain_list *head ;
27 float vg ;
28 double vbulk ;
29
30 vg = tpiv_get_voltage_driving_lotrs( link->ULINK.LOTRS );
31
32 if( TAS_CONTEXT->TAS_LEVEL == 2 )
33 elp_lotrs_param_get( link->ULINK.LOTRS,NULL,NULL, NULL, NULL,NULL, NULL, NULL, NULL,NULL,&vbulk,NULL,NULL,NULL,NULL );
34 else {
35 if( MLO_IS_TRANSP(link->ULINK.LOTRS->TYPE) )
36 vbulk = tas_getparam( link->ULINK.LOTRS, TAS_CASE, TP_VDDmax );
37 else
38 vbulk = 0.0 ;
39 }
40
41 trsmcc = mcc_create_trans_mcc( link->ULINK.LOTRS,
42 tas_getparam ( link->ULINK.LOTRS, TAS_CASE, TP_VDDmax),
43 TAS_CASE,
44 link->SIG,
45 vg,
46 vbulk
47 );
48
49 if( getptype( link->USER, TAS_LINK_CARAC ) ) {
50 trsmcc->TRWIDTH = TAS_GETWIDTH( link ) ;
51 trsmcc->TRLENGTH = TAS_GETLENGTH( link );
52 }
53
54 br->HEADTRSMCC = addchain( br->HEADTRSMCC, trsmcc );
55
56 head = NULL ;
57 head = addchain( head, trsmcc );
58 stm_solver_add_model( stmm,
59 (char(*)(void*,float,float,float*))mcc_mcc_ids_list,
60 (char(*)(void*,float,float,float*))mcc_mcc_vds_list,
61 head,
62 head
63 );
64 freechain( head );
65 return trsmcc ;
66 }
67
68 void tpiv_addtransmcc_switch( tpiv *br, stm_solver_maillon *stmm, link_list *link, lotrs_list *lotrs )
69 {
70 float rate = 1.0 ;
71 mcc_trans_mcc *trs1 ;
72 mcc_trans_mcc *trs2 ;
73 chain_list *head ;
74 float vg ;
75 double vbulk ;
76
77 if( !V_BOOL_TAB[ __AVT_NEW_SWITCH_MODEL ].VALUE ) {
78
79 trs1 = tpiv_addtransmcc( br, stmm, link );
80
81 rate = tas_get_current_rate( link ) ;
82 trs1->TRWIDTH = trs1->TRWIDTH * rate ;
83
84 }
85 else {
86
87 vg = tpiv_get_voltage_driving_lotrs( link->ULINK.LOTRS );
88
89 if( TAS_CONTEXT->TAS_LEVEL == 2 )
90 elp_lotrs_param_get( link->ULINK.LOTRS, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &vbulk,NULL,NULL,NULL,NULL );
91 else {
92 if( MLO_IS_TRANSP(link->ULINK.LOTRS->TYPE) )
93 vbulk = tas_getparam( link->ULINK.LOTRS, TAS_CASE, TP_VDDmax );
94 else
95 vbulk = 0.0 ;
96 }
97
98 trs1 = mcc_create_trans_mcc( link->ULINK.LOTRS,
99 tas_getparam ( link->ULINK.LOTRS, TAS_CASE, TP_VDDmax),
100 TAS_CASE,
101 link->SIG,
102 vg,
103 vbulk
104 );
105
106 if( getptype( link->USER, TAS_LINK_CARAC ) ) {
107 trs1->TRWIDTH = TAS_GETWIDTH( link ) ;
108 trs1->TRLENGTH = TAS_GETLENGTH( link );
109 }
110
111 vg = tpiv_get_voltage_driving_lotrs( lotrs );
112
113 if( TAS_CONTEXT->TAS_LEVEL == 2 )
114 elp_lotrs_param_get( lotrs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &vbulk,NULL,NULL,NULL,NULL );
115 else {
116 if( MLO_IS_TRANSP(lotrs->TYPE) )
117 vbulk = tas_getparam( lotrs, TAS_CASE, TP_VDDmax );
118 else
119 vbulk = 0.0 ;
120 }
121
122 trs2 = mcc_create_trans_mcc( lotrs,
123 tas_getparam ( lotrs, TAS_CASE, TP_VDDmax),
124 TAS_CASE,
125 link->SIG,
126 vg,
127 vbulk
128 );
129 /* the TAS_LINK_CARAC needs to update transistor dimension is not available
130 here... to be done ! */
131
132 br->HEADTRSMCC = addchain( br->HEADTRSMCC, trs1 );
133 br->HEADTRSMCC = addchain( br->HEADTRSMCC, trs2 );
134
135 head = NULL ;
136 head = addchain( head, trs1 );
137 head = addchain( head, trs2 );
138 stm_solver_add_model( stmm,
139 (char(*)(void*,float,float,float*))mcc_mcc_ids_list,
140 (char(*)(void*,float,float,float*))mcc_mcc_vds_list,
141 head,
142 head
143 );
144 freechain( head );
145 }
146 }
147
148 /******************************************************************************\
149 Convertie une branche au format CNS vers le format stm_solver()
150 Les tensions sur les grilles sont initialisées à vdd.
151 \******************************************************************************/
152 tpiv* tpiv_createbranch( link_list *head, char transtype )
153 {
154 link_list *cnsm;
155 stm_solver_maillon *stmm;
156 mcc_trans_spice *trsspice;
157 mcc_trans_mcc *trsmcc;
158 tpiv *br;
159 long w, l;
160 ptype_list *ptype;
161 lotrs_list *trspair;
162 float rate;
163 chain_list *trlist;
164 float vg ;
165 double vbulk ;
166
167 br = tpiv_alloc();
168
169 /* Transforme la branche CNS en branche STM */
170 for( cnsm = head ; cnsm ; cnsm = cnsm->NEXT ) {
171 if ((cnsm->TYPE & CNS_EXT) == CNS_EXT) break;
172 stmm = stm_solver_new_maillon();
173
174 switch( transtype ) {
175
176 case TAS_TRMODEL_MCCRSAT :
177
178 trspair = NULL ;
179 if( (cnsm->TYPE & CNS_SWITCH)==CNS_SWITCH ) {
180 ptype = getptype( cnsm->ULINK.LOTRS->USER, TAS_TRANS_SWITCH );
181 if( ptype )
182 trspair = (lotrs_list*)ptype->DATA ;
183 }
184
185 if( trspair )
186 tpiv_addtransmcc_switch( br, stmm, cnsm, trspair );
187 else
188 trsmcc = tpiv_addtransmcc( br, stmm, cnsm );
189
190 break;
191
192 case TAS_TRMODEL_SPICE :
193
194 vg = tpiv_get_voltage_driving_lotrs( cnsm->ULINK.LOTRS );
195
196 /*
197 if( TAS_CONTEXT->TAS_LEVEL == 2 )
198 */
199 elp_lotrs_param_get( cnsm->ULINK.LOTRS, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &vbulk,NULL,NULL,NULL,NULL );
200 /*
201 else {
202 if( MLO_IS_TRANSP(cnsm->ULINK.LOTRS->TYPE) )
203 vbulk = tas_getparam( cnsm->ULINK.LOTRS, TAS_CASE, TP_VDDmax );
204 else
205 vbulk = 0.0 ;
206 }
207 */
208
209 trsspice = mcc_create_trans_spice( cnsm->ULINK.LOTRS,
210 tas_getparam ( cnsm->ULINK.LOTRS,
211 TAS_CASE,
212 TP_VDDmax),
213 cnsm->SIG,
214 vg,
215 vbulk
216 );
217 br->HEADTRSSPICE = addchain( br->HEADTRSSPICE, trsspice );
218 elpLotrsGetUnShrinkDim( cnsm->ULINK.LOTRS,
219 TAS_GETLENGTH( cnsm ),
220 TAS_GETWIDTH( cnsm ),
221 &l,
222 &w,
223 TAS_CASE
224 );
225 rate = tas_get_current_rate( cnsm );
226 w = w * rate ;
227 trsspice->TRLENGTH = ((float)l)*1e-6 / ((float)SCALE_X) ;
228 trsspice->TRWIDTH = ((float)w)*1e-6 / ((float)SCALE_X) ;
229
230 // Voir le deshrinkage
231 // trsspice->WIDTH = TAS_GETWIDTH( cnsm );
232 // trsspice->LENGTH = TAS_GETLENGTH( cnsm );
233 // Voir l'influence de WIDTH sur les aires.
234
235 trlist = addchain( NULL, trsspice );
236 stm_solver_add_model( stmm,
237 (char(*)(void*,float,float,float*))mcc_spice_ids_list,
238 (char(*)(void*,float,float,float*))mcc_spice_vds_list,
239 trlist,
240 trlist
241 );
242 freechain( trlist );
243 break;
244
245 default :
246 fprintf( stderr, "Bad transistor model.\n" );
247 EXIT(1);
248 }
249
250 br->HEAD = stm_solver_maillon_addchain( br->HEAD, stmm );
251 }
252
253 br->HEAD = stm_solver_maillon_reverse( br->HEAD );
254
255 return br;
256 }
257
258 /******************************************************************************\
259 Crée une branche pour le calcul du leakage dont le transistor activelink est bloque
260 \******************************************************************************/
261 tpiv* tpiv_createbranch_leakage( link_list *head, link_list *activelink, char transtype )
262 {
263 link_list *cnsm;
264 stm_solver_maillon *stmm;
265 mcc_trans_spice *trsspice;
266 mcc_trans_mcc *trsmcc;
267 tpiv *br;
268 long w, l;
269 ptype_list *ptype;
270 lotrs_list *trspair;
271 float rate;
272 chain_list *trlist;
273 float vg ;
274 double vbulk ;
275
276 br = tpiv_alloc();
277
278 /* Transforme la branche CNS en branche STM */
279 for( cnsm = head ; cnsm ; cnsm = cnsm->NEXT ) {
280 if ((cnsm->TYPE & CNS_EXT) == CNS_EXT) break;
281 stmm = stm_solver_new_maillon();
282
283 if((cnsm == activelink) || (TAS_PATH_TYPE == 'm')){
284 vg = tpiv_get_blocked_voltage_driving_lotrs( cnsm->ULINK.LOTRS );
285 }else{
286 vg = tpiv_get_voltage_driving_lotrs( cnsm->ULINK.LOTRS );
287 }
288
289 elp_lotrs_param_get( cnsm->ULINK.LOTRS, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &vbulk,NULL,NULL,NULL,NULL );
290
291 trsspice = mcc_create_trans_spice( cnsm->ULINK.LOTRS,
292 tas_getparam ( cnsm->ULINK.LOTRS,
293 TAS_CASE,
294 TP_VDDmax),
295 cnsm->SIG,
296 vg,
297 vbulk
298 );
299 br->HEADTRSSPICE = addchain( br->HEADTRSSPICE, trsspice );
300 elpLotrsGetUnShrinkDim( cnsm->ULINK.LOTRS,
301 TAS_GETLENGTH( cnsm ),
302 TAS_GETWIDTH( cnsm ),
303 &l,
304 &w,
305 TAS_CASE
306 );
307 rate = tas_get_current_rate( cnsm );
308 w = w * rate ;
309 trsspice->TRLENGTH = ((float)l)*1e-6 / ((float)SCALE_X) ;
310 trsspice->TRWIDTH = ((float)w)*1e-6 / ((float)SCALE_X) ;
311
312 trlist = addchain( NULL, trsspice );
313 stm_solver_add_model( stmm,
314 (char(*)(void*,float,float,float*))mcc_spice_ids_list,
315 (char(*)(void*,float,float,float*))mcc_spice_vds_list,
316 trlist,
317 trlist
318 );
319 freechain( trlist );
320
321
322 br->HEAD = stm_solver_maillon_addchain( br->HEAD, stmm );
323 }
324
325 br->HEAD = stm_solver_maillon_reverse( br->HEAD );
326
327 return br;
328 }
329
330 tpiv* tpiv_createbranch_leakage_2( link_list *head, link_list *activelink, char transtype )
331 {
332 link_list *cnsm;
333 stm_solver_maillon *stmm;
334 mcc_trans_spice *trsspice;
335 mcc_trans_mcc *trsmcc;
336 tpiv *br;
337 long w, l;
338 ptype_list *ptype;
339 lotrs_list *trspair;
340 float rate;
341 chain_list *trlist;
342 float vg ;
343 double vbulk ;
344 chain_list *chain, *ptparachain, *ptchain;
345 lotrs_list *ptparatrans, *ptlotrs;
346 ptype_list *ptuser;
347 cone_list *cone;
348
349 br = tpiv_alloc();
350
351 /* Transforme la branche CNS en branche STM */
352 for( cnsm = head ; cnsm ; cnsm = cnsm->NEXT ) {
353 if ((cnsm->TYPE & CNS_EXT) == CNS_EXT) break;
354 stmm = stm_solver_new_maillon();
355
356 cone = (cone_list *)getptype( cnsm->ULINK.LOTRS->USER, CNS_DRIVINGCONE )->DATA;
357 if((((cone->TECTYPE & (CNS_STATE_ONE|CNS_ONE)) != 0) && MLO_IS_TRANSN(cnsm->ULINK.LOTRS->TYPE))
358 || (((cone->TECTYPE & (CNS_STATE_ZERO|CNS_ZERO)) != 0) && MLO_IS_TRANSP(cnsm->ULINK.LOTRS->TYPE))){
359 vg = tpiv_get_voltage_driving_lotrs( cnsm->ULINK.LOTRS );
360 }else{
361 vg = tpiv_get_blocked_voltage_driving_lotrs( cnsm->ULINK.LOTRS );
362 }
363
364 elp_lotrs_param_get( cnsm->ULINK.LOTRS, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &vbulk,NULL,NULL,NULL,NULL );
365
366 trsspice = mcc_create_trans_spice( cnsm->ULINK.LOTRS,
367 tas_getparam ( cnsm->ULINK.LOTRS,
368 TAS_CASE,
369 TP_VDDmax),
370 cnsm->SIG,
371 vg,
372 vbulk
373 );
374 br->HEADTRSSPICE = addchain( br->HEADTRSSPICE, trsspice );
375 ptlotrs = cnsm->ULINK.LOTRS;
376 if ((ptuser = getptype(ptlotrs->USER, MBK_TRANS_PARALLEL)) != NULL) {
377 ptparachain = (chain_list *)ptuser->DATA;
378 l = ptlotrs->LENGTH;
379 w = 0;
380 for (ptchain = ptparachain; ptchain; ptchain = ptchain->NEXT) {
381 ptparatrans = (lotrs_list *)ptchain->DATA;
382 w += ptparatrans->WIDTH * (l / ptparatrans->LENGTH);
383 }
384 }else{
385 l = ptlotrs->LENGTH;
386 w = ptlotrs->WIDTH;
387 }
388
389 rate = tas_get_current_rate( cnsm );
390 w = w * rate ;
391 trsspice->TRLENGTH = ((float)l)*1e-6 / ((float)SCALE_X) ;
392 trsspice->TRWIDTH = ((float)w)*1e-6 / ((float)SCALE_X) ;
393
394 trlist = addchain( NULL, trsspice );
395 stm_solver_add_model( stmm,
396 (char(*)(void*,float,float,float*))mcc_spice_ids_list,
397 (char(*)(void*,float,float,float*))mcc_spice_vds_list,
398 trlist,
399 trlist
400 );
401 freechain( trlist );
402
403
404 br->HEAD = stm_solver_maillon_addchain( br->HEAD, stmm );
405 }
406
407 br->HEAD = stm_solver_maillon_reverse( br->HEAD );
408
409 return br;
410 }
411 /******************************************************************************\
412 Libère une branche
413 \******************************************************************************/
414 void tpiv_freebranch( tpiv *br )
415 {
416 chain_list *scantrsmcc;
417 chain_list *scantrsspice;
418 mcc_trans_mcc *trsmcc;
419 mcc_trans_spice *trsspice;
420
421 stm_solver_maillon_freechain( br->HEAD );
422
423 for( scantrsmcc = br->HEADTRSMCC ;
424 scantrsmcc ;
425 scantrsmcc = scantrsmcc->NEXT
426 ) {
427 trsmcc = (mcc_trans_mcc*)scantrsmcc->DATA;
428 mcc_delete_trans_mcc( trsmcc );
429 }
430 freechain( br->HEADTRSMCC );
431
432 for( scantrsspice = br->HEADTRSSPICE ;
433 scantrsspice ;
434 scantrsspice = scantrsspice->NEXT
435 )
436 {
437 trsspice = (mcc_trans_spice*)scantrsspice->DATA;
438 mcc_delete_trans_spice( trsspice );
439 }
440 freechain( br->HEADTRSSPICE );
441
442 tpiv_free( br );
443 }
444
445 /******************************************************************************\
446 Crée un modèle timing_iv de la branche CNS passée en paramètre.
447 Pour l'instant, le conflit modélisé par une capacité calculée avec MCC.
448 head Premier maillon de la branche
449 active Maillon qui commute
450 vref Polarisation de la branche (vdd ou vss)
451 pconf0 Paramètre pour le calcul de la capacité
452 pconf1 Paramètre pour le calcul de la capacité
453 fin_vi Entrée : tension initiale
454 fin_vf Entrée : tension finale
455 fin_vs Entrée : seuil logique
456 vouti Sortie : tension initiale
457 \******************************************************************************/
458 timing_iv *tpiv_dualmodel( cone_list *cone,
459 branch_list *branch,
460 link_list *active,
461 float vref,
462 float pconf0,
463 float pconf1,
464 float fin_vi,
465 float fin_vf,
466 float fin_vs,
467 float vouti
468 )
469 {
470 tpiv *br;
471 timing_iv *iv = NULL;
472 tpiv_i d;
473 stm_solver_maillon_list *maillon;
474 link_list *link;
475 float vdd;
476 double capai;
477 double irap;
478 double temps;
479 double AX, BX, rtx, rx, VT, QX, QY, thr, vddmax, vddin, imax ;
480 char trtype;
481
482 tas_getmcc( branch->LINK,
483 active,
484 &vddin,
485 &AX,
486 &BX,
487 &rtx,
488 &rx,
489 &VT,
490 &QX,
491 &QY,
492 &thr,
493 &vddmax,
494 NULL,
495 NULL,
496 NULL,
497 NULL,
498 NULL
499 );
500 imax = tas_get_current ( branch, branch->LINK, 1.0, NO );
501 pconf0 = pconf0 + tas_getcapaparams (cone, branch, active, imax, QX, QY, &capai, &irap, &temps,TAS_UNKNOWN_EVENT,0);
502
503 switch( TAS_CONTEXT->TAS_LEVEL ) {
504 case 3:
505 trtype = TAS_TRMODEL_MCCRSAT;
506 break;
507 case 4:
508 trtype = TAS_TRMODEL_SPICE;
509 break;
510 default:
511 trtype = TAS_TRMODEL_MCCRSAT;
512 break;
513 }
514 br = tpiv_createbranch( branch->LINK, trtype );
515
516 d.HEAD = br->HEAD ;
517 d.TRTYPE = trtype ;
518 d.VDDMAX = vddmax ;
519
520 for( link=branch->LINK, maillon=br->HEAD ;
521 link && link != active ;
522 link = link->NEXT, maillon = maillon->NEXT );
523
524 if( link ) {
525 d.ACTIVE = maillon ;
526 d.TRS = link->ULINK.LOTRS ;
527
528 // Polarise le dernier élément
529 for( maillon = br->HEAD ; maillon->NEXT ; maillon = maillon->NEXT );
530 maillon->MAILLON->VS=vref;
531
532 vdd = tas_getparam( branch->LINK->ULINK.LOTRS, TAS_CASE, TP_VDDmax );
533 iv = stm_modiv_create( 10,
534 10,
535 vdd,
536 vdd,
537 (char(*)(void*,float,float,float*))tpiv_calc_i,
538 (void*)&d
539 );
540 if( iv ) {
541 stm_modiv_set_cf( iv, capai, pconf0, pconf1, irap );
542 stm_modiv_set_in( iv, VT, fin_vi, fin_vf, fin_vs );
543 stm_modiv_set_ti( iv, vouti );
544 }
545 }
546 tpiv_freebranch( br );
547
548 return iv;
549 }
550
551 char tpiv_calc_i( tpiv_i *model, float ve, float vs, float *is )
552 {
553 chain_list *chtrs ;
554 mcc_trans_mcc *trsmcc ;
555 mcc_trans_spice *trsspi ;
556 char ret;
557 float vg;
558
559 for( chtrs = model->ACTIVE->MAILLON->MODEL_VDS ; chtrs ; chtrs = chtrs->NEXT ) {
560 if( model->TRTYPE == TAS_TRMODEL_MCCRSAT ) {
561 trsmcc = (mcc_trans_mcc*)chtrs->DATA ;
562 if( trsmcc->TYPE == model->TRS->TYPE )
563 vg = ve ;
564 else
565 vg = model->VDDMAX - ve ;
566 trsmcc->VG = vg ;
567 }
568 else {
569 trsspi = (mcc_trans_spice*)chtrs->DATA ;
570 if( ( trsspi->TRANSTYPE == MCC_NMOS && MLO_IS_TRANSN( model->TRS->TYPE ) ) ||
571 ( trsspi->TRANSTYPE == MCC_PMOS && MLO_IS_TRANSP( model->TRS->TYPE ) ) )
572 vg = ve ;
573 else
574 vg = model->VDDMAX - ve ;
575 trsspi->VG = vg ;
576 }
577 }
578 ret = stm_solver_i( model->HEAD, vs, is );
579 return ret ;
580 }
581
582 void tpiv_set_voltage_driving_lotrs( lotrs_list *lotrs, float voltage )
583 {
584 ptype_list *ptl ;
585
586 ptl = getptype( lotrs->GRID->SIG->USER, TAS_SIG_VOLTAGE );
587 if( !ptl ) {
588 lotrs->GRID->SIG->USER = addptype( lotrs->GRID->SIG->USER, TAS_SIG_VOLTAGE, 0l );
589 ptl = lotrs->GRID->SIG->USER ;
590 }
591
592 ptl->DATA = (void*)((long)(voltage*1000.0));
593 }
594
595 void tpiv_clean_voltage_driving_lotrs( lotrs_list *lotrs )
596 {
597 lotrs->GRID->SIG->USER = testanddelptype( lotrs->GRID->SIG->USER, TAS_SIG_VOLTAGE );
598 }
599
600 float tpiv_get_voltage_driving_lotrs( lotrs_list *lotrs )
601 {
602 cone_list *cone_avant;
603 alim_list *power;
604 float voltage=0.0 ;
605 float vdeg=0.0 ;
606 char usedefault ;
607 ptype_list *ptl, *ptype ;
608
609 ptl = getptype( lotrs->GRID->SIG->USER, TAS_SIG_VOLTAGE );
610 if( ptl )
611 return ((float)((long)(ptl->DATA)))/1000.0 ;
612
613 usedefault = 1 ;
614
615 cone_avant = (cone_list *)getptype( lotrs->USER, CNS_DRIVINGCONE )->DATA ;
616
617 if( cone_avant ) {
618
619 power = cns_get_multivoltage( cone_avant );
620
621 if( power ) {
622
623 usedefault = 0 ;
624
625 if( ( lotrs->TYPE & CNS_TN) == CNS_TN ) {
626 if( TAS_PATH_TYPE == 'M' )
627 voltage = power->VDDMIN;
628 else
629 voltage = power->VDDMAX;
630 }
631 else {
632 if( TAS_PATH_TYPE == 'M' )
633 voltage = power->VSSMAX;
634 else
635 voltage = power->VSSMIN;
636 }
637 }
638
639 /* solution provisoire : ici, on prend la dégradation du maillon courant,
640 pas celle du cone d'entrée. */
641
642 if( MLO_IS_TRANSN( lotrs->TYPE) &&
643 ((cone_avant->TECTYPE & CNS_VDD_DEGRADED) == CNS_VDD_DEGRADED) ) {
644 vdeg = tas_getparam( lotrs, TAS_CASE, TP_deg);
645 if((ptype = getptype(cone_avant->USER, TAS_VDD_NOTDEG)) != NULL){
646 vdeg += *(float*)(&ptype->DATA);
647 }
648 vdeg -= tas_getparam ( lotrs, TAS_CASE, TP_VDDmax);
649
650 }
651 else {
652 if( MLO_IS_TRANSP( lotrs->TYPE) &&
653 ((cone_avant->TECTYPE & CNS_VSS_DEGRADED) == CNS_VSS_DEGRADED) ) {
654 vdeg = tas_getparam( lotrs, TAS_CASE, TP_deg);
655 }
656 }
657 }
658
659 /* prise en compte si degradation des inputs */
660
661 if( usedefault == 1 ) {
662 if( ( lotrs->TYPE & CNS_TN) == CNS_TN )
663 voltage = tas_getparam ( lotrs, TAS_CASE, TP_VDDmax);
664 else
665 voltage = 0.0;
666 }
667
668 voltage = voltage + vdeg ;
669
670 return voltage ;
671 }
672
673 /******************************************************************************\
674 Renvoie la tension de blocage d'un transistor pour le calcul du leakage
675 \******************************************************************************/
676 float tpiv_get_blocked_voltage_driving_lotrs( lotrs_list *lotrs )
677 {
678 cone_list *cone_avant;
679 alim_list *power;
680 float voltage=0.0 ;
681 float delta=0.0;
682 char usedefault ;
683
684 usedefault = 1 ;
685
686 cone_avant = (cone_list *)getptype( lotrs->USER, CNS_DRIVINGCONE )->DATA ;
687
688 if( cone_avant ) {
689
690 power = cns_get_multivoltage( cone_avant );
691
692 if( power ) {
693 /* tasLeakageRatio Calcul du delta voltage sur la tension de grille pour le leakage */
694 if (V_FLOAT_TAB[__AVT_LEAKAGE_RATIO].SET){
695 if( TAS_PATH_TYPE == 'M' )
696 delta = power->VDDMIN * V_FLOAT_TAB[__AVT_LEAKAGE_RATIO].VALUE;
697 else
698 delta = power->VDDMAX * V_FLOAT_TAB[__AVT_LEAKAGE_RATIO].VALUE;
699 }
700
701 usedefault = 0 ;
702
703 /* Si TN alors on la tension de blocage n'est pas tout a fait 0v si delta!=0 */
704 if( ( lotrs->TYPE & CNS_TN) == CNS_TN ) {
705 if( TAS_PATH_TYPE == 'M' )
706 voltage = power->VSSMAX + delta;
707 else
708 voltage = power->VSSMIN + delta;
709 }
710 else {
711 /* Si TP alors on la tension de blocage n'est pas tout a fait VDD si delta!=0 */
712 if( TAS_PATH_TYPE == 'M' )
713 voltage = power->VDDMIN - delta;
714 else
715 voltage = power->VDDMAX - delta;
716 }
717 }
718 }
719
720 if( usedefault == 1 ) {
721 if (V_FLOAT_TAB[__AVT_LEAKAGE_RATIO].SET){
722 delta = tas_getparam ( lotrs, TAS_CASE, TP_VDDmax) * V_FLOAT_TAB[__AVT_LEAKAGE_RATIO].VALUE;
723 }
724 if( ( lotrs->TYPE & CNS_TP) == CNS_TP )
725 voltage = tas_getparam ( lotrs, TAS_CASE, TP_VDDmax) - delta;
726 else
727 voltage = 0.0 + delta;
728 }
729
730 return voltage ;
731 }
732
733
734 /******************************************************************************\
735 Calcul le courant maximum dans une branche en utilisant stm_solver.
736 \******************************************************************************/
737 char tpiv_i_brdual( head, vout, valim, imax, savepol )
738 link_list *head;
739 float vout;
740 float valim;
741 float *imax;
742 char savepol;
743 {
744 tpiv *br ;
745 char r ;
746 char brtype ;
747 stm_solver_maillon_list *maillon ;
748 link_list *link ;
749
750 if( ( head->TYPE & (CNS_IN | CNS_INOUT ) ) != 0 )
751 return 0;
752
753 for( link = head->NEXT ; link ; link = link->NEXT ) {
754 if ((link->TYPE & CNS_EXT) == CNS_EXT) break;
755 if( !V_BOOL_TAB[ __AVT_NEW_SWITCH_MODEL ].VALUE ) {
756 if( link->ULINK.LOTRS->TYPE != head->ULINK.LOTRS->TYPE )
757 return 0;
758 }
759 }
760
761 switch( TAS_CONTEXT->TAS_LEVEL ) {
762 case 1:
763 case 3:
764 brtype = TAS_TRMODEL_MCCRSAT;
765 break;
766 case 2:
767 case 4:
768 brtype = TAS_TRMODEL_SPICE;
769 break;
770 default:
771 brtype = TAS_TRMODEL_MCCRSAT;
772 break;
773 }
774
775 br = tpiv_createbranch( head, brtype );
776 for( maillon = br->HEAD ; maillon->NEXT ; maillon = maillon->NEXT );
777 maillon->MAILLON->VS=valim;
778
779 r = stm_solver_i( br->HEAD, vout, imax );
780
781 if( savepol == YES ) {
782 for( maillon = br->HEAD, link = head ;
783 maillon ;
784 maillon = maillon->NEXT, link = link->NEXT ) {
785
786 // old: if(link->ULINK.LOTRS->TYPE==TRANSP)
787 if(MLO_IS_TRANSP(link->ULINK.LOTRS->TYPE))
788 tas_set_vpol( link, valim - maillon->MAILLON->VD );
789 else
790 tas_set_vpol( link, maillon->MAILLON->VD );
791 }
792 }
793
794 tpiv_freebranch( br );
795
796 if( TPIV_DEBUG_IBR &&
797 ( V_BOOL_TAB[ __TAS_CHECK_IMAX ].VALUE || V_BOOL_TAB[ __TAS_USE_BSIM_CURRENT ].VALUE )
798 ) {
799 float imcc ;
800 float d ;
801 static FILE *file=NULL ;
802
803 TPIV_DEBUG_IBR = 0 ;
804 for( link = head ; link ; link = link->NEXT ) {
805 if( ( link->TYPE & CNS_EXT ) == CNS_EXT )
806 break ;
807 if( getptype( link->ULINK.LOTRS->USER, MBK_TRANS_PARALLEL ) )
808 break ;
809 if( getptype( link->ULINK.LOTRS->USER, TAS_TRANS_SWITCH ) )
810 break ;
811 }
812
813 if( !link ) {
814 if( V_BOOL_TAB[ __TAS_CHECK_IMAX ].VALUE ) {
815 if( !file )
816 file = mbkfopen( "current", "dat", "w" );
817 }
818 brtype = TAS_TRMODEL_SPICE;
819 br = tpiv_createbranch( head, brtype );
820 for( maillon = br->HEAD ; maillon->NEXT ; maillon = maillon->NEXT );
821 maillon->MAILLON->VS=valim;
822 stm_solver_i( br->HEAD, vout, &imcc );
823 d = (*imax-imcc)*100.0/imcc ;
824 if( V_BOOL_TAB[ __TAS_CHECK_IMAX ].VALUE ) {
825 fprintf( file, "error=%f\n",d );
826 }
827 tpiv_freebranch( br );
828 if( V_BOOL_TAB[ __TAS_USE_BSIM_CURRENT ].VALUE )
829 *imax = imcc ;
830 }
831 }
832
833 return r;
834 }
835
836 /******************************************************************************\
837 Calcul du courant leakage d'une branche dont le transistor activelink est bloque
838 \******************************************************************************/
839 char tpiv_i_brdual_leakage( head, activelink, vout, valim, imax)
840 link_list *head;
841 link_list *activelink;
842 float vout;
843 float valim;
844 float *imax;
845 {
846 tpiv *br ;
847 char r ;
848 char brtype ;
849 stm_solver_maillon_list *maillon ;
850 link_list *link ;
851
852 if( ( head->TYPE & (CNS_IN | CNS_INOUT ) ) != 0 )
853 return 0;
854
855 for( link = head->NEXT ; link ; link = link->NEXT ) {
856 if ((link->TYPE & CNS_EXT) == CNS_EXT) break;
857 if( !V_BOOL_TAB[ __AVT_NEW_SWITCH_MODEL ].VALUE ) {
858 if( link->ULINK.LOTRS->TYPE != head->ULINK.LOTRS->TYPE )
859 return 0;
860 }
861 }
862
863 brtype = TAS_TRMODEL_SPICE;
864
865 br = tpiv_createbranch_leakage( head, activelink, brtype );
866 for( maillon = br->HEAD ; maillon->NEXT ; maillon = maillon->NEXT );
867 maillon->MAILLON->VS=valim;
868
869 r = stm_solver_i( br->HEAD, vout, imax );
870
871 tpiv_freebranch( br );
872
873
874 return r;
875 }
876
877 char tpiv_i_brdual_leakage_2( head, activelink, vout, valim, imax)
878 link_list *head;
879 link_list *activelink;
880 float vout;
881 float valim;
882 float *imax;
883 {
884 tpiv *br ;
885 char r ;
886 char brtype ;
887 stm_solver_maillon_list *maillon ;
888 link_list *link ;
889
890 if( ( head->TYPE & (CNS_IN | CNS_INOUT ) ) != 0 )
891 return 0;
892
893 for( link = head->NEXT ; link ; link = link->NEXT ) {
894 if ((link->TYPE & CNS_EXT) == CNS_EXT) break;
895 if( !V_BOOL_TAB[ __AVT_NEW_SWITCH_MODEL ].VALUE ) {
896 if( link->ULINK.LOTRS->TYPE != head->ULINK.LOTRS->TYPE )
897 return 0;
898 }
899 }
900
901 brtype = TAS_TRMODEL_SPICE;
902
903 br = tpiv_createbranch_leakage_2( head, activelink, brtype );
904 for( maillon = br->HEAD ; maillon->NEXT ; maillon = maillon->NEXT );
905 maillon->MAILLON->VS=valim;
906
907 r = stm_solver_i( br->HEAD, vout, imax );
908
909 tpiv_freebranch( br );
910
911
912 return r;
913 }
914 /******************************************************************************\
915 Renvoie le courant d'une branche lorsque tous les maillons commandés par le même
916 signal que celui qui controle activelink valent vin. Les autres sont drivés par
917 les tensions des cones d'avant.
918 \******************************************************************************/
919 int tpiv_get_i_multi_input( link0, activelink, vout, valim, vin, vinopp, trmodel, imax )
920 link_list *link0;
921 link_list *activelink;
922 float vout;
923 float valim;
924 float vin;
925 float vinopp;
926 char trmodel;
927 float *imax;
928 {
929 tpiv *br ;
930 char r ;
931 stm_solver_maillon_list *maillon ;
932 link_list *link ;
933
934 br = tpiv_createbranch( link0, trmodel );
935 for( maillon = br->HEAD ; maillon->NEXT ; maillon = maillon->NEXT );
936 maillon->MAILLON->VS=valim;
937
938 for( maillon = br->HEAD, link = link0 ;
939 maillon ;
940 maillon = maillon->NEXT, link = link->NEXT ) {
941
942 if( link->ULINK.LOTRS->GRID->SIG == activelink->ULINK.LOTRS->GRID->SIG ) {
943 tas_tpiv_set_vg_for_switch( maillon->MAILLON,
944 trmodel,
945 MLO_IS_TRANSN(activelink->ULINK.LOTRS->TYPE) ? 'N' : 'P',
946 vin,
947 vinopp
948 );
949 }
950 }
951
952 r = stm_solver_i( br->HEAD, vout, imax );
953
954 tpiv_freebranch( br );
955
956 return r ;
957 }
958
959 /******************************************************************************\
960 Trace dans un fichier le courant d'un branche lorsque le maillon 'actif' varie
961 de 'vin_d' a 'vin_f', et lorsque la la tension de sortie varie de 'vout_d' à 'vout_f'
962 Calcul le courant maximum dans une branche en utilisant stm_solver.
963 \******************************************************************************/
964 void tpiv_i_trace_brdual( filename, head, actif, brtype, vin_d, vin_f, vout_d, vout_f, valim, vdd )
965 char *filename;
966 link_list *head;
967 link_list *actif;
968 char brtype;
969 float vin_d;
970 float vin_f;
971 float vout_d;
972 float vout_f;
973 float valim;
974 float vdd;
975 {
976 tpiv *br;
977 char r;
978 stm_solver_maillon_list *maillon;
979 link_list *lnk;
980 int k, l ;
981 FILE *ptf;
982 float v, step;
983 float imax;
984 char buffer[256];
985 float vt;
986 float timax[3], vin[3] ;
987 int i;
988
989 br = tpiv_createbranch( head, brtype );
990 for( maillon = br->HEAD ; maillon->NEXT ; maillon = maillon->NEXT );
991 maillon->MAILLON->VS=valim;
992
993 k=100;
994
995 /**** variation de vin ****/
996 sprintf( buffer, "%s_vin.dat", filename );
997 ptf = fopen( buffer, "w" );
998 step = (vin_f-vin_d)/((float)k) ;
999
1000 for( l=0 , v=vin_d ; l<=k ; l++, v=v+step ) {
1001 for( maillon = br->HEAD, lnk = head ; maillon && lnk ; maillon = maillon->NEXT, lnk = lnk->NEXT ) {
1002 if( lnk->ULINK.LOTRS->GRID->SIG == actif->ULINK.LOTRS->GRID->SIG ) {
1003 tas_tpiv_set_vg_for_switch( maillon->MAILLON,
1004 brtype,
1005 MLO_IS_TRANSN(actif->ULINK.LOTRS->TYPE) ? 'N' : 'P',
1006 v,
1007 vdd-v
1008 );
1009 }
1010 }
1011
1012 r = stm_solver_i( br->HEAD, vout_f, &imax );
1013 fprintf( ptf, "%g %g\n", v, -imax );
1014 }
1015
1016 fclose( ptf );
1017
1018 /**** variation de vout ****/
1019 sprintf( buffer, "%s_vout.dat", filename );
1020 ptf = fopen( buffer, "w" );
1021 vt = tas_getparam( actif->ULINK.LOTRS, TAS_CASE, TP_VT );
1022 step = (vout_f-vout_d)/((float)k) ;
1023
1024 if( MLO_IS_TRANSN(actif->ULINK.LOTRS->TYPE) ) {
1025 vin[0] = 3.0 * (vin_f-vt)/3.0 + vt ;
1026 vin[1] = 2.0 * (vin_f-vt)/3.0 + vt ;
1027 vin[2] = 1.0 * (vin_f-vt)/3.0 + vt ;
1028 }
1029 else {
1030 vin[0] = 0.0*(vdd-vt-vin_f)/3.0 + vin_f ;
1031 vin[1] = 1.0*(vdd-vt-vin_f)/3.0 + vin_f ;
1032 vin[2] = 2.0*(vdd-vt-vin_f)/3.0 + vin_f ;
1033 }
1034
1035 fprintf( ptf, "#vin %g %g %g\n", vin[0], vin[1], vin[2] );
1036 for( l=0 , v=vout_d ; l<=k ; l++, v=v+step ) {
1037
1038 for( i=0; i<=2 ; i++ ) {
1039 for( maillon = br->HEAD, lnk = head ; maillon && lnk ; maillon = maillon->NEXT, lnk = lnk->NEXT ) {
1040 if( lnk->ULINK.LOTRS->GRID->SIG == actif->ULINK.LOTRS->GRID->SIG ) {
1041 tas_tpiv_set_vg_for_switch( maillon->MAILLON,
1042 brtype,
1043 MLO_IS_TRANSN(actif->ULINK.LOTRS->TYPE) ? 'N' : 'P',
1044 vin[i],
1045 vdd-vin[i]
1046 );
1047 }
1048 }
1049
1050 r = stm_solver_i( br->HEAD, v, &timax[i] );
1051 }
1052 fprintf( ptf, "%g %g %g %g\n", v, -timax[0], -timax[1], -timax[2] );
1053 }
1054
1055 fclose( ptf );
1056
1057 tpiv_freebranch( br );
1058 }
1059
1060 /******************************************************************************\
1061 Alloue une structure tpiv
1062 \******************************************************************************/
1063 tpiv* tpiv_alloc( void )
1064 {
1065 tpiv *s;
1066 s = (tpiv*)addptype( NULL, 0l, NULL );
1067 s->HEAD=NULL;
1068 s->HEADTRSSPICE=NULL;
1069 s->HEADTRSMCC=NULL;
1070
1071 return s;
1072 }
1073
1074 /******************************************************************************\
1075 Libère une structure tpiv
1076 \******************************************************************************/
1077 void tpiv_free( tpiv *s )
1078 {
1079 ptype_list *ptl;
1080 ptl = (ptype_list*)s;
1081 ptl->NEXT = NULL;
1082 freeptype( ptl );
1083 }
1084
1085 /******************************************************************************\
1086 Trace la tension de sortie d'un inverseur.
1087 \******************************************************************************/
1088
1089 void tpiv_inverter( char *fname,
1090 lotrs_list *tn,
1091 lotrs_list *tp,
1092 char sens,
1093 float f,
1094 float r,
1095 float c1,
1096 float c2,
1097
1098 stm_driver *driver,
1099 float tmax,
1100 dualparams *scmmodel,
1101
1102 char transtype
1103 )
1104 {
1105 stm_solver_maillon *stmp;
1106 stm_solver_maillon *stmn;
1107 mcc_trans_mcc *trsmccn;
1108 mcc_trans_spice *trsspicen;
1109 mcc_trans_mcc *trsmccp;
1110 mcc_trans_spice *trsspicep;
1111 long w, l;
1112 FILE *file;
1113 double dt;
1114 double ve, vs, lve, lvs, v2, lv2 ;
1115 double t;
1116 int rn, rp;
1117 float in, ip, lin, lip ;
1118 double qp, qn;
1119 double te, ts ;
1120 float vbp, vbn ;
1121 double qsatn ,qsatp, qsat, qsatx ;
1122 double qovrn ,qovrp, qovr ;
1123 double qconfn ,qconfp, qconf ;
1124 float isatn, isatp, lisatn, lisatp ;
1125 double seuil1, seuil2, ts1, ts2, fth ;
1126 double seuil ;
1127 chain_list *trslist;
1128 char trtype ;
1129 int reverse ;
1130 double t0 ;
1131 double dt0 ;
1132 ptype_list *ptl ;
1133 chain_list *chain ;
1134 lotrs_list *lotrs ;
1135 int encore ;
1136 int k ;
1137 stm_dual_param_timing paramtiming ;
1138 double vt, vdd, ci, capaie[4], vcap[3], vt0, vt0c, dtpwl, load ;
1139
1140 vt = scmmodel->DP[STM_VT];
1141 vt0 = scmmodel->DP[STM_VT0];
1142 vt0c = scmmodel->DP[STM_VT0C];
1143 vdd = scmmodel->DP[STM_VDDMAX];
1144 ci = scmmodel->DP[STM_CAPAI];
1145 capaie[0] = scmmodel->DP[STM_CAPAI0] ;
1146 capaie[1] = scmmodel->DP[STM_CAPAI1] ;
1147 capaie[2] = scmmodel->DP[STM_CAPAI2] ;
1148 capaie[3] = scmmodel->DP[STM_CAPAI3] ;
1149 vcap[0] = vt0 ;
1150 vcap[1] = vdd/2.0 ;
1151 vcap[2] = vt0c ;
1152
1153 if( r>0 && c2>0.0 )
1154 load = stm_modscm_dual_capaeq (scmmodel, NULL, f, r, c1, c2, scmmodel->DP[STM_THRESHOLD], NULL );
1155 else
1156 load = c1 ;
1157 stm_modscm_dual_fill_param( scmmodel, f, NULL, driver, load, &paramtiming ) ;
1158
1159 reverse=tpiv_inverter_config_reverse;
1160 if (sens=='U') t0=tpiv_inverter_config_t0r; else t0=tpiv_inverter_config_t0f;
1161
1162 if( sens=='U' )
1163 printf( "ud" );
1164 else
1165 printf( "du" );
1166 printf( " f=%.1f r=%.3g c1=%.3gfF c2=%.3gfF ci=%.3gfF\n", f, r, c1, c2, ci );
1167
1168 file = fopen( fname, "w" );
1169 if( !file ) {
1170 perror( "can't open file " );
1171 return;
1172 }
1173
1174 vbn = 0.0 ;
1175 vbp = 0.0 ;
1176
1177 switch( transtype ) {
1178 case 'S' :
1179 if( tn->BULK && tn->BULK->SIG ) {
1180 if( ! getlosigalim( tn->BULK->SIG, &vbn ) )
1181 vbn = 0.0 ;
1182 }
1183 if( tp->BULK && tp->BULK->SIG ) {
1184 if( ! getlosigalim( tp->BULK->SIG, &vbp ) )
1185 vbp = 0.0 ;
1186 else
1187 vbp = vbp-vdd;
1188 }
1189 break ;
1190 }
1191
1192 if( sens=='U' ) {
1193 seuil1 = vdd * SIM_VTH_HIGH ;
1194 seuil2 = vdd * SIM_VTH_LOW ;
1195 }
1196 else {
1197 seuil1 = vdd * SIM_VTH_LOW ;
1198 seuil2 = vdd * SIM_VTH_HIGH ;
1199 }
1200
1201 ci = ci / 1000.0 ;
1202 c1 = c1 / 1000.0 ;
1203 if( c2>0.0 ) c2 = c2 / 1000.0 ;
1204
1205 stmp = stm_solver_new_maillon();
1206 stmn = stm_solver_new_maillon();
1207
1208 switch( transtype ) {
1209
1210 case 'T' :
1211 trtype = TAS_TRMODEL_MCCRSAT ;
1212 trsmccn = mcc_create_trans_mcc( tn, vdd, TAS_CASE, NULL, 0.0, 0.0 );
1213 elpLotrsGetShrinkDim( tn, &l, &w, NULL, NULL, NULL, NULL, NULL, NULL, TAS_CASE );
1214 trsmccn->TRWIDTH = w;
1215 trsmccn->TRLENGTH = l;
1216 trslist = addchain( NULL,trsmccn );
1217 ptl = getptype( tn->USER, MBK_TRANS_PARALLEL );
1218 if( ptl ) {
1219 for( chain = (chain_list*)ptl->DATA ; chain ; chain = chain->NEXT ) {
1220 lotrs = (lotrs_list*)chain->DATA ;
1221 if( lotrs==tn ) continue ;
1222 trsmccn = mcc_create_trans_mcc( lotrs, vdd, TAS_CASE, NULL, 0.0, 0.0 );
1223 elpLotrsGetShrinkDim( lotrs, &l, &w, NULL, NULL, NULL, NULL, NULL, NULL, TAS_CASE );
1224 trsmccn->TRWIDTH = w;
1225 trsmccn->TRLENGTH = l;
1226 trslist = addchain( trslist,trsmccn );
1227 }
1228 }
1229 stm_solver_add_model( stmn,
1230 (char(*)(void*,float,float,float*))mcc_mcc_ids_list,
1231 (char(*)(void*,float,float,float*))mcc_mcc_vds_list,
1232 trslist,
1233 trslist
1234 );
1235 freechain( trslist );
1236
1237 trsmccp = mcc_create_trans_mcc( tp, vdd, TAS_CASE, NULL, 0.0, 0.0 );
1238 elpLotrsGetShrinkDim( tp, &l, &w, NULL, NULL, NULL, NULL, NULL, NULL, TAS_CASE );
1239 trsmccp->TRWIDTH = w;
1240 trsmccp->TRLENGTH = l;
1241 trslist = addchain( NULL, trsmccp );
1242 ptl = getptype( tp->USER, MBK_TRANS_PARALLEL );
1243 if( ptl ) {
1244 for( chain = (chain_list*)ptl->DATA ; chain ; chain = chain->NEXT ) {
1245 lotrs = (lotrs_list*)chain->DATA ;
1246 if( lotrs==tp ) continue ;
1247 trsmccp = mcc_create_trans_mcc( lotrs, vdd, TAS_CASE, NULL, 0.0, 0.0 );
1248 elpLotrsGetShrinkDim( lotrs, &l, &w, NULL, NULL, NULL, NULL, NULL, NULL, TAS_CASE );
1249 trsmccp->TRWIDTH = w;
1250 trsmccp->TRLENGTH = l;
1251 trslist = addchain( trslist,trsmccp );
1252 }
1253 }
1254 stm_solver_add_model( stmp,
1255 (char(*)(void*,float,float,float*))mcc_mcc_ids_list,
1256 (char(*)(void*,float,float,float*))mcc_mcc_vds_list,
1257 trslist,
1258 trslist
1259 );
1260 freechain( trslist );
1261 break;
1262
1263 case 'S' :
1264 trtype = TAS_TRMODEL_SPICE;
1265 trsspicen = mcc_create_trans_spice( tn, vdd, NULL, 0.0, 0.0 );
1266 trslist = addchain( NULL, trsspicen );
1267 ptl = getptype( tn->USER, MBK_TRANS_PARALLEL );
1268 if( ptl ) {
1269 for( chain = (chain_list*)ptl->DATA ; chain ; chain = chain->NEXT ) {
1270 lotrs = (lotrs_list*)chain->DATA ;
1271 if( lotrs==tn ) continue ;
1272 trsspicen = mcc_create_trans_spice( lotrs, vdd, NULL, 0.0, 0.0 );
1273 trslist = addchain( trslist, trsspicen );
1274 }
1275 }
1276 stm_solver_add_model( stmn,
1277 (char(*)(void*,float,float,float*))mcc_spice_ids_list,
1278 (char(*)(void*,float,float,float*))mcc_spice_vds,
1279 trslist,
1280 trslist
1281 );
1282 freechain( trslist );
1283
1284 trsspicep = mcc_create_trans_spice( tp, vdd, NULL, 0.0, 0.0 );
1285 trslist = addchain( NULL, trsspicep );
1286 ptl = getptype( tp->USER, MBK_TRANS_PARALLEL );
1287 if( ptl ) {
1288 for( chain = (chain_list*)ptl->DATA ; chain ; chain = chain->NEXT ) {
1289 lotrs = (lotrs_list*)chain->DATA ;
1290 if( lotrs==tp ) continue ;
1291 trsspicep = mcc_create_trans_spice( lotrs, vdd, NULL, 0.0, 0.0 );
1292 trslist = addchain( trslist, trsspicep );
1293 }
1294 }
1295 stm_solver_add_model( stmp,
1296 (char(*)(void*,float,float,float*))mcc_spice_ids_list,
1297 (char(*)(void*,float,float,float*))mcc_spice_vds_list,
1298 trslist,
1299 trslist
1300 );
1301 freechain( trslist );
1302 break;
1303
1304 default :
1305 fprintf( stderr, "Bad transistor model.\n" );
1306 EXIT(1);
1307 }
1308
1309 dt = 0.05 ;
1310 if( sens == 'U' ) {
1311 vs = vdd ;
1312 ve = 0.0 ;
1313 }
1314 else {
1315 vs = 0.0 ;
1316 ve = vdd ;
1317 }
1318 v2 = vs ;
1319
1320 te = 1e-12 * ( stm_modscm_dual_calte (vdd-vt, vt, vdd/2.0, f ) - stm_modscm_dual_calte (vdd-vt, vt, 0, f ) );
1321 dt0 = t0-te ;
1322
1323 lin = 0.0 ;
1324 lip = 0.0 ;
1325 lisatn = 0.0 ;
1326 lisatp = 0.0 ;
1327 qn = 0.0 ;
1328 qp = 0.0 ;
1329 qsatn = 0.0 ;
1330 qsatp = 0.0 ;
1331 qovrn = 0.0 ;
1332 qovrp = 0.0 ;
1333 qconfn = 0.0 ;
1334 qconfp = 0.0 ;
1335 qovr = -1.0 ;
1336 ts1 = -1.0 ;
1337 ts2 = -1.0 ;
1338 te = -1.0 ;
1339 ts = -1.0 ;
1340
1341 fprintf( file, "# tas time origin : vt=%g, tsim=%g\n\n", vt, dt0 + 1e-12 * ( stm_modscm_dual_calte (vdd-vt, vt, vt, f ) - stm_modscm_dual_calte (vdd-vt, vt, 0, f ) ) );
1342 fprintf( file, "# %12s %12s %12s %12s %12s %12s %12s %12s\n\n",
1343 "T", "ve", "vs", "in", "ip", "qn", "qp", "qsat"
1344 );
1345
1346 t=0.0;
1347 encore = 0 ;
1348 k = 0 ;
1349
1350 if( paramtiming.NTHSHRK ) {
1351 dtpwl = stm_get_t_pwth( paramtiming.VDDIN, vt, 0.0, paramtiming.PWTHSHRK );
1352 }
1353
1354 while( ts < 0.0 || te < 0.0 || ts1 < 0.0 || ts2 < 0.0 || encore ) {
1355
1356 lvs = vs ;
1357 lv2 = v2 ;
1358 lve = ve ;
1359
1360 if( sens == 'U' ) {
1361
1362 if( paramtiming.NTHSHRK )
1363 ve = stm_get_v_pwth( t+dtpwl, vt, vdd, STM_UP, paramtiming.PWTHSHRK );
1364 else
1365 ve = stm_get_v (t, vt, 0.0, vdd, f);
1366
1367 if( ve > vdd/2.0 ) {
1368 if( te < 0.0 )
1369 te=t ;
1370 }
1371 while( k <3 && ve >= vcap[k] )
1372 k++ ;
1373 }
1374 else {
1375
1376 if( paramtiming.NTHSHRK )
1377 ve = stm_get_v_pwth( t+dtpwl, vt, vdd, STM_DN, paramtiming.PWTHSHRK );
1378 else
1379 ve = stm_get_v (t, vdd-vt, vdd, 0.0, f);
1380
1381 if( ve < vdd/2.0 ) {
1382 if( te < 0.0 )
1383 te=t ;
1384 }
1385 while( k <3 && ve < vcap[2-k] )
1386 k++ ;
1387 }
1388
1389 //ci = capaie[k]/1000.0;
1390
1391 tas_tpiv_solver_calc_ids( stmn, ve, vbn, vdd, &isatn, trtype );
1392 tas_tpiv_solver_calc_ids( stmp, (ve-vdd), vbp, -vdd, &isatp, trtype );
1393
1394 rn = tas_tpiv_solver_calc_ids( stmn, ve, vbn, vs, &in, trtype );
1395 rp = tas_tpiv_solver_calc_ids( stmp, (ve-vdd), vbp, (vs-vdd), &ip, trtype );
1396
1397 if( !reverse ) {
1398 if( in < 0.0 )
1399 in = 0.0 ;
1400 if( ip > 0.0 )
1401 ip = 0.0 ;
1402 }
1403
1404 if( rn && rp ) {
1405 if( r >=0.0 && c2 >= 0.0 ) {
1406 vs = ( (-ip)-in + ci*(ve-lve)/dt + c1*lvs/dt - r*c2*c2*lv2/(dt+r*c2)/dt + c2*lv2/dt ) / ( c1/dt + c2/(dt+r*c2));
1407 v2 = dt/(dt+r*c2)*(vs+r*c2*lv2/dt);
1408 }
1409 else
1410 vs = ( dt * ( (-in) - ip ) + c1 * lvs + ci * ( ve - lve ) ) / c1 ;
1411 }
1412 else {
1413 printf( "error : ve=%g vs=%g vbn=%g vbp=%g rn=%d rp=%d\n",
1414 ve, vs, vbn, vbp, rn, rp
1415 );
1416 break ;
1417 }
1418
1419
1420 qsatx = 0.0 ;
1421 if( in > 0.0 ) {
1422 qn = qn + ( in + lin ) * (dt*1.0e-12) / 2.0 ;
1423 qsatn = qsatn + ( (isatn-in) + (lisatn-lin) ) * (dt*1.0e-12) / 2.0 ;
1424 }
1425 else {
1426 qovrn = qovrn + ( in + lin ) * (dt*1.0e-12) / 2.0 ;
1427 }
1428
1429 if( ip < 0.0 ) {
1430 qp = qp + ( ip + lip ) * (dt*1.0e-12) / 2.0 ;
1431 qsatp = qsatp + ( (isatp-ip) + (lisatp-lip) ) * (dt*1.0e-12) / 2.0 ;
1432 }
1433 else {
1434 qovrp = qovrp + ( ip + lip ) * (dt*1.0e-12) / 2.0 ;
1435 }
1436
1437 lin = in ;
1438 lip = ip ;
1439 lisatn = isatn ;
1440 lisatp = isatp ;
1441
1442 if( sens == 'U' )
1443 qsatx = qsatn ;
1444 else
1445 qsatx = -qsatp ;
1446
1447 fprintf( file, "%12g %12g %12g %12g %12g %12g %12g %12g\n",
1448 t*1e-12+dt0, ve, vs, in, ip, qn, qp, qsatx
1449 );
1450
1451 if( sens == 'U' ) {
1452 if ( vs < vdd/2.0 ) {
1453 if( ts < 0.0 ) {
1454 ts = t ;
1455 qsat = qsatn ;
1456 qconf = -qp ;
1457 }
1458 }
1459 if( vs < seuil1 ) {
1460 if( ts1 < 0.0 )
1461 ts1 = t ;
1462 }
1463 if( vs < seuil2 ) {
1464 if( ts2 < 0.0 )
1465 ts2 = t ;
1466 }
1467 if( ve > vt ) {
1468 if( qovr < 0.0 )
1469 qovr = fabs(qovrp) ;
1470 }
1471 }
1472 else {
1473 if ( vs > vdd/2.0 ) {
1474 if( ts < 0.0 ) {
1475 ts = t ;
1476 qsat = -qsatp ;
1477 qconf = qn;
1478 }
1479 }
1480 if( vs > seuil1 ) {
1481 if( ts1 < 0.0 )
1482 ts1 = t;
1483 }
1484 if( vs > seuil2 ) {
1485 if( ts2 < 0.0 )
1486 ts2 = t;
1487 }
1488 if( ve < vdd-vt ) {
1489 if( qovr < 0.0 )
1490 qovr = fabs(qovrn) ;
1491 }
1492 }
1493
1494 t = t + dt ;
1495
1496 encore = 1 ;
1497 if( tmax > 0.0 ) {
1498 if( t >= tmax )
1499 encore = 0 ;
1500 }
1501 else {
1502 if( sens=='U' ) { /* ud */
1503 if( vs < 0.01*vdd )
1504 encore = 0 ;
1505 }
1506 else {
1507 if( vs > 0.99*vdd )
1508 encore = 0 ;
1509 }
1510 }
1511 }
1512
1513 if( sens=='U' )
1514 fth = stm_thr2scm( ts2-ts1, seuil2/vdd, seuil1/vdd, vt, 0.0, vdd, STM_DN );
1515 else
1516 fth = stm_thr2scm( ts2-ts1, seuil1/vdd, seuil2/vdd, vt, vdd, vdd, STM_UP );
1517
1518 printf( " -> te=%g ts=%g tp=%g\n", te, ts, ts-te );
1519 printf( " t1=%g t2=%g f=%g (fshrk=%.2f)\n", ts1, ts2, ts2-ts1, fth );
1520 printf( " qsat = %.3gfC (%.3gfF)\n",
1521 qsat*1.0e15, qsat/(vdd/2.0)*1.0e15 );
1522 printf( " qconf = %.3gfC (%.3gfF)\n",
1523 qconf*1.0e15, qconf/(vdd/2.0)*1.0e15 );
1524 printf( " qovr(vt) = %.3gfC (%.3gfF)\n",
1525 qovr*1.0e15, qovr/(vdd/2.0)*1.0e15
1526 );
1527
1528 fclose( file );
1529
1530 return ;
1531 /************** Calcul du conflit en statique ***********/
1532
1533 /* seuil statique */
1534
1535 seuil = tpiv_getseuil( stmn, stmp, vdd, vbn, vbp, 1, trtype );
1536 printf( " Static threshold (vin where vout=vdd/2.0) (satured) : %.3gV\n", seuil );
1537 qn = tpiv_getconflict( stmn, stmp, vdd, vbn, vbp, vt, f, seuil, sens, dt, 1, trtype );
1538 printf( " -> Satured Qconf=%.3gfF (Cconf=%.3gfF)\n", qn*1e15, qn*1e15/(vdd/2.0) );
1539 qn = tpiv_getconflict( stmn, stmp, vdd, vbn, vbp, vt, f, seuil, sens, dt, 0, trtype );
1540 printf( " -> Real Qconf=%.3gfF (Cconf=%.3gfF)\n", qn*1e15, qn*1e15/(vdd/2.0) );
1541
1542 seuil = tpiv_getseuil( stmn, stmp, vdd, vbn, vbp, 0, trtype );
1543 printf( " Static threshold (vin where vout=vdd/2.0) (real) : %.3gV\n", seuil );
1544 qn = tpiv_getconflict( stmn, stmp, vdd, vbn, vbp, vt, f, seuil, sens, dt, 1, trtype );
1545 printf( " -> Satured Qconf=%.3gfF (Cconf=%.3gfF)\n", qn*1e15, qn*1e15/(vdd/2.0) );
1546 qn = tpiv_getconflict( stmn, stmp, vdd, vbn, vbp, vt, f, seuil, sens, dt, 0, trtype );
1547 printf( " -> Real Qconf=%.3gfF (Cconf=%.3gfF)\n", qn*1e15, qn*1e15/(vdd/2.0) );
1548
1549 }
1550
1551 double tpiv_getconflict( stm_solver_maillon *stmn, stm_solver_maillon *stmp, double vdd, double vbn, double vbp, double vt, double f, double seuil, char sens, double dt, char satured, char brtype )
1552 {
1553 float i, li ;
1554 double q ;
1555 double ve ;
1556 double vs ;
1557 int r ;
1558 double t ;
1559
1560 li = 0.0 ;
1561 q = 0.0 ;
1562
1563 if( sens=='U' )
1564 ve = 0.0 ;
1565 else
1566 ve = vdd ;
1567
1568 for( t = 0.0 ; ( sens == 'U' && ve < seuil ) || ( sens == 'D' && ve > seuil ) ; t = t + dt ) {
1569
1570 if( sens == 'U' )
1571 ve = stm_get_v( t, vt, 0.0, vdd, f);
1572 else
1573 ve = stm_get_v (t, vt, vdd, 0.0, f);
1574
1575 if( satured ) {
1576 if( sens=='U' )
1577 vs = vdd ;
1578 else
1579 vs = 0.0 ;
1580 }
1581 else {
1582 vs = tpiv_getvs( stmn, stmp, ve, vbn, vbp, vdd, brtype );
1583 }
1584
1585 if( sens=='U' )
1586 r = tas_tpiv_solver_calc_ids( stmn, ve, vbn, vs, &i, brtype );
1587 else {
1588 r = tas_tpiv_solver_calc_ids( stmp, (ve-vdd), vbp, vs-vdd, &i, brtype );
1589 i=-i;
1590 }
1591
1592 if( !r )
1593 break ;
1594 q = q + ( i + li ) * (dt*1.0e-12) / 2.0 ;
1595 li = i ;
1596 }
1597
1598 return q ;
1599 }
1600
1601 double tpiv_getvs( stm_solver_maillon *stmn, stm_solver_maillon *stmp, double ve, double vbn, double vbp, double vdd, char brtype )
1602 {
1603 double vmin ;
1604 double vmax ;
1605 int iter ;
1606 double vs ;
1607 int rn ;
1608 int rp ;
1609 float in ;
1610 float ip ;
1611 char stop ;
1612
1613 iter = 100 ;
1614 vmin = 0.0 ;
1615 vmax = vdd ;
1616
1617 do {
1618 vs = (vmax+vmin)/2.0;
1619
1620 rn = tas_tpiv_solver_calc_ids( stmn, ve, vbn, vs, &in, brtype );
1621 rp = tas_tpiv_solver_calc_ids( stmp, (ve-vdd), vbp, vs-vdd, &ip, brtype );
1622
1623 if( !rn || !rp )
1624 break ;
1625
1626 ip=-ip;
1627
1628 if( in > ip )
1629 vmax = vs ;
1630 else
1631 vmin = vs ;
1632 iter-- ;
1633
1634 stop=0;
1635 if( fabs(ip-in)/ip < 1e-8 )
1636 stop = 1 ;
1637 }
1638 while( !stop && iter );
1639
1640 if( !rn || !rp )
1641 return vdd/2.0 ;
1642
1643 return (vmax+vmin)/2.0 ;
1644 }
1645
1646 double tpiv_getseuil( stm_solver_maillon *stmn, stm_solver_maillon *stmp, double vdd, double vbn, double vbp, char satured, char brtype )
1647 {
1648 double vmin ;
1649 double vmax ;
1650 int iter ;
1651 double ve ;
1652 double vs ;
1653 int rn ;
1654 int rp ;
1655 float in ;
1656 float ip ;
1657 char stop ;
1658
1659 iter = 100 ;
1660 vmin = 0.0 ;
1661 vmax = vdd ;
1662 vs = vdd/2.0 ;
1663
1664 do {
1665 ve = (vmax+vmin)/2.0;
1666
1667 if( satured ) {
1668 rn = tas_tpiv_solver_calc_ids( stmn, ve, vbn, vdd, &in, brtype );
1669 rp = tas_tpiv_solver_calc_ids( stmp, (ve-vdd), vbp, -vdd, &ip, brtype );
1670 }
1671 else {
1672 rn = tas_tpiv_solver_calc_ids( stmn, ve, vbn, vs, &in, brtype );
1673 rp = tas_tpiv_solver_calc_ids( stmp, (ve-vdd), vbp, vs-vdd, &ip, brtype );
1674 }
1675
1676 if( !rn || !rp )
1677 break ;
1678
1679 ip=-ip;
1680
1681 if( in > ip )
1682 vmax = ve ;
1683 else
1684 vmin = ve ;
1685 iter-- ;
1686
1687 stop=0;
1688 if( fabs(ip-in)/ip < 1e-8 )
1689 stop = 1 ;
1690 }
1691 while( !stop && iter );
1692
1693 if( !rn || !rp )
1694 return vdd/2.0 ;
1695
1696 return (vmax+vmin)/2.0 ;
1697 }
1698
1699 void tpiv_carac_static( lotrs_list *lotrs,
1700 float vdd,
1701 float vdsmax,
1702 float vgsmax,
1703 float vb, /* uniquement pris en compte pour modèle spice */
1704 float vs
1705 )
1706 {
1707 FILE *ptf ;
1708 mcc_trans_mcc *trsmcc ;
1709 mcc_trans_spice *trsspi ;
1710 char fname[1024] ;
1711 char bname[1024] ;
1712 int i, j ;
1713 int ni, nj ;
1714 long w, l ;
1715 float vi, vj ;
1716 float imcc ;
1717 float ispi ;
1718 float vt ;
1719 float vbs = vb-vs ;
1720 float vbulk ;
1721
1722 if( MLO_IS_TRANSP(lotrs->TYPE) )
1723 vbulk = tas_getparam( lotrs, TAS_CASE, TP_VDDmax );
1724 else
1725 vbulk = 0.0 ;
1726
1727 trsmcc = mcc_create_trans_mcc( lotrs, vdd, TAS_CASE, NULL, 0.0, vbulk );
1728 elpLotrsGetShrinkDim( lotrs, &l, &w, NULL, NULL, NULL, NULL, NULL, NULL, TAS_CASE );
1729 trsmcc->TRWIDTH = w;
1730 trsmcc->TRLENGTH = l;
1731
1732 trsspi = mcc_create_trans_spice( lotrs, vdd, NULL, 0.0, 0.0 );
1733
1734 if (SIMUINV_PREFIX==NULL)
1735 sprintf( bname, "static_%c_w=%ld_l=%ld",
1736 MLO_IS_TRANSN(lotrs->TYPE) ? 'n' : 'p',
1737 lotrs->WIDTH,
1738 lotrs->LENGTH
1739 );
1740 else
1741 sprintf( bname, "%s.%s.static_%c_w=%ld_l=%ld", SIMUINV_PREFIX,env_SIMUINV=='T'?"tas":"mcc",
1742 MLO_IS_TRANSN(lotrs->TYPE) ? 'n' : 'p',
1743 lotrs->WIDTH,
1744 lotrs->LENGTH
1745 );
1746
1747 sprintf( fname, "%s_ids=f(vds)", bname );
1748
1749 ptf = mbkfopen( fname, "dat", WRITE_TEXT );
1750 if( !ptf )
1751 EXIT(1);
1752
1753 ni = 1000;
1754 nj = 4;
1755 vt = trsmcc->VT ;
1756
1757 for( j=1 ; j<=nj ; j++ ) {
1758
1759 vj = ((float)j)/((float)nj) * (vgsmax-vt)+vt ;
1760 fprintf( ptf, "# vgs = %g\n\n", vj );
1761
1762 fprintf( ptf, "# vds imcc ispi\n\n" );
1763
1764 for( i=0 ; i<=ni ; i++ ) {
1765
1766 vi = ((float)i)/((float)ni) * vdsmax ;
1767
1768 if( MLO_IS_TRANSN(lotrs->TYPE) ) {
1769 trsmcc->VG = vs+vj ;
1770 //trsmcc->VB = 0.0 ;
1771 mcc_mcc_ids( trsmcc, vs, vs+vi, &imcc );
1772 mcc_spice_ids( trsspi, vj, vbs, vi, &ispi );
1773 }
1774 else {
1775 trsmcc->VG = vs-vj ;
1776 //trsmcc->VB = vdd ;
1777 mcc_mcc_ids( trsmcc, vs, vs-vi, &imcc );
1778 mcc_spice_ids( trsspi, -vj, vbs, -vi, &ispi );
1779 }
1780
1781 fprintf( ptf, "%g %g %g\n", vi, imcc, ispi );
1782 }
1783 fprintf( ptf, "\n" );
1784 }
1785
1786 fclose( ptf );
1787
1788 sprintf( fname, "%s_ids=f(vgs)", bname );
1789
1790 ptf = mbkfopen( fname, "dat", WRITE_TEXT );
1791 if( !ptf )
1792 EXIT(1);
1793
1794 ni = 1000;
1795 nj = 4;
1796
1797 for( j=1 ; j<=nj ; j++ ) {
1798
1799 vj = ((float)j)/((float)nj) * vdsmax ;
1800 fprintf( ptf, "# vds = %g\n\n", vj );
1801
1802 fprintf( ptf, "# vgs imcc ispi\n\n" );
1803
1804 for( i=0 ; i<=ni ; i++ ) {
1805
1806 vi = ((float)i)/((float)ni)*vgsmax ;
1807
1808 if( MLO_IS_TRANSN(lotrs->TYPE) ) {
1809 trsmcc->VG = vs+vi ;
1810 mcc_mcc_ids( trsmcc, vs, vs+vj, &imcc );
1811 mcc_spice_ids( trsspi, vi, vbs, vj, &ispi );
1812 }
1813 else {
1814 trsmcc->VG = vs-vi ;
1815 mcc_mcc_ids( trsmcc, vs, vs-vj, &imcc );
1816 mcc_spice_ids( trsspi, -vi, vbs, -vj, &ispi );
1817 }
1818
1819 fprintf( ptf, "%g %g %g\n", vi, imcc, ispi );
1820 }
1821 fprintf( ptf, "\n" );
1822 }
1823
1824 fclose( ptf );
1825
1826 ptf = mbkfopen( bname, "plt", WRITE_TEXT );
1827
1828 fprintf( ptf, "set grid\n");
1829 fprintf( ptf, "set title \"%s\"\n",MLO_IS_TRANSN(lotrs->TYPE)?"NMOS":"PMOS");
1830 fprintf( ptf, "plot '%s_ids=f(vds).dat' using 1:2 title \"TAS\" with lines, '%s_ids=f(vds).dat' using 1:3 title \"MCC\" with lines\n", bname, bname );
1831 fprintf( ptf, "pause -1\n" );
1832 fprintf( ptf, "plot '%s_ids=f(vgs).dat' using 1:2 title \"TAS\" with lines, '%s_ids=f(vgs).dat' using 1:3 title \"MCC\" with lines\n", bname, bname );
1833 fprintf( ptf, "pause -1\n" );
1834
1835 fclose( ptf );
1836
1837 }
1838
1839 void tas_tpiv_set_vg_for_switch( stm_solver_maillon *maillon, char brtype, char typeactive, float vgactive, float vgswitch )
1840 {
1841 chain_list *chtrs ;
1842 mcc_trans_mcc *trsmcc ;
1843 mcc_trans_spice *trsspi ;
1844
1845 for( chtrs = (chain_list*)maillon->MODEL_VDS ; chtrs ; chtrs = chtrs->NEXT ) {
1846 if( brtype == TAS_TRMODEL_MCCRSAT ) {
1847 trsmcc = (mcc_trans_mcc*)chtrs->DATA ;
1848 if( ( typeactive == 'N' && MLO_IS_TRANSN(trsmcc->TYPE) ) || ( typeactive == 'P' && MLO_IS_TRANSP(trsmcc->TYPE) ) )
1849 trsmcc->VG = vgactive ;
1850 else
1851 trsmcc->VG = vgswitch ;
1852 }
1853 else {
1854 trsspi = (mcc_trans_spice*)chtrs->DATA ;
1855 if( ( typeactive == 'N' && trsspi->TRANSTYPE == MCC_NMOS ) || ( typeactive == 'P' && trsspi->TRANSTYPE == MCC_PMOS ) )
1856 trsspi->VG = vgactive ;
1857 else
1858 trsspi->VG = vgswitch ;
1859 }
1860 }
1861
1862 }
1863
1864 void tas_tpiv_set_vg( stm_solver_maillon *maillon, char brtype, float vg )
1865 {
1866 chain_list *chtrs ;
1867 mcc_trans_mcc *trsmcc ;
1868 mcc_trans_spice *trsspi ;
1869
1870 for( chtrs = (chain_list*)maillon->MODEL_VDS ; chtrs ; chtrs = chtrs->NEXT ) {
1871 if( brtype == TAS_TRMODEL_MCCRSAT ) {
1872 trsmcc = (mcc_trans_mcc*)chtrs->DATA ;
1873 trsmcc->VG = vg ;
1874 }
1875 else {
1876 trsspi = (mcc_trans_spice*)chtrs->DATA ;
1877 trsspi->VG = vg ;
1878 }
1879 }
1880 }
1881
1882 void tas_tpiv_set_vb( stm_solver_maillon *maillon, char brtype, float vb )
1883 {
1884 chain_list *chtrs ;
1885 mcc_trans_mcc *trsmcc ;
1886 mcc_trans_spice *trsspi ;
1887
1888 for( chtrs = (chain_list*)maillon->MODEL_VDS ; chtrs ; chtrs = chtrs->NEXT ) {
1889 if( brtype == TAS_TRMODEL_MCCRSAT ) {
1890 trsmcc = (mcc_trans_mcc*)chtrs->DATA ;
1891 trsmcc->VB = vb ;
1892 }
1893 else {
1894 trsspi = (mcc_trans_spice*)chtrs->DATA ;
1895 trsspi->VB = vb ;
1896 }
1897 }
1898 }
1899
1900 char tas_tpiv_solver_calc_ids( stm_solver_maillon *maillon, float vgs, float vbs, float vds, float *ids, char brtype )
1901 {
1902 tas_tpiv_set_vg( maillon, brtype, vgs );
1903 tas_tpiv_set_vb( maillon, brtype, vbs );
1904 return stm_solver_calc_ids( maillon, 0.0, vds, ids );
1905 }