1 /*
2 * *********************************************************************
3 * * Copyright (C) 1988, 1990 Stanford University. *
4 * * Permission to use, copy, modify, and distribute this *
5 * * software and its documentation for any purpose and without *
6 * * fee is hereby granted, provided that the above copyright *
7 * * notice appear in all copies. Stanford University *
8 * * makes no representations about the suitability of this *
9 * * software for any purpose. It is provided "as is" without *
10 * * express or implied warranty. Export of this software outside *
11 * * of the United States of America may require an export license. *
12 * *********************************************************************
13 */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17
18 #include "defs.h"
19 #include "net.h"
20 #include "globals.h"
21
22 /* event driven mosfet simulator. Chris Terman (2/80) */
23
24 public iptr hinputs = NULL; /* list of nodes to be driven high */
25 public iptr linputs = NULL; /* list of nodes to be driven low */
26 public iptr uinputs = NULL; /* list of nodes to be driven X */
27 public iptr xinputs = NULL; /* list of nodes to be removed from input */
28
29 public iptr infree = NULL; /* unused input list cells */
30
31 public iptr *listTbl[8];
32
33 public
34 #define FreeInput( X ) (X)->next = infree, infree = (X)
35
36
init_listTbl()37 public void init_listTbl()
38 {
39 int i;
40
41 for( i = 0; i < 8; listTbl[ i++ ] = NULL );
42 listTbl[ INPUT_NUM( H_INPUT ) ] = &hinputs;
43 listTbl[ INPUT_NUM( L_INPUT ) ] = &linputs;
44 listTbl[ INPUT_NUM( U_INPUT ) ] = &uinputs;
45 listTbl[ INPUT_NUM( X_INPUT ) ] = &xinputs;
46 }
47
48
49 #define pvalue( node_name, node ) \
50 lprintf( stdout, "%s=%c ", (node_name), "0XX1"[(node)->npot] )
51
52
pgvalue(t)53 private void pgvalue( t )
54 register tptr t;
55 {
56 register nptr n;
57 static char *states[] = { "OFF", "ON", "UKNOWN", "WEAK" };
58
59 if( debug )
60 lprintf( stdout, "[%s] ", states[t->state] );
61
62 if( t->ttype & GATELIST )
63 {
64 lprintf( stdout, "( " );
65 for( t = (tptr) t->gate; t != NULL; t = t->scache.t )
66 {
67 n = t->gate;
68 pvalue( pnode( n ), n );
69 }
70
71 lprintf( stdout, ") " );
72 }
73 else
74 {
75 n = t->gate;
76 pvalue( pnode( n ), n );
77 }
78 }
79
80
pr_one_res(s,r)81 private void pr_one_res( s, r )
82 char *s;
83 double r;
84 {
85 if( r < 1e-9 or r > 100e9 )
86 (void) sprintf( s, "%2.1e", r );
87 else
88 {
89 int e = 3;
90
91 if( r >= 1000.0 )
92 do { e++; r *= 0.001; } while( r >= 1000.0 );
93 else if( r < 1 and r > 0 )
94 do { e--; r *= 1000; } while( r < 1.0 );
95 (void) sprintf( s, "%.1f%c", r, "num\0KMG"[ e ] );
96 }
97 }
98
99
pr_t_res(fp,r)100 private void pr_t_res( fp, r )
101 FILE *fp;
102 Resists *r;
103 {
104 char buf[3][15];
105
106 pr_one_res( buf[0], r->rstatic );
107 pr_one_res( buf[1], r->dynhigh );
108 pr_one_res( buf[2], r->dynlow );
109 lprintf( fp, "[%s, %s, %s]", buf[0], buf[1], buf[2] );
110 }
111
112
ptrans(t)113 private void ptrans( t )
114 register tptr t;
115 {
116 lprintf( stdout, "%s ", ttype[ BASETYPE( t->ttype ) ] );
117 if( BASETYPE( t->ttype ) != RESIST )
118 pgvalue( t );
119
120 pvalue( pnode( t->source ), t->source );
121 pvalue( pnode( t->drain ), t->drain );
122 pr_t_res( stdout, t->r );
123 if( t->tlink != t and (treport & REPORT_TCOORD) )
124 lprintf( stdout, " <%d,%d>\n", t->x.pos, t->y.pos );
125 else
126 lprintf( stdout, "\n" );
127 }
128
129
idelete(n,list)130 public void idelete( n, list )
131 register nptr n;
132 register iptr *list;
133 {
134 register iptr p = *list;
135 register iptr q;
136
137 if( p == NULL )
138 return;
139 else if( p->inode == n )
140 {
141 *list = p->next;
142 FreeInput( p );
143 }
144 else
145 {
146 for( q = p->next; q != NULL; p = q, q = p->next )
147 if( q->inode == n )
148 {
149 p->next = q->next;
150 FreeInput( q );
151 return;
152 }
153 }
154 }
155
156
iinsert(n,list)157 public void iinsert( n, list )
158 nptr n;
159 iptr *list;
160 {
161 register iptr p = infree;
162
163 if( p == NULL )
164 p = infree = (iptr) MallocList( sizeof( struct Input ), 1 );
165 infree = p->next;
166
167 p->next = *list;
168 *list = p;
169 p->inode = n;
170 }
171
172
iinsert_once(n,list)173 public void iinsert_once( n, list )
174 nptr n;
175 iptr *list;
176 {
177 register iptr p;
178
179 for( p = *list; p != NULL; p = p->next )
180 if( p->inode == n )
181 return;
182
183 iinsert( n, list );
184 }
185
186
clear_input(n)187 private int clear_input( n )
188 register nptr n;
189 {
190 if( not( n->nflags & POWER_RAIL ) )
191 n->nflags &= ~INPUT;
192 return( 0 );
193 }
194
195
ClearInputs()196 public void ClearInputs()
197 {
198 register int i;
199 register iptr p, next;
200 register nptr n;
201
202 for( i = 0; i < 5; i++ )
203 {
204 if( listTbl[ i ] == NULL )
205 continue;
206 for( p = *listTbl[ i ]; p != NULL; p = next )
207 {
208 next = p->next;
209 n = p->inode;
210 FreeInput( p );
211 if( not( n->nflags & POWER_RAIL ) )
212 n->nflags &= ~(INPUT_MASK | INPUT);
213 }
214 *(listTbl[ i ]) = NULL;
215 }
216 walk_net( clear_input, (char *) 0 );
217 }
218
219
220 /*
221 * set/clear input status of node and add/remove it to/from corresponding list.
222 */
setin(n,which)223 public int setin( n, which )
224 register nptr n;
225 char *which;
226 {
227 char locwhich = *which;
228
229 if (locwhich == '!') /* Toggle the bit value */
230 {
231 if (n->npot == HIGH)
232 locwhich = 'l';
233 else if (n->npot == LOW)
234 locwhich = 'h';
235 }
236
237 while( n->nflags & ALIAS )
238 n = n->nlink;
239
240 if( n->nflags & (POWER_RAIL | MERGED) ) /* Gnd, Vdd, or merged node */
241 {
242 if( (n->nflags & MERGED) or "lxuh"[ n->npot ] != locwhich )
243 lprintf( stdout, "Can't drive `%s' to `%c'\n",
244 pnode( n ), locwhich );
245 }
246 else
247 {
248 iptr *list = listTbl[ INPUT_NUM( n->nflags ) ];
249
250 # define WASINP( N, P ) ( ((N)->nflags & INPUT) && (N)->npot == (P) )
251
252 switch( locwhich )
253 {
254 case 'h' :
255 if( list != NULL and list != &hinputs )
256 {
257 n->nflags = n->nflags & ~INPUT_MASK;
258 idelete( n, list );
259 }
260 if( not (list == &hinputs or WASINP( n, HIGH )) )
261 {
262 n->nflags = (n->nflags & ~INPUT_MASK) | H_INPUT;
263 iinsert( n, &hinputs );
264 }
265 break;
266
267 case 'l' :
268 if( list != NULL and list != &linputs )
269 {
270 n->nflags = n->nflags & ~INPUT_MASK;
271 idelete( n, list );
272 }
273 if( not (list == &linputs or WASINP( n, LOW )) )
274 {
275 n->nflags = (n->nflags & ~INPUT_MASK) | L_INPUT;
276 iinsert( n, &linputs );
277 }
278 break;
279
280 case 'u' :
281 if( list != NULL and list != &uinputs )
282 {
283 n->nflags = n->nflags & ~INPUT_MASK;
284 idelete( n, list );
285 }
286 if( not (list == &uinputs or WASINP( n, X )) )
287 {
288 n->nflags = (n->nflags & ~INPUT_MASK) | U_INPUT;
289 iinsert( n, &uinputs );
290 }
291 break;
292
293 case 'x' :
294 if( list == &xinputs )
295 break;
296 if( list )
297 {
298 n->nflags = n->nflags & ~INPUT_MASK;
299 idelete( n, list );
300 }
301 if( n->nflags & INPUT )
302 {
303 n->nflags = (n->nflags & ~INPUT_MASK) | X_INPUT;
304 iinsert( n, &xinputs );
305 }
306 break;
307 default :
308 return( 0 );
309 }
310 }
311 return( 1 );
312 }
313
314
wr_value(n,fp)315 private int wr_value( n, fp )
316 register nptr n;
317 FILE *fp;
318 {
319 if( not (n->nflags & (ALIAS | POWER_RAIL)) )
320 {
321 int ch = ((n->nflags & INPUT) ? '4' : '0') + n->npot;
322 (void) putc( ch, fp );
323 }
324 return( 0 );
325 }
326
327
wr_state(fname)328 public int wr_state( fname )
329 char *fname;
330 {
331 FILE *fp;
332
333 if( (fp = fopen( fname, "w" )) == NULL )
334 return( 1 );
335
336 (void) fprintf( fp, "%d\n", nnodes );
337 walk_net( wr_value, (char *) fp );
338 (void) fclose( fp );
339 return( 0 );
340 }
341
342
343 typedef struct
344 {
345 FILE *file;
346 int errs;
347 int restore;
348 } StateFile;
349
350
rd_stvalue(n,st)351 private int rd_stvalue( n, st )
352 register nptr n;
353 StateFile *st;
354 {
355 int ch, inp;
356
357 if( n->nflags & (ALIAS | POWER_RAIL) )
358 return( 0 );
359
360 FreeHistList( n );
361 while( n->events != NULL ) /* remove any pending events */
362 free_event( n->events );
363
364 if( st->file == NULL )
365 {
366 ch = X;
367 st->errs ++;
368 }
369 else
370 {
371 ch = getc( st->file );
372 if( ch == EOF )
373 {
374 ch = X;
375 st->errs ++;
376 (void) fclose( st->file );
377 st->file = NULL;
378 }
379 else if( ch < '0' or ch > '7' or ch == '2' or ch == '6' )
380 {
381 st->errs ++;
382 ch = X;
383 }
384 else if( st->restore and ch >= '4' )
385 {
386 ch = ch - '4';
387 inp = 1;
388 }
389 else
390 {
391 ch = (ch - '0') & (LOW | X | HIGH);
392 inp = 0;
393 }
394 }
395
396 if( n->nflags & MERGED )
397 return( 0 );
398
399 if( inp )
400 n->nflags |= INPUT;
401
402 n->head.val = ch;
403 n->head.inp = inp;
404
405 if( ch != n->npot )
406 {
407 register lptr l;
408 register tptr t;
409
410 n->npot = ch;
411 for( l = n->ngate; l != NULL; l = l->next )
412 {
413 t = l->xtor;
414 t->state = compute_trans_state( t );
415 }
416 }
417 return( 0 );
418 }
419
420
rd_state(fname,restore)421 public char *rd_state( fname, restore )
422 char *fname;
423 int restore;
424 {
425 char rline[25];
426 StateFile st;
427
428 if( (st.file = fopen( fname, "r" )) == NULL )
429 return( "can not read state file\n" );
430
431 (void) fgetline( rline, 25, st.file );
432 if( atoi( rline ) != nnodes )
433 {
434 (void) fclose( st.file );
435 return( "bad node count in state file\n" );
436 }
437
438 ClearInputs();
439
440 if( analyzerON )
441 StopAnalyzer();
442
443 sim_time0 = cur_delta = 0;
444
445 st.errs = 0;
446 st.restore = restore;
447 walk_net( rd_stvalue, (char *) &st );
448
449 NoInit();
450
451 if( analyzerON )
452 RestartAnalyzer( sim_time0, cur_delta, FALSE );
453
454 if( st.file == NULL )
455 {
456 (void) sprintf( fname, "premature EOF in state file (%d errors)\n",
457 st.errs );
458 return( fname );
459 }
460
461 (void) fclose( st.file );
462
463 if( st.errs != 0 )
464 {
465 (void) sprintf( fname, "%d errors found in state file\n", st.errs );
466 return( fname );
467 }
468 return( NULL );
469 }
470
471
info(n,which)472 public int info( n, which )
473 register nptr n;
474 char *which;
475 {
476 register tptr t;
477 register lptr l;
478 char *name;
479
480 if( n == NULL )
481 return( 0 );
482
483 if( int_received )
484 return( 1 );
485
486 name = pnode( n );
487 while( n->nflags & ALIAS )
488 n = n->nlink;
489
490 if( n->nflags & MERGED )
491 {
492 lprintf( stdout, "%s => node is inside a transistor stack\n", name );
493 return( 1 );
494 }
495
496 pvalue( name, n );
497 if( n->nflags & INPUT )
498 lprintf( stdout, "[NOTE: node is an input] " );
499 lprintf( stdout, "(vl=%.2f vh=%.2f) ", n->vlow, n->vhigh );
500 if( n->nflags & USERDELAY )
501 lprintf( stdout, "(tplh=%d, tphl=%d) ", n->tplh, n->tphl );
502 lprintf( stdout, "(%5.4f pf) ", n->ncap );
503
504 if ((*which == '?') || !strcmp(which, "querysource"))
505 {
506 lprintf( stdout, "is computed from:\n" );
507 for( l = n->nterm; l != NULL and int_received == 0; l = l->next )
508 {
509 t = l->xtor;
510 lprintf( stdout, " " );
511 if( debug == 0 )
512 {
513 char *drive = NULL;
514 nptr rail;
515
516 rail = (t->drain->nflags & POWER_RAIL) ? t->drain : t->source;
517 if( BASETYPE( t->ttype ) == NCHAN and rail == GND_node )
518 drive = "pulled down by ";
519 else if( BASETYPE( t->ttype ) == PCHAN and rail == VDD_node )
520 drive = "pulled up by ";
521 else if( BASETYPE( t->ttype ) == DEP and rail == VDD_node and
522 other_node( t, rail ) == t->gate )
523 drive = "pullup ";
524 else
525 ptrans( t );
526
527 if( drive != NULL )
528 {
529 lprintf( stdout, drive );
530 pgvalue( t );
531 pr_t_res( stdout, t->r );
532 if( t->tlink != t and (treport & REPORT_TCOORD) )
533 lprintf( stdout, " <%d,%d>\n", t->x.pos, t->y.pos );
534 else
535 lprintf( stdout, "\n" );
536 }
537 }
538 else
539 ptrans( t );
540 }
541 }
542 else
543 {
544 lprintf( stdout, "affects:\n" );
545 for( l = n->ngate; l != NULL and int_received == 0; l = l->next )
546 ptrans( l->xtor );
547 }
548
549 if( int_received )
550 lprintf( stdout, "-- interrupted\n" );
551
552 if( n->events != NULL )
553 {
554 register evptr e;
555
556 lprintf( stdout, "Pending events:\n" );
557 for( e = n->events; e != NULL; e = e->nlink )
558 lprintf( stdout, " transition to %c at %2.2fns\n",
559 "0XX1"[e->eval], d2ns( e->ntime ) );
560 }
561
562 return( 1 );
563 }
564