/*
 * DBtcontact.c --
 *
 * Management of contacts.
 * This file makes a distinction between the following two terms:
 *
 *  Layer	-- Logical type as specified in "types" section of .tech
 *		   file.  A layer may consist of many TileTypes, as is the
 *		   case when it is a contact.
 *  Type	-- TileType stored in a tile
 *
 *     *********************************************************************
 *     * 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/database/DBtcontact.c,v 1.3 2008/09/05 13:56:25 tim Exp $";
#endif  /* not lint */

#include <stdio.h>
#include <string.h>
#include <ctype.h>

#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/utils.h"
#include "utils/malloc.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "utils/tech.h"
#include "textio/textio.h"

/* type-to-bitmask conversion (1 bit per entry) */
TileTypeBitMask DBLayerTypeMaskTbl[NT];

/* Filled in after contact types have been generated */
TileTypeBitMask DBPlaneTypes[PL_MAXTYPES];
TileTypeBitMask DBHomePlaneTypes[PL_MAXTYPES];
PlaneMask        DBTypePlaneMaskTbl[NT];

/* --------------------- Data local to this file ---------------------- */

/* Table of the properties of all layers */
LayerInfo dbLayerInfo[NT];

/* Array of pointers to the entries in above table for contacts only */
LayerInfo *dbContactInfo[NT];
int dbNumContacts;

/* Forward declaration */
void dbTechMatchResidues(TileTypeBitMask *inMask, TileTypeBitMask *outMask, bool contactsOnly);
void dbTechAddStackedContacts();
int dbTechAddOneStackedContact();


/*
 * ----------------------------------------------------------------------------
 *
 * DBTechInitContact --
 *
 * Mark all types as being non-contacts initially.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Initializes dbLayerInfo.
 *
 * ----------------------------------------------------------------------------
 */

void
DBTechInitContact()
{
    TileType t;
    LayerInfo *lp;

    for (t = 0; t < TT_MAXTYPES; t++)
    {
	lp = &dbLayerInfo[t];
	lp->l_type = t;
	lp->l_isContact = FALSE;
	lp->l_pmask = 0;
	TTMaskZero(&lp->l_residues);
	TTMaskSetOnlyType(&DBLayerTypeMaskTbl[t], t);
    }

    dbNumContacts = 0;
}

/*
 * ----------------------------------------------------------------------------
 *
 * DBTechAddContact --
 *
 * Add the definition of a new contact type.
 * The syntax of each line in the "contact" section is:
 *
 *	contactType res1 res2 [res3...]
 *
 * where res1, res2, res3, etc. are the residue types on the planes
 * connected by the contact.  The home plane of the contact (the
 * plane specified in the "types" section for the type contactType)
 * must be the lowest-numbered plane in the list of residues.  Each
 * listed residue must be on a different plane. There are no other
 * restrictions on contacts.
 *
 * Magic-7.3 additional syntax:
 *
 *	stackable type1 [type2 [alias12] [type3 [alias13] ...]]
 *
 * where type1 and type2 are contact types, allows type1 and type2
 * to be drawn on top of one other by generating an extra contact
 * type to represent the union of type1 and type2 on the shared
 * plane.  If more than two types are specified, then type1 will be
 * set to be stackable with each of the indicated types.  If only
 * type1 is specified, then type1 will be made stackable with all
 * other (existing) contact types.  Wherever a layer name exists
 * after a known type that is not a known layer name, it is
 * considered to be an alias name for the stacked type.  e.g.,
 * "stackable pc via pm12contact" is valid if "pc" and "via" are
 * defined types.  Thie provides compatibility with layout files
 * created with technology files that explicitly define stacked
 * contact types, especially those from magic-7.2 and earlier
 * versions.
 *
 *	stackable
 *
 * allows all contact types to stack, where applicable.  This
 * statement overrides any other "stackable" statement.
 *
 * Notes:
 *	All indicated types must have been declared in the "contact"
 *	section prior to use of the "stackable" keyword.  The 1- and
 *	2-argument variants will create stacking types with all
 *	previously-declared contact types.
 *
 * Expanded syntax:
 *	Now allows the section "image" with statements "contact" and
 *	"device".  Statements beginning with the layer name are
 *	backwardly-compatible with the original syntax.  "contact"
 *	statements are equivalent to the original syntax after skipping
 *	the keyword "contact".  "device" statements have the same
 *	syntax as the "contact" statement but describe a composite
 *	image such as a transistor or capacitor formed by layers on
 *	different planes.
 *
 * Results:
 *	FALSE on error, TRUE if successful.
 *
 * Side effects:
 *	Adds the definition of a new contact type.
 *
 * ----------------------------------------------------------------------------
 */

bool
DBTechAddContact(
    char *sectionName,
    int argc,
    char *argv[])
{
    TileType contactType;
    int nresidues;

    if ((contactType = DBTechNameType(*argv)) < 0)
    {
	if (!strcmp(*argv, "contact") || !strcmp(*argv, "device"))
	{
	    argc--;
	    argv++;
	    if ((contactType = DBTechNameType(*argv)) < 0)
	    {
		DBTechNoisyNameType(*argv);
		return FALSE;
	    }
	}
	else if (!strcmp(*argv, "stackable"))
	{
	    TileType stackType, newType = -1;
	    LayerInfo *lim, *lin;

	    if (argc == 1)
		dbTechAddStackedContacts();
	    else
	    {
		contactType = DBTechNoisyNameType(*++argv);
		if (contactType < 0)
		    return FALSE;
		else if (argc == 2)
		{
		    int n, result;

		    lim = &dbLayerInfo[contactType];

		    for (n = 0; n < dbNumContacts; n++)
		    {
			lin = dbContactInfo[n];
			if (lim == lin) continue;
		 	result = dbTechAddOneStackedContact(lim->l_type, lin->l_type);
			if (result == -3)
			    return FALSE;	/* overran tiletype maximum number */
		    }
		}
		else
		{
		    TileType lastType = TT_SPACE;
		    char *primary;

		    while (--argc > 1)
		    {
			stackType = DBTechNameType(*++argv);
			if (stackType >= 0)
			{
			    newType = dbTechAddOneStackedContact(contactType,
					stackType);
			    if (newType == -1)
				TechError("Contact types %s and %s do not stack\n",
					DBTypeLongNameTbl[contactType],
					DBTypeLongNameTbl[stackType]);
			    lastType = stackType;
			}
			else if (lastType >= TT_SPACE)
			{
			    /* (*argv) becomes an alias name for layer newType */
			    if (newType < 0)
				TechError("Contact type %s unknown or contact "
					"missing in stackable statement\n", *argv);
			    else
				DBTechAddNameToType(*argv, newType, FALSE);
			    lastType = TT_SPACE;
			}
			else
			{
			    DBTechNoisyNameType(*argv);
			    lastType = TT_SPACE;
			}
		    }
		}
	    }
	    return TRUE;
	}
	else
	{
	    DBTechNoisyNameType(*argv);
	    return FALSE;
	}
    }

    /* Read the contact residues and check them for validity */
    nresidues = dbTechContactResidues(--argc, ++argv, contactType);
    if (nresidues < 0)
	return FALSE;

    /* Remember this as a paintable contact */
    dbContactInfo[dbNumContacts++] = &dbLayerInfo[contactType];

    return TRUE;
}

/*
 * ----------------------------------------------------------------------------
 * dbTechAddStackedContacts --
 *
 *	Generate new contact types where existing contact types share a
 *	residue.  These contact types will exist only on the planes
 *	shared between the two contact types.  This method allows contacts
 *	to be stacked without requiring a declaration of every combination
 *	in the techfile.
 *
 *	When searching for contact types with shared planes, we want to
 *	make sure that no existing contact exactly matches the stacked
 *	type, in case stacked contacts are explicitly called out in the
 *	tech file (e.g., pm12contact).
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Adds to the tiletype database.
 *
 * ----------------------------------------------------------------------------
 */

void
dbTechAddStackedContacts()
{
    int m, n;
    LayerInfo *lim, *lin;
    int dbNumUserContacts = dbNumContacts;
    int result;

    for (m = 0; m < dbNumUserContacts; m++)
    {
	lim = dbContactInfo[m];
	for (n = m + 1; n < dbNumUserContacts; n++)
	{
	    lin = dbContactInfo[n];
	    result = dbTechAddOneStackedContact(lim->l_type, lin->l_type);
	    if (result == -3)
		return;		/* overran tiletype maximum number */
	}
    }

    /* Diagnostic */
    /* fprintf(stderr, "DBNumUserLayers = %d, DBNumTypes = %d\n",
		DBNumUserLayers, DBNumTypes);
    fflush(stderr); */
}

/*
 * ----------------------------------------------------------------------------
 * dbTechAddOneStackedContact --
 *
 *	Generate one new stacked contact type representing the union of
 *	types "type1" and "type2" on their shared plane(s) (normally
 *	one, but not necessarily).
 *
 * Results:
 *	tile type of new stacked contact if successful, -1 if stacking
 *	not allowed, -2 if a contact type already exists which stacks
 *	type1 and type2, or -3 on overrun of the total number of layers.
 * ----------------------------------------------------------------------------
 */

int
dbTechAddOneStackedContact(
    TileType type1,
    TileType type2)
{
    LayerInfo *lim, *lin, *lp;
    TileTypeBitMask ttshared, ttall, mmask;
    TileType stackedType, sres;

    lim = &dbLayerInfo[type1];
    lin = &dbLayerInfo[type2];

    /* Both types must be contacts */
    if (!lim->l_isContact || !lin->l_isContact) return -1;

    /* Contacts do not stack if they share more than one plane */
    /* if (lim->l_pmask == lin->l_pmask) return -1; */
    if (((lim->l_pmask & lin->l_pmask) & ((lim->l_pmask & lin->l_pmask) - 1))
		!= 0)
	return -1;

    TTMaskAndMask3(&ttshared, &lim->l_residues, &lin->l_residues);

    if (!TTMaskEqual(&ttshared, &DBZeroTypeBits))
    {
	/* Find if there exists an image with the same residue	*/
	/* mask as the combination of these two contact types.  */

	TTMaskZero(&ttall);
	TTMaskSetMask3(&ttall, &lim->l_residues, &lin->l_residues);

	dbTechMatchResidues(&ttall, &mmask, TRUE);

	if (!TTMaskEqual(&mmask, &DBZeroTypeBits))
	    return -2; /* Contact type exists, so don't create one. */

	/* Also check if there is a stacking type made of these contact */
	/* images.  If we already have one, don't re-make it.		*/

	else if (DBTechFindStacking(type1, type2) != -1)
	    return -2; /* Stacking type exists, so don't create one. */

	/* All clear to set the residue bitmask for this contact type */

	/* Diagnostic */
	/* fprintf(stderr, "Stackable %s and %s\n",
		DBTypeLongName(lim->l_type),
		DBTypeLongName(lin->l_type));
	fflush(stderr); */

	stackedType = dbTechNewStackedType(lim->l_type, lin->l_type);

	/* Error condition (usually, reached max. no. tile types) */
	if (stackedType < 0) return -3;

	/* fill in layer info */

	lp = &dbLayerInfo[stackedType];
	lp->l_isContact = TRUE;

	/* The residue of a stacked contact is the two contacts	*/
	/* which make it up.  Residues which are contact types	*/
	/* are unique to stacking types.			*/

	TTMaskZero(&lp->l_residues);
	TTMaskSetType(&lp->l_residues, lim->l_type);
	TTMaskSetType(&lp->l_residues, lin->l_type);
	lp->l_pmask = lin->l_pmask | lim->l_pmask;

	/* The home plane of the contact is the plane of the	*/
	/* first shared residue found.				*/

	for (sres = TT_TECHDEPBASE; sres < DBNumUserLayers; sres++)
	    if (TTMaskHasType(&ttshared, sres))
	    {
		DBPlane(stackedType) = DBPlane(sres);
		break;
	    }

	/* Remember this as a paintable contact */
	dbContactInfo[dbNumContacts++] = &dbLayerInfo[stackedType];

	return (int)stackedType;	/* success */
    }
    return -1;
}

/*
 * ----------------------------------------------------------------------------
 *
 * DBPlaneToResidue --
 *
 * For the given tile type and plane, return the residue of that type on the
 * plane.
 *
 * Results:
 *	A tile type.
 *
 * Side effects:
 *	None.
 *
 * ----------------------------------------------------------------------------
 */

TileType
DBPlaneToResidue(
    TileType type,
    int plane)
{
    TileType rt, rt2;
    LayerInfo *lp = &dbLayerInfo[type], *lr;

    for (rt = TT_TECHDEPBASE; rt < DBNumUserLayers; rt++)
	if (TTMaskHasType(&lp->l_residues, rt))
	{
	    if (type >= DBNumUserLayers)	/* Stacked type */
	    {
		lr = &dbLayerInfo[rt];
		for (rt2 = TT_TECHDEPBASE; rt2 < DBNumUserLayers; rt2++)
		    if (TTMaskHasType(&lr->l_residues, rt2))
			if (DBPlane(rt2) == plane)
			    return rt2;
	    }
	    else if (DBPlane(rt) == plane)	/* Normal type */
		return rt;
	}

    return TT_SPACE;	/* no residue on plane */
}

/*
 * ----------------------------------------------------------------------------
 *
 * DBMaskAddStacking ---
 *
 * A general-purpose routine to add stacked types containing types that are
 * already in the mask.
 *
 * ----------------------------------------------------------------------------
 */

void
DBMaskAddStacking(
    TileTypeBitMask *mask)
{
    TileType ttype;
    TileTypeBitMask *rMask;

    for (ttype = DBNumUserLayers; ttype < DBNumTypes; ttype++)
    {
	rMask = DBResidueMask(ttype);
	if (TTMaskIntersect(rMask, mask))
	    TTMaskSetType(mask, ttype);
    }
}


/*
 * ----------------------------------------------------------------------------
 *
 * dbTechContactResidues --
 *
 * Process an argc/argv vector of contact residue type names, creating
 * image types for each, and ensuring that:
 *	No residue is itself a contact
 *	One of the residues is on the home plane of contactType.
 *
 * Results:
 *	Returns the number of residues in the contact,
 *	or -1 in the event of an error.
 *
 * Side effects:
 *	Adds to database of layer types.
 *
 * ----------------------------------------------------------------------------
 */

int
dbTechContactResidues(
    int argc,
    char **argv,
    TileType contactType)
{
    int       homePlane, residuePlane, nresidues;
    PlaneMask pMask;
    TileType  residueType, imageType;
    bool      residueOnHome;
    LayerInfo *lp;
    TileTypeBitMask rmask, mmask;

    nresidues = 0;
    pMask = 0;
    residueOnHome = FALSE;

    TTMaskZero(&rmask);
    homePlane = DBPlane(contactType);
    for ( ; argc > 0; argc--, argv++)
    {
	if ((residueType = DBTechNoisyNameType(*argv)) < 0)
	    return -1;

	if (IsContact(residueType))
	{
	    TechError("Residue type %s is a contact itself\n",
		DBTypeLongName(residueType));
	    return -1;
	}

	/*
	 * Make sure the residue is on the same or an adjacent plane
	 * to the contact's home type.
	 */
	residuePlane = DBPlane(residueType);
	if (residuePlane < 0)
	{
	    TechError("Residue type %s doesn't have a home plane\n",
		DBTypeLongName(residueType));
	    return -1;
	}

	/* Enforce a single residue per plane */
	if (PlaneMaskHasPlane(pMask, residuePlane))
	{
	    TechError("Contact residues (%s) must be on different planes\n",
		DBTypeLongName(residueType));
	    return -1;
	}
	pMask |= PlaneNumToMaskBit(residuePlane);
	if (homePlane == residuePlane)
	    residueOnHome = TRUE;

	TTMaskSetType(&rmask, residueType);
    }

    if (!residueOnHome)
    {
	TechError("Contact type %s missing a residue on its home plane\n",
		DBTypeLongName(contactType));
	return -1;
    }

    /*
     * See if there are any other contact types with identical residues;
     * if so, disallow contactType.
     *
     * Can this restriction be lifted?  ---Tim 07/24/03
     * This restriction is partially lifted, as one can create a non-stacked
     * type such as "pad" having the same residues as one stacked type,
     * such as "m123c".  Due to the way magic handles stacked types, these
     * will not be confused.	---Tim 05/11/04
     *
     * Restriction entirely lifted 6/18/04.  Error message left as a warning
     * until it is clear that there are no unwanted side effects of having
     * two contact types with identical residues.
     */

    /* Find if there exists an image with the same residue mask */

    dbTechMatchResidues(&rmask, &mmask, TRUE);

    /* Ignore self */

    TTMaskClearType(&mmask, contactType);

    if (!TTMaskEqual(&mmask, &DBZeroTypeBits))
    {
	TxPrintf("Contact residues for %s identical to those for ",
		DBTypeLongName(contactType));

	for (imageType = TT_TECHDEPBASE; imageType < DBNumTypes; imageType++)
	    if (TTMaskHasType(&mmask, imageType))
		TxPrintf("%s ", DBTypeLongName(imageType));

	TxPrintf("\n");
    }

    /* All clear to set the residue bitmask for this contact type */

    lp = &dbLayerInfo[contactType];

    lp->l_isContact = TRUE;
    TTMaskSetMask(&lp->l_residues, &rmask);
    lp->l_pmask = pMask;

    return nresidues;
}

/*
 * ----------------------------------------------------------------------------
 *
 * dbTechMatchResidues --
 *
 * Find the types whose residues match those of the supplied inMask.
 *
 * All this masking about is rather subtle, so pay attention:  Each TYPE
 * has a RESIDUAL, which for a contact is (generally) the type which surrounds
 * each contact image on its plane (remember, there is one contact image per
 * plane contacted).  So when creating the paint/erase tables, we want to
 * knock out planes from the residual mask of a contact and see if what's
 * left is another kind of contact.  So from the original contact TYPE, we
 * make a mask of RESIDUALS, then this routine compares that to the mask
 * of residuals for all other (contact) types, then create another mask of
 * all the types which had matching residual masks, and return it.  Grok
 * that?
 *
 * Note that the stacked contact mechanism returns the stacked type where
 * residues of two types match.  This is required when composing paint
 * rules for contacts on contacts.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *      Yet another TileType bitmask pointer, outMask, is filled in with
 *	the matching types.
 *
 * ----------------------------------------------------------------------------
 */

void
dbTechMatchResidues(
    TileTypeBitMask *inMask,
    TileTypeBitMask *outMask,
    bool contactsOnly)
{
    TileType type;
    LayerInfo *li;

    TTMaskZero(outMask);
    for (type = TT_TECHDEPBASE; type < DBNumUserLayers; type++)
    {
	li = &dbLayerInfo[type];
	if (!li->l_isContact && contactsOnly)
	    continue;

	if (TTMaskEqual(inMask, &li->l_residues))
	    TTMaskSetType(outMask, type);
    }
}


/*
 * ----------------------------------------------------------------------------
 * DBTechFindStacking --
 *
 *	Find a stacking tile type which connects the two indicated types.
 * Stacking types have the l_residues field of the LayerInfo entry filled
 * with the mask of the two types which make up the stacked contact type.
 *
 * Results:
 *	The stacking tile type, if it exists, or -1 if there's no stacking
 *	type connecting type1 and type2.
 *
 * Side effects:
 *	None.
 * ----------------------------------------------------------------------------
 */

TileType
DBTechFindStacking(
    TileType type1,
    TileType type2)
{
    TileType rtype, rtype1, rtype2, stackType;
    LayerInfo *li;

    for (stackType = DBNumUserLayers; stackType < DBNumTypes; stackType++)
    {
	rtype1 = rtype2 = -1;
	li = &dbLayerInfo[stackType];
	for (rtype = TT_TECHDEPBASE; rtype < DBNumUserLayers; rtype++)
	    if (TTMaskHasType(&li->l_residues, rtype))
	    {
		rtype1 = rtype;
		break;
	    }
	for (++rtype; rtype < DBNumUserLayers; rtype++)
	    if (TTMaskHasType(&li->l_residues, rtype))
	    {
		rtype2 = rtype;
		break;
	    }

	if (((rtype1 == type1) && (rtype2 == type2)) ||
		((rtype1 == type2) && (rtype2 == type1)))
	    return stackType;

    }
    return -1;
}

/*
 * ----------------------------------------------------------------------------
 *
 * DBTechFinalContact --
 *
 * Conclude reading the "contact" section of a technology file.
 * At this point, all tile types are known so we can call dbTechInitPaint()
 * to fill in the default paint/erase tables, and dbTechInitMasks() to fill
 * in the various exported TileTypeBitMasks.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Fills in the dbLayerInfo table for non-contacts.
 *	Sets DBLayerTypeMaskTbl to its final value.
 *	Initializes DBTypePlaneMaskTbl[] and DBPlaneTypes[].
 *
 * ----------------------------------------------------------------------------
 */

void
DBTechFinalContact()
{
    TileType primaryType;
    LayerInfo *lp;
    int pNum;

    /* Fill in plane and residue info for non-contact types */

    for (primaryType = 0; primaryType < DBNumTypes; primaryType++)
    {
	lp = &dbLayerInfo[primaryType];
	pNum = DBPlane(primaryType);
	if (!lp->l_isContact && (pNum > 0))
	{
	    lp->l_pmask = PlaneNumToMaskBit(pNum);
	    TTMaskSetOnlyType(&lp->l_residues, primaryType);
	}
    }

    /*
     * Initialize the masks of planes on which each type appears.
     * It will contain all planes (except router) for space,
     * the home plane for each type up to DBNumTypes, and no
     * planes for undefined types.  Also update the mask of
     * types visible on each plane.
     */

    DBTypePlaneMaskTbl[TT_SPACE] = ~(PlaneNumToMaskBit(PL_ROUTER));
    for (primaryType = 0; primaryType < DBNumTypes; primaryType++)
    {
	pNum = DBPlane(primaryType);
	if (pNum > 0)
	{
	    DBTypePlaneMaskTbl[primaryType] = PlaneNumToMaskBit(pNum);
	    if (!IsContact(primaryType))
		TTMaskSetType(&DBPlaneTypes[pNum], primaryType);
	    else
	    {
		lp = &dbLayerInfo[primaryType];

		/* if (primaryType < DBNumUserLayers) */
		    DBTypePlaneMaskTbl[primaryType] |= lp->l_pmask;

		for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
		    if (PlaneMaskHasPlane(lp->l_pmask, pNum))
			TTMaskSetType(&DBPlaneTypes[pNum], primaryType);
	    }
	}
    }

    /* Create a mask for which each type only appears on one plane.     */
    /* This is useful for non-redundant searches.                       */

    for (pNum = 0;  pNum < PL_MAXTYPES;  pNum++)
	TTMaskZero(&DBHomePlaneTypes[pNum]);

    for (primaryType = TT_SPACE + 1; primaryType < DBNumTypes; primaryType++)
	TTMaskSetType(&DBHomePlaneTypes[DBPlane(primaryType)], primaryType);
}

/*
 * ----------------------------------------------------------------------------
 * DBTechTypesOnPlane --
 *
 * Given a tile type bitmask and a plane index, check if all types in the
 * bitmask have an image on the indicated plane.
 *
 * Results:
 *	TRUE if all types in "src" have at least one image on plane.
 *	FALSE if any type in "src" does not contain any image in plane.
 *
 * Side effects:
 *	None.
 * ----------------------------------------------------------------------------
 */

bool
DBTechTypesOnPlane(
    TileTypeBitMask *src,
    int plane)
{
    int i;
    PlaneMask pmask;

    for (i = 0; i < DBNumTypes; i++)
	if (TTMaskHasType(src, i))
	    if (!PlaneMaskHasPlane(DBTypePlaneMaskTbl[i], plane))
		return FALSE;

    return TRUE;
}

/*
 * ----------------------------------------------------------------------------
 *
 * DBTechGetContact --
 *
 * Given two tile types, determine the corresponding contact type.
 * (Or rather, for two types, get the first contact type connecting
 * the two planes on which those types lie. . . not quite the same
 * thing.)
 *
 * Results:
 *	Returns a contact type.
 *
 * Side effects:
 *	Prints stuff if it can't find a contact type.
 *
 * ----------------------------------------------------------------------------
 */

TileType
DBTechGetContact(
    TileType type1,
    TileType type2)
{
    int pmask;
    LayerInfo *lp;
    TileType t;

    pmask = DBTypePlaneMaskTbl[type1] | DBTypePlaneMaskTbl[type2];
    for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
    {
	lp = &dbLayerInfo[t];
	if (lp->l_isContact)
	    if (lp->l_pmask == pmask)
		return t;
    }

    TxPrintf("No contact type for %d %d\n", type1, type2);
    return (TileType) -1;
}

/*
 * ----------------------------------------------------------------------------
 *
 * DBIsContact --
 *
 *   Like IsContact(), except as a subroutine, not a macro.  For export
 *   to other routines.
 *
 * ----------------------------------------------------------------------------
 */

bool
DBIsContact(
    TileType type)
{
    if (IsContact(type)) return TRUE;
    return FALSE;
}

/*
 * ----------------------------------------------------------------------------
 *
 * DBLayerPlanes --
 *
 *   Like LayerPlaneMask(), except as a subroutine, not a macro.  For export
 *   to other routines.
 *
 * ----------------------------------------------------------------------------
 */

PlaneMask
DBLayerPlanes(
    TileType type)
{
    return LayerPlaneMask(type);
}

/*
 * ----------------------------------------------------------------------------
 *
 * DBResidueMask --
 *
 *   Get the residue mask of the specified type.  For export to other
 *   routines.
 * ----------------------------------------------------------------------------
 */

TileTypeBitMask *
DBResidueMask(
    TileType type)
{
    LayerInfo *li = &dbLayerInfo[type];
    return (&li->l_residues);
}

/*
 * ----------------------------------------------------------------------------
 *
 * DBFullResidueMask --
 *
 *   Get the residue mask of the specified type.  For stacking contacts,
 *   decompose the contact residues into their component residue layers.
 *
 * Results:
 *	None.
 *
 * Side Effects:
 *	"rmask" is a pointer to a TileTypeBitMask.  The result is placed
 *	in this location.
 * ----------------------------------------------------------------------------
 */

void
DBFullResidueMask(
    TileType type,
    TileTypeBitMask *rmask)
{
    TileType t;
    TileTypeBitMask *lmask;
    LayerInfo *li, *lr;

    li = &dbLayerInfo[type];
    lmask = &li->l_residues;
    TTMaskZero(rmask);

    if (type < DBNumUserLayers)
    {
	TTMaskSetMask(rmask, &li->l_residues);
    }
    else
    {
	for (t = TT_TECHDEPBASE; t < DBNumUserLayers; t++)
	    if (TTMaskHasType(lmask, t))
	    {
		lr = &dbLayerInfo[t];
		TTMaskSetMask(rmask, &lr->l_residues);
	    }
    }
}

/*
 * ----------------------------------------------------------------------------
 *
 * dbTechPrintContacts --
 *
 * DEBUGGING.
 * Print a list of the contact types to which each possible contact image
 * belongs.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Prints stuff.
 *
 * ----------------------------------------------------------------------------
 */

void
dbTechPrintContacts()
{
    LayerInfo *lpImage;
    TileType t;
    int m, pNum;

    for (m = 0; m < dbNumContacts; m++)
    {
	lpImage = dbContactInfo[m];
	TxPrintf("Contact %s (on %s) ",
		DBTypeLongName(lpImage->l_type),
		DBPlaneLongName(DBPlane(lpImage->l_type)));

	TxPrintf(" connects:");
	for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
	    if ( TTMaskHasType(&DBConnectTbl[lpImage->l_type], t) )
		TxPrintf(" %s", DBTypeLongName(t));

	TxPrintf(" planes:");
	for ( pNum = PL_TECHDEPBASE; pNum < PL_MAXTYPES; pNum++ )
	    if ( PlaneNumToMaskBit(pNum) & DBConnPlanes[lpImage->l_type] )
		TxPrintf(" %s", DBPlaneLongName(pNum));

	TxPrintf(" residues:");
	for ( t = TT_TECHDEPBASE; t < DBNumTypes; t++ )
	    if (TTMaskHasType(&lpImage->l_residues, t))
		TxPrintf(" %s on plane %s\n",
				DBTypeLongName(t),
				DBPlaneLongName(DBPlane(t)));

	TxPrintf("\n");
    }
}

