/*
 * grouteMain.c --
 *
 * Top level code for the global signal router.
 *
 * The global router's job is to find the sequence of channel pins
 * through which each signal must pass, and mark these pins so the
 * channel router can connect them within each channel.
 *
 * Our overall approach is greedy: we compute the area of the bounding
 * box of all terminals in a net for each net, and perform global routing
 * of each net in order of increasing area of this bounding box.  This
 * has the effect of routing more constrained nets first, and less
 * constrained ones later.
 *
 *     *********************************************************************
 *     * 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 <sys/types.h>
#include <sys/times.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"

/* Global data */
Heap glMazeHeap;	/* Heap of search points for global routing */
FILE *glLogFile;	/* Used for debugging to remember crossings processed */
int glNumTries;		/* Debugging too -- # calls to glProcessLoc() */

/* Forward declarations */
void glClientInit();
void glClientFree();


/*
 * ----------------------------------------------------------------------------
 *
 * GlGlobalRoute --
 *
 * Build a heap of nets, ordered with smallest area first.
 * Globally route nets on the heap, decomposing multi-pin nets using
 * Steiner-like trees.  Leave routing problems in channel structures.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	On completion crossing points for nets have been set.  Channel
 *	structures are ready to be routed by the channel structure.
 *
 * ----------------------------------------------------------------------------
 */

void
GlGlobalRoute(chanList, netList)
    GCRChannel *chanList;	/* List of all channels in routing problem */
    NLNetList *netList;		/* Netlist built by caller */
{
    HeapEntry entry;
    Heap netHeap;
    bool doFast;
    int numTerms;
    NLNet *net;

    GlInit();
    glStatsInit();
    doFast = DebugIsSet(glDebugID, glDebFast);

    /*
     * Initialize the client-specific portion of each channel and
     * of each net.  These fields point to structures holding
     * (respectively) density information and blocked regions
     * during global routing.
     */
    glClientInit(chanList, netList);

    /*
     * Build a tile plane that represents all the channels in the
     * routing problem.  This tile plane will be used to search
     * for nearby channels during global routing.
     */
    glChanBuildMap(chanList);
    if (DebugIsSet(glDebugID, glDebChan))
    {
	SigInterruptPending = TRUE;
	return;
    }

    /* Compute penalties for passing through congested zones */
    if (DebugIsSet(glDebugID, glDebPen))
	glPenCompute(chanList, netList);

    /*
     * Build a heap of nets sorted in order of increasing size, then
     * successively remove the topmost entry of the heap and route its
     * net.  Make almost-Steiner tree global routes for multi-pin nets.
     */
    numTerms = 0;
    NLSort(netList, &netHeap);
    while (HeapRemoveTop(&netHeap, &entry) && !SigInterruptPending)
    {
	net = (NLNet *) entry.he_id;
	if (DebugIsSet(glDebugID, glDebPen))
	{
	    glCrossUnreserve(net);
	    glPenSetPerChan(net);
	}
	numTerms += glMultiSteiner(EditCellUse, net, glProcessLoc,
			glCrossMark, INT2CD(doFast), (ClientData) 0);
	if (DebugIsSet(glDebugID, glDebPen))
	    glPenClearPerChan(net);
	RtrMilestonePrint();
    }
    HeapKill(&netHeap, (cb_heap_kill_t) NULL);

    glClientFree(chanList, netList);
    glChanFreeMap();
    glStatsDone(netList->nnl_numNets, numTerms);
}

/*
 * ----------------------------------------------------------------------------
 *
 * glClientInit --
 *
 * Allocate and initialize the structures that go in the gcr_client and
 * nnet_cdata fields of all the channels and nets respectively in chanList
 * and netList, and leave these fields pointing to the newly allocated and
 * initialized structures.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Allocates memory; see above.
 *
 * ----------------------------------------------------------------------------
 */

void
glClientInit(chanList, netList)
    GCRChannel *chanList;
    NLNetList *netList;
{
    GCRChannel *ch;
    GlobChan *gc;
    NLNet *net;
    int nrow, ncol;

    for (ch = chanList; ch; ch = ch->gcr_next)
    {
	gc = (GlobChan *) mallocMagic((unsigned) (sizeof (GlobChan)));
	gc->gc_penList = (CZone *) NULL;
	nrow = ch->gcr_width;
	ncol = ch->gcr_length;
	glDMAlloc(&gc->gc_prevDens[CZ_COL], ncol, nrow);
	glDMAlloc(&gc->gc_prevDens[CZ_ROW], nrow, ncol);
	glDMAlloc(&gc->gc_postDens[CZ_COL], ncol, nrow);
	glDMAlloc(&gc->gc_postDens[CZ_ROW], nrow, ncol);
	glDensInit(gc->gc_prevDens, ch);
	glDMCopy(&gc->gc_prevDens[CZ_COL], &gc->gc_postDens[CZ_COL]);
	glDMCopy(&gc->gc_prevDens[CZ_ROW], &gc->gc_postDens[CZ_ROW]);
	ch->gcr_client = (ClientData) gc;
    }

    for (net = netList->nnl_nets; net; net = net->nnet_next)
	net->nnet_cdata = (ClientData) callocMagic(1, (unsigned) (sizeof (NetClient)));
}

/*
 * ----------------------------------------------------------------------------
 *
 * glClientFree --
 *
 * Free the memory allocated by glClientInit() above (as well as any
 * memory allocated to CZone lists pointed to by the NetClient structs
 * in the NLNetList netList).
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Frees memory.
 *
 * ----------------------------------------------------------------------------
 */

void
glClientFree(chanList, netList)
    GCRChannel *chanList;
    NLNetList *netList;
{
    GlobChan *gc;
    CZone *cz;
    NetClient *nclient;
    GCRChannel *ch;
    NLNet *net;

    for (ch = chanList; ch; ch = ch->gcr_next)
    {
	gc = (GlobChan *) ch->gcr_client;
	glDMFree(&gc->gc_prevDens[CZ_COL]);
	glDMFree(&gc->gc_prevDens[CZ_ROW]);
	glDMFree(&gc->gc_postDens[CZ_COL]);
	glDMFree(&gc->gc_postDens[CZ_ROW]);
	freeMagic((char *) gc);
	ch->gcr_client = (ClientData) NULL;
    }

    for (net = netList->nnl_nets; net; net = net->nnet_next)
    {
	nclient = (NetClient *) net->nnet_cdata;
	free_magic1_t mm1 = freeMagic1_init();
	for (cz = nclient->nc_pens; cz; cz = cz->cz_next)
	    freeMagic1(&mm1, (char *) cz);
	freeMagic1_end(&mm1);
	net->nnet_cdata = (ClientData) NULL;
    }
}

/*
 * ----------------------------------------------------------------------------
 *
 * glProcessLoc --
 *
 * Function called for all but the first NLTermLoc in a net: finds and
 * returns the best-cost path from any of the points in the starting
 * point list to loc->nloc_stem.
 *
 * Algorithm:
 *	We use two passes.  The first attempts to find the shortest
 *	distance path between the source and the destination, if
 *	such a path exists.  It uses a mechanism for storing the
 *	best cost so far to each crossing point considered, so
 *	we avoid looping.  If no path can be found, we simply
 *	give up; otherwise, we perform a second pass where we
 *	try to generate not only the shortest path, but the
 *	next shortest, etc, until we find one whose distance
 *	plus crossing penalty is minimized.
 *
 * Results:
 *	Returns the best path.  The first element on the list
 *	(linked by gl_path pointers) is the destination point.
 *	If no path could be found with cost less than bestCost,
 *	returns NULL.
 *
 * Side effects:
 *	Allocates memory from the temporary GlPoint arena.
 *
 * ----------------------------------------------------------------------------
 */

GlPoint *
glProcessLoc(startList, loc, bestCost, doFast)
    GlPoint *startList;	/* List of starting points */
    NLTermLoc *loc;	/* Location of terminal being routed to */
    int bestCost;	/* Best cost so far; if we can't find a path in
			 * less than this cost, give up.
			 */
    bool doFast;	/* If TRUE, only wiggle crossings around within the
			 * channels on the shortest path; don't bother
			 * considering other sequences of channels.  If FALSE,
			 * we keep generating longer and longer paths until
			 * the sheer length of a path exceeds our best
			 * adjusted cost to date.
			 */
{
    extern bool glMazeShortest;
    extern Tile *glMazeDestTile;
    extern Point glMazeDestPoint;
    extern GlPoint *glMazeFindPath();
    extern GlPoint *glCrossAdjust();
    int headFree, shortLength, bestLength;
    GlPoint *lastPt, *bestPt, *adjustedPt;
    GlPage *headPage;

    glNumTries++;
    glCrossScalePenalties();

    /* Sanity checks */
    ASSERT(GEO_SAMEPOINT(loc->nloc_pin->gcr_point, loc->nloc_stem),
		"glProcessLoc");

    /*
     * Passed to glMazeFindPath() for use in estimating the remaining
     * distance to the destination point.  Also figure out which
     * channel tile contains the destination, so we can handle
     * points in it specially.  If the destination point is inside
     * a blocked area, give up immediately.
     */
    glMazeDestPoint = loc->nloc_stem;
    glMazeDestTile = glChanPinToTile((Tile *) NULL, loc->nloc_pin);

    /* Abort immediately if destination is obviously unreachable */
    if (glMazeDestTile == NULL)
	return (GlPoint *) NULL;

    /*
     * First try finding the shortest path.
     * This goes very quickly, because we are able to chop
     * off unpromising paths at an early stage.
     */
    glMazeShortest = TRUE;
    HeapInit(&glMazeHeap, 128, FALSE, FALSE);
    glListToHeap(startList, &loc->nloc_stem);
    headPage = glPathCurPage;
    headFree = glPathCurPage->glp_free;
    bestPt = glMazeFindPath(loc, bestCost);
    glMazeResetCost(headPage, headFree);
    HeapKill(&glMazeHeap, (cb_heap_kill_t) NULL);
    if (bestPt == (GlPoint *) NULL)
    {
	glBadRoutes++;
	return bestPt;
    }
    shortLength = bestPt->gl_cost;

    /*
     * Now try finding a path that minimizes the crossing penalty.
     * We do this by continuing to generate paths in order of
     * increasing length, then adjusting the crossing points
     * along the path to minimize (locally) the penalty for
     * the path, until we find a path whose unadjusted length
     * exceeds the best cost we've been able to achieve so far.
     * The gl_cost fields in the paths generated by glCrossAdjust
     * incorporate the penalties as well as distance.
     */
    HeapInit(&glMazeHeap, 128, FALSE, FALSE);
    glListToHeap(startList, &loc->nloc_stem);
    if (doFast)
    {
	headPage = glPathCurPage;
	headFree = glPathCurPage->glp_free;
    }
    else glMazeShortest = FALSE;
    bestPt = (GlPoint *) NULL;
    while ((lastPt = glMazeFindPath(loc, bestCost)))
    {
	adjustedPt = glCrossAdjust((GlPoint *) NULL, lastPt);
	if (adjustedPt->gl_cost < bestCost)
	{
	    bestCost = adjustedPt->gl_cost;
	    bestLength = lastPt->gl_cost;
	    bestPt = adjustedPt;
	}
    }
    if (doFast)
	glMazeResetCost(headPage, headFree);
    HeapKill(&glMazeHeap, (cb_heap_kill_t) NULL);
    if (bestPt)
    {
	if (glLogFile)
	{
	    fprintf(glLogFile, "%d\t%d (%.2f)\t%d (%.2f)\n",
		shortLength, bestLength,
		(float) bestLength / (float) shortLength * 100.0,
		bestPt->gl_cost,
		(float) bestPt->gl_cost / (float) shortLength * 100.0);
	}
	glGoodRoutes++;
	return bestPt;
    }

    glBadRoutes++;
    glNoRoutes++;
    return (GlPoint *) NULL;
}
