/* rtrMain.c -
 *
 *	Top level routing code, and glue that doesn't belong elsewhere.
 *
 *     *********************************************************************
 *     * 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/router/rtrMain.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif  /* not lint */

#include <stdio.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <sys/types.h>
#include <sys/times.h>
#include <ctype.h>

#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/hash.h"
#include "utils/heap.h"
#include "tiles/tile.h"
#include "database/database.h"
#include "gcr/gcr.h"
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "utils/main.h"
#include "utils/signals.h"
#include "router/rtrDcmpose.h"
#include "netmenu/netmenu.h"
#include "router/router.h"
#include "grouter/grouter.h"
#include "utils/netlist.h"
#include "textio/textio.h"
#include "netmenu/netmenu.h"
#include "utils/runstats.h"

/* C99 compat */
#include "garouter/garouter.h"

/* Forward declarations */

extern int rtrMakeChannel();
void RtrMilestoneStart(char *);
void RtrMilestoneDone();


/*
 * The origin point for the routing grid.
 * Set by the "route origin" command.
 */
Point RtrOrigin = { 0, 0 };

/*
 * ----------------------------------------------------------------------------
 *
 * Route --
 *
 * Top level procedure for the routing code.
 *
 * Route all channels in the cell routeUse->cu_def, based on net lists
 * in the net list hash table.  There currently is no check that the net
 * list belongs to the edit cell.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Memory for channels is allocated and set.  The channel structure is
 *	kept around to allow flags to be examined and displayed on the screen.
 *	Leaves paint in routeUse->cu_def.
 *
 * ----------------------------------------------------------------------------
 */

void
Route(routeUse, routeArea)
    CellUse *routeUse;
    Rect *routeArea;
{
    CellDef *channelDef;
    int errs, numNets;
    NLNetList netList;
    char *netListName;

    /* Read the netlist into an internal NLNetList structure */
    if (!NMHasList())
    {
	netListName = routeUse->cu_def->cd_name;
	TxPrintf("No netlist selected yet;  using \"%s\".\n", netListName);
	NMNewNetlist(netListName);
    }
    else netListName = NMNetlistName();
    RtrMilestoneStart("Building netlist");
    numNets = NLBuild(routeUse, &netList);
    RtrMilestoneDone();
    if (numNets == 0)
    {
	TxError("No nets to route.\n");
	return;
    }

    /*
     * Create a plane whose space tiles correspond to channels.
     * See the comments in RtrDecompose() for details.
     */
    RtrMilestoneStart("Channel decomposition");
    channelDef = RtrDecompose(routeUse, routeArea, &netList);
    RtrMilestoneDone();
    if (channelDef == NULL)
    {
	TxError("Routing area (box) is too small to be of any use.\n");
	goto done;
    }
    RtrChannelPlane = channelDef->cd_planes[PL_DRC_ERROR];

    /*
     * Enumerate all space tiles in the channel plane, generating a
     * channel for each one.  Initialize each channel's dimensions,
     * but don't do anything else.
     */
    RtrChannelList = (GCRChannel *) NULL;
    (void) DBSrPaintArea((Tile *) NULL, RtrChannelPlane, &RouteArea,
	    &DBAllTypeBits, rtrMakeChannel, (ClientData) &RouteArea);
    if (!SigInterruptPending)
    {
	errs = GARoute(RtrChannelList, routeUse, &netList);
	if (errs == 0)
	    TxPrintf("No routing errors.\n");
	else if (errs == 1)
	    TxPrintf("There was one routing error:  see feedback.\n");
	else TxPrintf("There were %d routing errors:  see feedback.\n", errs);
    }

done:
    /* Clean up global routing information */
    NLFree(&netList);
}

/*
 * ----------------------------------------------------------------------------
 *
 * rtrMakeChannel --
 *
 * Function passed to DBSrPaintArea to enumerate space tiles and convert them
 * to channels.  Clip all tiles against the box 'clipBox'.  Don't set
 * hazards for this channel; that has to happen after stem assignment.
 *
 * Results:
 *	Return 0 to keep the search going, 1 to abort.
 *
 * Side effects:
 *	Hashes space tile pointers from the channel cell's drc error plane
 *	to get a pointer to a malloc'ed channel structure.
 *
 *	Prepends this channel to the list being built in RtrChannelList.
 *
 * ----------------------------------------------------------------------------
 */

int
rtrMakeChannel(tile, dinfo, clipBox)
    Tile *tile;		/* Potential channel tile; we create a channel whose
			 * area is equal to that of this tile if the type of
			 * this tile is TT_SPACE.
			 */
    TileType dinfo;	/* Split tile information (unused) */
    Rect *clipBox;	/* If non-NULL, clip the channel area to this box */
{
    int length, width;
    HashEntry *entry;
    GCRChannel *ch;
    Point origin;
    Rect bbox;

    if (SigInterruptPending) return (1);
    if (TiGetBody(tile) != (ClientData) NULL) return (0);

    entry = HashFind(&RtrTileToChannel, (char *) tile);
    ASSERT(HashGetValue(entry) == (char *) 0, "rtrMakeChannel");
    TITORECT(tile, &bbox);
    GeoClip(&bbox, clipBox);

    /*
     * Figure out how many columns and rows will fit in the area,
     * then create and initialize a channel.
     */
    RtrChannelBounds(&bbox, &length, &width, &origin);
    ch = GCRNewChannel(length, width);
    ch->gcr_area = bbox;
    ch->gcr_origin = origin;
    ch->gcr_type = CHAN_NORMAL;

    /* Remember that we've processed it */
    HashSetValue(entry, (char *) ch);

    /* Prepend to RtrChannelList */
    ch->gcr_next = RtrChannelList;
    RtrChannelList = ch;

    return(0);
}

/*
 * ----------------------------------------------------------------------------
 *
 * RtrRunStats --
 * RtrMilestoneStart --
 * RtrMilestoneDone --
 * RtrMilestonePrint --
 *
 * Miscellaneous procedures for debugging/timing.
 * Calling RtrRunStats() prints out the time since the last call
 * and the total amount of memory used in the heap.  The procedures
 * RtrMilestoneStart() and RtrMilestoneDone() should be used to bracket
 * calls to the various pieces of the router: the former announces
 * that the router is about to enter a given section, and the latter
 * says it is done and tells how long it took.  During a given section,
 * RtrMilestonePrint() will print '#' if no errors have occurred since
 * the last call; otherwise, it will print a '!'.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Output to terminal.
 *
 * ----------------------------------------------------------------------------
 */

    /* The following are both set by RtrMilestoneStart() */
static char *rtrMilestoneName;	/* Name of the current section */
static struct tms rtrStartTime;	/* Starting time of the current section */
static int rtrFeedCount;	/* Most recent # of feedback areas */

void
RtrRunStats()
{
    char *RunStats();
    static struct tms last, delta;

    TxPrintf("%s\n", RunStats(RS_TINCR|RS_MEM, &last, &delta));
    TxFlush();
}

void
RtrMilestoneStart(event)
    char *event;
{
    rtrMilestoneName = event;
    TxPrintf("%s: ", event);
    TxFlush();
    (void) times(&rtrStartTime);
    rtrFeedCount = DBWFeedbackCount;
}

void
RtrMilestoneDone()
{
    struct tms tend;

    times(&tend);
    TxPrintf("\n%s time: %.1fu %.1fs\n", rtrMilestoneName,
		(tend.tms_utime - rtrStartTime.tms_utime) / 60.0,
		(tend.tms_stime - rtrStartTime.tms_stime) / 60.0);
}

void
RtrMilestonePrint()
{
    TxPrintf("%c", (DBWFeedbackCount > rtrFeedCount) ? '!' : '#');
    TxFlush();
    rtrFeedCount = DBWFeedbackCount;
}
