static char *SccsId = "@(#)out.c 4.21 (TU-Delft) 06/01/93";
/**********************************************************

Name/Version      : space/4.21

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

Author(s)         : A.J. van Genderen
		  : N.P. van der Meijs
Creation date     : 15-Mar-1988
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) 1988. All rights reserved.
**********************************************************/
#include <stdio.h>
#include <dmincl.h>
#include <math.h>
#include "include/config.h"
#include "include/type.h"
#include "aux/aux.h"
#include "aux/plot.h"
#include "lump/define.h"
#include "lump/extern.h"

extern PLOT_KEY * cirPK;

DM_STREAM *dmsNet;
DM_STREAM *dmsMc;
DM_STREAM *dmsCon = NULL;
DM_STREAM *dmsTermpos = NULL;
DM_STREAM *dmsDevgeo = NULL;
DM_STREAM *dmsNetTerm;
DM_STREAM *dmsNetHier;

int res_cnt;
int cap_cnt;
int gndCap_cnt;
int node_cnt;
int tor_cnt;
int group_cnt;

int act_dev_cnt;

static DM_CELL* saveCellCirKey;
static DM_CELL* saveCellLayKey;
static int geoScale;

static long lastdmscon;


#ifdef DEBUG_NODES
#define MAX_NODE_ARRAY 500

int check_cnt;
int leftBehind;
int hasPrinted;

FILE *fp_dbn;
#endif

initOut (cellCirKey, cellLayKey, scale)
DM_CELL * cellCirKey;
DM_CELL * cellLayKey;
int scale;
{
    if ((!prePass1 && !prePass2) || optOnlyPrePass) {
	dmsNet = dmOpenStream (cellCirKey, "net", "w");
	dmsMc = dmOpenStream (cellCirKey, "mc", "a");
	if (optGenNetTerm)
	    dmsNetTerm = dmOpenStream (cellLayKey, "netterm", "w");
	if (optReadNetTerm)
	    dmsNetHier = dmOpenStream (cellCirKey, "nethier", "w");
    }


    res_cnt = 0;
    cap_cnt = 0;
    gndCap_cnt = 0;
    node_cnt = 0;
    tor_cnt = 0;
    group_cnt = 0;

    act_dev_cnt = 0;

    saveCellCirKey = cellCirKey;
    saveCellLayKey = cellLayKey;
    geoScale = scale;

#ifdef DEBUG_NODES
    debug_nodes_init ();
#endif
}

endOut ()
{
    if ((!prePass1 && !prePass2) || optOnlyPrePass) {
	dmCloseStream (dmsNet, COMPLETE);
	dmCloseStream (dmsMc, COMPLETE);
	if (optGenNetTerm)
	    dmCloseStream (dmsNetTerm, COMPLETE);
	if (optReadNetTerm)
	    dmCloseStream (dmsNetHier, COMPLETE);
    }

}

outGroup (qn, n_cnt)
node_t **qn;
int n_cnt;
{
    int i;
    netEquiv_t * ne;
    netEquiv_t * ne2;

    group_t * grp = Grp (qn[0]);

#ifdef DEBUG_NODES
    fprintf (fp_dbn, "\nOutputing group %x\n", grp);
#endif



    for (i = 0; i < n_cnt; i++) {
	ASSERT (Grp (qn[i]) == grp);
	outNode (qn[i]);
    }


    groupDel (grp);
    outGrp++;
}

outNode (n)
node_t *n;
{
    int connection;
    int cancelWrite;
    int addSource;
    int number;
    int k;
    char buf[80];
    char net_name[DM_MAXNAME + 1];
    int net_neqv;
    int new_net_neqv;
    int rnt_net_neqv;
    int new_rnt_net_neqv;
    int connectionSave;
    int cancelWriteSave;
    element_t * con;
    element_t * cap;
    element_t * next;
    terminal_t * tm;
    terminal_t * tmHelp;
    netEquiv_t * ne;
    netEquiv_t * ne2;
    netEquiv_t * next_ne;
    group_t * grp;
    struct cir_net *eqv;
    struct cir_net *neweqv ();

#ifdef CIR_NET_ATOM_AVAILABLE

    /* First we are going to count how many subnets (equivalences)
       we have, and if we should really output the net.
       The following code must be an exact reflection of what is
       done later on when we write the subnets !!!!!!!!
    */

    connection = 0;
    cancelWrite = 0;

    net_neqv = 0;
    rnt_net_neqv = 0;

    if (n -> names) {
	connection = 1;

        if (n -> names -> instName == NULL
	    && n -> names -> termX < 0 && n -> names -> termY < 0) {
	    tm = n -> names -> next;
	}
	else {
	    tm = n -> names;
	}

        if (optReadNetTerm) {

            tmHelp = tm;
	    while (tm != NULL) {
		if (tm -> instName != NULL) {
		    rnt_net_neqv++;
		}
		tm = tm -> next;
	    }

	    tm = tmHelp;
	}

	while (tm != NULL) {

	    if (!optReadNetTerm || tm -> instName == NULL) {
		net_neqv++;
	    }
	    tm = tm -> next;
	}
    }


    ne = n -> netEq;
    while (ne != NULL) {

	next_ne = ne -> next;

	net_neqv++;

	addSource = 0;

	switch (ne -> instType) {
	    case TOR :
		if (optDsConJoin 
		    && (ne -> term == 'd' 
			|| ne -> term == 's')) {

		    if (connection || n -> netEq -> next) {

			if (ne -> term == 'd') {
			    addSource = 1;
			    grp = Grp (ne -> net);
			    ne2 = ne -> nextDsRing;
			    while (ne2 != ne) {

				if (Grp (ne2 -> net) != grp) {
				    addSource = 0;
				}
			    ne2 = ne2 -> nextDsRing;
			    }
			}
		    }
		    else {  
			if (ne -> term == 'd') {
			    if (ne -> nextDsRing != ne) {
				if (ne -> nextDsRing -> nextDsRing != ne)
				    cancelWrite = 1;
			    }

			    if (!cancelWrite) {
				addSource = 1;
				grp = Grp (ne -> net);
				ne2 = ne -> nextDsRing;
				while (ne2 != ne) {

				    if (Grp (ne2 -> net) != grp) {
					addSource = 0;
				    }
				    ne2 = ne2 -> nextDsRing;
				}
			    }
			}
			else if (ne -> term == 's') {
			    if (ne -> nextDsRing != ne) {
				cancelWrite = 1;
			    }
			}
		    }
		}
		break;
	    default:
		break;
	}

	if (addSource) {
	    net_neqv++;
	}

	connection = 1;

	ne = next_ne;
    }

    if (!cancelWrite && n -> gndCap != 0 && optCap) {
	net_neqv++;
    }

    if ((prePass1 || prePass2) && !optOnlyPrePass) {
	cancelWrite = 1;
    }

    connectionSave = connection;
    cancelWriteSave = cancelWrite;

    /* Now, we do the real writing and memory de-allocation */

    new_net_neqv = 0;
    new_rnt_net_neqv = 0;

#endif

    connection = 0;
    cancelWrite = 0;

    cnet.net_dim = 0;
    strcpy (cnet.inst_name, "");
    cnet.inst_dim = 0;

	cnet.net_attribute = 0;


    cnet.net_neqv = 0;

    if (n -> names == NULL) {
	node_cnt++;
	sprintf (cnet.net_name, "%d", node_cnt + maxTermNumber);
	sprintf (net_name, cnet.net_name);
#ifdef CIR_NET_ATOM_AVAILABLE
        if (!cancelWriteSave) {
	    cnet.net_neqv = net_neqv;
	    dmPutDesignData (dmsNet, CIR_NET_ATOM);
	}
#endif
    }
    else {
	connection = 1;

        if (n -> names -> instName == NULL
	    && n -> names -> termX < 0 && n -> names -> termY < 0) {
	    strcpy (cnet.net_name, n -> names -> termName);
	    tm = n -> names -> next;
	}
	else {
	    node_cnt++;
	    sprintf (cnet.net_name, "%d", node_cnt + maxTermNumber);
	    tm = n -> names;
	}

        if (optReadNetTerm) {
	    /* first write the net, together with the subnets that
	       are sub-terminals, into the stream 'nethier'
	    */

#ifdef CIR_NET_ATOM_AVAILABLE
	    cnet.net_neqv = rnt_net_neqv;
	    dmPutDesignData (dmsNetHier, CIR_NET_ATOM);
#endif
            tmHelp = tm;
	    while (tm != NULL) {
		if (tm -> instName != NULL) {
		    eqv = neweqv ();
		    fillEqvWithTerm (eqv, tm);
#ifdef CIR_NET_ATOM_AVAILABLE
		    dmPutDesignData (dmsNetHier, CIR_NET_ATOM);
		    new_rnt_net_neqv++;
#endif
		}
		tm = tm -> next;
	    }
#ifndef CIR_NET_ATOM_AVAILABLE
	    dmPutDesignData (dmsNetHier, CIR_NET);
#endif
	    tm = tmHelp;
	    cnet.net_neqv = 0;
	}

	sprintf (net_name, cnet.net_name);
#ifdef CIR_NET_ATOM_AVAILABLE
        if (!cancelWriteSave) {
	    cnet.net_neqv = net_neqv;
	    dmPutDesignData (dmsNet, CIR_NET_ATOM);
	}
#endif

	while (tm != NULL) {

	    if (!optReadNetTerm || tm -> instName == NULL) {
		eqv = neweqv ();
		fillEqvWithTerm (eqv, tm);
#ifdef CIR_NET_ATOM_AVAILABLE
		if (!cancelWriteSave) {
		    dmPutDesignData (dmsNet, CIR_NET_ATOM);
		}
		new_net_neqv++;
#endif
	    }
	    tm = tm -> next;
	}
    }


    ne = n -> netEq;
    while (ne != NULL) {

        next_ne = ne -> next;

	eqv = neweqv ();

        addSource = 0;

        switch (ne -> instType) {
	    case CAP :
		sprintf (eqv -> inst_name, "_C%d", ne -> number);
		break;
	    case RES :
		sprintf (eqv -> inst_name, "_R%d", ne -> number);
		break;
	    case TOR :
		sprintf (eqv -> inst_name, "_T%d", ne -> number);

                if (optDsConJoin 
		    && (ne -> term == 'd' 
		        || ne -> term == 's')) {

		    if (connection || n -> netEq -> next) {

			/* this terminal is connected to another terminal */

			if (ne -> term == 'd') {
			    addSource = 1;
			    grp = Grp (ne -> net);
			    ne2 = ne -> nextDsRing;
			    while (ne2 != ne) {

				if (Grp (ne2 -> net) != grp) {
				    ne2 -> term = 's';
				    addSource = 0;
				}
				ne2 = ne2 -> nextDsRing;
			    }
			}
		    }
		    else {  
			/* this terminal is unconnected; do not write
			   the terminal if there are two other d/s 
			   terminals for this transistor */

			if (ne -> term == 'd') {
			    if (ne -> nextDsRing != ne) {
				if (ne -> nextDsRing -> nextDsRing != ne)
			            cancelWrite = 1;
			    }

			    if (!cancelWrite) {
				addSource = 1;
				grp = Grp (ne -> net);
				ne2 = ne -> nextDsRing;
				while (ne2 != ne) {

				    if (Grp (ne2 -> net) != grp) {
					ne2 -> term = 's';
					addSource = 0;
				    }
				    ne2 = ne2 -> nextDsRing;
				}
			    }
			}
			else if (ne -> term == 's') {
			    if (ne -> nextDsRing != ne) {
			        cancelWrite = 1;
			    }
			}
		    }
		    if (ne -> nextDsRing != ne) {

			/* remove from dsRing ! */

			ne2 = ne -> nextDsRing;
			while (ne2 -> nextDsRing != ne) {
			    ne2 = ne2 -> nextDsRing;
			}
			ne2 -> nextDsRing = ne -> nextDsRing;
		    }
		}

		break;
	    default:
#ifndef lint
		ASSERT (0);
#endif /* lint */
		break;
	}
	eqv -> inst_dim = 0;

	eqv -> net_name[0] = ne -> term;
	eqv -> net_name[1] = '\0';
	eqv -> net_dim = 0;

#ifdef CIR_NET_ATOM_AVAILABLE
	if (!cancelWriteSave) {
	    dmPutDesignData (dmsNet, CIR_NET_ATOM);
	}
	new_net_neqv++;
#endif
        if (addSource) {
	    eqv = neweqv ();
	    sprintf (eqv -> inst_name, "_T%d", ne -> number);
	    eqv -> inst_dim = 0;
	    eqv -> net_name[0] = 's';
	    eqv -> net_name[1] = '\0';
	    eqv -> net_dim = 0;
#ifdef CIR_NET_ATOM_AVAILABLE
	    if (!cancelWriteSave) {
		dmPutDesignData (dmsNet, CIR_NET_ATOM);
	    }
	    new_net_neqv++;
#endif
	}

        DISPOSE (ne);
	currNeqv--;

	connection = 1;

	ne = next_ne;
    }

    if (!cancelWrite && n -> gndCap != 0 && optCap) {

	eqv = neweqv ();

	gndCap_cnt++;

	sprintf (eqv -> inst_name, "_CG%d", gndCap_cnt);
	eqv -> inst_dim = 0;

	strcpy (eqv -> net_name, "p");
	eqv -> net_dim = 0;

#ifdef CIR_NET_ATOM_AVAILABLE
	if (!cancelWriteSave) {
	    dmPutDesignData (dmsNet, CIR_NET_ATOM);
	}
	new_net_neqv++;
#endif

        outCapacitor (n, (element_t *) NULL, gndCap_cnt);
    }

    if (!cancelWrite) {


	if ((prePass1 || prePass2) && !optOnlyPrePass) {
	    cancelWrite = 1;
	}
	else {
	    if (optGenNetTerm) {
		sprintf (gterm.term_name, net_name);
		gterm.layer_no = n -> mask;

		/* zero area terminals give problems with Space during 
		   the extraction of the father cell.
		 */

		gterm.xl = (long)(n -> x / geoScale);
		gterm.xr = (long)(n -> x / geoScale + 1);
		gterm.yb = (long)(n -> y / geoScale);
		gterm.yt = (long)(n -> y / geoScale + 1);
		ASSERT (cnet.net_dim <= 0);
		gterm.bxl = (long)(n -> x / geoScale);
		gterm.bxr = (long)(n -> x / geoScale + 1);
		gterm.byb = (long)(n -> y / geoScale);
		gterm.byt = (long)(n -> y / geoScale + 1);
		gterm.dx = 0, gterm.dy = 0, gterm.nx = 0, gterm.ny = 0;
		dmPutDesignData (dmsNetTerm, GEO_TERM);
	    }
#ifndef CIR_NET_ATOM_AVAILABLE
	    dmPutDesignData (dmsNet, CIR_NET);
#endif
	}
    }

#ifdef CIR_NET_ATOM_AVAILABLE
    ASSERT (connection == connectionSave);
    ASSERT (cancelWrite == cancelWriteSave);
    ASSERT (new_net_neqv == net_neqv);
    ASSERT (new_rnt_net_neqv == rnt_net_neqv);
#endif

    nodeDel (n);

    outNod++;
}

fillEqvWithTerm (eqv, tm)
struct cir_net *eqv;
terminal_t *tm;
{

#ifdef CIR_NET_ATOM_AVAILABLE
    if (tm -> termX >= 0 || tm -> termY >= 0) {
	eqv -> net_upper  = eqv -> net_lower  = NEW (long, 2);
    }
    if (tm -> instX >= 0 || tm -> instY >= 0) {
	eqv -> inst_upper = eqv -> inst_lower = NEW (long, 2);
    }
#endif

    strcpy (eqv -> net_name, tm -> termName);
    if (tm -> termX < 0 && tm -> termY < 0) {
	eqv -> net_dim = 0;
    }
    else if (tm -> termX >= 0 && tm -> termY >= 0) {
	eqv -> net_dim = 2;
	eqv -> net_lower[0] = tm -> termX;
	eqv -> net_lower[1] = tm -> termY;
    }
    else if (tm -> termX >= 0) {
	eqv -> net_dim = 1;
	eqv -> net_lower[0] = tm -> termX;
    }
    else {
	eqv -> net_dim = 1;
	eqv -> net_lower[0] = tm -> termY;
    }

    if (tm -> instName != NULL) {
	strcpy (eqv -> inst_name, tm -> instName);
	if (tm -> instX < 0 && tm -> instY < 0) {
	    eqv -> inst_dim = 0;
	}
	else if (tm -> instX >= 0 && tm -> instY >= 0) {
	    eqv -> inst_dim = 2;
	    eqv -> inst_lower[0] = tm -> instX;
	    eqv -> inst_lower[1] = tm -> instY;
	}
	else if (tm -> instX >= 0) {
	    eqv -> inst_dim = 1;
	    eqv -> inst_lower[0] = tm -> instX;
	}
	else {
	    eqv -> inst_dim = 1;
	    eqv -> inst_lower[0] = tm -> instY;
	}
    }
    else {
	strcpy (eqv -> inst_name, "");
	eqv -> inst_dim = 0;
    }
}

# ifdef CIR_NET_ATOM_AVAILABLE
outGndNode ()
{
    int cnt;

    if (!((!prePass1 && !prePass2) || optOnlyPrePass))
	return;

    cnet.inst_dim = 0;
    cnet.net_dim = 0;
    cnet.ref_dim = 0;
    cnet.net_attribute = 0;

    strcpy (cnet.inst_name, "");
    strcpy (cnet.net_name, "GND");
    cnet.net_neqv = gndCap_cnt;

    dmPutDesignData (dmsNet, CIR_NET_ATOM);

    strcpy (cnet.net_name, "n");
    for (cnt = 1; cnt <= gndCap_cnt; cnt++) {
	cnet.net_neqv = 0;
	sprintf (cnet.inst_name, "_CG%d", cnt);
	dmPutDesignData (dmsNet, CIR_NET_ATOM);
    }

    outNod++;
}

# else /* not CIR_NET_ATOM_AVAILABLE */

outGndNode ()
{
    int cnt;
    struct cir_net *eqv;
    struct cir_net *neweqv ();

    strcpy (cnet.inst_name, "");
    cnet.inst_dim = 0;

    strcpy (cnet.net_name, "GND");
    cnet.net_dim = 0;

    cnet.net_attribute = 0;

    cnet.net_neqv = 0;

    for (cnt = 1; cnt <= gndCap_cnt; cnt++) {

	eqv = neweqv ();

	sprintf (eqv -> inst_name, "_CG%d", cnt);
	eqv -> inst_dim = 0;

	strcpy (eqv -> net_name, "n");
	eqv -> net_dim = 0;
    }

    if ((!prePass1 && !prePass2) || optOnlyPrePass)
	dmPutDesignData (dmsNet, CIR_NET);

    outNod++;
}

# endif /* not CIR_NET_ATOM_AVAILABLE */


outCapacitor (n, el, number)
node_t * n;
element_t * el;
int number;
{
    char buf[80];
    double val;

    if (el) {
    }
    else {
	val = n -> gndCap;

	sprintf (cmc.inst_name, "_CG%d", number);
    }

    totOutCap += val;

    strcpy (cmc.cell_name, "cap");
    cmc.imported = LOCAL;

    sprintf (buf, "v=%e", val);
    cmc.inst_attribute = buf;
    cmc.inst_dim = 0;

    if ((!prePass1 && !prePass2) || optOnlyPrePass)
	dmPutDesignData (dmsMc, CIR_MC);

    outCap++;
}

outTransistor (t, dsn)
transistor_t * t;
node_t * dsn;
{
    int dsDone;
    int gDone;
    int number;
    char term;
    nodeTorLink_t * nTL;
    nodeTorLink_t * next_nTL;
    dsCoor_t * point;
    dsCoor_t * nextPoint;
    dsBoundary_t * dsBdr;
    dsBoundary_t * nextDsBdr;
    char buf[64];
    char buf2[24];
    double w, l;
    static int dsWarning = 0;
    netEquiv_t * dsRing;
    netEquiv_t * addDsNetEq ();
    element_t * con;
    node_t * nA;
    node_t * nB;
    tileRef_t * help;

    number = ++tor_cnt;

    nTL = t -> gate;

    if (nTL != NULL) {

	addNetEq (nTL -> n, TOR, 'g', number);

        nTLinkDel (nTL);
    }

    if (optDsConJoin) {

	dsRing = NULL;
	dsDone = 0;

	nTL = t -> drains;

	while (nTL != NULL) {   /* first round for making the equivalences */

	    dsRing = addDsNetEq (nTL -> n, TOR, 'd', number, dsRing);

	    dsDone++;

	    nTL = nTL -> nextT;
	}
    }

    if (!optDsConJoin) {

        /* keep separate ds boundaries */

	dsDone = 0;
    }

    gDone = 0;

    dsBdr = t -> boundaries;
    while (dsBdr) {                        /* first round */

        if (!optDsConJoin) {

	    if (dsDone >= 2) {

		if (!dsWarning) {

      say ("transistor(s) with more than two drain/source terminals detected\n       (x=%d y=%d), consider option -j", 
           (((int)(t -> xl)) / currScale), (((int)(t -> yb)) / currScale));

		    dsWarning = 1;
		}
                term = 's';
	    }
	    else {
		if (dsDone == 0) {
		    term = 'd';
		}
		else {
		    term = 's';
		}
	    }

	    addNetEq (dsBdr -> dsCond -> node, TOR, term, number);

	    dsDone++;
	}

	point = dsBdr -> points;
	while (point) {
	    if (point -> nr == 1)
		break;
	    point = point -> next;
	}
	if (point) {
	    gDone++;    /* the dsBdr is not a closed ring */
	}

	dsBdr = dsBdr -> next;;
    }

    calcTorWL (t, gDone, &w, &l);

    if (optDsConJoin) {

	nTL = t -> drains;

	while (nTL != NULL) {     /* second round for deleting the links */

	    next_nTL = nTL -> nextT;

	    nTLinkDel (nTL);

	    nTL = next_nTL;    
	} 
    }

    dsBdr = t -> boundaries;
    while (dsBdr) {          /* second round (cannot combined with first 
				round since tors may be outputed now) */

	point = dsBdr -> points;
	while (point) {
	    nextPoint = point -> next;
	    DISPOSE (point);
	    point = nextPoint;
	}
	nextDsBdr = dsBdr -> next;
	subnodeDel (dsBdr -> dsCond);
	DISPOSE (dsBdr -> dsCond);
	DISPOSE (dsBdr);
	dsBdr = nextDsBdr;
    }


    sprintf (cmc.inst_name, "_T%d", number);
    cmc.inst_dim = 0;
    strcpy (cmc.cell_name, t -> name);
    cmc.imported = LOCAL;

    *buf = '\0';
    if (!optNoDim) {
	sprintf (buf, "w=%.4e;l=%.4e", w, l);
    }

    if (optTorPos) {
	if (*buf)
	    sprintf (buf + strlen (buf), ";");
	sprintf (buf + strlen (buf), "x=%d;y=%d",
	    ((int)t -> xl) / currScale, ((int)t -> yb) / currScale);
    }
    cmc.inst_attribute = buf;

    if ((!prePass1 && !prePass2) || optOnlyPrePass)
	dmPutDesignData (dmsMc, CIR_MC);

    if (optBeeb) {
	fprintf (stderr, "\033#>");
	fflush (stderr);
    }

    if (optPlotCir) {
	sprintf (buf2, "%d %s", number, t -> name);
	plotString (cirPK, 6, BELOW, buf2, (int)(t -> xl), (int)(t -> yb));
    }


    torDel (t);

    outTor++;
}

#ifdef CIR_NET_ATOM_AVAILABLE

struct cir_net *neweqv ()
{
    cnet.net_neqv = 0;
    return (&cnet);
}

#else

struct cir_net *neweqv ()
{
    int i;
    char * p;
    long * ul;
    static int size = 0;
    int newsize;
	
    struct cir_net *eqv;

    if (cnet.net_neqv >= size) {
	if (size <= 0) {
	    newsize = 50;
	    cnet.net_eqv = NULL;
	}
	else {
	    newsize = size * 1.5;
	}

	/* round-up for minimum fragmentation */
	newsize = FIT (struct cir_net, newsize);

	cnet.net_eqv = RESIZE (cnet.net_eqv, struct cir_net, newsize);

	p = (char *) cnet.net_eqv;

	(void) memset (p + size * sizeof (struct cir_net), 0,
	    (newsize - size) * sizeof (struct cir_net));

	ul = NEW (long, 4 * (newsize - size));

	for (i = size; i < newsize; i++) {
	    eqv =  cnet.net_eqv + i;
	    eqv -> net_upper  = eqv -> net_lower  = ul; ul += 2;
	    eqv -> inst_upper = eqv -> inst_lower = ul; ul += 2;
	}

	size = newsize;
    }

    eqv = &cnet.net_eqv [cnet.net_neqv++];

    return (eqv);
}

#endif

calcTorWL (t, N, pw, pl)
transistor_t *t;
int N;
double *pw;
double *pl;
{
    if (N > 0 && (t -> totPerimeter - t -> dsPerimeter) > 0) {
	*pl = ((double)(t -> totPerimeter) - (double)(t -> dsPerimeter)) / N;
	*pw = t -> surface / *pl;
    }
    else {
	*pw = (double)(t -> totPerimeter) / 2;
	*pl = t -> surface / *pw;
    }
}

groupDel (grp) 
group_t *grp;
{
    DISPOSE (grp);
    currIntGrp--;
}

nodeDel (n)
node_t *n;
{
    group_t * grp;

    if (n -> prev) 
	n -> prev -> next = n -> next;
    else
	node_list = n -> next;

    if (n -> next)
	n -> next -> prev = n -> prev;
    
    /* findRoot will check if n is a leaf node,
     * and if so, actually dispose the node.
     * Special case: if n is a root, and it is disposed,
     * findRoot returns NULL.
     * Therefore, we must get the grp before the node is condemned.
     */

    grp = Grp (n);
    ASSERT (grp != NULL);
    grp -> nod_cnt--;

    n -> condemned = TRUE;

    findRoot (n);

    condemnCnt++;
    currIntNod--;
}

torDel (t)
transistor_t * t;
{
    currIntTor--;

    DISPOSE (t);
}

addNetEq (n, instType, term, number)
node_t * n;
int instType;
char term;
int number;
{
    netEquiv_t * netEq = NEW (netEquiv_t, 1);

    currNeqv++;

    netEq -> instType = instType;
    netEq -> term = term;
    netEq -> number = number;
    netEq -> net = n;
    netEq -> next = n -> netEq;
    n -> netEq = netEq;
}

netEquiv_t * addDsNetEq (n, instType, term, number, dsRing)
node_t * n;
int instType;
char term;
int number;
netEquiv_t * dsRing;
{
    netEquiv_t * netEq = NEW (netEquiv_t, 1);

    currNeqv++;

    netEq -> instType = instType;
    netEq -> term = term;
    netEq -> number = number;
    netEq -> net = n;
    netEq -> next = n -> netEq;
    n -> netEq = netEq;

    /* construct a ring of drain/sources for this transistor */

    if (dsRing == NULL)
	netEq -> nextDsRing = netEq;
    else {
	netEq -> nextDsRing = dsRing -> nextDsRing;
	dsRing -> nextDsRing = netEq;
    }

    return (netEq);
}


#ifdef DEBUG_NODES

debug_nodes_init ()
{
    if ((fp_dbn = fopen ("debnod", "w")) == NULL) {
        fprintf (stderr, "Cannot open debnod\n");
        exit (1);
    }

    check_cnt = 0;
    leftBehind = 0;
    hasPrinted = 0;
}

int debug_nodes_check (nr)
int nr;
{
    int i;
    int help;
    node_t *n;
    node_t *m;
    element_t *cap;
    extern node_t **QN;
    extern int QN_cnt;

    check_cnt++;

    for (m = node_list; m; m = m -> next) {

	if (!m -> flag && Grp (m) -> notReady == 0) {

            QN_cnt = 0;
	    searchGroup (m);

	    help = 1;

	    for (i = 0; i < QN_cnt; i++) {

		n = QN[i];

		cap = n -> cap;
		while (cap) {
		    
		    if (Grp (OTHER (cap, n)) != Grp (n)
			&& Grp (OTHER (cap, n)) -> notReady == 1) {

			help = 0;
		    }

		    cap = NEXT (cap, n);
		}
	    }

	    if (help == 1)
		leftBehind = 1;
	}
    }

    for (m = node_list; m; m = m -> next) {
	m -> flag = 0;
    }


    if (hasPrinted)
	return (leftBehind);

	/* print only before and after an error has occured ! */

    if (!leftBehind) {
	rewind (fp_dbn);       /* this might be before an error occurs */
        debug_nodes_print ();      /* before (?) */
    }
    else {
        debug_nodes_print ();      /* after */
	hasPrinted = 1;
    }


    return (leftBehind);
}

debug_nodes_print ()
{
    int i;
    int help;
    element_t *con;
    element_t *cap;
    nodeTorLink_t *port;
    node_t *m;
    node_t *n;
    extern node_t **QN;
    extern int QN_cnt;

    if (leftBehind) {
	fprintf (fp_dbn, "\n\n!!!!!!  Nodes are left alone !!!!!!\n");
    }

    fprintf (fp_dbn, "\ncheck_cnt: %d  outNodes: %d\n\n", check_cnt, outNod);

    for (m = node_list; m; m = m -> next) {

	QN_cnt = 0;
	searchGroup (m);

	fprintf (fp_dbn, 
	"Grp: %x notReady: %d\n", Grp (m), Grp (m) -> notReady);

	help = 1;

	for (i = 0; i < QN_cnt; i++) {

	    n = QN[i];

	    fprintf (fp_dbn, 
	    "    node %x subs: %d pin: %d grp: %x notReady: %d \n", 
		     n, 
		     (n -> subs)?(1):(0),
		     (n -> pin)?(1):(0), 
		     Grp (n),
		     Grp (n) -> notReady);


	    if (n -> ports != NULL) {

		port = n -> ports;
		while (port) {

		    fprintf (fp_dbn, "      tor %c %x %x\n", 
		    port -> type, port -> n, port -> t);

		    port = port -> nextN;
		}
	    }
	}

	if (Grp (m) -> notReady == 0 && help == 1) {
	    fprintf (fp_dbn, "    This group is left alone !!!\n");
	}
    }

    for (m = node_list; m; m = m -> next) {
	m -> flag = 0;
    }
}

#endif
