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

Name/Version      : sls/4.2

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"

NODE ** bcH_rfront = NULL;  /* search front for best case path to H */
NODE ** bcL_rfront = NULL;  /* search front for best case path to L */
NODE ** wcH_rfront = NULL;  /* search front for worst case path to H */
NODE ** wcL_rfront = NULL;  /* search front for worst case path to L */
int     bcHf_cnt;
int     bcLf_cnt;
int     wcHf_cnt;
int     wcLf_cnt;

initresistdiv () {
    if (bcH_rfront != NULL)
	CFREE (bcH_rfront);
    if (bcL_rfront != NULL)
	CFREE (bcL_rfront);
    if (wcH_rfront != NULL)
	CFREE (wcH_rfront);
    if (wcL_rfront != NULL)
	CFREE (wcL_rfront);
    PPALLOC (bcH_rfront, maxnvicin, NODE);
    PPALLOC (bcL_rfront, maxnvicin, NODE);
    PPALLOC (wcH_rfront, maxnvicin, NODE);
    PPALLOC (wcL_rfront, maxnvicin, NODE);
}

resistdivide () {  /* perform a complete resistance division on the */
		   /* vicinity, including a possibly second step    */
		   /* to account for saturated transistors   */

    int cnt;
    TRANSISTOR ** tt;
    TRANSISTOR * t;
    int do2;

    single_resistdivide (1);

    do2 = FALSE;
    tt = vicin.tors;
    for (cnt = vicin.tor_cnt; cnt > 0; cnt--) {
	t = *tt++;
	switch (t-> type) {
	    case Nenh :
		if (N[t -> drain].ei -> svmin > vswitch
		    || N[t -> source].ei -> svmin > vswitch) {
		    do2 = TRUE;
		}
		break;
	    case Penh :
		if (N[t -> drain].ei -> svmax < vswitch
		    || N[t -> source].ei -> svmax < vswitch) {
		    do2 = TRUE;
		}
		break;
	    case Depl :
		break;
	}
	if (do2) {
	    single_resistdivide (2);
	    break;
	}
    }
}

single_resistdivide (step)    /* perform a single resistance */
int step;                     /* division on the vicinity */
{   
    int satu;
    int     cnt;           
    NODE ** nn;
    NODE * n;
    NODE * forn;
    NODE * conn;
    NODE * search;
    NODE * track;
    NODE * trackstop;
    NODE * lastcommon;
    NODE * follow;
    TRANSISTOR ** tt;
    TRANSISTOR * t;
    float   newsvmin;
    float   newsvmax;
    float   resist;
    float   torpar ();

    if (debugsim) {
	fprintf (debug, "***** resistdivide (%d) *****\n\n", step);
    }

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

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

	n -> ei -> undetermined = TRUE;
	n -> ei -> bcH_path = NULL;
	n -> ei -> bcL_path = NULL;
	n -> ei -> wcH_path = NULL;
	n -> ei -> wcL_path = NULL;
	n -> ei -> bcH_done = FALSE;
	n -> ei -> bcL_done = FALSE;
	n -> ei -> wcH_done = FALSE;
	n -> ei -> wcL_done = FALSE;
	n -> ei -> ontrack = FALSE;
	n -> ei -> common = FALSE;
    }

    bcHf_cnt = 0;
    bcLf_cnt = 0;
    wcHf_cnt = 0;
    wcLf_cnt = 0;

    /* after the above initializations have been done, nodes connected */
    /* to Forced nodes are put on the front list. */

    tt = vicin.tors;
    for (cnt = vicin.tor_cnt; cnt > 0; cnt--) {
	t = *tt++;

        if (step == 2) {
	    satu = FALSE;
	    switch (t-> type) {
		case Nenh :
		    if (N[t -> drain].ei -> svmin > vswitch
			|| N[t -> source].ei -> svmin > vswitch) {
			satu = TRUE;
		    }
		    break;
		case Penh :
		    if (N[t -> drain].ei -> svmax < vswitch
			|| N[t -> source].ei -> svmax < vswitch) {
			satu = TRUE;
		    }
		    break;
		case Depl :
		    break;
	    }
	    if (satu) {
		resist = torpar (t, NULL, Rsatu);  
	    }
	    else {
		resist = torpar (t, NULL, Rstat);
	    }
	}
	else {
	    resist = torpar (t, NULL, Rstat);
	}
	t -> ei -> resist = resist;

	if (N[t -> drain].type == Forced) {
	    forn = &N[t -> drain];
	    conn = &N[t -> source];
	}
	else
	    if (N[t -> source].type == Forced) {
		forn = &N[t -> source];
		conn = &N[t -> drain];
	    }
	    else
		forn = NULL;

	if (forn != NULL && conn -> type != Forced) {
	    if (forn -> ei -> lstate != L_state) {
		if (conn -> ei -> bcH_path == NULL) {
		    conn -> ei -> bcH_r = resist;
		    conn -> ei -> bcH_path = forn;
		    bcH_rfront[bcHf_cnt++] = conn;
		}
		else
		    if (conn -> ei -> bcH_r > resist) {
			conn -> ei -> bcH_r = resist;
			conn -> ei -> bcH_path = forn;
		    }
	    }
	    if (forn -> ei -> lstate != H_state) {
		if (conn -> ei -> bcL_path == NULL) {
		    conn -> ei -> bcL_r = resist;
		    conn -> ei -> bcL_path = forn;
		    bcL_rfront[bcLf_cnt++] = conn;
		}
		else
		    if (conn -> ei -> bcL_r > resist) {
			conn -> ei -> bcL_r = resist;
			conn -> ei -> bcL_path = forn;
		    }
	    }
	    if (vicin.undeftors || vicin.forcedsX) {
	        if (t -> state == Closed && forn -> ei -> lstate == H_state) {
		    if (conn -> ei -> wcH_path == NULL) {
		        conn -> ei -> wcH_r = resist;
		        conn -> ei -> wcH_path = forn;
		        wcH_rfront[wcHf_cnt++] = conn;
		    }
		    else
		        if (conn -> ei -> wcH_r > resist) {
			    conn -> ei -> wcH_r = resist;
			    conn -> ei -> wcH_path = forn;
		        }
	        }
	        if (t -> state == Closed && forn -> ei -> lstate == L_state) {
		    if (conn -> ei -> wcL_path == NULL) {
		        conn -> ei -> wcL_r = resist;
		        conn -> ei -> wcL_path = forn;
		        wcL_rfront[wcLf_cnt++] = conn;
		    }
		    else
		        if (conn -> ei -> wcL_r > resist) {
			    conn -> ei -> wcL_r = resist;
			    conn -> ei -> wcL_path = forn;
		        }
	        }
	    }
	}
    }

    /* determine the minimum resistance paths */

    pathbcH ();
    pathbcL ();
    if (vicin.undeftors || vicin.forcedsX) {
        pathwcH ();
        pathwcL ();
    }
    else {
        nn = vicin.nodes;
        for (cnt = vicin.node_cnt; cnt > 0; cnt--) {
	    n = *nn++;

	    n -> ei -> wcL_path = n -> ei -> bcL_path;
	    n -> ei -> wcL_r = n -> ei -> bcL_r;
	    n -> ei -> wcH_path = n -> ei -> bcH_path;
	    n -> ei -> wcH_r = n -> ei -> bcH_r;
	}
    }

    /* calculate stable voltages from path values */

    vicin.floatpossible = FALSE;

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

	if (n -> type != Forced 
	&& n -> ei -> wcH_path == NULL && n -> ei -> wcL_path == NULL) {
	    vicin.floatpossible = TRUE;
	}
	else
	    n -> ei -> posfloat = FALSE;

	if (!n -> ei -> undetermined)
	    continue;

        /* find the common part of the paths */

	n -> ei -> common = TRUE;
	lastcommon = trackstop = n;

	if (n -> ei -> bcH_path != NULL && n -> ei -> bcL_path != NULL) {
	    search = n;
	    while (search -> ei -> undetermined
		   && search -> ei -> bcH_path == search -> ei -> bcL_path
		   && (search -> ei -> wcH_path == search -> ei -> bcH_path
		       || search -> ei -> wcH_path == NULL)
		   && (search -> ei -> wcL_path == search -> ei -> bcL_path
		       || search -> ei -> wcL_path == NULL)) {
		search = search -> ei -> bcH_path;
		search -> ei -> common = TRUE;
	    }
	    lastcommon = trackstop = search;

	    if (search -> ei -> undetermined
		&& search -> ei -> bcH_path == search -> ei -> bcL_path) {

	        /* there may be a next common part. */
		/* therefore, first lay a track for the best case paths. */

		track = search;
		while (track -> type != Forced
		       && track -> ei -> bcH_path == track -> ei -> bcL_path) {
		    track = track -> ei -> bcH_path;
		    track -> ei -> ontrack = TRUE;
		}
		trackstop = track;

                /* and find the parts of the worst case path which are common */
		/* with that track */

		while (search -> type != Forced
		       && search != trackstop
		       && (search -> ei -> wcH_path == search -> ei -> wcL_path
			   || search -> ei -> wcH_path == NULL
			   || search -> ei -> wcL_path == NULL)) {
		    if (search -> ei -> wcL_path == NULL)
			search = search -> ei -> wcH_path;
		    else
			search = search -> ei -> wcL_path;
		    if (search -> ei -> ontrack) {
			search -> ei -> common = TRUE;
			lastcommon = search;
		    }
		}
	    }
	}

        /* the stable voltage will be calculated for the */
	/* last common path node */

	if (lastcommon -> type == Forced) {
	    switch (lastcommon -> ei -> lstate) {
		case H_state: 
		    newsvmin = vH;
		    newsvmax = vH;
		    break;
		case L_state: 
		    newsvmin = 0;
		    newsvmax = 0;
		    break;
		case X_state: 
		    newsvmin = 0;
		    newsvmax = vH;
		    break;
	    }
	}
	else {
	    if (lastcommon -> ei -> undetermined) {
		if (lastcommon -> ei -> bcL_path == NULL)
		    lastcommon -> ei -> svmin = vH;
		else
		    if (lastcommon -> ei -> wcH_path == NULL)
			lastcommon -> ei -> svmin = 0;
		    else
			lastcommon -> ei -> svmin =
			    vH * lastcommon -> ei -> bcL_r
			    / (lastcommon -> ei -> bcL_r
				+ lastcommon -> ei -> wcH_r);

		if (lastcommon -> ei -> bcH_path == NULL)
		    lastcommon -> ei -> svmax = 0;
		else
		    if (lastcommon -> ei -> wcL_path == NULL)
			lastcommon -> ei -> svmax = vH;
		    else
			lastcommon -> ei -> svmax =
			    vH * lastcommon -> ei -> wcL_r
			    / (lastcommon -> ei -> wcL_r
				+ lastcommon -> ei -> bcH_r);

		lastcommon -> ei -> undetermined = FALSE;
	    }
	    newsvmin = lastcommon -> ei -> svmin;
	    newsvmax = lastcommon -> ei -> svmax;
	}

        /* and that stable voltage is assigned to all the nodes which */
	/* are on the common path parts */

	follow = n;
	while (follow != trackstop) {
	    follow -> ei -> ontrack = FALSE;
	    if (follow != lastcommon && follow -> ei -> common) {
		follow -> ei -> svmin = newsvmin;
		follow -> ei -> svmax = newsvmax;
		follow -> ei -> undetermined = FALSE;
	    }
	    follow -> ei -> common = FALSE;
	    follow = follow -> ei -> bcH_path;
	}
    }
}

pathbcH () {          /* search best case path to H */
    int     cnt;
    int     index;
    int     index_fn;
    int     index_m_r;
    NODE * n;
    NODE * conn;
    TRANSISTOR * cont;
    float   resist;
    float   res;
    float   min_res;

    while (bcHf_cnt > 0) {
	min_res = MAXRESIST;
	for (index_fn = 0; index_fn < bcHf_cnt; index_fn++) {
	    res = bcH_rfront[index_fn] -> ei -> bcH_r;
	    if (res < min_res) {
		min_res = res;
		index_m_r = index_fn;
	    }
	}
	n = bcH_rfront[index_m_r];
	n -> ei -> bcH_done = TRUE;
	bcH_rfront[index_m_r] = bcH_rfront[--bcHf_cnt];

	index = n -> dsx;
	for (cnt = DS[index]; cnt > 0; cnt--) {
	    index++;
	    cont = &T[DS[index]];

	    if (cont -> state == Open)
		continue;

	    if (&N[cont -> source] == n)
		conn = &N[cont -> drain];
	    else
		conn = &N[cont -> source];

	    if (conn -> type == Forced || conn -> ei -> bcH_done)
		continue;

	    resist = n -> ei -> bcH_r + cont -> ei -> resist;
	    if (conn -> ei -> bcH_path == NULL) {
		conn -> ei -> bcH_r = resist;
		conn -> ei -> bcH_path = n;
		bcH_rfront[bcHf_cnt++] = conn;
	    }
	    else
		if (conn -> ei -> bcH_r > resist) {
		    conn -> ei -> bcH_r = resist;
		    conn -> ei -> bcH_path = n;
		}
	}
    }
}

pathbcL () {          /* search best case path to L */
    int     cnt;
    int     index;
    int     index_fn;
    int     index_m_r;
    NODE * n;
    NODE * conn;
    TRANSISTOR * cont;
    float   resist;
    float   res;
    float   min_res;

    while (bcLf_cnt > 0) {
	min_res = MAXRESIST;
	for (index_fn = 0; index_fn < bcLf_cnt; index_fn++) {
	    res = bcL_rfront[index_fn] -> ei -> bcL_r;
	    if (res < min_res) {
		min_res = res;
		index_m_r = index_fn;
	    }
	}
	n = bcL_rfront[index_m_r];
	n -> ei -> bcL_done = TRUE;
	bcL_rfront[index_m_r] = bcL_rfront[--bcLf_cnt];

	index = n -> dsx;
	for (cnt = DS[index]; cnt > 0; cnt--) {
	    index++;
	    cont = &T[DS[index]];

	    if (cont -> state == Open)
		continue;

	    if (&N[cont -> source] == n)
		conn = &N[cont -> drain];
	    else
		conn = &N[cont -> source];

	    if (conn -> type == Forced || conn -> ei -> bcL_done)
		continue;

	    resist = n -> ei -> bcL_r + cont -> ei -> resist;
	    if (conn -> ei -> bcL_path == NULL) {
		conn -> ei -> bcL_r = resist;
		conn -> ei -> bcL_path = n;
		bcL_rfront[bcLf_cnt++] = conn;
	    }
	    else
		if (conn -> ei -> bcL_r > resist) {
		    conn -> ei -> bcL_r = resist;
		    conn -> ei -> bcL_path = n;
		}

	    /* the above else should be substituted by the following
	       to deal with some particular situations in which parasitic 
	       resistances have a bad influence on common part tracing 

	    else
		if (conn -> ei -> bcL_r > resist * (1 + DELTA)) {
		    conn -> ei -> bcL_r = resist;
		    conn -> ei -> bcL_path = n;
		}
		else
		    if (conn -> ei -> bcL_r >= resist * (1 - DELTA)
			&& conn -> ei -> bcH_path == n) {
			conn -> ei -> bcL_path = n;
		    }
	    */
	}
    }
}

pathwcH () {          /* search worst case path to H */
    int     cnt;
    int     index;
    int     index_fn;
    int     index_m_r;
    NODE * n;
    NODE * conn;
    TRANSISTOR * cont;
    float   resist;
    float   res;
    float   min_res;

    while (wcHf_cnt > 0) {
	min_res = MAXRESIST;
	for (index_fn = 0; index_fn < wcHf_cnt; index_fn++) {
	    res = wcH_rfront[index_fn] -> ei -> wcH_r;
	    if (res < min_res) {
		min_res = res;
		index_m_r = index_fn;
	    }
	}
	n = wcH_rfront[index_m_r];
	n -> ei -> wcH_done = TRUE;
	wcH_rfront[index_m_r] = wcH_rfront[--wcHf_cnt];

	index = n -> dsx;
	for (cnt = DS[index]; cnt > 0; cnt--) {
	    index++;
	    cont = &T[DS[index]];

	    if (cont -> state != Closed)
		continue;

	    if (&N[cont -> source] == n)
		conn = &N[cont -> drain];
	    else
		conn = &N[cont -> source];

	    if (conn -> type == Forced || conn -> ei -> wcH_done)
		continue;

	    resist = n -> ei -> wcH_r + cont -> ei -> resist;
	    if (conn -> ei -> wcH_path == NULL) {
		conn -> ei -> wcH_r = resist;
		conn -> ei -> wcH_path = n;
		wcH_rfront[wcHf_cnt++] = conn;
	    }
	    else
		if (conn -> ei -> wcH_r > resist) {
		    conn -> ei -> wcH_r = resist;
		    conn -> ei -> wcH_path = n;
		}

	    /* the above else should be substituted by the following
	       to deal with some particular situations in which parasitic 
	       resistances have a bad influence on common part tracing 

	    else
		if (conn -> ei -> wcH_r > resist * (1 + DELTA)) {
		    conn -> ei -> wcH_r = resist;
		    conn -> ei -> wcH_path = n;
		}
		else
		    if (conn -> ei -> wcH_r >= resist * (1 - DELTA)
			    && conn -> ei -> bcH_path == n) {
			conn -> ei -> wcH_path = n;
		    }
	    */
	}
    }
}

pathwcL () {          /* search worst case path to L */
    int     cnt;
    int     index;
    int     index_fn;
    int     index_m_r;
    NODE * n;
    NODE * conn;
    TRANSISTOR * cont;
    float   resist;
    float   res;
    float   min_res;

    while (wcLf_cnt > 0) {
	min_res = MAXRESIST;
	for (index_fn = 0; index_fn < wcLf_cnt; index_fn++) {
	    res = wcL_rfront[index_fn] -> ei -> wcL_r;
	    if (res < min_res) {
		min_res = res;
		index_m_r = index_fn;
	    }
	}
	n = wcL_rfront[index_m_r];
	n -> ei -> wcL_done = TRUE;
	wcL_rfront[index_m_r] = wcL_rfront[--wcLf_cnt];

	index = n -> dsx;
	for (cnt = DS[index]; cnt > 0; cnt--) {
	    index++;
	    cont = &T[DS[index]];

	    if (cont -> state != Closed)
		continue;

	    if (&N[cont -> source] == n)
		conn = &N[cont -> drain];
	    else
		conn = &N[cont -> source];

	    if (conn -> type == Forced || conn -> ei -> wcL_done)
		continue;

	    resist = n -> ei -> wcL_r + cont -> ei -> resist;
	    if (conn -> ei -> wcL_path == NULL) {
		conn -> ei -> wcL_r = resist;
		conn -> ei -> wcL_path = n;
		wcL_rfront[wcLf_cnt++] = conn;
	    }
	    else
		if (conn -> ei -> wcL_r > resist) {
		    conn -> ei -> wcL_r = resist;
		    conn -> ei -> wcL_path = n;
		}

	    /* the above else should be substituted by the following
	       to deal with some particular situations in which parasitic 
	       resistances have a bad influence on common part tracing 

	    else
		if (conn -> ei -> wcL_r > resist * (1 + DELTA)) {
		    conn -> ei -> wcL_r = resist;
		    conn -> ei -> wcL_path = n;
		}
		else
		    if (conn -> ei -> wcL_r >= resist * (1 - DELTA)
			    && conn -> ei -> wcH_path == n) {
			conn -> ei -> wcL_path = n;
		    }
	    */
	}
    }
}
