mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-09-05 00:50:50 +02:00
a resistor subnet has been linked to itself (or something like that). Otherwise it leads to a double-free and a crash. This commit does not address why the subnet was linked to itself, and the crash was preceded by another internal diagnostic message "Missing rptr at ..." which has been noted before but still needs to be tracked down and fixed. It is likely that a bad output netlist was created, but at least magic doesn't segfault.
1254 lines
34 KiB
C
1254 lines
34 KiB
C
|
|
#ifndef lint
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResMerge.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
|
#endif /* not lint */
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "utils/magic.h"
|
|
#include "utils/geometry.h"
|
|
#include "utils/geofast.h"
|
|
#include "tiles/tile.h"
|
|
#include "utils/hash.h"
|
|
#include "database/database.h"
|
|
#include "utils/malloc.h"
|
|
#include "textio/textio.h"
|
|
#include "extract/extractInt.h"
|
|
#include "resis/resis.h"
|
|
|
|
TileTypeBitMask ResNoMergeMask[NT];
|
|
|
|
/* Forward declarations */
|
|
|
|
extern void ResMergeNodes();
|
|
extern void ResDeleteResPointer();
|
|
extern void ResEliminateResistor();
|
|
extern void ResCleanNode();
|
|
extern void ResFixBreakPoint();
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* ResDoneWithNode--
|
|
* After all connections to node are made, ResDoneWithNode is
|
|
* called. It checks for parallel, series, loop, triangle, and
|
|
* single conections, and simplifies the network where possible.
|
|
*
|
|
* Results: none
|
|
*
|
|
* Side Effects: deletes resistors and/or nodes.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
ResDoneWithNode(resptr)
|
|
resNode *resptr;
|
|
|
|
{
|
|
int status;
|
|
resNode *resptr2;
|
|
resElement *rcell1;
|
|
resResistor *rr1;
|
|
|
|
resptr2 = NULL;
|
|
resptr->rn_status |= RES_TRUE;
|
|
status = UNTOUCHED;
|
|
|
|
/* are there any resistors? */
|
|
|
|
if (resptr->rn_re == NULL) return;
|
|
|
|
/* Special handling for geometry option */
|
|
|
|
if (ResOptionsFlags & ResOpt_Geometry) return;
|
|
|
|
/* Eliminate resistors with connections to one terminal and */
|
|
/* resistors with value 0. */
|
|
|
|
for (rcell1 = resptr->rn_re; rcell1 != NULL; rcell1 = rcell1->re_nextEl)
|
|
{
|
|
rr1 = rcell1->re_thisEl;
|
|
if (rr1->rr_connection1 == rr1->rr_connection2)
|
|
{
|
|
ResDeleteResPointer(resptr, rr1);
|
|
ResDeleteResPointer(resptr, rr1);
|
|
resptr->rn_float.rn_area += rr1->rr_float.rr_area;
|
|
ResEliminateResistor(rr1, &ResResList);
|
|
status = LOOP;
|
|
ResDoneWithNode(resptr);
|
|
break;
|
|
|
|
}
|
|
else if (rr1->rr_value == 0)
|
|
{
|
|
ResDeleteResPointer(rr1->rr_connection1, rr1);
|
|
ResDeleteResPointer(rr1->rr_connection2, rr1);
|
|
if (rr1->rr_connection1 == resptr)
|
|
resptr2 = rr1->rr_connection2;
|
|
else
|
|
resptr2 = rr1->rr_connection1;
|
|
|
|
ResMergeNodes(resptr2, resptr, &ResNodeQueue, &ResNodeList);
|
|
resptr2->rn_float.rn_area += rr1->rr_float.rr_area;
|
|
ResEliminateResistor(rr1, &ResResList);
|
|
if ((resptr2->rn_status & RES_TRUE) == RES_TRUE)
|
|
{
|
|
resptr2->rn_status &= ~RES_TRUE;
|
|
ResDoneWithNode(resptr2);
|
|
}
|
|
resptr2 = NULL;
|
|
status = SINGLE;
|
|
break;
|
|
}
|
|
}
|
|
if (status != UNTOUCHED) return; /* resptr may be invalid */
|
|
|
|
/* Eliminations that can be only if there are no devices connected */
|
|
/* to node. Series and dangling connections fall in this group. */
|
|
|
|
if ((status == UNTOUCHED) && (resptr->rn_te == NULL) &&
|
|
!(resptr->rn_why & (RES_NODE_ORIGIN | RES_NODE_SINK)))
|
|
status = ResSeriesCheck(resptr);
|
|
|
|
if ((status == UNTOUCHED) &&
|
|
!(resptr->rn_why & (RES_NODE_ORIGIN | RES_NODE_SINK)))
|
|
status = ResParallelCheck(resptr);
|
|
|
|
if ((status == UNTOUCHED) &&
|
|
!(resptr->rn_why & (RES_NODE_ORIGIN | RES_NODE_SINK)))
|
|
status = ResTriangleCheck(resptr);
|
|
}
|
|
|
|
|
|
/*
|
|
*------------------------------------------------------------------------
|
|
*
|
|
* ResFixRes--
|
|
*
|
|
* Results: none
|
|
*
|
|
* Side Effects: ResFixRes combines two resistors in series. the second
|
|
* Resistor is eliminated. Resptr is the node that is "cut out" of the
|
|
* network.
|
|
*
|
|
*------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
ResFixRes(resptr, resptr2, resptr3, elimResis, newResis)
|
|
resNode *resptr, *resptr2, *resptr3;
|
|
resResistor *elimResis, *newResis;
|
|
|
|
{
|
|
resElement *thisREl;
|
|
|
|
resptr3->rn_float.rn_area += newResis->rr_value * resptr->rn_float.rn_area
|
|
/ ((float)(newResis->rr_value + elimResis->rr_value));
|
|
resptr2->rn_float.rn_area += elimResis->rr_value * resptr->rn_float.rn_area
|
|
/ ((float)(newResis->rr_value + elimResis->rr_value));
|
|
newResis->rr_value += elimResis->rr_value;
|
|
ASSERT(newResis->rr_value > 0, "series");
|
|
newResis->rr_float.rr_area += elimResis->rr_float.rr_area;
|
|
|
|
for (thisREl = resptr3->rn_re; (thisREl != NULL); thisREl = thisREl->re_nextEl)
|
|
{
|
|
if (thisREl->re_thisEl == elimResis)
|
|
{
|
|
(thisREl->re_thisEl = newResis);
|
|
break;
|
|
}
|
|
|
|
}
|
|
if (thisREl == NULL) TxError("Resistor not found in duo\n");
|
|
ResDeleteResPointer(resptr, elimResis);
|
|
ResDeleteResPointer(resptr, newResis);
|
|
ResEliminateResistor(elimResis, &ResResList);
|
|
ResCleanNode(resptr, TRUE, &ResNodeList, &ResNodeQueue);
|
|
}
|
|
|
|
/*
|
|
*------------------------------------------------------------------------
|
|
*
|
|
* ResFixParallel--
|
|
*
|
|
* Results: none
|
|
*
|
|
* Side Effects: ResFixParallel combines two resistors in parallel. T
|
|
* The second Resistor is eliminated.
|
|
*
|
|
*
|
|
*------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
ResFixParallel(elimResis, newResis)
|
|
resResistor *elimResis, *newResis;
|
|
|
|
{
|
|
if ((newResis->rr_value + elimResis->rr_value) != 0)
|
|
{
|
|
newResis->rr_value = (((float) newResis->rr_value) *
|
|
((float)elimResis->rr_value)) /
|
|
((float)(newResis->rr_value +
|
|
elimResis->rr_value));
|
|
ASSERT(newResis->rr_value >= 0, "parallel");
|
|
}
|
|
else
|
|
{
|
|
newResis->rr_value = 0;
|
|
}
|
|
newResis->rr_float.rr_area += elimResis->rr_float.rr_area;
|
|
ResDeleteResPointer(elimResis->rr_connection1, elimResis);
|
|
ResDeleteResPointer(elimResis->rr_connection2, elimResis);
|
|
ResEliminateResistor(elimResis, &ResResList);
|
|
}
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* ResSeriesCheck -- for nodes with no devices, sees if a series
|
|
* or loop combination is possible.
|
|
*
|
|
* Results: returns SINGLE, LOOP, or SERIES if succesful.
|
|
*
|
|
* Side Effects: may delete some nodes and resistors.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
ResSeriesCheck(resptr)
|
|
resNode *resptr;
|
|
|
|
{
|
|
resResistor *rr1,*rr2;
|
|
resNode *resptr2, *resptr3;
|
|
int status = UNTOUCHED;
|
|
resElement *res_next;
|
|
|
|
rr1 = resptr->rn_re->re_thisEl;
|
|
res_next = resptr->rn_re->re_nextEl;
|
|
|
|
if (res_next == NULL)
|
|
/* node with only one connection */
|
|
{
|
|
resptr2 = (rr1->rr_connection1 == resptr) ? rr1->rr_connection2:
|
|
rr1->rr_connection1;
|
|
|
|
ResDeleteResPointer(rr1->rr_connection1, rr1);
|
|
ResDeleteResPointer(rr1->rr_connection2, rr1);
|
|
resptr2->rn_float.rn_area += rr1->rr_float.rr_area +
|
|
resptr->rn_float.rn_area;
|
|
ResEliminateResistor(rr1, &ResResList);
|
|
ResCleanNode(resptr, TRUE, &ResNodeList, &ResNodeQueue);
|
|
status = SINGLE;
|
|
if (resptr2->rn_status & RES_TRUE)
|
|
{
|
|
resptr2->rn_status &= ~RES_TRUE;
|
|
ResDoneWithNode(resptr2);
|
|
}
|
|
resptr2 = NULL;
|
|
}
|
|
else if (res_next->re_nextEl == NULL)
|
|
{
|
|
rr2 = res_next->re_thisEl;
|
|
if (!TTMaskHasType(ResNoMergeMask + rr1->rr_tt, rr2->rr_tt))
|
|
{
|
|
if (rr1->rr_connection1 == resptr)
|
|
{
|
|
if (rr2->rr_connection1 == resptr)
|
|
{
|
|
resptr2 = rr1->rr_connection2;
|
|
if (rr1 == rr2) /* This should not happen, but does? */
|
|
{
|
|
TxError("Internal error: Resistor linked to itself!\n");
|
|
status = LOOP;
|
|
ResDeleteResPointer(rr2->rr_connection1, rr2);
|
|
ResDeleteResPointer(rr2->rr_connection2, rr2);
|
|
resptr2->rn_float.rn_area += rr2->rr_float.rr_area
|
|
+ rr2->rr_float.rr_area
|
|
+ resptr->rn_float.rn_area;
|
|
ResEliminateResistor(rr2, &ResResList);
|
|
ResCleanNode(resptr, TRUE, &ResNodeList, &ResNodeQueue);
|
|
}
|
|
else if (rr1->rr_connection2 == rr2->rr_connection2)
|
|
{
|
|
status = LOOP;
|
|
ResDeleteResPointer(rr1->rr_connection1, rr1);
|
|
ResDeleteResPointer(rr1->rr_connection2, rr1);
|
|
ResDeleteResPointer(rr2->rr_connection1, rr2);
|
|
ResDeleteResPointer(rr2->rr_connection2, rr2);
|
|
resptr2->rn_float.rn_area += rr1->rr_float.rr_area
|
|
+ rr2->rr_float.rr_area
|
|
+ resptr->rn_float.rn_area;
|
|
ResEliminateResistor(rr1, &ResResList);
|
|
ResEliminateResistor(rr2, &ResResList);
|
|
ResCleanNode(resptr, TRUE, &ResNodeList, &ResNodeQueue);
|
|
}
|
|
else
|
|
{
|
|
status = SERIES;
|
|
resptr3 = rr2->rr_connection2;
|
|
rr1->rr_connection1 = rr2->rr_connection2;
|
|
ResFixRes(resptr, resptr2, resptr3, rr2, rr1);
|
|
}
|
|
if ((resptr2->rn_status & RES_TRUE) == RES_TRUE)
|
|
{
|
|
resptr2->rn_status &= ~RES_TRUE;
|
|
ResDoneWithNode(resptr2);
|
|
}
|
|
resptr2 = NULL;
|
|
}
|
|
else
|
|
{
|
|
resptr2 = rr1->rr_connection2;
|
|
if (rr1->rr_connection2 == rr2->rr_connection1)
|
|
{
|
|
status = LOOP;
|
|
ResDeleteResPointer(rr1->rr_connection1, rr1);
|
|
ResDeleteResPointer(rr1->rr_connection2, rr1);
|
|
ResDeleteResPointer(rr2->rr_connection1, rr2);
|
|
ResDeleteResPointer(rr2->rr_connection2, rr2);
|
|
resptr2->rn_float.rn_area += rr1->rr_float.rr_area
|
|
+ rr2->rr_float.rr_area
|
|
+ resptr->rn_float.rn_area;
|
|
ResEliminateResistor(rr1, &ResResList);
|
|
ResEliminateResistor(rr2, &ResResList);
|
|
ResCleanNode(resptr, TRUE, &ResNodeList, &ResNodeQueue);
|
|
}
|
|
else
|
|
{
|
|
status = SERIES;
|
|
resptr3 = rr2->rr_connection1;
|
|
rr1->rr_connection1 = rr2->rr_connection1;
|
|
ResFixRes(resptr, resptr2, resptr3, rr2, rr1);
|
|
}
|
|
if ((resptr2->rn_status & RES_TRUE) == RES_TRUE)
|
|
{
|
|
resptr2->rn_status &= ~RES_TRUE;
|
|
ResDoneWithNode(resptr2);
|
|
}
|
|
resptr2 = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (rr2->rr_connection1 == resptr)
|
|
{
|
|
resptr2 = rr1->rr_connection1;
|
|
if (rr1->rr_connection1 == rr2->rr_connection2)
|
|
{
|
|
status = LOOP;
|
|
ResDeleteResPointer(rr1->rr_connection1, rr1);
|
|
ResDeleteResPointer(rr1->rr_connection2, rr1);
|
|
ResDeleteResPointer(rr2->rr_connection1, rr2);
|
|
ResDeleteResPointer(rr2->rr_connection2, rr2);
|
|
resptr2->rn_float.rn_area += rr1->rr_float.rr_area
|
|
+ rr2->rr_float.rr_area
|
|
+ resptr->rn_float.rn_area;
|
|
ResEliminateResistor(rr1, &ResResList);
|
|
ResEliminateResistor(rr2, &ResResList);
|
|
ResCleanNode(resptr, TRUE, &ResNodeList, &ResNodeQueue);
|
|
}
|
|
else
|
|
{
|
|
status = SERIES;
|
|
resptr3 = rr2->rr_connection2;
|
|
rr1->rr_connection2 = rr2->rr_connection2;
|
|
ResFixRes(resptr, resptr2, resptr3, rr2, rr1);
|
|
}
|
|
if ((resptr2->rn_status & RES_TRUE) == RES_TRUE)
|
|
{
|
|
resptr2->rn_status &= ~RES_TRUE;
|
|
ResDoneWithNode(resptr2);
|
|
}
|
|
resptr2 = NULL;
|
|
}
|
|
else
|
|
{
|
|
resptr2 = rr1->rr_connection1;
|
|
if (rr1->rr_connection1 == rr2->rr_connection1)
|
|
{
|
|
status = LOOP;
|
|
ResDeleteResPointer(rr1->rr_connection1, rr1);
|
|
ResDeleteResPointer(rr1->rr_connection2, rr1);
|
|
ResDeleteResPointer(rr2->rr_connection1, rr2);
|
|
ResDeleteResPointer(rr2->rr_connection2, rr2);
|
|
resptr2->rn_float.rn_area += rr1->rr_float.rr_area
|
|
+ rr2->rr_float.rr_area
|
|
+ resptr->rn_float.rn_area;
|
|
ResEliminateResistor(rr1, &ResResList);
|
|
ResEliminateResistor(rr2, &ResResList);
|
|
ResCleanNode(resptr, TRUE, &ResNodeList, &ResNodeQueue);
|
|
}
|
|
else
|
|
{
|
|
status = SERIES;
|
|
resptr3 = rr2->rr_connection1;
|
|
rr1->rr_connection2 = rr2->rr_connection1;
|
|
ResFixRes(resptr, resptr2, resptr3, rr2, rr1);
|
|
}
|
|
if ((resptr2->rn_status & RES_TRUE) == RES_TRUE)
|
|
{
|
|
resptr2->rn_status &= ~RES_TRUE;
|
|
ResDoneWithNode(resptr2);
|
|
}
|
|
resptr2 = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* ResParallelCheck -- tries to do parallel combinations of devices.
|
|
*
|
|
* Results: returns PARALLEL if successful
|
|
*
|
|
* Side Effects: may delete resistors and nodes.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
ResParallelCheck(resptr)
|
|
resNode *resptr;
|
|
{
|
|
resResistor *r1, *r2;
|
|
resNode *resptr2, *resptr3;
|
|
int status = UNTOUCHED;
|
|
resElement *rcell1, *rcell2;
|
|
|
|
int rcount = 0;
|
|
|
|
/* When the number of resistors gets to be large enough, it is more efficient to
|
|
* sort the resistor list and then do a single pass to see if any two consecutive
|
|
* items in the sorted list can be merged, than to do a double loop through the
|
|
* resistor list at ~O(N^2).
|
|
*/
|
|
|
|
for (rcell1 = resptr->rn_re; rcell1 != NULL; rcell1 = rcell1->re_nextEl)
|
|
{
|
|
rcount++;
|
|
if (rcount >= 10) break;
|
|
}
|
|
|
|
if (rcount >= 10)
|
|
{
|
|
HashTable NodeResTable;
|
|
HashEntry *he;
|
|
|
|
/* Hash the connections */
|
|
HashInit(&NodeResTable, HT_DEFAULTSIZE, HT_WORDKEYS);
|
|
|
|
for (rcell2 = resptr->rn_re; rcell2 != NULL; rcell2 = rcell2->re_nextEl)
|
|
{
|
|
/* One connection is always resptr; find the other one */
|
|
resptr3 = rcell2->re_thisEl->rr_connection1;
|
|
if (resptr3 == resptr) resptr3 = rcell2->re_thisEl->rr_connection2;
|
|
|
|
he = HashFind(&NodeResTable, (char *)resptr3);
|
|
if ((rcell1 = (resElement*)HashGetValue(he)))
|
|
{
|
|
r1 = rcell1->re_thisEl;
|
|
r2 = rcell2->re_thisEl;
|
|
|
|
if (TTMaskHasType(ResNoMergeMask+r1->rr_tt, r2->rr_tt)) continue;
|
|
|
|
ResFixParallel(r1, r2);
|
|
status = PARALLEL;
|
|
resptr2 = NULL;
|
|
if (resptr3->rn_status & RES_TRUE)
|
|
{
|
|
resptr2 = resptr3;
|
|
resptr2->rn_status &= ~RES_TRUE;
|
|
}
|
|
ResDoneWithNode(resptr);
|
|
if (resptr2 != NULL) ResDoneWithNode(resptr2);
|
|
break;
|
|
}
|
|
else
|
|
HashSetValue(he, (char *)rcell2);
|
|
}
|
|
HashKill(&NodeResTable);
|
|
return status;
|
|
}
|
|
|
|
/* This does the same thing as above, but for a small number of resistors
|
|
* per node, it avoids the overhead of creating and destroying hash tables.
|
|
*/
|
|
|
|
for (rcell1 = resptr->rn_re; rcell1->re_nextEl != NULL;
|
|
rcell1 = rcell1->re_nextEl)
|
|
{
|
|
r1 = rcell1->re_thisEl;
|
|
|
|
for (rcell2 = rcell1->re_nextEl; rcell2 != NULL;
|
|
rcell2 = rcell2->re_nextEl)
|
|
|
|
{
|
|
r2 = rcell2->re_thisEl;
|
|
if (TTMaskHasType(ResNoMergeMask+r1->rr_tt, r2->rr_tt)) continue;
|
|
if (((r1->rr_connection1 == r2->rr_connection1) &&
|
|
(r1->rr_connection2 == r2->rr_connection2))||
|
|
((r1->rr_connection1 == r2->rr_connection2) &&
|
|
(r1->rr_connection2 == r2->rr_connection1)))
|
|
{
|
|
resptr3 = (r1->rr_connection1 == resptr) ?
|
|
r1->rr_connection2 : r1->rr_connection1;
|
|
ResFixParallel(r1, r2);
|
|
status = PARALLEL;
|
|
resptr2 = NULL;
|
|
if (resptr3->rn_status & RES_TRUE)
|
|
{
|
|
resptr2 = resptr3;
|
|
resptr2->rn_status &= ~RES_TRUE;
|
|
}
|
|
ResDoneWithNode(resptr);
|
|
if (resptr2 != NULL) ResDoneWithNode(resptr2);
|
|
break;
|
|
}
|
|
}
|
|
if (status == PARALLEL) break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* ResTriangleCheck -- looks for places to do the traingle-to-Y conversion.
|
|
*
|
|
* Results: returns TRIANGLE if successful.
|
|
*
|
|
* Side Effects: may allocate a new node.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
ResTriangleCheck(resptr)
|
|
resNode *resptr;
|
|
|
|
{
|
|
resResistor *rr1, *rr2, *rr3;
|
|
int status = UNTOUCHED;
|
|
float r1, r2, r3, denom;
|
|
resNode *n1, *n2, *n3;
|
|
resElement *rcell1, *rcell2, *rcell3, *element;
|
|
int rcount = 0;
|
|
|
|
/* When the size of the linked list of resistors is long, it is faster to
|
|
* hash the neighboring connections and then find the first entry in the
|
|
* neighbor's node list that is another neighbor.
|
|
*/
|
|
for (rcell1 = resptr->rn_re; rcell1 != NULL; rcell1 = rcell1->re_nextEl)
|
|
{
|
|
rcount++;
|
|
if (rcount >= 10) break;
|
|
}
|
|
|
|
if (rcount >= 10)
|
|
{
|
|
HashTable NodeResTable;
|
|
HashEntry *he, *he2;
|
|
HashSearch hs;
|
|
|
|
/* Hash the neighboring connections */
|
|
HashInit(&NodeResTable, HT_DEFAULTSIZE, HT_WORDKEYS);
|
|
|
|
for (rcell2 = resptr->rn_re; rcell2 != NULL; rcell2 = rcell2->re_nextEl)
|
|
{
|
|
rr2 = rcell2->re_thisEl;
|
|
|
|
/* One connection is always resptr; find the other one */
|
|
n2 = rr2->rr_connection1;
|
|
if (n2 == resptr) n2 = rr2->rr_connection2;
|
|
|
|
he = HashFind(&NodeResTable, (char *)n2);
|
|
if (!(rcell1 = (resElement *)HashGetValue(he)))
|
|
HashSetValue(he, (char *)rcell2);
|
|
}
|
|
|
|
HashStartSearch(&hs);
|
|
while ((he = HashNext(&NodeResTable, &hs)))
|
|
{
|
|
/* Get each node that neighbors resptr */
|
|
n1 = (resNode *)he->h_key.h_ptr;
|
|
rcell1 = (resElement *)HashGetValue(he);
|
|
rr1 = rcell1->re_thisEl;
|
|
|
|
/* Check the list of resistors of neighbor n1 for any resistor whose
|
|
* other end is also a neighbor of resptr.
|
|
*/
|
|
for (rcell3 = n1->rn_re; rcell3 != NULL; rcell3 = rcell3->re_nextEl)
|
|
{
|
|
rr3 = rcell3->re_thisEl;
|
|
|
|
/* Resistor can't be merged */
|
|
if (TTMaskHasType(ResNoMergeMask + rr1->rr_tt, rr3->rr_tt))
|
|
continue;
|
|
|
|
/* One connection is always n1; find the other one */
|
|
n2 = rr3->rr_connection1;
|
|
if (n2 == n1) n2 = rr3->rr_connection2;
|
|
|
|
he2 = HashLookOnly(&NodeResTable, (char *)n2);
|
|
if (he2)
|
|
{
|
|
/* Found a triangle */
|
|
rcell2 = (resElement *)HashGetValue(he2);
|
|
rr2 = rcell2->re_thisEl;
|
|
|
|
/* . . . But it can't be merged */
|
|
if (TTMaskHasType(ResNoMergeMask + rr1->rr_tt, rr2->rr_tt))
|
|
continue;
|
|
if (TTMaskHasType(ResNoMergeMask + rr2->rr_tt, rr3->rr_tt))
|
|
continue;
|
|
|
|
status = TRIANGLE;
|
|
if ((denom = rr1->rr_value + rr2->rr_value + rr3->rr_value) != 0.0)
|
|
{
|
|
denom = 1.0 /denom;
|
|
/* calculate new values for resistors */
|
|
r1 = (((float)rr1->rr_value) * ((float)rr2->rr_value)) * denom;
|
|
r2 = (((float)rr2->rr_value) * ((float)rr3->rr_value)) * denom;
|
|
r3 = (((float)rr1->rr_value) * ((float)rr3->rr_value)) * denom;
|
|
|
|
rr1->rr_value = r1 + 0.5;
|
|
rr2->rr_value = r2 + 0.5;
|
|
rr3->rr_value = r3 + 0.5;
|
|
ASSERT(rr1->rr_value >= 0, "Triangle");
|
|
ASSERT(rr2->rr_value >= 0, "Triangle");
|
|
ASSERT(rr3->rr_value >= 0, "Triangle");
|
|
}
|
|
else
|
|
{
|
|
rr1->rr_value = 0;
|
|
rr2->rr_value = 0;
|
|
rr3->rr_value = 0;
|
|
}
|
|
n3 = (resNode *)mallocMagic((unsigned)(sizeof(resNode)));
|
|
|
|
/* Where should the new node be put? It */
|
|
/* is arbitrarily assigned to the location */
|
|
/* occupied by the first node. */
|
|
|
|
InitializeResNode(n3, resptr->rn_loc.p_x, resptr->rn_loc.p_y, TRIANGLE);
|
|
n3->rn_status = RES_FINISHED | RES_TRUE | RES_MARKED;
|
|
|
|
n3->rn_less = NULL;
|
|
n3->rn_more = ResNodeList;
|
|
ResNodeList->rn_less = n3;
|
|
ResNodeList = n3;
|
|
if (resptr == rr1->rr_connection1)
|
|
{
|
|
ResDeleteResPointer(rr1->rr_connection2, rr1);
|
|
rr1->rr_connection2 = n3;
|
|
}
|
|
else
|
|
{
|
|
ResDeleteResPointer(rr1->rr_connection1, rr1);
|
|
rr1->rr_connection1 = n3;
|
|
}
|
|
if (n2 == rr2->rr_connection1)
|
|
{
|
|
ResDeleteResPointer(rr2->rr_connection2, rr2);
|
|
rr2->rr_connection2 = n3;
|
|
}
|
|
else
|
|
{
|
|
ResDeleteResPointer(rr2->rr_connection1, rr2);
|
|
rr2->rr_connection1 = n3;
|
|
}
|
|
if (n1 == rr3->rr_connection1)
|
|
{
|
|
ResDeleteResPointer(rr3->rr_connection2, rr3);
|
|
rr3->rr_connection2 = n3;
|
|
}
|
|
else
|
|
{
|
|
ResDeleteResPointer(rr3->rr_connection1, rr3);
|
|
rr3->rr_connection1 = n3;
|
|
}
|
|
element = (resElement *)mallocMagic((unsigned)(sizeof(resElement)));
|
|
element->re_nextEl = NULL;
|
|
element->re_thisEl = rr1;
|
|
n3->rn_re = element;
|
|
element = (resElement *)mallocMagic((unsigned)(sizeof(resElement)));
|
|
element->re_nextEl = n3->rn_re;
|
|
element->re_thisEl = rr2;
|
|
n3->rn_re = element;
|
|
element = (resElement *)mallocMagic((unsigned)(sizeof(resElement)));
|
|
element->re_nextEl = n3->rn_re;
|
|
element->re_thisEl = rr3;
|
|
n3->rn_re = element;
|
|
if ((n1->rn_status & RES_TRUE) == RES_TRUE)
|
|
n1->rn_status &= ~RES_TRUE;
|
|
else
|
|
n1 = NULL;
|
|
|
|
if ((n2->rn_status & RES_TRUE) == RES_TRUE)
|
|
n2->rn_status &= ~RES_TRUE;
|
|
else
|
|
n2 = NULL;
|
|
|
|
ResDoneWithNode(resptr);
|
|
if (n1 != NULL) ResDoneWithNode(n1);
|
|
if (n2 != NULL) ResDoneWithNode(n2);
|
|
break;
|
|
}
|
|
}
|
|
if (status == TRIANGLE) break;
|
|
}
|
|
|
|
HashKill(&NodeResTable);
|
|
return status;
|
|
}
|
|
|
|
/* This does the same thing as above, but for a small number of resistors
|
|
* per node, avoiding the overhead of creating and destroying hash tables.
|
|
*/
|
|
|
|
for (rcell1 = resptr->rn_re; rcell1->re_nextEl != NULL;
|
|
rcell1 = rcell1->re_nextEl)
|
|
{
|
|
rr1 = rcell1->re_thisEl;
|
|
n1 = (rr1->rr_connection1 == resptr) ? rr1->rr_connection2:
|
|
rr1->rr_connection1;
|
|
|
|
for (rcell2 = rcell1->re_nextEl; rcell2 != NULL;
|
|
rcell2 = rcell2->re_nextEl)
|
|
{
|
|
rr2 = rcell2->re_thisEl;
|
|
if (TTMaskHasType(ResNoMergeMask + rr1->rr_tt, rr2->rr_tt))
|
|
continue;
|
|
n2 = (rr2->rr_connection1 == resptr) ? rr2->rr_connection2 :
|
|
rr2->rr_connection1;
|
|
for (rcell3 = n1->rn_re; rcell3 != NULL;
|
|
rcell3 = rcell3->re_nextEl)
|
|
{
|
|
rr3 = rcell3->re_thisEl;
|
|
if (TTMaskHasType(ResNoMergeMask + rr1->rr_tt, rr3->rr_tt))
|
|
continue;
|
|
if (TTMaskHasType(ResNoMergeMask + rr2->rr_tt, rr3->rr_tt))
|
|
continue;
|
|
|
|
if (((rr3->rr_connection1 != n1) ||
|
|
(rr3->rr_connection2 != n2)) &&
|
|
((rr3->rr_connection2 != n1) ||
|
|
(rr3->rr_connection1 != n2))) continue;
|
|
|
|
status = TRIANGLE;
|
|
if ((denom = rr1->rr_value + rr2->rr_value + rr3->rr_value) != 0.0)
|
|
{
|
|
denom = 1.0 /denom;
|
|
/* calculate new values for resistors */
|
|
r1 = (((float)rr1->rr_value) * ((float)rr2->rr_value)) * denom;
|
|
|
|
r2 = (((float)rr2->rr_value) * ((float)rr3->rr_value)) * denom;
|
|
|
|
r3 = (((float)rr1->rr_value) * ((float)rr3->rr_value)) * denom;
|
|
|
|
rr1->rr_value = r1 + 0.5;
|
|
rr2->rr_value = r2 + 0.5;
|
|
rr3->rr_value = r3 + 0.5;
|
|
ASSERT(rr1->rr_value >= 0, "Triangle");
|
|
ASSERT(rr2->rr_value >= 0, "Triangle");
|
|
ASSERT(rr3->rr_value >= 0, "Triangle");
|
|
}
|
|
else
|
|
{
|
|
rr1->rr_value = 0;
|
|
rr2->rr_value = 0;
|
|
rr3->rr_value = 0;
|
|
}
|
|
n3 = (resNode *)mallocMagic((unsigned)(sizeof(resNode)));
|
|
|
|
/* Where should the new node be put? It */
|
|
/* is arbitrarily assigned to the location */
|
|
/* occupied by the first node. */
|
|
|
|
InitializeResNode(n3, resptr->rn_loc.p_x, resptr->rn_loc.p_y, TRIANGLE);
|
|
n3->rn_status = RES_FINISHED | RES_TRUE | RES_MARKED;
|
|
|
|
n3->rn_less = NULL;
|
|
n3->rn_more = ResNodeList;
|
|
ResNodeList->rn_less = n3;
|
|
ResNodeList = n3;
|
|
if (resptr == rr1->rr_connection1)
|
|
{
|
|
ResDeleteResPointer(rr1->rr_connection2, rr1);
|
|
rr1->rr_connection2 = n3;
|
|
}
|
|
else
|
|
{
|
|
ResDeleteResPointer(rr1->rr_connection1, rr1);
|
|
rr1->rr_connection1 = n3;
|
|
}
|
|
if (n2 == rr2->rr_connection1)
|
|
{
|
|
ResDeleteResPointer(rr2->rr_connection2, rr2);
|
|
rr2->rr_connection2 = n3;
|
|
}
|
|
else
|
|
{
|
|
ResDeleteResPointer(rr2->rr_connection1, rr2);
|
|
rr2->rr_connection1 = n3;
|
|
}
|
|
if (n1 == rr3->rr_connection1)
|
|
{
|
|
ResDeleteResPointer(rr3->rr_connection2, rr3);
|
|
rr3->rr_connection2 = n3;
|
|
}
|
|
else
|
|
{
|
|
ResDeleteResPointer(rr3->rr_connection1, rr3);
|
|
rr3->rr_connection1 = n3;
|
|
}
|
|
element = (resElement *)mallocMagic((unsigned)(sizeof(resElement)));
|
|
element->re_nextEl = NULL;
|
|
element->re_thisEl = rr1;
|
|
n3->rn_re = element;
|
|
element = (resElement *)mallocMagic((unsigned)(sizeof(resElement)));
|
|
element->re_nextEl = n3->rn_re;
|
|
element->re_thisEl = rr2;
|
|
n3->rn_re = element;
|
|
element = (resElement *)mallocMagic((unsigned)(sizeof(resElement)));
|
|
element->re_nextEl = n3->rn_re;
|
|
element->re_thisEl = rr3;
|
|
n3->rn_re = element;
|
|
if ((n1->rn_status & RES_TRUE) == RES_TRUE)
|
|
n1->rn_status &= ~RES_TRUE;
|
|
else
|
|
n1 = NULL;
|
|
|
|
if ((n2->rn_status & RES_TRUE) == RES_TRUE)
|
|
n2->rn_status &= ~RES_TRUE;
|
|
else
|
|
n2 = NULL;
|
|
|
|
ResDoneWithNode(resptr);
|
|
if (n1 != NULL) ResDoneWithNode(n1);
|
|
if (n2 != NULL) ResDoneWithNode(n2);
|
|
break;
|
|
}
|
|
if (status == TRIANGLE) break;
|
|
}
|
|
if (status == TRIANGLE) break;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
*--------------------------------------------------------------------------
|
|
*
|
|
* ResMergeNodes--
|
|
*
|
|
* Results: none
|
|
*
|
|
* Side Effects: appends all the cElement, jElement, tElement and
|
|
* resElement structures from node 2 onto node 1. Node 2 is
|
|
* then eliminated.
|
|
*
|
|
*---------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
ResMergeNodes(node1, node2, pendingList, doneList)
|
|
resNode *node1, *node2;
|
|
resNode **pendingList, **doneList;
|
|
{
|
|
resElement *workingRes, *tRes;
|
|
tElement *workingDev, *tDev;
|
|
jElement *workingJunc, *tJunc;
|
|
cElement *workingCon, *tCon;
|
|
Tile *tile;
|
|
int i;
|
|
|
|
/* sanity check */
|
|
if (node1 == node2) return;
|
|
|
|
if (node1 == NULL || node2 == NULL)
|
|
{
|
|
TxError("Attempt to merge NULL node\n");
|
|
return;
|
|
}
|
|
|
|
/* don't want to merge away start or end points */
|
|
if (node2->rn_why & RES_NODE_ORIGIN)
|
|
node1->rn_why = RES_NODE_ORIGIN;
|
|
|
|
if (node2->rn_why & RES_NODE_SINK)
|
|
node1->rn_why = RES_NODE_SINK;
|
|
|
|
/* set node resistance */
|
|
if (node1->rn_noderes > node2->rn_noderes)
|
|
{
|
|
node1->rn_noderes = node2->rn_noderes;
|
|
if ((node1->rn_status & RES_FINISHED) != RES_FINISHED)
|
|
{
|
|
ResRemoveFromQueue(node1, pendingList);
|
|
ResAddToQueue(node1, pendingList);
|
|
}
|
|
}
|
|
node1->rn_float.rn_area += node2->rn_float.rn_area;
|
|
|
|
/* combine relevant flags */
|
|
node1->rn_status |= (node2->rn_status & RES_MAXTDI);
|
|
|
|
/* merge device lists */
|
|
workingDev = node2->rn_te;
|
|
while (workingDev != NULL)
|
|
{
|
|
int j;
|
|
|
|
for (j = 0; j != workingDev->te_thist->rd_nterms; j++)
|
|
if (workingDev->te_thist->rd_terminals[j] == node2)
|
|
workingDev->te_thist->rd_terminals[j] = node1;
|
|
|
|
tDev = workingDev;
|
|
workingDev = workingDev->te_nextt;
|
|
tDev->te_nextt = node1->rn_te;
|
|
node1->rn_te = tDev;
|
|
}
|
|
|
|
/* append junction lists */
|
|
|
|
workingJunc = node2->rn_je;
|
|
while (workingJunc != NULL)
|
|
{
|
|
tJunc = workingJunc;
|
|
for (i = 0; i < TILES_PER_JUNCTION; i++)
|
|
{
|
|
resInfo *info;
|
|
|
|
tile = tJunc->je_thisj->rj_Tile[i];
|
|
info = (resInfo *) TiGetClientPTR(tile);
|
|
|
|
if ((info->ri_status & RES_TILE_DONE) == FALSE)
|
|
ResFixBreakPoint(&info->breakList, node2, node1);
|
|
}
|
|
tJunc->je_thisj->rj_jnode = node1;
|
|
workingJunc = workingJunc->je_nextj;
|
|
tJunc->je_nextj = node1->rn_je;
|
|
node1->rn_je = tJunc;
|
|
}
|
|
|
|
/* Append connection lists */
|
|
workingCon = node2->rn_ce;
|
|
while (workingCon != NULL)
|
|
{
|
|
tCon = workingCon;
|
|
for (i = 0; i < workingCon->ce_thisc->cp_currentcontact; i++)
|
|
{
|
|
if (workingCon->ce_thisc->cp_cnode[i] == node2)
|
|
{
|
|
resInfo *info;
|
|
|
|
workingCon->ce_thisc->cp_cnode[i] = node1;
|
|
tile =tCon->ce_thisc->cp_tile[i];
|
|
info = (resInfo *) TiGetClientPTR(tile);
|
|
if ((info->ri_status & RES_TILE_DONE) == FALSE)
|
|
ResFixBreakPoint(&info->breakList, node2, node1);
|
|
}
|
|
}
|
|
workingCon = workingCon->ce_nextc;
|
|
tCon->ce_nextc = node1->rn_ce;
|
|
node1->rn_ce = tCon;
|
|
}
|
|
|
|
/* Moves name to new node, if new node does not have a name */
|
|
if (node1->rn_name == NULL)
|
|
node1->rn_name = node2->rn_name;
|
|
else if ((node2->rn_name != NULL) && (node2->rn_name != node1->rn_name))
|
|
{
|
|
HashEntry *entry;
|
|
ResExtNode *node;
|
|
|
|
/* Check if node2 is a port */
|
|
entry = HashFind(&ResNodeTable, node2->rn_name);
|
|
node = (ResExtNode *)HashGetValue(entry);
|
|
if (node && (node->status & PORTNODE))
|
|
node1->rn_name = node2->rn_name;
|
|
}
|
|
|
|
/* Moves resistors to new node */
|
|
|
|
workingRes = node2->rn_re;
|
|
while (workingRes != NULL)
|
|
{
|
|
if (workingRes->re_thisEl->rr_connection1 == node2)
|
|
workingRes->re_thisEl->rr_connection1 = node1;
|
|
else if (workingRes->re_thisEl->rr_connection2 == node2)
|
|
workingRes->re_thisEl->rr_connection2 = node1;
|
|
else
|
|
TxError("Resistor not found.\n");
|
|
|
|
tRes = workingRes;
|
|
workingRes = workingRes->re_nextEl;
|
|
tRes->re_nextEl = node1->rn_re;
|
|
node1->rn_re = tRes;
|
|
}
|
|
if ((node2->rn_status & RES_FINISHED) == RES_FINISHED)
|
|
ResRemoveFromQueue(node2, doneList);
|
|
else
|
|
ResRemoveFromQueue(node2, pendingList);
|
|
|
|
if (node2->rn_client != (ClientData)NULL)
|
|
{
|
|
freeMagic((char *)node2->rn_client);
|
|
node2->rn_client = (ClientData)NULL;
|
|
}
|
|
|
|
/* Don't merge away the ResNodeAtOrigin node */
|
|
if (ResNodeAtOrigin == node2) ResNodeAtOrigin = node1;
|
|
|
|
node2->rn_re = (resElement *)CLIENTDEFAULT;
|
|
node2->rn_ce = (cElement *)CLIENTDEFAULT;
|
|
node2->rn_je = (jElement *)CLIENTDEFAULT;
|
|
node2->rn_te = (tElement *)CLIENTDEFAULT;
|
|
node2->rn_more = (resNode *)CLIENTDEFAULT;
|
|
node2->rn_less = (resNode *)CLIENTDEFAULT;
|
|
freeMagic((char *)node2);
|
|
}
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* ResDeleteResPointer-- Deletes the pointer from a node to a resistor.
|
|
* Used when a resistor is deleted.
|
|
*
|
|
* Results: none
|
|
*
|
|
* Side Effects: Modifies a node's resistor list.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
ResDeleteResPointer(node, resistor)
|
|
resNode *node;
|
|
resResistor *resistor;
|
|
|
|
{
|
|
resElement *rcell1, *rcell2;
|
|
int notfound = TRUE;
|
|
|
|
rcell1 = NULL;
|
|
rcell2 = node->rn_re;
|
|
while (rcell2 != NULL)
|
|
{
|
|
if (rcell2->re_thisEl == resistor)
|
|
{
|
|
notfound = FALSE;
|
|
if (rcell1 != NULL)
|
|
rcell1->re_nextEl = rcell2->re_nextEl;
|
|
else
|
|
node->rn_re = rcell2->re_nextEl;
|
|
|
|
/* Set fields to null just in case there are any stray */
|
|
/* pointers to structure. */
|
|
rcell2->re_thisEl = NULL;
|
|
rcell2->re_nextEl = NULL;
|
|
freeMagic((char *)rcell2);
|
|
break;
|
|
}
|
|
rcell1 = rcell2;
|
|
rcell2 = rcell2->re_nextEl;
|
|
}
|
|
if (notfound)
|
|
TxError("Missing rptr at (%d %d).\n",
|
|
node->rn_loc.p_x, node->rn_loc.p_y);
|
|
}
|
|
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* ResEliminateResistor--
|
|
*
|
|
* Results: none
|
|
*
|
|
* Side Effects: Deletes a resistor. Does not delete pointers from nodes to
|
|
* resistor.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
ResEliminateResistor(resistor, homelist)
|
|
resResistor *resistor, **homelist;
|
|
|
|
{
|
|
if (resistor->rr_lastResistor == NULL)
|
|
*homelist = resistor->rr_nextResistor;
|
|
else
|
|
resistor->rr_lastResistor->rr_nextResistor = resistor->rr_nextResistor;
|
|
|
|
if (resistor->rr_nextResistor != NULL)
|
|
resistor->rr_nextResistor->rr_lastResistor = resistor->rr_lastResistor;
|
|
|
|
/* set everything to null so that any stray pointers will cause */
|
|
/* immediate death instead of a slow lingering one. */
|
|
|
|
resistor->rr_nextResistor = NULL;
|
|
resistor->rr_lastResistor = NULL;
|
|
resistor->rr_connection1 = NULL;
|
|
resistor->rr_connection2 = NULL;
|
|
freeMagic((char *)resistor);
|
|
}
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* ResCleanNode--removes the linked lists of junctions and contacts after
|
|
* they are no longer needed. If the 'info' option is used,
|
|
* the node is eradicated.
|
|
*
|
|
* Results: none.
|
|
*
|
|
* Side Effects: frees memory
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
ResCleanNode(resptr, info, homelist1, homelist2)
|
|
resNode *resptr;
|
|
int info;
|
|
resNode **homelist1;
|
|
resNode **homelist2;
|
|
{
|
|
resElement *rcell;
|
|
cElement *ccell;
|
|
jElement *jcell;
|
|
tElement *tcell;
|
|
|
|
/* free up contact and junction lists */
|
|
while (resptr->rn_ce != NULL)
|
|
{
|
|
ccell = resptr->rn_ce;
|
|
resptr->rn_ce = resptr->rn_ce->ce_nextc;
|
|
freeMagic((char *)ccell);
|
|
}
|
|
while (resptr->rn_je != NULL)
|
|
{
|
|
jcell = resptr->rn_je;
|
|
resptr->rn_je = resptr->rn_je->je_nextj;
|
|
freeMagic((char *)jcell->je_thisj);
|
|
freeMagic((char *)jcell);
|
|
}
|
|
if (info == TRUE)
|
|
{
|
|
if (resptr->rn_client != (ClientData)NULL)
|
|
{
|
|
freeMagic((char *)resptr->rn_client);
|
|
resptr->rn_client = (ClientData)NULL;
|
|
}
|
|
while (resptr->rn_te != NULL)
|
|
{
|
|
tcell = resptr->rn_te;
|
|
resptr->rn_te = resptr->rn_te->te_nextt;
|
|
freeMagic((char *)tcell);
|
|
}
|
|
while (resptr->rn_re != NULL)
|
|
{
|
|
rcell = resptr->rn_re;
|
|
resptr->rn_re = resptr->rn_re->re_nextEl;
|
|
freeMagic((char *)rcell);
|
|
}
|
|
if (resptr->rn_less != NULL)
|
|
resptr->rn_less->rn_more = resptr->rn_more;
|
|
else
|
|
{
|
|
if (*homelist1 == resptr)
|
|
*homelist1 = resptr->rn_more;
|
|
else if (*homelist2 == resptr)
|
|
*homelist2 = resptr->rn_more;
|
|
else
|
|
TxError("Error: Attempted to eliminate node from wrong list.\n");
|
|
}
|
|
if (resptr->rn_more != NULL)
|
|
resptr->rn_more->rn_less = resptr->rn_less;
|
|
|
|
resptr->rn_re = (resElement *) CLIENTDEFAULT;
|
|
resptr->rn_ce = (cElement *) CLIENTDEFAULT;
|
|
resptr->rn_je = (jElement *) CLIENTDEFAULT;
|
|
resptr->rn_te = (tElement *) CLIENTDEFAULT;
|
|
resptr->rn_more = (resNode *) CLIENTDEFAULT;
|
|
resptr->rn_less = (resNode *) CLIENTDEFAULT;
|
|
|
|
freeMagic((char *)resptr);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* ResFixBreakPoint--moves breakpoints from one node to another, checking
|
|
* first to see whether the target node already has the breakpoint.
|
|
* Used when nodes are merged.
|
|
*
|
|
* Results: none
|
|
*
|
|
* Side Effects: may free up memory if breakpoint is already present.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
ResFixBreakPoint(sourcelist, origNode, newNode)
|
|
Breakpoint **sourcelist;
|
|
resNode *origNode, *newNode;
|
|
|
|
{
|
|
Breakpoint *bp, *bp2, *bp3, *bp4;
|
|
int alreadypresent;
|
|
|
|
alreadypresent = FALSE;
|
|
for (bp4 = *sourcelist; bp4 != NULL; bp4 = bp4->br_next)
|
|
{
|
|
if (bp4->br_this == newNode)
|
|
{
|
|
alreadypresent = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
bp2 = NULL;
|
|
bp = *sourcelist;
|
|
while (bp != NULL)
|
|
{
|
|
if (bp->br_this == origNode)
|
|
{
|
|
if (alreadypresent)
|
|
{
|
|
if (bp2 == NULL)
|
|
*sourcelist = bp->br_next;
|
|
else
|
|
bp2->br_next = bp->br_next;
|
|
|
|
bp3 = bp;
|
|
bp = bp->br_next;
|
|
|
|
if (bp3->br_crect != NULL && bp4->br_crect == NULL)
|
|
bp4->br_crect = bp3->br_crect;
|
|
|
|
freeMagic((char *)bp3);
|
|
continue;
|
|
}
|
|
else
|
|
bp->br_this = newNode;
|
|
}
|
|
bp2 = bp;
|
|
bp = bp->br_next;
|
|
}
|
|
}
|