diff --git a/VERSION b/VERSION index 641fc72d..d7e92369 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.645 +8.3.646 diff --git a/resis/ResMain.c b/resis/ResMain.c index 6b8af42f..988a67a9 100644 --- a/resis/ResMain.c +++ b/resis/ResMain.c @@ -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. * diff --git a/resis/ResMakeRes.c b/resis/ResMakeRes.c index db1727ce..73fe0b99 100644 --- a/resis/ResMakeRes.c +++ b/resis/ResMakeRes.c @@ -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) diff --git a/resis/ResSimple.c b/resis/ResSimple.c index 700345f5..1dea7b95 100644 --- a/resis/ResSimple.c +++ b/resis/ResSimple.c @@ -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 +#include /* for qsort() */ #include #include #include @@ -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) {