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

Name/Version      : sls/4.19

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"
#ifdef ESE
#include "eseOption.h"
#include "tversion.h"
#endif
#include <signal.h>

#ifdef FUNCSLS
char * argv0 = "funcsls";
#else
char * argv0 = "sls";
#endif

char * ST;
NAMETABLE * NT;
MODELTABLE * MT;
CONTEXTTABLE * CTT;
MODELCALLTABLE * MCT;
int * XT;
int * XX;
NODE * N;
int * DS;
CONTROL * C;
INTERCAP * I;
TRANSISTOR * T;
FUNCTION * F;
int * FI; 
int * FR; 
FUNCOUT * FO; 
char * FS;

int ST_cnt;
int NT_cnt;
int MT_cnt;
int CTT_cnt;
int MCT_cnt;
int XT_cnt;
int XX_cnt;
int N_cnt;
int DS_cnt;
int C_cnt;
int T_cnt;
int F_cnt;
int I_cnt;
int FI_cnt;
int FR_cnt;
int FO_cnt;
int FS_cnt;

FILE * debug;

char * netwname;
char * ressuffix = "res";
char * pltsuffix = "plt";
char * outsuffix = "out";
char * fn_cmd;
char * fn_proc;
char * fn_res;
char * fn_plt;
char * fn_out;
char * fn_init;

int debugdata;
int debugsim;
int debugmem;
int monitoring;
int verbose;
int no_expand;
int make_output;

int delaysim;
int outonchange;
int proclogic;
int printraces;
int printinfo;
int printdevices;
int printstatis;
int maxpagewidth;
int printremain;
int dissip;
int use_io_views;
int random_initialization;
int random_td_initialization;

float mindevtime;
float maxdevtime;
int simperiod;
int disperiod;
int sig_toffset;

float sigtimeunit;   /* signal time unit */
float outtimeunit;   /* output time unit */
float outtimeaccur;  /* output time accuracy */
float inttimeaccur;  /* internal time accuracy */
float sigtoint;      /* sig time to internal time conversion factor */

int vH;
float vHtmp;
float vswitch_ext;
float vswitch;
float vminH;
float vmaxL;
float krise;
float kfall;

int maxevents;
int maxnvicin;
int maxtvicin;
int logic_depth;
int res_cnt;
int nodes_cnt;
int essnodes_cnt;
int inpnodes_cnt;
int funcoutpnodes_cnt;
int pnodes_cnt;
int plotnodes_cnt;
int events_cnt;
int simstep_cnt;
int timepoint_cnt;
int act_maxnvicin;
int act_maxtvicin;
int sigendless;
int * tdumps;
NODE_REF_LIST ** prinvert;

int tcurr;
int tbreak;
int tsimduration;

int stopsim;
int stepdelay;

int fatalerror;

VICINITY vicin;
AGGLOMERATION agglom;
INTERRUPTMASK intrupm;

NODE_REF_LIST * pl_begin = NULL;
NODE_REF_LIST * pl_end;
NODE_REF_LIST * plotl_begin = NULL;
NODE_REF_LIST * plotl_end;
NODE_REF_LIST * disl_begin = NULL;
NODE_REF_LIST * disl_end;
ABSTRACT_OUTPUT * abstractl_begin = NULL;
ABSTRACT_OUTPUT * abstractl_end;
RES_PATH * rp_begin = NULL;
RES_PATH * rp_end;
HISTORY_LIST * ol_begin;
HISTORY_LIST * ol_end;

int * fsnulls;
FUNCTION * currf;

int dbinitialized = FALSE;
DM_PROJECT * dmproject = NULL;
DM_CELL * stimuli_key = NULL;
DM_CELL * simout_key = NULL;

/* below this line only global to this file */

long	ttprev;
long	starttime;
long	stoptime;

#ifdef ESE
OptionSpec optionSpecs[] = {
    { "usage", NO, eseHelp, (void *) optionSpecs,
            "usage:     sls [options] cell commandfile\nOptions (may be abbreviated) are: "},
    { "%etext", NO, eseText, (void *) NULL,
            "    -%etext:                   print the '(int) & etext' number" },
    { "%help", NO, eseHelpAll, (void *) optionSpecs,
            "    -%help:                   print this list" },
    { "help", NO, eseHelp, (void *) optionSpecs,
            "    -help:                    print this list" },
    { "release", NO, esePrintString, (void *) TOOLVERSION,
            "    -release:                 print the release number of this tool"},
    { "monitor", NO, eseTurnOn, (void *) & monitoring,
            "    -monitor:                 generate run-time statistics" },
    { "verbose", NO, eseTurnOn, (void *) & verbose,
            "    -verbose:                 print some information about actions taken by the program" },
    { "noexpand", NO, eseTurnOn, (void *) & no_expand,
            "    -noexpand:                do not run the expansion program" },
    { "%datadebug", NO, eseTurnOn, (void *) & debugdata,
            "    -%datadebug:              debugdata = TRUE"},
    { "%simdebug", NO, eseTurnOn, (void *) & debugsim,
            "    -%simdebug:               debugsim = TRUE"},
    { "%memdebug", NO, eseTurnOn, (void *) & debugmem,
            "    -%memdebug:               debugmem = TRUE"},
    { (char *) 0, (char) 0, (IFP) 0, (void *) 0, (char *) 0 },
};
#endif


main (argc, argv)
int     argc;
char   *argv[];
{
#ifndef ESE
    char *use_msg = "\nUsage: %s [-mnv] cell commandfile\n\n";
#else
    char *use_msg = "\nUsage: %s [options] cell commandfile\n\n";
    extern int eseCO ();
#endif
    char simoutname[DM_MAXNAME + 1];

    char   *s;
    int int_hdl ();
    float vscaling;
    float fl_to_pt ();
    char ** arguments;
    
    fatalerror = FALSE;

    debugdata = FALSE;
    debugsim = FALSE;
    debugmem = FALSE;
    monitoring = FALSE;
    verbose = FALSE;
    no_expand = FALSE;
    make_output = FALSE;

    fn_cmd = NULL;

#ifndef ESE
    while (--argc > 0) {
        if ( (*++argv)[0] == '-' ) {
	    for (s = *argv + 1; *s != '\0'; s++) {
	        switch (*s) {
		    case 'm':
		        monitoring = TRUE;
		        break;
		    case 'n':
			no_expand = TRUE;
			break;
		    case 'o':
			make_output = TRUE;
			break;
		    case 'v':
			verbose = TRUE;
			break;
		    case '%' :
			switch (*++s) {
		            case 'd': 
			        debugdata = TRUE;
			        break;
		            case 'b': 
			        debugsim = TRUE;
			        break;
		            case 'm': 
			        debugmem = TRUE;
			        break;
			    case '\0':
				break;
			    default :
		                fprintf (stderr, "%s: illegal option: %c\n", 
				argv0, *s);
		                die (1);
			}
			break;
		    default: 
		        fprintf (stderr, "%s: illegal option: %c\n", argv0, *s);
		        die (1);
	        }
	    }
	}
	else {
            if (netwname == NULL) {
		netwname = *argv;
	    }
	    else {
                if (fn_cmd == NULL) {
                    fn_cmd = *argv;
                }
                else {
                    fprintf (stderr, use_msg, argv0);
		    die (1);
                }
	    }
	}
    }
#else
    arguments = (char **) calloc (2, sizeof (char *));
    if ((eseOptionHandler (argc, argv, optionSpecs, 2, arguments) > 0)) {
        fprintf (stderr, use_msg, argv0);
        die (1);
    }
    netwname = arguments[0];
    fn_cmd = arguments[1];
#endif

    if (fn_cmd == NULL || netwname == NULL) {
        fprintf (stderr, use_msg, argv0);
	die (1);
    }

    if (no_expand == FALSE) {
	struct stat buf;
	int newtime;
	int oldtime;
	char com[132];

	if (stat (argv0, &buf) == 0)
	    oldtime = buf.st_mtime;
	else
	    oldtime = -1;

        if (verbose)
#ifdef ESE
	    sprintf (com, "netexp %s", netwname);
#else
	    sprintf (com, "sls_exp %s", netwname);
#endif
	else
#ifdef ESE
	    sprintf (com, "netexp -silent %s", netwname);
#else
	    sprintf (com, "sls_exp -s %s", netwname);
#endif
	if (system (com) != 0)
	    die (1);

	if (stat (argv0, &buf) == 0)
	    newtime = buf.st_mtime;
	else
	    newtime = -1;

	if (newtime > oldtime) {
#ifdef ESE
            if (strcmp (argv0, "funcsls") == 0) {
		if (verbose)
		    execl (argv0, "-noexpand", "-verbose", 
						 netwname, fn_cmd, (char *)0);
		else
		    execl (argv0, "-noexpand", netwname, fn_cmd, (char *)0);
	    }
#else
	    if (verbose)
		execl (argv0, "-nv", netwname, fn_cmd, (char *)0);
	    else
		execl (argv0, "-n", netwname, fn_cmd, (char *)0);
#endif
	}
    }

    if (verbose) {
	fprintf (stderr, "Simulating %s with %s\n",
			 netwname, fn_cmd);
    }

    if (debugdata || debugsim || debugmem) {
	OPENW (debug, "deb");
	setbuf (debug, (char *) NULL);
    }

    if (monitoring) {
	startmonitime (argv0);
	monitime ("B main");
    }

    dbinitialized = TRUE;

#ifdef ESE
#ifdef FUNCSLS
    eseCO ("size");
#endif
#endif

    dmInit (argv0);
    dmproject = dmOpenProject (DEFAULT_PROJECT, DEFAULT_MODE);

    if (signal (SIGINT, SIG_IGN) != SIG_IGN)   
        signal (SIGINT, int_hdl);
        /* only when value was not SIG_IGN, a jump must be done to int_hdl */
    if (signal (SIGQUIT, SIG_IGN) != SIG_IGN)
        signal (SIGQUIT, int_hdl);
        /* only when value was not SIG_IGN, a jump must be done to int_hdl */
    signal (SIGTERM, int_hdl);
    signal (SIGILL, int_hdl);
    signal (SIGFPE, int_hdl);
#   ifdef SIGBUS
    signal (SIGBUS, int_hdl);
#   endif
    signal (SIGSEGV, int_hdl);

    use_io_views = FALSE;
#if NCF_RELEASE >= 400
    {
	/* Unfortunately, 

	if ((int)dmGetMetaDesignData (EXISTVIEW, dmproject, VIEW) != 1) {
        }

	   does not work since it calls dmError if the view does not exist.
	*/

        DM_QDATA **view_list;
        int view_entry;
        int exist_views = 0;

	view_list = dmproject -> views;
	for (view_entry = 0; view_list[view_entry] != NULL; ++view_entry) {
	    if (strcmp (STIMULI, view_list[view_entry][0].point) == 0
	     || strcmp (SIMOUT, view_list[view_entry][0].point) == 0) {
                exist_views++;
	    }
	}

	if (exist_views == 2)
	    use_io_views = TRUE;
    }
#endif

    if (use_io_views) {
	char * tmp_p;

	stimuli_key = dmCheckOut (dmproject, fn_cmd, WORKING,
				 DONTCARE, STIMULI, READONLY);

        strcpy (simoutname, netwname);
        if ((tmp_p = strchr (simoutname, '#')) != NULL) {
	   /* '#' character in netwname. */
	   *tmp_p = '\0';
	}

	simout_key = dmCheckOut (dmproject, simoutname, DERIVED,
				 DONTCARE, SIMOUT, UPDATE);
    }

    binfil ();

    PALLOC (fn_res, 15, char);
    sprintf (fn_res, "%.10s.%s", netwname, ressuffix);

    PALLOC (fn_plt, 15, char);
    sprintf (fn_plt, "%.10s.%s", netwname, pltsuffix);

    PALLOC (fn_out, 15, char);
    sprintf (fn_out, "%.10s.%s", netwname, outsuffix);

    if (!make_output)
	initfunctionals (1);   /* execute 'load' part of functions */

    if (debugmem) {
        deb_mem ();
    }

    if (debugdata) {
	deb_all ();
    }

    fn_proc = NULL;
    fn_init = NULL;
    delaysim = FALSE;
    outonchange = FALSE;
    proclogic = FALSE;
    printraces = TRUE;
    printinfo = FALSE;
    printdevices = FALSE;
    printstatis = FALSE;
    maxpagewidth = 132;
    printremain = FALSE;
    dissip = FALSE;
    random_initialization = FALSE;
    random_td_initialization = FALSE;

    mindevtime = -1;
    maxdevtime = -1;
    simperiod = -1;
    sig_toffset = 0;
    disperiod = -1;

    sigtimeunit = -1;
    outtimeunit = -1;
    outtimeaccur = -1;
    vHtmp = -1;
    vswitch_ext = -1;
    vminH = -1;
    vmaxL = -1;

    logic_depth = -1;

    pnodes_cnt = 0;
    plotnodes_cnt = 0;
    sigendless = FALSE;

    getcommands ();

    if (printinfo) {
	printdevices = TRUE;
	printstatis = TRUE;
    }

    if (random_td_initialization)
	random_initialization = TRUE;

    if (sigtimeunit < 0)
	sigtimeunit = 1;
    if (outtimeunit < 0)
	outtimeunit = fl_to_pt (sigtimeunit);
    if (outtimeaccur < 0)
	outtimeaccur = outtimeunit;
    else if (outtimeaccur > outtimeunit)
	slserror (NULL, 0, ERROR1, "outacc is more than outunit", NULL);
    inttimeaccur = outtimeaccur;
    sigtoint = sigtimeunit / inttimeaccur;
    if (simperiod < 0 && sigendless)
	slserror (NULL, 0, ERROR1, "endless changing input signal",
	"while no simperiod was specified");
    if (simperiod < 0)
	tsimduration = MAXINT + 1;  /* this value is used later ! */
    else {
	if (simperiod * sigtoint > MAXINT) {
	    slserror (NULL, 0, ERROR1, "time resolution too large:",
	    "reduce 'simperiod' or enlarge 'outaccur'");
	}
	tsimduration = simperiod * sigtoint;
    }

    if (mindevtime > 1) {
	slserror (NULL, 0, ERROR1, "illegal tdevmin", NULL);
	die (1);
    }
    if (mindevtime < 0) mindevtime = 1;

    if (maxdevtime >= 0 && maxdevtime < 1) {
	slserror (NULL, 0, ERROR1, "illegal tdevmax", NULL);
    }
    if (maxdevtime < 0) maxdevtime = 1;

    if (!make_output && (proclogic || delaysim))
	getproc ();

    if (vHtmp >= 0)
        vscaling = VOLTMAX_INT / vHtmp;
    else
	vscaling = 1;
    vH = VOLTMAX_INT;

    if (vswitch_ext >= 0) {
	if (vHtmp >= 0)
	    vswitch = (vswitch_ext / vHtmp) * vH;
	else
	    vswitch = (vswitch_ext / 5.0) * vH;
    }
    else
	vswitch = vH / 2;

    if (vswitch > vH) {
	slserror (NULL, 0, ERROR1, "error: vswitch > vh", NULL);
    }

    if (vminH >= 0)
	vminH = vminH * vscaling;
    else
        vminH = VOLTMAX_INT * VMINH_REL_DEF;

    if (vmaxL >= 0)
	vmaxL = vmaxL * vscaling;
    else
        vmaxL = VOLTMAX_INT * VMAXL_REL_DEF;

    if (vminH > vH || vmaxL < 0 || vminH < vmaxL) {
	slserror (NULL, 0, ERROR1, "error on logic threshold voltages", NULL);
    }

    if (vminH < vswitch) {
	slserror (NULL, 0, ERROR1, "error: vminh < vswitch", NULL);
    }

    if (vmaxL > vswitch) {
	slserror (NULL, 0, ERROR1, "error: vmaxl > vswitch", NULL);
    }

    if (debugsim) {
	fprintf (debug, "vH: %12d  vswitch: %20f\n\n", vH, vswitch);
	fprintf (debug, "vminH: %20f  vmaxL: %20f\n\n", vminH, vmaxL);
	fprintf (debug, "sigtimeunit = %e\n", sigtimeunit);
	fprintf (debug, "outtimeunit = %e\n", outtimeunit);
	fprintf (debug, "outtimeaccur = %e\n", outtimeaccur);
	fprintf (debug, "inttimeaccur = %e\n", inttimeaccur);
	fprintf (debug, "simperiod = %d\n", simperiod);
	fprintf (debug, "tsimduration = %d\n", tsimduration);
	fprintf (debug, "\n");
    }

    if (!make_output) {
	initnodes ();
	inittors ();
    }

    if (logic_depth < 0) {
        logic_depth = essnodes_cnt;
        if (logic_depth > 100)
            logic_depth = 100;	/* max logic depth when not specified */
    }

    maxevents = essnodes_cnt + inpnodes_cnt + funcoutpnodes_cnt + plotnodes_cnt;

    if (!make_output)
	initsimul ();

    initintrup ();

    if (!make_output)
	plot_scale ();

    if (delaysim && !make_output)
	initmode ();

    if (!make_output)
	initfunctionals (2);   /* execute 'initial' part of functions */

    if (!make_output)
	simulate ();

    endintrup ();

    if (use_io_views) {
        dmCheckIn (stimuli_key, COMPLETE);
        stimuli_key = NULL;
        dmCheckIn (simout_key, COMPLETE);
        simout_key = NULL;

	_dmAddCellEquivalence (dmproject, fn_cmd, STIMULI,
					  simoutname, SIMOUT);
	_dmAddCellEquivalence (dmproject, netwname, CIRCUIT,
					  simoutname, SIMOUT);
    }

    if (dmproject) dmCloseProject (dmproject, COMPLETE);
    dmQuit ();
    dbinitialized = FALSE;

    if (signal (SIGINT, SIG_IGN) != SIG_IGN)
        signal (SIGINT, SIG_DFL);
    if (signal (SIGQUIT, SIG_IGN) != SIG_IGN)
        signal (SIGQUIT, SIG_DFL);
    signal (SIGTERM, SIG_DFL);
    signal (SIGILL, SIG_DFL);
    signal (SIGFPE, SIG_DFL);
#   ifdef SIGBUS
    signal (SIGBUS, SIG_DFL);
#   endif
    signal (SIGSEGV, SIG_DFL);

    if (debugdata || debugsim || debugmem)
	CLOSE (debug);

    if (monitoring) {
	monitime ("E main");
	stopmonitime ();
    }

    return (0);
}

initnodes () {
    int     cnt;
    int     cnt2;
    int     index;
    NODE * n;
    TRANSISTOR * t;
    float   tp;
    float   torpar ();

    int i;
    int fox;
    FUNCTION *f;
    FORCEDSIGNAL *fs;

    nodes_cnt = 0;
    essnodes_cnt = 0;
    inpnodes_cnt = 0;
    funcoutpnodes_cnt = 0;

    for (cnt = 0; cnt < FR_cnt; cnt++) {
	N[ FR[cnt] ].essential = TRUE;
    }
    /* nodes that are connected to an inread should 
       be essential because otherwise next values 
       are used in one simulation step 
    */

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

        if (n -> redirect) 
	    continue;

	nodes_cnt++;

	if (n -> inp || n -> funcoutp || n -> cx != -1 || n -> outp) {
	    n -> essential = TRUE;
	}
	else {
	    n -> essential = FALSE;
	}

	if (proclogic) {
	    if (n -> dsx != -1) {
		index = n -> dsx;
		for (cnt2 = DS[index]; cnt2 > 0; cnt2--) {
		    index++;
		    t = &T[DS[index]];
		    tp = torpar (t, NULL, Cestat);
		    n -> statcap += tp;
		}
	    }

	    if (n -> cx != -1) {
		index = n -> cx;
		for (cnt2 = C[index].c; cnt2 > 0; cnt2--) {
		    index++;
		    if (C[index].sort == Transistor) {
		        t = &T[C[index].c];
			n -> statcap += torpar (t, NULL, Cgstat);
		    }
		}
	    }
	}

	if (!proclogic || (proclogic && n -> statcap <= 0)) {
	    n -> statcap = NODECAP_DEF;
	}

	if (n -> essential)
	    essnodes_cnt++;

	if (n -> inp) {
	    if (n -> forcedinfo -> sigmult < 0) 
		n -> forcedinfo -> sigmult = 1;
	    else
		n -> forcedinfo -> sigmult = 
		n -> forcedinfo -> sigmult / (inttimeaccur * sigtoint);
	    inpnodes_cnt++;
	}

	n -> thisvicin = FALSE;
	n -> flag = FALSE;
	n -> evalflag = FALSE;
	n -> ei = NULL;
    }

    for ( i=0; i<F_cnt; i++ ){
	f = &F[i];
	if ( (fox = f->fox) >=0 ) {
	    cnt = FO[fox++].x;
	    while ( cnt>0 ) {
		funcoutpnodes_cnt++;
		n = &N[ FO[fox].x ];
		PALLOC(fs, 1, FORCEDSIGNAL);
		fs->fox = fox;
		fs->initfstate = X_state;
		fs->next = n->forcedinfo;
		n->forcedinfo = fs;
		cnt--;
		fox++;
	    }
	}
    }
		    
}

inittors () {
    int     cnt;
    TRANSISTOR * t;
    int warningdone;

    res_cnt = 0;

    warningdone = FALSE;

    for (cnt = 0; cnt < T_cnt; cnt++) {
	t = &T[cnt];
	if (t -> type == Res) 
            res_cnt++;
        else {
            if ((t -> length > 0.01 || t -> width > 0.01)
                && !warningdone) {
                slserror (NULL, 0, WARNING, 
                "transistors with dimensions which are more than 1 cm,\n",
                "that doesn't seem to be a very clever design");
                warningdone = TRUE;
            }
        }
	t -> flag = FALSE;
	t -> ei = NULL;
    }
}

float   torpar (trans, mode, par)
        TRANSISTOR * trans;
int     mode;
int     par;
{
    float   val;
    float   enhpar ();
    float   deplpar ();
    float   respar ();

    if (!proclogic && (par == Rstat || par == Rsatu)) {
	switch (trans -> type) {
	    case Nenh: 
		val = NENH_RSTAT_DEF;
		break;
	    case Penh: 
		val = PENH_RSTAT_DEF;
		break;
	    case Depl: 
		val = DEPL_RSTAT_DEF;
		break;
	    case Res: 
		val = RES_RSTAT_DEF;
		break;
	}
    }
    else {
	switch (trans -> type) {
	    case Nenh: 
	    case Penh: 
		val = enhpar (trans, mode, par);
		break;
	    case Depl: 
		val = deplpar (trans, mode, par);
		break;
	    case Res: 
		val = respar (trans, mode, par);
		break;
	}
    }

    return (val);
}

int     initconv (ct)
float   ct;
{
    int     res;

    if (ct < 0) {
	ERROR_EXIT (1);   /* conversion error occurred */
    }
    else
	if (ct < 0.5) {
	    res = -1;
	    while (ct < 0.5) {
		res = res * 10;
		ct = ct * 10;
	    }
	}
	else {
	    res = 1;
	    while (ct > 5) {
		res = res * 10;
		ct = ct / 10;
	    }
	}

    return (res);
}

int     intconv (t, cf)
int     t;
int     cf;
{
    int d_round ();

    if (cf > 0)
	return (t * cf);
    else
	return ( d_round ( (double)t / (double)(-cf) ) );
}

double   doubconv (t, cf)
int     t;
int     cf;
{
    if (cf > 0)
	return (((double) t) * cf);
    else
	return (((double) t) / (-cf));
}

float fl_to_pt (f)   /* converts f to the closest power_ten */
float f;
{
    int exp = 0;

    if (f >= 1) {
	while (f >= 5) {
	    f = f / 10;
	    exp++;
	}
	f = 1;
	while (exp != 0) {
	    f = f * 10;
	    exp--;
	}
    }
    else {
	while (f < 0.5) {
	    f = f * 10;
	    exp--;
	}
	f = 1;
	while (exp != 0) {
	    f = f / 10;
	    exp++;
	}
    }

    return (f);
}

int d_round (d)      /* rounds d to an integer */
double d;
{
    int i = d;   
    /* it is supposed that double is converted to int by truncation */

    if (d - (double)i >= 0.5)
        i++;

    return (i);
}

arr_init (pa, elsize, ispace, incr)
char ** pa;    /* address of pointer to be used as array */
int elsize;    /* the size of an array element */
int ispace;    /* initial number of allocated elements */
float incr;    /* increase factor when free elements are exhausted */
{
    char * p;
    int roundincr;
    char * malloc ();

    if (ispace <= 0) ispace = 0;

    if ((p = malloc ((unsigned)((4 * sizeof (int)) 
                                + (ispace * elsize)))) == NULL) {
        slserror (NULL, 0, ERROR1, "Cannot allocate storage", NULL);
    }

    roundincr = 100 * incr;

    *pa = p + 4 * (int)sizeof (int);
    *(((int *)*pa) - 4 ) = elsize;
    *(((int *)*pa) - 3 ) = ispace;  /* space */
    *(((int *)*pa) - 2 ) = (int)0;  /* used  */
    *(((int *)*pa) - 1 ) = roundincr;   
}
    
int arr_new (pa)  /* returns an index for a new element in the array */
char ** pa;       /* pa is the address of the array pointer */
{
    char * p;
    int elsize;
    int space = *(((int *)*pa) - 3 );
    int used = *(((int *)*pa) - 2 );
    int roundincr;
    char * realloc ();

    if (used == space) {
        roundincr = *(((int *)*pa) - 1 );
        if (space == space * roundincr / 100)
            space++;
        else
            space = space * roundincr / 100;
        *(((int *)*pa) - 3 ) = space;
        elsize = *(((int *)*pa) - 4 );
        p = *pa - 4 * (int)sizeof (int); 
        if ((p = realloc (p,
                 (unsigned)(4 * (int)sizeof (int) + elsize * space))) == NULL) {
            slserror (NULL, 0, ERROR1, "Cannot allocate storage", NULL);
        }
        *pa = p + 4 * (int)sizeof (int);
    }
    return ( (*(((int *)*pa) - 2 ) = ++used) - 1 );
}

int arr_size (p)  /* returns number of elements in array p */
char * p;
{
    return ( *(((int *)p) - 2 ) );
}

arr_reset (p)   /* resets number of elements used */
char * p;
{
    *(((int *)p) - 2 ) = (int)0;
}

cannotAlloc (fn, lineno, nel, sizel)
char * fn;
int lineno;
int nel;
int sizel;
{
    int allocated;

    allocated = 0;
    allocated += sizeof (FUNCVAR) * FV_cnt;
    allocated += sizeof (FUNCDESCR) * FD_cnt;
    allocated += sizeof (char) * ST_cnt;
    allocated += sizeof (NAMETABLE) * NT_cnt;
    allocated += sizeof (MODELTABLE) * MT_cnt;
    allocated += sizeof (CONTEXTTABLE) * CTT_cnt;
    allocated += sizeof (MODELCALLTABLE) * MCT_cnt;
    allocated += sizeof (int) * XT_cnt;
    allocated += sizeof (int) * XX_cnt;
    allocated += sizeof (NODE) * N_cnt;
    allocated += sizeof (int) * DS_cnt;
    allocated += sizeof (CONTROL) * C_cnt;
    allocated += sizeof (INTERCAP) * I_cnt;
    allocated += sizeof (TRANSISTOR) * T_cnt;
    allocated += sizeof (FUNCTION) * F_cnt;
    allocated += sizeof (int) * FI_cnt; 
    allocated += sizeof (int) * FR_cnt; 
    allocated += sizeof (FUNCOUT) * FO_cnt; 
    allocated += sizeof (char) * FS_cnt;

    if (debugmem) {
        deb_mem ();

        fprintf (debug, "Cannot allocate storage at %s:%d\n", fn, lineno);
        fprintf (debug, "should be allocated : %d\n", allocated);
        fprintf (debug, "current request     : %d * %d = %d\n\n", 
                 nel, sizel, nel * sizel);
    }

    fprintf (stderr, "%s: Cannot allocate storage ", argv0);
    fprintf (stderr, "(%d, %d)", allocated, nel * sizel);
    fprintf (stderr, "\n");

    die (1);
}

int_hdl (sig)   /* interrupt handler */
int sig;
{
    switch (sig) {
        case SIGILL :
            fprintf (stderr, "Illegal instruction\n");
            break;
        case SIGFPE :
            fprintf (stderr, "Floating point exception\n");
            break;
#       ifdef SIGBUS
        case SIGBUS :
            fprintf (stderr, "Bus error\n");
            break;
#       endif
        case SIGSEGV :
            fprintf (stderr, "Segmentation violation\n");
            break;
        default :
            break;
    }

    die (sig);
}

dmError (s)
char *s;
{
    dmPerror (s);
    die (1);
}

die (nr)
int nr;
{
    if (dbinitialized) {
	if (dmproject) dmCloseProject (dmproject, QUIT);
	dmQuit ();
    }

    exit (nr);
}

#ifdef ESE
#ifdef FUNCSLS

dummyFuncCalls ()
{
    /* call functions from libfunc.a to force them to be included
    /* in the sls.o file.
    */

    BSFREE ();
    BSRESET ();
    BSROTATE ();
    BSSET ();
    BSTOI ();
    BSUNDEF ();
    BTAND ();
    BTEXNOR ();
    BTEXOR ();
    BTINVERT ();
    BTNAND ();
    BTNOR ();
    BTOR ();
    BWAND ();
    BWEXNOR ();
    BWEXOR ();
    BWINVERT ();
    BWNAND ();
    BWNOR ();
    BWOR ();
    ITOBS ();
    ITOTC ();
    TCTOI ();
    curs_error ();
    func_error ();
    single_curs_step ();
    single_step ();
}

#endif
#endif
