/*
 * mzTech.c --
 *
 * Technology file read-in for the maze router.
 * Processes mzrouter and drc sections of tech file to
 * set up maze routing parameter sets.
 *
 *     ********************************************************************* 
 *     * Copyright (C) 1988, 1990 Michael H. Arnold and the 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-7.5/mzrouter/mzTech.c,v 1.7 2007/03/24 22:58:43 tim Exp $";
#endif  /* not lint */

#include <stdio.h>
#include <stdlib.h>
#include <string.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 "utils/signals.h"
#include "textio/textio.h"
#include "wiring/wiring.h"
#include "utils/utils.h"
#include "utils/tech.h"
#include "utils/malloc.h"
#include "utils/list.h"
#include "windows/windows.h"
#include "utils/main.h"
#include "mzrouter/mzrouter.h"
#include "mzrouter/mzInternal.h"

/* Procedures referenced before they are defined 
 * (these procedures are local to this file)
 */
RouteType *mzFindRouteType();
RouteLayer *mzFindRouteLayer();
RouteContact *mzFindRouteContact();

/* Techspacing structure -
 * 
 * This structure is used to build a temporary list of spacings from
 * spacing lines in the mzrouter section of the technology file.  Spacings are
 * copied to RouteTypes after technology readin completes.
 */
typedef struct techspacing
{
    RouteType *ts_routeType;
    TileType ts_tileType;
    int ts_spacing;
    struct techspacing *ts_next;
} TechSpacing;
TechSpacing *mzTechSpacingList = NULL;  /* Temporary list of explicit spacings.
					 * Generated by spacing lines in 
					 * mzrouter
					 * section.  Used in mzTechFinal to
					 * set spacings ispacings n RouteTypes
					 * after technology readin completes.
					 */

/* mask of all routetypes - referenced in this file only */
TileTypeBitMask mzRTypesMask;      /* And of bitmaps for tileTypes of
				    * all routeTypes of all styles
				    * (note image types for
				    * contacts included).
				    */

/* Forward declarations */
extern void mzTechStyle();
extern void mzStyleEnd();
extern void mzSetParmDefaults();
extern void mzTechLayer();
extern void mzTechNotActive();
extern void mzTechSpacing();
extern void mzTechSearch();
extern void mzTechWidth();
extern void mzTechContact();
extern void mzInitRouteType();
extern void mzUpdateSpacing();

void mzWidthRule(int, char **);
void mzSpacingRule(int, char **);
void mzEdgeRule(int, char **);

/*
 * ----------------------------------------------------------------------------
 *
 * MZFreeParameters ---
 *
 * Deallocate memory for a maze router style parameters structure.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Memory free'd.
 *
 * ----------------------------------------------------------------------------
 */

void
MZFreeParameters(params)
    MazeParameters *params;
{
    RouteLayer *rL;
    RouteContact *rC;

    for (rL = params->mp_rLayers; rL; rL = rL->rl_next)
    {
	ListDealloc(rL->rl_contactL);
	TiFreePlane(rL->rl_routeType.rt_hBlock);
	TiFreePlane(rL->rl_routeType.rt_vBlock);
	freeMagic(rL);
    }

    for (rC = params->mp_rContacts; rC; rC = rC->rc_next)
	freeMagic(rC);
}


/*
 * ----------------------------------------------------------------------------
 *
 * MZTechInit --
 *
 * Initialize the technology datastructures for the maze router.
 * This routine is made a client of the tech module in main/main.c.
 * It is called when the beginning of the "mzrouter" section is encountered.
 *
 * Results:
 *	None.
 *
 * ----------------------------------------------------------------------------
 */

void
MZTechInit()
{
    MazeStyle *style;

    /* Clear out any old information */
    if (mzStyles != NULL)
    {
	for (style = mzStyles; style != NULL; style = style->ms_next)
	{
	    MZFreeParameters(&(style->ms_parms));
	    freeMagic(style->ms_name);
	    freeMagic(style);
	}
    }

    /* Initially no route types defined */
    mzRTypesMask = DBZeroTypeBits;
  
    /* Initially no maze styles are defined */
    mzStyles = NULL;

    return;
}


/*
 * ----------------------------------------------------------------------------
 *
 * MZTechFinal --
 *
 * Close out final style.
 * This routine is made a client of the tech module in main/main.c.
 * It is called when the end of the "mzrouter" section is encountered.
 *
 * Results:
 *	None.
 *
 * ----------------------------------------------------------------------------
 */

void
MZTechFinal()
{
    if(mzStyles)
    {
	mzStyleEnd();
    }

    return;
}


/*
 * ----------------------------------------------------------------------------
 *
 * MZAfterTech --
 *
 * Finish up tech datastructures.
 * This routine called by MZInit after tech file readin, or after grid
 * rescaling, when the DRC rules are re-evaluated at the new scale.  It
 * derives all of the maze router width and spacing rules from the DRC
 * rule set.
 *
 * Results:
 *	None.
 *
 * ----------------------------------------------------------------------------
 */

void
MZAfterTech()
{
    MazeStyle *style;
    RouteType *rT;
    int i, maxSpacing;

    /* Fill all width and spacing rules from DRC tables */

    for(style=mzStyles; style!=NULL; style=style->ms_next)
    {
	for(rT=style->ms_parms.mp_rTypes; rT!=NULL; rT=rT->rt_next)
	{
	    rT->rt_width = DRCGetDefaultLayerWidth(rT->rt_tileType);
	    for (i = 0; i < TT_MAXTYPES; i++)
		rT->rt_spacing[i] = DRCGetDefaultLayerSpacing(rT->rt_tileType, i);

	    /* We assume square contacts and no area minimums unless	*/
	    /* specifically set by a wizard command (for now, at least)	*/
	    rT->rt_length = rT->rt_width;
	}
    }

    /* Adjust spacings for all styles */

    for(style=mzStyles; style!=NULL; style=style->ms_next)
    {
	List *l;

	/* add (non SUBCELL) spacings in spacingL to spacing 
	 * arrays in RouteTypes */
	for(l=style->ms_spacingL; l!=NULL; l=LIST_TAIL(l))
	{
	    TechSpacing *tS = (TechSpacing *) LIST_FIRST(l);

	    if(tS->ts_tileType != TT_SUBCELL)
	    {
		tS->ts_routeType->rt_spacing[tS->ts_tileType] = tS->ts_spacing;
	    }
	}

	/* Compute spacing to unexpanded subcells for each routeType
	 * = maximum of all spacings for that route type
	 */
	for(rT=style->ms_parms.mp_rTypes; rT!=NULL; rT=rT->rt_next)
	{
	    maxSpacing = 0;
	    for(i=0;i<TT_MAXTYPES;i++)
	    maxSpacing = MAX(maxSpacing,rT->rt_spacing[i]);
	    rT->rt_spacing[TT_SUBCELL] = maxSpacing;
	}

	/* add SUBCELL spacings in spacingL to spacing 
	 * arrays in RouteTypes */
	for(l=style->ms_spacingL; l!=NULL; l=LIST_TAIL(l))
	{
	    TechSpacing *tS = (TechSpacing *) LIST_FIRST(l);

	    if(tS->ts_tileType == TT_SUBCELL)
	    {
		tS->ts_routeType->rt_spacing[tS->ts_tileType] = tS->ts_spacing;
	    }
	}

	/* free up spacing list */
	ListDeallocC(style->ms_spacingL);
	style->ms_spacingL = NULL;
    }
}


/*
 * ----------------------------------------------------------------------------
 *
 * MZTechLine --
 *
 * This routine is made a client of the tech module in main/main.c.
 * It is invoked during technology file readin, once for each line
 * in the mzrouter section of the technology file.
 *
 * On each invocation one line of the "mzrouter" section is processed.
 *
 * Results:
 *	TRUE always.
 *
 * Side effects:
 *	An element  is built and added to the RouteLayers or RouteContacts
 *      list.  Or in the case of spacing request, the spacing is added to
 *      the deferred spacing list for processing in mzTechFinal after
 *      technology readin is completed.
 *
 * Note: 
 *    The mzrouter section of the technology file must preceed the drc
 *    section.  Thus the route layers and contacts are known prior
 *    to design rule processsing.
 * 
 * ----------------------------------------------------------------------------
 */

bool
MZTechLine(sectionName, argc, argv)
    char *sectionName;	/* Unused */
    int argc;
    char *argv[];
{
    if(strcmp(argv[0], "style") == 0)
    {
        mzTechStyle(argc, argv);
    }
    else if(mzStyles == NULL)
    {
	TechError("Missing style line.\n");
    }
    else if (strcmp(argv[0], "layer") == 0)
    {
	mzTechLayer(argc, argv);
    }
    else if (strcmp(argv[0], "contact") == 0)
    {
	mzTechContact(argc, argv);
    }
    else if (strcmp(argv[0], "notactive") == 0)
    {
	mzTechNotActive(argc, argv);
    }
    else if (strcmp(argv[0], "spacing") == 0)
    {
        mzTechSpacing(argc, argv);
    }
    else if (strcmp(argv[0], "search") == 0)
    {
        mzTechSearch(argc, argv);
    }
    else if (strcmp(argv[0], "width") == 0)
    {
        mzTechWidth(argc, argv);
    }
    else
    {
        TechError("Unrecognized keyword: \"%s\"\n", argv[0]);
    }

    return (TRUE);
}


/*
 * ----------------------------------------------------------------------------
 *
 * mzTechStyle --
 *
 * Process a "style" line from the "mzrouter" section of the tech file.
 * Each set of lines in the "mzrouter" section of the tech file is headed
 * by a style line that gives a name to the set of parameters.
 * Style lines have the form:
 *
 *	style <name>
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Complete previous style and initial this one.
 *
 * ----------------------------------------------------------------------------
 */

void
mzTechStyle(argc, argv)
    int argc;
    char *argv[];
{

    /* if there is a previous style, complete processing on it */
    if(mzStyles)
    {
	mzStyleEnd();
    }

    /* alloc new style */
    {
	MazeStyle *new;
	new = (MazeStyle*) mallocMagic((unsigned)(sizeof (MazeStyle)));
	
	new->ms_name = StrDup(NULL, argv[1]);
	new->ms_spacingL = NULL;
	new->ms_next = mzStyles;
	mzStyles = new;
    }

    /* set default parameters */
    mzSetParmDefaults(&(mzStyles->ms_parms));

    /* reset temporary lists */
    mzRouteLayers = NULL;
    mzRouteContacts = NULL;
    mzRouteTypes = NULL;

    return;
} 


/*
 * ----------------------------------------------------------------------------
 *
 * mzStyleEnd --
 *
 * Close out style.  (Saves temporary lists in parms for style.) 
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	See above.
 *
 * ----------------------------------------------------------------------------
 */

void
mzStyleEnd()
{
    /* Reverse mzRouteLayer, mzRouteContacts and mzRouteTypes lists
     * so they are displayed in order they appear in tech file.
     */
    {
	RouteLayer *newRLList;
	RouteContact *newRCList;
	RouteType *newRTList;

	newRLList = NULL;
	while(mzRouteLayers!=NULL)
	{
	    RouteLayer *rL = mzRouteLayers;
	    mzRouteLayers = rL->rl_next;
	    rL->rl_next = newRLList;
	    newRLList = rL;
	}
	mzRouteLayers = newRLList;

	newRCList = NULL;
	while(mzRouteContacts!=NULL)
	{
	    RouteContact *rC = mzRouteContacts;
	    mzRouteContacts = rC->rc_next;
	    rC->rc_next = newRCList;
	    newRCList = rC;
	}
	mzRouteContacts = newRCList;

	newRTList = NULL;
	while(mzRouteTypes!=NULL)
	{
	    RouteType *rT = mzRouteTypes;
	    mzRouteTypes = rT->rt_next;
	    rT->rt_next = newRTList;
	    newRTList = rT;
	}
	mzRouteTypes = newRTList;
    }

    /* Copy lists to parm structure for this style */
    mzStyles->ms_parms.mp_rLayers = mzRouteLayers;
    mzStyles->ms_parms.mp_rContacts = mzRouteContacts;
    mzStyles->ms_parms.mp_rTypes = mzRouteTypes;

    return;
}


/*
 * ----------------------------------------------------------------------------
 *
 * mzSetParmDefaults --
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Sets default parameter values.
 *	
 * ----------------------------------------------------------------------------
 */
void
mzSetParmDefaults(parms)
    MazeParameters *parms;
{

    /* initialize penalty factor for excess cost togo */
    parms->mp_penalty.rf_mantissa = DEF_PENALTY_MANTISSA;
    parms->mp_penalty.rf_nExponent = DEF_PENALTY_NEXPONENT;

    /* Initialize other Search Control Parameters */
    parms->mp_wRate = (dlong) DEF_WINDOW_RATE;
    parms->mp_wWidth = (dlong) DEF_WINDOW_WIDTH;
    parms->mp_bloomDeltaCost = (dlong) DEF_BLOOM_DELTA_COST;

    /* initialize blockage generation increment */
    parms->mp_boundsIncrement = DEF_BOUNDS_INCREMENT;

    /* Estimation flags (if set nontrivial estimation used) */
    parms->mp_estimate = DEF_ESTIMATE;

    /* endpoint expansion flag, if set start and dest areas are
     * expanded to include all electrically connected areas.
     */
    parms->mp_expandEndpoints = DEF_EXPAND_ENDPOINTS;

    /* If set, only hints in toplevel cell are recognized */
    parms->mp_topHintsOnly = DEF_TOP_HINTS_ONLY;
    
    /* Maximum penetration into node (or subcell) blockage to reach
     * destination.
     */
    parms->mp_maxWalkLength = DEF_MAX_WALK_LENGTH;

    /* If nonnull, limits search area for performance 
     * NOTE:   IF NONNULL, IT IS THE USERS RESPONSIBILITY TO CONFINE THE 
     *         ROUTE TO WITHIN THIS AREA BY FENCES.
     */
    parms->mp_boundsHint = NULL;

    /* Amount of messages printed */
    parms->mp_verbosity = DEF_VERBOSITY;

    /* If positive, limit on number of blooms during search */
    parms->mp_bloomLimit = DEF_BLOOM_LIMIT;

    return;
}


/*
 * ----------------------------------------------------------------------------
 *
 * mzTechLayer --
 *
 * Process a "layer" line from the "mzrouter" section of the tech file.
 * A layer line defines a route layer.  It has the following form:
 *
 *	layer layername hcost vcost jogcost hintcost overcost
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Builds and adds an element to the RouteLayers list.
 *	RouteType also added to RouteTypes list.
 *
 * ----------------------------------------------------------------------------
 */

void
mzTechLayer(argc, argv)
    int argc;
    char *argv[];
{
    RouteLayer *new;
    TileType tileType;

    /* Check the argument count */
    if (argc < 4 || argc > 7)
    {
	TechError("Malformed \"layer\" line, should be:  \"layer name hCost vCost [jogCost [hintCost [overCost]]]\"\n");
	return;
    }

    /* get the tiletype */
    tileType = DBTechNoisyNameType(argv[1]);
    if (tileType < 0) return;

    /* make sure we don't already have a routeLayer on same plane */
    {
	RouteLayer *rL;

	for(rL=mzRouteLayers; rL!=NULL; rL=rL->rl_next)
	{
	    if(DBTypePlaneTbl[rL->rl_routeType.rt_tileType] ==
	       DBTypePlaneTbl[tileType])
	    {
		TechError("Attempt to define two route layers on same plane:  %s and %s\n", 
			  DBTypeLongNameTbl[tileType], 
			  DBTypeLongNameTbl[rL->rl_routeType.rt_tileType]);
		return;
	    }
	}
    }

    /* Allocate  new route layer */
    new = (RouteLayer *) callocMagic((unsigned) (sizeof (RouteLayer)));

    /* Initialize RouteType section */
    mzInitRouteType(&(new->rl_routeType),tileType);

    /* Initialize list of contacts connecting this layer to NULL */
    new->rl_contactL = NULL;

    /* set the plane */
    new->rl_planeNum = DBPlane(new->rl_routeType.rt_tileType);
    if (new->rl_planeNum < 0)
    {
	TechError("Type \"%s\" appears on more than one plane\n", argv[1]);
	return;
    }

    /* set hCost */
    if (!StrIsInt(argv[2]))
    {
	TechError("Cost arguments to \"layer\" line must be numeric\n");
	return;
    }
    new->rl_hCost = atoi(argv[2]);
    if (new->rl_hCost <= 0)
    {
	TechError("hCost must be > 0\n");
	return;
    }

    /* set vCost */
    if (!StrIsInt(argv[3]))
    {
	TechError("Cost arguments to \"layer\" line must be numeric\n");
	return;
    }
    new->rl_vCost = atoi(argv[3]);
    if (new->rl_vCost <= 0)
    {
	TechError("vCost must be > 0\n");
	return;
    }

    /* Other costs are optional, and default to 1 */
    new->rl_jogCost = 1;
    new->rl_hintCost = 1;
    new->rl_overCost = 1;

    /* set jogCost */
    if (argc > 4)
    {
	if (!StrIsInt(argv[4]))
	{
	    TechError("Cost arguments to \"layer\" line must be numeric\n");
	    return;
	}
	new->rl_jogCost = atoi(argv[4]);
	if (new->rl_jogCost <= 0)
	{
	    TechError("jogCost must be > 0\n");
	    return;
	}
    }

    /* set hintCost */
    if (argc > 5)
    {
	if (!StrIsInt(argv[5]))
	{
	    TechError("Cost arguments to \"layer\" line must be numeric\n");
	    return;
	}
	new->rl_hintCost = atoi(argv[5]);
	if (new->rl_hintCost <= 0)
	{
	    TechError("hintCost must be > 0\n");
	    return;
	}
    }

    /* set overCost */
    if (argc > 6)
    {
	if (!StrIsInt(argv[6]))
	{
	    TechError("Cost arguments to \"layer\" line must be numeric\n");
	    return;
	}
	new->rl_overCost = atoi(argv[6]);
	if (new->rl_overCost <= 0)
	{
	    TechError("overCost must be > 0\n");
	    return;
	}
    }

    /* Add new route layer to list */
    new->rl_next = mzRouteLayers;
    mzRouteLayers = new;

    return;
}


/*
 * ----------------------------------------------------------------------------
 *
 * mzTechNotActive --
 *
 * Process a "notactive" line from the "mzrouter" section of the tech file.
 * A notactive line specifies routetype(s) that are to be initially unavail.
 * to the router.
 *
 *	spacing routeType1 ... [routeTypen]
 *
 * Valid spacings are nonnegative integers, or "nil: if no spacing applies.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Build and add an element to spacing list
 *
 * ----------------------------------------------------------------------------
 */

void
mzTechNotActive(argc, argv)
    int argc;
    char *argv[];
{
    int argI;
    TileType tileType;
    RouteType *rT;

    /* check number of arguments */
    if(argc < 2)
    {
	TechError("Bad form on mzroute notactive.\n");
	TechError("Usage: notactive routeType1 ... [routeTypen]\n");
    return;
    }

    /* process args */
    for(argI = 1; argI<argc; argI += 1)
    {
	/* convert arg to routeType */
	{
	    tileType = DBTechNoisyNameType(argv[argI]);
	    if(tileType < 0) continue;
	    rT = mzFindRouteType(tileType);
	    if(rT==NULL)
	    {
		TechError("Unrecognized route type: \"%.20s\"\n",
			  argv[argI]);
		continue;
	    }
	}

	/* set to not active */
	rT->rt_active = FALSE;
    }

    return;
}


/*
 * ----------------------------------------------------------------------------
 *
 * mzTechSpacing --
 *
 * Process a "spacing" line from the "mzrouter" section of the tech file.
 * A spacing line defines spacings from a routetype (layer or contact) to
 * other type(s).  These spacings are stored on a list on technology readin
 * and then actually set in the routeType structure after technology readin
 * is complete.  This is so they will overide default values based on the
 * DRC section.
 *
 *	spacing routeType type1 spacing1 ... [typen] [spacingn]
 *
 * Valid spacings are nonnegative integers, or "nil: if no spacing applies.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Build and add an element to spacing list
 *
 * ----------------------------------------------------------------------------
 */

void
mzTechSpacing(argc, argv)
    int argc;
    char *argv[];
{
    TechSpacing *new;
    TileType tileType;
    RouteType *rT;
    int argI, value, which;
    char *s;

    /* Subcell Table */
    static struct
    {
	char	*sT_name;	/* name of value */
	int     sT_value;	/* corresponding interger value */
    } subcellTable[] = {
	"subcell",		TT_SUBCELL,
	0
    };

    /* check number of arguments */
    if(argc <4 || ODD(argc))
    {
	TechError("Bad form on mzroute spacing.\n");
	TechError("Usage: spacing routeType type1 spacing1 ... [typen spacingn]\n"); 
    return;
    }

    /* convert first arg to routeType */
    tileType = DBTechNoisyNameType(argv[1]);
    if(tileType < 0) return;
    rT = mzFindRouteType(tileType);
    if(rT==NULL)
    {
	TechError("Unrecognized route type: \"%.20s\"\n",
	    argv[1]);
	return;
    }

    for(argI = 2; argI<argc; argI += 2)
    {
	/* convert argI to type */
	tileType = DBTechNameType(argv[argI]);
	if(tileType<0) 
	{
	    /* if not a real type, check to see if "SUBCELL" */
	    which = LookupStruct(
		argv[argI],
		(LookupTable *) subcellTable,
		sizeof subcellTable[0]);
	    if ( which>= 0)
	        tileType = TT_SUBCELL;
	}
	if(tileType<0) 
	{
	    TechError("Unrecognized layer (type): \"%.20s\"\n", 
		argv[argI]);
	    continue;
	}

	/* convert argI+1 to  value */
	s = argv[argI+1];
	value = -2;
	if (StrIsInt(s)) 
	{
	    value = atoi(s);
	    if (value < 0)
	    {
		TechError("Bad spacing value: %d\n",value);
		TechError("Valid values are nonnegative integers and \"NIL\".\n");
		return;
	    }
	}
	else if (strcmp(s,"NIL")==0)
	{
	    value = -1;
	}
	else
	{
	    TechError("Bad spacing value: %s\n",s);
	    TechError("Valid values are nonnegative integers and \"NIL\".\n");
	    return;
	}

	/* add entry to spacing list */
	new = (TechSpacing*) mallocMagic((unsigned)(sizeof (TechSpacing)));
	new->ts_routeType = rT;
	new->ts_tileType = tileType;
	new->ts_spacing = value;
	LIST_ADD(new, mzStyles->ms_spacingL);
    }

    return;
}


/*
 * ----------------------------------------------------------------------------
 *
 * mzTechSearch --
 *
 * Process a "search" line from the "mzrouter" section of the tech file.
 * A search line sets several parameters controling the search.
 * It has the form: 
 *
 *	search <rate> <width> <penalty>
 *
 * Rate and width must be positive integers, penalty a non-negative decimal.
 * Search lines are optional, if none is given for a style default values
 * are assigned.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Set rate width and penalty parms for this style.
 *
 * ----------------------------------------------------------------------------
 */

void
mzTechSearch(argc, argv)
    int argc;
    char *argv[];
{
    /* check number of arguments */
    if(argc != 4)
    {
	TechError("Bad form on search.\n");
	TechError("Usage: search <rate> <width> <penalty>\n");
	return;
    }

    /* set WINDOW RATE */
    if (!StrIsInt(argv[1])) 
    {
	TechError("Bad rate: %s\n",argv[1]);
	TechError("Rate must be a positive integer.\n");
    }
    else
    {
	int value = atoi(argv[1]);
	if (value <= 0)
	{
	    TechError("Bad rate: %d\n",value);
	    TechError("Rate must be a positive integer.\n");
	}
	else
	{
	    mzStyles->ms_parms.mp_wRate = (dlong) value;
	}
    }

    /* set WINDOW WIDTH */
    if (!StrIsInt(argv[2])) 
    {
	TechError("Bad width: %s\n",argv[2]);
	TechError("Width must be a positive integer.\n");
    }
    else
    {
	int value = atoi(argv[2]);
	if (value <= 0)
	{
	    TechError("Bad width: %d\n",value);
	    TechError("Width must be a positive integer.\n");
	}
	else
	{
	    mzStyles->ms_parms.mp_wWidth = (dlong) value;
	}
    }

    /* set PENALTY */
    {
	float value;

	if(sscanf(argv[3],"%f",&value)!=1)
	{
	    TxError("Bad penalty value: %s\n",argv[3]);
	    TxError("Penalty must be non-negative decimal.\n");
	}
	else
	{
	    if(value<0)
	    {
		TxError("Bad penalty value: %f\n", value);
		TxError("Penalty must be non-negative decimal.\n");
	    }
	    else
	    {
		mzStyles->ms_parms.mp_penalty.rf_mantissa 
		= (int) (value *
			 (1<<mzStyles->ms_parms.mp_penalty.rf_nExponent));
	    }
	}
    }

    return;
}


/*
 * ----------------------------------------------------------------------------
 *
 * mzTechWidth --
 *
 * Process  "width" line from the "mzrouter" section of the tech file.
 * A width line defines a routing width for a given route type.  It
 * has the form.
 *
 *	width <routeType> <width>
 *
 * Valid widths are positive integers.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Set width for given routetype in current style.
 *
 * ----------------------------------------------------------------------------
 */

void
mzTechWidth(argc, argv)
    int argc;
    char *argv[];
{
    TileType tileType;
    RouteType *rT;
    int value;

    /* check number of arguments */
    if (argc !=3 && argc != 4)
    {
	TechError("Bad form on mzroute width.\n");
	TechError("Usage: width <routeType> <width> [<length>]\n");
	return;
    }

    /* convert first arg to routeType */
    tileType = DBTechNoisyNameType(argv[1]);
    if(tileType < 0) return;
    rT = mzFindRouteType(tileType);
    if(rT==NULL)
    {
	TechError("Unrecognized route type: \"%.20s\"\n",
	    argv[1]);
	return;
    }
    
    /* convert 2nd arg to int */
    {
	if (!StrIsInt(argv[2])) 
	{
	    TechError("Bad width: %s\n",argv[2]);
	    TechError("Width must be a positive integer.\n");
	    return;
	}

	value = atoi(argv[2]);
	if (value <= 0)
	{
	    TechError("Bad width: %d\n",value);
	    TechError("Width must be a positive integer.\n");
	    return;
	}
    }

    /* set width */
    rT->rt_width = value;

    /* convert 3rd arg, if any, to int */
    if (argc == 4) 
    {
	if (!StrIsInt(argv[3])) 
	{
	    TechError("Bad minimum length: %s\n",argv[3]);
	    TechError("Length must be a positive integer.\n");
	    return;
	}

	value = atoi(argv[3]);
	if (value <= 0)
	{
	    TechError("Bad minimum length: %d\n",value);
	    TechError("Length must be a positive integer.\n");
	    return;
	}
	rT->rt_length = value;
    }
    else
    {
	/* By default, set minimum length requirement to width */
	rT->rt_length = rT->rt_width;
    }

    return;
}


/*
 * ----------------------------------------------------------------------------
 *
 * mzTechContact --
 *
 * Process a "contact" line from the "mzrouter" section of the tech file.
 * A contact line defines a contact between route layers.  It has the form:
 *
 *	contact conlayer routelayer1 routelayer2 cost
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Build and add an element to RouteContacts list.
 *
 * ----------------------------------------------------------------------------
 */

void
mzTechContact(argc, argv)
    int argc;
    char *argv[];
{
    RouteContact *new;
    TileType type, tileType;

    /* check arg count */
    if (argc !=  5)
    {
	TechError("Malformed \"contact\" line, should be:  contact layer "
		"layer1 layer2 cost\n");
	return;
    }

    /* get tiletype */
    tileType = DBTechNoisyNameType(argv[1]);
    if(tileType < 0) return;

    /* allocate new route contact */
    new = (RouteContact *) callocMagic((unsigned) (sizeof (RouteContact)));

    /* initialize RouteType section:
     * sets route type, initializes spacing array, etc.
     */
    mzInitRouteType(&(new->rc_routeType),tileType);

    /* set first route layer */
    type = DBTechNoisyNameType(argv[2]);
    if(type<0) return;
    new->rc_rLayer1 = mzFindRouteLayer(type);
    if (new->rc_rLayer1==NULL)
    {
	TechError("route layer must be declared before used in contact.\n");
	return; 
    }

    /* add this contact to contacts list of first route layer */
    LIST_ADD(new, new->rc_rLayer1->rl_contactL);

    /* set second route layer */
    type = DBTechNoisyNameType(argv[3]);
    if(type<0) return;
    new->rc_rLayer2 = mzFindRouteLayer(type);
    if (new->rc_rLayer2==NULL)
    {
	TechError("route layer must be declared before used in contact.\n");
	return;
    }

    /* add this contact to contacts list of second route layer */
    LIST_ADD(new, new->rc_rLayer2->rl_contactL);

    /* set cost */
    if (!StrIsInt(argv[4]))
    {
	TechError("Cost argument to \"contact\" line must be numeric\n");
	return;
    }
    new->rc_cost = atoi(argv[4]);
    if (new->rc_cost <= 0)
    {
	TechError("Cost must be > 0\n");
	return;
    }

    /* add route contact to list */
    new->rc_next = mzRouteContacts;
    mzRouteContacts = new;

    return;
}


/*
 * ----------------------------------------------------------------------------
 *
 * mzInitRouteType --
 *
 * Initialize RouteType struc.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Element added to mzRouteTypes list.
 *	Types ORed into mzRTypesMask.
 *
 * ----------------------------------------------------------------------------
 */

void
mzInitRouteType(rT,tileType)
    RouteType *rT;
    TileType tileType;
{
    int t;

    /* Get mask of all image types of routeType.
     * RouteLayers will have one bit set in mask.  RouteContacts will have 
     * two bits set, one for the contact "home" type, and one for the contact
     * image type on the plane it connects to.
     */
    TileTypeBitMask *imageTypeMask = &(DBLayerTypeMaskTbl[tileType]);

    /* set tileType */
    rT->rt_tileType = tileType;

    /* initialize as active */
    rT->rt_active = TRUE;
    
    /* initialize spacing array (gives spacing between 
     * RouteType and all tiletypes) 
     */
    for (t=0;t<TT_MAXTYPES;t++)
    {
	/* If type "t" is on home plane of RouteType or 
	 * plane of image of RouteContact */
      if( DBTypePlaneTbl[t] >= 0 ) {
	if(TTMaskIntersect(&(DBPlaneTypes[DBTypePlaneTbl[t]]),imageTypeMask)
	    && t!=TT_SPACE)
	{
	    /* initialize to zero spacing - i.e. no overlap allowed */
	    rT->rt_spacing[t] = 0;
	}
	else
	{
	    /* otherwise no default spacing restriction applys */
	    rT->rt_spacing[t] = -1;
	}
      }
    }

    /* Initialize Blockage Planes */
    rT->rt_hBlock = DBNewPlane((ClientData) TT_SPACE);
    rT->rt_vBlock = DBNewPlane((ClientData) TT_SPACE);

    /* Add to RouteType list */
    rT->rt_next = mzRouteTypes;
    mzRouteTypes = rT;

    /* OR type and images into global route types mask */
    TTMaskSetMask(&mzRTypesMask,imageTypeMask);

    return;
}


/*
 * ----------------------------------------------------------------------------
 *
 * mzFindRouteType --
 *
 * Search RouteLayer and RouteContact lists for routeType of given
 * tile type.
 *
 * Results:
 *	pointer to routetype struc if found, else Null.
 *
 * ----------------------------------------------------------------------------
 */

RouteType *
mzFindRouteType(type)
    TileType type;
{
    RouteType *rT;

    /* Search list of routetypes for one with appropriate type */
    for (rT = mzRouteTypes; 
	rT && rT->rt_tileType!=type; 
	rT=rT->rt_next)
	;

    /* return result */
    return(rT);
}


/*
 * ----------------------------------------------------------------------------
 *
 * mzFindRouteLayer --
 *
 * Find routelayer struc for given tiletype.
 *
 * Results:
 *	pointer to routelayer struc if found, else Null.
 *
 * ----------------------------------------------------------------------------
 */

RouteLayer *
mzFindRouteLayer(type)
    TileType type;
{
    RouteLayer *rL;

    /* Search list of routelayers for one with appropriate type */
    for (rL = mzRouteLayers; 
	rL && rL->rl_routeType.rt_tileType!=type; 
	rL=rL->rl_next)
	;

    /* return result */
    return(rL);
}


/*
 * ----------------------------------------------------------------------------
 *
 * mzFindRouteContact --
 *
 * Find routecontact struc for given tiletype.
 *
 * Results:
 *	pointer to routecontact struc if found, else Null.
 *
 * ----------------------------------------------------------------------------
 */

RouteContact *
mzFindRouteContact(type)
    TileType type;
{
    RouteContact *rC;

    /* Search list of routecontacts for one with appropriate type */
    for (rC = mzRouteContacts; 
	rC && rC->rc_routeType.rt_tileType!=type; 
	rC=rC->rc_next)
	;

    /* return result */
    return(rC);
}


/*
 * ----------------------------------------------------------------------------
 *
 * mzUpdateSpacing --
 *
 * Add spacing requirement to RouteType.
 * (RouteTypes are routing layers and contact layers used by the router.)
 *
 * Results:
 *	None.
 *
 * SideEffects:
 *    RouteType struc modifed.
 *
 * ----------------------------------------------------------------------------
 */

void
mzUpdateSpacing(rType,tType,distance)
    RouteType *rType;	/* Route Type to which spacing applies */
    TileType tType;		/* spacing from this tiletype */
    int distance;		/* min spacing betweeen rType and tType */
{
    rType->rt_spacing[tType] = 
	MAX(rType->rt_spacing[tType],distance);

#ifdef debugmha 
    TxPrintf("UPDATESPACING:\n");
    TxPrintf("\troute type = %s\n",DBTypeLongNameTbl[rType->rt_tileType]);
    TxPrintf("\tother type = %s\n",DBTypeLongNameTbl[tType]);
    TxPrintf("\tdistance = %d\n",distance);
#endif /* debugmha */

    return;
}

