/*
 * gcrRiver.c -
 *
 * The greedy router: river-routing across the tops of channels.
 *
 *     ********************************************************************* 
 *     * 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[] = "$Header: /ufs/repository/magic/gcr/gcrRiver.c,v 1.2 2001/01/12 22:12:43 jsolomon Exp $";
#endif  not lint

#include <stdio.h>
#include "misc/magic.h"
#include "utils/geometry.h"
#include "gcr/gcr.h"
#include "textio/textio.h"
#include "utils/malloc.h"


/*
 * ----------------------------------------------------------------------------
 *
 * gcrRiverRoute --
 *
 * Determine if a channel should be routed by a simple river-router;
 * if so, then route it.  Currently, river-routing channels are identified
 * during channel decomposition.
 *
 * Results:
 *	Returns TRUE on success, FALSE on failure (in which case
 *	the caller should try to route the channel by other means.
 *
 * Side effects:
 *	If successful, sets flags in the channel structure to show
 *	where routing is to be placed.
 *
 * ----------------------------------------------------------------------------
 */

bool
gcrRiverRoute(ch)
    GCRChannel *ch;
{
    switch (ch->gcr_type)
    {
	case CHAN_HRIVER:
	    if (gcrOverCellHoriz(ch))
		return (TRUE);
	    break;
	case CHAN_VRIVER:
	    if (gcrOverCellVert(ch))
		return (TRUE);
	    break;
    }

    return (FALSE);
}

/*
 * ----------------------------------------------------------------------------
 *
 * gcrOverCellHoriz --
 * gcrOverCellVert --
 *
 * Route an over-cell channel if possible.  These channels should be
 * river-routable.  We perform a few quick checks to ensure that there
 * are terminals only on opposite sides in pairs.  Channels routed
 * horizontally are processed by gcrOverCellHoriz(); those routed
 * vertically are processed by gcrOverCellVert().
 *
 * Results:
 *	TRUE if the channel met our requirements and we routed it
 *	successfully; FALSE if we couldn't route it.
 *
 * Side effects:
 *	Sets flags in the channel structure to show where routing
 *	is to be placed.
 *
 * ----------------------------------------------------------------------------
 */

#define	USED(pin) \
	((pin)->gcr_pId != (GCRNet *) 0 && (pin)->gcr_pId != (GCRNet *) -1)

bool
gcrOverCellHoriz(ch)
    GCRChannel *ch;
{
    register short **result = ch->gcr_result;
    register int col, row;

    /* Ensure top and bottom pins aren't used */
    for (col = 1; col <= ch->gcr_length; col++)
	if (USED(&ch->gcr_tPins[col]) || USED(&ch->gcr_bPins[col]))
	{
	    TxPrintf("Failing because top or bottom pins are used\n");
	    return (FALSE);
	}

    /* Ensure left and right pins match */
    for (row = 1; row <= ch->gcr_width; row++)
	if (USED(&ch->gcr_lPins[row]) && USED(&ch->gcr_rPins[row]))
	{
	    if (ch->gcr_lPins[row].gcr_pId != ch->gcr_rPins[row].gcr_pId
		|| ch->gcr_lPins[row].gcr_pSeg != ch->gcr_rPins[row].gcr_pSeg)
	    {
		TxPrintf("Failing because left and right pins don't match\n");
		return (FALSE);
	    }
	}

    /*
     * Channel is routable by a simple river-router:
     * zoom across for each row that is to be connected
     * across the channel.
     */
    for (row = 1; row <= ch->gcr_width; row++)
	if (USED(&ch->gcr_lPins[row]))
	    for (col = 0; col <= ch->gcr_length; col++)
		result[col][row] |= GCRR;

    return (TRUE);
}

bool
gcrOverCellVert(ch)
    GCRChannel *ch;
{
    register short **result = ch->gcr_result;
    register int col, row;

    /* Ensure left and right pins aren't used */
    for (row = 1; row <= ch->gcr_width; row++)
	if (USED(&ch->gcr_lPins[row]) || USED(&ch->gcr_rPins[row]))
	{
	    TxPrintf("Failing because left or right pins are used\n");
	    return (FALSE);
	}

    /* Ensure top and bottom pins match */
    for (col = 1; col <= ch->gcr_length; col++)
	if (USED(&ch->gcr_tPins[col]) && USED(&ch->gcr_bPins[col]))
	{
	    if (ch->gcr_tPins[col].gcr_pId != ch->gcr_bPins[col].gcr_pId
		|| ch->gcr_tPins[col].gcr_pSeg != ch->gcr_bPins[col].gcr_pSeg)
	    {
		TxPrintf("Failing because top and bottom pins don't match\n");
		return (FALSE);
	    }
	}

    /*
     * Channel is routable by a simple river-router:
     * zoom across for each column that is to be connected
     * across the channel.
     */
    for (col = 1; col <= ch->gcr_length; col++)
	if (USED(&ch->gcr_tPins[col]))
	    for (row = 0; row <= ch->gcr_width; row++)
		result[col][row] |= GCRU;

    return (TRUE);
}
