mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-08-30 18:02:32 +02:00
Added a ARG_UNUSED macro in utils/magic.h, which produces a simple cast to void to silence the warnings. The reasons this is used as opposed to an attribute is that most compilers should support this. Besides this, the macro can be easily searched for in the future to potentially remove (where possible) the unused parameters.
919 lines
26 KiB
C
919 lines
26 KiB
C
/*
|
|
* DBtechpaint2.c --
|
|
*
|
|
* Default composition rules.
|
|
* Pretty complicated, unfortunately, so it's in a separate file.
|
|
*
|
|
* *********************************************************************
|
|
* * 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/DBtpaint2.c,v 1.4 2009/12/30 13:42:33 tim Exp $";
|
|
#endif /* not lint */
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
|
|
#include "utils/magic.h"
|
|
#include "utils/geometry.h"
|
|
#include "utils/utils.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"
|
|
|
|
#define SETPAINT(have,paint,plane,get) \
|
|
if (IsDefaultPaint((have), (paint)) \
|
|
&& TTMaskHasType(&DBPlaneTypes[(plane)], (have))) \
|
|
dbSetPaintEntry((have), (paint), (plane), (get))
|
|
#define SETERASE(have,erase,plane,get) \
|
|
if (IsDefaultErase((have), (erase)) \
|
|
&& TTMaskHasType(&DBPlaneTypes[(plane)], (have))) \
|
|
dbSetEraseEntry((have), (erase), (plane), (get))
|
|
|
|
LayerInfo *dbTechLpPaint;
|
|
|
|
/* Forward declarations */
|
|
|
|
extern void dbTechPaintErasePlanes();
|
|
extern void dbComposePaintAllImages();
|
|
extern void dbComposeResidues();
|
|
extern void dbComposeContacts();
|
|
extern void dbComposePaintContact();
|
|
extern void dbComposeEraseContact();
|
|
extern void dbComposeSavedRules();
|
|
extern void dbComposeCompose();
|
|
extern void dbComposeDecompose();
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* DBTechFinalCompose --
|
|
*
|
|
* Process all the contact erase/compose rules saved by DBTechAddCompose
|
|
* when it was reading in the "compose" section of a technology file.
|
|
* Also sets up the default paint/erase rules for contacts.
|
|
*
|
|
* Since by the end of this section we've processed all the painting
|
|
* rules, we initialize the tables that say which planes get affected
|
|
* by painting/erasing a given type.
|
|
*
|
|
* There's a great deal of work done here, so it's broken up into a
|
|
* number of separate procedures, each of which implements a single
|
|
* operation or default rule. Most of the work deals with painting
|
|
* and erasing contacts.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Modifies the paint/erase tables.
|
|
* Initializes DBTypePaintPlanesTbl[] and DBTypeErasePlanesTbl[].
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
DBTechFinalCompose()
|
|
{
|
|
TileType i;
|
|
TileTypeBitMask testmask, *rMask;
|
|
|
|
/* Default rules for painting/erasing contacts */
|
|
dbComposePaintAllImages();
|
|
dbComposeResidues();
|
|
dbComposeContacts();
|
|
|
|
/* Process rules saved from reading the "compose" section */
|
|
dbComposeSavedRules();
|
|
|
|
/* Build up exported tables */
|
|
dbTechPaintErasePlanes();
|
|
|
|
/* Adjust paint tables for any locked layers */
|
|
for (i = TT_TECHDEPBASE; i < DBNumUserLayers; i++)
|
|
if (!TTMaskHasType(&DBActiveLayerBits, i))
|
|
if (DBIsContact(i))
|
|
DBLockContact(i);
|
|
for (i = DBNumUserLayers; i < DBNumTypes; i++)
|
|
{
|
|
rMask = DBResidueMask(i);
|
|
TTMaskAndMask3(&testmask, &DBActiveLayerBits, rMask);
|
|
if (!TTMaskEqual(&testmask, rMask))
|
|
{
|
|
TTMaskClearType(&DBActiveLayerBits, i);
|
|
DBLockContact(i);
|
|
}
|
|
}
|
|
|
|
/* Diagnostic */
|
|
/* dbTechPrintPaint("DBTechFinalCompose", TRUE, FALSE); */
|
|
/* dbTechPrintPaint("DBTechFinalCompose", FALSE, FALSE); */
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* dbTechPaintErasePlanes --
|
|
*
|
|
* Fill in the tables telling which planes get affected
|
|
* by painting and erasing. One may take the naive view that only
|
|
* the planes on which a type is defined can be affected, but then
|
|
* one can't define arbitrary composite types.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Fills in DBTypePaintPlanesTbl[] and DBTypeErasePlanesTbl[].
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
dbTechPaintErasePlanes()
|
|
{
|
|
TileType t, s;
|
|
int pNum;
|
|
|
|
/* Space tiles are special: they may appear on any plane except router */
|
|
DBTypePaintPlanesTbl[TT_SPACE] = ~(PlaneNumToMaskBit(PL_ROUTER));
|
|
DBTypeErasePlanesTbl[TT_SPACE] = ~(PlaneNumToMaskBit(PL_ROUTER));
|
|
|
|
/* Skip TT_SPACE */
|
|
for (t = 1; t < DBNumTypes; t++)
|
|
{
|
|
DBTypePaintPlanesTbl[t] = DBTypeErasePlanesTbl[t] = 0;
|
|
|
|
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
|
|
for (s = 0; s < DBNumTypes; s++)
|
|
{
|
|
if (DBStdPaintEntry(s, t, pNum) != s)
|
|
DBTypePaintPlanesTbl[t] |= PlaneNumToMaskBit(pNum);
|
|
if (DBStdEraseEntry(s, t, pNum) != s)
|
|
DBTypeErasePlanesTbl[t] |= PlaneNumToMaskBit(pNum);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* dbComposePaintAllImages --
|
|
*
|
|
* Painting the primary type of a contact layer paints its image
|
|
* over all types on each image's plane. (The only types that
|
|
* should ever be painted are primary types.)
|
|
*
|
|
* This rule is called first because it may be overridden by later
|
|
* rules, or by explicit composition rules.
|
|
*
|
|
* Only affects paint entries that haven't already been set to other
|
|
* values by explicit paint rules.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Modifies paint/erase tables.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
dbComposePaintAllImages()
|
|
{
|
|
TileType tPaint, s, res;
|
|
LayerInfo *lp;
|
|
int p, n;
|
|
|
|
/* Iterate over primary types only */
|
|
for (n = 0; n < dbNumContacts; n++)
|
|
{
|
|
lp = dbContactInfo[n];
|
|
tPaint = lp->l_type;
|
|
if (tPaint >= DBNumUserLayers) continue;
|
|
for (res = TT_TECHDEPBASE; res < DBNumTypes; res++)
|
|
{
|
|
if (TTMaskHasType(&lp->l_residues, res))
|
|
{
|
|
p = DBPlane(res);
|
|
for (s = TT_TECHDEPBASE; s < DBNumTypes; s++)
|
|
if (DBPlane(s) == p)
|
|
SETPAINT(s, tPaint, p, tPaint);
|
|
|
|
if (IsDefaultPaint(TT_SPACE, tPaint))
|
|
dbSetPaintEntry(TT_SPACE, tPaint, p, tPaint);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* dbComposeResidues --
|
|
*
|
|
* The behavior of a contact type when other, non-contact types are
|
|
* painted over it or erased from it is derived from the behavior of
|
|
* its residue types.
|
|
*
|
|
* 1. If painting doesn't affect a contact's residue on a plane,
|
|
* it doesn't affect the contact's image on that plane either.
|
|
* This allows, for example, painting metal1 over a contact
|
|
* "containing" metal1 without breaking the contact.
|
|
*
|
|
* 2. If painting or erasing a type affects a residue of a
|
|
* contact, the image's connectivity to adjacent planes
|
|
* is broken and the image is replaced by the result of
|
|
* painting or erasing over the residue.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Modifies paint/erase tables.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
dbComposeResidues()
|
|
{
|
|
LayerInfo *lp;
|
|
TileType s, res;
|
|
int n;
|
|
|
|
/* Painting that doesn't affect the residue doesn't affect the contact. */
|
|
|
|
for (n = 0; n < dbNumContacts; n++)
|
|
{
|
|
lp = dbContactInfo[n];
|
|
|
|
for (res = TT_TECHDEPBASE; res < DBNumUserLayers; res++)
|
|
{
|
|
if (TTMaskHasType(&lp->l_residues, res))
|
|
{
|
|
for (s = TT_TECHDEPBASE; s < DBNumUserLayers; s++)
|
|
if (!PAINTAFFECTS(res, s))
|
|
SETPAINT(lp->l_type, s, DBPlane(res), lp->l_type);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* dbComposeContacts --
|
|
*
|
|
* This procedure handles the rules for composition of contact types.
|
|
* We look at the results of painting each type of contact in
|
|
* dbContactInfo[] over all other contact types.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Modifies paint/erase tables.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
dbComposeContacts()
|
|
{
|
|
LayerInfo *lpImage, *lpPaint;
|
|
int m, pNum;
|
|
TileTypeBitMask *rmask;
|
|
TileType n, ttype, itype, presult, eresult;
|
|
|
|
for (m = 0; m < dbNumContacts; m++)
|
|
{
|
|
lpImage = dbContactInfo[m]; /* Existing contact image */
|
|
for (n = TT_TECHDEPBASE; n < DBNumUserLayers; n++)
|
|
{
|
|
lpPaint = &dbLayerInfo[n]; /* Layer being painted or erased */
|
|
if (lpImage->l_type != n)
|
|
dbComposePaintContact(lpImage, lpPaint);
|
|
dbComposeEraseContact(lpImage, lpPaint);
|
|
}
|
|
}
|
|
|
|
/* For stacking types, determine the result of painting or erasing */
|
|
/* each stacking type by applying the paint and erase results of */
|
|
/* each of its residues in sequence. */
|
|
|
|
for (itype = 0; itype < DBNumTypes; itype++)
|
|
{
|
|
for (n = DBNumUserLayers; n < DBNumTypes; n++)
|
|
{
|
|
lpPaint = &dbLayerInfo[n]; /* Layer being painted or erased */
|
|
rmask = &lpPaint->l_residues;
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
{
|
|
presult = eresult = itype;
|
|
for (ttype = TT_TECHDEPBASE; ttype < DBNumUserLayers; ttype++)
|
|
if (TTMaskHasType(rmask, ttype))
|
|
{
|
|
presult = DBStdPaintEntry(presult, ttype, pNum);
|
|
eresult = DBStdEraseEntry(eresult, ttype, pNum);
|
|
}
|
|
SETPAINT(itype, n, pNum, presult);
|
|
SETERASE(itype, n, pNum, eresult);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* dbComposePaintContact --
|
|
*
|
|
* Construct the painting rules for painting type lpPaint over
|
|
* the contact image lpImage.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
dbComposePaintContact(lpImage, lpPaint)
|
|
LayerInfo *lpImage, *lpPaint;
|
|
{
|
|
int pNum;
|
|
PlaneMask pmask, pshared;
|
|
LayerInfo *lp;
|
|
TileTypeBitMask rmask, cmask;
|
|
TileType newtype, ptype, itype;
|
|
bool overlap;
|
|
|
|
/*
|
|
* If the residues of lpImage and lpPaint can be merged without
|
|
* affecting any of the layers, then we merge them, and look for
|
|
* any contact matching the merged residues. If none is found,
|
|
* and the planes do not overlap, then just paint the new
|
|
* contact. If they cannot be merged, then the original contact
|
|
* is dissolved and replaced by its residues.
|
|
*/
|
|
|
|
pmask = lpImage->l_pmask & lpPaint->l_pmask;
|
|
overlap = (pmask == 0) ? FALSE : TRUE;
|
|
|
|
if (overlap)
|
|
{
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
{
|
|
if (PlaneMaskHasPlane(pmask, pNum))
|
|
{
|
|
ptype = DBPlaneToResidue(lpPaint->l_type, pNum);
|
|
itype = DBPlaneToResidue(lpImage->l_type, pNum);
|
|
if (ptype != itype)
|
|
break;
|
|
}
|
|
}
|
|
if (pNum == DBNumPlanes)
|
|
{
|
|
/* Residues are compatible; check for a contact type with */
|
|
/* the merged residues (explicitly defined stacked contact */
|
|
/* type) */
|
|
|
|
TTMaskZero(&rmask);
|
|
TTMaskSetMask3(&rmask, &lpImage->l_residues, &lpPaint->l_residues);
|
|
dbTechMatchResidues(&rmask, &cmask, TRUE);
|
|
|
|
/* Implicitly-defined stacking types override any */
|
|
/* explicitly-defined types, or havoc results. */
|
|
/* This allows one to create a type such as "pad" */
|
|
/* having the same residues as "m123c" without */
|
|
/* magic confusing them in the paint tables. */
|
|
|
|
newtype = DBTechFindStacking(lpImage->l_type, lpPaint->l_type);
|
|
|
|
if (TTMaskIsZero(&cmask) || (newtype != -1))
|
|
{
|
|
/* If there is a stacking contact type, use it */
|
|
|
|
if (newtype >= DBNumUserLayers)
|
|
{
|
|
pshared = lpImage->l_pmask & lpPaint->l_pmask;
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
if (PlaneMaskHasPlane(pshared, pNum))
|
|
SETPAINT(lpImage->l_type, lpPaint->l_type,
|
|
pNum, newtype);
|
|
}
|
|
|
|
else if (lpPaint->l_isContact && (lpImage->l_type < DBNumUserLayers))
|
|
{
|
|
/* Original contact is replaced by the new one where
|
|
* the planes overlap, and is dissolved into its
|
|
* residues where they don't.
|
|
* In this condition, the residues of image must be
|
|
* non-contact types.
|
|
*/
|
|
|
|
for (itype = TT_TECHDEPBASE; itype < DBNumUserLayers; itype++)
|
|
{
|
|
if (TTMaskHasType(&lpImage->l_residues, itype))
|
|
{
|
|
if (TTMaskHasType(&lpPaint->l_residues, itype))
|
|
{
|
|
SETPAINT(lpImage->l_type, lpPaint->l_type,
|
|
DBPlane(itype), lpPaint->l_type);
|
|
}
|
|
else
|
|
{
|
|
SETPAINT(lpImage->l_type, lpPaint->l_type,
|
|
DBPlane(itype), itype);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (lpPaint->l_isContact &&
|
|
!TTMaskHasType(&lpImage->l_residues, lpPaint->l_type))
|
|
{
|
|
/* Original contact is replaced by the new one where
|
|
* the planes overlap, and is dissolved into its
|
|
* residues where they don't.
|
|
* In this condition, the residues of image are contact
|
|
* types.
|
|
*/
|
|
|
|
for (itype = TT_TECHDEPBASE; itype < DBNumUserLayers; itype++)
|
|
{
|
|
if (TTMaskHasType(&lpImage->l_residues, itype))
|
|
{
|
|
if (TTMaskHasType(&lpPaint->l_residues, itype))
|
|
{
|
|
SETPAINT(lpImage->l_type, lpPaint->l_type,
|
|
DBPlane(itype), lpPaint->l_type);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Painting a residue type on top of a contact */
|
|
/* with a compatible residue does nothing, as does */
|
|
/* painting one of the types of a stacked contact */
|
|
/* on the stacking contact type. In the plane of */
|
|
/* the image type, this is non-default behavior. */
|
|
|
|
SETPAINT(lpImage->l_type, lpPaint->l_type,
|
|
DBPlane(lpImage->l_type), lpImage->l_type);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Presumably there is at most one contact type here */
|
|
for (newtype = TT_TECHDEPBASE; newtype < DBNumUserLayers; newtype++)
|
|
{
|
|
if (TTMaskHasType(&cmask, newtype))
|
|
{
|
|
lp = &dbLayerInfo[newtype];
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
if (PlaneMaskHasPlane(lp->l_pmask, pNum))
|
|
SETPAINT(lpImage->l_type, lpPaint->l_type,
|
|
pNum, newtype);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Image and paint types overlap in a plane, but */
|
|
/* residues are not compatible. Replace image with the */
|
|
/* residues of image, except on the overlapping plane. */
|
|
|
|
for (ptype = TT_TECHDEPBASE; ptype < DBNumUserLayers; ptype++)
|
|
if (TTMaskHasType(&lpImage->l_residues, ptype))
|
|
if (ptype != itype)
|
|
SETPAINT(lpImage->l_type, lpPaint->l_type,
|
|
DBPlane(ptype), ptype);
|
|
}
|
|
}
|
|
else if (lpPaint->l_isContact)
|
|
{
|
|
/* No overlapping planes, and both paint & image types are contacts */
|
|
|
|
TTMaskZero(&rmask);
|
|
TTMaskSetMask3(&rmask, &lpImage->l_residues, &lpPaint->l_residues);
|
|
dbTechMatchResidues(&rmask, &cmask, TRUE);
|
|
if (!TTMaskIsZero(&cmask))
|
|
{
|
|
/* Replace image with the new contact type */
|
|
for (newtype = TT_TECHDEPBASE; newtype < DBNumUserLayers; newtype++)
|
|
{
|
|
if (TTMaskHasType(&cmask, newtype))
|
|
{
|
|
lp = &dbLayerInfo[newtype];
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
if (PlaneMaskHasPlane(lp->l_pmask, pNum))
|
|
SETPAINT(lpImage->l_type, lpPaint->l_type,
|
|
pNum, newtype);
|
|
}
|
|
}
|
|
}
|
|
/* else default paint/erase behavior */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* dbComposeSubsetResidues --
|
|
*
|
|
* Create a mask of all contact types whose residues are subsets
|
|
* of the "have" type but are not supersets of the "erase" type.
|
|
*
|
|
* Results:
|
|
* True if residues of types in outMask overlap, False if not.
|
|
*
|
|
* Side Effects:
|
|
* outMask is filled with the mask of types.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
bool
|
|
dbComposeSubsetResidues(lpImage, lpErase, outMask)
|
|
LayerInfo *lpImage, *lpErase;
|
|
TileTypeBitMask *outMask;
|
|
{
|
|
TileTypeBitMask ires;
|
|
TileTypeBitMask smask, overlapmask;
|
|
LayerInfo *li;
|
|
int n;
|
|
bool rval = FALSE;
|
|
|
|
/* The residues of lpImage must themselves be decomposed if lpImage */
|
|
/* is a stacking type. */
|
|
|
|
TTMaskZero(&ires);
|
|
if (lpImage->l_type >= DBNumUserLayers)
|
|
{
|
|
for (n = 0; n < dbNumContacts; n++)
|
|
{
|
|
li = dbContactInfo[n];
|
|
if (TTMaskHasType(&lpImage->l_residues, li->l_type))
|
|
TTMaskSetMask(&ires, &li->l_residues);
|
|
}
|
|
}
|
|
else
|
|
TTMaskSetMask(&ires, &lpImage->l_residues);
|
|
|
|
/*
|
|
* Generate a mask of all contact types whose residue masks are
|
|
* subsets of the residues of lpImage. These are all types
|
|
* which contain no residues that are not part of lpImage.
|
|
*/
|
|
|
|
TTMaskZero(outMask);
|
|
TTMaskZero(&overlapmask);
|
|
for (n = 0; n < dbNumContacts; n++)
|
|
{
|
|
li = dbContactInfo[n];
|
|
TTMaskAndMask3(&smask, &li->l_residues, &ires);
|
|
if (TTMaskEqual(&smask, &li->l_residues))
|
|
{
|
|
/* The residues of type cannot be a superset of the */
|
|
/* residues of the erase type */
|
|
|
|
TTMaskAndMask3(&smask, &li->l_residues, &lpErase->l_residues);
|
|
if (!TTMaskEqual(&smask, &lpErase->l_residues))
|
|
{
|
|
TTMaskSetType(outMask, li->l_type);
|
|
|
|
/* Check if the residues of type overlap one of */
|
|
/* the types already generated. */
|
|
|
|
TTMaskAndMask3(&smask, &overlapmask, &li->l_residues);
|
|
if (TTMaskIsZero(&smask))
|
|
TTMaskSetMask(&overlapmask, &li->l_residues);
|
|
else
|
|
rval = TRUE;
|
|
}
|
|
}
|
|
}
|
|
return rval;
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* dbComposeEraseContact --
|
|
*
|
|
* Construct the erasing rules for erasing type lpErase from
|
|
* the contact image lpImage.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
dbComposeEraseContact(lpImage, lpErase)
|
|
LayerInfo *lpImage, *lpErase;
|
|
{
|
|
int pNum;
|
|
PlaneMask pmask;
|
|
LayerInfo *lp;
|
|
TileTypeBitMask cmask;
|
|
TileType itype;
|
|
bool overlap;
|
|
|
|
/* The erased planes generally end up with space, so we generate */
|
|
/* space as default behavior. This may be altered in specific */
|
|
/* cases, below. */
|
|
|
|
/* The specific check for lpImage as a stacking contact is not */
|
|
/* necessary, but prevents generation of non-default rules in */
|
|
/* cases which cannot occur. */
|
|
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
if (PlaneMaskHasPlane(lpErase->l_pmask, pNum))
|
|
if ((lpImage->l_type < DBNumUserLayers)
|
|
|| (pNum == DBPlane(lpImage->l_type)))
|
|
SETERASE(lpImage->l_type, lpErase->l_type, pNum, TT_SPACE);
|
|
|
|
/* Erasing self should always leave space; otherwise */
|
|
/* the "undo" records aren't symmetric, which screws */
|
|
/* everything up. */
|
|
|
|
if (lpImage->l_type == lpErase->l_type) return;
|
|
|
|
/* If planes of HAVE and ERASE types don't overlap, we can erase */
|
|
/* the ERASE type without affecting the image, so we're done. */
|
|
|
|
pmask = lpImage->l_pmask & lpErase->l_pmask;
|
|
overlap = (pmask == 0) ? FALSE : TRUE;
|
|
if (!overlap) return;
|
|
|
|
/* Find what contacts are subsets of this one and generate a mask */
|
|
/* of the types that might be left over after erasing this one. */
|
|
/* If those types overlap, leave the existing type alone. If they */
|
|
/* don't, then paint them. */
|
|
|
|
overlap = dbComposeSubsetResidues(lpImage, lpErase, &cmask);
|
|
|
|
if (overlap)
|
|
{
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
if (PlaneMaskHasPlane(lpImage->l_pmask, pNum))
|
|
// SETERASE(lpImage->l_type, lpErase->l_type, pNum, TT_SPACE);
|
|
SETERASE(lpImage->l_type, lpErase->l_type, pNum, lpImage->l_type);
|
|
}
|
|
else
|
|
{
|
|
pmask = lpImage->l_pmask & (~(lpErase->l_pmask));
|
|
for (itype = TT_TECHDEPBASE; itype < DBNumTypes; itype++)
|
|
if (TTMaskHasType(&cmask, itype))
|
|
{
|
|
lp = &dbLayerInfo[itype];
|
|
pmask &= ~(lp->l_pmask);
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
if (PlaneMaskHasPlane(lp->l_pmask, pNum))
|
|
if ((lpImage->l_type < DBNumUserLayers)
|
|
|| (pNum == DBPlane(lpImage->l_type)))
|
|
SETERASE(lpImage->l_type, lpErase->l_type, pNum, itype);
|
|
}
|
|
|
|
/* If there are any planes in the image which have not been */
|
|
/* accounted for, then we decompose these into the residues */
|
|
/* of the image. */
|
|
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
if (PlaneMaskHasPlane(pmask, pNum))
|
|
{
|
|
itype = DBPlaneToResidue(lpImage->l_type, pNum);
|
|
SETERASE(lpImage->l_type, lpErase->l_type, pNum, itype);
|
|
}
|
|
|
|
}
|
|
|
|
/* Diagnostic (to be removed or commented out) */
|
|
|
|
/*
|
|
if (!TTMaskIsZero(&cmask))
|
|
{
|
|
TxPrintf("Have %s, Erase %s: ", DBTypeLongNameTbl[lpImage->l_type],
|
|
DBTypeLongNameTbl[lpErase->l_type]);
|
|
for (itype = TT_TECHDEPBASE; itype < DBNumTypes; itype++)
|
|
if (TTMaskHasType(&cmask, itype))
|
|
TxPrintf("%s ", DBTypeLongNameTbl[itype]);
|
|
if (overlap)
|
|
TxPrintf("overlapping");
|
|
TxPrintf("\n");
|
|
}
|
|
*/
|
|
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* DBLockContact --
|
|
*
|
|
* This procedure modifies the erase tables so that the specified contact
|
|
* type cannot be erased by erasing one of its residues, which is the default
|
|
* behavior.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
DBLockContact(ctype)
|
|
TileType ctype;
|
|
{
|
|
LayerInfo *lpPaint;
|
|
TileType n;
|
|
TileTypeBitMask *rmask;
|
|
int pNum;
|
|
|
|
/* Have type, Erase * --> Result is type */
|
|
|
|
lpPaint = &dbLayerInfo[ctype];
|
|
for (n = TT_TECHDEPBASE; n < DBNumTypes; n++)
|
|
{
|
|
if (n == ctype) continue;
|
|
|
|
/* Avoid the case, e.g., if ctype is pc+v, then pc+v - pc = v */
|
|
/* is still valid if pc is an active layer. */
|
|
|
|
if (ctype >= DBNumUserLayers)
|
|
{
|
|
rmask = DBResidueMask(ctype);
|
|
if (TTMaskHasType(rmask, n))
|
|
if (TTMaskHasType(&DBActiveLayerBits, n))
|
|
continue;
|
|
}
|
|
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
if (PlaneMaskHasPlane(lpPaint->l_pmask, pNum))
|
|
SETERASE(ctype, n, pNum, ctype);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* DBUnlockContact --
|
|
*
|
|
* This procedure reverses the operation of DBLockContact, allowing a contact
|
|
* to be erased by erasing one of its residues. This is the same code as
|
|
* dbComposeContacts(), for a single contact type.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
DBUnlockContact(ctype)
|
|
TileType ctype;
|
|
{
|
|
LayerInfo *lpImage, *lpPaint;
|
|
TileType n;
|
|
|
|
lpImage = &dbLayerInfo[ctype];
|
|
|
|
for (n = TT_TECHDEPBASE; n < DBNumUserLayers; n++)
|
|
{
|
|
lpPaint = &dbLayerInfo[n];
|
|
dbComposeEraseContact(lpImage, lpPaint);
|
|
}
|
|
|
|
/* To be done (maybe): revert rules for stacked contact types */
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* dbComposeSavedRules --
|
|
*
|
|
* Process all the contact compose/decompose rules saved
|
|
* when the compose section of the tech file was read.
|
|
* Each pair on the RHS of one of these rules must contain
|
|
* exactly one contact type that spans the same set of planes
|
|
* as the image type.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Modifies entries in the paint and erase tables.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
dbComposeSavedRules()
|
|
{
|
|
LayerInfo *lpContact;
|
|
TileType imageType;
|
|
TypePair *pair;
|
|
Rule *rule;
|
|
int n;
|
|
|
|
for (n = 0; n < dbNumSavedRules; n++)
|
|
{
|
|
rule = &dbSavedRules[n];
|
|
lpContact = &dbLayerInfo[rule->r_result];
|
|
imageType = lpContact->l_type;
|
|
|
|
for (pair = rule->r_pairs; pair < &rule->r_pairs[rule->r_npairs];
|
|
pair++)
|
|
{
|
|
dbComposeDecompose(imageType, pair->rp_a, pair->rp_b);
|
|
dbComposeDecompose(imageType, pair->rp_b, pair->rp_a);
|
|
if (rule->r_ruleType == RULE_COMPOSE)
|
|
{
|
|
dbComposeCompose(imageType, pair->rp_a, pair->rp_b);
|
|
dbComposeCompose(imageType, pair->rp_b, pair->rp_a);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* dbComposeDecompose --
|
|
*
|
|
* Painting componentType over imageType is a no-op.
|
|
* Erasing componentType from imageType gives either the image of
|
|
* remainingType, if one exists on DBPlane(imageType), or else
|
|
* gives the residue of imageType.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Modifies the paint/erase tables as described above.
|
|
* Indicates that these modifications are not default
|
|
* rules by setting the corresponding bits in the tables
|
|
* dbNotDefaultPaintTbl[] and dbNotDefaultEraseTbl[].
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
dbComposeDecompose(imageType, componentType, remainingType)
|
|
TileType imageType;
|
|
TileType componentType;
|
|
TileType remainingType;
|
|
{
|
|
ARG_UNUSED(remainingType);
|
|
int pNum = DBPlane(imageType);
|
|
TileType resultType;
|
|
|
|
/* Painting componentType is a no-op */
|
|
dbSetPaintEntry(imageType, componentType, pNum, imageType);
|
|
TTMaskSetType(&dbNotDefaultPaintTbl[imageType], componentType);
|
|
|
|
/* Which residue belongs to the plane pNum? */
|
|
resultType = DBPlaneToResidue(imageType, pNum);
|
|
|
|
/*
|
|
* Erasing componentType gives remainingType or breaks
|
|
* imageType's contact.
|
|
*/
|
|
dbSetEraseEntry(imageType, componentType, pNum, resultType);
|
|
TTMaskSetType(&dbNotDefaultEraseTbl[imageType], componentType);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* dbComposeCompose --
|
|
*
|
|
* Painting paintType over existingType gives imageType.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Modifies the paint/erase tables as described above.
|
|
* Indicates that these modifications are not default
|
|
* rules by setting the corresponding bits in the tables
|
|
* dbNotDefaultPaintTbl[] and dbNotDefaultEraseTbl[].
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
dbComposeCompose(imageType, existingType, paintType)
|
|
TileType imageType;
|
|
TileType existingType;
|
|
TileType paintType;
|
|
{
|
|
int pNum = DBPlane(imageType);
|
|
|
|
if (PlaneMaskHasPlane(LayerPlaneMask(existingType), pNum))
|
|
{
|
|
dbSetPaintEntry(existingType, paintType, pNum, imageType);
|
|
TTMaskSetType(&dbNotDefaultPaintTbl[existingType], paintType);
|
|
}
|
|
}
|