/* * gaChannel.c - * * Channel management for the gate-array router. * * ********************************************************************* * * 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/garouter/gaChannel.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $"; #endif /* not lint */ #include #include "utils/magic.h" #include "utils/geometry.h" #include "utils/hash.h" #include "utils/heap.h" #include "tiles/tile.h" #include "database/database.h" #include "windows/windows.h" #include "utils/main.h" #include "dbwind/dbwind.h" #include "utils/signals.h" #include "netmenu/netmenu.h" #include "gcr/gcr.h" #include "router/router.h" #include "grouter/grouter.h" #include "garouter/garouter.h" #include "utils/netlist.h" #include "textio/textio.h" #include "utils/styles.h" #include "debug/debug.h" /* C99 compat */ #include "garouter/gaInternal.h" /* List of all active channels */ GCRChannel *gaChannelList = NULL; /* Def used to hold channel plane */ CellDef *gaChannelDef = NULL; /* Forward declarations */ int gaSplitTile(); int gaSetClient(); void gaChannelStats(); void gaPinStats(); void gaPropagateBlockages(); void gaInitRiverBlockages(); #define CNULL ((ClientData) NULL) int gaTotNormCross, gaTotRiverCross, gaClearNormCross, gaClearRiverCross; /* * ---------------------------------------------------------------------------- * * GAChannelInitOnce -- * * Once-only channel initialization for the gate-array router. * * Results: * None. * * Side effects: * Allocates the tile plane used to hold channel information, * RtrChannelPlane. * * ---------------------------------------------------------------------------- */ void GAChannelInitOnce() { if (gaChannelDef == NULL) gaChannelDef = RtrFindChannelDef(); RtrChannelPlane = gaChannelDef->cd_planes[PL_DRC_ERROR]; GAClearChannels(); } /* * ---------------------------------------------------------------------------- * * GAClearChannels -- * * Clear any pre-existing channels in preparation for definition of * new ones. * * Results: * None. * * Side effects: * Paints TileType 1 (blocked) over the tile plane that records all * available channel area, and frees all channel structures. * * ---------------------------------------------------------------------------- */ void GAClearChannels() { GCRChannel *ch; Rect r; r.r_xbot = TiPlaneRect.r_xbot / 2; r.r_ybot = TiPlaneRect.r_ybot / 2; r.r_xtop = TiPlaneRect.r_xtop / 2; r.r_ytop = TiPlaneRect.r_ytop / 2; SigDisableInterrupts(); (void) DBPaintPlane(RtrChannelPlane, &r, DBStdWriteTbl(1), (PaintUndoInfo *) NULL); for (ch = gaChannelList; ch; ch = ch->gcr_next) GCRFreeChannel(ch); gaChannelList = (GCRChannel *) NULL; SigEnableInterrupts(); } /* * ---------------------------------------------------------------------------- * * GADefineChannel -- * * Add a new channel definition to the list of channels we know * about. First ensure that the channel boundaries are correctly * aligned (round down if they aren't) and also that the area of * this channel has not already been assigned to another channel. * * The parameter chanType is one of 0 (for an ordinary channel), * CHAN_HRIVER (for a horizontal river-routing channel), or CHAN_VRIVER * (for a vertical river-routing channel). * * The rectangle 'r' gives the area of the channel. * * Results: * TRUE on success, FALSE on failure. * * Side effects: * Paints the area of this channel into RtrChannelPlane (as space) * to mark that this area is used. * * ---------------------------------------------------------------------------- */ bool GADefineChannel(chanType, r) int chanType; Rect *r; { int length, width, halfGrid = RtrGridSpacing / 2; GCRChannel *ch; Point origin; Rect r2; /* * Make the channel boundaries lie halfway between grid lines. * To ensure consistent results when RtrGridSpacing is odd, * we always subtract halfGrid from a grid line. */ r2 = *r; r->r_xbot = RTR_GRIDUP(r->r_xbot, RtrOrigin.p_x) - halfGrid; r->r_ybot = RTR_GRIDUP(r->r_ybot, RtrOrigin.p_y) - halfGrid; r->r_xtop = RTR_GRIDDOWN(r->r_xtop, RtrOrigin.p_x) + RtrGridSpacing - halfGrid; r->r_ytop = RTR_GRIDDOWN(r->r_ytop, RtrOrigin.p_y) + RtrGridSpacing - halfGrid; if (r2.r_xbot != r->r_xbot || r2.r_ybot != r->r_ybot || r2.r_xtop != r->r_xtop || r2.r_ytop != r->r_ytop) { TxPrintf("Rounding channel to center-grid alignment: "); TxPrintf("ll=(%d,%d) ur=(%d,%d)\n", r->r_xbot, r->r_ybot, r->r_xtop, r->r_ytop); } /* Ensure no overlap */ if (DBSrPaintArea((Tile *) NULL, RtrChannelPlane, r, &DBSpaceBits, gaAlwaysOne, (ClientData) NULL)) { TxError("Channel ll=(%d,%d) ur=(%d,%d) overlaps existing channels\n", r->r_xbot, r->r_ybot, r->r_xtop, r->r_ytop); return (FALSE); } if (DebugIsSet(gaDebugID, gaDebShowChans)) DBWFeedbackAdd(r, "Channel area", EditCellUse->cu_def, 1, STYLE_OUTLINEHIGHLIGHTS); /* Paint it into the channel plane */ SigDisableInterrupts(); (void) DBPaintPlane(RtrChannelPlane, r, DBStdWriteTbl(TT_SPACE), (PaintUndoInfo *) NULL); /* Allocate the new channel */ RtrChannelBounds(r, &length, &width, &origin); ch = GCRNewChannel(length, width); ch->gcr_area = *r; ch->gcr_origin = origin; ch->gcr_type = chanType; /* Link it in with the pre-existing list */ ch->gcr_next = gaChannelList; gaChannelList = ch; SigEnableInterrupts(); return (TRUE); } /* * ---------------------------------------------------------------------------- * * gaChannelInit -- * * Called immediately prior to routing to set up lots of useful * information in channels: * * Tile plane initialization: * - Carve up the tile plane so each channel corresponds to a * single space tile, and unavailable areas correspond to * tiles of type 1. * - Make the ti_client fields of tiles in the channel plane * point to their corresponding channels. * * Obstacle initialization: * - Initialize the obstacle and hazard maps for each channel. * Identify pins too close to two-layer blockages and mark * them as already taken (by net GCR_BLOCKEDNETID). * - For river-routing channels, ensure that pairs of pins * can be river-routed to each other; if not, mark both * as unavailable. * * Pin initialization (including stem assignment): * - Fill in the global-routing information in the channel * structure. Specifically, set gcr_ch, gcr_side, gcr_linked, * and gcr_point for each GCRPin. Link available pins for * each side of the channel into a doubly-linked list so * they can be visited easily during global routing. * * Results: * None. * * Side effects: * Fills in a lot of information in the channel structures. * * ---------------------------------------------------------------------------- */ void gaChannelInit(list, routeUse, netList) GCRChannel *list; /* List of channels to process */ CellUse *routeUse; /* Cell being routed (searched for obstacles) */ NLNetList *netList; /* Netlist being routed */ { GCRChannel *ch; RtrMilestoneStart("Obstacle map initialization"); for (ch = list; ch && !SigInterruptPending; ch = ch->gcr_next) { /* Ensure that no channel tiles cross channel boundaries */ while (DBSrPaintArea((Tile *) NULL, RtrChannelPlane, &ch->gcr_area, &DBAllTypeBits, gaSplitTile, (ClientData) &ch->gcr_area)) /* Nothing */; /* Obstacle initialization */ RtrMilestonePrint(); RtrChannelObstacles(routeUse, ch); if (ch->gcr_type == CHAN_NORMAL) RtrChannelDensity(ch); RtrChannelCleanObstacles(ch); } RtrMilestoneDone(); /* * Set all ti_client fields in the channel plane to NULL, and then * for each channel set the ti_client fields of the tiles it overlaps * to point back to that channel. */ (void) DBSrPaintArea((Tile *) NULL, RtrChannelPlane, &TiPlaneRect, &DBAllTypeBits, gaSetClient, (ClientData) NULL); for (ch = list; ch && !SigInterruptPending; ch = ch->gcr_next) (void) DBSrPaintArea((Tile *) NULL, RtrChannelPlane, &ch->gcr_area, &DBAllTypeBits, gaSetClient, (ClientData) ch); if (SigInterruptPending) return; /* * Pin initialization. * This fills in a bunch of information needed for global * routing in each pin along each channel boundary. */ for (ch = list; ch && !SigInterruptPending; ch = ch->gcr_next) RtrPinsInit(ch); /* * Pick the actual pin locations for terminals. * This comes here because it needs the blockage and gcr_linked * information set above. However, it must precede marking * pairs of river-routing crossings as unavailable, since * these pairs are only marked unavailable for routes across * the channel. They may still be usable as stem tips, so * we can't block them until after stems have been assigned. */ gaStemAssignAll(routeUse, netList); if (SigInterruptPending) return; /* * Now mark pairs of river-routing crossings as unavailable. * A crossing is unavailable if a straight-across from one side * of the channel to the other on a single layer is impossible. * Propagate these blockages.. */ for (ch = list; ch && !SigInterruptPending; ch = ch->gcr_next) if (ch->gcr_type != CHAN_NORMAL) gaInitRiverBlockages(routeUse, ch); gaPropagateBlockages(list); if (SigInterruptPending) return; /* * Hazard initialization. * This has to happen after blockages have been propagated. */ RtrMilestoneStart("Hazard initialization"); for (ch = list; ch && !SigInterruptPending; ch = ch->gcr_next) if (ch->gcr_type == CHAN_NORMAL) { RtrHazards(ch); RtrMilestonePrint(); } RtrMilestoneDone(); /* * Link all the available pins along each side of each * channel into a linked list. Only unblocked pins with * non-NULL gcr_linked pins are linked into this list. * Since pins taken as stem tips by gaAssignPins above * were marked, these lists don't include any pins that * are stem tips. */ for (ch = list; ch && !SigInterruptPending; ch = ch->gcr_next) RtrPinsLink(ch); if (DebugIsSet(gaDebugID, gaDebChanStats)) gaChannelStats(list); } void gaChannelStats(list) GCRChannel *list; { GCRChannel *ch; int *tot, *clear, numTot, numClear; double fNorm, fRiver, fTot; gaTotNormCross = 0; gaTotRiverCross = 0; gaClearNormCross = 0; gaClearRiverCross = 0; for (ch = list; ch; ch = ch->gcr_next) { switch (ch->gcr_type) { case CHAN_NORMAL: tot = &gaTotNormCross; clear = &gaClearNormCross; break; case CHAN_HRIVER: case CHAN_VRIVER: tot = &gaTotRiverCross; clear = &gaClearRiverCross; break; default: /* otherwise tot and clear is not intialized */ tot = NULL; clear = NULL; break; } if (tot && clear) { gaPinStats(ch->gcr_tPins, ch->gcr_length, tot, clear); gaPinStats(ch->gcr_bPins, ch->gcr_length, tot, clear); gaPinStats(ch->gcr_lPins, ch->gcr_width, tot, clear); gaPinStats(ch->gcr_rPins, ch->gcr_width, tot, clear); } } numTot = gaTotRiverCross + gaTotNormCross; numClear = gaClearRiverCross + gaClearNormCross; fRiver = ((double) gaClearRiverCross / (double) gaTotRiverCross) * 100.0; fNorm = ((double) gaClearNormCross / (double) gaTotNormCross) * 100.0; fTot = ((double) numClear / (double) numTot) * 100.0; TxPrintf("Total pins: %d, clear: %d (%.1f%%)\n", numTot, numClear, fTot); TxPrintf("Norm chan pins: %d, clear: %d (%.1f%%)\n", gaTotNormCross, gaClearNormCross, fNorm); TxPrintf("River chan pins: %d, clear: %d (%.1f%%)\n", gaTotRiverCross, gaClearRiverCross, fRiver); } void gaPinStats(pins, nPins, pTot, pClear) GCRPin *pins; int nPins; int *pTot, *pClear; { GCRPin *pin, *pend; pin = &pins[1]; pend = &pins[nPins]; for ( ; pin <= pend; pin++) { *pTot += 1; if (pin->gcr_linked && pin->gcr_pId == (GCRNet *) NULL && pin->gcr_linked->gcr_pId == (GCRNet *) NULL) { *pClear += 1; } } } /* * ---------------------------------------------------------------------------- * * gaPropagateBlockages -- * * If a pin is blocked on one side of a channel BOUNDARY, * it is blocked on the other side as well. If a pin on * one side of a river-routing CHANNEL is blocked, the pin * on the other side gets blocked too. Several iterations * may be necessary to propagate blockages across all * channel boundaries and river-routing channels. * * Results: * None. * * Side effects: * See above. * * ---------------------------------------------------------------------------- */ void gaPropagateBlockages(list) GCRChannel *list; { GCRChannel *ch; bool changed; do { changed = FALSE; for (ch = list; ch; ch = ch->gcr_next) if (RtrPinsBlock(ch)) changed = TRUE; } while (changed); } /* * ---------------------------------------------------------------------------- * * gaSetClient -- * * Called for each tile overlapping ch->gcr_area to set the * client pointer for that tile to 'cdata'. * * Results: * Always returns 0. * * Side effects: * See above. * * ---------------------------------------------------------------------------- */ int gaSetClient(tile, cdata) Tile *tile; ClientData cdata; { tile->ti_client = (ClientData) cdata; return (0); } /* * ---------------------------------------------------------------------------- * * gaSplitTile -- * * Called for each tile overlapping the area of a channel (the Rect 'r'), * we ensure that no tiles cross the channel boundary. If one does, we * split it at the boundary and return 1. * * Results: * Returns 1 if tile was split, or 0 if no split occurred. * We return 1 to ensure that DBSrPaintArea doesn't get * confused from our having modified the tile plane. * * Side effects: * May split 'tile'; if it does, we return 1. * * ---------------------------------------------------------------------------- */ int gaSplitTile(tile, r) Tile *tile; Rect *r; { Tile *tp; ASSERT(TiGetType(tile) == TT_SPACE, "gaSplitTile"); if (TOP(tile) > r->r_ytop) { tp = TiSplitY(tile, r->r_ytop); TiSetBody(tp, TT_SPACE); return (1); } if (BOTTOM(tile) < r->r_ybot) { tp = TiSplitY(tile, r->r_ybot); TiSetBody(tp, TT_SPACE); return (1); } if (LEFT(tile) < r->r_xbot) { tp = TiSplitX(tile, r->r_xbot); TiSetBody(tp, TT_SPACE); return (1); } if (RIGHT(tile) > r->r_xtop) { tp = TiSplitX(tile, r->r_xtop); TiSetBody(tp, TT_SPACE); return (1); } return (0); } /* * ---------------------------------------------------------------------------- * * gaInitRiverBlockages -- * * The channel 'ch' is a river-routing channel (ch->gcr_type is either * CHAN_HRIVER or CHAN_VRIVER). These channels can only be routed * across in a single direction (horizontally for CHAN_HRIVER, or * vertically for CHAN_VRIVER). * * If pins have already been taken by terminals (as stem tips), we * don't mark them as blocked. * * Results: * None. * * Side effects: * Marks pairs of pins on the channel boundary as blocked if * a river-route across the channel is not possible along * the track that runs between the pin pair. Blocked pins * have a special gcr_pId of GCR_BLOCKEDNETID to mark them as * "in use". * * ---------------------------------------------------------------------------- */ void gaInitRiverBlockages(routeUse, ch) CellUse *routeUse; GCRChannel *ch; { GCRPin *p1, *p2; int n, nPins, coord; SearchContext scx; switch (ch->gcr_type) { case CHAN_HRIVER: p1 = &ch->gcr_lPins[1]; p2 = &ch->gcr_rPins[1]; nPins = ch->gcr_width; scx.scx_area.r_xbot = ch->gcr_area.r_xbot; scx.scx_area.r_xtop = ch->gcr_area.r_xtop; coord = ch->gcr_origin.p_y + RtrGridSpacing; break; case CHAN_VRIVER: p1 = &ch->gcr_tPins[1]; p2 = &ch->gcr_bPins[1]; nPins = ch->gcr_length; scx.scx_area.r_ybot = ch->gcr_area.r_ybot; scx.scx_area.r_ytop = ch->gcr_area.r_ytop; coord = ch->gcr_origin.p_x + RtrGridSpacing; break; } scx.scx_use = routeUse; scx.scx_trans = GeoIdentityTransform; for (n = 1; n <= nPins; n++, p1++, p2++, coord += RtrGridSpacing) { switch (ch->gcr_type) { case CHAN_HRIVER: scx.scx_area.r_ybot = coord - RtrSubcellSepUp; scx.scx_area.r_ytop = coord + RtrSubcellSepDown; break; case CHAN_VRIVER: scx.scx_area.r_xbot = coord - RtrSubcellSepUp; scx.scx_area.r_xtop = coord + RtrSubcellSepDown; break; } /* * If obstacles to both routing layers are found, * then block this pair of crossing points if they * aren't already taken. */ if (DBTreeSrTiles(&scx, &RtrMetalObstacles, 0, gaAlwaysOne, CNULL) && DBTreeSrTiles(&scx, &RtrPolyObstacles, 0, gaAlwaysOne, CNULL)) { if (p1->gcr_pId == (GCRNet *) NULL) p1->gcr_pId = GCR_BLOCKEDNETID; if (p2->gcr_pId == (GCRNet *) NULL) p2->gcr_pId = GCR_BLOCKEDNETID; } } } int gaAlwaysOne() { return (1); }