/* * gaSimple.c - * * Code to try very simple stems * (straight line connection from pin to terminal * with a possible contact at or near each end) * * ********************************************************************* * * 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/gaSimple.c,v 1.2 2009/05/13 15:03:16 tim Exp $"; #endif /* not lint */ #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 "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 "utils/malloc.h" #include "drc/drc.h" #include "debug/debug.h" #include "extract/extract.h" #include "extract/extractInt.h" bool gaIsClear(); /*--- Externals referenced in this file and not declared in include files ---*/ extern int gaMetalClear; extern int gaPolyClear; extern int gaContactClear; /* * ---------------------------------------------------------------------------- * * gaStemSimpleInit -- * * Initialize the SimpleStem struct to contain information on what * simple routes are possible. * * Simple routes are grid aligned straight routes from the terminal * to the pin, with a possible contact at the terminal and another near * the pin on the grid line just before the channel edge. * * If this routine returns TRUE, gaStemSimpleRoute() must still be called * to determine if a simple route is possible (and optionally to paint the * route into a cell). * * Results: * TRUE if successful, FALSE if it was not possible to make a * grid-aligned route. * * Side effects: * Fills in the fields of *simple. * * ---------------------------------------------------------------------------- */ bool gaStemSimpleInit(routeUse, term, pinPoint, pinSide, simple) CellUse *routeUse; /* Search this cell for obstacles */ NLTermLoc *term; /* Route from term->nloc_rect */ Point *pinPoint; /* Crossing point to reach */ int pinSide; /* Direction of pin from term. */ SimpleStem *simple; /* Fill this in */ { SimpleWire *sMetal = &simple->ss_metalWire; SimpleWire *sPoly = &simple->ss_polyWire; Rect *cTerm = &simple->ss_cTerm; Rect *cPin = &simple->ss_cPin; Rect *termLoc = &term->nloc_rect; /* * Check that the start terminal is big enough for the route to be * grid-aligned. The start terminal has to be big enough * to hold a grid-aligned wire on each of the routing types. */ { int bot, top; switch (pinSide) { case GEO_NORTH: case GEO_SOUTH: { bot = pinPoint->p_x; top = termLoc->r_xtop; if (bot < termLoc->r_xbot) return (FALSE); break; } case GEO_EAST: case GEO_WEST: { bot = pinPoint->p_y; top = termLoc->r_ytop; if (bot < termLoc->r_ybot) return (FALSE); break; } } if (bot + RtrMetalWidth > top || bot + RtrPolyWidth > top) return (FALSE); } /* Misc initialization */ { simple->ss_dir = pinSide; simple->ss_pinPoint = *pinPoint; simple->ss_termArea = term->nloc_rect; simple->ss_termType = term->nloc_label->lab_type; sMetal->sw_type = RtrMetalType; sPoly->sw_type = RtrPolyType; } /* Determine which types connect to terminal directly * (without adding a contact) */ if (simple->ss_termType == RtrContactType) { TTMaskSetOnlyType(&(simple->ss_termMask), RtrMetalType); TTMaskSetType(&(simple->ss_termMask), RtrPolyType); } else { TTMaskSetOnlyType(&(simple->ss_termMask), simple->ss_termType); } /* * Compute contact and wire areas. * Defn of areas: * - long wires run from terminal to pin, * - short wires run from terminal to contact near pin, * - pinStubs run from pinContact to pin. */ { switch (pinSide) { case GEO_NORTH: /* pin is directly above terminal */ { /* compute terminal contact location */ cTerm->r_xbot = pinPoint->p_x + RtrContactOffset; cTerm->r_ybot = termLoc->r_ytop - RtrContactWidth; cTerm->r_xtop = cTerm->r_xbot + RtrContactWidth; cTerm->r_ytop = cTerm->r_ybot + RtrContactWidth; /* compute pin contact location */ cPin->r_xbot = pinPoint->p_x + RtrContactOffset; cPin->r_ybot = (RTR_GRIDDOWN(pinPoint->p_y, RtrOrigin.p_y) + RtrContactOffset); cPin->r_xtop = cPin->r_xbot + RtrContactWidth; cPin->r_ytop = cPin->r_ybot + RtrContactWidth; /* compute poly pin stub location */ sPoly->sw_pinStub.r_xbot = pinPoint->p_x; sPoly->sw_pinStub.r_ybot = cPin->r_ytop; sPoly->sw_pinStub.r_xtop = pinPoint->p_x + RtrPolyWidth; sPoly->sw_pinStub.r_ytop = pinPoint->p_y; /* compute metal pin stub location */ sMetal->sw_pinStub.r_xbot = pinPoint->p_x; sMetal->sw_pinStub.r_ybot = cPin->r_ytop; sMetal->sw_pinStub.r_xtop = pinPoint->p_x + RtrMetalWidth; sMetal->sw_pinStub.r_ytop = pinPoint->p_y; /* compute short metal wire */ sMetal->sw_short.r_xbot = pinPoint->p_x; sMetal->sw_short.r_ybot = termLoc->r_ytop; sMetal->sw_short.r_xtop = pinPoint->p_x + RtrMetalWidth; sMetal->sw_short.r_ytop = cPin->r_ybot; /* compute short poly wire */ sPoly->sw_short.r_xbot = pinPoint->p_x; sPoly->sw_short.r_xtop = pinPoint->p_x + RtrPolyWidth; sPoly->sw_short.r_ybot = termLoc->r_ytop; sPoly->sw_short.r_ytop = cPin->r_ybot; /* compute long metal wire */ sMetal->sw_long = sMetal->sw_short; sMetal->sw_long.r_ytop = pinPoint->p_y; /* compute long poly wire */ sPoly->sw_long = sPoly->sw_short; sPoly->sw_long.r_ytop = pinPoint->p_y; break; } case GEO_SOUTH: /* pin is directly below terminal */ { /* compute terminal contact location */ cTerm->r_xbot = pinPoint->p_x + RtrContactOffset; cTerm->r_ybot = termLoc->r_ybot; cTerm->r_xtop = cTerm->r_xbot + RtrContactWidth; cTerm->r_ytop = cTerm->r_ybot + RtrContactWidth; /* compute pin contact location */ cPin->r_xbot = pinPoint->p_x + RtrContactOffset; cPin->r_ybot = (RTR_GRIDUP(pinPoint->p_y, RtrOrigin.p_y) + RtrContactOffset); cPin->r_xtop = cPin->r_xbot + RtrContactWidth; cPin->r_ytop = cPin->r_ybot + RtrContactWidth; /* compute poly pin stub location */ sPoly->sw_pinStub.r_xbot = pinPoint->p_x; sPoly->sw_pinStub.r_ybot = pinPoint->p_y; sPoly->sw_pinStub.r_xtop = pinPoint->p_x + RtrPolyWidth; sPoly->sw_pinStub.r_ytop = cPin->r_ybot; /* compute metal pin stub location */ sMetal->sw_pinStub.r_xbot = pinPoint->p_x; sMetal->sw_pinStub.r_ybot = pinPoint->p_y; sMetal->sw_pinStub.r_xtop = pinPoint->p_x + RtrMetalWidth; sMetal->sw_pinStub.r_ytop = cPin->r_ybot; /* compute short metal wire */ sMetal->sw_short.r_xbot = pinPoint->p_x; sMetal->sw_short.r_ybot = cPin->r_ytop; sMetal->sw_short.r_xtop = pinPoint->p_x + RtrMetalWidth; sMetal->sw_short.r_ytop = termLoc->r_ybot; /* compute short poly wire */ sPoly->sw_short.r_xbot = pinPoint->p_x; sPoly->sw_short.r_ybot = cPin->r_ytop; sPoly->sw_short.r_xtop = pinPoint->p_x + RtrPolyWidth; sPoly->sw_short.r_ytop = termLoc->r_ybot; /* long metal wire */ sMetal->sw_long = sMetal->sw_short; sMetal->sw_long.r_ybot = pinPoint->p_y; /* long poly wire */ sPoly->sw_long = sPoly->sw_short; sPoly->sw_long.r_ybot = pinPoint->p_y; break; } case GEO_EAST: /* pin is directly to right of terminal */ { /* compute terminal contact location */ cTerm->r_xbot = termLoc->r_xtop - RtrContactWidth; cTerm->r_ybot = pinPoint->p_y + RtrContactOffset; cTerm->r_xtop = cTerm->r_xbot + RtrContactWidth; cTerm->r_ytop = cTerm->r_ybot + RtrContactWidth; /* compute pin contact location */ cPin->r_xbot = (RTR_GRIDDOWN(pinPoint->p_x, RtrOrigin.p_x) + RtrContactOffset); cPin->r_ybot = pinPoint->p_y + RtrContactOffset; cPin->r_xtop = cPin->r_xbot + RtrContactWidth; cPin->r_ytop = cPin->r_ybot + RtrContactWidth; /* compute poly pin stub location */ sPoly->sw_pinStub.r_xbot = cPin->r_xtop; sPoly->sw_pinStub.r_ybot = pinPoint->p_y; sPoly->sw_pinStub.r_xtop = pinPoint->p_x; sPoly->sw_pinStub.r_ytop = pinPoint->p_y + RtrPolyWidth; /* compute metal pin stub location */ sMetal->sw_pinStub.r_xbot = cPin->r_xtop; sMetal->sw_pinStub.r_ybot = pinPoint->p_y; sMetal->sw_pinStub.r_xtop = pinPoint->p_x; sMetal->sw_pinStub.r_ytop = pinPoint->p_y + RtrMetalWidth; /* compute short metal wire */ sMetal->sw_short.r_xbot = termLoc->r_xtop; sMetal->sw_short.r_ybot = pinPoint->p_y; sMetal->sw_short.r_xtop = cPin->r_xbot; sMetal->sw_short.r_ytop = pinPoint->p_y + RtrMetalWidth; /* compute short poly wire */ sPoly->sw_short.r_xbot = termLoc->r_xtop; sPoly->sw_short.r_ybot = pinPoint->p_y; sPoly->sw_short.r_xtop = cPin->r_xbot; sPoly->sw_short.r_ytop = pinPoint->p_y + RtrPolyWidth; /* compute long metal wire */ sMetal->sw_long = sMetal->sw_short; sMetal->sw_long.r_xtop = pinPoint->p_x; /* compute long poly wire */ sPoly->sw_long = sPoly->sw_short; sPoly->sw_long.r_xtop = pinPoint->p_x; break; } case GEO_WEST: /* pin is directly to left of terminal */ { /* compute terminal contact location */ cTerm->r_xbot = termLoc->r_xbot; cTerm->r_ybot = pinPoint->p_y + RtrContactOffset; cTerm->r_xtop = cTerm->r_xbot + RtrContactWidth; cTerm->r_ytop = cTerm->r_ybot + RtrContactWidth; /* compute pin contact location */ cPin->r_xbot = (RTR_GRIDUP(pinPoint->p_x, RtrOrigin.p_x) + RtrContactOffset); cPin->r_ybot = pinPoint->p_y + RtrContactOffset; cPin->r_xtop = cPin->r_xbot + RtrContactWidth; cPin->r_ytop = cPin->r_ybot + RtrContactWidth; /* compute poly pin stub location */ sPoly->sw_pinStub.r_xbot = pinPoint->p_x; sPoly->sw_pinStub.r_ybot = pinPoint->p_y; sPoly->sw_pinStub.r_xtop = cPin->r_xbot; sPoly->sw_pinStub.r_ytop = pinPoint->p_y + RtrPolyWidth; /* compute metal pin stub location */ sMetal->sw_pinStub.r_xbot = pinPoint->p_x; sMetal->sw_pinStub.r_ybot = pinPoint->p_y; sMetal->sw_pinStub.r_xtop = cPin->r_xbot; sMetal->sw_pinStub.r_ytop = pinPoint->p_y + RtrMetalWidth; /* compute short metal wire */ sMetal->sw_short.r_xbot = cPin->r_xtop; sMetal->sw_short.r_ybot = pinPoint->p_y; sMetal->sw_short.r_xtop = termLoc->r_xbot; sMetal->sw_short.r_ytop = pinPoint->p_y + RtrMetalWidth; /* compute short poly wire */ sPoly->sw_short.r_xbot = cPin->r_xtop; sPoly->sw_short.r_ybot = pinPoint->p_y; sPoly->sw_short.r_xtop = termLoc->r_xbot; sPoly->sw_short.r_ytop = pinPoint->p_y + RtrPolyWidth; /* long metal wire */ sMetal->sw_long = sMetal->sw_short; sMetal->sw_long.r_xbot = pinPoint->p_x; /* long poly wire */ sPoly->sw_long = sPoly->sw_short; sPoly->sw_long.r_xbot = pinPoint->p_x; break; } } /* end switch */ } /* check which wires and contacts are blocked */ { Rect rTerm, rPin, rShortMetal, rShortPoly, rLongMetal, rLongPoly; Rect rStubMetal, rStubPoly; /* * bloat wire and contact areas to produce the areas that must * be clear of obstacles in order for a route to be possible. */ { GEO_EXPAND(cTerm, gaContactClear, &rTerm); GEO_EXPAND(cPin, gaContactClear, &rPin); GEO_EXPAND(&sMetal->sw_short, gaMetalClear, &rShortMetal); GEO_EXPAND(&sMetal->sw_long, gaMetalClear, &rLongMetal); GEO_EXPAND(&sMetal->sw_pinStub, gaMetalClear, &rStubMetal); GEO_EXPAND(&sPoly->sw_short, gaPolyClear, &rShortPoly); GEO_EXPAND(&sPoly->sw_long, gaPolyClear, &rLongPoly); GEO_EXPAND(&sPoly->sw_pinStub, gaPolyClear, &rStubPoly); } /* * Prune check areas at terminal and pin to allow prexisting * material at the connection points. * * (NOTE the terminal contact area is not trimmed, but will * only be checked on the layer (if any) that is not part * of the terminal) */ { Rect pruneR; /* compute prune area */ { pruneR = routeUse->cu_bbox; switch (pinSide) { case GEO_NORTH: { pruneR.r_ybot = termLoc->r_ytop; pruneR.r_ytop = pinPoint->p_y; break; } case GEO_SOUTH: { pruneR.r_ybot = pinPoint->p_y; pruneR.r_ytop = termLoc->r_ybot; break; } case GEO_EAST: { pruneR.r_xbot = termLoc->r_xtop; pruneR.r_xtop = pinPoint->p_x; break; } case GEO_WEST: { pruneR.r_xbot = pinPoint->p_x; pruneR.r_xtop = termLoc->r_xbot; } } } /* prune the areas (accept for rTerm) */ { GEOCLIP(&rPin, &pruneR); GEOCLIP(&rShortMetal, &pruneR); GEOCLIP(&rLongMetal, &pruneR); GEOCLIP(&rStubMetal, &pruneR); GEOCLIP(&rShortPoly, &pruneR); GEOCLIP(&rLongPoly, &pruneR); GEOCLIP(&rStubPoly, &pruneR); } } /* check areas for obstacles */ { /* terminal contact */ { if(!TTMaskHasType(&simple->ss_termMask, RtrMetalType)) { simple->ss_cTermOK = gaIsClear(routeUse, &rTerm, &RtrMetalObstacles); } if(!TTMaskHasType(&simple->ss_termMask, RtrPolyType)) { simple->ss_cTermOK = gaIsClear(routeUse, &rTerm, &RtrPolyObstacles); } } /* pin contact */ { TileTypeBitMask allObs; TTMaskSetMask3(&allObs, &RtrPolyObstacles, &RtrMetalObstacles); simple->ss_cPinOK = gaIsClear(routeUse, &rPin, &allObs); } /* short metal wire * (a short wire is only ok if both the short wire itself and * the complementary stub are clear) */ sMetal->sw_shortOK = (gaIsClear(routeUse, &rShortMetal, &RtrMetalObstacles) && gaIsClear(routeUse, &rStubPoly, &RtrPolyObstacles)); /* long metal wire */ sMetal->sw_longOK = gaIsClear(routeUse, &rLongMetal, &RtrMetalObstacles); /* short poly wire */ sPoly->sw_shortOK = (gaIsClear(routeUse, &rShortPoly, &RtrPolyObstacles) && gaIsClear(routeUse, &rStubMetal, &RtrMetalObstacles)); /* long poly wire */ sPoly->sw_longOK = gaIsClear(routeUse, &rLongPoly, &RtrPolyObstacles); } } return (TRUE); } /* * ---------------------------------------------------------------------------- * * gaIsClear -- * * * Check that r is clear of all material of types in mask. * * Results: * TRUE if the area is clear, FALSE if not. * * Side effects: * None. * * ---------------------------------------------------------------------------- */ bool gaIsClear(use, r, mask) CellUse *use; Rect *r; TileTypeBitMask *mask; { int gaIsClearFunc(); SearchContext scx; scx.scx_use = use; scx.scx_trans = GeoIdentityTransform; scx.scx_area = *r; if (DebugIsSet(gaDebugID, gaDebStems)) { ShowRect(use->cu_def, r, STYLE_OUTLINEHIGHLIGHTS); TxMore("Checking clear area"); ShowRect(use->cu_def, r, STYLE_ERASEHIGHLIGHTS); } if (DBTreeSrTiles(&scx, mask, 0, gaIsClearFunc, (ClientData) NULL)) return (FALSE); return (TRUE); } /* * ---------------------------------------------------------------------------- * * gaIsClearFunc -- * * Called for tiles whose type matches 'mask' underneath the area * 'r' in gaIsClear() above. * * Results: * Always returns 1 since we only need a single obstacle to not have * a clear area. * * Side effects: * None. * * ---------------------------------------------------------------------------- */ int gaIsClearFunc(tile, cxp) Tile *tile; TreeContext *cxp; { return 1; } /* * ---------------------------------------------------------------------------- * * gaStemSimpleRoute -- * * See if a simple type of route is possible given the pinLayer. * All other information describing the simple route is * present in *simple. * * Results: * TRUE if a route was possible, FALSE if not. * * Side effects: * Paints the path into 'def' if 'def' is non-NULL. * * ---------------------------------------------------------------------------- */ bool gaStemSimpleRoute(simple, pinLayer, def) SimpleStem *simple; /* Describes the route */ TileType pinLayer; /* Connect to pin on this layer */ CellDef *def; /* If non-NULL, paint to this def */ { SimpleWire *wPin, *wOther; /* * Determine which wire corresponds to pin * and which corresponds to the other route layer. */ if (pinLayer == RtrPolyType) { wPin = &simple->ss_polyWire; wOther = &simple->ss_metalWire; } else if (pinLayer == RtrMetalType) { wPin = &simple->ss_metalWire; wOther = &simple->ss_polyWire; } else { ASSERT(FALSE, "gaStemSimpleRoute: bad destType"); } if(TTMaskHasType(&simple->ss_termMask, pinLayer)) /* layer of pin also OK for final connection at terminal */ { if(wPin->sw_longOK) /* No contact connection */ { if(def) { DBPaint(def, &wPin->sw_long, wPin->sw_type); } return TRUE; } /* contact at pin only */ else if (TTMaskHasType(&simple->ss_termMask, wOther->sw_type) && wOther->sw_shortOK && simple->ss_cPinOK) { if(def) { DBPaint(def, &wOther->sw_short, wOther->sw_type); RtrPaintContact(def, &simple->ss_cPin); DBPaint(def, &wPin->sw_pinStub, wPin->sw_type); } return TRUE; } else if (simple->ss_cTermOK && wOther->sw_shortOK && simple->ss_cPinOK) /* two contact route */ { if(def) { RtrPaintContact(def, &simple->ss_cTerm); DBPaint(def, &wOther->sw_short, wOther->sw_type); RtrPaintContact(def, &simple->ss_cPin); DBPaint(def, &wPin->sw_pinStub, wPin->sw_type); } return TRUE; } else /* No simple route */ { return FALSE; } } else /* pin and terminal connections on opposite layers */ { if(simple->ss_cTermOK && wPin->sw_longOK) /* contact at terminal only */ { if(def) { RtrPaintContact(def, &simple->ss_cTerm); DBPaint(def, &wPin->sw_long, wPin->sw_type); } return TRUE; } else if(wOther->sw_shortOK && simple->ss_cPinOK) /* contact at pin only */ { if(def) { DBPaint(def, &wOther->sw_short, wOther->sw_type); RtrPaintContact(def, &simple->ss_cPin); DBPaint(def, &wPin->sw_pinStub, wPin->sw_type); } return TRUE; } else /* No simple route */ { return FALSE; } } }