534 lines
15 KiB
C
534 lines
15 KiB
C
/* rtrTraverse.c -
|
||
*
|
||
* This file contains routines for traversing electrically
|
||
* connected regions of a layout.
|
||
* This code was copied from DBconnect.c and
|
||
* modified to maintain a traversal path using
|
||
* the C runtime stack.
|
||
*
|
||
* *********************************************************************
|
||
* * 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/router/rtrTravers.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 "utils/signals.h"
|
||
#include "utils/malloc.h"
|
||
#include "router/router.h"
|
||
#include "windows/windows.h"
|
||
#include "utils/main.h"
|
||
#include "gcr/gcr.h"
|
||
#include "router/routerInt.h"
|
||
|
||
int rtrTarget; /* Via minimization, target type */
|
||
int rtrReplace; /* Via minimization, replacement type */
|
||
int rtrDelta; /* Change in layer width */
|
||
|
||
/* General note for rtrSrTraverse:
|
||
*
|
||
* The connectivity extractor works in two passes, in order to avoid
|
||
* circularities. During the first pass, each connected tile gets
|
||
* marked, using the ti_client field. This marking is needed to
|
||
* avoid infinite searches on circular structures. The second pass
|
||
* is used to clear the markings again.
|
||
*/
|
||
|
||
/* The following structure is used to hold several pieces
|
||
* of information that must be passed through multiple
|
||
* levels of search function.
|
||
*/
|
||
|
||
struct conSrArg
|
||
{
|
||
CellDef *csa_def; /* Definition being searched. */
|
||
int csa_pNum; /* Index of plane being searched. */
|
||
TileTypeBitMask *csa_connect; /* Table indicating what connects
|
||
* to what.
|
||
*/
|
||
int (*csa_clientFunc)(); /* Client function to call. */
|
||
ClientData csa_clientData; /* Argument for clientFunc. */
|
||
bool csa_clear; /* FALSE means pass 1, TRUE
|
||
* means pass 2.
|
||
*/
|
||
Rect csa_bounds; /* Area that limits search. */
|
||
};
|
||
|
||
/*
|
||
* The search path is maintained on the C runtime stack
|
||
* with rtrTileStack sructures. Each entry on the stack
|
||
* points back to the previous connected tile.
|
||
*/
|
||
|
||
struct rtrTileStack
|
||
{
|
||
Tile *ts_tile; /* Tile at this level in the stack */
|
||
struct rtrTileStack *ts_link; /* Pointer to previous stack entry */
|
||
struct conSrArg *ts_csa; /* Pointer to search arguments */
|
||
};
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* rtrSrTraverse --
|
||
*
|
||
* This function is almost identical to DBSrConnect
|
||
* in that it searches through a cell to find all
|
||
* paint that is electrically connected to things
|
||
* in a given starting area.
|
||
* It differs in that it maintains a stack
|
||
* (on the C runtime stack) of the search path.
|
||
* This enables the client routine to examine
|
||
* the stack and recognize patterns of material
|
||
* in the connection path. Since the connection path
|
||
* is a tree, a stack is convenient data structure for
|
||
* recording a particular path originating from a single node.
|
||
*
|
||
* Results:
|
||
* 0 is returned if the search finished normally. 1 is returned
|
||
* if the search was aborted.
|
||
*
|
||
* Side effects:
|
||
* The search starts from one (random) non-space tile in "startArea"
|
||
* that matches the types in the mask parameter. For every paint
|
||
* tile that is electrically connected to the initial tile and that
|
||
* intersects the rectangle "bounds", func is called. Func should
|
||
* have the following form:
|
||
*
|
||
* int
|
||
* func(tile, clientData)
|
||
* Tile *tile;
|
||
* ClientData clientData;
|
||
* {
|
||
* }
|
||
*
|
||
* The clientData passed to func is the same one that was passed
|
||
* to us. Func returns 0 under normal conditions; if it returns
|
||
* 1 then the search is aborted.
|
||
*
|
||
* *** WARNING ***
|
||
*
|
||
* Func should not modify any paint during the search, since this
|
||
* will mess up pointers kept by these procedures and likely cause
|
||
* a core-dump.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
rtrSrTraverse(def, startArea, mask, connect, bounds, func, clientData)
|
||
CellDef *def; /* Cell definition in which to carry out
|
||
* the connectivity search. Only paint
|
||
* in this definition is considered.
|
||
*/
|
||
Rect *startArea; /* Area to search for an initial tile. Only
|
||
* tiles OVERLAPPING the area are considered.
|
||
* This area should have positive x and y
|
||
* dimensions.
|
||
*/
|
||
TileTypeBitMask *mask; /* Only tiles of one of these types are used
|
||
* as initial tiles.
|
||
*/
|
||
TileTypeBitMask *connect; /* Pointer to a table indicating what tile
|
||
* types connect to what other tile types.
|
||
* Each entry gives a mask of types that
|
||
* connect to tiles of a given type.
|
||
*/
|
||
Rect *bounds; /* Area, in coords of scx->scx_use->cu_def,
|
||
* that limits the search: only tiles
|
||
* overalapping this area will be returned.
|
||
* Use TiPlaneRect to search everywhere.
|
||
*/
|
||
int (*func)(); /* Function to apply at each connected tile. */
|
||
ClientData clientData; /* Client data for above function. */
|
||
|
||
{
|
||
struct conSrArg csa;
|
||
struct rtrTileStack ts;
|
||
int startPlane, result;
|
||
Tile *startTile; /* Starting tile for search. */
|
||
extern int rtrSrTraverseFunc(); /* Forward declaration. */
|
||
extern int rtrSrTraverseStartFunc();
|
||
|
||
result = 0;
|
||
csa.csa_def = def;
|
||
csa.csa_bounds = *bounds;
|
||
|
||
/* Find a starting tile (if there are many tiles underneath the
|
||
* starting area, pick any one). The search function just saves
|
||
* the tile address and returns.
|
||
*/
|
||
|
||
startTile = NULL;
|
||
for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++)
|
||
{
|
||
if (DBSrPaintArea((Tile *) NULL,
|
||
def->cd_planes[startPlane], startArea, mask,
|
||
rtrSrTraverseStartFunc, (ClientData) &startTile) != 0) break;
|
||
}
|
||
if (startTile == NULL)
|
||
return 0;
|
||
|
||
/* Pass 1. During this pass the client function gets called. */
|
||
|
||
csa.csa_clientFunc = func;
|
||
csa.csa_clientData = clientData;
|
||
csa.csa_clear = FALSE;
|
||
csa.csa_connect = connect;
|
||
csa.csa_pNum = startPlane;
|
||
|
||
ts.ts_tile = (Tile *) NULL;
|
||
ts.ts_link = (struct rtrTileStack *) NULL;
|
||
ts.ts_csa = &csa;
|
||
|
||
if (rtrSrTraverseFunc(startTile, &ts) != 0)
|
||
result = 1;
|
||
|
||
/* Pass 2. Don't call any client function, just clear the marks.
|
||
* Don't allow any interruptions.
|
||
*/
|
||
|
||
SigDisableInterrupts();
|
||
csa.csa_clientFunc = NULL;
|
||
csa.csa_clear = TRUE;
|
||
csa.csa_pNum = startPlane;
|
||
(void) rtrSrTraverseFunc(startTile, &ts);
|
||
SigEnableInterrupts();
|
||
|
||
return result;
|
||
}
|
||
|
||
int
|
||
rtrSrTraverseStartFunc(tile, pTile)
|
||
Tile *tile; /* This will be the starting tile. */
|
||
Tile **pTile; /* We store tile's address here. */
|
||
{
|
||
*pTile = tile;
|
||
return 1;
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* rtrSrTraverseFunc --
|
||
*
|
||
* This search function gets called by DBSrPaintArea as part
|
||
* of rtrSrTraverse, and also recursively by itself. Each invocation
|
||
* is made to process a single tile that is of interest.
|
||
* This function is copied from dbSrConnectFunc and differs by
|
||
* maintaining a stack (on the C-run time stack) of the search
|
||
* path.
|
||
*
|
||
* Results:
|
||
* 0 is returned unless the client function returns a non-zero
|
||
* value, in which case 1 is returned.
|
||
*
|
||
* Side effects:
|
||
* If this tile has been seen before, then just return
|
||
* immediately. If this tile hasn't been seen before, it is
|
||
* marked and the client procedure is called. A NULL client
|
||
* procedure is not called, of course. In addition, we scan
|
||
* the tiles perimeter for any connected tiles, and call
|
||
* ourselves recursively on them.
|
||
*
|
||
* Design note:
|
||
* This one procedure is used during both the marking and clearing
|
||
* passes, so "seen before" is a function both of the ti_client
|
||
* field in the tile and the csa_clear value.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
rtrSrTraverseFunc(tile, ts)
|
||
Tile *tile; /* Tile that is connected. */
|
||
struct rtrTileStack *ts; /* Contains information about the search. */
|
||
{
|
||
Tile *t2;
|
||
Rect tileArea;
|
||
int i;
|
||
TileTypeBitMask *connectMask;
|
||
TileType ttype;
|
||
unsigned int planes;
|
||
struct conSrArg *csa = ts->ts_csa;
|
||
struct rtrTileStack nts;
|
||
|
||
nts.ts_csa = csa;
|
||
nts.ts_tile = tile;
|
||
nts.ts_link = ts;
|
||
|
||
TiToRect(tile, &tileArea);
|
||
ttype = TiGetType(tile);
|
||
|
||
/* Make sure this tile overlaps the area we're interested in. */
|
||
|
||
if (!GEO_OVERLAP(&tileArea, &csa->csa_bounds)) return 0;
|
||
|
||
/* See if we've already been here before, and mark the tile as already
|
||
* visited.
|
||
*/
|
||
|
||
if (csa->csa_clear)
|
||
{
|
||
if (tile->ti_client == (ClientData) CLIENTDEFAULT) return 0;
|
||
tile->ti_client = (ClientData) CLIENTDEFAULT;
|
||
}
|
||
else
|
||
{
|
||
if (tile->ti_client != (ClientData) CLIENTDEFAULT) return 0;
|
||
tile->ti_client = (ClientData) 1;
|
||
}
|
||
|
||
/* Call the client function, if there is one. */
|
||
|
||
if (csa->csa_clientFunc != NULL)
|
||
{
|
||
if ((*csa->csa_clientFunc)(tile, &nts) != 0)
|
||
return 1;
|
||
}
|
||
|
||
/* Now search around each of the four sides of this tile for
|
||
* connected tiles. For each one found, call ourselves
|
||
* recursively.
|
||
*/
|
||
|
||
connectMask = &csa->csa_connect[ttype];
|
||
|
||
/* Left side: */
|
||
|
||
for (t2 = BL(tile); BOTTOM(t2) < tileArea.r_ytop; t2 = RT(t2))
|
||
{
|
||
if (TTMaskHasType(connectMask, TiGetType(t2)))
|
||
{
|
||
if (csa->csa_clear)
|
||
{
|
||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) continue;
|
||
}
|
||
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) continue;
|
||
if (rtrSrTraverseFunc(t2, &nts) != 0) return 1;
|
||
}
|
||
}
|
||
|
||
/* Bottom side: */
|
||
|
||
for (t2 = LB(tile); LEFT(t2) < tileArea.r_xtop; t2 = TR(t2))
|
||
{
|
||
if (TTMaskHasType(connectMask, TiGetType(t2)))
|
||
{
|
||
if (csa->csa_clear)
|
||
{
|
||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) continue;
|
||
}
|
||
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) continue;
|
||
if (rtrSrTraverseFunc(t2, &nts) != 0) return 1;
|
||
}
|
||
}
|
||
|
||
/* Right side: */
|
||
|
||
for (t2 = TR(tile); ; t2 = LB(t2))
|
||
{
|
||
if (TTMaskHasType(connectMask, TiGetType(t2)))
|
||
{
|
||
if (csa->csa_clear)
|
||
{
|
||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) goto nextRight;
|
||
}
|
||
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) goto nextRight;
|
||
if (rtrSrTraverseFunc(t2, &nts) != 0) return 1;
|
||
}
|
||
nextRight: if (BOTTOM(t2) <= tileArea.r_ybot) break;
|
||
}
|
||
|
||
/* Top side: */
|
||
|
||
for (t2 = RT(tile); ; t2 = BL(t2))
|
||
{
|
||
if (TTMaskHasType(connectMask, TiGetType(t2)))
|
||
{
|
||
if (csa->csa_clear)
|
||
{
|
||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) goto nextTop;
|
||
}
|
||
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) goto nextTop;
|
||
if (rtrSrTraverseFunc(t2, &nts) != 0) return 1;
|
||
}
|
||
nextTop: if (LEFT(t2) <= tileArea.r_xbot) break;
|
||
}
|
||
|
||
/* Lastly, check to see if this tile connects to anything on
|
||
* other planes. If so, search those planes.
|
||
*/
|
||
|
||
planes = DBConnPlanes[ttype];
|
||
planes &= ~(csa->csa_pNum);
|
||
if (planes != 0)
|
||
{
|
||
struct conSrArg newcsa;
|
||
|
||
newcsa = *csa;
|
||
nts.ts_csa = &newcsa;
|
||
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
|
||
{
|
||
newcsa.csa_pNum = i;
|
||
if (DBSrPaintArea((Tile *) NULL,
|
||
newcsa.csa_def->cd_planes[i],
|
||
&tileArea, connectMask, rtrSrTraverseFunc,
|
||
(ClientData) &nts) != 0)
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* rtrExamineTile --
|
||
*
|
||
* Examine a tile to see if it overlaps or connects
|
||
* the target tile.
|
||
*
|
||
* Results:
|
||
* Returns 1 if tile overlaps or connects
|
||
* the target tile. This means the target tile
|
||
* cannot be moved to another routing layer.
|
||
* Returns 0 otherwise.
|
||
*
|
||
* Side effects:
|
||
* None.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
rtrExamineTile(tile, cdata)
|
||
Tile *tile;
|
||
ClientData cdata;
|
||
{
|
||
if ( TiGetType(tile) == rtrTarget )
|
||
return 1;
|
||
|
||
if ( (tile != (Tile *) cdata) &&
|
||
(TiGetType(tile) == rtrReplace) )
|
||
return 1;
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* rtrExamineStack --
|
||
*
|
||
* Examine a segment of the traversal path
|
||
* and identify segments of replacement material
|
||
* connected by vias at both ends and not overlapped
|
||
* or electrically connected to other routing material.
|
||
*
|
||
* Results:
|
||
* Always returns 0 to continue search.
|
||
*
|
||
* Side effects:
|
||
* Segments of replacement material are added to a list
|
||
* for later conversion to the target material.
|
||
* The vias are added to a list for later removal.
|
||
* They can't be processed now as pointers would get
|
||
* fouled up for the area search.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
rtrExamineStack(tile, ts)
|
||
Tile *tile;
|
||
struct rtrTileStack *ts;
|
||
{
|
||
int i;
|
||
Tile *tp[3];
|
||
struct conSrArg *csa = ts->ts_csa;
|
||
CellDef *def = csa->csa_def;
|
||
|
||
/*
|
||
* Collect topmost three elements of the stack.
|
||
*/
|
||
|
||
i = 0;
|
||
while ( i < 3 && ts && ts->ts_tile )
|
||
{
|
||
tp[i++] = ts->ts_tile;
|
||
ts = ts->ts_link;
|
||
}
|
||
|
||
if ( i == 3 )
|
||
{
|
||
/*
|
||
* Identify pattern -- *via* *replacement_material* *via*
|
||
*/
|
||
|
||
if ( DBIsContact(TiGetType(tp[0])) &&
|
||
(TiGetType(tp[1]) == rtrReplace) &&
|
||
DBIsContact(TiGetType(tp[2])))
|
||
{
|
||
int plane;
|
||
Rect area;
|
||
TileTypeBitMask mask;
|
||
int deltax = rtrDelta, deltay = rtrDelta;
|
||
|
||
/*
|
||
* Search for overlapping or
|
||
* electrically connected routing material.
|
||
*/
|
||
|
||
TTMaskZero(&mask);
|
||
TTMaskSetType(&mask, RtrPolyType);
|
||
TTMaskSetType(&mask, RtrMetalType);
|
||
TITORECT(tp[1], &area);
|
||
area.r_xbot--;
|
||
area.r_xtop++;
|
||
for ( plane = PL_PAINTBASE; plane < DBNumPlanes; plane++ )
|
||
if ( DBPaintOnPlane(RtrPolyType, plane) ||
|
||
DBPaintOnPlane(RtrMetalType, plane) )
|
||
if ( DBSrPaintArea((Tile *)NULL, def->cd_planes[plane],
|
||
&area, &mask, rtrExamineTile, (ClientData) tp[1]) )
|
||
return 0;
|
||
|
||
/*
|
||
* Mark areas for later processing.
|
||
*/
|
||
|
||
if ( rtrDelta < 0 )
|
||
{
|
||
if ( (TOP(tp[1]) == BOTTOM(tp[0])) || (TOP(tp[1]) == BOTTOM(tp[2])))
|
||
deltay = 0;
|
||
if ( (RIGHT(tp[1]) == LEFT(tp[0])) || (RIGHT(tp[1]) == LEFT(tp[2])))
|
||
deltax = 0;
|
||
}
|
||
|
||
rtrListVia (tp[0]);
|
||
rtrListArea(tp[1], rtrReplace, rtrTarget, deltax, deltay);
|
||
rtrListVia (tp[2]);
|
||
}
|
||
}
|
||
return 0;
|
||
}
|