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