mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-08-31 18:25:50 +02:00
Added a ARG_UNUSED macro in utils/magic.h, which produces a simple cast to void to silence the warnings. The reasons this is used as opposed to an attribute is that most compilers should support this. Besides this, the macro can be easily searched for in the future to potentially remove (where possible) the unused parameters.
588 lines
16 KiB
C
588 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 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);
|
|
}
|