static char *SccsId = "@(#)prNets.c 4.11 (TU-Delft) 07/28/92";
/**********************************************************

Name/Version      : xsls/4.11

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

Author(s)         : A.J. van Genderen
Creation date     : 16-Feb-1987
Modified by       : S. de Graaf
Modification date : 29-Aug-1988


        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-1988, All rights reserved
**********************************************************/
#include "incl.h"

extern int out_indent;
extern int language;
extern int tog_range;
extern int tog_comma;
extern int tog_nodnbr;
extern int tog_use0;
extern int eldo;

#define MAXDECL  80

prNets (ntw, nets)
struct model_info *ntw;
struct net_ref *nets;
{
    int i;
    int j;
    int k;
    int h;
    int kstop;
    int net_cnt;
    int noNet;
    struct net_ref *nref;
    struct net_ref *pref;
    struct net_ref *Fref;
    struct net_ref *Nref;
    struct net_ref *Pref;
    struct term_ref *tref;
    struct cir_net *n;
    struct net_ref *n_nref;
    struct net_ref *help;
    struct net_ref *expNet ();
    struct cir_net *findNet ();
    struct cir_net *actNetFound ();
    struct cir_net *fnet;
    struct cir_net *anet;
    char buf[20];
    char *nname;
    char *sname;
    char *declared[MAXDECL];
    int decl_nr = 0;

    int not;
    char *rightName;
    char *leftName;
    int rightNameNbr;
    int leftNameNbr;
    char *nameToStr ();

    if (language == SIMON)
	return;

    if (language == SLS)
	out_indent = 4;
    net_cnt = 0;

    pref = NULL;
    for (nref = nets; nref != NULL; pref = nref, nref = nref -> next) {

	if (language == SLS) {
	    /*
	    ** If needed, suffle net reference structures.
	    ** Local arrays must first be defined!
	    */
	    n = nref -> n;
	    nname = n -> net_name;
	    Fref = NULL;
	    for (i = 0; i < n -> net_neqv; i++) {
		if (n -> net_eqv[i].net_dim <= 0) continue;
		if (n -> net_eqv[i].inst_name[0] != '\0') continue;
		sname = n -> net_eqv[i].net_name;
		if (strcmp (sname, nname) == 0) continue;
		nname = sname;
		Pref = nref;
		for (Nref = nref -> next; Nref != NULL;
				    Pref = Nref, Nref = Nref -> next) {
		    if (strcmp (sname, Nref -> n -> net_name) == 0) {
			if (!Fref) Fref = Nref;
			if (pref) pref -> next = Nref;
			else nets = Nref;
			Pref -> next = Nref -> next;
			pref = Nref;
			Nref -> next = nref;
			break;
		    }
		}
	    }
	    if (Fref) nref = Fref;
	}

        if (language == EDIF) {
	    oprint (0, "(net ");
	}

	n = nref -> n;

        /* first, if it has a dimension and is not a terminal,
	   it must be declared */

	if (language == SLS && n -> net_dim > 0) {
	    tref = ntw -> terms;
	    while (tref != NULL
		&& strcmp (tref -> t -> term_name, n -> net_name) != 0) {
		tref = tref -> next;
	    }

	    if (tref == NULL) {

		/* also, check if it has not been declared before */

		for (i = 0; i < decl_nr; i++) {
		    if (strcmp (declared[i], n -> net_name) == 0) {
			break;
		    }
		}

                if (i == decl_nr) {

		    /* declare it */

		    oprint (0, "net {(");
		    nmprint (0, n -> net_name, n -> net_dim,
				n -> net_lower, n -> net_upper, 1, 0, 1);
		    oprint (1, ")};");
		    oprint (1, "\n");

		    if (decl_nr < MAXDECL - 1)
			declared[decl_nr++] = n -> net_name;
		}
	    }
	}

        if (tog_use0) {
	    if (test0 (n -> net_name) == 0
		&& testNameNbr (n -> net_name) < 0) { 
		assignNameNbr (n -> net_name, 0);   
			             /* make it known in the name list */
	    }
	}

        noNet = 1;

	if (language == EDIF) {
	    tref = ntw -> terms;
	    while (tref != NULL
		&& strcmp (tref -> t -> term_name, n -> net_name) != 0) {
		tref = tref -> next;
	    }

	    if (tref != NULL) {
		sprintf (buf, "xxxnet%d", net_cnt);
		net_cnt++;
		oprint (0, buf);
		if (noNet) {
		    oprint (0, "(joined ");
		    noNet = 0;
		}

		oprint (0, "(portRef ");
		nmprint (0, n -> net_name,
			 n -> net_dim,
			 n -> net_lower,
			 n -> net_upper,
			 0, tog_nodnbr, 0);
		oprint (0, ")");
	    }
	    else {
	        nmprint (1, n -> net_name, n -> net_dim,
			 n -> net_lower, n -> net_upper, 0, 0, 1);
	    }
	}

        for (i = 0; i < n -> net_neqv; i++) {

	    if (language == EDIF) {

                /* we assume that 'arrays of nets' are not specified */

	        if (n -> net_eqv[i].inst_name[0] == '\0') {
		    tref = ntw -> terms;
		    while (tref != NULL
		     && strcmp (tref -> t -> term_name, n -> net_name) != 0) {
			tref = tref -> next;
		    }
		}

	        if (n -> net_eqv[i].inst_name[0] != '\0' || tref != NULL) {

		    /* it's a portRef ! */

                    if (noNet) {
			oprint (0, "(joined ");
			noNet = 0;
		    }

		    oprint (0, "(portRef ");
		    nmprint (0, n -> net_eqv[i].net_name,
			     n -> net_eqv[i].net_dim,
			     n -> net_eqv[i].net_lower,
			     n -> net_eqv[i].net_upper,
			     0, tog_nodnbr, 0);

	            if (n -> net_eqv[i].inst_name[0] != '\0') {
		        oprint (0, "(instanceRef ");
			nmprint (0, n -> net_eqv[i].inst_name,
				 n -> net_eqv[i].inst_dim,
				 n -> net_eqv[i].inst_lower,
				 n -> net_eqv[i].inst_upper,
				 0, tog_nodnbr, 0);
		        oprint (0, ")");
		    }

		    oprint (0, ")");
		}
	    }

	    if (language != EDIF && n -> net_eqv[i].inst_name[0] == '\0') {

                /* Find the connections (name equivalences) */

		n_nref = expNet (&(n -> net_eqv[i]));

		while (n_nref != NULL) {

		    fnet = findNet (n_nref -> n);
		    /* fnet should be some physical node in 'n' now */

                    not = 0;

                    if (language == SPICE) {

			/* try to remove useless net statements */

			if (tog_nodnbr) {

			    leftName = nameToStr (fnet -> net_name, 
					  fnet -> net_dim, fnet -> net_lower, 
					  fnet -> net_upper);

			    leftNameNbr = testNameNbr (leftName);

			    rightName = nameToStr (n_nref -> n -> net_name,
						 n_nref -> n -> net_dim,
						 n_nref -> n -> net_lower,
						 n_nref -> n -> net_upper);

			    rightNameNbr = testNameNbr (rightName);

			    if (leftNameNbr < 0 && test0 (leftName) < 0
				&& rightNameNbr > 0) {
				assignNameNbr (leftName, rightNameNbr);
				not = 1;
			    }
			    else if (rightNameNbr < 0 && test0 (rightName) < 0
				     && leftNameNbr > 0) {
				    assignNameNbr (rightName, leftNameNbr);
				not = 1;
			    }
			    else if (rightNameNbr < 0 && test0 (rightName) < 0
				   && leftNameNbr < 0 && test0 (leftName) < 0) {
				assignNameNbr (rightName, nameNbr (leftName));
				not = 1;
			    }

			    if (tog_use0) {
				if (test0 (rightName) == 0
				    && testNameNbr (rightName) < 0) { 
				    assignNameNbr (rightName, 0);   
					    /* make it known in the name list */
				}
			    }
			}
			else {

			    /* The following code may eventually also be 
			    /* used for the SLS language to remove 
			    /* superfluous net statements.
			    /* It will change stuff like
			    /*
			    /*    ... (terminal n_a8  .. )
			    /*    
			    /*    net {10, n_a8};
			    /*    {fb3} mod2fb (10, .... );
			    /*
			    /* into
			    /*
			    /*    ... (terminal n_a8  .. )
			    /*    
			    /*    {fb3} mod2fb (n_a8, .... );
			    */
			    
			    int aIsTerm = 0;
			    int bIsTerm = 0;

			    for (tref = ntw -> terms; 
				 tref != NULL; 
			         tref = tref -> next) {

				if (!unequalTermNet (tref -> t, fnet)) {
				    aIsTerm = 1;
				}
				if (!unequalTermNet (tref -> t, n_nref -> n)) {
				    bIsTerm = 1;
				}
			    }

			    if (!bIsTerm
			     && !(tog_use0 
				  && test0 (n_nref -> n -> net_name) == 0))
				not = 1;

			    if (!aIsTerm && bIsTerm
			     && !(tog_use0 && test0 (fnet -> net_name) == 0)) {

				/* see if it is possible to use 'b' as
				   node name; then the net need not to
				   be printed */

                                anet = actNetFound ();

				for (j = anet -> net_dim - 1; j >= 0; j--) {
				    if (anet -> net_upper[j]
					!= anet -> net_lower[j])
					break;
				}

				if (j == -1) {

				    /* PLACE N_NREF->N IN ANET !!! */

				    strcpy (anet -> net_name, 
					    n_nref -> n -> net_name);

				    if (anet -> net_dim 
					< n_nref -> n -> net_dim) {
					PALLOC (anet -> net_lower, 
						n_nref -> n -> net_dim,
						long);
					PALLOC (anet -> net_upper, 
						n_nref -> n -> net_dim,
						long);

					for (h = 0;
					     h < anet -> net_neqv;
					     h++) {
					     PALLOC (
					       anet -> net_eqv[h].ref_lower,
					       n_nref -> n -> net_dim,
					       long);
					     PALLOC (
					       anet -> net_eqv[h].ref_upper,
					       n_nref -> n -> net_dim,
					       long);
					}
				    }
				    anet -> net_dim = n_nref -> n -> net_dim;

				    for (j = n_nref -> n -> net_dim - 1; 
					 j >= 0; j--) {

					anet -> net_lower[j] =
					   n_nref -> n -> net_lower[j];
					anet -> net_upper[j] =
					   n_nref -> n -> net_upper[j];

					for (h = 0;
					     h < anet -> net_neqv;
					     h++) {
					    anet -> net_eqv[h].ref_lower[j] =
					       n_nref -> n -> net_lower[j];
					    anet -> net_eqv[h].ref_upper[j] =
					       n_nref -> n -> net_upper[j];
					}
				    }

				    not = 1;
				}
			    }

			    if (tog_use0) {
				if (test0 (n_nref -> n -> net_name) == 0
				    && testNameNbr (
					 n_nref -> n -> net_name) < 0) { 
				    assignNameNbr (n_nref -> n -> net_name, 
									  0);   
					   /* make it known in the name list */
				}
			    }
			}
		    }

		    if (!not && unequalNet (fnet, n_nref -> n)) {

			net_cnt++;

                        if (language == SPICE && !eldo)
                            kstop = 2;
                        else
                            kstop = 1;

                        /* generate a resistor and a voltage source
                           for a SPICE net since SPICE does not handle 
                           a node with one element connected to it. 
                        */

                        for (k = 1; k <= kstop; k++) {
			    if (language == SLS)
			        oprint (0, "net {");
			    else if (language == SPICE) {
				if (eldo) 
			            sprintf (buf, ".connect ");
                                else if (k == 1)
			            sprintf (buf, "rnet%d ", net_cnt);
                                else
			            sprintf (buf, "vnet%d ", net_cnt);
			        oprint (0, buf);
			    }
    
			    nmprint (0, fnet -> net_name, fnet -> net_dim,
				     fnet -> net_lower, fnet -> net_upper,
				     0, tog_nodnbr, 1);
			    if (tog_comma)
			        oprint (1, ",");
			    oprint (0, " ");
			    nmprint (0, n_nref -> n -> net_name,
				     n_nref -> n -> net_dim,
				     n_nref -> n -> net_lower,
				     n_nref -> n -> net_upper,
				     0, tog_nodnbr, 1);
			    if (language == SLS)
			        oprint (1, "};");
			    else if (language == SPICE && !eldo) {
                                if (k == 1)
				    oprint (1, " 1mohm");
                                else
				    oprint (1, " 0v");
                            }
			    oprint (1, "\n");
                        }
		    }

		    help = n_nref;
		    n_nref = n_nref -> next;
		    FREE (help);
		}
	    }
	}

        if (language == EDIF) {
	    if (!noNet) {
	        oprint (0, ")");
	    }
	    oprint (0, ")");
	}
    }

    if (language == EDIF)
        oprint (0, ")");    /* close contents */


    out_indent = 0;
}

static char bufx[DM_MAXNAME + 132];
static char bufy[DM_MAXNAME + 132];
static char xory = 'x';

char * nameToStr (name, dim, lower, upper)
char *name;
int dim;
long *lower;
long *upper;
{
    int i;
    char *buf;

    if (xory == 'x') {
	buf = bufy;
	xory = 'y';
    }
    else {
	buf = bufx;
	xory = 'x';
    }

    sprintf (buf, "%s", name);
    if (dim > 0) {
	sprintf (buf + strlen (buf), "[");
	for (i = 0; i < dim; i++) {
	    sprintf (buf + strlen (buf), "%d", lower[i]);
	    if (i + 1 < dim)
	        sprintf (buf + strlen (buf), ",");
	}
	sprintf (buf + strlen (buf), "]");
    }

    return (buf);
}

int unequalNet (n1, n2)
struct cir_net *n1;
struct cir_net *n2;
{
    int i;

    if (tog_use0) {
	if (nameNbr (n1 -> net_name) == 0
	&& nameNbr (n2 -> net_name) == 0)
	    return (0);
    }

    if (strcmp (n1 -> net_name, n2 -> net_name) != 0)
	return (1);

    if (n1 -> net_dim != n2 -> net_dim)
	return (1);

    for (i = 0; i < n1 -> net_dim; i++) {
	if (n1 -> net_lower[i] != n2 -> net_lower[i]
	 || n1 -> net_upper[i] != n2 -> net_upper[i])
	    return (1);
    }

    return (0);
}

int unequalTermNet (t, n)
struct cir_term *t;
struct cir_net *n;
{
    if (strcmp (t -> term_name, n -> net_name) != 0)
	return (1);

    if (t -> term_dim != n -> net_dim)
	return (1);

    return (0);
}
