/* *------------------------------------------------------------------------- * * 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 #include #include #include #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); } }