/*
 * grouteDens.c
 *
 * Procedures for manipulating DensMap structures.
 *
 *     ********************************************************************* 
 *     * 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/grouter/grouteDens.c,v 1.2 2001/01/12 22:12:51 jsolomon Exp $";
#endif	lint

#include <stdio.h>
#include "misc/magic.h"
#include "utils/geometry.h"
#include "utils/hash.h"
#include "utils/doubleint.h"
#include "utils/heap.h"
#include "tiles/tile.h"
#include "database/database.h"
#include "netlist/netlist.h"
#include "gcr/gcr.h"
#include "router/router.h"
#include "grouter/grouter.h"
#include "signals/signals.h"
#include "textio/textio.h"
#include "utils/malloc.h"
#include "misc/styles.h"
#include "debug/debug.h"

/*
 * ----------------------------------------------------------------------------
 *
 * glDensAdjust --
 *
 * Increment the density in the channel as a result of routing the segment
 * from p1 to p2 through the channel common to both.  The segment is
 * identified by the NetId 'netid'.  The density map 'dens' is incremented
 * for each column/row of the channel through which the segment must run,
 * where the segment doesn't already exist.
 *
 * Results:
 *	Returns TRUE if any more of srcPin->gcr_ch became filled
 *	up to maximum density.
 *
 * Side effects:
 *	Modifies the local and possibly the maximum densities in *dens.
 *
 * ----------------------------------------------------------------------------
 */

bool
glDensAdjust(dens, srcPin, dstPin, netid)
    register DensMap dens[2];
    GCRPin *srcPin, *dstPin;
    NetId netid;
{
    int minprow, maxprow, minpcol, maxpcol, mincol, maxcol, minrow, maxrow;
    int maxvd, maxhd, col, row, nrow, ncol;
    GCRChannel *ch = srcPin->gcr_ch;
    register GCRPin *p1, *p2;
    register short *dvec;
    bool densChanged;

    /* Sanity checking */
    ASSERT(srcPin && dstPin, "glDensAdjust");
    ASSERT(srcPin->gcr_ch == dstPin->gcr_ch, "glDensAdjust");

    if (DebugIsSet(glDebugID, glDebGreedy))
	return;

    /*
     * Find the first and last column where this net (netId)
     * is previously present in the channel, and also the first
     * and last row.
     */
    nrow = dens[CZ_ROW].dm_size - 1;
    ncol = dens[CZ_COL].dm_size - 1;
    maxprow = 0, minprow = dens[CZ_ROW].dm_size;
    maxpcol = 0, minpcol = dens[CZ_COL].dm_size;

	/* Rows */
    p1 = &ch->gcr_lPins[1], p2 = &ch->gcr_rPins[1];
    for (row = 1; row < dens[CZ_ROW].dm_size; row++, p1++, p2++)
    {
	if (SAMENET(p1, netid.netid_net, netid.netid_seg))
	{
	    minpcol = 1;
	    minprow = MIN(row, minprow);
	    maxprow = MAX(row, maxprow);
	}
	if (SAMENET(p2, netid.netid_net, netid.netid_seg))
	{
	    maxpcol = ncol;
	    minprow = MIN(row, minprow);
	    maxprow = MAX(row, maxprow);
	}
    }

	/* Columns */
    p1 = &ch->gcr_bPins[1], p2 = &ch->gcr_tPins[1];
    for (col = 1; col < dens[CZ_COL].dm_size; col++, p1++, p2++)
    {
	if (SAMENET(p1, netid.netid_net, netid.netid_seg))
	{
	    minprow = 1;
	    minpcol = MIN(col, minpcol);
	    maxpcol = MAX(col, maxpcol);
	}
	if (SAMENET(p2, netid.netid_net, netid.netid_seg))
	{
	    maxprow = nrow;
	    minpcol = MIN(col, minpcol);
	    maxpcol = MAX(col, maxpcol);
	}
    }

    /*
     * Increment the density over any range where
     * this net was not already present but is now.
     */
    p1 = srcPin;
    p2 = dstPin;

#define	CLIPTORANGE(x, min, max) \
    ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x)))

    densChanged = FALSE;
    minrow = MIN(p1->gcr_y, p2->gcr_y);
    minrow = CLIPTORANGE(minrow, 1, nrow);
    maxrow = MAX(p1->gcr_y, p2->gcr_y);
    maxrow = CLIPTORANGE(maxrow, 1, nrow);
    maxvd = dens[CZ_ROW].dm_max;
    dvec = dens[CZ_ROW].dm_value;
    for (row = minrow; row <= maxrow; row++)
	if (row < minprow || row > maxprow)
	    if (++dvec[row] >= maxvd)
	    {
		densChanged = TRUE;
		maxvd = dvec[row];
	    }
    dens[CZ_ROW].dm_max = maxvd;

    mincol = MIN(p1->gcr_x, p2->gcr_x);
    mincol = CLIPTORANGE(mincol, 1, ncol);
    maxcol = MAX(p1->gcr_x, p2->gcr_x);
    maxcol = CLIPTORANGE(maxcol, 1, ncol);
    maxhd = dens[CZ_COL].dm_max;
    dvec = dens[CZ_COL].dm_value;
    for (col = mincol; col <= maxcol; col++)
	if (col < minpcol || col > maxpcol)
	    if (++dvec[col] >= maxhd)
	    {
		maxhd = dvec[col];
		densChanged = TRUE;
	    }
    dens[CZ_COL].dm_max = maxhd;
    return densChanged;
}

/*
 * ----------------------------------------------------------------------------
 *
 * glDMAlloc --
 *
 * Allocate and zero the dm_value array for the DensMap structure 'dm'.
 * This array will have size 'top+1'.  The maximum capacity is 'cap'.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	See above.
 *
 * ----------------------------------------------------------------------------
 */

glDMAlloc(dm, top, cap)
    register DensMap *dm;
    int top, cap;
{
    dm->dm_max = 0;
    dm->dm_size = top + 1;
    dm->dm_cap = cap;
    CALLOC(short *, dm->dm_value, sizeof (short) * dm->dm_size);
}

/*
 * ----------------------------------------------------------------------------
 *
 * glDMCopy --
 *
 * Copy the DensMap structure *dm1 to *dm2, copying the dm_value array
 * as well.  (The two DensMap structures better have the same size;
 * also, dm2->dm_value must already be allocated).
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	See above.
 *
 * ----------------------------------------------------------------------------
 */

Void
glDMCopy(dm1, dm2)
    register DensMap *dm1, *dm2;
{
    dm2->dm_max = dm1->dm_max;
    ASSERT(dm2->dm_size == dm1->dm_size, "glDMCopy");
    ASSERT(dm2->dm_cap == dm1->dm_cap, "glDMCopy");
    bcopy((char *) dm1->dm_value, (char *) dm2->dm_value,
	    sizeof (short) * dm1->dm_size);
}

/*
 * ----------------------------------------------------------------------------
 *
 * glDMFree --
 *
 * Free the memory allocated to dm->dm_value.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Frees memory.
 *
 * ----------------------------------------------------------------------------
 */

Void
glDMFree(dm)
    DensMap *dm;
{
    FREE((char *) dm->dm_value);
}

/*
 * ----------------------------------------------------------------------------
 *
 * glDMMaxInRange --
 *
 * Return the maximum value of the DensMap in the inclusive range lo .. hi.
 *
 * Results:
 *	See above.
 *
 * Side effects:
 *	None.
 *
 * ----------------------------------------------------------------------------
 */

int
glDMMaxInRange(dm, lo, hi)
    DensMap *dm;
    int lo, hi;
{
    register short *dval = dm->dm_value;
    register int n, max;

    /* Sanity checks */
    ASSERT(lo > 0, "glDMMaxInRange");
    ASSERT(hi < dm->dm_size, "glDMMaxInRange");

    max = 0;
    for (n = lo; n <= hi; n++)
	if (dval[n] > max)
	    max = dval[n];

    return (max);
}

/*
 * ----------------------------------------------------------------------------
 *
 * glDensInit --
 *
 * Initialize the DensMap pair dmap[] from the already-initialized
 * density map in the GCRChannel *ch.  (The use of two separate kinds
 * of density maps is a temporary measure that will go away when the
 * integration of the new routing code is complete).
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	See above.
 *
 * ----------------------------------------------------------------------------
 */

Void
glDensInit(dmap, ch)
    register DensMap dmap[2];
    GCRChannel *ch;
{
    register short *dSrc, *dDst, *dEnd;

    dmap[CZ_COL].dm_max = ch->gcr_dMaxByCol;
    dmap[CZ_ROW].dm_max = ch->gcr_dMaxByRow;
    dSrc = ch->gcr_dRowsByCol;
    dDst = dmap[CZ_COL].dm_value;
    dEnd = &dmap[CZ_COL].dm_value[dmap[CZ_COL].dm_size];
    while (dDst < dEnd)
	*dDst++ = *dSrc++;

    dSrc = ch->gcr_dColsByRow;
    dDst = dmap[CZ_ROW].dm_value;
    dEnd = &dmap[CZ_ROW].dm_value[dmap[CZ_ROW].dm_size];
    while (dDst < dEnd)
	*dDst++ = *dSrc++;
}
