magic/router/rtrDcmpose.c

1026 lines
28 KiB
C
Raw Normal View History

/*
* rtrDcmpose.c --
*
* Channel decomposition module.
*
* Create a cell tile plane where each space tile in the error
* plane represents a channel to be separately routed by the
* channel router.
*
* Enumerate cell tile corners, choosing the shortest horizontal or
* vertical extention from a corner to another cell or a previously
* defined channel boundary. Split or merge tiles accordingly.
*
* The ti_client field of space tiles is used is a boolean flag
* in order to distinguish between horizontal edges generated by
* the original plane and horizontal edges defining channels. This
* is done in the new, generated plane--not in the original plane.
*
* *********************************************************************
* * 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/rtrDcmpose.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/times.h>
#include "utils/magic.h"
#include "textio/textio.h"
#include "utils/geometry.h"
#include "utils/geofast.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "windows/windows.h"
#include "utils/main.h"
#include "dbwind/dbwind.h"
#include "utils/heap.h"
#include "utils/undo.h"
#include "router/router.h"
#include "router/rtrDcmpose.h"
#include "gcr/gcr.h"
#include "grouter/grouter.h"
#include "utils/netlist.h"
#include "utils/styles.h"
#include "utils/malloc.h"
#include "netmenu/netmenu.h"
#include "debug/debug.h"
/* The following tile types are used during channel decomposition */
#define CELLTILE 1 /* Cell tile -- no channels here */
#define USERCHAN 2 /* User-defined channel */
bool rtrDidInit = FALSE; /* TRUE when rtrTileToChannel initialized */
/* Area being routed; set in RtrDecompose */
Rect RouteArea;
/* Forward declarations */
extern int rtrSrCells();
extern void rtrRoundRect();
extern void rtrHashKill();
extern void rtrSplitToArea();
extern void rtrMarkChannel();
extern void rtrMerge();
bool rtrUseCorner();
/*
* ----------------------------------------------------------------------------
*
* RtrDecomposeName --
*
* Interface to commands module; perform channel decomposition
* over the area 'area', as though we would be routing the netlist
* with the name 'name'. If 'name' is NULL, don't assume any
* netlist; if it is the string "-", use the current netlist.
*
* Results:
* Pointer to the def holding the decomposed channel tiles. If
* the area is too small to be useful, returns NULL.
*
* Side effects:
* See RtrDecompose().
*
* ----------------------------------------------------------------------------
*/
CellDef *
RtrDecomposeName(routeUse, area, name)
CellUse *routeUse; /* Cell to be decomposed */
Rect *area; /* Confine channels to this area */
char *name; /* Name of netlist if non-NULL; otherwise, use the
* name of the current netlist or that of routeUse
* as described above.
*/
{
NLNetList netList, *netListPtr = (NLNetList *) NULL;
CellDef *def;
if (name)
{
if (strcmp(name, "-") == 0)
name = routeUse->cu_def->cd_name;
NMNewNetlist(name);
if (NLBuild(routeUse, &netList) <= 0)
TxError("No nets in netlist.\n");
else
netListPtr = &netList;
}
def = RtrDecompose(routeUse, area, netListPtr);
/* Clean up global routing information */
if (netListPtr)
NLFree(netListPtr);
return (def);
}
/*
* ----------------------------------------------------------------------------
*
* RtrDecompose --
*
* Top level function of the channel decomposition code. Initialize
* and then enumerate subcells of the edit cell for processing.
* Channels can currently appear only in empty space where there
* are no subcells.
*
* The list of all nets to route is pointed to by 'netList'; this
* will eventually be used when support for over-cell channels is
* put back in.
*
* Results:
* Pointer to the def holding the decomposed channel tiles. If
* the area is too small to be useful, returns NULL.
*
* Side effects:
* The DRC error plane of the returned cell def is marked with space
* tiles [ NO LONGER MAXIMAL HORIZONTAL ] representing channels.
* Modifies area to round it down to even grid points. Modifies
* RouteArea to hold final routing area.
*
* ----------------------------------------------------------------------------
*/
CellDef *
RtrDecompose(routeUse, area, netList)
CellUse *routeUse;
Rect *area;
NLNetList *netList;
{
SearchContext scx;
CellDef *cdTo;
int tmp;
/*
* Redoing the channel structure invalidates the RtrTileToChannel table.
* Reinitialize the hash table before proceeding.
*/
if (rtrDidInit) rtrHashKill(&RtrTileToChannel);
HashInit(&RtrTileToChannel, 128, 1);
rtrDidInit = TRUE;
/*
* Round area up so that its edges are at the canonical places
* halfway between grid points.
*/
tmp = RTR_GRIDUP(area->r_xtop, RtrOrigin.p_x) - RtrGridSpacing/2;
if (tmp < area->r_xtop) area->r_xtop = tmp + RtrGridSpacing;
else area->r_xtop = tmp;
tmp = RTR_GRIDUP(area->r_xbot, RtrOrigin.p_x) - RtrGridSpacing/2;
if (tmp > area->r_xbot) area->r_xbot = tmp - RtrGridSpacing;
else area->r_xbot = tmp;
tmp = RTR_GRIDUP(area->r_ytop, RtrOrigin.p_y) - RtrGridSpacing/2;
if (tmp < area->r_ytop) area->r_ytop = tmp + RtrGridSpacing;
else area->r_ytop = tmp;
tmp = RTR_GRIDUP(area->r_ybot, RtrOrigin.p_y) - RtrGridSpacing/2;
if (tmp > area->r_ybot) area->r_ybot = tmp - RtrGridSpacing;
else area->r_ybot = tmp;
RouteArea = *area;
if (GEO_RECTNULL(area)) return NULL;
cdTo = RtrFindChannelDef();
/*
* Paint non-space tiles in both the DRC check and error planes where
* cells are in the source def. Pass the search area to rtrSrCells()
* vi the global RouteArea. The code in rtrSrCells() takes care of
* leaving empty space wherever there are __CHANNEL__ labels.
*
* We make two copies of the channel information because it isn't
* safe to be both searching and updating the same plane. Thus,
* one plane (DRC check) is used for searching, but updates are
* made in the other plane.
*/
UndoDisable();
DBClearPaintPlane(cdTo->cd_planes[PL_DRC_ERROR]);
DBClearPaintPlane(cdTo->cd_planes[PL_DRC_CHECK]);
scx.scx_use = routeUse;
scx.scx_area = RouteArea;
scx.scx_trans = GeoIdentityTransform;
(void) DBCellSrArea(&scx, rtrSrCells, (ClientData) cdTo);
/* Split space tiles to the edges of the routing area */
rtrSplitToArea(&RouteArea, cdTo);
/*
* Clear the valid flags for horizontal edges for all space tiles in
* the error plane of the result cell.
*/
(void) DBSrPaintArea((Tile *) NULL, cdTo->cd_planes[PL_DRC_ERROR],
&RouteArea, &DBAllTypeBits, rtrSrClear,
(ClientData) &RouteArea);
/*
* Enumerate all tiles in the given area.
* If a tile is not a space tile, then perform the corner
* extension algorithm.
*/
(void) DBSrPaintArea((Tile *) NULL, cdTo->cd_planes[PL_DRC_CHECK],
&RouteArea, &DBAllTypeBits, rtrSrFunc,
(ClientData) (cdTo->cd_planes[PL_DRC_ERROR]));
/* Allow the modified area to be redisplayed if the cell is visible */
DBReComputeBbox(cdTo);
DBWAreaChanged(cdTo, &RouteArea, DBW_ALLWINDOWS, &DBAllButSpaceBits);
UndoEnable();
return (cdTo);
}
/*
* ----------------------------------------------------------------------------
*
* RtrFindChannelDef --
*
* Return a pointer to the __CHANNEL__ cell def that holds the
* channel structure. Creates this cell if it doesn't exist
*
* Results:
* Pointer to the __CHANNEL__ def.
*
* Side effects:
* May create the __CHANNEL__ def if it doesn't already exist.
* If it creates the def, marks it as CDINTERNAL.
*
* ----------------------------------------------------------------------------
*/
CellDef *
RtrFindChannelDef()
{
CellDef *def;
/* Create our target cell */
if ((def = DBCellLookDef("__CHANNEL__")) == (CellDef *) NULL)
{
def = DBCellNewDef("__CHANNEL__");
DBCellSetAvail(def);
def->cd_flags |= CDINTERNAL;
}
return (def);
}
/*
* ----------------------------------------------------------------------------
*
* rtrSrCells --
*
* Paints a silhouette of the cell tile plane. For each cell, paint
* error paint into the error plane of the CellDef 'def'. Clip any
* paints to the global RouteArea. If the cell is an array, enumerate
* each of its instances separately; this allows connections on interior
* edges of the array.
*
* Results:
* Returns 0 to keep DBCellSrArea from aborting the search.
*
* Side effects:
* Paints into both the DRC check and DRC error planes of the celldef
* given by 'def'. The area of each cell is expanded before painting,
* out to points midway between grid lines. The points are chosen
* so that any routing on grid lines outside the painted area will
* be far enough from the cell not to cause design-rule violations
* (this distance is determined by RtrSubcellSep). In addition, one
* extra grid line is left along side cells to jog terminals over
* to grid points.
*
* ----------------------------------------------------------------------------
*/
int
rtrSrCells(scx, targetDef)
SearchContext *scx; /* The cell to be painted */
CellDef *targetDef; /* The def into which the silhouette is painted */
{
CellDef *def = scx->scx_use->cu_def;
Rect rootBbox, gridBbox;
/*
* Transform the enumerated cell use outlines to get the outline
* of the cell within its parent.
*/
RtrMilestonePrint();
GeoTransRect(&scx->scx_trans, &def->cd_bbox, &rootBbox);
/*
* First, move down the bottom and left boundaries of the cell
* to a safe point midway between grid lines.
*/
gridBbox = rootBbox;
rtrRoundRect(&gridBbox, RtrSubcellSepUp, RtrSubcellSepDown, TRUE);
/* Clip to the routing area and paint into the channel planes */
GeoClip(&gridBbox, &RouteArea);
(void) DBPaintPlane(targetDef->cd_planes[PL_DRC_CHECK], &gridBbox,
DBStdWriteTbl(CELLTILE), (PaintUndoInfo *) NULL);
(void) DBPaintPlane(targetDef->cd_planes[PL_DRC_ERROR], &gridBbox,
DBStdWriteTbl(CELLTILE), (PaintUndoInfo *) NULL);
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* rtrRoundRect --
*
* Round a rectangle out to the nearest grid line, and
* extend to a point halfway to the next grid point (if
* doRoundUp is TRUE) or back half a grid from the nearest
* grid line (if doRoundUp is FALSE).
*
* The halfway points are chosen to be RtrGridSpacing/2
* down or to the left from grid lines. Before rounding,
* we add sepUp to the top and right, and sepDown to the
* bottom and left.
*
* Results:
* None.
*
* Side effects:
* Modifies 'r' as indicated above.
*
* ----------------------------------------------------------------------------
*/
void
rtrRoundRect(r, sepUp, sepDown, doRoundUp)
Rect *r;
int sepUp, sepDown;
bool doRoundUp;
{
int halfGrid = RtrGridSpacing / 2;
r->r_xbot = RTR_GRIDDOWN(r->r_xbot - sepDown, RtrOrigin.p_x);
r->r_ybot = RTR_GRIDDOWN(r->r_ybot - sepDown, RtrOrigin.p_y);
if (doRoundUp)
{
r->r_xbot -= halfGrid;
r->r_ybot -= halfGrid;
}
else
{
r->r_xbot += RtrGridSpacing - halfGrid;
r->r_ybot += RtrGridSpacing - halfGrid;
}
/*
* Move up the top and right boundaries. Note: it's important
* that we always SUBTRACT halfgrid from a grid point rather
* than adding sometimes: if RtrGridSpacing is odd, then adding
* and subtracting give different results.
*/
r->r_xtop = RTR_GRIDUP(r->r_xtop + sepUp, RtrOrigin.p_x);
r->r_ytop = RTR_GRIDUP(r->r_ytop + sepUp, RtrOrigin.p_y);
if (doRoundUp)
{
r->r_xtop += RtrGridSpacing - halfGrid;
r->r_ytop += RtrGridSpacing - halfGrid;
}
else
{
r->r_xtop -= halfGrid;
r->r_ytop -= halfGrid;
}
}
/*
* ----------------------------------------------------------------------------
*
* rtrHashKill --
*
* Free the remaining storage in channels in the hash table.
* Kill the table.
*
* Results:
* None.
*
* Side effects:
* Memory gets freed. The global RtrTileToChannel gets cleared.
*
* ----------------------------------------------------------------------------
*/
void
rtrHashKill(ht)
HashTable *ht;
{
HashEntry *he;
HashSearch hs;
HashStartSearch(&hs);
while (he = HashNext(ht, &hs))
GCRFreeChannel((GCRChannel *) HashGetValue(he));
HashKill(ht);
}
/*
* ----------------------------------------------------------------------------
*
* rtrSplitToArea --
*
* Clip space tiles to the edges of the (given) routing area.
*
* Results:
* None.
*
* Side effects:
* Changes tiles in the data base.
*
* ----------------------------------------------------------------------------
*/
void
rtrSplitToArea(area, def)
Rect *area; /* Routing area */
CellDef *def; /* Def holding routing results */
{
Tile *tile;
Point p;
/*
* First split top and bottom space tiles, if any.
* Note, there is at most one space tile spanning the top
* of the routing area, due to the horizontal strip property
* plus the earlier clipping of cell tiles to the routing area.
*/
p = area->r_ur;
tile = TiSrPoint((Tile *) NULL, def->cd_planes[PL_DRC_ERROR], &p);
if ((TOP(tile) > area->r_ytop) && (BOTTOM(tile) < area->r_ytop))
(void) TiSplitY(tile, area->r_ytop);
p.p_y = area->r_ll.p_y - 1;
tile = TiSrPoint((Tile *) NULL, def->cd_planes[PL_DRC_ERROR], &p);
if ((BOTTOM(tile) < area->r_ybot) && (TOP(tile) > area->r_ybot))
tile = TiSplitY(tile, area->r_ybot);
/*
* Search up the left edge of the routing area,
* looking for space tiles spanning the edge.
* If found, split them.
*/
p = area->r_ll;
while (p.p_y < area->r_ytop)
{
tile = TiSrPoint(tile, def->cd_planes[PL_DRC_ERROR], &p);
if ((LEFT(tile) < p.p_x) && (RIGHT(tile) > p.p_x))
tile = TiSplitX(tile, p.p_x);
p.p_y = TOP(tile);
}
/* Do the right edge of the routing area in the same manner */
p.p_x = area->r_xtop;
p.p_y = area->r_ybot;
while (p.p_y < area->r_ytop)
{
tile = TiSrPoint(tile, def->cd_planes[PL_DRC_ERROR], &p);
if ((LEFT(tile) < p.p_x) && (RIGHT(tile) > p.p_x))
tile = TiSplitX(tile, p.p_x);
p.p_y = TOP(tile);
}
}
/*
* ----------------------------------------------------------------------------
*
* rtrSrClear --
*
* DBSrPaintArea function for each tile in the error plane of the __CHANNEL__
* def. Sets the flags to 0 in internal space tiles, marking horizontal
* invalid. Mark edges at the boundary of the routing region as valid.
*
* Results:
* Always returns 0.
*
* Side effects:
* Sets flags in tiles.
*
* ----------------------------------------------------------------------------
*/
int
rtrSrClear(tile, area)
Tile *tile;
Rect *area;
{
/* Clear all */
rtrCLEAR(tile, -1);
if (TiGetBody(tile) == (ClientData) NULL)
{
/* Mark horizontal edges touching box */
if (TOP(tile) == area->r_ytop)
{
/* Mark top */
rtrMARK(tile, rtrNW);
rtrMARK(tile, rtrNE);
}
if (BOTTOM(tile) == area->r_ytop)
{
/* Mark bottom */
rtrMARK(tile, rtrSW);
rtrMARK(tile, rtrSE);
}
}
else
{
/* Mark all flags in a non-space tile */
/* Mark top */
rtrMARK(tile, rtrNW);
rtrMARK(tile, rtrNE);
/* Mark bottom */
rtrMARK(tile, rtrSW);
rtrMARK(tile, rtrSE);
}
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* rtrSrFunc --
*
* Search function called from DBSrPaintArea for each tile in the
* plane. Do this search in the OLD TILE PLANE. Process corners
* bordering space tiles.
*
* Results:
* Returns a 0 to DBSrPaintArea so it won't abort the search.
*
* Side effects:
* Modifies the result plane to reflect the channel structure.
*
* ----------------------------------------------------------------------------
*/
int
rtrSrFunc(tile, plane)
Tile *tile; /* Candidate cell tile */
Plane *plane; /* Plane in which searches take place */
{
Tile *tiles[3];
Point p;
/* Ignore space tiles */
if (TiGetBody(tile) == (ClientData) NULL)
return (0);
/*
* Check each corner of this cell tile to see if it is convex,
* and no marked boundary is incident upon it.
*/
p = tile->ti_ll;
if (rtrUseCorner(&p, rtrSW, plane, tiles))
rtrMarkChannel(plane, tiles, &p, rtrSW);
p.p_y = TOP(tile);
if (rtrUseCorner(&p, rtrNW, plane, tiles))
rtrMarkChannel(plane, tiles, &p, rtrNW);
p.p_x = RIGHT(tile);
if (rtrUseCorner(&p, rtrNE, plane, tiles))
rtrMarkChannel(plane, tiles, &p, rtrNE);
p.p_y = BOTTOM(tile);
if (rtrUseCorner(&p, rtrSE, plane, tiles))
rtrMarkChannel(plane, tiles, &p, rtrSE);
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* rtrUseCorner --
*
* Search for legal corners upon which to apply the channel definition
* algorithm. Check both horizontal tiles for markings, since only
* one (the shorter) might be marked.
*
* Results:
* Return FALSE if the corner is not convex or a legal boundary already
* extends from the corner. Otherwise return TRUE.
*
* Side effects:
* Return pointers to space tiles adjacent to the corner.
* tiles[0] is not modified by this routine.
* tiles[1] is the spanning tile above or below the corner.
* tiles[2] is the side tile left or right of the corner.
*
* ----------------------------------------------------------------------------
*/
bool
rtrUseCorner(point, corner, plane, tiles)
Point *point; /* Point at which a cell corner is found */
int corner; /* Selects NE, NW, SE, or SW cell corner */
Plane *plane; /* Plane to be searched for tiles */
Tile *tiles[]; /* Return pointers to found space tiles */
{
Point p0, p1;
Tile * tile;
/* Reject a corner if it lies on the boundary of the routing area */
if (point->p_x <= RouteArea.r_xbot
|| point->p_x >= RouteArea.r_xtop
|| point->p_y <= RouteArea.r_ybot
|| point->p_y >= RouteArea.r_ytop)
{
return (FALSE);
}
/*
* Search the area above (below) the corner. If two space tiles, then a
* vertical boundary marks a channel edge. If one top (bottom) tile and
* one side tile, and the horizontal edge is not marked, then the corner
* is okay.
*/
p1 = p0 = *point;
switch (corner)
{
case rtrNE:
p1.p_y--;
break;
case rtrNW:
p1.p_x--;
p1.p_y--;
break;
case rtrSE:
p0.p_y--;
break;
case rtrSW:
p0.p_y--;
p1.p_x--;
break;
default:
ASSERT(FALSE, "rtrUseCorner corner botch");
break;
}
tile = tiles[1] = TiSrPoint((Tile *) NULL, plane, &p0);
if( (TiGetBody(tile) != (ClientData) NULL) || (LEFT(tile) == point->p_x)
|| (RIGHT(tile) == point->p_x) )
return(FALSE); /* Vertical boundary at corner */
tile = tiles[2] = TiSrPoint((Tile *) NULL, plane, &p1);
if(TiGetBody(tile) != (ClientData) NULL)
return(FALSE); /* Not a corner */
switch(corner)
{
case rtrNE: return(!rtrMARKED(tile, rtrNW)); break;
case rtrNW: return(!rtrMARKED(tile, rtrNE)); break;
case rtrSE: return(!rtrMARKED(tile, rtrSW)); break;
case rtrSW: return(!rtrMARKED(tile, rtrSE)); break;
}
return(FALSE);
}
/*
* ----------------------------------------------------------------------------
*
* rtrMarkChannel --
*
* Find the shortest segment from the corner to another boundary.
* Split and merge space tiles to reflect channel structure. Update
* edge status in the tile plane.
*
* Results:
* None.
*
* Side effects:
* Modifies the result plane to reflect channel definition.
*
* ----------------------------------------------------------------------------
*/
void
rtrMarkChannel(plane, tiles, point, corner)
Plane *plane; /* Plane for searching */
Tile *tiles[]; /* Bordering space tiles */
Point *point; /* Coordinates of corner */
int corner; /* Corner of tile to process */
{
int xDist, yDist, d1, d2, lastY;
Tile *tile, *new;
Point curPt;
bool pos;
pos = ((corner == rtrNE) || (corner == rtrSE));
xDist = rtrXDist(tiles, point->p_x, pos);
yDist = rtrYDist(tiles, point, ((corner==rtrNE) || (corner==rtrNW)), plane);
if (xDist < yDist) /* Choose and mark the horizontal boundary */
{
if(pos)
{
d1 = RIGHT(tiles[1]);
d2 = RIGHT(tiles[2]);
if(corner == rtrNE)
{
rtrMARK(tiles[2], rtrNW);
if(d1 >= d2) rtrMARK(tiles[2], rtrNE);
if(d1 <= d2) rtrMARK(tiles[1], rtrSE);
}
else
{
rtrMARK(tiles[2], rtrSW);
if(d1 >= d2) rtrMARK(tiles[2], rtrSE);
if(d1 <= d2) rtrMARK(tiles[1], rtrNE);
}
}
else
{
d1 = LEFT(tiles[1]);
d2 = LEFT(tiles[2]);
if(corner == rtrNW)
{
rtrMARK(tiles[2], rtrNE);
if(d1 >= d2) rtrMARK(tiles[2], rtrNW);
if(d1 <= d2) rtrMARK(tiles[1], rtrSW);
}
else
{
rtrMARK(tiles[2], rtrSE);
if(d1 >= d2) rtrMARK(tiles[2], rtrSW);
if(d1 <= d2) rtrMARK(tiles[1], rtrNW);
}
}
}
else /* Choose the vertical boundary */
{
/*
* Split a sequence of space tiles starting with tiles[0]
* (the bottom tile), for yDist at the point->p_y.
* Merge tiles where possible.
*/
tile=tiles[0];
curPt.p_x=point->p_x;
curPt.p_y=BOTTOM(tile);
lastY = point->p_y;
if((corner == rtrNW) || (corner == rtrNE)) lastY += yDist;
while(TRUE)
{
ASSERT(TiGetBody(tile) == (ClientData)NULL,
"rtrMerge: merge cell tile");
new = TiSplitX(tile, curPt.p_x);
ASSERT(TiGetBody(new) == (ClientData)NULL, "rtrMerge: merge cell new");
/* Fix horizontal flags in 'new' tile and (old) 'tile' tile */
if (rtrMARKED(tile,rtrNE)) rtrMARK(new,rtrNE);
else rtrCLEAR(new,rtrNE);
if (rtrMARKED(tile,rtrSE)) rtrMARK(new,rtrSE);
else rtrCLEAR(new,rtrNE);
/*
* Clear these flags:
* couldn't cross the boundary unless it was clear.
*/
rtrCLEAR(new, rtrNW);
rtrCLEAR(new, rtrSW);
rtrCLEAR(tile, rtrNE);
rtrCLEAR(tile, rtrSE);
/* Merge tile and new with lower neighbors if possible */
rtrMerge(new, LB(new), plane);
rtrMerge(tile, LB(tile), plane);
/* Find next (higher) tile to split */
if (TOP(tile) >= lastY) break;
curPt.p_y = TOP(tile);
tile=TiSrPoint(tile, plane, &curPt);
}
/* Merge new and tile with upper neighbors if possible */
rtrMerge(RT(new), new, plane);
rtrMerge(RT(tile), tile, plane);
}
}
/*
* ----------------------------------------------------------------------------
*
* rtrYDist --
*
* Finds the distance from a point to an upper or lower channel boundary.
*
* Results:
* The integer distance from the point to the boundary.
*
* Side effects:
* Return a pointer to the bottom tile in the split sequence.
*
* ----------------------------------------------------------------------------
*/
int
rtrYDist(tiles, point, up, plane)
Tile *tiles[]; /* Start tile in [1]. Put bottom tile in [0] */
Point *point; /* Point from which distance is measure */
bool up; /* TRUE if search up, FALSE if down */
Plane *plane; /* Cell plane for search */
{
Tile *current = tiles[1], *next;
int x, yStart, flag;
Point p;
p = *point;
x = p.p_x;
yStart = p.p_y;
for (;;)
{
if (up)
{
p.p_y = TOP(current);
if (p.p_y >= RouteArea.r_ytop) break;
}
else
{
p.p_y = BOTTOM(current);
if (p.p_y <= RouteArea.r_ybot) break;
p.p_y--;
}
/*
* See if we ran into a cell tile. Since the cell tile defines
* the boundary of a channel, terminate the search. If going
* down, reset the y coordinate to the bottom of the last good
* channel.
*/
next = TiSrPoint(current, plane, &p);
if (TiGetBody(next) != (ClientData) NULL)
{
if (!up) p.p_y++;
break;
}
/* Done if a vertical boundary */
if (LEFT(next) == x || RIGHT(next) == x)
break;
/*
* Classify as one of the following cases:
*
* __|_n_|__ |___c___| __|_n__| |__ c|__ |__n|__ __|_c__|
* | c | | n | | c| | n | |c | | n|
* (A) (B) (C) (D) (E) (F)
*/
if (LEFT(current) < LEFT(next))
{
if (RIGHT(current) > RIGHT(next))
{
if (up) flag = rtrMARKED(next, rtrSW); /*(A)*/
else flag = rtrMARKED(next, rtrNW); /*(B)*/
}
else
{
if (up) flag = rtrMARKED(current, rtrNE); /*(C)*/
else flag = rtrMARKED(current, rtrSE); /*(D)*/
}
}
else
{
if (up) flag = rtrMARKED(current, rtrNW); /*(E)*/
else flag = rtrMARKED(current, rtrSW); /*(F)*/
}
if (flag)
{
if (!up) p.p_y = BOTTOM(current);
break;
}
current = next;
}
if (up)
{
tiles[0] = tiles[1];
return (p.p_y - yStart);
}
else
{
tiles[0] = current;
return (yStart - p.p_y);
}
}
/*
* ----------------------------------------------------------------------------
*
* rtrXDist --
*
* Finds the distance from a point to a left or right channel boundary.
*
* Results:
* The integer distance from the point to the boundary.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
rtrXDist(tiles, x, isRight)
Tile *tiles[]; /* Space tiles bordering the corner */
int x; /* Starting x for distance calculation */
bool isRight; /* TRUE if right, FALSE if left */
{
int l0, l1;
if (isRight)
l0 = RIGHT(tiles[1]) - x, l1 = RIGHT(tiles[2]) - x;
else
l0 = x - LEFT(tiles[1]), l1 = x - LEFT(tiles[2]);
return (MIN(l0, l1));
}
/*
* ----------------------------------------------------------------------------
*
* rtrMerge --
*
* Merge two space tiles provided they share a common horizontal edge.
* The upper is the first argument tile.
*
* Results:
* None.
*
* Side effects:
* Updates the horizontal flags in the resulting tile.
*
* ----------------------------------------------------------------------------
*/
void
rtrMerge(tup, tdn, plane)
Tile *tup, *tdn;
Plane *plane;
{
Tile *side;
/* Skip if either is a cell tile */
if (TiGetBody(tup) != (ClientData) NULL
|| TiGetBody(tdn) != (ClientData) NULL)
return;
if (LEFT(tdn) != LEFT(tup) || RIGHT(tdn) != RIGHT(tup))
return;
/*
* Set flags for the result.
* Relies on TiJoinY to preserve the first arg as the composite tile.
*/
ASSERT( (BOTTOM(tdn)>=RouteArea.r_ybot) && (TOP(tup)<=RouteArea.r_ytop),
"rtrMerge: merging with a tile outside the routing area");
if (rtrMARKED(tdn, rtrSW)) rtrMARK(tup, rtrSW); else rtrCLEAR(tup, rtrSW);
if (rtrMARKED(tdn, rtrSE)) rtrMARK(tup, rtrSE); else rtrCLEAR(tup, rtrSE);
TiJoinY(tup, tdn, plane);
/*
* Merge sideways if the result of the join matches a tile on either side,
* provided the neighbor is a space tile and is inside the routing area.
*/
side = BL(tup);
if (TiGetBody(side) == (ClientData) NULL
&& LEFT(side) >= RouteArea.r_xbot
&& TOP(side) == TOP(tup)
&& BOTTOM(side) == BOTTOM(tup))
TiJoinX(tup, side, plane);
side = TR(tup);
if (TiGetBody(side) == (ClientData) NULL
&& RIGHT(side) <= RouteArea.r_xtop
&& TOP(side) == TOP(tup)
&& BOTTOM(side) == BOTTOM(tup))
TiJoinX(tup, side, plane);
}