magic/plow/PlowQueue.c

589 lines
16 KiB
C

/*
* 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 <stdio.h>
#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);
}