static char *SccsId = "@(#)simul.c 4.8 (TU-Delft) 06/22/93";
/**********************************************************

Name/Version      : sls/4.8

Language          : C
Operating system  : UNIX SYSTEM V
Host machine      : HP9000

Author(s)         : A.C. de Graaf, A.J. van Genderen
Creation date     : 10-Jul-1986
Modified by       : S. de Graaf
Modification date : 10-Jul-1986


        Delft University of Technology
        Department of Electrical Engineering
        Network Theory Section
        Mekelweg 4 - P.O.Box 5031
        2600 GA DELFT
        The Netherlands

        Phone : 015 - 786234

        COPYRIGHT (C) 1986 , All rights reserved
**********************************************************/
#include "extern.h"

extern int tlastwritten;  /* from intrup.c */

NODE ** steplist;

initsimul () {
    initeventl ();
    initeval ();
    PPALLOC (steplist, maxevents, NODE);
    ol_begin = NULL;
    simstep_cnt = 0;
    timepoint_cnt = 0;
}

simulate () 
{
    int     cnt;
    char hc;
    NODE * n;
    FILE * fp_init;
    int     n_cnt_dp;
    char  fn_dp[20];
    char  str[20];
    int     vmin;
    int     vmax;
    int     state;
    int     t_n_e;
    int     time_next_event ();

    FORCEDSIGNAL *fs;

    if (monitoring) {
	monitime ("B simulate");
	monitime ("B state inits");
    }
    if (debugsim) {
	fprintf (debug, "\n================== start simulation ");
	fprintf (debug, "==================\n\n");
    }

    for (cnt = 0; cnt < T_cnt; cnt++) {
	set_trans (&T[cnt], X_state);
    }

    tcurr = -1;
    for (cnt = 0; cnt < N_cnt; cnt++) {
	n = &N[cnt];
	if (n -> redirect)
	    continue;
	n -> svmin = 0;
	n -> svmax = vH;
	n -> state = X_state;
	n -> nextstate = X_state;
	n -> stabstate = X_state;
	n -> tstabmin = tcurr;
	n -> tstabmax = tcurr;
	if (n -> inp ) {
	    n -> type = Forced;
	    n -> forcedinfo -> tswitch = tcurr;
	    nextsig_sched (n);
	}
	else if ( n -> funcoutp) {
	    n -> type = Forced;
	    fs = n->forcedinfo;
	    while ( fs != NULL ) {
		fs->tswitch = tcurr;
		fs = fs->next;
	    }
	}
	else
	    n -> type = Normal;
    }

    if (fn_init != NULL) {

        OPENR (fp_init, fn_init);
        if (fscanf (fp_init, "%s", str) != 1 || strcmp (str, "dumpfile") != 0 
            || fscanf (fp_init, "%s", str) != 1 || strcmp (str, "for") != 0)
	    slserror (fn_init, 0, ERROR1, "this file is not a dump file", NULL);
        if (fscanf (fp_init, "%s", fn_dp) != 1)
	    slserror (fn_init, 0, ERROR1, "error in this dump file", NULL);
	if (strcmp (fn_dp, netwname) != 0)
	    slserror (fn_init, 0, ERROR1,
            "this file is a dump file for network", fn_dp);
        if (fscanf (fp_init, "%d", &n_cnt_dp) != 1)
	    slserror (fn_init, 0, ERROR1, "error in this dump file", NULL);
	if (N_cnt != n_cnt_dp)
	    slserror (fn_init, 0, ERROR1,
            "number of nodes does not correspond with network",
	    netwname);

        n = &N[0];
        for (cnt = 0; cnt < N_cnt; cnt++, n++) {
            if (fscanf (fp_init, "%d %d %d", &vmin, &vmax, &state) != 3) {
	        slserror (fn_init, 0, ERROR1, "error in this dump file", NULL);
            }
	    if (n -> redirect)
	        continue;
            if (n -> inp && n -> forcedinfo -> nextfstate != Free_state)
                continue;
	    n -> svmin = vmin;
	    n -> svmax = vmax;
	    n -> nextstate = state;
	    n -> stabstate = state;
	    n -> tstabmin = 0;
	    n -> tstabmax = 0;
	    if (n -> essential) {
                if (n -> funcoutp) {
		    fs = n->forcedinfo;
		    while ( fs != NULL ) {
			fs -> initfstate = state;
			fs -> nextfstate = state;
			fs -> stabfstate = state;
			fs -> tswitch = 0;
			fs -> tswitch_stab = 0;
			fs = fs->next;
		    }
		    sched_event (n, Forced, 0);
	        }
                else
	            sched_event (n, Normal, 0);
            }
        }

        if (fscanf (fp_init, "%1s", &hc) != 1 || hc != '|') 
	    slserror (fn_init, 0, ERROR1, "error in this dump file", NULL);

        for (cnt = 0; cnt < FS_cnt; cnt++) {
            if (FS[cnt] == '*') {
                cnt += sizeof (int);
                cnt += (*(int *)(FS + cnt) + 1) * SIZE_PTR_INT - 1;
            }
            else {
                if (fread (FS + cnt, 1, 1, fp_init) <= 0)
	            slserror (fn_init, 0, ERROR1, 
                    "error in this dump file", NULL);
            }
        }

	CLOSE (fp_init);
    }

    if (monitoring) {
	monitime ("E state inits");
    }

    stepdelay = TRUE;
    tcurr = 0;
    events_cnt = 0;

    plot_begin ();

    if (dissip) 
	init_dis ();

    currtimestep ();

    if (random_initialization)
	init_random ();

    stepdelay = !delaysim;

    stopsim = FALSE;
    while (!stopsim) {
	t_n_e = time_next_event ();
	if (tlastwritten < 0
	    && ((t_n_e < 0 && tsimduration > 0) || t_n_e > 0)) {
	    intrupm.on = TRUE;
	    interrupt ();       /* force printing of signals at t = 0 */
	}
	else if ((t_n_e > tbreak || t_n_e < 0) && tbreak <= tsimduration) {
	    tcurr = tbreak;
	    intrupm.on = TRUE;
	    intrupm.timebreak = TRUE;
	    interrupt ();
	}
        else if (t_n_e < 0) {
	    stopsim = TRUE;       /* event list is empty */
            if (simperiod >= 0) {
		if (tsimduration > MAXINT)
		    slserror (NULL, 0, WARNING, 
		    "time resolution becomes too large: simulation stopped",
		    NULL);
		tcurr = tsimduration;
                if (tlastwritten < tsimduration) {
                    intrupm.on = TRUE;
                    interrupt ();        /* print values at t = simperiod */
                }
            }
        }
	else if (t_n_e > tsimduration) {
	    stopsim = TRUE;
            if (tsimduration > MAXINT)
                slserror (NULL, 0, WARNING, 
                "time resolution becomes too large: simulation stopped",
                NULL);
	    tcurr = tsimduration;
	    if (tlastwritten < tsimduration) {
		intrupm.on = TRUE;
		interrupt ();        /* print values at t = simperiod */
	    }
        }
	else {
	    tcurr = t_n_e;
	    currtimestep ();
	}
    }

    if (dissip)
 	dis_end ();

    plot_end ();

    if (monitoring) {
	monitime ("E simulate");
    }
}

init_random () {
    int save_outputchange;
    int cnt;
    NODE *n;
    int orig_type;
    int x_cnt;
    int randomstate;
    long int t;
    long mrand48 ();

    if (debugsim) {
	fprintf (debug, "\n================== start random initialization ");
	fprintf (debug, "==================\n\n");
    }

    if (random_td_initialization) {
	t = (long)time (0);
	srand48 (t);
    }

    save_outputchange = intrupm.outputchange;
    intrupm.outputchange = FALSE;

    for (cnt = 0; cnt < N_cnt; cnt++) {
	n = &N[cnt];

	if (n -> essential 
	    && !(n -> inp && n -> type == Forced)
	    && LSTATE (n) == X_state) {

	    if (debugsim) {
		fprintf (debug, "\n++++++++ random initialization node %s ",
				 hiername (n - N));
		fprintf (debug, "++++++++\n\n");
	    }

	    t = mrand48 ();
	    if (t > 0)
		randomstate = H_state;
	    else
		randomstate = L_state;

	    orig_type = n -> type;
	    if (n -> type == Normal)
		n -> type = Forced;

	    n -> nextstate = randomstate;
	    n -> stabstate = randomstate;

	    n -> linked = TRUE;  
	    /* To mark this (special) event (see update ()) */

	    /* Although it is a Forced event, we schedule it as a Normal
	       event in order to not confuse with other Forced events that
	       may have already been scheduled for this node.
	       The Normal eventlist should be empty right now.
	    */
	    sched_event (n, Normal, 0);

	    currtimestep ();
	    timepoint_cnt--;

            /* Make logic state of node n consistent with its environment */

            if (orig_type == Normal) {
		n -> nextstate = Free_state;
		n -> stabstate = Free_state;
	    }

	    sched_event (n, Normal, 0);

	    currtimestep ();
	    timepoint_cnt--;
	}
    }

    intrupm.outputchange = save_outputchange;

    if (debugsim) {
	fprintf (debug, "\n================== end random initialization ");
	fprintf (debug, "==================\n\n");
    }
}

currtimestep () {
    int     step_cnt;
    NODE * n;
    int     time_next_event ();
    int     time_read_event ();
    NODE * read_event ();
    NODE * next_event ();

    int fraces;
    FORCEDSIGNAL *fs;

    timepoint_cnt++;

    step_cnt = 0;
    while (time_next_event () == tcurr && step_cnt <= logic_depth && !stopsim) {
	simstep ();
	step_cnt++;
    }

    if (stopsim)
	return;

    while (time_next_event () == tcurr && !stopsim) {
	reset_read_event ();
	while (time_read_event () == tcurr) {
	    n = read_event ();
            if ( n -> type == Normal ) {
	        if ( n -> stabstate != X_state ) {
	            n -> nextstate = n -> stabstate = X_state;
	            n -> svmin = 0;
	            n -> svmax = vH;
	            if (printraces) {
	                if (ol_begin == NULL) {
		            PALLOC (ol_begin, 1, HISTORY_LIST);
		            ol_end = ol_begin;
	                }
	                else {
		            PALLOC (ol_end -> next, 1, HISTORY_LIST);
		            ol_end = ol_end -> next;
	                }
	                ol_end -> t = tcurr;
	                ol_end -> ntx = (n - N);
	                ol_end -> next = NULL;
	            }
	        }
            }
            else { /* type == Forced */
		fraces = 0;
	        if ( n -> forcedinfo -> stabfstate != X_state ) {
	            n -> forcedinfo -> nextfstate = X_state;
		    n -> forcedinfo -> stabfstate = X_state;
	            n -> svmin = 0;
	            n -> svmax = vH;
		    fraces = TRUE;
		}
		if ( fraces || printraces) {
		    if (ol_begin == NULL) {
			PALLOC (ol_begin, 1, HISTORY_LIST);
			ol_end = ol_begin;
		    }
		    else {
			PALLOC (ol_end -> next, 1, HISTORY_LIST);
			ol_end = ol_end -> next;
		    }
		    ol_end -> t = tcurr;
		    ol_end -> ntx = (n - N);
		    ol_end -> next = NULL;
                }
            }    
	}
	simstep ();

	/* after the races have been detected and all nodes that are      */
	/* involved have been given the X-state, a user-defined function  */
	/* might place another event on the forced-event-list as a        */
	/* result of the X-values of the 'races'-nodes; this is done in   */
	/* the final simstep(); when this is done the simulation will     */
	/* never stop, so it is necessary to take all the events ON       */
	/* t=tcurr off the event-lists                                    */

        reset_read_event ();
	while (time_read_event () == tcurr) {
	    n = next_event ();
	    if (debugsim) {
		fprintf (debug, "event deleted from a certain event list\n");
	    }
	    reset_read_event ();
	}
    }

    if (intrupm.outputchange) {
	intrupm.on = TRUE;
	interrupt ();
    }
}

simstep () {
    NODE ** freesteplist;
    NODE ** nn;
    NODE * n;
    NODE * conn;
    int     event_cnt;
    int     cnt;
    int     concnt;
    int     torcnt;
    TRANSISTOR * t;
    INTERCAP * ic;
    int     index;
    unsigned  oldtorstate;
    int     time_next_event ();
    NODE * next_event ();

    simstep_cnt++;

    if (debugsim) {
	fprintf (debug, "\n======================");
	fprintf (debug, " simstep : tcurr = %d ", tcurr);
	fprintf (debug, "=======================\n\n");
    }

    freesteplist = steplist;
    event_cnt = 0;
    while (time_next_event () == tcurr) {
	*freesteplist++ = next_event ();
	event_cnt++;
    }

    nn = steplist;

    for (cnt = 0; cnt < event_cnt; cnt++) {

	n = *nn++;

        if (n -> plot > 0
        && n -> plotevent
        && (n -> tstabmin == tcurr || n -> tstabmax == tcurr)) {
            if (n -> tstabmin == tcurr)
                plot_node (n, 'l', (int)(n -> svmin));
            if (n -> tstabmax == tcurr)
                plot_node (n, 'u', (int)(n -> svmax));
	    retr_event (n, Plot);
            n -> plotevent = FALSE;      /* event caused by spline changing */
            if (n -> tstabmin > tcurr || n -> tstabmax > tcurr) {
                if (n -> tstabmin > tcurr)                  /* another event */
                    sched_event (n, Plot, n -> tstabmin);
                else
                    sched_event (n, Plot, n -> tstabmax);
                n -> plotevent = TRUE;
            }
            continue;
        }

	update(n);

	if (n -> thisvicin) {
	    n -> evalflag = TRUE;
	    continue;
	}
	if (n -> cx != -1) {
	    index = n -> cx;
	    for (concnt = C[index].c; concnt > 0; concnt--) {
		index++;
		switch (C[index].sort)
		{
		    case Transistor :
			t = &T[ C[index].c ];
			oldtorstate = t -> state;
			set_trans (t, (int)(LSTATE (n)));
			if (t -> state != oldtorstate) {
			    if (N[t -> drain].type != Forced)
				N[t -> drain].evalflag = TRUE;
			    if (N[t -> source].type != Forced)
				N[t -> source].evalflag = TRUE;
			}
			break;
		    case Intercap :
			ic = &I[ C[index].c ];
			if ( &N[ ic -> con1 ] == n ) {
			    /* hier lading injectie doen            */
                            /* (nu is dat nog niet geimplementeerd) */
                            /*
			    N[ ic -> con2 ].evalflag = TRUE;
                            */
			}
			else {
			    /* hier lading injectie doen            */
                            /* (nu is dat nog niet geimplementeerd) */
                            /*
			    N[ ic -> con1 ].evalflag = TRUE;
                            */
			}
			break;
		    case Functional :
			F[ C[index].c ].evalflag = TRUE;
			break;
		}
	    }
	}
	if (n -> type == Forced && n -> dsx != -1) {
	    index = n -> dsx;
	    for (torcnt = DS[index]; torcnt > 0; torcnt--) {
		index++;
		t = &T[DS[index]];
		if (t -> state != Open) {
		    if (&N[t -> drain] == n)
			conn = &N[t -> source];
		    else
			conn = &N[t -> drain];
		    if (conn -> type != Forced)
			conn -> evalflag = TRUE;
		}
	    }
	}
    }

    if (intrupm.on)
	interrupt ();

    if (stopsim)
	return;

    nn = steplist;

    for (cnt = 0; cnt < event_cnt; cnt++) {

	n = *nn++;

	if (n -> thisvicin) {
	    if (n -> evalflag)
	        evalvicinity (n);
	    n -> thisvicin = FALSE;
	    continue;
	}
	if (n -> cx != -1) {
	    index = n -> cx;
	    for (concnt = C[index].c; concnt > 0; concnt--) {
		index++;
		switch (C[index].sort)
		{
		    case Transistor :
			t = &T[ C[index].c ];
			if (N[t -> drain].evalflag)
			    evalvicinity (&N[t -> drain]);
			if (N[t -> source].evalflag)
			    evalvicinity (&N[t -> source]);
			break;
		    case Intercap :
			ic = &I[ C[index].c ];
			if ( N[ ic -> con1 ].evalflag )
			    evalvicinity (&N[ ic -> con1 ]);
			if ( N[ ic -> con2 ].evalflag )
			    evalvicinity (&N[ ic -> con2 ]);
			break;
		    case Functional :
			if ( F[ C[index].c ].evalflag )
			    evalfunctional ( &F[ C[index].c ] );
			break;
	    	}
	    }
	}
	if (n -> type == Forced && n -> dsx != -1) {
	    index = n -> dsx;
	    for (torcnt = DS[index]; torcnt > 0; torcnt--) {
		index++;
		t = &T[DS[index]];
		if (t -> state != Open) {
		    if (&N[t -> drain] == n)
			conn = &N[t -> source];
		    else
			conn = &N[t -> drain];
		    if (conn -> evalflag)
			evalvicinity (conn);
		}
	    }
	}
    }
}

update(n)
NODE * n;
{
    unsigned oldlstate;
    unsigned oldtype;
    int tswitch;
    UPAIR * up;
    UPAIR * uminmax ();

    int mintswitch;
    short nextfres;

    events_cnt++;
    oldlstate = LSTATE(n);
    oldtype = n -> type;


    if ( n->inp ) {
	mintswitch = n->forcedinfo->tswitch;
	nextfres = n->forcedinfo->nextfstate;
    }
    else if ( n->funcoutp && !n -> linked )
	eval_forcedinfos( n, tcurr-1, &mintswitch, &nextfres );
    else if ( n -> type == Forced ) {
	mintswitch = 0;
	nextfres = n -> nextstate;
    }

    if (oldtype == Forced) { 

	if ( mintswitch != tcurr) ERROR_EXIT (1);

        if ( nextfres == Free_state) {
	    n -> state = n -> nextstate = n -> stabstate = oldlstate;
    	    n -> type = Normal;
    	    n -> thisvicin = TRUE;
	    if ( n->inp )
		n -> forcedinfo -> tswitch = -1;
        }
	else {

	    if (dissip > 0)
		forced_dis (n, n -> state, (unsigned)nextfres);

	    n -> state = nextfres;
            n -> ivmin = n -> svmin;
            n -> ivmax = n -> svmax;
	    n -> tstabmin = tcurr;
	    n -> tstabmax = tcurr;
	    switch (n -> state) {
		case L_state: 
    		    n -> svmin = 0;
    		    n -> svmax = 0;
    		    break;
    	        case H_state: 
    		    n -> svmin = vH;
    		    n -> svmax = vH;
    		    break;
    	        case X_state: 
    		    n -> svmin = 0;
    		    n -> svmax = vH;
    		    break;
    	    }
            if (n -> plot > 0) {
                if (n -> ivmin != n -> svmin || n -> ivmax != n -> svmax) {
                    plot_node (n, 'l', (int)(n -> ivmin));
                    plot_node (n, 'u', (int)(n -> ivmax));
                    plot_node (n, 'l', (int)(n -> svmin));
                    plot_node (n, 'u', (int)(n -> svmax));
                }
            }
	    if ( n->inp )
		n -> forcedinfo -> tswitch = -1;
	}

        if (n -> inp)
	    nextsig_sched (n);
	else if ( n->funcoutp && !n -> linked )
	    next_forced_event( n, FALSE );
    }

    else if (oldtype == Normal) {

        if ( (n -> inp  || n -> funcoutp)
	&& mintswitch == tcurr
	&& nextfres != Free_state) {

	    if (oldlstate != n -> nextstate) {
		retr_event (n, Normal);
	    }

            if (n -> plot > 0) {
                up = uminmax (n);
            }

	    n -> type = Forced;
	    n -> state = nextfres;
	    n -> tstabmin = tcurr;
	    n -> tstabmax = tcurr;
	    switch (n -> state) {
		case L_state: 
    		    n -> svmin = 0;
    		    n -> svmax = 0;
    		    break;
    	        case H_state: 
    		    n -> svmin = vH;
    		    n -> svmax = vH;
    		    break;
    	        case X_state: 
    		    n -> svmin = 0;
    		    n -> svmax = vH;
    		    break;
            }
            if (n -> plot > 0) {
                plot_node (n, 'l', (int)(up -> umin));
                plot_node (n, 'u', (int)(up -> umax));
                plot_node (n, 'l', (int)(n -> svmin));
                plot_node (n, 'u', (int)(n -> svmax));
            }

            if (n -> inp) {
		n -> forcedinfo -> tswitch = -1;
	        nextsig_sched (n);
	    }
	    else if ( n->funcoutp && !n -> linked )
		next_forced_event( n, FALSE);
	}
	else {
            n -> state = n -> nextstate;
	    if (n -> nextstate != n -> stabstate) {

		switch (n -> stabstate) {
		    case L_state :
			tswitch = (n -> tstabmax - n -> Ttmax) +
				  n -> Ttmax * 
				  (vswitch - (float)(n -> ivmax))
				  / ((float)(n -> svmax) - (float)(n -> ivmax));
			break;
		    case H_state :
			tswitch = (n -> tstabmin - n -> Ttmin) +
				  n -> Ttmin * 
				  (vswitch - (float)(n -> ivmin))
				  / ((float)(n -> svmin) - (float)(n -> ivmin));
			break;
		    default :
			ERROR_EXIT (1);
			break;
		}

		if (tswitch <= tcurr) {
		    ERROR_EXIT (1);  /* error on second interval event */
		}

		sched_event (n, Normal, tswitch);

		n -> nextstate = n -> stabstate;
	    }
	}
    }

    if (n -> outp)
        checkbreak (n, oldlstate, oldtype);

    if (debugsim) {
	fprintf (debug, "UPDATED: ");
	fprintf (debug, "%s : on t=%d from %d to %d\n",
		hiername (n - N), tcurr, oldlstate, LSTATE(n));
	if (oldtype != n -> type) {
	    fprintf (debug, "type did change to ");
	    if (n -> type == Forced)
		fprintf(debug, "Forced\n");
	    else
		fprintf(debug, "Normal\n");
	}
    }

    if (n -> linked)
	n -> linked = FALSE;
}

set_trans (t, s)
TRANSISTOR * t;
int     s;
{
    switch (t -> type) {
	case Nenh: 
	    switch (s) {
		case H_state: 
		    t -> state = Closed;
		    break;
		case L_state: 
		    t -> state = Open;
		    break;
		case X_state: 
		    t -> state = Undefined;
		    break;
	    }
	    break;
	case Penh: 
	    switch (s) {
		case H_state: 
		    t -> state = Open;
		    break;
		case L_state: 
		    t -> state = Closed;
		    break;
		case X_state: 
		    t -> state = Undefined;
		    break;
	    }
	    break;
	case Depl: 
	    t -> state = Closed;
	    break;
	case Res: 
	    t -> state = Closed;
	    break;
    }
}
