/* rtrChannel.c - * * Code to handle channels and the obstacles within them. * * ********************************************************************* * * 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/rtrChannel.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $"; #endif /* not lint */ #include #include #include "utils/magic.h" #include "utils/geometry.h" #include "utils/geofast.h" #include "utils/hash.h" #include "utils/heap.h" #include "tiles/tile.h" #include "database/database.h" #include "gcr/gcr.h" #include "windows/windows.h" #include "dbwind/dbwind.h" #include "utils/signals.h" #include "utils/main.h" #include "router/router.h" #include "router/rtrDcmpose.h" #include "grouter/grouter.h" #include "textio/textio.h" #include "utils/styles.h" /* C99 compat */ #include "router/routerInt.h" /* * Maps a tile pointer to a channel structure. * We use this rather than the client fields of tiles because * they are already used to hold flags during channel decomposition. */ HashTable RtrTileToChannel; /* Plane in __CHANNEL__ def holding channel tiles */ Plane *RtrChannelPlane; /* List of channels created from decomposed tile plane */ GCRChannel *RtrChannelList = NULL; /* Multiplier for when to make end connections */ #ifndef lint float RtrEndConst = 1.0; #else float RtrEndConst; /* Sun lint brain death */ #endif /* lint */ /* Forward declarations */ extern int rtrChannelObstacleMark(); extern void rtrChannelObstaclePins(); /* * ---------------------------------------------------------------------------- * * RtrChannelRoute -- * * This procedure invokes the channel router for the channel 'ch'. * If the channel is taller than it is wide, swap in x and y before * routing. If the channel has more pins on the left edge than the * right, flip left to right before routing. * * Results: * None. * * Side effects: * The parameter *pCount is incremented by the number of errors that * occurred while routing this channel. * * ---------------------------------------------------------------------------- */ void RtrChannelRoute(ch, pCount) GCRChannel *ch; int *pCount; { GCRChannel *flipped, *flipped_again, *copy; int errs1, errs2; /* * Mark unused stem-tip crossing points as unused once again. * (They had been marked as blocked during global routing so * the global router wouldn't try to use them to route over * cell tops, thereby making it impossible to generate a stem). */ RtrPinsFixStems(ch); /* * If the channel is taller than it is long, flip it before * routing, in order to give the router a better chance of success. */ if (ch->gcr_width < ch->gcr_length) { flipped = GCRNewChannel(ch->gcr_length, ch->gcr_width); GCRNoFlip(ch, flipped); errs1 = GCRroute(flipped); if (errs1 == 0) { /* Save the routing results back in ch. Clean up and return */ GCRNoFlip(flipped, ch); RtrFBPaint(0); goto bottom; } /* Try again with a left-right flip */ RtrFBSwitch(); flipped_again = GCRNewChannel(ch->gcr_length, ch->gcr_width); GCRFlipLeftRight(ch, flipped_again); errs2 = GCRroute(flipped_again); if (GcrDebug) TxError(" Rerouting a channel with %d errors...", errs1); if (errs2 < errs1) { errs1 = errs2; GCRFlipLeftRight(flipped_again, ch); if (GcrDebug) TxError(" to get %d errors\n", errs1); RtrFBPaint(1); } else { GCRNoFlip(flipped, ch); if(GcrDebug) TxError(" unsuccessfully.\n"); RtrFBPaint(0); } GCRFreeChannel(flipped_again); goto bottom; } else { flipped = GCRNewChannel(ch->gcr_width, ch->gcr_length); GCRFlipXY(ch, flipped); errs1 = GCRroute(flipped); if(errs1 == 0) { GCRFlipXY(flipped, ch); RtrFBPaint(0); goto bottom; } RtrFBSwitch(); flipped_again = GCRNewChannel(flipped->gcr_length, flipped->gcr_width); GCRFlipXY(ch, flipped_again); copy = GCRNewChannel(flipped->gcr_length, flipped->gcr_width); GCRFlipLeftRight(flipped_again, copy); if(GcrDebug) TxError(" Rerouting a channel with %d errors ...", errs1); errs2 = GCRroute(copy); if(errs2 < errs1) { errs1 = errs2; GCRFlipLeftRight(copy, flipped); if(GcrDebug) TxError(" successfully, with %d errors\n", errs1); RtrFBPaint(1); } else { RtrFBPaint(0); if(GcrDebug) TxError(" unsuccessfully\n"); } GCRFlipXY(flipped, ch); GCRFreeChannel(flipped_again); // GCRFreeChannel(copy); // FIXME evaluate if this should be uncommented } bottom: GCRFreeChannel(flipped); if (errs1 > 0) gcrSaveChannel(ch); *pCount += errs1; RtrMilestonePrint(); } /* * ---------------------------------------------------------------------------- * * RtrChannelBounds -- * * Figure out the dimensions of the given channel. * * Results: * None. * * Side effects: * The parameters plength and pwidth are filled in with the number * of usable columns and rows in channel. The Point pointed to * by 'origin' is filled in with x and y coords to go in * ch->origin. * * ---------------------------------------------------------------------------- */ void RtrChannelBounds(loc, pLength, pWidth, origin) Rect *loc; /* Area the channel is to occupy */ int *pLength; /* Filled in with # columns in channel */ int *pWidth; /* Filled in with # rows in channel */ Point *origin; /* Filled in with coords of (0,0) grid point * (one grid line below and to left of first * usable grid point) */ { char mesg[256]; int hi, lo; /* Find rightmost and leftmost grid contained within channel area */ hi = RTR_GRIDDOWN(loc->r_xtop, RtrOrigin.p_x); lo = RTR_GRIDUP(loc->r_xbot, RtrOrigin.p_x); origin->p_x = lo - RtrGridSpacing; if (hi < lo) { (void) sprintf(mesg, "Degenerate channel at (%d, %d) (%d, %d)", loc->r_xbot, loc->r_ybot, loc->r_xtop, loc->r_ytop); DBWFeedbackAdd(loc, mesg, EditCellUse->cu_def, 1, STYLE_PALEHIGHLIGHTS); TxError("%s\n", mesg); } *pLength = (hi - lo) / RtrGridSpacing + 1; /* Find topmost and bottommost grid contained within channel area */ hi = RTR_GRIDDOWN(loc->r_ytop, RtrOrigin.p_y); lo = RTR_GRIDUP(loc->r_ybot, RtrOrigin.p_y); origin->p_y = lo - RtrGridSpacing; if (hi < lo) { (void) sprintf(mesg, "Degenerate channel at (%d, %d) (%d, %d)", loc->r_xbot, loc->r_ybot, loc->r_xtop, loc->r_ytop); DBWFeedbackAdd(loc, mesg, EditCellUse->cu_def, 1, STYLE_PALEHIGHLIGHTS); TxError("%s\n", mesg); } *pWidth = (hi - lo) / RtrGridSpacing + 1; } /* * ---------------------------------------------------------------------------- * * RtrChannelObstacles -- * * Searches a channel area for obstacles. Sets the channel obstacle map * to indicate which grid locations have obstacles. Uses DBTreeSrTiles() * to search for obstacles, rather than DBSrPaintArea, since channels can * lie over existing cells. * * Mark obstacles to channel crossings. Reserve blocked pins for net * GCR_BLOCKEDNETID. Flag obstructed pins to allow the size of their * accompanying obstacle to be set later (by RtrHazards()). * * Only obstacles in this channel are considered; GLBlockPins() must be * called later to propagate the obstacle information from the border of * this channel to adjacent channels. * * NOTE: RtrChannelObstacles() and those procedures it calls are heavily * tuned for speed, since DBTreeSrTiles can cause flat searching of * large portions of a design hierarchy if invoked over the tops of cells. * * Results: * None. * * Side effects: * Sets the channel obstacle map. * * ---------------------------------------------------------------------------- */ void RtrChannelObstacles(use, ch) CellUse *use; GCRChannel * ch; { int l, w, up = RtrSubcellSepUp, down = RtrSubcellSepDown; TileTypeBitMask allObs; SearchContext scx; /* * Set the obstacle maps in the metal and poly planes. * Ensure that the combination of this channel and its * neighbors are sufficient to cover all obstacles in * the area between the outermost tracks/columns of this * channel and those of its neighbors. */ if (RtrSubcellSepUp + RtrSubcellSepDown < RtrGridSpacing) { /* Shouldn't happen; this is just insurance */ up = RtrGridSpacing - RtrSubcellSepDown; } l = ch->gcr_length + 1; w = ch->gcr_width + 1; scx.scx_area.r_ll = scx.scx_area.r_ur = ch->gcr_origin; scx.scx_area.r_xbot -= up; scx.scx_area.r_ybot -= up; scx.scx_area.r_xtop += l * RtrGridSpacing + down; scx.scx_area.r_ytop += w * RtrGridSpacing + down; scx.scx_use = use; scx.scx_trans = GeoIdentityTransform; TTMaskZero(&allObs); TTMaskSetMask3(&allObs, &RtrMetalObstacles, &RtrPolyObstacles); (void) DBTreeSrTiles(&scx, &allObs, 0, rtrChannelObstacleMark, (ClientData) ch); rtrChannelObstaclePins(ch); } /* * ---------------------------------------------------------------------------- * * rtrChannelObstaclePins -- * * Mark obstacles to channel crossings. An obstacle affects a channel * crossing if it lies within the area from the first track of this * channel to the first track of the next channel. Reserve blocked pins * for net GCR_BLOCKEDNETID (ILLEGAL). Flag obstructed pins to allow the * size of their accompanying obstacle to be set later. * * Results: * None. * * Side effects: * Sets the channel obstacle map. * * ---------------------------------------------------------------------------- */ void rtrChannelObstaclePins(ch) GCRChannel *ch; { short **res; int row, col, end; res = ch->gcr_result; end = ch->gcr_length + 1; for (row = 1; row <= ch->gcr_width; row++) { if (BLOCK(res[0][row])) { ch->gcr_lPins[row].gcr_pId = GCR_BLOCKEDNETID; ch->gcr_lPins[row].gcr_pFlags = GCRBLK; } else if (!CLEAR(res[0][row])) ch->gcr_lPins[row].gcr_pFlags = GCROBST; if (BLOCK(res[end][row])) { ch->gcr_rPins[row].gcr_pId = GCR_BLOCKEDNETID; ch->gcr_rPins[row].gcr_pFlags = GCRBLK; } else if (!CLEAR(res[end][row])) ch->gcr_rPins[row].gcr_pFlags = GCROBST; } end = ch->gcr_width+1; for (col = 1; col <= ch->gcr_length; col++) { if (BLOCK(res[col][0])) { ch->gcr_bPins[col].gcr_pId = GCR_BLOCKEDNETID; ch->gcr_bPins[col].gcr_pFlags = GCRBLK; } else if (!CLEAR(res[col][0])) ch->gcr_bPins[col].gcr_pFlags = GCROBST; if (BLOCK(res[col][end])) { ch->gcr_tPins[col].gcr_pId = GCR_BLOCKEDNETID; ch->gcr_tPins[col].gcr_pFlags = GCRBLK; } else if (!CLEAR(res[col][end])) ch->gcr_tPins[col].gcr_pFlags = GCROBST; } } /* * ---------------------------------------------------------------------------- * * rtrChannelObstacleMark -- * * Search routine called by DBTreeSrTiles() from RtrChannelObstacles * for each tile found in the given area. If the tile is an obstacle, * mark locations in the channel flag map to indicate their presence. * * In addition to setting the GCRBLKM/GCRBLKP flags, we set the bits * GCRBLKT/GCRBLKC to indicate whether the obstacle blocks a track or * a column. These latter bits are used only for initializing the * density information for global routing, and should be reset to * zero prior to calling the channel router (since they conflict * with the bits used to show routing). * * Results: * Always returns 0. * * Side effects: * Sets the obstacle map for obstacles in a given channel. * * ---------------------------------------------------------------------------- */ int rtrChannelObstacleMark(tile, cxp) Tile *tile; TreeContext *cxp; { short **mcol, *mrow, *mrowend, mask; GCRChannel *ch = (GCRChannel *) cxp->tc_filter->tf_arg; TileType type = TiGetType(tile); int loX, numX, loY; short **mcolend; int n; Rect r, r2; mask = 0; if (TTMaskHasType(&RtrMetalObstacles, type)) mask |= GCRBLKM; if (TTMaskHasType(&RtrPolyObstacles, type)) mask |= GCRBLKP; if (mask == 0) return (0); TITORECT(tile, &r); GEOTRANSRECT(&cxp->tc_scx->scx_trans, &r, &r2); /* * Determine the range of columns in this channel that are blocked * by the obstacle: find the grid coordinates enclosing the tile. * Clip to a grid 1 larger than the size of the channel. */ n = r2.r_xbot - RtrPaintSepsDown[type] + 1; n = (RTR_GRIDUP(n, RtrOrigin.p_x) - ch->gcr_origin.p_x) / RtrGridSpacing; loX = MAX(n, 0); n = r2.r_xtop + RtrPaintSepsUp[type] - 1; n = (RTR_GRIDUP(n, RtrOrigin.p_x) - ch->gcr_origin.p_x) / RtrGridSpacing; numX = MIN(n, ch->gcr_length + 1) - loX; /* Do the same thing for the rows (n will be the number of rows) */ n = r2.r_ybot - RtrPaintSepsDown[type] + 1; n = (RTR_GRIDUP(n, RtrOrigin.p_y) - ch->gcr_origin.p_y) / RtrGridSpacing; loY = MAX(n, 0); n = r2.r_ytop + RtrPaintSepsUp[type] - 1; n = (RTR_GRIDDOWN(n, RtrOrigin.p_y) - ch->gcr_origin.p_y) / RtrGridSpacing; n = MIN(n, ch->gcr_width + 1) - loY; /* * Figure out whether tracks or columns are being blocked, * for purposes of the density initialization. */ if ((mask & (GCRBLKM|GCRBLKP)) == (GCRBLKM|GCRBLKP)) { /* 2-layer obstacles block both tracks and columns */ mask |= GCRBLKT|GCRBLKC; } else if (numX < n) { /* Tall and narrow obstacles block columns */ mask |= GCRBLKC; } else { /* Short and wide obstacles block tracks */ mask |= GCRBLKT; } /* * Now set the flags in the channel. * The following loop is tuned for speed. */ mcol = &ch->gcr_result[loX]; mcolend = &mcol[numX]; while (mcol <= mcolend) { mrow = &(*mcol++)[loY]; mrowend = &mrow[n]; while (mrow <= mrowend) *mrow++ |= mask; } return (0); } /* * ---------------------------------------------------------------------------- * * RtrChannelDensity -- * * Adjusts the density variables gcr_dRowsByCol and gcr_dColsByRow * to reflect the commitment of tracks or columns to existing wiring; * for each column or track blocked by material, the density for * that track is incremented. Also updates gcr_dMaxByCol and * gcr_dMaxByRow, the maximum column and track densities. * * Results: * None. * * Side effects: * Initializes ch->gcr_dRowsByCol, ch->gcr_dColsByRow arrays * and the corresponding maximum values ch->gcr_dMaxByCol * and ch->gcr_dMaxByRow. * * ---------------------------------------------------------------------------- */ void RtrChannelDensity(ch) GCRChannel *ch; { short *hdens, *vdens, *rptr; int col, density; short *hdend, *vdend; /* * Adjust the density information for global routing. * Whether a column or track is blocked is indicated by the * presence of the GCRBLKC/GCRBLKT flags in the result array. * If both bits are set, then both a column and a track are * blocked. */ hdens = &ch->gcr_dRowsByCol[1]; hdend = &ch->gcr_dRowsByCol[ch->gcr_length]; for (col = 1; hdens <= hdend; hdens++, col++) { vdens = &ch->gcr_dColsByRow[1]; vdend = &ch->gcr_dColsByRow[ch->gcr_width]; rptr = &ch->gcr_result[col][1]; for ( ; vdens <= vdend; vdens++, rptr++) { if (*rptr & GCRBLKT) *hdens += 1; if (*rptr & GCRBLKC) *vdens += 1; } } #ifdef IDENSITY bcopy((char *) ch->gcr_dColsByRow, (char *) ch->gcr_iColsByRow, (ch->gcr_width + 2) * sizeof (short)); bcopy((char *) ch->gcr_dRowsByCol, (char *) ch->gcr_iRowsByCol, (ch->gcr_length + 2) * sizeof (short)); #endif /* IDENSITY */ /* Compute the maximum row and column density */ /* Column density */ density = 0; hdens = &ch->gcr_dRowsByCol[1]; hdend = &ch->gcr_dRowsByCol[ch->gcr_length]; for ( ; hdens <= hdend; hdens++) if (*hdens > density) density = *hdens; ch->gcr_dMaxByCol = density; /* Row density */ density = 0; vdens = &ch->gcr_dColsByRow[1]; vdend = &ch->gcr_dColsByRow[ch->gcr_width]; for ( ; vdens <= vdend; vdens++) if (*vdens > density) density = *vdens; ch->gcr_dMaxByRow = density; } /* * ---------------------------------------------------------------------------- * * RtrChannelCleanObstacles -- * * Clears the GCRBLKC/GCRBLKT bits in the result array of 'ch'. * * Results: * None. * * Side effects: * Resets the GCRBLKC/GCRBLKT flags in the result array, * since these bits are also used to mean something else * by the channel router. * * ---------------------------------------------------------------------------- */ void RtrChannelCleanObstacles(ch) GCRChannel *ch; { short *rptr; int row, rtop; int col, ctop; ctop = ch->gcr_length + 1; rtop = ch->gcr_width + 1; for (col = 0; col <= ctop; col++) { rptr = &ch->gcr_result[col][0]; for (row = 0; row <= rtop; row++) *rptr++ &= ~(GCRBLKT|GCRBLKC); } }