static char *SccsId = "@(#)intrup.c 4.8 (TU-Delft) 06/30/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"

int     ia_ou_fac;

FILE * simout;
FILE * simres;

int outwidth;

int tlastwritten;

RES_FILE * rf_simres;
STRING_REF ** pnames;

DM_STREAM * dsp_res;

int *abstractl_len;
char *abstractl_adj;

char *nrl2int ();

initintrup () {
    int     initconv ();
    RES_PATH * rp;
    int min;
    int i;
    int tdmp;
    int nbr;
    double flo_to_doub ();

    ia_ou_fac = initconv (inttimeaccur / outtimeunit);

    intrupm.on = FALSE;
    intrupm.timebreak = FALSE;
    intrupm.outputchange = FALSE;
    intrupm.signalbreak = FALSE;
    tbreak = MAXINT + 2;

    if (!make_output) {
	if (use_io_views) {
	    dsp_res = dmOpenStream (simout_key, "res", "w");
	    simres = dsp_res -> dmfp;
	}
	else
	    OPENW (simres, fn_res);

	if (debugsim)
	    setbuf (simres, (char *) NULL);

	fprintf (simres, "%e ", inttimeaccur);
	for (rp = rp_begin; rp != NULL; rp = rp -> next) {
	    wr_path (simres, rp -> path);
	}
	fprintf (simres, "\n");
    }
    else {
	if (use_io_views) {
	    dsp_res = dmOpenStream (simout_key, "res", "r");
	    simres = dsp_res -> dmfp;
	}
	else
	    OPENR (simres, fn_res);
	while (getc (simres) != '\n');
    }

    PALLOC (rf_simres, 1, RES_FILE);
    rf_simres -> offset = ftell (simres);
    rf_simres -> signals = rp_begin;
    rf_simres -> sig_cnt = pnodes_cnt;
    strcpy (rf_simres -> name, fn_res);

    min = -1;
    nbr = arr_size ((char *)tdumps);
    for (i = 0; i < nbr; i++) {
        tdmp = d_round ( flo_to_doub ((float)tdumps[i] * sigtoint) );
        if ((tdmp < min || min < 0) && tdmp > tcurr)
            min = tdmp;
    }
    if (min > 0 && min < tbreak)
        tbreak = min;

    tlastwritten = -1;

    if (!make_output)
	fflush (simres);
}

interrupt () {
    NODE_REF_LIST * pl;
    NODE_REF_LIST * ref_el;
    ABSTRACT_OUTPUT * ab_el;
    ABSTRACT_VALUE * ab_val;
    char s;
    char *val;
    char *p;
    int sign_bit;
    int two_compl;
    int min;
    int i;
    int tdmp;
    int nbr;
    int nbr_inverted;
    int nbr_tdumps;
    double flo_to_doub ();

    if (intrupm.timebreak) {
        dump_state (tcurr);
        min = -1;
        nbr_tdumps = arr_size ((char *)tdumps);
        for (i = 0; i < nbr_tdumps; i++) {
            tdmp = d_round ( flo_to_doub ((float)tdumps[i] * sigtoint) );
            if ((tdmp < min || min < 0) && tdmp > tcurr)
                min = tdmp;
        }
        if (min < 0)
            tbreak = tsimduration + 1;
        else
            tbreak = min;
        intrupm.on = FALSE;
        intrupm.timebreak = FALSE;
        return;
    }

    nbr_inverted = arr_size (prinvert);
    nbr = 0;

    fprintf (simres, "%15d", tcurr);
    for (pl = pl_begin; pl != NULL; pl = pl -> next) {
	if (pl -> nx >= 0) {
	    if (pl -> nx < N_cnt) {
		switch ( LSTATE (&N[pl->nx]) ) {
		    case H_state: 
			s = 'h';
			break;
		    case L_state: 
			s = 'l';
			break;
		    case X_state: 
			s = 'x';
			break;
		}
	    }
	    else {
		ab_el = abstractl_begin;
		i = pl -> nx - N_cnt;
		while (i > 0) {
		    ab_el = ab_el -> next;
		    i--;
		}
                val = "X";
                ab_val = ab_el -> vals;
                while (ab_val) {
		    ref_el = ab_el -> inputs;
                    i = 0;
                    while (ref_el) {
                        if (!(ab_val -> in_values[i] == Dontcare
                              || ab_val -> in_values[i] 
                                               == LSTATE (&N[ref_el -> nx]))) {
                            break;
                        }
                        ref_el = ref_el -> next;
                        i++;
                    }
                    if (ref_el)
                        /* it did not match, try another min-term */
			ab_val = ab_val -> next;
                    else {
                        /* we found matching inputs ! */
			val = ab_val -> out_value;
			if (val[0] == '$') {
			    sign_bit = 0;
			    two_compl = 0;
			    if (val[1] == 's') {
				sign_bit = 1;
				p = val + 2;
			    }
			    else if (val[1] == 't') {
				two_compl = 1;
				p = val + 2;
			    }
			    else {
				p = val + 1;
			    }
			    if (strcmp (p, "dec") == 0) {
				val = nrl2int (ab_el -> inputs, 10, 
					       sign_bit, two_compl);
			    }
			    else if (strcmp (p, "oct") == 0) {
				val = nrl2int (ab_el -> inputs, 8, 
					       sign_bit, two_compl);
			    }
			    else if (strcmp (p, "hex") == 0) {
				val = nrl2int (ab_el -> inputs, 16, 
					       sign_bit, two_compl);
			    }
			}
                        ab_val = NULL;
                    }
                }
		s = 0;
	    }
            if (nbr < nbr_inverted && prinvert[ nbr ] == pl) {
                switch (s) {
                    case 'h':
                        s = 'l';
                        break;
                    case 'l':
                        s = 'h';
                        break;
                    default :
                        break;
                }
                nbr++;
            }
	    if (pl -> nx < N_cnt)
		putc (s, simres);
	    else 
		fprintf (simres, "(%s)", val);
	}
    }
    putc ('\n', simres);

    tlastwritten = tcurr;

    intrupm.on = FALSE;
    intrupm.timebreak = FALSE;
    intrupm.outputchange = FALSE;
    intrupm.signalbreak = FALSE;

    fflush (simres);
}

endintrup () {
    int     i;
    int     l;
    int     tnow;
    int     currpos;
    int     ln;
    char    c;
    char    line1[51];
    char    line2[61];
    char    * nodename;
    int     pos;
    long    help;
    NODE_REF_LIST * pl;
    int nbr;
    ABSTRACT_OUTPUT *ab_el;
    ABSTRACT_VALUE *ab_val;

    if (use_io_views) {
        dmCloseStream (dsp_res, COMPLETE);
        dsp_res = NULL;
    }
    else
	CLOSE (simres);

    if (use_io_views) {
	dsp_res = dmOpenStream (simout_key, "res", "r");
	simres = dsp_res -> dmfp;
    }
    else
	OPENR (simres, fn_res);

    OPENW (simout, fn_out);

    if (debugsim)
	setbuf (simout, (char *) NULL);

    nbr = 0;
    ab_el = abstractl_begin;
    while (ab_el) {
	nbr++;
	ab_el = ab_el -> next;
    }

    PALLOC (abstractl_len, nbr + 1, int);
    for (i = 0; i < nbr; i++) {
	abstractl_len[i] = 1;
    }

    PALLOC (abstractl_adj, nbr + 1, char);
    for (i = 0; i < nbr; i++) {
	abstractl_adj[i] = 'l';
    }

    /* go to begin of signal values */
    while ((c = getc (simres)) != '\n' && c != EOF);

    while (fscanf (simres, "%ld", &help) == 1) {
	pl = pl_begin;
	while ((c = getc (simres)) != '\n' && c != EOF) {
	    while (pl -> nx < 0 && pl)
		pl = pl -> next;
	    if (c == '(') {
		l = 0;
		while ((c = getc (simres)) != ')' && c != '\n' && c != EOF) {
		    if (l == 0 && ((c >= '0' && c <= '9') || c == '-'))
			abstractl_adj[pl -> nx - N_cnt] = 'r';
		    l++;
		}
		if (l > abstractl_len[pl -> nx - N_cnt])
		    abstractl_len[pl -> nx - N_cnt] = l;
	    }
	    pl = pl -> next;
	}
    }

    rewind (simres);

    pos = 15;
    for (pl = pl_begin; pl != NULL; pl = pl -> next) {
	if (pl -> nx < N_cnt)
	    pos = pos + 2;
	else {
	    pos = pos + abstractl_len[pl -> nx - N_cnt] + 1;
	}
    }

    outwidth = maxpagewidth;
    if (pos <= 80 && 80 < maxpagewidth) 
	outwidth = 80;

    prequals ();
    prcenter ("S L S");
    sprintf (line1, "version: %s", VERSION);
    prcenter (line1);
    prcenter ("S I M U L A T I O N   R E S U L T S");
    prequals ();

    outresults ();

    if (printraces && ol_begin != NULL) {
	fprintf (simout, "  races occurred");
	fprintf (simout, " during simulation :\n");
	fprintf (simout, "         time  nodes\n");
	while (ol_begin != NULL) {
	    tnow = ol_begin -> t;
	    prtime (13, tnow);
	    fprintf (simout, " ");
	    currpos = 15;
	    while (ol_begin != NULL && ol_begin -> t == tnow) {
		nodename = hiername (ol_begin -> ntx);
		ln = strlen (nodename);
		if (currpos + ln <= outwidth) {
		    fprintf (simout, " %s", nodename);
		    currpos = currpos + 1 + ln;
		}
		else {
		    fprintf (simout, "\n              ");
		    fprintf (simout, " %s", nodename);
		    currpos = 15 + 1 + ln;
		}
		ol_begin = ol_begin -> next;
	    }
	    fprintf (simout, "\n");
            prequals ();
	}
    }

    sprintf (line1, "  network : %.16s", netwname);
    sprintf (line2, "nodes : %d  ", N_cnt);
    prbeginend (line1, line2);
    if (printdevices || printstatis) {
        prequals ();
	fprintf (simout, " \n");
    }
    if (printdevices) {
        sprintf (line1, "  transistors : %7d", T_cnt - res_cnt);
	prbeginend (line1, NULL);
        sprintf (line1, "  resistors   : %7d", res_cnt);
	prbeginend (line1, NULL);
        /* sls_exp has removed all capacitors as separate devices 
        sprintf (line1, "  capacitors  : %7d", I_cnt);
	prbeginend (line1, NULL);
        */
        sprintf (line1, "  functions   : %7d", F_cnt);
	prbeginend (line1, NULL);
	fprintf (simout, " \n");
    }
    if (printstatis) {
        sprintf (line1, "  simulation timepoints        : %7d", timepoint_cnt);
	prbeginend (line1, NULL);
        sprintf (line1, "  simulation steps             : %7d", simstep_cnt);
	prbeginend (line1, NULL);
        sprintf (line1, "  essential logic events       : %7d", events_cnt);
	prbeginend (line1, NULL);
        sprintf (line1, "  max. nodes in vicinity       : %7d", act_maxnvicin);
	prbeginend (line1, NULL);
        sprintf (line1, "  max. transistors in vicinity : %7d", act_maxtvicin);
	prbeginend (line1, NULL);
	fprintf (simout, " \n");
    }
    prequals ();

    CLOSE (simout);

    if (use_io_views) {
        dmCloseStream (dsp_res, COMPLETE);
        simres = NULL;
    }
    else
	CLOSE (simres);
}

NODE_REF_LIST * pl_begpage;
NODE_REF_LIST * pl_nextpage;
int n_beg;
int n_next;

outresults () {
    int n;
    RES_PATH * rp;
    STRING_REF * sr;
    STRING_REF * names_from_path ();

    PPALLOC (pnames, pnodes_cnt, STRING_REF);

    n = 0;
    for (rp = rf_simres -> signals; rp != NULL; rp = rp -> next) {
	sr = names_from_path (0, rp -> path);
	while (sr != NULL) {
	    pnames[n++] = sr;
	    sr = sr -> next;
	}
    }

    pl_begpage = pl_begin;
    n_beg = 0;

    while (pl_begpage != NULL) {

	signamesresults (simout);
	lineresults (simout);

	pl_begpage = pl_nextpage;
        n_beg = n_next;
    }
}
	
int nbr_on_line;

signamesresults (fp)
FILE * fp;
{
    int     i;
    int     j;
    int     n;
    int     l1;
    int     ready;
    int     currpos;
    float   t;
    int     e;
    char    c;
    NODE_REF_LIST * pl;

    j = 0;
    ready = FALSE;
    while (!ready) {
	ready = TRUE;
	if (j == 0) {
	    fprintf (fp, " time         | ");
	    ready = FALSE;
	}
	else {
	    if (j == 1) {
		fprintf (fp, " in 1e");
                if (outtimeunit > 5) {
                    e = 0;
                    for (t = outtimeunit; t > 5; t = t / 10)
                        e++;
                }
                else {
                    e = 0;
                    for (t = outtimeunit; t < 0.5; t = t * 10)
                        e++;
                }
                if (outtimeunit < 0.5)
                    fprintf (fp, "-");
                else
                    fprintf (fp, "+");
                if (e < 10) 
                    fprintf (fp, "0%1d sec", e);
                else
                    fprintf (fp, "%2d sec", e);

		fprintf (fp, " | ");
	    }
	    else {
		fprintf (fp, "              | ");
	    }
	}

        nbr_on_line = 0;

        n = n_beg;
	for (pl = pl_begpage, currpos = 15; 
	     pl != NULL && currpos < outwidth; ) {

	    if (pl == pl_begpage) {
		if (pl -> nx < N_cnt)
		    currpos = currpos + 2;
		else
		    currpos = currpos + abstractl_len[pl -> nx - N_cnt] + 1;
	    }

	    if (pl -> nx < 0) {
		fprintf (fp, "  ");
	    }
	    else {
		if (pl -> nx >= N_cnt 
		    && abstractl_adj[pl -> nx - N_cnt] == 'r') {
		    i = abstractl_len[pl -> nx - N_cnt] - 1;
		    while (i > 0) {
			fprintf (fp, " ");
			i--;
		    }
		}
		l1 = strlen (pnames[n] -> str);
	        if (j < l1 - 1)
		    ready = FALSE;
	        if (j < l1) {
		    c = (pnames[n] -> str)[j];
		    if (c == '[' || c == ']')
			c = '*';
		    fprintf (fp, "%c ", c); 
	        }
		else {
		    fprintf (fp, "  ");
		}
		if (pl -> nx >= N_cnt
		    && abstractl_adj[pl -> nx - N_cnt] == 'l') {
		    i = abstractl_len[pl -> nx - N_cnt] - 1;
		    while (i > 0) {
			fprintf (fp, " ");
			i--;
		    }
		}
		n++;
	    }
	    nbr_on_line++;
	    pl = pl -> next;
	    if (pl) {
		if (pl -> nx < N_cnt)
		    currpos = currpos + 2;
		else
		    currpos = currpos + abstractl_len[pl -> nx - N_cnt] + 1;
	    }
	}
	fprintf (fp, "\n");
	j++;
    }

    pl_nextpage = pl;
    n_next = n;

    prequals ();
}

lineresults (fp)
FILE * fp;
{
    unsigned * last_vals;
    unsigned firstline;
    unsigned prev_s;
    int t;
    char s;
    int i;
    int j;
    NODE_REF_LIST * pl;
    char buf[132];
    int     intconv ();

    PALLOC (last_vals, nbr_on_line, unsigned);
    firstline = TRUE;

    fseek (simres, rf_simres -> offset, 0);
    while (fscanf (simres, "%d", &t) > 0) {
        prtime (13, t);
        fprintf (simout, " |");

        for (pl = pl_begin; pl != pl_begpage; pl = pl -> next) 
	    if (pl -> nx >= 0) {
		s = getc (simres);
		if (s == '(') {
		    while (getc (simres) != ')');
		}
	    }

        i = 0;
        for ( ; pl != pl_nextpage; pl = pl -> next) {
	    if (pl -> nx < 0) {
	        fprintf (fp, "  ");
	    }
	    else {
		if ((s = getc (simres)) == EOF || s == '\n')
		    s = '?';
		if (pl -> nx >= N_cnt) {
		    if (s != '(') {
			fprintf (stderr, 
			"error in res file: '%c' in .res file for '('\n", s);
			die (1);
		    }
		    putc (' ', fp);
		    j = 0;
		    while ((s = getc (simres)) != ')') {
			buf[j++] = s;
		    }
		    buf[j] = '\0';
		    if (abstractl_adj[pl -> nx - N_cnt] == 'r') {
			while (j < abstractl_len[pl -> nx - N_cnt]) {
			    putc (' ', fp);
			    j++;
			}
		    }
		    fprintf (fp, buf);
		    if (abstractl_adj[pl -> nx - N_cnt] == 'l') {
			while (j < abstractl_len[pl -> nx - N_cnt]) {
			    putc (' ', fp);
			    j++;
			}
		    }
		}
		else {
		    prev_s = last_vals[i];
		    last_vals[i] = s;
		    if ( printremain && (! firstline) && prev_s == s ) {
			fprintf (fp, " .");
		    }
		    else {
			switch (s) {
			    case 'h': 
				fprintf (fp, " 1");
				break;
			    case 'l': 
				fprintf (fp, " 0");
				break;
			    case 'x': 
				fprintf (fp, " x");
				break;
			    case 'f': 
				fprintf (fp, " f");
				break;
			    case '.':
				fprintf (fp, " .");
				break;
			    default: 
				fprintf (fp, " ?");
				break;
			}
		    }
		}
	    }
	    i++;
        }
        fprintf (fp, "\n");

	while ((s = getc (simres)) != '\n' && s != EOF);

	firstline = FALSE;
    }

    CFREE (last_vals);

    prequals ();
}

prtime (npos, t)
int     npos;
int     t;
{
    int     ac;
    char    format[20];
    float   help;
    int     intconv ();
    double  doubconv ();

    if (outtimeaccur < outtimeunit) {
	ac = 0;
	help = outtimeaccur / outtimeunit;
	while (help < 0.5) {
	    ac++;
	    help = help * 10;
	}
	sprintf (format, "%%%d.%df", npos, ac);
	fprintf (simout, format, doubconv (t, ia_ou_fac));
    }
    else {
	sprintf (format, "%%%dd", npos);
	fprintf (simout, format, intconv (t, ia_ou_fac));
    }
}

prequals ()
{
    int pos = 1;
    while (pos++ <= outwidth) fprintf(simout, "=");
    fprintf (simout, "\n");
}

prcenter (s)
char * s;
{
    int pos;
    int l = strlen(s);

    for (pos = 1; pos <= (outwidth - l)/2; pos++)
	fprintf (simout, " ");

    fprintf (simout, "%s", s);
    pos = pos + l;

    while (pos++ <= outwidth)
	fprintf (simout, " ");

    fprintf (simout, "\n");
}

prbeginend (s1, s2)
char * s1;
char * s2;
{
    int pos;
    int l1;
    int l2;

    if (s1 != NULL)
	l1 = strlen(s1);
    else
	l1 = 0;

    if (s2 != NULL)
	l2 = strlen(s2);
    else
	l2 = 0;

    if (l1 > 0)
        fprintf (simout, "%s", s1);

    for (pos = l1 + 1; pos <= outwidth - l2; pos++)
	fprintf (simout, " ");

    if (l2 > 0)
        fprintf (simout, "%s", s2);

    fprintf (simout, "\n");
}

nextsig_sched (n)
NODE * n;
{
    int     tswitch;
    SIGNALEVENT nextevent;

    nextevent.time = tcurr; 

    do {
	getsignal (n, nextevent.time, &nextevent);
    }
    while (nextevent.time >= 0 && nextevent.time <= tsimduration
    && nextevent.val == n -> forcedinfo -> nextfstate && tcurr >= 0);

    if (nextevent.time >= 0) {
	tswitch = nextevent.time;
	n -> forcedinfo -> nextfstate = nextevent.val;
        n -> forcedinfo -> stabfstate = nextevent.val;
	n -> forcedinfo -> tswitch = tswitch;
	sched_event (n, Forced, tswitch);
    }
}

checkbreak (n, oldlstate, oldtype)
NODE * n;
unsigned oldlstate;
unsigned oldtype;
{
    if (n -> state != oldlstate) {
        if (n -> breaksig) {
	    intrupm.on = TRUE;
	    intrupm.signalbreak = TRUE;
        }

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

dump_state (t)
int t;
{
    char fn_dump[20];
    FILE * fp_dump;
    NODE * n;
    int cnt;
    UPAIR * up;
    UPAIR * uminmax ();
    double flo_to_doub ();

    t = d_round ((double)t / flo_to_doub (sigtoint));
    sprintf (fn_dump, "dump.%d", t);

    OPENW (fp_dump, fn_dump);

    fprintf (fp_dump, "dumpfile for %s\n\n", netwname);
    fprintf (fp_dump, "%d\n", N_cnt);

    n = &N[0];
    for (cnt = 0; cnt < N_cnt; cnt++) {
        up = uminmax (n);
        fprintf (fp_dump, "%d %d %d\n", 
        (int)(up -> umin), (int)(up -> umax), (int)(n -> state));
        n++;
    }

    fprintf (fp_dump, "|");

    for (cnt = 0; cnt < FS_cnt; cnt++) {
        if (FS[cnt] == '*') {
            cnt += sizeof (int);
            cnt += (*(int *)(FS + cnt) + 1) * SIZE_PTR_INT - 1;
        }
        else {
            fwrite (FS + cnt, 1, 1, fp_dump);
        }
    }

    CLOSE (fp_dump);
}

char *nrl2int (nrl, fmt, sign_bit, two_compl)
NODE_REF_LIST *nrl;
int fmt;
int sign_bit;
int two_compl;
{
    unsigned long w;
    unsigned long result;
    int i;
    int nr_vbits;
    int max_vbits;
    char sign = '\0';
    NODE_REF_LIST *nrl_local;
    NODE_REF_LIST *nrl_el;
    static char buf[32];

    if (sign_bit || two_compl) {
	/* the first bit is a sign bit */
	if (!nrl) {
	    strcpy (buf, "x");
	    goto end_of_nrl2int;
	}
	nrl_local = nrl -> next;
    }
    else {
	nrl_local = nrl;
    }

    max_vbits = sizeof (long) * 8;

    nr_vbits = 0;
    nrl_el = nrl_local;
    while (nrl_el) {
	nr_vbits++;
	nrl_el = nrl_el -> next;
    }

    result = 0;

    i = 0;
    nrl_el = nrl_local;
    while (nrl_el) {
	switch ( LSTATE (&N[nrl_el -> nx]) ) {
	    case H_state: 
		if (((fmt == 8 || fmt == 16) && nr_vbits - i > max_vbits)
		     || (fmt == 10 && nr_vbits - i > max_vbits - 1)) {
		    strcpy (buf, "<overflow>");
		    goto end_of_nrl2int;
		}
		result = result + (1 << (nr_vbits - i - 1));
		break;
	    case L_state: 
		break;
	    case X_state: 
		strcpy (buf, "x");
		goto end_of_nrl2int;
	}
	nrl_el = nrl_el -> next;
	i++;
    }

    if (sign_bit) {
	switch ( LSTATE (&N[nrl -> nx]) ) {
	    case H_state: 
		sign = '-';
		break;
	    case L_state: 
		sign = '+';
		break;
	    case X_state: 
		strcpy (buf, "x");
		goto end_of_nrl2int;
	}
    }

    if (two_compl) {
	switch ( LSTATE (&N[nrl -> nx]) ) {
	    case H_state: 
		result = result - (1 << nr_vbits);
		sign = '-';
		result = -result;
		break;
	    case L_state: 
		break;
	    case X_state: 
		strcpy (buf, "x");
		goto end_of_nrl2int;
	}
    }

    if (fmt == 8)
	sprintf (buf, "%lo", result);
    else if (fmt == 16)
	sprintf (buf, "%lx", result);
    else
	sprintf (buf, "%ld", result);

    if (sign == '-') {
	i = strlen (buf);
	while (i >= 0) {
	    buf[i + 1] = buf[i];
	    i--;
	}
	buf[0] = sign;
    }

end_of_nrl2int:
    return (buf);
}
