static char *SccsId = "@(#)evalf.c 4.3 (TU-Delft) 07/27/92";
/**********************************************************

Name/Version      : sls/4.3

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"

initfunctionals (round) 
int round;
{
    int i;
    int cnt;
    int fsx;
    int fix;
    int frx;
    int fox;
    int newx;
    FUNCTION * f;

    if (round == 1)
	arr_init ((char **)&fsnulls, sizeof (int), 10, 3.0);

    for (i = 0; i < F_cnt; i++) {
        if (F[i].type < 1000) {

            f = &F[i];
            fsx = f -> fsx;

            arr_reset ((char *)fsnulls);

            if ((fox = f -> fox) >= 0) {
                cnt = FO[ fox++ ].x;
                while (cnt > 0) {
                    if ( FS[ fsx ] != '\0' ) {
                        cnt--;
                    }
                    else {
                        newx = arr_new ((char **)&fsnulls);
                        fsnulls[ newx ] = fsx;
                    }
                    fsx++;
                }
            }

            if ((fix = f -> fix) >= 0) {
                cnt = FI[ fix++ ];
                while (cnt > 0) {
                    if ( FS[ fsx ] != '\0' ) {
                        cnt--;
                    }
                    else {
                        newx = arr_new ((char **)&fsnulls);
                        fsnulls[ newx ] = fsx;
                    }
                    fsx++;
                }
            }

            if ((frx = f -> frx) >= 0) {
                cnt = FR[ frx++ ];
                while (cnt > 0) {
                    if ( FS[ fsx ] != '\0' ) {
                        cnt--;
                    }
                    else {
                        newx = arr_new ((char **)&fsnulls);
                        fsnulls[ newx ] = fsx;
                    }
                    fsx++;
                }
            }

            newx = arr_new ((char **)&fsnulls);
            fsnulls[ newx ] = -1;

            currf = &F[i];
	    if (round == 1)

	        /* the load part of the user-defined function block 
		   is executed */

		loaddf ((int)F[i].type, (char *)&FS[ F[i].fsx ]);

	    else

	        /* the initial part of the user-defined function block 
		   is executed   */

		initdf ((int)F[i].type, (char *)&FS[ F[i].fsx ]);
        }
    }
}

evalfunctional (f)
FUNCTION * f;
{
    char name[NAMESIZE];
    int fix;
    int frx;
    int fox;
    int fsx;
    int cnt;
    int newx;
    int fsnullsx;
    int lsn;
    NODE * n;

    FORCEDSIGNAL *fs; /* the field 'forcedinfo'  of a forced node is */
		      /* of this type as well                        */

    if (debugsim) {
        switch (f -> type)
        {
            case F_OR :
                sprintf (name, "OR");
                break;
            case F_NOR :
                sprintf (name, "NOR");
                break;
            case F_AND :
                sprintf (name, "AND");
                break;
            case F_NAND :
                sprintf (name, "NAND");
                break;
            case F_EXOR :
                sprintf (name, "EXOR");
                break;
            case F_INVERT :
                sprintf (name, "INVERT");
                break;
            default :
                sprintf (name, "%s", FD[f->type].name);
                break;
        }
	fprintf (debug, "\n---------- evalfunctional %s ----------\n\n", name);
    }

    switch ( f -> type ) 
    {
	case F_OR :
	    all_fsched ( f -> fox, evalfor (f -> fix));
	    break;
	case F_AND :
	    all_fsched ( f -> fox, evalfand (f -> fix));
	    break;
	case F_NOR :
	    all_fsched ( f -> fox, evalfnor (f -> fix));
	    break;
	case F_NAND :
	    all_fsched ( f -> fox, evalfnand (f -> fix));
	    break;
	case F_EXOR :
	    all_fsched ( f -> fox, evalfexor (f -> fix));
	    break;
	case F_INVERT :
	    all_fsched ( f -> fox, evalfnand (f -> fix));
				   /* use nand evaluation */
	    break;

	default :

            fsx = f -> fsx;

            arr_reset ((char *)fsnulls);

	/* the output terminals of a user-defined function block as     */
	/* they are represented in the FO array, are initialized before */
	/* the beginning of the evaluation in the following way:        */
	/*    - when the terminal is of type OUTPUT the value of the    */
	/*      this terminal as it can be found in the 'forcedinfo'    */
	/*      list of the node is put back to the FS array;           */
	/*    - when the terminal is of type INOUT  the value of the    */
	/*      node is put in the FS  array;                           */
	/* if the value of the terminal is changed in the function      */
	/* this new value is put in the FS array; when this is not      */
	/* the case, the value as it was put in FS before evaluation    */
	/* of the function block will remain in FS                      */

            if ((fox = f -> fox) >= 0) {
                cnt = FO[ fox++ ].x;
                while (cnt > 0) {
                    if ( FS[ fsx ] != '\0' ) {
                        n = &N[ FO[ fox ].x ];
			if ( FO[ fox ].type == INOUT ) {
			    lsn = LSTATE (n);
			    FS[ fsx ] = ltoc (lsn);
			}
			else if ( FO[ fox ].type == OUTPUT ) {
			    fs = n->forcedinfo;
			    while ( fs != NULL && fs->fox != fox ) 
				fs = fs->next;
			    if ( fs == NULL ) ERROR_EXIT(1);
			    FS[ fsx ] = ltoc (fs->stabfstate);
			}
			else
			     ERROR_EXIT(1);

			fox++;
			cnt--;
                    }
                    else {
                        newx = arr_new ((char **)&fsnulls);
                        fsnulls[ newx ] = fsx;
                    }
                    fsx++;
                }
            }

	/* the  input terminals of a user-defined function block as     */
	/* they are represented in the FI array, are initialized before */
	/* the beginning of the evaluation by putting the value of the  */
	/* node the terminal is connected to in the FS array            */

            if ((fix = f -> fix) >= 0) {
                cnt = FI[ fix++ ];
                while (cnt > 0) {
                    if ( FS[ fsx ] != '\0' ) {
                        n = &N[ FI[ fix++ ] ];
                        lsn = LSTATE (n);
                        FS[ fsx ] = ltoc (lsn);
                        if (debugsim) {
                            fprintf (debug, "input_t %s : %c\n", 
                            hiername (n - N),
                            FS[ fsx ]);
                        }
                        cnt--;
                    }
                    else {
                        newx = arr_new ((char **)&fsnulls);
                        fsnulls[ newx ] = fsx;
                    }
                    fsx++;
                }
            }

	/* the inread terminals of a user-defined function block as     */
	/* they are represented in the FR array, are initialized before */
	/* the beginning of the evaluation by putting the value of the  */
	/* node the terminal is connected to in the FS array            */

            if ((frx = f -> frx) >= 0) {
                cnt = FR[ frx++ ];
                while (cnt > 0) {
                    if ( FS[ fsx ] != '\0' ) {
                        n = &N[ FR[ frx++ ] ];
                        lsn = LSTATE (n);
                        FS[ fsx ] = ltoc (lsn);
                        if (debugsim) {
                            fprintf (debug, "input_r %s : %c\n", 
                            hiername (n - N),
                            FS[ fsx ]);
                        }
                        cnt--;
                    }
                    else {
                        newx = arr_new ((char **)&fsnulls);
                        fsnulls[ newx ] = fsx;
                    }
                    fsx++;
                }
            }

            newx = arr_new ((char **)&fsnulls);
            fsnulls[ newx ] = -1;

	/* the behavior part of the user-defined function block is executed   */

            currf = f;
            evaldf ((int)(f -> type), (char *)&FS[ f -> fsx ]);

            fsx = f -> fsx;

            fsnullsx = 0;

            if ((fox = f -> fox) >= 0) {
                cnt = FO[ fox++ ].x;
                while (cnt > 0) {
                    if ( fsnulls [ fsnullsx ] == fsx ) {
                        FS[ fsx ] = '\0';
                        fsnullsx++;
                    }
                    else {
                        fsched ( fox++, ctol (FS[ fsx ]) );
                        FS[ fsx ] = 'X';
                        cnt--;
                    }
                    fsx++;
                }
            }

            if ((fix = f -> fix) >= 0) {
                cnt = FI[ fix++ ];
                while (cnt > 0) {
                    if ( fsnulls [ fsnullsx ] == fsx ) {
                        FS[ fsx ] = '\0';
                        fsnullsx++;
                    }
                    else {
                        FS[ fsx ] = 'X';
                        cnt--;
                    }
                    fsx++;
                }
            }

            if ((frx = f -> frx) >= 0) {
                cnt = FR[ frx++ ];
                while (cnt > 0) {
                    if ( fsnulls [ fsnullsx ] == fsx ) {
                        FS[ fsx ] = '\0';
                        fsnullsx++;
                    }
                    else {
                        FS[ fsx ] = 'X';
                        cnt--;
                    }
                    fsx++;
                }
            }
    }

    f -> evalflag = FALSE;
}

all_fsched (fox, res)
int fox;
int res;
{
    int cnt = FO[fox++].x;

    while (cnt-- > 0) {
        fsched (fox++, res);
    }
}

fsched (fox, res)
int fox;
int res;
{
    int nextres;
    int stabres;
    float delay;
    int minevent;
    int maxevent;
    NODE * n;

    int found;
    int eventpres;
    short nextfres;
    int mintswitch;
    FORCEDSIGNAL *nfoxforcedinfo, *fs;

    if (stepdelay) {
        delay = 0;
    }
    else {
        switch (res) 
        {
	    case H_state :
                delay = (float) FO[fox].trise / inttimeaccur;
	        break;
	    case L_state :
                delay = (float) FO[fox].tfall / inttimeaccur;
	        break;
	    case X_state :
	    case Free_state :
	        if (FO[fox].trise < FO[fox].tfall)
                    delay = (float) FO[fox].trise / inttimeaccur;
	        else
                    delay = (float) FO[fox].tfall / inttimeaccur;
	        break;
        }
    }

    minevent = tcurr + delay * mindevtime;
    maxevent = tcurr + delay * maxdevtime;
    stabres = res;

    /* for node n and the output/inout terminal of the function block    */
    /* represented by fox, the correct forcedinfo in the forcedinfo-list */
    /* is found                                                          */

    n = &N[ FO[fox].x ];
    nfoxforcedinfo = n->forcedinfo;
    while ( nfoxforcedinfo != NULL && nfoxforcedinfo ->fox != fox )
    	nfoxforcedinfo = nfoxforcedinfo->next;
    if ( nfoxforcedinfo == NULL ) ERROR_EXIT(1);

    /*     the found forcedinfo is given the correct initfstate          */

    if ( tcurr < nfoxforcedinfo->tswitch )
	nfoxforcedinfo -> initfstate = nfoxforcedinfo -> initfstate ;
    else if ( tcurr < nfoxforcedinfo->tswitch_stab )
	nfoxforcedinfo -> initfstate = nfoxforcedinfo -> nextfstate ;
    else
	nfoxforcedinfo -> initfstate = nfoxforcedinfo -> stabfstate ;

    /* the following 'if statements' change the value of nextres and/or    */
    /* minevent if special cases occur                                     */

    if (minevent != maxevent && stabres != nfoxforcedinfo->initfstate) {
        if (nfoxforcedinfo->initfstate == X_state) {
            nextres = stabres;
            minevent = maxevent;
            if (nfoxforcedinfo -> nextfstate == nextres
                && nfoxforcedinfo -> tswitch < minevent
                && nfoxforcedinfo -> tswitch > tcurr)
                minevent = nfoxforcedinfo -> tswitch;
        }
        else
            nextres = X_state;
    }
    else
        nextres = stabres;

    if (nfoxforcedinfo -> nextfstate != stabres 
        && nextres != nfoxforcedinfo->initfstate
        && nfoxforcedinfo -> tswitch < minevent
        && nfoxforcedinfo -> tswitch > tcurr) {
        nextres = X_state;
        minevent = nfoxforcedinfo -> tswitch;
    }

    if (debugsim) {
	fprintf (debug,
           "output %s : (current) %c (next) %c (stable) %c\n",
	    hiername (n - N), ltoc ((int)(nfoxforcedinfo->initfstate)), 
            ltoc (nextres), ltoc (stabres));
    }

    mintswitch = MAXINT;
    eventpres = FALSE;

    found = eval_forcedinfos( n, tcurr-1, &mintswitch, &nextfres );
    while ( found && (nextfres == LSTATE(n) ) ) 
    	found = eval_forcedinfos( n, mintswitch, &mintswitch, &nextfres );
    if ( found  )
	eventpres = TRUE;

    /* now is known whether an event for node n is on the forced-eventlist */

    nfoxforcedinfo -> nextfstate = nextres;
    nfoxforcedinfo -> stabfstate = stabres;
    if (nextres != nfoxforcedinfo -> initfstate)
	nfoxforcedinfo -> tswitch = minevent;
    else
	nfoxforcedinfo -> tswitch = tcurr;
    if (stabres != nfoxforcedinfo -> initfstate)
	nfoxforcedinfo -> tswitch_stab = maxevent;
    else
	nfoxforcedinfo -> tswitch_stab = tcurr;

    if (debugsim) {
	fprintf (debug, "**new** eventpres = %d \n",eventpres);
	fs = n->forcedinfo;
	while ( fs!=NULL ) {
	    fprintf (debug,
"**new** forcedinfo : fox = %d : \n\tinitfstate = %c \n\tnextfstate = %c \n\t",
		fs->fox , ltoc ((int)(fs->initfstate)) , 
			  ltoc ((int)(fs -> nextfstate)) );
	    fprintf (debug,
	       "stabfstate = %c \n\ttswitch = %d \n\ttswitch_stab = %d \n",
		ltoc ((int)(fs->stabfstate)) ,
		fs->tswitch , 
		fs->tswitch_stab );
	    fs = fs->next;
	}
    }

    next_forced_event( n, eventpres );
}


/* next_force_event() : the forcedinfo-list of node n is evaluated and  */
/*                    : the first event on or after t=tcurr is put on   */
/*                    : the forced-event-list                           */

next_forced_event( n, eventpres )
NODE *n;
int eventpres;
{
    int found;
    int mintswitch;
    short nextfres;

    found = eval_forcedinfos( n, tcurr-1, &mintswitch, &nextfres );

    /* if an event results from the forcedinfo-list, BUT the resulting */
    /* logical value is the same as the value of the node at this      */
    /* moment, OR the resulting logical value is free and the type     */
    /* of the node is already normal  : the event has NO effect  and   */
    /* is not to be scheduled                                          */

    while ( found && (  ( nextfres == LSTATE(n)  && n->type == Forced )  || 
		        ( nextfres == Free_state && n->type == Normal ) ) ) {
    	found = eval_forcedinfos( n, mintswitch, &mintswitch, &nextfres );
    }

    if ( found ) {
	if ( eventpres ) 
	    resched_event( n, Forced, mintswitch );
	else
	    sched_event( n, Forced, mintswitch );
    }
    else {
	if (eventpres)
	    retr_event( n, Forced );
    }
}


/* eval_forcedinfos() : the forcedinfo-list of node n is evaluated and   */
/*                    : the first tswitch or tswitch_stab of a           */
/*                    : forcedinfo on or after t=tmin that is  found     */
/*                    : defines pmintswitch;                             */
/*                    : pnextres is the logical value that results       */
/*                    : when the logical values of all the forcedinfo's  */
/*                    : on t=pmintswitch are combined                    */
/*                    : if NO new event results from the forcedinfo-list */
/*                    : the routine returns 0,  else 1                   */

eval_forcedinfos( n, tmin, pmintswitch, pnextfres )
NODE *n;
int tmin;
int *pmintswitch;
short *pnextfres;
{
    FORCEDSIGNAL *fs;

    *pmintswitch = MAXINT;
    *pnextfres = X_state;
    fs = n->forcedinfo;

    while ( fs != NULL ) {
	if ( fs->tswitch > tmin && fs->tswitch < *pmintswitch ) {
		*pmintswitch = fs->tswitch;
		*pnextfres = fs->nextfstate;
	}
	else if ( fs->tswitch_stab > tmin && fs->tswitch_stab < *pmintswitch ) {
		*pmintswitch = fs->tswitch_stab;
		*pnextfres = fs->stabfstate;
	}
	fs = fs->next;
    }
    if ( *pmintswitch == MAXINT )  
	return(0);

    fs = n->forcedinfo;

    while ( fs != NULL ) {
	if ( *pmintswitch < fs->tswitch ) {
	    if ( fs->initfstate != Free_state &&
	    	 fs->initfstate != *pnextfres ) {
		    if ( *pnextfres != Free_state ) {
			*pnextfres = X_state;
		    }
		    else {
			*pnextfres = fs->initfstate;
		    }
	    }
	}
	else if ( *pmintswitch < fs->tswitch_stab ) {
	    if ( fs->nextfstate != Free_state &&
	    	 fs->nextfstate != *pnextfres ) {
		    if ( *pnextfres != Free_state ) {
			*pnextfres = X_state;
		    }
		    else {
			*pnextfres = fs->nextfstate;
		    }
	    }
	}
	else  {
	    if ( fs->stabfstate != Free_state &&
	    	 fs->stabfstate != *pnextfres ) {
		    if ( *pnextfres != Free_state ) {
			*pnextfres = X_state;
		    }
		    else {
			*pnextfres = fs->stabfstate;
		    }
	    }
	}
	fs = fs->next;
    }
    return(1);
}

int evalfor (fix)
int fix;
{
    int cnt;
    int res = L_state;

    for (cnt = FI[fix++]; cnt > 0; cnt--) {
	if (debugsim) {
	    fprintf (debug, "input %s : %d\n", 
	    hiername ( FI[fix] ), LSTATE( &N[ FI[fix] ]) );
	}
	switch ( LSTATE( &N[ FI[fix] ] ) ) {
	    case H_state :
		res = H_state;
		break;
	    case X_state :
		if (res != H_state) res = X_state;
		break;
	    case L_state :
		break;
	}

	fix++;
    }

    return (res);
}

int evalfand (fix)
int fix;
{
    int cnt;
    int res = H_state;

    for (cnt = FI[fix++]; cnt > 0; cnt--) {
	if (debugsim) {
	    fprintf (debug, "input %s : %d\n", 
	    hiername ( FI[fix] ), LSTATE( &N[ FI[fix] ]) );
	}
	switch ( LSTATE( &N[ FI[fix] ] ) ) {
	    case H_state :
		break;
	    case X_state :
		if( res != L_state )
		res = X_state;
		break;
	    case L_state :
		res = L_state;
		break;
	}

	fix++;
    }

    return (res);
}

int evalfnor (fix)
int fix;
{
    int cnt;
    int res = H_state;

    for (cnt = FI[fix++]; cnt > 0; cnt--) {
	if (debugsim) {
	    fprintf (debug, "input %s : %d\n", 
	    hiername ( FI[fix] ), LSTATE( &N[ FI[fix] ]) );
	}
	switch ( LSTATE( &N[ FI[fix] ] ) ) {
	    case H_state :
		res = L_state;
		break;
	    case X_state :
		if (res != L_state) res = X_state;
		break;
	    case L_state :
		break;
	}

	fix++;
    }

    return (res);
}

int evalfnand (fix)
int fix;
{
    int cnt;
    int res = L_state;

    for (cnt = FI[fix++]; cnt > 0; cnt--) {
	if (debugsim) {
	    fprintf (debug, "input %s : %d\n", 
	    hiername ( FI[fix] ), LSTATE( &N[ FI[fix] ]) );
	}
	switch ( LSTATE( &N[ FI[fix] ] ) ) {
	    case H_state :
		break;
	    case X_state :
		if( res != H_state )
		res = X_state;
		break;
	    case L_state :
		res = H_state;
		break;
	}

	fix++;
    }

    return (res);
}

int evalfexor (fix)
int fix;
{
    int cnt;
    int H_cnt;
    int X_cnt;
    int res;

    H_cnt = 0;
    X_cnt = 0;

    for (cnt = FI[fix++]; cnt > 0; cnt--) {
	if (debugsim) {
	    fprintf (debug, "input %s : %d\n", 
	    hiername ( FI[fix] ), LSTATE( &N[ FI[fix] ]) );
	}
	switch ( LSTATE( &N[ FI[fix] ] ) ) {
	    case H_state :
                H_cnt++;
		break;
	    case X_state :
                X_cnt++;
		break;
	    case L_state :
		break;
	}

	fix++;
    }
    if (X_cnt > 0)
        res = X_state;
    else {
        if (((H_cnt / 2) * 2) != H_cnt)
            res = H_state;            /* odd */
        else
            res = L_state;            /* even */
    }

    return (res);
}

char ltoc (l)
int l;
{
    char val;

    switch (l) {
        case L_state :
            val = 'O';
            break;
        case H_state :
            val = 'I';
            break;
        case Free_state :
            val = 'F';
            break;
        case X_state :
        default :
            val = 'X';
            break;
    }
    return (val);
}

int ctol (c)
char c;
{
    int val;

    switch (c) {
        case 'O':
            val = L_state;
            break;
        case 'I':
            val = H_state;
            break;
        case 'F':
            val = Free_state;
            break;
        case 'X':
        default :
            val = X_state;
            break;
    }

    return (val);
}
