/* * PlowQueue.c -- * * Plowing. * Queue of edges to move. * * ********************************************************************* * * Copyright (C) 1985, 1990 Regents of the University of California. * * * Permission to use, copy, modify, and distribute this * * * software and its documentation for any purpose and without * * * fee is hereby granted, provided that the above copyright * * * notice appear in all copies. The University of California * * * makes no representations about the suitability of this * * * software for any purpose. It is provided "as is" without * * * express or implied warranty. Export of this software outside * * * of the United States of America may require an export license. * * ********************************************************************* */ #ifndef lint static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/plow/PlowQueue.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $"; #endif /* not lint */ #include #include "utils/magic.h" #include "utils/geometry.h" #include "tiles/tile.h" #include "utils/hash.h" #include "database/database.h" #include "debug/debug.h" #include "plow/plowInt.h" #include "utils/malloc.h" /* * The following describe the queue of edges to be moved. * The array plowBinArray is indexed by the initial X coordinate * of an edge (relative to plowBinXBase). Each element plowBinArray[n] * is a pointer to a list of Edges whose initial X coordinates are * plowBinXBase + n. * * There is an array for each plane in a CellDef. */ int plowNumBins; /* Number of horizontal bins */ int plowDistance; /* Distance the plow is moving */ int plowBinXBase; /* Left-hand coordinate of cell's bbox */ int plowNumEdges; /* Number of edges currently in queue */ Edge **plowBinArray[NP]; /* Array of bins for each X coordinate */ Edge **plowFirstBin[NP]; /* First bin that has any edges in it */ Edge **plowLastBin[NP]; /* Last bin that has any edges in it */ /* Debugging */ int plowTooFar; /* # times we reduced plow size */ /* * ---------------------------------------------------------------------------- * * plowQueueInit -- * * Initialize the queue of edges to be moved by plowing. * The argument 'bbox' is the bounding box of the cell * being plowed. * * Results: * None. * * Side effects: * Obvious. * * ---------------------------------------------------------------------------- */ void plowQueueInit(bbox, dist) Rect *bbox; /* Bounding box for the cell being plowed */ int dist; /* Distance the plow moves */ { Edge **pptr, **pend; int pNum; unsigned binArraySize; plowNumBins = bbox->r_xtop - bbox->r_xbot + 1; plowDistance = dist; plowBinXBase = bbox->r_xbot; plowNumEdges = 0; plowTooFar = 0; binArraySize = plowNumBins * sizeof (Edge *); for (pNum = 0; pNum < DBNumPlanes; pNum++) { /* Don't need planes for DRC, etc. */ if (pNum > 0 && pNum < PL_TECHDEPBASE) continue; plowBinArray[pNum] = (Edge **) mallocMagic(binArraySize); plowFirstBin[pNum] = (Edge **) NULL; plowLastBin[pNum] = (Edge **) NULL; pptr = plowBinArray[pNum]; pend = &pptr[plowNumBins]; while (pptr < pend) *pptr++ = (Edge *) NULL; } } /* * ---------------------------------------------------------------------------- * * plowQueueDone -- * * Free the memory allocated by plowQueueInit above. * * Results: * None. * * Side effects: * Frees memory. * * ---------------------------------------------------------------------------- */ void plowQueueDone() { int pNum; for (pNum = 0; pNum < DBNumPlanes; pNum++) { if (pNum == 0 || pNum >= PL_TECHDEPBASE) freeMagic((char *) plowBinArray[pNum]); } } /* * ---------------------------------------------------------------------------- * * plowQueueAdd -- * * Add an edge to the queue of those to be moved. * * Results: * Returns 0 always (so it can be used as a filter function). * * Side effects: * Adds edges to the queue. * * ---------------------------------------------------------------------------- */ #define SAMETYPE(e1, e2) ((e1)->e_ltype == (e2)->e_ltype \ && (e1)->e_rtype == (e2)->e_rtype) int plowQueueAdd(eadd) Edge *eadd; /* Edge added to queue. We assume that * e_ltype and e_rtype have been set to * the types on the LHS and RHS of this * edge, respectively. */ { extern CellDef *plowYankDef; extern int plowQueuedEdges; int xbin = eadd->e_x - plowBinXBase; Edge *enew, *eprev, *ep; Edge **pbin; int pNum; Rect addRect; ASSERT(eadd->e_ybot < eadd->e_ytop, "plowQueueAdd"); ASSERT(xbin < plowNumBins, "plowQueueAdd"); /* * Make sure we're not moving the edge too far. * This should only happen in the event of design * rule violations in the initial circuit, but we * keep track of the number of times it happened * for the sake of debugging. */ if (eadd->e_newx > eadd->e_x + plowDistance) { eadd->e_newx = eadd->e_x + plowDistance; plowTooFar++; } /* Display this edge if we're debugging */ plowQueuedEdges++; if (DebugIsSet(plowDebugID, plowDebAdd)) plowDebugEdge(eadd, plowCurrentRule, "add"); /* Which plane is this on? */ pNum = eadd->e_pNum; /* * If this is the first edge added to this bin, we may have to update * the first or last pointers. */ pbin = &plowBinArray[pNum][xbin]; if (*pbin == (Edge *) NULL) { if (plowFirstBin[pNum] == (Edge **) NULL) plowFirstBin[pNum] = plowLastBin[pNum] = pbin; else if (pbin < plowFirstBin[pNum]) plowFirstBin[pNum] = pbin; else if (pbin > plowLastBin[pNum]) plowLastBin[pNum] = pbin; goto prepend; } /* * If a cell, see if there is already an edge ep in the queue * for this cell. If so, update ep->e_newx to the larger of * eadd->e_newx and ep->e_newx and we're done. Otherwise, * just prepend this edge to the queue. */ if (pNum == 0) { ASSERT(eadd->e_use != (CellUse *) NULL, "plowQueueAdd"); for (ep = *pbin; ep; ep = ep->e_next) { if (ep->e_use == eadd->e_use) { if (eadd->e_newx > ep->e_newx) ep->e_newx = eadd->e_newx; goto done; } } goto prepend; } /* * There was one or more edge in this bin. * Edges are sorted on increasing e_ybot coordinate, so we can * stop when ep->e_ybot > eadd->e_ytop. * The edges are disjoint in Y. */ /* Skip all edges strictly below eadd */ for (ep = *pbin, eprev = (Edge *) NULL; ep && ep->e_ytop < eadd->e_ybot; eprev = ep, ep = ep->e_next) { /* Nothing */; } /* * Keep going until we find an edge above or touching eadd's top, * or we run out of edges in this bin. We keep addRect updated * to the unprocessed portion of eadd->e_rect. Initially, this * rectangle is non-degenerate since eadd->e_ybot < eadd->e_ytop. * THE FOLLOWING LOOP IS HAIRY. */ addRect = eadd->e_rect; for ( ; ep && ep->e_ybot < addRect.r_ytop; eprev = ep, ep = ep->e_next) { /* * Done when we've processed all of addRect. * Since we may have changed eprev->e_newx, we * want to check to see if it can merge with * the new ep. */ if (addRect.r_ybot >= addRect.r_ytop) goto mergeFinal; /* * ep->e_ybot < addRect.r_ytop * addRect.r_ybot <= ep->e_ytop * addRect.r_ybot < addRect.r_ytop * * We know that addRect is non-degenerate and either overlaps * ep or touches its top. Whatever portion of addRect that lies * below ep we KNOW does not overlap any other edges. */ if (!SAMETYPE(ep, eadd)) { /* * If not the same type of edge, then they can't overlap. * Handle creating the new edge for addRect on the next iteration, * since we never merge up. */ ASSERT(addRect.r_ybot == ep->e_ytop, "plowQueueAdd"); continue; } /* If moving by the same amount as ep, absorb eadd into ep */ if (ep->e_newx == eadd->e_newx) { if (addRect.r_ybot < ep->e_ybot) ep->e_ybot = addRect.r_ybot; goto mergeDown; } /* Remember, ep->e_ybot < addRect.r_ytop */ if (addRect.r_ybot < ep->e_ybot) { /* * Clip the portion of addRect below ep (we know * that there is a non-degenerate part of addRect * above ep by the comment above). * Try to merge the lower part of addRect with eprev; * otherwise, create a new edge for this portion. */ if (eprev && SAMETYPE(eadd, eprev) && eprev->e_newx == eadd->e_newx && eprev->e_ytop == addRect.r_ybot) { /* Merge with eprev */ eprev->e_ytop = ep->e_ybot; } else { /* Create a new edge, replacing eprev */ enew = (Edge *) mallocMagic((unsigned) (sizeof (Edge))); *enew = *ep; enew->e_ybot = addRect.r_ybot; enew->e_ytop = ep->e_ybot; enew->e_newx = eadd->e_newx; if (eprev) eprev->e_next = enew; else *pbin = enew; enew->e_next = ep; eprev = enew; plowNumEdges++; } addRect.r_ybot = ep->e_ybot; } else if (ep->e_ybot < addRect.r_ybot) { /* Done except for merging if ep and addRect only touch */ if (ep->e_ytop == addRect.r_ybot) goto mergeDown; /* * Clip the portion of ep below addRect. * The new edge becomes eprev. */ enew = (Edge *) mallocMagic((unsigned) (sizeof (Edge))); *enew = *ep; enew->e_ytop = ep->e_ybot = addRect.r_ybot; enew->e_next = ep; if (eprev) eprev->e_next = enew; else *pbin = enew; eprev = enew; plowNumEdges++; } /* * At this point, addRect.r_ybot == ep->e_ybot, and * addRect.r_ytop > ep->e_ybot. Clip the portion of * ep above addRect. */ if (ep->e_ytop > addRect.r_ytop) { enew = (Edge *) mallocMagic((unsigned) (sizeof (Edge))); *enew = *ep; enew->e_ybot = ep->e_ytop = addRect.r_ytop; enew->e_next = ep->e_next; ep->e_next = enew; plowNumEdges++; } /* * Update the portion of the original ep that * was overlapped by addRect. */ ep->e_newx = MAX(ep->e_newx, eadd->e_newx); /* * Try to merge ep with eprev. * If successful, eprev->e_ytop gets updated, ep gets * freed, and we leave ep pointing to eprev. */ mergeDown: addRect.r_ybot = ep->e_ytop; if (eprev && SAMETYPE(ep, eprev) && eprev->e_newx == ep->e_newx && eprev->e_ytop == ep->e_ybot) { eprev->e_ytop = ep->e_ytop; eprev->e_next = ep->e_next; freeMagic((char *) ep); ep = eprev; plowNumEdges--; } /* NOTE: we switched ep above if we merged with eprev */ } /* * Something may be left of addRect. * Try to merge with eprev if possible; otherwise, allocate * a new edge and make this the new eprev. */ if (addRect.r_ybot < addRect.r_ytop) { if (eprev && SAMETYPE(eprev, eadd) && eprev->e_newx == eadd->e_newx && eprev->e_ytop == addRect.r_ybot) { eprev->e_ytop = addRect.r_ytop; } else { enew = (Edge *) mallocMagic((unsigned) (sizeof (Edge))); *enew = *eadd; enew->e_ybot = addRect.r_ybot; if (eprev) eprev->e_next = enew; else *pbin = enew; enew->e_next = ep; eprev = enew; plowNumEdges++; } } mergeFinal: /* * If ep is non-NULL, it is above or touching the top of * eprev (either as extended in the first branch above, or * as newly allocated in the second). */ if (ep && SAMETYPE(ep, eprev) && ep->e_newx == eprev->e_newx && ep->e_ybot == eprev->e_ytop) { eprev->e_ytop = ep->e_ytop; eprev->e_next = ep->e_next; freeMagic((char *) ep); plowNumEdges--; } goto done; /* * Prepend eadd to the current bin. */ prepend: enew = (Edge *) mallocMagic((unsigned) (sizeof (Edge))); *enew = *eadd; enew->e_next = *pbin; *pbin = enew; plowNumEdges++; done: return (0); } /* * ---------------------------------------------------------------------------- * * plowQueueLeftmost -- * * Returns the leftmost edge from the queue. * * Results: * TRUE if an edge was filled in, FALSE otherwise. * * Side effects: * Removes an edge from the queue and deallocates it * after filling in the caller's Edge. * * ---------------------------------------------------------------------------- */ bool plowQueueLeftmost(edge) Edge *edge; { Edge *enew, **pp, **plast; int pNum; int pMin, xMin; if (plowNumEdges <= 0) return (FALSE); /* Find the leftmost edge in any of the planes */ xMin = INFINITY, pMin = -1; for (pNum = 0; pNum < DBNumPlanes; pNum++) if (pNum == 0 || pNum >= PL_TECHDEPBASE) if ((pp = plowFirstBin[pNum]) && (pp - plowBinArray[pNum]) < xMin) xMin = pp - plowBinArray[pMin = pNum]; pNum = pMin; ASSERT(pNum >= 0, "plowQueueLeftmost"); ASSERT(*plowFirstBin[pNum] != (Edge *) NULL, "plowQueueLeftmost"); plowNumEdges--; enew = *plowFirstBin[pNum]; *plowFirstBin[pNum] = enew->e_next; if (*plowFirstBin[pNum] == (Edge *) NULL) { /* * No more edges left in this bin, so we have to advance the bounds * pointer plowFirstBin[pNum]. */ pp = plowFirstBin[pNum]; plast = plowLastBin[pNum]; while (pp < plast && *pp == (Edge *) NULL) pp++; /* * If there are no more edges on this plane, set both * plowFirstBin[pNum] and plowLastBin[pNum] to NULL. */ if (*pp) plowFirstBin[pNum] = pp; else plowFirstBin[pNum] = plowLastBin[pNum] = (Edge **) NULL; } /* Display this edge if we're debugging */ if (DebugIsSet(plowDebugID, plowDebNext)) plowDebugEdge(enew, (RuleTableEntry *) NULL, "next"); /* Debugging */ ASSERT(enew->e_ytop > enew->e_ybot, "plowQueueLeftmost"); ASSERT(enew->e_newx >= enew->e_x, "plowQueueLeftmost"); /* Fill in the caller's edge */ *edge = *enew; freeMagic((char *) enew); return (TRUE); } /* * ---------------------------------------------------------------------------- * * plowQueueRightmost -- * * Returns the rightmost edge from the queue. * * Results: * TRUE if an edge was filled in, FALSE otherwise. * * Side effects: * Removes an edge from the queue and deallocates it * after filling in the caller's Edge. * * ---------------------------------------------------------------------------- */ bool plowQueueRightmost(edge) Edge *edge; { Edge *enew, **pp, **plast; int pNum; int pMax, xMax; if (plowNumEdges <= 0) return (FALSE); /* Find the rightmost edge in any of the planes */ xMax = MINFINITY, pMax = -1; for (pNum = 0; pNum < DBNumPlanes; pNum++) if (pNum == 0 || pNum >= PL_TECHDEPBASE) if ((pp = plowLastBin[pNum]) && (pp - plowBinArray[pNum]) > xMax) xMax = pp - plowBinArray[pMax = pNum]; pNum = pMax; ASSERT(pNum >= 0, "plowQueueRightmost"); ASSERT(*plowLastBin[pNum] != (Edge *) NULL, "plowQueueRightmost"); plowNumEdges--; enew = *plowLastBin[pNum]; *plowLastBin[pNum] = enew->e_next; if (*plowLastBin[pNum] == (Edge *) NULL) { /* * No more edges left in this bin, so we have to advance the bounds * pointer plowLastBin[pNum]. */ pp = plowLastBin[pNum]; plast = plowFirstBin[pNum]; while (pp > plast && *pp == (Edge *) NULL) pp--; /* * If there are no more edges on this plane, set both * plowFirstBin[pNum] and plowLastBin[pNum] to NULL. */ if (*pp) plowLastBin[pNum] = pp; else plowFirstBin[pNum] = plowLastBin[pNum] = (Edge **) NULL; } /* Display this edge if we're debugging */ if (DebugIsSet(plowDebugID, plowDebNext)) plowDebugEdge(enew, (RuleTableEntry *) NULL, "next"); /* Debugging */ ASSERT(enew->e_ytop > enew->e_ybot, "plowQueueRightmost"); ASSERT(enew->e_newx >= enew->e_x, "plowQueueRightmost"); /* Fill in the caller's edge */ *edge = *enew; freeMagic((char *) enew); return (TRUE); }