Continued optimizing poorly written routines in "extresist".
Changed the "ResDissolveContacts()" routine to avoid running both redundant and useless code. Changed the breakpoint sorting routine from a bubble sort to a merge sort for linked lists longer than 16, as merge sort is more efficient for long lists.
This commit is contained in:
parent
29447a35cd
commit
a062fdcfe0
|
|
@ -148,29 +148,32 @@ void
|
|||
ResDissolveContacts(contacts)
|
||||
ResContactPoint *contacts;
|
||||
{
|
||||
TileType t, oldtype;
|
||||
TileType t, oldtype, lasttype = TT_SPACE;
|
||||
Tile *tp;
|
||||
TileTypeBitMask residues;
|
||||
|
||||
for (; contacts != (ResContactPoint *)NULL; contacts = contacts->cp_nextcontact)
|
||||
{
|
||||
oldtype=contacts->cp_type;
|
||||
oldtype = contacts->cp_type;
|
||||
|
||||
#ifdef PARANOID
|
||||
if (oldtype == TT_SPACE)
|
||||
TxError("Error in Contact Dissolving for %s \n",ResCurrentNode);
|
||||
#endif
|
||||
DBFullResidueMask(oldtype, &residues);
|
||||
if (oldtype != lasttype)
|
||||
{
|
||||
lasttype = oldtype;
|
||||
DBFullResidueMask(oldtype, &residues);
|
||||
}
|
||||
|
||||
DBErase(ResUse->cu_def, &(contacts->cp_rect), oldtype);
|
||||
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
|
||||
if (TTMaskHasType(&residues, t))
|
||||
DBPaint(ResUse->cu_def, &(contacts->cp_rect), t);
|
||||
|
||||
#ifdef PARANOID
|
||||
tp = PlaneGetHint(ResDef->cd_planes[DBPlane(contacts->cp_type)]);
|
||||
GOTOPOINT(tp, &(contacts->cp_rect.r_ll));
|
||||
|
||||
#ifdef PARANOID
|
||||
if (TiGetTypeExact(tp) == contacts->cp_type)
|
||||
TxError("Error in Contact Preprocess Routines\n");
|
||||
#endif
|
||||
|
|
@ -378,13 +381,14 @@ ResAddBreakpointFunc(tile, dinfo, node)
|
|||
*
|
||||
* ResFindNewContactTiles --
|
||||
*
|
||||
* Dissolving contacts eliminated the tiles that contacts->nextcontact
|
||||
* pointed to. This procedure finds the tile now under center and sets
|
||||
* that tile's ti_client field to point to the contact. The old value
|
||||
* of clientdata is set to nextTilecontact.
|
||||
*
|
||||
* Results: none
|
||||
*
|
||||
* Side Effects: dissolving contacts eliminated the tiles that
|
||||
* contacts->nextcontact pointed to. This procedure finds the tile now under
|
||||
* center and sets that tile's ti_client field to point to the contact. The
|
||||
* old value of clientdata is set to nextTilecontact.
|
||||
* Side Effects: modifies information in the contact records.
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
@ -396,27 +400,37 @@ ResFindNewContactTiles(contacts)
|
|||
int pNum;
|
||||
Tile *tile;
|
||||
TileTypeBitMask mask;
|
||||
TileType lastType = TT_SPACE;
|
||||
|
||||
for (; contacts != (ResContactPoint *) NULL; contacts = contacts->cp_nextcontact)
|
||||
{
|
||||
DBFullResidueMask(contacts->cp_type, &mask);
|
||||
|
||||
/* Watch for types that connect to the substrate plane or well; */
|
||||
/* e.g., psubstratepdiff connects to nwell but not through a */
|
||||
/* contact. */
|
||||
|
||||
if (ExtCurStyle->exts_globSubstratePlane != -1)
|
||||
/* Avoid re-running the following code for the same contact type */
|
||||
if (contacts->cp_type != lastType)
|
||||
{
|
||||
TileTypeBitMask cMask;
|
||||
TTMaskAndMask3(&cMask, &DBConnectTbl[contacts->cp_type],
|
||||
&DBPlaneTypes[ExtCurStyle->exts_globSubstratePlane]);
|
||||
lastType = contacts->cp_type;
|
||||
DBFullResidueMask(contacts->cp_type, &mask);
|
||||
|
||||
if (!TTMaskIsZero(&cMask))
|
||||
TTMaskSetMask(&mask, &cMask);
|
||||
/* Watch for types that connect to the substrate plane or well; */
|
||||
/* e.g., psubstratepdiff connects to nwell but not through a */
|
||||
/* contact. */
|
||||
|
||||
if (ExtCurStyle->exts_globSubstratePlane != -1)
|
||||
{
|
||||
TileTypeBitMask cMask;
|
||||
TTMaskAndMask3(&cMask, &DBConnectTbl[contacts->cp_type],
|
||||
&DBPlaneTypes[ExtCurStyle->exts_globSubstratePlane]);
|
||||
|
||||
if (!TTMaskIsZero(&cMask))
|
||||
TTMaskSetMask(&mask, &cMask);
|
||||
}
|
||||
}
|
||||
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
{
|
||||
if (!DBTypeOnPlane(contacts->cp_type, pNum) &&
|
||||
(pNum != ExtCurStyle->exts_globSubstratePlane))
|
||||
continue;
|
||||
|
||||
tile = PlaneGetHint(ResDef->cd_planes[pNum]);
|
||||
GOTOPOINT(tile, &(contacts->cp_center));
|
||||
#ifdef PARANOID
|
||||
|
|
@ -476,10 +490,11 @@ ResFindNewContactTiles(contacts)
|
|||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* ResProcessTiles--Calls ResEachTile with processed tiles belonging to
|
||||
* nodes in ResNodeQueue. When all the tiles corresponding
|
||||
* to a node have been processed, the node is moved to
|
||||
* ResNodeList.
|
||||
* ResProcessTiles --
|
||||
*
|
||||
* Calls ResEachTile with processed tiles belonging to nodes in ResNodeQueue.
|
||||
* When all the tiles corresponding to a node have been processed, the node
|
||||
* is moved to ResNodeList.
|
||||
*
|
||||
* Results: Return 1 if any error occurred, 0 otherwise.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -525,7 +525,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
|||
(devedge & TOPEDGE) == devedge ||
|
||||
(devedge & BOTTOMEDGE) == devedge)
|
||||
{
|
||||
ResSortBreaks(&info->breakList,TRUE);
|
||||
ResSortBreaks(&info->breakList, TRUE);
|
||||
p2 = NULL;
|
||||
for (p1 = info->breakList; p1 != NULL; p1 = p1->br_next)
|
||||
{
|
||||
|
|
@ -916,11 +916,182 @@ ResDoContacts(contact, nodes, resList)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* BreakCompare --
|
||||
*
|
||||
* Helper routine for MergeSortBreaks() (below). Simple
|
||||
* comparison of the breakpoint position. Comparison is
|
||||
* done for the X position if "xsort" is TRUE, and the Y
|
||||
* position if "xsort" is FALSE.
|
||||
*
|
||||
* Return value:
|
||||
* Return -1 if the (x or y) position of a is less than the
|
||||
* (x or y) position of b; return +1 if the position of a is
|
||||
* greater than the position of b; and return 0 if they have
|
||||
* equal positions.
|
||||
*
|
||||
* Side effect:
|
||||
* None.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
BreakCompare(
|
||||
Breakpoint *a,
|
||||
Breakpoint *b,
|
||||
int xsort)
|
||||
{
|
||||
if (xsort == TRUE)
|
||||
{
|
||||
if (a->br_loc.p_x < b->br_loc.p_x) return -1;
|
||||
if (a->br_loc.p_x > b->br_loc.p_x) return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (a->br_loc.p_y < b->br_loc.p_y) return -1;
|
||||
if (a->br_loc.p_y > b->br_loc.p_y) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* MergeSorted --
|
||||
*
|
||||
* Helper routine for MergeSortBreaks() (below). Merge sort
|
||||
* merging routine.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Breakpoint *
|
||||
MergeSorted(
|
||||
Breakpoint *a,
|
||||
Breakpoint *b,
|
||||
int xsort)
|
||||
{
|
||||
Breakpoint head;
|
||||
Breakpoint *tail = &head;
|
||||
|
||||
head.br_next = NULL;
|
||||
|
||||
while (a != NULL && b != NULL)
|
||||
{
|
||||
if (BreakCompare(a, b, xsort) <= 0)
|
||||
{
|
||||
tail->br_next = a;
|
||||
a = a->br_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
tail->br_next = b;
|
||||
b = b->br_next;
|
||||
}
|
||||
tail = tail->br_next;
|
||||
}
|
||||
tail->br_next = (a != NULL) ? a : b;
|
||||
|
||||
return head.br_next;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* SplitList --
|
||||
*
|
||||
* Helper routine for MergeSortBreaks() (below). Merge sort
|
||||
* splitting routine.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
SplitList(
|
||||
Breakpoint *source,
|
||||
Breakpoint **front,
|
||||
Breakpoint **back)
|
||||
{
|
||||
Breakpoint *slow;
|
||||
Breakpoint *fast;
|
||||
|
||||
if (source == NULL || source->br_next == NULL)
|
||||
{
|
||||
*front = source;
|
||||
*back = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
slow = source;
|
||||
fast = source->br_next;
|
||||
|
||||
while (fast != NULL)
|
||||
{
|
||||
fast = fast->br_next;
|
||||
|
||||
if (fast != NULL)
|
||||
{
|
||||
slow = slow->br_next;
|
||||
fast = fast->br_next;
|
||||
}
|
||||
}
|
||||
|
||||
*front = source;
|
||||
*back = slow->br_next;
|
||||
slow->br_next = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* MergeSortBreaks --
|
||||
*
|
||||
* See "ResSortBreaks" below. Alternative to bubble sort for long
|
||||
* linked lists.
|
||||
*
|
||||
* Results:
|
||||
* Pointer to a sorted breakpoint list.
|
||||
*
|
||||
* Side effects:
|
||||
* The breakpoints are sorted.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Breakpoint *
|
||||
MergeSortBreaks(Breakpoint *list, int xsort)
|
||||
{
|
||||
Breakpoint *a, *b;
|
||||
|
||||
if (list == NULL || list->br_next == NULL)
|
||||
return list;
|
||||
|
||||
SplitList(list, &a, &b);
|
||||
|
||||
a = MergeSortBreaks(a, xsort);
|
||||
b = MergeSortBreaks(b, xsort);
|
||||
|
||||
return MergeSorted(a, b, xsort);
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResSortBreaks --
|
||||
*
|
||||
* Sort breakpoints, either in the X direction (if "xsort" is TRUE)
|
||||
* or in the Y direction (if "xsort" is FALSE). For short lists
|
||||
* (< 16 elements), a simple bubble sort is used. For larger lists,
|
||||
* a merge sort is used. Most resistor networks are short, but
|
||||
* power/ground networks can be huge and cause a performance
|
||||
* bottleneck.
|
||||
*
|
||||
* Results:
|
||||
* None
|
||||
*
|
||||
|
|
@ -934,6 +1105,19 @@ ResSortBreaks(masterlist, xsort)
|
|||
{
|
||||
Breakpoint *p1, *p2, *p3, *p4;
|
||||
bool changed;
|
||||
int count = 0;
|
||||
|
||||
for (p1 = *masterlist; p1; p1 = p1->br_next)
|
||||
{
|
||||
count++;
|
||||
if (count > 16)
|
||||
{
|
||||
*masterlist = MergeSortBreaks(*masterlist, xsort);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Simple bubble sort */
|
||||
|
||||
changed = TRUE;
|
||||
while (changed == TRUE)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResSimple.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
||||
#endif /* not lint */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* for qsort() */
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
|
@ -401,6 +402,29 @@ ResMoveDevices(node1, node2)
|
|||
node1->rn_te = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* qrescompare ---
|
||||
*
|
||||
* Sort routine for qsort() to be used by ResScrunchNet(). Sorts in
|
||||
* order of the resistor value, smallest to largest.
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
qrescompare(const void *one, const void *two)
|
||||
{
|
||||
int cval;
|
||||
|
||||
resResistor *r1 = *((resResistor **)one);
|
||||
resResistor *r2 = *((resResistor **)two);
|
||||
|
||||
if (r1->rr_value < r2->rr_value) return -1;
|
||||
else if (r1->rr_value == r2->rr_value) return 0;
|
||||
else return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -424,29 +448,82 @@ ResScrunchNet(reslist, pendingList, biglist, tolerance)
|
|||
float tolerance;
|
||||
|
||||
{
|
||||
resResistor *locallist = NULL, *current, *working;
|
||||
resResistor *current, *working;
|
||||
resNode *node1, *node2;
|
||||
resElement *rcell1;
|
||||
int c1, c2;
|
||||
int c1, c2, count = 0;
|
||||
|
||||
/* Sort resistors by size */
|
||||
current = *reslist;
|
||||
while (current != NULL)
|
||||
/* Method used to sort resistors by size depends on list length */
|
||||
for (current = *reslist; current; current = current->rr_nextResistor)
|
||||
{
|
||||
working = current;
|
||||
current = current->rr_nextResistor;
|
||||
if (working == *reslist)
|
||||
*reslist = current;
|
||||
else
|
||||
working->rr_lastResistor->rr_nextResistor = current;
|
||||
count++;
|
||||
if (count >= 10) break;
|
||||
}
|
||||
|
||||
/* Sort resistors by size */
|
||||
|
||||
if (current != NULL)
|
||||
current->rr_lastResistor = working->rr_lastResistor;
|
||||
if (count >= 10)
|
||||
{
|
||||
int i;
|
||||
resResistor **resSortList;
|
||||
|
||||
ResAddResistorToList(working, &locallist);
|
||||
/* For long lists, sort using qsort() */
|
||||
/* NOTE: It might be better to use the same merge sort used for
|
||||
* MergeSortBreaks() in ResMakeRes.c, as it does not incur the
|
||||
* overhead of allocating memory and populating the array.
|
||||
*/
|
||||
count = 0;
|
||||
for (current = *reslist; current; current = current->rr_nextResistor)
|
||||
count++;
|
||||
|
||||
resSortList = (resResistor **)mallocMagic(count * sizeof(resResistor *));
|
||||
|
||||
count = 0;
|
||||
for (current = *reslist; current; current = current->rr_nextResistor)
|
||||
{
|
||||
resSortList[count] = current;
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Sort the list */
|
||||
|
||||
qsort(resSortList, count, sizeof(resResistor *), qrescompare);
|
||||
|
||||
/* Regenerate links on sorted list */
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
current = resSortList[i];
|
||||
current->rr_nextResistor = (i == count - 1) ? NULL : resSortList[i + 1];
|
||||
current->rr_lastResistor = (i == 0) ? NULL : resSortList[i - 1];
|
||||
}
|
||||
*reslist = resSortList[0];
|
||||
|
||||
freeMagic(resSortList);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Original method: Walk the linked list and re-sort by size. */
|
||||
|
||||
resResistor *locallist = NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
*reslist = locallist;
|
||||
while (*reslist != NULL && (*reslist)->rr_value < tolerance)
|
||||
{
|
||||
current = *reslist;
|
||||
|
|
@ -501,8 +578,8 @@ ResScrunchNet(reslist, pendingList, biglist, tolerance)
|
|||
}
|
||||
}
|
||||
/*
|
||||
* 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,
|
||||
* If the current resistor isn't a dead end, add its value and
|
||||
* area to that of the next smallest one. If it is a dead end,
|
||||
* simply add its area to its node.
|
||||
*/
|
||||
if (c1 != 0 && c2 != 0)
|
||||
|
|
@ -567,7 +644,7 @@ ResAddResistorToList(resistor, locallist)
|
|||
resResistor *resistor, **locallist;
|
||||
|
||||
{
|
||||
resResistor *local,*last=NULL;
|
||||
resResistor *local, *last = NULL;
|
||||
|
||||
for (local = *locallist; local != NULL; local = local->rr_nextResistor)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue