magic/resis/ResSimple.c

1165 lines
32 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
*-------------------------------------------------------------------------
*
* 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,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_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");
}
/* workingNode->rn_float.rn_area += rptr->re_thisEl->rr_float.rr_area/2; */
}
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;
/* get capacitance for all connected gates */
for (tptr = me->rn_te; tptr != NULL; tptr = tptr->te_nextt)
{
dev = tptr->te_thist;
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); /* Patched 7/5/94 */
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 && (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);
}
}