static char *SccsId = "@(#)getnet.c 4.6 (TU-Delft) 04/20/93";
/**********************************************************

Name/Version      : sls_exp/4.6

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

Author(s)         : 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"

char fn_net[80];
int item;
int fc_getnet = TRUE;   /* first call to getnet must still be done */

PATH_SPEC path_sp[2];

getnet (m)   /* get nets (node connections) of model m */
DM_CELL * m;
{
    DM_STREAM * dsp;
    int i;
    int new;
    int q;
    int k;
    int fnv;
    int nx;
    int ntx;
    int ntx2;
    int nbr;
    int xx;
    PATH_SPEC * path;
    NODE_REF_LIST * ref_list;
    NODE_REF_LIST * eqv_ref_list;
    char buf[128];

    if (fc_getnet) {
        path_sp[0].next = NULL;
        path_sp[0].also = NULL;
        path_sp[1].next = NULL;
        path_sp[1].also = NULL;
	fc_getnet = FALSE;
    }

    sprintf (fn_net, "circuit/%s/net", m -> cell);

    dsp = dmOpenStream (m, "net", "r");

    /* first the net records are parsed to allocate the nodes in the
       current level of the hierarchy (net nodes without instance name).
       only these nodes are assumed to be the 'head' net.
    */

    item = 0;
    while (dmGetDesignData (dsp, CIR_NET) > 0) {
	item++;

        resetfindnodes ();

        strcpy (path_sp[0].name, cnet.net_name);
        path_sp[0].xarray[0][0] = cnet.net_dim;
        for (k = 0; k < cnet.net_dim; k++) {
            path_sp[0].xarray[k+1][0] = cnet.net_lower[k];
            path_sp[0].xarray[k+1][1] = cnet.net_upper[k];
        }
        path_sp[0].next = NULL;
        path = &(path_sp[0]);

        fnv = findnodes (path, NULL, TRUE, &ref_list, FALSE);

        if (fnv == NAMENEG) {      /* node doesn't exist yet */

            ntx = newname (path -> name);
	    NT[ntx].sort = Node;
	    nbr = 1;

	    if (path -> xarray[0][0] > 0) {
		new = NT[ntx].xtx = newxt ();
		XT[ new ] = path -> xarray[0][0];
		for (i = 1; i <= path -> xarray[0][0]; i++) {
		    new = newxt ();
		    XT[ new ] = path -> xarray[i][0];
		    new = newxt ();
		    XT[ new ] = path -> xarray[i][1];
		    nbr = nbr * 
		          (path -> xarray[i][1] - path -> xarray[i][0] + 1);
		}
	    }

	    if (path -> xarray[0][0] <= 0) {
	        nx = newnode ();
	        NT[ ntx ].x = nx;
	        N[ nx ].ntx = ntx;
	    }
	    else {
	        xx = newxx (nbr) - nbr + 1;
	        NT[ ntx ].x = xx;
	        while (nbr-- > 0) {
		    nx = newnode ();
		    XX[ xx++ ] = nx;
	            N[ nx ].ntx = ntx;
	        }
	    }
        }
	else if (fnv == REFIMIS || fnv == REFINEG || fnv == REFIERR) {
	    dberror (fn_net, item, "inconsistent index for net", cnet.net_name);
	}
        else if (fnv < 0) {
	    dberror (fn_net, item, "error for net", cnet.net_name);
        }

        free_cnet ();
    }

    dmSeek (dsp, (long)0, 0);  /* rewind */

    /* now the actual net coalescing will be done */

    item = 0;
    while (dmGetDesignData (dsp, CIR_NET) > 0) {
	item++;

        for (q = 0; q < cnet.net_neqv; q++) {

            resetfindnodes ();

            strcpy (path_sp[0].name, cnet.net_name);
            path_sp[0].xarray[0][0] = cnet.net_dim;
            for (k = 0; k < cnet.net_dim; k++) {
                path_sp[0].xarray[k+1][0] = cnet.net_eqv[q].ref_lower[k];
                path_sp[0].xarray[k+1][1] = cnet.net_eqv[q].ref_upper[k];
            }
            path_sp[0].next = NULL;
            path = &(path_sp[0]);  

            fnv = findnodes (path, NULL, TRUE, &ref_list, FALSE);

            if (fnv < 0)
	        dberror (fn_net, item, "error for net", cnet.net_name);

            strcpy (path_sp[0].name, cnet.net_eqv[q].inst_name);
            path_sp[0].xarray[0][0] = cnet.net_eqv[q].inst_dim;
            for (k = 0; k < cnet.net_eqv[q].inst_dim; k++) {
                path_sp[0].xarray[k+1][0] = cnet.net_eqv[q].inst_lower[k];
                path_sp[0].xarray[k+1][1] = cnet.net_eqv[q].inst_upper[k];
            }
            strcpy (path_sp[1].name, cnet.net_eqv[q].net_name);
            path_sp[1].xarray[0][0] = cnet.net_eqv[q].net_dim;
            for (k = 0; k < cnet.net_eqv[q].net_dim; k++) {
                path_sp[1].xarray[k+1][0] = cnet.net_eqv[q].net_lower[k];
                path_sp[1].xarray[k+1][1] = cnet.net_eqv[q].net_upper[k];
            }
            if (cnet.net_eqv[q].inst_name[0] == '\0') {
                path = &(path_sp[1]);
            }
            else {
                path = &(path_sp[0]);
                path_sp[0].next = &(path_sp[1]);
            }

            fnv = findnodes (path, NULL, TRUE, &eqv_ref_list, FALSE);

            if (fnv == NAMENEG 
                && path -> next == NULL 
                && path -> xarray[0][0] == 0)  {
                           /* nodes that are not a terminal of a modelcall   */
                           /* and that are also not an array, can be defined */
                           /* by being used as an equivalence */

                ntx = newname (path -> name);
	        NT[ntx].sort = Node;

	        nx = newnode ();
	        NT[ ntx ].x = nx;
	        N[ nx ].ntx = ntx;
                fnv = findnodes (path, NULL, TRUE, &eqv_ref_list, FALSE);
	    }

	    if (fnv == NAMENEG) {
		if (path -> next != NULL) {
		    ntx2 = findhashedname (cnet.net_eqv[q].inst_name);
		    if (ntx2 >= 0 && NT[ntx2].sort == Modelcall)
			sprintf (buf, 
		"reference to unknown terminal %s\n   of cell %s (instance %s)",
			     cnet.net_eqv[q].net_name,
			     MT[ MCT[ NT[ntx2].x ].mtx ].name,
			     cnet.net_eqv[q].inst_name);
		    else
			sprintf (buf, 
			     "reference to unknown terminal %s of instance %s",
			     cnet.net_eqv[q].net_name,
			     cnet.net_eqv[q].inst_name);
		}
		else {
		    sprintf (buf, 
			     "reference to unknown terminal %s",
			     cnet.net_eqv[q].net_name);
		}
	        dberror (fn_net, item, buf, NULL);
	    }
	    else if (fnv == REFIMIS || fnv == REFINEG || fnv == REFIERR) {
		if (path -> next != NULL) {
		    ntx2 = findhashedname (cnet.net_eqv[q].inst_name);
		    if (ntx2 >= 0 && NT[ntx2].sort == Modelcall)
			sprintf (buf, 
	"inconsistent index usage for terminal %s\n   of cell %s (instance %s)",
			     cnet.net_eqv[q].net_name,
			     MT[ MCT[ NT[ntx2].x ].mtx ].name,
			     cnet.net_eqv[q].inst_name);
		    else
			sprintf (buf, 
		     "inconsistent index usage for terminal %s of instance %s",
			     cnet.net_eqv[q].net_name,
			     cnet.net_eqv[q].inst_name);
		}
		else {
		    sprintf (buf, 
		     "inconsistent index usage for terminal %s",
			     cnet.net_eqv[q].net_name);
		}
	        dberror (fn_net, item, buf, NULL);
	    }
	    else if (fnv == NOTRELEVANT) {
		/* do nothing with it */
	    }
            else if (fnv < 0) {
		if (path -> next != NULL) {
		    sprintf (buf, 
			     "error for terminal %s of instance %s",
			     cnet.net_eqv[q].net_name,
			     cnet.net_eqv[q].inst_name);
		}
		else {
		    sprintf (buf, 
			     "error for terminal %s",
			     cnet.net_eqv[q].net_name);
		}
	        dberror (fn_net, item, buf, NULL);
	    }

	    if (fnv >= 0) {
		while (ref_list != NULL) {
		    if (eqv_ref_list == NULL)
			dberror (fn_net, item, 
				 "too less nodes in equivalence", NULL);
		    if (eqv_ref_list -> nx < 0) {
			*(eqv_ref_list -> xptr) = ref_list -> nx;
		    }
		    else
			join_node (ref_list -> nx, eqv_ref_list -> nx);
		    ref_list = ref_list -> next;
		    eqv_ref_list = eqv_ref_list -> next;
		}
		if (eqv_ref_list != NULL)
		    dberror (fn_net, item, 
			     "too many nodes in equivalence", NULL);
	    }
        }

        free_cnet ();
    }

    dmCloseStream (dsp, COMPLETE);

}

free_cnet ()
{
    int i;

    if (cnet.net_attribute != NULL)
        CFREE (cnet.net_attribute);
    if (cnet.net_lower != NULL)
        CFREE (cnet.net_lower);
    if (cnet.net_upper != NULL)
        CFREE (cnet.net_upper);
    if (cnet.inst_lower != NULL)
        CFREE (cnet.inst_lower);
    if (cnet.inst_upper != NULL)
        CFREE (cnet.inst_upper);
    if (cnet.ref_lower != NULL)
        CFREE (cnet.ref_lower);
    if (cnet.ref_upper != NULL)
        CFREE (cnet.ref_upper);
    for (i = 0; i < cnet.net_neqv; i++) {
        if (cnet.net_eqv[i].net_lower != NULL)
            CFREE (cnet.net_eqv[i].net_lower);
        if (cnet.net_eqv[i].net_upper != NULL)
            CFREE (cnet.net_eqv[i].net_upper);
        if (cnet.net_eqv[i].inst_lower != NULL)
            CFREE (cnet.net_eqv[i].inst_lower);
        if (cnet.net_eqv[i].inst_upper != NULL)
            CFREE (cnet.net_eqv[i].inst_upper);
        if (cnet.net_eqv[i].ref_lower != NULL)
            CFREE (cnet.net_eqv[i].ref_lower);
        if (cnet.net_eqv[i].ref_upper != NULL)
            CFREE (cnet.net_eqv[i].ref_upper);
    }
    if (cnet.net_eqv != NULL)
        CFREE (cnet.net_eqv);
}
            
join_node (nxh, nxj)   /* joins node nxj to node nxh */
int nxh;
int nxj;
{
    NODE * nh; 
    NODE * nj;
    int j;
    int nbr;
    int index;

    while (N[nxh].redirect)
	nxh = N[nxh].cx;

    while (N[nxj].redirect)
	nxj = N[nxj].cx;

    if (nxh == nxj) 
	return;

    nh = &N[nxh];
    nj = &N[nxj];

    nh -> statcap += nj -> statcap;

    if (nh -> linked) {
	if (nh -> dsx >= 0) {
	    j = nh -> dsx;
	    nh -> dsx = nbr = DS[j++];
	    while (nbr-- > 0) {
	        DS[j++] = 0;
	    }
	}
	else
	    nh -> dsx = 0;
	
	if (nh -> cx >= 0) {
	    j = nh -> cx;
	    nh -> cx = nbr = C[j++].c;
	    while (nbr-- > 0) {
	        C[j++].c = 0;
	    }
	}
	else
	    nh -> cx = 0;

	nh -> linked = FALSE;
    }

    /* the number of ds or c connections of nj is added to nh.      */
    /* these connections are originating from nodes already linked, */
    /* but when nj is not linked it can have them because of a      */
    /* possible previous joining */

    if (! nj -> linked) {
        nh -> dsx += nj -> dsx;
        nh -> cx += nj -> cx;
	nj -> dsx = 0;
	nj -> cx = 0;
    }
    else {
	if (nj -> dsx >= 0) {
	    nh -> dsx += DS[ nj -> dsx];
	    index = nj -> dsx;
	    nbr = DS[ index ]; 
	    DS[ index ] = 0;
	    while (nbr-- > 0) 
		DS[ ++index ] = 0;
	}
	if (nj -> cx >= 0) {
	    nh -> cx += C[ nj -> cx].c;
	    index = nj -> cx;
	    nbr = C[ index ].c;
	    C[ index ].c = 0;
	    while (nbr-- > 0) 
		C[ ++index ].c = 0;
        }
    }

    nj -> redirect = TRUE;
    nj -> cx = nxh;
}
