magic/garouter/gaSimple.c

706 lines
19 KiB
C

/*
* 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 <stdio.h>
#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;
}
}
}