Logo Search packages:      
Sourcecode: magic version File versions  Download package

grouteChan.c

/*
 * grouteChan.c --
 *
 * Code to maintain a map of usable channel areas, using a
 * tile plane.  One tile is used for each "unobstructed"
 * channel area, namely one that contains no embedded regions
 * where the channel's density has been exceeded.
 *
 *     ********************************************************************* 
 *     * 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.    * 
 *     *********************************************************************
 */

#include <stdio.h>

#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/styles.h"
#include "utils/hash.h"
#include "utils/heap.h"
#include "utils/utils.h"
#include "tiles/tile.h"
#include "database/database.h"
#include "debug/debug.h"
#include "gcr/gcr.h"
#include "windows/windows.h"
#include "utils/main.h"
#include "dbwind/dbwind.h"
#include "utils/signals.h"
#include "router/router.h"
#include "grouter/grouter.h"
#include "utils/netlist.h"
#include "utils/styles.h"
#include "textio/textio.h"
#include "utils/malloc.h"

/* Plane to hold channel information */
Plane *glChanPlane;

/* Dummy celldef whose PL_DRC_CHECK plane is identical to glChanPlane above */
CellDef *glChanDef;
CellUse *glChanUse;

TileTypeBitMask glMaskRiver;  /* Mask of river channel types */
TileTypeBitMask glMaskNormal; /* Mask of normal channel type */
TileTypeBitMask   glMaskChannel;    /* Mask of all channel types */

int glChanSplitRiver();
int glChanRiverBlock();
int glChanFloodVFunc(), glChanFloodHFunc();
bool glChanClip();
int glChanClipFunc();
int glChanMergeFunc();
int glChanFeedFunc();
int glChanPaintFunc();
int glChanSetClient();
void glChanFreeMap();
void glChanCheckCover();
void glChanBlockDens();
void glChanFlood();

00070 typedef struct pa
{
    Rect     pa_area;
    TileType       pa_type;
    struct pa     *pa_next;
} PaintArea;

PaintArea *glChanPaintList;

/*
 * ----------------------------------------------------------------------------
 *
 * glChanBuildMap --
 *
 * Build a tile plane that represents all the channels in the routing
 * problem.  This tile plane will contain tiles of four types: CT_BLOCKED,
 * CT_NORMAL, CT_HRIVER, and CT_VRIVER, corresponding to unusable routing
 * area and the three types of channels respectively.
 *
 * Each channel tile's client field points back to the channel it covers.
 * A single channel can be covered by several tiles, however.  Initially,
 * each normal channel is covered by a single tile, but each river tile
 * is covered by several tiles.  For example, the tiles covering a HRIVER
 * channel are chosen such that there is never a vertical tile boundary
 * on either their RHS or LHS except at the top or bottom of the CT_HRIVER
 * tile.  Situations such as the following:
 *
 *          +-------+
 *          |     |
 *          |     | normal
 *          |     |
 *          |HRIVER     +------
 *          |     |
 *          |     | normal
 *          |     |
 *          +-------+
 *
 * aren't allowed to exist; the HRIVER tile gets split:
 *
 *          +-------+
 *          |     |
 *          |HRIVER     | normal
 *          |     |
 *          +-------+------
 *          |     |
 *          |HRIVER     | normal
 *          |     |
 *          +-------+
 *    
 * The reason for splitting CT_HRIVER tiles in this way (and CT_VRIVER tiles
 * vertically using similar criteria) is to ensure that there is a different
 * river tile for each channel on its opposite side.  This fact is crucial
 * to the working of the inner loop of the global router; see the code in
 * groutePair.c for details of the algorithm used.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    Builds the tile plane glChanPlane as described above.
 *
 * ----------------------------------------------------------------------------
 */

void
glChanBuildMap(chanList)
    GCRChannel *chanList;     /* List of all channels in routing problem */
{
    GCRChannel *ch;
    bool workDone;

    if (glChanPlane == NULL)
    {
      DBNewYank("__CHANMAP__", &glChanUse, &glChanDef);
      glChanPlane = glChanDef->cd_planes[PL_DRC_CHECK];
      glChanFreeMap();
      TTMaskSetOnlyType(&glMaskRiver, CHAN_HRIVER);
      TTMaskSetType(&glMaskRiver, CHAN_VRIVER);
      TTMaskSetOnlyType(&glMaskNormal, CHAN_NORMAL);
      TTMaskSetMask3(&glMaskChannel, &glMaskNormal, &glMaskRiver);
    }

    /*
     * First pass: use painting to cover the areas of all channels
     * with the appropriate type of tile.
     */
    for (ch = chanList; ch; ch = ch->gcr_next)
      DBPaintPlane(glChanPlane, &ch->gcr_area, DBStdWriteTbl(ch->gcr_type),
                  (PaintUndoInfo *) NULL);

    if (DebugIsSet(glDebugID, glDebTiles))
      glChanShowTiles("After painting all channels");

    /*
     * Second pass: use splits and merges to ensure that each channel
     * covers exactly one tile.  Leave this tile's ti_client field
     * pointing to 'ch'.
     */
    do
    {
      workDone = FALSE;
      for (ch = chanList; ch; ch = ch->gcr_next)
          if (glChanClip(ch))
            workDone = TRUE;
    }
    while (workDone);
    if (DebugIsSet(glDebugID, glDebTiles))
      glChanShowTiles("After splits and merges");
    if (DebugIsSet(glDebugID, glDebChan))
      glChanCheckCover(chanList, &glMaskChannel);

    /*
     * Third pass: find regions of maximum density and "paint" them into
     * the tile map.  Regions where the density is exceeded in only one
     * of the two possible directions through a normal channel result in
     * painting a CHAN_HRIVER or CHAN_VRIVER tile as appropriate, while
     * regions that are totally blocked result in CHAN_BLOCKED tiles.
     * The client fields of the remaining nonblocked tiles are left
     * pointing to the channels those tiles overlap.
     */
    for (ch = chanList; ch; ch = ch->gcr_next)
      glChanBlockDens(ch);
    if (DebugIsSet(glDebugID, glDebTiles))
      glChanShowTiles("After density blockages");

    /*
     * Fourth pass: split river tiles as necessary to ensure
     * that no river tile has a perpendicular tile boundary
     * on either of the sides from which signals can enter.
     */
    while (DBSrPaintArea((Tile *) NULL, glChanPlane, &TiPlaneRect, &glMaskRiver,
            glChanSplitRiver, (ClientData) NULL))
      /* Nothing */;
    if (DebugIsSet(glDebugID, glDebTiles))
      glChanShowTiles("After splitting river tiles");

    /*
     * Final pass: turn any river tiles whose pins are completely
     * blocked on one side into blocked tiles.  This just involves
     * changing the type of the tile.
     */
    (void) DBSrPaintArea((Tile *) NULL, glChanPlane, &TiPlaneRect,
            &glMaskRiver, glChanRiverBlock, (ClientData) NULL);
    if (DebugIsSet(glDebugID, glDebTiles))
      glChanShowTiles("After blocking river tiles");
    if (DebugIsSet(glDebugID, glDebChan))
    {
      glChanCheckCover(chanList, &glMaskNormal);
      (void) DBSrPaintArea((Tile *) NULL, glChanPlane, &TiPlaneRect,
            &glMaskChannel, glChanFeedFunc, (ClientData) NULL);
    }
}

/*
 * glChanFeedFunc --
 *
 * Used for leaving feedback for each channel tile above.
 *
 * Results:
 *    Always returns 0.
 *
 * Side effects:
 *    Leaves feedback for each tile found.
 */

int
glChanFeedFunc(tile)
    Tile *tile;
{
    char *mesg;
    Rect r;

    switch (TiGetType(tile))
    {
      case CHAN_NORMAL: mesg = "normal channel"; break;
      case CHAN_HRIVER: mesg = "horizontal river channel"; break;
      case CHAN_VRIVER: mesg = "vertical river channel"; break;
    }
    TITORECT(tile, &r);
    DBWFeedbackAdd(&r, mesg, EditCellUse->cu_def, 1, STYLE_OUTLINEHIGHLIGHTS);
    return 0;
}

/*
 * ----------------------------------------------------------------------------
 *
 * glChanFreeMap --
 *
 * Free the tile plane built by glChanBuildMap().
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    Frees memory.
 *
 * ----------------------------------------------------------------------------
 */

void
glChanFreeMap()
{
    Tile *newCenterTile;

    /* Eliminate all the tiles from this plane */
    DBFreePaintPlane(glChanPlane);

    /* Allocate a new central space tile */
    newCenterTile = TiAlloc();
    glChanPlane->pl_hint = newCenterTile;
    TiSetBody(newCenterTile, CHAN_BLOCKED);
    dbSetPlaneTile(glChanPlane, newCenterTile);
}

/*
 * ----------------------------------------------------------------------------
 *
 * glChanCheckCover --
 *
 * Debugging procedure used to check that each channel whose type is
 * contained in 'mask' is covered by exactly one tile.  Also check
 * all channels to make sure that the tiles they cover are the same
 * as the channel type (except for blockages).
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    Leaves feedback where errors occur.
 *
 * ----------------------------------------------------------------------------
 */

int glChanCheckCount;

void
glChanCheckCover(chanList, mask)
    GCRChannel *chanList;
    TileTypeBitMask *mask;
{
    int glChanCheckFunc();
    GCRChannel *ch;
    char mesg[1024];

    for (ch = chanList; ch; ch = ch->gcr_next)
    {
      glChanCheckCount = 0;
      (void) DBSrPaintArea((Tile *) NULL, glChanPlane, &ch->gcr_area,
            &DBAllTypeBits, glChanCheckFunc,
            (ClientData) ch);
      if (TTMaskHasType(mask, ch->gcr_type) && glChanCheckCount != 1)
      {
          (void) sprintf(mesg, "%d tiles over channel", glChanCheckCount);
          DBWFeedbackAdd(&ch->gcr_area, mesg, EditCellUse->cu_def, 1,
                  STYLE_PALEHIGHLIGHTS);
      }
    }
}

/*
 * glChanCheckFunc --
 *
 * Called by above for each tile overlapping a channel.
 *
 * Results:
 *    Always returns 0.
 *
 * Side effects:
 *    May leave feedback if a channel is overlapped by the
 *    wrong type of tile.
 */

int
glChanCheckFunc(tile, ch)
    Tile *tile;
    GCRChannel *ch;
{
    char mesg[1024];
    Rect r;

    glChanCheckCount++;
    if (NOTBLOCKED(tile))
    {
      if (TiGetType(tile) != ch->gcr_type)
      {
          TITORECT(tile, &r);
          (void) sprintf(mesg, "Different tile type %d for chan %d",
                TiGetType(tile), ch->gcr_type);
          DBWFeedbackAdd(&r, mesg, EditCellUse->cu_def,
                1, STYLE_MEDIUMHIGHLIGHTS);
      }
      if (tile->ti_client != (ClientData) ch)
      {
          TITORECT(tile, &r);
          (void) sprintf(mesg, "Tile client %x doesn't match chan %x",
                tile->ti_client, ch);
          DBWFeedbackAdd(&r, mesg, EditCellUse->cu_def,
                1, STYLE_MEDIUMHIGHLIGHTS);
      }
    }
    return 0;
}

/*
 * ----------------------------------------------------------------------------
 *
 * glChanClip --
 *
 * Leave a single tile overlapping the area of channel 'ch'.
 * Leave this tile pointing to 'ch'.
 *
 * Results:
 *    Returns TRUE if we had to do any splits or merges,
 *    FALSE if everything was as it should be.
 *
 * Side effects:
 *    May split or merge tiles.
 *
 * ----------------------------------------------------------------------------
 */

bool
glChanClip(ch)
    GCRChannel *ch;
{
    bool ret;

    ret = FALSE;

    /* First part: clip every tile overlapping this channel to its boundary */
    while (DBSrPaintArea((Tile *) NULL, glChanPlane, &ch->gcr_area,
          &DBAllTypeBits, glChanClipFunc, (ClientData) &ch->gcr_area))
      ret = TRUE;

    /* Second part: set the client field of every tile to 'ch' */
    (void) DBSrPaintArea((Tile *) NULL, glChanPlane, &ch->gcr_area,
          &DBAllTypeBits, glChanSetClient, (ClientData) ch);

    /*
     * Third part: merge every tile overlapping this channel into a
     * single one.  The procedure called for each tile extracts the
     * channel boundaries from the client field of the tile, and
     * then generates merges within the channel boundary.
     */
    while (DBSrPaintArea((Tile *) NULL, glChanPlane, &ch->gcr_area,
          &DBAllTypeBits, glChanMergeFunc, (ClientData) NULL))
      ret = TRUE;

    if (DebugIsSet(glDebugID, glDebTiles))
    {
      char mesg[256];

      (void) sprintf(mesg, "After clipping chan %x", ch);
      glChanShowTiles(mesg);
    }

    return ret;
}

int
glChanSetClient(tile, cdata)
    Tile *tile;
    ClientData cdata;
{
    tile->ti_client = cdata;
    return 0;
}

int
glChanShowTiles(mesg)
    char *mesg;
{
    int glChanShowFunc();
    char answer[100], m[1024];

    DBWAreaChanged(glChanDef, &TiPlaneRect, DBW_ALLWINDOWS, 0);
    WindUpdate();
    (void) sprintf(m, "%s: --more-- (t for tiles): ", mesg);
    if (TxGetLinePrompt(answer, sizeof answer, m) == NULL || answer[0] != 't')
      return;

    (void) DBSrPaintArea((Tile *) NULL, glChanPlane, &TiPlaneRect,
          &DBAllTypeBits, glChanShowFunc, (ClientData) NULL);
}

int
glChanShowFunc(tile)
    Tile *tile;
{
    GCRChannel *ch;
    char mesg[1024];
    Rect r;

    TITORECT(tile, &r);
    ShowRect(EditCellUse->cu_def, &r, STYLE_PALEHIGHLIGHTS);
    (void) sprintf(mesg, "tile ch=%x type=%d",
            tile->ti_client, TiGetType(tile));
    TxMore(mesg);
    ShowRect(EditCellUse->cu_def, &r, STYLE_ERASEHIGHLIGHTS);
    if (tile->ti_client == (ClientData) CLIENTDEFAULT)
      return;
    ch = (GCRChannel *) tile->ti_client;
    ShowRect(EditCellUse->cu_def, &ch->gcr_area, STYLE_MEDIUMHIGHLIGHTS);
    (void) sprintf(mesg, "chan %x type=%d", ch, ch->gcr_type);
    TxMore(mesg);
    ShowRect(EditCellUse->cu_def, &ch->gcr_area, STYLE_ERASEHIGHLIGHTS);
}

/*
 * ----------------------------------------------------------------------------
 *
 * glChanClipFunc --
 *
 * Called by DBSrPaintArea() on behalf of glChanClip() above for each
 * tile overlapping 'area': splits 'tile' as necessary to ensure that
 * it is completely contained within area.
 *
 * Results:
 *    Returns 1 if we did any splitting, 0 otherwise.
 *
 * Side effects:
 *    May split tiles.
 *    When a tile is split, the new tile's body and ti_client
 *    field are set to copies of the original tile's.
 *
 * ----------------------------------------------------------------------------
 */

int
glChanClipFunc(tile, area)
    Tile *tile;
    Rect *area;
{
    ClientData tileClient = tile->ti_client;
    TileType type = TiGetType(tile);
    Tile *newTile;
    int ret;

    ret = 0;
    if (LEFT(tile) < area->r_xbot)
    {
      tile = TiSplitX(tile, area->r_xbot);
      TiSetBody(tile, type);
      tile->ti_client = tileClient;
      ret = 1;
    }
    if (BOTTOM(tile) < area->r_ybot)
    {
      tile = TiSplitY(tile, area->r_ybot);
      TiSetBody(tile, type);
      tile->ti_client = tileClient;
      ret = 1;
    }
    if (RIGHT(tile) > area->r_xtop)
    {
      newTile = TiSplitX(tile, area->r_xtop);
      TiSetBody(newTile, type);
      newTile->ti_client = tileClient;
      ret = 1;
    }
    if (TOP(tile) > area->r_ytop)
    {
      newTile = TiSplitY(tile, area->r_ytop);
      TiSetBody(newTile, type);
      newTile->ti_client = tileClient;
      ret = 1;
    }

    return ret;
}

/*
 * ----------------------------------------------------------------------------
 *
 * glChanMergeFunc --
 *
 * Called by DBSrPaintArea() on behalf of glChanClip() above for each
 * tile contained within some area.  Merges this tile with any of
 * its neighbors within its channel's area, where the channel is
 * pointed to by the ti_client field.  We leave the resulting tile's
 * ti_client field pointing to this channel ('ch').
 *
 * IMPORTANT ASSUMPTION: no tile actually overlaps the boundary of
 * ch->gcr_area.  This is ensured by the caller's having called
 * glChanClipFunc() enough times to have split all the tiles
 * that originally might have crossed the channel's boundary.
 *
 * Results:
 *    Returns 1 if we did any merging, 0 otherwise.
 *
 * Side effects:
 *    May merge tiles.
 *    Leaves tile->ti_client set to 'ch'.
 *
 * ----------------------------------------------------------------------------
 */

int
glChanMergeFunc(tile)
    Tile *tile;
{
    GCRChannel *ch = (GCRChannel *) tile->ti_client;
    Tile *tp;
    int ret;

    ret = 0;
    if (TOP(tile) < ch->gcr_area.r_ytop)
    {
      tp = RT(tile);
      if (TiGetType(tp) == TiGetType(tile)
            && LEFT(tp) == LEFT(tile)
            && RIGHT(tp) == RIGHT(tile))
      {
          TiJoinY(tile, tp, glChanPlane);
          ret = 1;
      }
    }
    if (LEFT(tile) > ch->gcr_area.r_xbot)
    {
      tp = BL(tile);
      if (TiGetType(tp) == TiGetType(tile)
            && TOP(tp) == TOP(tile)
            && BOTTOM(tp) == BOTTOM(tile))
      {
          TiJoinX(tile, tp, glChanPlane);
          ret = 1;
      }
    }
    if (BOTTOM(tile) > ch->gcr_area.r_ybot)
    {
      tp = LB(tile);
      if (TiGetType(tp) == TiGetType(tile)
            && LEFT(tp) == LEFT(tile)
            && RIGHT(tp) == RIGHT(tile))
      {
          TiJoinY(tile, tp, glChanPlane);
          ret = 1;
      }
    }
    if (RIGHT(tile) < ch->gcr_area.r_xtop)
    {
      tp = TR(tile);
      if (TiGetType(tp) == TiGetType(tile)
            && TOP(tp) == TOP(tile)
            && BOTTOM(tp) == BOTTOM(tile))
      {
          TiJoinX(tile, tp, glChanPlane);
          ret = 1;
      }
    }

    return ret;
}

/*
 * ----------------------------------------------------------------------------
 *
 * glChanBlockDens --
 *
 * Find regions of maximum density in 'ch' (if 'ch' is a normal channel) and
 * "paint" them into the tile map.  Blockages of a single direction result
 * in CHAN_HRIVER or CHAN_VRIVER tiles being painted as appropriate; if
 * blockages exist in both directions, then we produce a CHAN_BLOCKED tile.
 *
 * We rely on the fact that regions of maximum density extend completely
 * across a channel, and hence completely across any tile (since tiles are
 * never bigger than channels).  The client fields of the any tiles in the
 * area of the channel that aren't totally blocked are left pointing to
 * the overlapping channel.
 *
 * If columns i through j inclusive have maximum density, then the blockage
 * we paint extends from midway between columns i-1 and i to midway between
 * column j and j+1, guaranteeing that tile boundaries will always fall
 * on half-grid lines.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    See above.
 *
 * ----------------------------------------------------------------------------
 */

void
glChanBlockDens(ch)
    GCRChannel *ch;
{
    GlobChan *gc = (GlobChan *) ch->gcr_client;
    int halfGrid, shiftedOrigin;
    DensMap *dRow, *dCol;
    PaintArea *pa;
    short *dens;
    int lo, hi;
    Rect area;

    if (ch->gcr_type != CHAN_NORMAL)
      return;

    dCol = &gc->gc_postDens[CZ_COL];
    dRow = &gc->gc_postDens[CZ_ROW];
    halfGrid = RtrGridSpacing / 2;
    glChanPaintList = (PaintArea *) NULL;
    if (dCol->dm_max >= dCol->dm_cap)
    {
      dens = dCol->dm_value;
      area.r_ybot = ch->gcr_area.r_ybot;
      area.r_ytop = ch->gcr_area.r_ytop;
      shiftedOrigin = ch->gcr_origin.p_x - halfGrid;
      for (lo = 1; lo < dCol->dm_size; lo++)
      {
          if (dens[lo] >= dCol->dm_cap)
          {
            hi = lo+1;
            while (dens[hi] >= dCol->dm_cap && hi < dCol->dm_size)
                hi++;

            /* Remember area of blocked tile to paint */
            area.r_xbot = shiftedOrigin + lo * RtrGridSpacing;
            area.r_xtop = shiftedOrigin + hi * RtrGridSpacing;
            pa = (PaintArea *) mallocMagic((unsigned)(sizeof (PaintArea)));
            pa->pa_area = area;
            pa->pa_next = glChanPaintList;
            pa->pa_type = CHAN_VRIVER;
            glChanPaintList = pa;

            /* Will get incremented in loop header */
            lo = hi-1;
          }
      }
    }

    if (dRow->dm_max >= dRow->dm_cap)
    {
      dens = dRow->dm_value;
      area.r_xbot = ch->gcr_area.r_xbot;
      area.r_xtop = ch->gcr_area.r_xtop;
      shiftedOrigin = ch->gcr_origin.p_y - halfGrid;
      for (lo = 1; lo < dRow->dm_size; lo++)
      {
          if (dens[lo] >= dRow->dm_cap)
          {
            hi = lo+1;
            while (dens[hi] >= dRow->dm_cap && hi < dRow->dm_size)
                hi++;

            /* Remember area of blocked tile to paint */
            area.r_ybot = shiftedOrigin + lo * RtrGridSpacing;
            area.r_ytop = shiftedOrigin + hi * RtrGridSpacing;
            pa = (PaintArea *) mallocMagic((unsigned)(sizeof (PaintArea)));
            pa->pa_area = area;
            pa->pa_next = glChanPaintList;
            pa->pa_type = CHAN_HRIVER;
            glChanPaintList = pa;

            /* Will get incremented in loop header */
            lo = hi-1;
          }
      }
    }

    /*
     * Now do all the work.
     * First paint all the blocked areas on glChanPaintList.
     * Then make a second pass through this list, searching the
     * area around each blocked area tile we painted for river
     * tiles of the appropriate type, and propagating this blockage
     * to those river tiles as well.  Do this until the wavefront
     * stops, which will happen as soon as we reach a normal channel.
     */
    do
    {
      for (pa = glChanPaintList; pa; pa = pa->pa_next)
      {
          /* Clip tiles overlapped by pa->pa_area */
          while (DBSrPaintArea((Tile *) NULL, glChanPlane, &pa->pa_area,
                &DBAllTypeBits, glChanClipFunc, (ClientData) &pa->pa_area))
            /* Nothing */;

          /* Change the type of all tiles within the area */
          (void) DBSrPaintArea((Tile *) NULL, glChanPlane, &pa->pa_area,
                &DBAllTypeBits, glChanPaintFunc, (ClientData) pa->pa_type);

          /*
           * Allow merging, as long as no tiles get merged across
           * channel boundaries.
           */
          while (DBSrPaintArea((Tile *) NULL, glChanPlane, &pa->pa_area,
                &DBAllTypeBits, glChanMergeFunc, (ClientData) NULL));
      }

      /* Second pass to propagate blockages to nearby areas */
      for (pa = glChanPaintList, glChanPaintList = NULL; pa; pa = pa->pa_next)
      {
          glChanFlood(&pa->pa_area, pa->pa_type);
          freeMagic((char *) pa);
      }
    } while (glChanPaintList != NULL);
}

int
glChanPaintFunc(tile, type)
    Tile *tile;
    TileType type;
{
    static TileType changeTable[4][4] = {
          /* Paint atop CHAN_NORMAL */
          { CHAN_NORMAL, CHAN_HRIVER, CHAN_VRIVER, CHAN_BLOCKED },

          /* Paint atop CHAN_HRIVER */
          { CHAN_HRIVER, CHAN_HRIVER, CHAN_BLOCKED, CHAN_BLOCKED },

          /* Paint atop CHAN_VRIVER */
          { CHAN_VRIVER, CHAN_BLOCKED, CHAN_VRIVER, CHAN_BLOCKED },

          /* Paint atop CHAN_BLOCKED */
          { CHAN_BLOCKED, CHAN_BLOCKED, CHAN_BLOCKED, CHAN_BLOCKED },
    };

    TiSetBody(tile, changeTable[TiGetType(tile)][type]);
    return 0;
}

/*
 * ----------------------------------------------------------------------------
 *
 * glChanFlood --
 *
 * Search all four sides of 'area' (an area that has just been painted
 * as type) for river tiles of the appropriate type (where appropriate
 * means tiles that are completely blocked by a tile of type type to
 * the side to which it lies).
 *
 * Each time an appropriate river tiles is found, record a CHAN_BLOCKED
 * rectangle on the list glChanPaintList that extends from 'area' through to
 * the other side of the river channel.
 *
 * The purpose of this procedure is so that the presence of the blockage
 * on one side of a river tile will be visible from its other side.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    May prepend stuff to glChanPaintList.
 *
 * ----------------------------------------------------------------------------
 */

void
glChanFlood(area, type)
    Rect *area;
    TileType type;
{
    TileTypeBitMask hMask, vMask;
    Rect outside;

    TTMaskSetOnlyType(&hMask, CHAN_HRIVER);
    TTMaskSetOnlyType(&vMask, CHAN_VRIVER);

    if (type != CHAN_VRIVER)
    {
      /* TOP */
      outside = *area;
      outside.r_ybot = area->r_ytop;
      outside.r_ytop = area->r_ytop + 1;
      (void) DBSrPaintArea((Tile *) NULL, glChanPlane, &outside, &vMask,
            glChanFloodVFunc, (ClientData) area);

      /* BOTTOM */
      outside = *area;
      outside.r_ybot = area->r_ybot - 1;
      outside.r_ytop = area->r_ybot;
      (void) DBSrPaintArea((Tile *) NULL, glChanPlane, &outside, &vMask,
            glChanFloodVFunc, (ClientData) area);
    }

    if (type != CHAN_HRIVER)
    {
      /* LEFT */
      outside = *area;
      outside.r_xbot = area->r_xbot - 1;
      outside.r_xtop = area->r_xbot;
      (void) DBSrPaintArea((Tile *) NULL, glChanPlane, &outside, &hMask,
            glChanFloodHFunc, (ClientData) area);

      /* RIGHT */
      outside = *area;
      outside.r_xbot = area->r_xtop;
      outside.r_xtop = area->r_xtop + 1;
      (void) DBSrPaintArea((Tile *) NULL, glChanPlane, &outside, &hMask,
            glChanFloodHFunc, (ClientData) area);
    }
}

int
glChanFloodVFunc(tile, area)
    Tile *tile;
    Rect *area;
{
    PaintArea *pa;

    pa = (PaintArea *) mallocMagic((unsigned) (sizeof (PaintArea)));
    pa->pa_area.r_xbot = MAX(area->r_xbot, LEFT(tile));
    pa->pa_area.r_xtop = MIN(area->r_xtop, RIGHT(tile));
    pa->pa_area.r_ybot = BOTTOM(tile);
    pa->pa_area.r_ytop = TOP(tile);
    pa->pa_next = glChanPaintList;
    pa->pa_type = CHAN_BLOCKED;
    glChanPaintList = pa;

    return 0;
}

int
glChanFloodHFunc(tile, area)
    Tile *tile;
    Rect *area;
{
    PaintArea *pa;

    pa = (PaintArea *) mallocMagic((unsigned)(sizeof (PaintArea)));
    pa->pa_area.r_ybot = MAX(area->r_ybot, BOTTOM(tile));
    pa->pa_area.r_ytop = MIN(area->r_ytop, TOP(tile));
    pa->pa_area.r_xbot = LEFT(tile);
    pa->pa_area.r_xtop = RIGHT(tile);
    pa->pa_next = glChanPaintList;
    pa->pa_type = CHAN_BLOCKED;
    glChanPaintList = pa;

    return 0;
}

/*
 * ----------------------------------------------------------------------------
 *
 * glChanSplitRiver --
 *
 * Called for each river tile (CHAN_HRIVER or CHAN_VRIVER) in glChanPlane.
 * Search along the two sides of this tile from which signals can enter
 * (the LHS and RHS for CHAN_HRIVER, or the top and bottom for CHAN_VRIVER),
 * and make sure that there are no tile boundaries involving some type of
 * tile other than CHAN_BLOCKED along that side.  If there is a boundary,
 * split tile at the boundary.
 *
 * Results:
 *    Returns 1 if we did any splitting, 0 if not.
 *
 * Side effects:
 *    See above.
 *
 * ----------------------------------------------------------------------------
 */

int
glChanSplitRiver(tile)
    Tile *tile;
{
    ClientData tileClient = tile->ti_client;
    Tile *tp, *newTile;
    int ret;

    ret = 0;
    if (TiGetType(tile) == CHAN_HRIVER)
    {
      for (tp = BL(tile); TOP(tp) < TOP(tile); tp = RT(tp))
      {
          if (NOTBLOCKED(tp) || NOTBLOCKED(RT(tp)))
          {
            tile = TiSplitY(tile, TOP(tp));
            TiSetBody(tile, CHAN_HRIVER);
            tile->ti_client = tileClient;
            ret = 1;
          }
      }
      for (tp = TR(tile); BOTTOM(tp) > BOTTOM(tile); tp = LB(tp))
      {
          if (NOTBLOCKED(tp) || NOTBLOCKED(LB(tp)))
          {
            newTile = TiSplitY(tile, BOTTOM(tp));
            TiSetBody(newTile, CHAN_HRIVER);
            newTile->ti_client = tileClient;
            ret = 1;
          }
      }
    }
    else
    {
      for (tp = RT(tile); LEFT(tp) > LEFT(tile); tp = BL(tp))
      {
          if (NOTBLOCKED(tp) || NOTBLOCKED(BL(tp)))
          {
            newTile = TiSplitX(tile, LEFT(tp));
            TiSetBody(newTile, CHAN_VRIVER);
            newTile->ti_client = tileClient;
            ret = 1;
          }
      }
      for (tp = LB(tile); RIGHT(tp) < RIGHT(tile); tp = TR(tp))
      {
          if (NOTBLOCKED(tp) || NOTBLOCKED(TR(tp)))
          {
            tile = TiSplitX(tile, RIGHT(tp));
            TiSetBody(tile, CHAN_VRIVER);
            tile->ti_client = tileClient;
            ret = 1;
          }
      }
    }

    return ret;
}

/*
 * ----------------------------------------------------------------------------
 *
 * glChanRiverBlock --
 *
 * Called for each river routing tile.  Checks to make sure that at least
 * some of the pins along the usable sides of this channel are still free;
 * if they're not, we change this tile's type to CHAN_BLOCKED.
 *
 * Note: river routing tiles can overlay portions of a normal channel
 * in which the density of the channel equals its capacity in either
 * the horizontal or vertical direction.
 *
 * Results:
 *    Always returns 0.
 *
 * Side effects:
 *    See above.
 *
 * ----------------------------------------------------------------------------
 */

int
glChanRiverBlock(tile)
    Tile *tile;
{
    GCRPin *pin, *pinLast;
    GCRChannel *ch;
    int lo, hi;

    ch = (GCRChannel *) tile->ti_client;
    if (TiGetType(tile) == CHAN_HRIVER)
    {
      lo = (BOTTOM(tile) - ch->gcr_origin.p_y) / RtrGridSpacing;
      hi = (TOP(tile) - ch->gcr_origin.p_y) / RtrGridSpacing;
      if (lo < 1) lo = 1;
      if (hi > ch->gcr_width) hi = ch->gcr_width;
      pinLast = &ch->gcr_lPins[hi];
      for (pin = &ch->gcr_lPins[lo]; pin <= pinLast; pin++)
          if (pin->gcr_pId == NULL && pin->gcr_linked)
            return 0;
      pinLast = &ch->gcr_rPins[hi];
      for (pin = &ch->gcr_rPins[lo]; pin <= pinLast; pin++)
          if (pin->gcr_pId == NULL && pin->gcr_linked)
            return 0;
    }
    else
    {
      /* CHAN_VRIVER */
      lo = (LEFT(tile) - ch->gcr_origin.p_x) / RtrGridSpacing;
      hi = (RIGHT(tile) - ch->gcr_origin.p_x) / RtrGridSpacing;
      if (lo < 1) lo = 1;
      if (hi > ch->gcr_length) hi = ch->gcr_length;
      pinLast = &ch->gcr_bPins[hi];
      for (pin = &ch->gcr_bPins[lo]; pin <= pinLast; pin++)
          if (pin->gcr_pId == NULL && pin->gcr_linked)
            return 0;
      pinLast = &ch->gcr_tPins[hi];
      for (pin = &ch->gcr_tPins[lo]; pin <= pinLast; pin++)
          if (pin->gcr_pId == NULL && pin->gcr_linked)
            return 0;
    }

    TiSetBody(tile, CHAN_BLOCKED);
    return 0;
}

/*
 * ----------------------------------------------------------------------------
 *
 * glChanPinToTile --
 *
 * Find the tile corresponding to the pin 'pin'.
 * The pin mustn't be in one of the corners of a channel.
 *
 * Results:
 *    Returns a pointer to the tile found.
 *    Returns NULL if the tile found was of type CHAN_BLOCKED.
 *
 * Side effects:
 *    None.
 *
 * ----------------------------------------------------------------------------
 */

Tile *
glChanPinToTile(hintTile, pin)
    Tile *hintTile;     /* Hint for starting the tile search */
    GCRPin *pin;  /* Find tile containing this pin */
{
    GCRChannel *ch;
    Tile *tp;
    Point p;
    Rect r;

    /* Figure out which channel tile the output point lies in */
    p = pin->gcr_point;
    switch (pin->gcr_side)
    {
      case GEO_NORTH:   p.p_y--; break;
      case GEO_EAST:    p.p_x--; break;
    }

    tp = TiSrPoint(hintTile, glChanPlane, &p);
    if (TiGetType(tp) == CHAN_BLOCKED)
      return (Tile *) NULL;

    ASSERT(tp->ti_client != (ClientData) CLIENTDEFAULT, "glChanPinToTile");
    ch = (GCRChannel *) tp->ti_client;
    TITORECT(tp, &r);
    ASSERT(GEO_SURROUND(&ch->gcr_area, &r), "glChanPinToTile");

    return tp;
}

Generated by  Doxygen 1.6.0   Back to index