Files
magic/resis/ResSimple.c
T
Tim Edwards 0bb6ac1fa9 Modified the extresist code to handle substrate extraction. Currently
this appears to work correctly but does not yet handle the implicit
substrate (space as substrate) or "virtually" isolated substrate regions
(which need to be removed for full parasitic extraction).
2021-09-15 16:25:46 -04:00

1119 lines
31 KiB
C

/*
*-------------------------------------------------------------------------
*
* ResSimplify -- contains routines used to simplify signal nets.
*
*
*
*-------------------------------------------------------------------------
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResSimple.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/geofast.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "utils/heap.h"
#include "database/database.h"
#include "utils/malloc.h"
#include "textio/textio.h"
#include "extract/extract.h"
#include "extract/extractInt.h"
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "utils/stack.h"
#include "utils/tech.h"
#include "textio/txcommands.h"
#include "resis/resis.h"
#define MILLIOHMSPEROHM 1000
/* Forward declarations */
void ResSetPathRes();
void resPathNode();
void resPathRes();
Heap ResistorHeap;
int resRemoveLoops = FALSE;
/* Forward declarations */
extern void ResMoveDevices();
extern void ResAddResistorToList();
/*
*-------------------------------------------------------------------------
*
* ResSimplifyNet- Reduces complete (?) net produced by ResProcessTiles into
* something a little less chaotic.
*
* Results: none
*
* Side Effects: Can eliminate nodes and resistors, and move devices from
* one node to another.
*
*-------------------------------------------------------------------------
*/
void
ResSimplifyNet(nodelist, biglist, reslist, tolerance)
resNode **nodelist, **biglist;
resResistor **reslist;
float tolerance;
{
resElement *resisptr;
resNode *node, *otherNode, *node1, *node2;
resResistor *resistor1 = NULL, *resistor2 = NULL;
int numdrive = 0, numreceive = 0;
int MarkedReceivers, UnMarkedReceivers;
int NumberOfDrivers, PendingReceivers;
if (*nodelist == NULL) return;
node = *nodelist;
node->rn_status |= MARKED | FINISHED;
*nodelist = node->rn_more;
if (node->rn_more != NULL)
node->rn_more->rn_less = (resNode *) NULL;
node->rn_more = *biglist;
if (*biglist != (resNode *) NULL)
(*biglist)->rn_less = node;
*biglist = node;
/*
* Walk though resistors. Mark uninitialized ones and assign them
* a direction. Keep track of the number of resistors pointing in
* each direction.
*/
for (resisptr = node->rn_re; resisptr != NULL; resisptr = resisptr->re_nextEl)
{
if (((resisptr->re_thisEl->rr_status & RES_MARKED) == RES_MARKED) &&
(resisptr->re_thisEl->rr_connection2 == node))
{
if (resistor1 == NULL)
resistor1 = resisptr->re_thisEl;
else
resistor2 = resisptr->re_thisEl;
numdrive++;
}
else
{
/*
* Resistor direction is from node1 to node2. If the resistor
* is not marked, mark it and make sure the direction is
* set properly.
*/
if ((resisptr->re_thisEl->rr_status & RES_MARKED) != RES_MARKED)
{
if (resisptr->re_thisEl->rr_connection2 == node)
{
resisptr->re_thisEl->rr_connection2 =
resisptr->re_thisEl->rr_connection1;
resisptr->re_thisEl->rr_connection1 = node;
}
resisptr->re_thisEl->rr_status |= RES_MARKED;
}
if (resistor1 == NULL)
resistor1 = resisptr->re_thisEl;
else
resistor2 = resisptr->re_thisEl;
numreceive++;
}
}
/*
* Is the node reached by one resistor? If it is, check the resistor's
* other end. Check the number of drivers at the other end. If it is
* more than 1, delete the current resistor to break the deadlock.
*/
if (numreceive == 0 && numdrive == 1 && node->rn_why != RES_NODE_ORIGIN)
{
resistor1->rr_status |= RES_DEADEND;
if (resistor1->rr_value < tolerance)
{
otherNode = (resistor1->rr_connection1 == node) ?
resistor1->rr_connection2 : resistor1->rr_connection1;
MarkedReceivers = 0;
UnMarkedReceivers = 0;
NumberOfDrivers = 0;
PendingReceivers = 0;
resistor2 = resistor1;
for (resisptr = otherNode->rn_re; resisptr != NULL;
resisptr = resisptr->re_nextEl)
{
if (resisptr->re_thisEl->rr_connection1 == otherNode)
{
if ((resisptr->re_thisEl->rr_connection2->rn_status & MARKED)
!= MARKED)
{
PendingReceivers++;
}
if (resisptr->re_thisEl->rr_status & RES_DEADEND ||
resisptr->re_thisEl->rr_value > tolerance)
{
MarkedReceivers++;
resistor2 = (resisptr->re_thisEl->rr_value >=
resistor2->rr_value) ? resisptr->re_thisEl : resistor2;
}
else
UnMarkedReceivers++;
}
else
NumberOfDrivers++;
}
/* other recievers at far end? If so, reschedule other node;
* deadlock will be settled from that node.
*/
if ((MarkedReceivers+UnMarkedReceivers+NumberOfDrivers == 2) ||
(UnMarkedReceivers == 0 && MarkedReceivers > 1 &&
resistor2 == resistor1 && PendingReceivers == 0))
{
if (otherNode->rn_status & MARKED)
{
otherNode->rn_status &= ~MARKED;
ResRemoveFromQueue(otherNode, biglist);
otherNode->rn_less = NULL;
otherNode->rn_more = *nodelist;
if (*nodelist != NULL)
(*nodelist)->rn_less = otherNode;
*nodelist = otherNode;
}
return;
}
/*
* Break loop here. More than one driver indicates a loop;
* remove deadend, allowing drivers to be merged
*/
else if (UnMarkedReceivers == 0 && (MarkedReceivers == 1 &&
NumberOfDrivers > 1 || resistor2 != resistor1))
{
otherNode->rn_float.rn_area += resistor1->rr_float.rr_area;
otherNode->rn_status &= ~RES_DONE_ONCE;
ResDeleteResPointer(resistor1->rr_connection1, resistor1);
ResDeleteResPointer(resistor1->rr_connection2, resistor1);
ResEliminateResistor(resistor1, reslist);
ResMergeNodes(otherNode, node, nodelist, biglist);
if (otherNode->rn_status & MARKED)
{
otherNode->rn_status &= ~MARKED;
ResRemoveFromQueue(otherNode, biglist);
otherNode->rn_less= NULL;
otherNode->rn_more = *nodelist;
if (*nodelist != NULL)
(*nodelist)->rn_less = otherNode;
*nodelist = otherNode;
}
ResDoneWithNode(otherNode);
}
}
}
/*
* Two resistors in series? Combine them and move devices to
* appropriate end.
*/
else if (numdrive+numreceive == 2 && (resistor1->rr_value < tolerance &&
resistor2->rr_value < tolerance))
{
if ((resistor1->rr_status & RES_MARKED) == 0 &&
(resistor1->rr_connection2 == node))
{
resistor1->rr_connection2 = resistor1->rr_connection1;
resistor1->rr_connection1 = node;
}
resistor1->rr_status |= RES_MARKED;
if ((resistor2->rr_status & RES_MARKED) == 0 &&
(resistor2->rr_connection2 == node))
{
resistor2->rr_connection2 = resistor2->rr_connection1;
resistor2->rr_connection1 = node;
}
resistor2->rr_status |= RES_MARKED;
node1 = (resistor1->rr_connection1 == node) ? resistor1->rr_connection2 :
resistor1->rr_connection1;
node2 = (resistor2->rr_connection1 == node) ? resistor2->rr_connection2 :
resistor2->rr_connection1;
otherNode = (resistor1->rr_status & RES_DEADEND &&
resistor1->rr_value < tolerance / 2) ||
((resistor2->rr_status & RES_DEADEND) == 0 &&
resistor1->rr_value < resistor2->rr_value) ? node1 : node2;
/*
* Make one big resistor out of two little ones, eliminating
* the current node. Devices connected to this node are
* moved to either end depending on their resistance.
*/
ResMoveDevices(node,otherNode);
otherNode->rn_noderes = MIN(node->rn_noderes, otherNode->rn_noderes);
node2->rn_float.rn_area += resistor1->rr_value * node->rn_float.rn_area /
(resistor1->rr_value + resistor2->rr_value);
node1->rn_float.rn_area += resistor2->rr_value * node->rn_float.rn_area /
(resistor1->rr_value + resistor2->rr_value);
resistor1->rr_value += resistor2->rr_value;
resistor1->rr_float.rr_area +=resistor2->rr_float.rr_area;
if (resistor1 == *reslist)
*reslist = resistor1->rr_nextResistor;
else
resistor1->rr_lastResistor->rr_nextResistor = resistor1->rr_nextResistor;
if (resistor1->rr_nextResistor != NULL)
resistor1->rr_nextResistor->rr_lastResistor = resistor1->rr_lastResistor;
ResAddResistorToList(resistor1, reslist);
ResDeleteResPointer(node, resistor1);
ResDeleteResPointer(node, resistor2);
ResDeleteResPointer(node2, resistor2);
if (resistor1->rr_connection1 == node)
resistor1->rr_connection1 = node2;
else
resistor1->rr_connection2 = node2;
resisptr = (resElement *)mallocMagic((unsigned)(sizeof(resElement)));
resisptr->re_thisEl = resistor1;
resisptr->re_nextEl = node2->rn_re;
node2->rn_re = resisptr;
ResEliminateResistor(resistor2, reslist);
otherNode->rn_status |= (node->rn_status & RN_MAXTDI);
ResCleanNode(node, TRUE, biglist, nodelist);
node1->rn_status &= ~RES_DONE_ONCE;
if (node1->rn_status & MARKED)
{
node1->rn_status &= ~MARKED;
ResRemoveFromQueue(node1, biglist);
node1->rn_less = NULL;
node1->rn_more = *nodelist;
if (*nodelist != NULL)
(*nodelist)->rn_less = node1;
*nodelist = node1;
}
node2->rn_status &= ~RES_DONE_ONCE;
if (node2->rn_status & MARKED)
{
node2->rn_status &= ~MARKED;
ResRemoveFromQueue(node2, biglist);
node2->rn_less = NULL;
node2->rn_more = *nodelist;
if (*nodelist != NULL)
(*nodelist)->rn_less = node2;
*nodelist = node2;
}
ResDoneWithNode(node1);
}
/*
* Last resort- keep propagating down the tree. To avoid looping,
* mark each node when it is reached. Don't reschedule node if
* none of the connections to it have changed since it was marked
*/
else if (numreceive > 0 && (node->rn_status & RES_DONE_ONCE) == 0)
{
node->rn_status |= RES_DONE_ONCE;
for (resisptr = node->rn_re; resisptr != NULL; resisptr = resisptr->re_nextEl)
{
if (resisptr->re_thisEl->rr_connection1 == node)
{
/*
* Elements with a resistance greater than the
* tolerance should only be propagated past once-
* loops may occur otherwise.
*/
if (resisptr->re_thisEl->rr_status & RES_DONE_ONCE)
continue;
if (resisptr->re_thisEl->rr_connection2->rn_status & MARKED)
{
/*
* Mark big resistors so we only process them
* once.
*/
if (resisptr->re_thisEl->rr_value > tolerance)
resisptr->re_thisEl->rr_status |= RES_DONE_ONCE;
resisptr->re_thisEl->rr_connection2->rn_status &= ~MARKED;
ResRemoveFromQueue(resisptr->re_thisEl->rr_connection2, biglist);
resisptr->re_thisEl->rr_connection2->rn_less= NULL;
resisptr->re_thisEl->rr_connection2->rn_more = *nodelist;
if (*nodelist != NULL)
(*nodelist)->rn_less = resisptr->re_thisEl->rr_connection2;
*nodelist = resisptr->re_thisEl->rr_connection2;
}
}
}
}
}
/*
*-------------------------------------------------------------------------
*
* ResMoveDevices-- move devices from one node1 to node2
*
* Results: none
*
* Side Effects: Changes device connections and node tElements.
*
*-------------------------------------------------------------------------
*/
void
ResMoveDevices(node1, node2)
resNode *node1, *node2;
{
tElement *devptr, *oldptr;
resDevice *device;
devptr = node1->rn_te;
while (devptr != NULL)
{
device = devptr->te_thist;
oldptr = devptr;
devptr = devptr->te_nextt;
if (device->rd_status & RES_DEV_PLUG)
{
if (((ResPlug *)(device))->rpl_node == node1)
((ResPlug *)(device))->rpl_node = node2;
else
TxError("Bad node connection in plug\n");
}
else
{
if (device->rd_fet_gate == node1)
device->rd_fet_gate = node2;
else if (device->rd_fet_subs == node1)
device->rd_fet_subs = node2;
else if (device->rd_fet_source == node1)
device->rd_fet_source = node2;
else if (device->rd_fet_drain == node1)
device->rd_fet_drain = node2;
else
TxError("Missing Device connection in squish routines"
" at %d, %d\n", node1->rn_loc.p_x, node1->rn_loc.p_y);
}
oldptr->te_nextt = node2->rn_te;
node2->rn_te = oldptr;
}
node1->rn_te = NULL;
}
/*
*-------------------------------------------------------------------------
*
* ResScrunchNet-- Last ditch net simplification. Used to break deadlocks
* in ResSimplifyNet. Resistors are sorted by value. The smallest
* resistor is combined with its smallest neighbor, and ResSimplifyNet
* is called. This continues until the smallest resistor is greater
* than the tolerance.
*
* Results:none
*
* Side Effects: Nodes and resistors are eliminated.
*
*-------------------------------------------------------------------------
*/
void
ResScrunchNet(reslist, pendingList, biglist, tolerance)
resResistor **reslist;
resNode **pendingList, **biglist;
float tolerance;
{
resResistor *locallist = NULL, *current, *working;
resNode *node1, *node2;
resElement *rcell1;
int c1, c2;
/* Sort resistors by size */
current = *reslist;
while (current != NULL)
{
working = current;
current = current->rr_nextResistor;
if (working == *reslist)
*reslist = current;
else
working->rr_lastResistor->rr_nextResistor = current;
if (current != NULL)
current->rr_lastResistor = working->rr_lastResistor;
ResAddResistorToList(working, &locallist);
}
*reslist = locallist;
while (*reslist != NULL && (*reslist)->rr_value < tolerance)
{
current = *reslist;
if (current->rr_nextResistor == NULL)
break;
working = NULL;
c1 = 0;
c2 = 0;
/* Search for next smallest adjoining resistor */
for (rcell1 = current->rr_connection1->rn_re; rcell1 != NULL;
rcell1 = rcell1->re_nextEl)
{
if (rcell1->re_thisEl != current)
{
c1++;
if (working == NULL)
{
working = rcell1->re_thisEl;
node1 = current->rr_connection1;
}
else
{
if (working->rr_value > rcell1->re_thisEl->rr_value)
{
node1 = current->rr_connection1;
working = rcell1->re_thisEl;
}
}
}
}
for (rcell1 = current->rr_connection2->rn_re; rcell1 != NULL;
rcell1 = rcell1->re_nextEl)
{
if (rcell1->re_thisEl != current)
{
c2++;
if (working == NULL)
{
working = rcell1->re_thisEl;
node1 = current->rr_connection2;
}
else
{
if (working->rr_value > rcell1->re_thisEl->rr_value)
{
node1 = current->rr_connection2;
working = rcell1->re_thisEl;
}
}
}
}
/*
* If the current resistor isn't a deadend, add its value and
* area to that of the next smallest one. If it is a deadend,
* simply add its area to its node.
*/
if (c1 != 0 && c2 != 0)
{
working->rr_value += current->rr_value;
working->rr_float.rr_area += current->rr_float.rr_area;
}
else
{
node1->rn_float.rn_area += current->rr_float.rr_area;
}
/*
* Move everything from from one end of the ressistor to the
* other and eliminate the resistor.
*/
node2 = (current->rr_connection1 == node1) ? current->rr_connection2 :
current->rr_connection1;
ResDeleteResPointer(current->rr_connection1, current);
ResDeleteResPointer(current->rr_connection2, current);
working->rr_lastResistor->rr_nextResistor = working->rr_nextResistor;
if (working->rr_nextResistor != NULL)
working->rr_nextResistor->rr_lastResistor = working->rr_lastResistor;
ResEliminateResistor(current, reslist);
ResAddResistorToList(working, reslist);
if (node2->rn_why & RES_NODE_ORIGIN)
{
ResMergeNodes(node2, node1, pendingList, biglist);
node1 = node2;
}
else
ResMergeNodes(node1, node2, pendingList, biglist);
/*
* Try further simplification on net using ResDoneWithNode and
* ResSimplifyNet.
*/
ResRemoveFromQueue(node1, biglist);
ResAddToQueue(node1, pendingList);
node1->rn_status &= ~(RES_DONE_ONCE | FINISHED);
ResDoneWithNode(node1);
while (*pendingList != NULL)
ResSimplifyNet(pendingList, biglist, reslist, tolerance);
}
}
/*
*-------------------------------------------------------------------------
*
* ResAddResistorToList-- Adds resistor to list according to its value
* (smallest first).
*
* Results:none
*
* Side Effects: modifies locallist.
*
*-------------------------------------------------------------------------
*/
void
ResAddResistorToList(resistor, locallist)
resResistor *resistor, **locallist;
{
resResistor *local,*last=NULL;
for (local = *locallist; local != NULL; local = local->rr_nextResistor)
{
if (local->rr_value >= resistor->rr_value)
break;
last = local;
}
if (local != NULL)
{
resistor->rr_nextResistor = local;
resistor->rr_lastResistor = local->rr_lastResistor;
if (local->rr_lastResistor == NULL)
*locallist = resistor;
else
local->rr_lastResistor->rr_nextResistor = resistor;
local->rr_lastResistor = resistor;
}
else
{
if (last != NULL)
{
last->rr_nextResistor = resistor;
resistor->rr_lastResistor = last;
resistor->rr_nextResistor = NULL;
}
else
{
resistor->rr_nextResistor = NULL;
resistor->rr_lastResistor = NULL;
*locallist = resistor;
}
}
}
/*
*-------------------------------------------------------------------------
*
* ResdistributeSubstrateCapacitance--
*
* Results:
* None.
*
* Side Effects:
* takes total capacitance to VDD or GND in a node and distributes
* it onto the new nodes.
*
*-------------------------------------------------------------------------
*/
void
ResDistributeCapacitance(nodelist, totalcap)
resNode *nodelist;
float totalcap;
{
float totalarea = 0, capperarea;
resNode *workingNode;
resElement *rptr;
for (workingNode = nodelist; workingNode != NULL; workingNode = workingNode->rn_more)
{
for (rptr = workingNode->rn_re; rptr != NULL; rptr=rptr->re_nextEl)
if (rptr->re_thisEl->rr_float.rr_area != 0.0)
TxError("Nonnull resistor area\n");
totalarea += workingNode->rn_float.rn_area;
}
if (totalarea == 0)
{
TxError("Error: Node with no area.\n");
return;
}
capperarea = FEMTOTOATTO * totalcap / totalarea;
for (workingNode = nodelist; workingNode != NULL; workingNode = workingNode->rn_more)
workingNode->rn_float.rn_area *= capperarea;
}
/*
*-------------------------------------------------------------------------
*
* ResCalculateChildCapacitance-- calculates capacitance of this node and
* all downstream nodes.
*
* Results: Returns capacitance of this node and children nodes if connected
* to a tree- returns -1 If the subtree contains loops.
*
* Side Effects: Adds RCDelayStuff fields to nodes.
*
*-------------------------------------------------------------------------
*/
float
ResCalculateChildCapacitance(me)
resNode *me;
{
RCDelayStuff *myC;
resElement *workingRes;
resDevice *dev;
float childcap;
tElement *tptr;
int t;
ExtDevice *devptr;
if (me->rn_client != (ClientData) NULL) /* we have a loop */
return(-1);
myC = (RCDelayStuff *) mallocMagic((unsigned) (sizeof(RCDelayStuff)));
me->rn_client = (ClientData) myC;
/* This following assumes that ResDistributeCapacitance has been run */
/* and the the resulting capacitance value is stored in the area field */
myC->rc_Cdownstream = me->rn_float.rn_area;
myC->rc_Tdi = 0.0;
/* get capacitance for all connected gates */
for (tptr = me->rn_te; tptr != NULL; tptr = tptr->te_nextt)
{
dev = tptr->te_thist;
/* Hack for non-Manhattan geometry. Only one side of a split */
/* tile should correspond to a device type. */
if (IsSplit(dev->rd_tile))
{
t = TiGetLeftType(dev->rd_tile);
if (ExtCurStyle->exts_device[t] == NULL)
t = TiGetRightType(dev->rd_tile);
}
else
t = TiGetType(dev->rd_tile);
if (dev->rd_fet_gate == me)
{
devptr = ExtCurStyle->exts_device[t];
myC->rc_Cdownstream += dev->rd_length * dev->rd_width *
devptr->exts_deviceGateCap +
(dev->rd_width + dev->rd_width) *
devptr->exts_deviceSDCap;
}
}
/* Calculate child Capacitance */
for (workingRes = me->rn_re; workingRes != NULL; workingRes = workingRes->re_nextEl)
{
if (workingRes->re_thisEl->rr_connection1 == me &&
(workingRes->re_thisEl->rr_status & RES_TDI_IGNORE) == 0)
{
childcap = ResCalculateChildCapacitance(workingRes->re_thisEl->rr_connection2);
if (childcap == -1)
return(-1);
myC->rc_Cdownstream += childcap;
}
}
return (myC->rc_Cdownstream);
}
/*
*-------------------------------------------------------------------------
*
* ResCalculateTDi- Calculates TDi numbers for all the nodes in the circuit.
*
* Results: none
*
* Side Effects: sets the rc_Tdi fields of the RCDelayStuff fields of the
* nodes.
*
*-------------------------------------------------------------------------
*/
void
ResCalculateTDi(node, resistor, resistorvalue)
resNode *node;
resResistor *resistor;
int resistorvalue;
{
resElement *workingRes;
RCDelayStuff *rcd = (RCDelayStuff *)node->rn_client;
RCDelayStuff *rcd2;
ASSERT(rcd != NULL, "ResCalculateTdi");
if (resistor == NULL)
rcd->rc_Tdi = rcd->rc_Cdownstream*(float)resistorvalue;
else
{
rcd2 = (RCDelayStuff *)resistor->rr_connection1->rn_client;
ASSERT(rcd2 != NULL,"ResCalculateTdi");
rcd->rc_Tdi = rcd->rc_Cdownstream * (float)resistor->rr_value +
rcd2->rc_Tdi;
}
for (workingRes = node->rn_re; workingRes != NULL; workingRes = workingRes->re_nextEl)
{
if (workingRes->re_thisEl->rr_connection1 == node &&
(workingRes->re_thisEl->rr_status & RES_TDI_IGNORE) == 0)
ResCalculateTDi(workingRes->re_thisEl->rr_connection2,
workingRes->re_thisEl,
workingRes->re_thisEl->rr_value);
}
}
/*
*-------------------------------------------------------------------------
*
* ResPruneTree-- Designed to be run just after ResCalculateTDi to prune all
* branches off the tree whose end node value of Tdi is less than the
* tolerance. This eliminates many resistors in nets with high fanout.
*
* Results: none
*
* Side Effects: May Eliminate Resistors and Merge Nodes
*
*-------------------------------------------------------------------------
*/
void
ResPruneTree(node, minTdi, nodelist1, nodelist2, resistorlist)
resNode *node, **nodelist1, **nodelist2;
float minTdi;
resResistor **resistorlist;
{
resResistor *currentRes;
resElement *current;
current = node->rn_re;
while(current != NULL)
{
currentRes = current->re_thisEl;
current = current->re_nextEl;
/* if branch points outward, call routine on subtrees */
if (currentRes->rr_connection1 == node)
ResPruneTree(currentRes->rr_connection2, minTdi, nodelist1,
nodelist2, resistorlist);
}
/* We eliminate this branch if:
* 1. It is a terminal node, i.e. it is the connected
* to only one resistor.
* 2. The direction of this resistor is toward the node
* (This prevents the root from being eliminated
* 3. The time constant TDI is less than the tolerance.
*/
if (node->rn_re != NULL &&
node->rn_re->re_nextEl == NULL &&
node->rn_re->re_thisEl->rr_connection2 == node)
{
if (node->rn_client == (ClientData)NULL)
{
TxError("Internal Error in Tree Pruning: Missing TDi value.\n");
}
else if (((RCDelayStuff *)(node->rn_client))->rc_Tdi < minTdi)
{
currentRes = node->rn_re->re_thisEl;
ResDeleteResPointer(currentRes->rr_connection1, currentRes);
ResDeleteResPointer(currentRes->rr_connection2, currentRes);
ResMergeNodes(currentRes->rr_connection1, currentRes->rr_connection2,
nodelist2, nodelist1);
ResEliminateResistor(currentRes, resistorlist);
}
}
}
/*
*-------------------------------------------------------------------------
*
*-------------------------------------------------------------------------
*/
int
ResDoSimplify(tolerance, rctol, goodies)
float tolerance;
float rctol;
ResGlobalParams *goodies;
{
resNode *node, *slownode;
float bigres = 0;
float millitolerance;
float totalcap;
resResistor *res;
resRemoveLoops = FALSE;
ResSetPathRes();
for (node = ResNodeList; node != NULL; node = node->rn_more)
bigres = MAX(bigres, node->rn_noderes);
bigres /= OHMSTOMILLIOHMS; /* convert from milliohms to ohms */
goodies->rg_maxres = bigres;
#ifdef PARANOID
ResSanityChecks("ExtractSingleNet", ResResList, ResNodeList, ResDevList);
#endif
/* Is extracted network still greater than the tolerance? */
/* Even if it isn't, we still let the next section run if */
/* we're calculating lumped values so that the capacitance */
/* values get calculated correctly. */
(void) ResDistributeCapacitance(ResNodeList,goodies->rg_nodecap);
if (((tolerance > bigres) || ((ResOptionsFlags & ResOpt_Simplify) == 0)) &&
((ResOptionsFlags & ResOpt_DoLumpFile) == 0))
return 0;
res = ResResList;
while (res)
{
resResistor *oldres = res;
res = res->rr_nextResistor;
oldres->rr_status &= ~RES_HEAP;
if (oldres->rr_status & RES_TDI_IGNORE)
{
ResDeleteResPointer(oldres->rr_node[0], oldres);
ResDeleteResPointer(oldres->rr_node[1], oldres);
ResEliminateResistor(oldres, &ResResList);
}
}
if (ResOptionsFlags & ResOpt_Tdi)
{
if (goodies->rg_nodecap != -1 &&
(totalcap = ResCalculateChildCapacitance(ResOriginNode)) != -1)
{
RCDelayStuff *rc = (RCDelayStuff *) ResNodeList->rn_client;
goodies->rg_nodecap = totalcap;
ResCalculateTDi(ResOriginNode, (resResistor *)NULL,
goodies->rg_bigdevres);
if (rc != (RCDelayStuff *)NULL)
goodies->rg_Tdi = rc->rc_Tdi;
else
goodies->rg_Tdi = 0;
slownode = ResNodeList;
for (node = ResNodeList; node != NULL; node = node->rn_more)
{
rc = (RCDelayStuff *)node->rn_client;
if ((rc != NULL) && (goodies->rg_Tdi < rc->rc_Tdi))
{
slownode = node;
goodies->rg_Tdi = rc->rc_Tdi;
}
}
slownode->rn_status |= RN_MAXTDI;
}
else
goodies->rg_Tdi = -1;
}
else
goodies->rg_Tdi = 0;
if ((rctol+1) * goodies->rg_bigdevres * goodies->rg_nodecap >
rctol * goodies->rg_Tdi &&
(ResOptionsFlags & ResOpt_Tdi) &&
goodies->rg_Tdi != -1)
return 0;
/* Simplify network; resistors are still in milliohms, so use
* millitolerance.
*/
if (ResOptionsFlags & ResOpt_Simplify)
{
millitolerance = tolerance * MILLIOHMSPEROHM;
/*
* Start simplification at driver (R=0). Remove it from the done list
* and add it to the pending list. Call ResSimplifyNet as long as
* nodes remain in the pending list.
*/
for (node = ResNodeList; node != NULL; node = node->rn_more)
{
if (node->rn_noderes == 0)
ResOriginNode = node;
node->rn_status |= FINISHED;
}
if (ResOriginNode != NULL)
{
/* if Tdi is enabled, prune all branches whose end nodes */
/* have time constants less than the tolerance. */
if ((ResOptionsFlags & ResOpt_Tdi) &&
goodies->rg_Tdi != -1 &&
rctol != 0)
{
ResPruneTree(ResOriginNode, (rctol + 1) *
goodies->rg_bigdevres * goodies->rg_nodecap / rctol,
&ResNodeList, &ResNodeQueue, &ResResList);
}
ResOriginNode->rn_status &= ~MARKED;
if (ResOriginNode->rn_less == NULL)
ResNodeList = ResOriginNode->rn_more;
else
ResOriginNode->rn_less->rn_more = ResOriginNode->rn_more;
if (ResOriginNode->rn_more != NULL)
ResOriginNode->rn_more->rn_less = ResOriginNode->rn_less;
ResOriginNode->rn_more = NULL;
ResOriginNode->rn_less = NULL;
ResNodeQueue = ResOriginNode;
while (ResNodeQueue != NULL)
ResSimplifyNet(&ResNodeQueue, &ResNodeList, &ResResList, millitolerance);
/*
* Call ResScrunchNet to eliminate any remaining under tolerance
* resistors.
*/
ResScrunchNet(&ResResList, &ResNodeQueue, &ResNodeList, millitolerance);
}
}
return 0;
}
/*
*-------------------------------------------------------------------------
*
*-------------------------------------------------------------------------
*/
void
ResSetPathRes()
{
HeapEntry he;
resNode *node;
static int init = 1;
if (init)
{
init = 0;
HeapInit(&ResistorHeap, 128, FALSE, FALSE);
}
for (node = ResNodeList; node != NULL; node = node->rn_more)
{
if (node->rn_noderes == 0)
{
ResOriginNode = node;
node->rn_status |= FINISHED;
}
else
{
node->rn_noderes = RES_INFINITY;
node->rn_status &= ~FINISHED;
}
}
if (ResOriginNode == NULL)
{
resDevice *res = ResGetDevice(gparams.rg_devloc);
ResOriginNode = res->rd_fet_source;
ResOriginNode->rn_why = RES_NODE_ORIGIN;
ResOriginNode->rn_noderes = 0;
}
ASSERT(ResOriginNode != NULL, "ResDoSimplify");
resPathNode(ResOriginNode);
while (HeapRemoveTop(&ResistorHeap,&he))
resPathRes((resResistor *)he.he_id);
}
/*
*-------------------------------------------------------------------------
*
*-------------------------------------------------------------------------
*/
void
resPathNode(node)
resNode *node;
{
resElement *re;
node->rn_status |= FINISHED;
for (re = node->rn_re; re; re = re->re_nextEl)
{
resResistor *res = re->re_thisEl;
resNode *node2;
if (res->rr_status & RES_HEAP) continue;
if ((node2 = res->rr_node[0]) == node) node2 = res->rr_node[1];
if ((node2->rn_status & FINISHED) == 0)
HeapAddInt(&ResistorHeap, node->rn_noderes + res->rr_value,
(char *)res);
}
}
/*
*-------------------------------------------------------------------------
*
*-------------------------------------------------------------------------
*/
void
resPathRes(res)
resResistor *res;
{
resNode *node0, *node1;
int flag0, flag1;
res->rr_status |= RES_HEAP;
res->rr_status &= ~RES_MARKED;
node0 = res->rr_node[0];
node1 = res->rr_node[1];
flag0 = node0->rn_status & FINISHED;
flag1 = node1->rn_status & FINISHED;
if (flag0 && flag1)
{
res->rr_status |= RES_TDI_IGNORE;
if (resRemoveLoops)
{
ResDeleteResPointer(node0, res);
ResDeleteResPointer(node1, res);
ResEliminateResistor(res, &ResResList);
}
}
else if (flag0)
{
node1->rn_noderes = node0->rn_noderes + res->rr_value;
resPathNode(node1);
}
else
{
ASSERT(flag1, "ResPathRes");
res->rr_node[0] = node1;
res->rr_node[1] = node0;
node0->rn_noderes = node1->rn_noderes + res->rr_value;
resPathNode(node0);
}
}