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

Name/Version      : sls/4.2

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"

NODE ** vnptrs;          /* vicinity node pointers */
TRANSISTOR ** vtptrs;    /* vicinity transistor pointers */
NEVALINFO * neis;      /* node evaluation-info's */
TEVALINFO * teis;      /* transistor evaluation-info's */

NODE ** freevnptrs;
TRANSISTOR ** freevtptrs;
NEVALINFO * freeneis;
TEVALINFO * freeteis;

initeval () {
    maxnvicin = 50;   /* initial guess */
    maxtvicin = 50;   /* initial guess */
    initchargesh ();
    initresistdiv ();
    inittiming ();
    PPALLOC (vnptrs, maxnvicin, NODE);
    PPALLOC (vtptrs, maxtvicin, TRANSISTOR);
    PALLOC (neis, maxnvicin, NEVALINFO);
    PALLOC (teis, maxtvicin, TEVALINFO);
    act_maxnvicin = 0;
    act_maxtvicin = 0;
}

evalvicinity (vn)     /* evaluate vicinity of node vn */
NODE * vn;
{
    int cnt;
    NODE ** nn;
    NODE * n;

    if (debugsim)
	fprintf (debug, "\n---------- evalvicinity : %s ----------\n\n",
	hiername (vn - N) );

    startvsearch (vn);

    if (dissip)
	vicin_dis ();

    /* find stable voltages */

    if (vicin.forcedsH && !vicin.forcedsL && !vicin.forcedsX 
    && !vicin.undeftors) {
	vicin.type = Forced;
	nn = vicin.nodes;
	for (cnt = vicin.node_cnt; cnt > 0; cnt--) {
	    n = *nn++;

	    if (n -> type == Forced)
		continue;

	    n -> ei -> svmin = vH;
	    n -> ei -> svmax = vH;
	}
    }
    else
	if (vicin.forcedsL && !vicin.forcedsH && !vicin.forcedsX
	&& !vicin.undeftors) {
	    vicin.type = Forced;
	    nn = vicin.nodes;
	    for (cnt = vicin.node_cnt; cnt > 0; cnt--) {
		n = *nn++;

		if (n -> type == Forced)
		    continue;

		n -> ei -> svmin = 0;
		n -> ei -> svmax = 0;
	    }
	}
	else
	    if (vicin.forcedsX && !vicin.forcedsH && !vicin.forcedsL) {
		vicin.type = Forced;
		nn = vicin.nodes;
		for (cnt = vicin.node_cnt; cnt > 0; cnt--) {
		    n = *nn++;

		    if (n -> type == Forced)
			continue;

		    n -> ei -> svmin = 0;
		    n -> ei -> svmax = vH;
		}
	    }
	    else
		if (!vicin.forcedsH && !vicin.forcedsL && !vicin.forcedsX) {
		    vicin.type = Normal;
		    chargeshare ();
		}
		else {
		    vicin.type = Forced;
		    resistdivide ();
		    if (vicin.floatpossible)
			chargeshare ();
		}

    nn = vicin.nodes;
    for (cnt = vicin.node_cnt; cnt > 0; cnt--) {
	n = *nn++;

	if (n -> type == Forced)
	    continue;

	n -> stabstate = stabstateof (n -> ei -> svmin, n -> ei -> svmax);
#ifdef sun4
	n -> ivmin = (unsigned)(int)(n -> ei -> umin);
	n -> ivmax = (unsigned)(int)(n -> ei -> umax);
	n -> svmin = (unsigned)(int)(n -> ei -> svmin);
	n -> svmax = (unsigned)(int)(n -> ei -> svmax);
#else
	n -> ivmin = n -> ei -> umin;
	n -> ivmax = n -> ei -> umax;
	n -> svmin = n -> ei -> svmin;
	n -> svmax = n -> ei -> svmax;
#endif
	if (! proclogic) {
            if (n -> stabstate == X_state) {
                n -> svmin = 0;
                n -> svmax = vH;
            }
            else {
	        if (n -> svmin < vswitch) n -> svmin = 0;
	        else n -> svmin = vH;
	        if (n -> svmax < vswitch) n -> svmax = 0;
	        else n -> svmax = vH;
            }
	    if (n -> ivmin < vswitch) n -> ivmin = 0;
	    else n -> ivmin = vH;
	    if (n -> ivmax < vswitch) n -> ivmax = 0;
	    else n -> ivmax = vH;
	}
    }

    if (debugsim) {
	nn = vicin.nodes;
	for (cnt = vicin.node_cnt; cnt > 0; cnt--) {
	    n = *nn++;

	    if (n -> type == Forced)
		continue;

	    fprintf (debug, "%s :  svmin = %d svmax = %d ",
		    hiername (n - N), n -> svmin, n -> svmax);
	    fprintf (debug, "stabstate : %d\n", n -> stabstate);
	}
	fprintf (debug, "\n");
    }

    /* now, find dynamical behavior parameters */

    if (stepdelay) {
        nn = vicin.nodes;
        for (cnt = vicin.node_cnt; cnt > 0; cnt--) {
	    n = *nn++;

	    if (n -> type == Forced) 
	        continue;

	    n -> tstabmin = tcurr;
	    n -> tstabmax = tcurr;
	    n -> Ttmin = 0;
	    n -> Ttmax = 0;
        }
    }
    else {
	timing ();
    }

    vsched ();

    if (dissip)
	vicin_nsource_dis ();

    vclose ();
}

startvsearch (vn)
NODE * vn;
{
    int cnt;
    int nbr;
    NODE ** nn;
    NODE * n;
    TRANSISTOR ** tt;
    TRANSISTOR * t;
    UPAIR * up;
    UPAIR * uminmax ();

    freevnptrs = vnptrs;
    vicin.nodes = freevnptrs;
    freevtptrs = vtptrs;
    vicin.tors = freevtptrs;
    vicin.node_cnt = 0;
    vicin.tor_cnt = 0;
    freeneis = neis;
    freeteis = teis;

    vsearch (vn);

    nbr = freevnptrs - vnptrs;
    if (nbr > act_maxnvicin)
	act_maxnvicin = nbr;
    nbr = freevtptrs - vtptrs;
    if (nbr > act_maxtvicin)
	act_maxtvicin = nbr;

    vicin.forcedsH = vicin.forcedsL = vicin.forcedsX = FALSE;
    nn = vicin.nodes;
    for (cnt = vicin.node_cnt; cnt > 0; cnt--) {
	n = *nn++;

	n -> flag = FALSE;
	if (n -> essential) 
	    n -> ei -> lstate = LSTATE(n);
	if (n -> essential && n -> type == Normal
	&& n -> ei -> lstate != n -> nextstate)
	    n -> ei -> eventpending = TRUE;
	else
	    n -> ei -> eventpending = FALSE;
	if (n -> type == Forced) {
	    switch (n -> ei -> lstate) {
		case H_state: 
		    n -> ei -> svmin = vH;
		    n -> ei -> svmax = vH;
		    vicin.forcedsH = TRUE;
		    break;
		case L_state: 
		    n -> ei -> svmin = 0;
		    n -> ei -> svmax = 0;
		    vicin.forcedsL = TRUE;
		    break;
		case X_state: 
		    n -> ei -> svmin = 0;
		    n -> ei -> svmax = vH;
		    vicin.forcedsX = TRUE;
		    break;
	    }
	}
	else {
	    up = uminmax (n);
	    n -> ei -> umin = up -> umin;
	    n -> ei -> umax = up -> umax;
	}
    }

    vicin.undeftors = FALSE;
    tt = vicin.tors;
    for (cnt = vicin.tor_cnt; cnt > 0; cnt--) {
	t = *tt++;
	t -> flag = FALSE;
	if (t -> state == Undefined)
	    vicin.undeftors = TRUE;
    }
}

vsearch (n)       /* search vicinity recursively */
NODE * n;
{
    int     i;
    int     cnt;
    int     index;
    TRANSISTOR * t;   /* transistor connected to n by drain or source */
    NODE * con;       /* node connected to n by t */
    NODE ** nn;
    TRANSISTOR ** tt;

    n -> flag = TRUE;
    if (vicin.node_cnt >= maxnvicin) {   
        /* maxnvicin appears to be too small, so it is enlarged */
	CFREE (neis);
	PALLOC (neis, (1.5 * maxnvicin), NEVALINFO);
	freeneis = neis;
	PPALLOC (vnptrs, (1.5 * maxnvicin), NODE);
	freevnptrs = vnptrs;
	nn = vicin.nodes;
	for (i = vicin.node_cnt; i > 0; i--) {
	    *freevnptrs++ = *nn;
	    (*nn++) -> ei = freeneis++;
	}
	CFREE (vicin.nodes);
	vicin.nodes = vnptrs;
	maxnvicin = (1.5 * maxnvicin);
	initchargesh ();
	initresistdiv ();
	inittiming ();
    }
    *freevnptrs++ = n;
    vicin.node_cnt++;
    n -> ei = freeneis++;

    if (n -> type == Forced) {
	n -> ei -> posfloat = FALSE;
	return;
    }
    n -> ei -> posfloat = TRUE;
    if (n -> dsx < 0)
	return;

    index = n -> dsx;
    for (cnt = DS[index]; cnt > 0; cnt--) {
	index++;
	t = &T[DS[index]];
	if (!t -> flag && t -> state != Open) {
	    t -> flag = TRUE;
	    if (vicin.tor_cnt >= maxtvicin) {
                /* maxtvicin appears to be too small, so it is enlarged */
	        CFREE (teis);
	        PALLOC (teis, (1.5 * maxtvicin), TEVALINFO);
	        freeteis = teis;
	        PPALLOC (vtptrs, (1.5 * maxtvicin), TRANSISTOR);
	        freevtptrs = vtptrs;
	        tt = vicin.tors;
	        for (i = vicin.tor_cnt; i > 0; i--) {
	            *freevtptrs++ = *tt;
	            (*tt++) -> ei = freeteis++;
	        }
	        CFREE (vicin.tors);
	        vicin.tors = vtptrs;
	        maxtvicin = (1.5 * maxtvicin);
	        initchargesh ();
	        initresistdiv ();
	        inittiming ();
	    }
	    *freevtptrs++ = t;
	    vicin.tor_cnt++;
	    t -> ei = freeteis++;
	    if (&N[t -> drain] == n)
		con = &N[t -> source];
	    else
		con = &N[t -> drain];
	    if (!con -> flag)
		vsearch (con);
	}
    }
}

vclose () {

    NODE ** nn;
    NODE * n;
    TRANSISTOR ** tt;
    int cnt;

    /* reset flags */

    nn = vicin.nodes;
    for (cnt = vicin.node_cnt; cnt > 0; cnt--) {
	n = *nn++;
	n -> evalflag = FALSE;
	n -> ei = NULL;
    }

    tt = vicin.tors;
    for (cnt = vicin.tor_cnt; cnt > 0; cnt--) {
	(*tt++) -> ei = NULL;
    }
}

vsched () {            /* schedule reschedule or retrieve      */
    int     cnt;       /* logic state (and spline) transitions */
    int     tswitch;   /* of the nodes of the vicinity         */
    NODE ** nn;
    NODE * n;
    int tmin;
    int tmax;
    int tevent;
    float vminswitch;
    float vmaxswitch;

    nn = vicin.nodes;
    for (cnt = vicin.node_cnt; cnt > 0; cnt--) {
	n = *nn++;

        if (n -> type == Forced)
	    continue;

	if (n -> essential) {
	    if (n -> ei -> lstate != n -> stabstate) {

                if ( n -> stabstate == X_state
		&& ((n -> svmin > vmaxL && n -> svmin < vminH)
                   || (n -> svmax > vmaxL && n -> svmax < vminH)) ) { 
                    vminswitch = vminH;
                    vmaxswitch = vmaxL;
                }
                else {
                    vminswitch = vswitch;
                    vmaxswitch = vswitch;
                }

		if (n -> svmin == n -> ivmin)
		    tmin = tcurr;
		else
		    tmin = tcurr +
			   n -> Ttmin * (vminswitch - (float)(n -> ivmin))
			   / ((float)(n -> svmin) - (float)(n -> ivmin));

		if (n -> svmax == n -> ivmax)
		    tmax = tcurr;
		else
		    tmax = tcurr +
			   n -> Ttmax * (vmaxswitch - (float)(n -> ivmax))
			   / ((float)(n -> svmax) - (float)(n -> ivmax));

		switch (n -> ei -> lstate) {
		    case L_state :
			tswitch = tmax;
			if (n -> stabstate == H_state && tswitch < tmin)
			    n -> nextstate = X_state;
			else
			    n -> nextstate = n -> stabstate;
			break;
		    case H_state :
			tswitch = tmin;
			if (n -> stabstate == L_state && tswitch < tmax)
			    n -> nextstate = X_state;
			else
			    n -> nextstate = n -> stabstate;
			break;
		    case X_state :
			switch (n -> stabstate) {
			    case L_state :
			        tswitch = tmax;
				break;
			    case H_state :
			        tswitch = tmin;
				break;
			    default :
				ERROR_EXIT (1)
				break;
			}
			n -> nextstate = n -> stabstate;
			break;
		}

	        if (tswitch < tcurr) {
		    tswitch = tcurr;
	        }

	        if (n -> ei -> eventpending) {
	            resched_event (n, Normal, tswitch);
	        }
	        else {
		    sched_event (n, Normal, tswitch);
	        }
	    }

	    else {
		n -> nextstate = n -> stabstate;
	        if (n -> ei -> eventpending) {
		    retr_event (n, Normal);
	        }
	    }
	}

        if (n -> plot > 0) {
            if (n -> ivmin != n -> svmin || n -> ivmax != n -> svmax) {
                if (n -> ivmin == n -> svmin)
                    tevent = n -> tstabmax;
                else if (n -> ivmax == n -> svmax)
                    tevent = n -> tstabmin;
                else
                    tevent = MIN (n -> tstabmin, n -> tstabmax);
                if (! n -> plotevent) {
                    plot_node (n, 'l', (int)(n -> ivmin));
                    plot_node (n, 'u', (int)(n -> ivmax));
                    sched_event (n, Plot, tevent);
                    n -> plotevent = TRUE;
                }
                else {
                    plot_node (n, 'l', (int)(n -> ivmin));
                    plot_node (n, 'u', (int)(n -> ivmax));
                    resched_event (n, Plot, tevent);
                }
            }
            else {
                if (n -> plotevent) {
                    plot_node (n, 'l', (int)(n -> ivmin));
                    plot_node (n, 'u', (int)(n -> ivmax));
                    retr_event (n, Plot);
                    n -> plotevent = FALSE;
                }
            }
        }
    }
}

int lstate (n)    /* find logic state by using the voltages of the node */
NODE * n;
{
    UPAIR * up;
    UPAIR * uminmax ();
    int stateof();

    /* this function will be called when n is only a a 'read function input' */

    up = uminmax(n);

    if ( (n -> svmin > vmaxL && n -> svmin < vminH) 
    || (n -> svmax > vmaxL && n -> svmax < vminH) ) {
        if (up -> umin >= vminH)
            return (H_state);
        else if (up -> umax <= vmaxL)
            return (L_state);
        else
            return (X_state);
    }
    else {
        if (up -> umin >= vswitch)
            return (H_state);
        else if (up -> umax <= vswitch)
            return (L_state);
        else
            return (X_state);
    }
}

UPAIR uvals;

UPAIR * uminmax (n)    /* find current min and max voltage */
NODE * n;
{
    if (tcurr < n -> tstabmin - n -> Ttmin) {
	uvals.umin = n -> ivmin;
    }
    else
	if (tcurr >= n -> tstabmin) {
	    uvals.umin = n -> svmin;
	}
	else {
	    uvals.umin = n -> ivmin +
		((int)(unsigned) n -> svmin - (int)(unsigned) n -> ivmin)
		* (float) (tcurr - n -> tstabmin + n -> Ttmin)
		/ (n -> Ttmin);
	    /* float cast has been used because    */
	    /* it shouldn't be an integer division */
	}

    if (uvals.umin > vH * (1.1) || uvals.umin < (-vH * 0.1)) {
	ERROR_EXIT (1);
    }

    if (uvals.umin < 0)
	uvals.umin = 0;
    else
	if (uvals.umin > vH)
	    uvals.umin = vH;

    if (tcurr < n -> tstabmax - n -> Ttmax) {
	uvals.umax = n -> ivmax;
    }
    else
	if (tcurr >= n -> tstabmax) {
	    uvals.umax = n -> svmax;
	}
	else {
	    uvals.umax = n -> ivmax +
		((int)(unsigned) n -> svmax - (int)(unsigned) n -> ivmax)
		* (float) (tcurr - n -> tstabmax + n -> Ttmax)
		/ (n -> Ttmax);
	}

    if (uvals.umax > vH * (1.1) || uvals.umax < (-vH * 0.1)) {
	ERROR_EXIT (1);
    }

    if (uvals.umax < 0)
	uvals.umax = 0;
    else
	if (uvals.umax > vH)
	    uvals.umax = vH;

    if (n -> essential) {                /* correct possible inconsistancy */
                                         /* due to truncation */
	if ((n -> svmin > vmaxL && n -> svmin < vminH)  
        || (n -> svmax > vmaxL && n -> svmax < vminH)) {
            switch (n -> state) {
	        case H_state: 
		    if (uvals.umin < vminH)
		        uvals.umin = vminH;
		    if (uvals.umax < vminH)
		        uvals.umax = vminH;
	            break;
	        case L_state: 
		    if (uvals.umin > vmaxL)
		        uvals.umin = vmaxL;
		    if (uvals.umax > vmaxL)
		        uvals.umax = vmaxL;
	            break;
	        case X_state: 
		    if (uvals.umin > vminH)
		        uvals.umin = vminH;
		    if (uvals.umax < vmaxL)
		        uvals.umax = vmaxL;
	            break;
	    }
        }
        else {
            switch (n -> state) {
	        case H_state: 
		    if (uvals.umin < vswitch)
		        uvals.umin = vswitch;
		    if (uvals.umax < vswitch)
		        uvals.umax = vswitch;
	            break;
	        case L_state: 
		    if (uvals.umin > vswitch)
		        uvals.umin = vswitch;
		    if (uvals.umax > vswitch)
		        uvals.umax = vswitch;
	            break;
	        case X_state: 
		    if (uvals.umin > vswitch)
		        uvals.umin = vswitch;
		    if (uvals.umax < vswitch)
		        uvals.umax = vswitch;
	            break;
	    }
        }
    }

    return (&uvals);
}

int     stabstateof (vmin, vmax)   /* returns stable logic state, */
float   vmin;                      /* derived from these stable voltages */
float   vmax;
{
    if (vmin >= vminH)
	return (H_state);
    else
	if (vmax <= vmaxL)
	    return (L_state);
    return (X_state);
}
