static char *SccsId = "@(#)dissip.c 4.1 (TU-Delft) 05/24/90";
/**********************************************************

Name/Version      : sls/4.1

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

Author(s)         : A.J. van Genderen
Creation date     : 29-Oct-1987
Modified by       : 
Modification date :


        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) 1987 , All rights reserved
**********************************************************/
#include "extern.h"

STRING_REF * disnames = NULL;
STRING_REF * end_disnames;

double ** disvalues = NULL;
int nbr_disvalues;
int nbr_dissteps;

NODE ** nsources;

int interval;

dis_addname (path)      /* stores node name */
PATH_SPEC * path;
{
    STRING_REF * str_ref;
    STRING_REF * names_from_path ();

    str_ref = names_from_path (0, path);

    if (disnames) {
	end_disnames -> next = str_ref;
    }
    else {
	disnames = end_disnames = str_ref;
    }

    while (end_disnames -> next != NULL) {
        end_disnames = end_disnames -> next;
    }
}

init_dis ()
{
    NODE_REF_LIST * nrl;
    int i;

    if (simperiod <= 0) {
	slserror (NULL, -1, ERROR1, 
	"no appropriate simperiod specified for dissipation statistics",
	NULL);
    }

    if (! proclogic) {
	slserror (NULL, -1, WARNING,
	"dissipation statistics not valuable for simulation at level 1",
	NULL);
    }

    nbr_disvalues = 0;
    nrl = disl_begin;
    while (nrl != NULL) {
	nrl = nrl -> next;
	nbr_disvalues++;
    }

    if (disperiod > 0) {
	nbr_dissteps = simperiod / disperiod;
	interval = sigtoint * disperiod * nbr_dissteps;
    }
    else {
	nbr_dissteps = 0;
	interval = sigtoint * simperiod;
    }

    PALLOC (disvalues, nbr_disvalues + 1, double *);
    for (i = 0; i < nbr_disvalues + 1; i++) {
	PALLOC (disvalues[i], nbr_dissteps + 1, double);
    }

    PPALLOC (nsources, N_cnt, NODE)
}

vicin_nsource_dis ()    /* finds source node(s) for vicinity */
{
    int cnt;
    NODE ** nn;
    NODE * n;
    NODE * source_H;
    NODE * source_L;

    source_H = NULL;
    source_L = NULL;

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

	if (n -> type == Forced) {
	    if (source_H == NULL && LSTATE (n) == H_state) {
		source_H = n;
	    }
	    else if (source_L == NULL && LSTATE (n) == L_state) {
		source_L = n;
	    }
	}
    }

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

        nsources [n - N] = NULL;

	if (n -> svmin + n -> svmax > n -> ivmin + n -> ivmax) {
	    if (source_H && source_H -> dissip)
		nsources [n - N] = source_H;
	}
	else if (n -> svmin + n -> svmax < n -> ivmin + n -> ivmax) {
	    if (source_L && source_L -> dissip)
		nsources [n - N] = source_L;
	}
    }
}

vicin_dis ()    /* computes for each node in the vicinity the */
{               /* dissipation due to the last voltage change */
    NODE ** nn;
    NODE * n;
    int cnt;

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

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

	dis_node (n);
    }
}

forced_dis (n, old, new)   /* computes dissipation for a forced */
NODE * n;                  /* node that changes logic state     */
int old;
int new;
{
    float vstep_real;
    int dn;

    if (vHtmp > 0)
	vstep_real = vHtmp;
    else
	vstep_real = 5;

    if (old == X_state || new == X_state)
	vstep_real = vstep_real / 2;

    if (tcurr < interval) {

	disvalues [nbr_disvalues][nbr_dissteps] 
	+= 0.5 * n -> statcap * vstep_real * vstep_real;

	if (disperiod > 0) {
	    disvalues [nbr_disvalues][(tcurr * nbr_dissteps) / interval] 
	    += 0.5 * n -> statcap * vstep_real * vstep_real;
	}

	if (n -> dissip) {
	    dn = disnbr (n);
	    disvalues [ dn ][nbr_dissteps]
	    += 0.5 * n -> statcap * vstep_real * vstep_real;

	    if (disperiod > 0) {
		disvalues [ dn ][(tcurr * nbr_dissteps) / interval] 
		+= 0.5 * n -> statcap * vstep_real * vstep_real;
	    }
	}
    }
}

dis_end ()     /* ends dissipation book-keeping and writes file */
{
    int i;
    int j;
    int k;
    NODE_REF_LIST * nrl;
    NODE_REF_LIST * nrl_pg;
    STRING_REF * srl;
    STRING_REF * srl_pg;
    char str[20];
    int cnt;
    FILE * fp;
    char fn[16];
    double val;
    int dn;

    sprintf (fn, "%.10s.dis", netwname);
    OPENW (fp, fn);

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

	if (N[cnt].type != Forced)
	    dis_node (N + cnt);
    }

    fprintf (fp, "\nDynamic Dissipation [in Watts]\n");

    fprintf (fp, "\n");

    if (disperiod > 0)
	val = disperiod * nbr_dissteps * sigtimeunit;
    else
	val = simperiod * sigtimeunit;
    fprintf (fp, "--- time interval [0, %e)\n", val);

    fprintf (fp, "\n");

    j = 0;
    nrl_pg = disl_begin;
    srl_pg = disnames;
    while (j < nbr_disvalues + 1) {

        if (disperiod > 0)
	    fprintf (fp, "time [in sec]  ");
	else
	    fprintf (fp, "               ");

	i = 0;
        nrl = nrl_pg;
	srl = srl_pg;
	while (i + j < nbr_disvalues + 1 && i < 8) {
	    if (nrl == NULL)
		fprintf (fp, "<total netw.> ");
	    else {
		while (nrl -> nx < 0) {
		    nrl = nrl -> next;
		}
		fprintf (fp, "%-13.13s ", srl -> str);
		nrl = nrl -> next;
		srl = srl -> next;
	    }
	    i++;
	}
	fprintf (fp, "\n");

	for (k = 0; k < nbr_dissteps + 1; k++) {

            if (k == nbr_dissteps)
		fprintf (fp, "average        ");
	    else {
		sprintf (str, "%e", k * disperiod * sigtimeunit);
		fprintf (fp, "%-13.13s  ", str);
	    }

	    i = 0;
	    nrl = nrl_pg;
	    while (i + j < nbr_disvalues + 1 && i < 8) {
		if (nrl == NULL)
		    val = disvalues[nbr_disvalues][k];
		else {
		    while (nrl -> nx < 0) {
			nrl = nrl -> next;
		    }
		    dn = disnbr (N + nrl -> nx);
		    val = disvalues[ dn ][k];
		    nrl = nrl -> next;
		}
		if (k == nbr_dissteps)
		    val = val / (interval * inttimeaccur);
		else
		    val = val / (disperiod * sigtoint * inttimeaccur);
		sprintf (str, "%.5e", val);
		fprintf (fp, "%-13.13s ", str);
		i++;
	    }
	    fprintf (fp, "\n");
	}
	fprintf (fp, "\n");
	j += i;
	nrl_pg = nrl;
	srl_pg = srl;
    }

    CLOSE (fp);
}

dis_node (n)  /* computes dissipation for one node and */
NODE * n;     /* finds the source node for that node   */
{
    int vstep;
    float minpart;
    float maxpart;
    float vstep_real;
    double consumed;
    int tbegin;
    int tend;
    int tmiddle;
    int dn;

    if (tcurr >= n -> tstabmin)
	minpart = 1;
    else
	minpart = (tcurr - n -> tstabmin + n -> Ttmin) / n -> Ttmin;

    if (tcurr >= n -> tstabmax)
	maxpart = 1;
    else
	maxpart = (tcurr - n -> tstabmax + n -> Ttmax) / n -> Ttmax;

    vstep = 
	    ( (((int)(n -> svmin) - (int)(n -> ivmin)) * minpart)
	      +
	      (((int)(n -> svmax) - (int)(n -> ivmax)) * maxpart)
	    ) / 2;

    tbegin = (n -> tstabmin - n -> Ttmin
	      + n -> tstabmax - n -> Ttmax) / 2;
    if (tbegin < 0) tbegin = 0;

    tend = (n -> tstabmin + n -> tstabmin) / 2;
    if (tend < 0) tend = 0;
    if (tend > tcurr) tend = tcurr;

    tmiddle = (tend + tbegin) / 2;

    if (vHtmp > 0)
	vstep_real = vHtmp * vstep / VOLTMAX_INT; 
    else
	vstep_real = 5 * vstep / VOLTMAX_INT; 

    consumed = 0.5 * n -> statcap * vstep_real * vstep_real;

    if (tmiddle < interval) {
	disvalues [nbr_disvalues][nbr_dissteps] += consumed;

	if (disperiod > 0) {
	    disvalues [nbr_disvalues][(tmiddle * nbr_dissteps) / interval] 
	    += consumed;
	}

	if (nsources [n - N] != NULL) {
	    dn = disnbr (nsources [n - N]);
	    disvalues [dn][nbr_dissteps] += consumed;

	    if (disperiod > 0) {
		disvalues [dn]
			  [(tmiddle * nbr_dissteps) / interval] += consumed;
	    }
	}
    }
}

int disnbr (n)    /* returns the node list number */
NODE * n;
{
    NODE_REF_LIST * nrl;
    int cnt;

    nrl = disl_begin;
    cnt = 0;
    while (1) {
	if (nrl -> nx == n - N)
	    break;
	nrl = nrl -> next;
	cnt++;
    }

    return (cnt);
}
