mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-08-30 18:02:32 +02:00
All naked access to `ti_client` now uses the function-like-macro to encapsulate this action. This macro existed before this just makes all sites utilize it. Added additional INT and PTR variants to remove the programmer load on thinking about casing and casts polluting the point of use. So the use now looks cleaner. Equivalent prototypes: void TiSetClient(Tile*, ClientData) void TiSetClientINT(Tile*, intptr_t) /* pointertype */ void TiSetClientPTR(Tile*, void*) ClientData TiGetClient(Tile*) intptr_t TiGetClientINT(Tile*) /* pointertype */ void *TiGetClientPTR(Tile*)
1031 lines
27 KiB
C
1031 lines
27 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 |= RESTRUE;
|
|
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 & RESTRUE) == RESTRUE)
|
|
{
|
|
resptr2->rn_status &= ~RESTRUE;
|
|
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 ((resptr->rn_te == NULL) && (resptr->rn_why != RES_NODE_ORIGIN)
|
|
&& (status == UNTOUCHED))
|
|
status = ResSeriesCheck(resptr);
|
|
|
|
if ((status == UNTOUCHED) && (resptr->rn_why != RES_NODE_ORIGIN))
|
|
status = ResParallelCheck(resptr);
|
|
|
|
if ((status == UNTOUCHED) && (resptr->rn_why != RES_NODE_ORIGIN))
|
|
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;
|
|
|
|
#ifdef ARIEL
|
|
if (elimResis->rr_csArea && elimResis->rr_csArea < newResis->rr_csArea
|
|
|| newResis->rr_csArea == 0)
|
|
{
|
|
newResis->rr_csArea = elimResis->rr_csArea;
|
|
newResis->rr_tt = elimResis->rr_tt;
|
|
}
|
|
#endif
|
|
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;
|
|
#ifdef ARIEL
|
|
newResis->rr_csArea += elimResis->rr_csArea;
|
|
#endif
|
|
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 & RESTRUE)
|
|
{
|
|
resptr2->rn_status &= ~RESTRUE;
|
|
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->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 & RESTRUE) == RESTRUE)
|
|
{
|
|
resptr2->rn_status &= ~RESTRUE;
|
|
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 & RESTRUE) == RESTRUE)
|
|
{
|
|
resptr2->rn_status &= ~RESTRUE;
|
|
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 & RESTRUE) == RESTRUE)
|
|
{
|
|
resptr2->rn_status &= ~RESTRUE;
|
|
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 & RESTRUE) == RESTRUE)
|
|
{
|
|
resptr2->rn_status &= ~RESTRUE;
|
|
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;
|
|
|
|
|
|
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 & RESTRUE)
|
|
{
|
|
resptr2 = resptr3;
|
|
resptr2->rn_status &= ~RESTRUE;
|
|
}
|
|
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;
|
|
|
|
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. */
|
|
|
|
InitializeNode(n3, resptr->rn_loc.p_x, resptr->rn_loc.p_y, TRIANGLE);
|
|
n3->rn_status = FINISHED | RESTRUE | 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 & RESTRUE) == RESTRUE)
|
|
n1->rn_status &= ~RESTRUE;
|
|
else
|
|
n1 = NULL;
|
|
|
|
if ((n2->rn_status & RESTRUE) == RESTRUE)
|
|
n2->rn_status &= ~RESTRUE;
|
|
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 startpoint */
|
|
if (node2->rn_why & RES_NODE_ORIGIN)
|
|
node1->rn_why = RES_NODE_ORIGIN;
|
|
|
|
/* set node resistance */
|
|
if (node1->rn_noderes > node2->rn_noderes)
|
|
{
|
|
node1->rn_noderes = node2->rn_noderes;
|
|
if ((node1->rn_status & FINISHED) != 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 & RN_MAXTDI);
|
|
|
|
/* merge device lists */
|
|
workingDev = node2->rn_te;
|
|
while (workingDev != NULL)
|
|
{
|
|
if (workingDev->te_thist->rd_status & RES_DEV_PLUG)
|
|
{
|
|
ResPlug *plug = (ResPlug *) workingDev->te_thist;
|
|
if (plug->rpl_node == node2)
|
|
plug->rpl_node = node1;
|
|
else
|
|
{
|
|
TxError("Bad plug node: is (%d %d), should be (%d %d)\n",
|
|
plug->rpl_node->rn_loc.p_x, plug->rpl_node->rn_loc.p_y,
|
|
node2->rn_loc.p_x, node2->rn_loc.p_y);
|
|
plug->rpl_node = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
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++)
|
|
{
|
|
tileJunk *junk;
|
|
|
|
tile = tJunc->je_thisj->rj_Tile[i];
|
|
junk = (tileJunk *) TiGetClientPTR(tile);
|
|
|
|
if ((junk->tj_status & RES_TILE_DONE) == FALSE)
|
|
ResFixBreakPoint(&junk->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)
|
|
{
|
|
tileJunk *junk;
|
|
|
|
workingCon->ce_thisc->cp_cnode[i] = node1;
|
|
tile =tCon->ce_thisc->cp_tile[i];
|
|
junk = (tileJunk *) TiGetClientPTR(tile);
|
|
if ((junk->tj_status & RES_TILE_DONE) == FALSE)
|
|
ResFixBreakPoint(&junk->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;
|
|
ResSimNode *node;
|
|
|
|
/* Check if node2 is a port */
|
|
entry = HashFind(&ResNodeTable, node2->rn_name);
|
|
node = (ResSimNode *)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 & FINISHED) == FINISHED)
|
|
ResRemoveFromQueue(node2, doneList);
|
|
else
|
|
ResRemoveFromQueue(node2, pendingList);
|
|
|
|
if (node2->rn_client != (ClientData)NULL)
|
|
{
|
|
freeMagic((char *)node2->rn_client);
|
|
node2->rn_client = (ClientData)NULL;
|
|
}
|
|
|
|
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 'junk' option is used,
|
|
* the node is eradicated.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side Effects: frees memory
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
ResCleanNode(resptr, junk, homelist1, homelist2)
|
|
resNode *resptr;
|
|
int junk;
|
|
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 (junk == 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;
|
|
}
|
|
}
|