Merge branch 'master' into bplane
Conflicts: VERSION database/DBcellsrch.c database/DBconnect.c extract/ExtInter.c lef/Depend utils/Depend Updated bplane branch with all changes to master since the bplane branch was last modified.
This commit is contained in:
commit
cd87b08b21
|
|
@ -10,5 +10,18 @@ scripts/defs.mak
|
|||
*.so
|
||||
*~
|
||||
scmos/cif_template/objs/*
|
||||
UPDATE_ME
|
||||
VERSION
|
||||
database/database.h
|
||||
install.log
|
||||
magic/proto.magicrc
|
||||
make.log
|
||||
readline/readline
|
||||
scmos/gdsquery.tech
|
||||
scmos/minimum.tech
|
||||
scmos/scmos-sub.tech
|
||||
scmos/scmos-tm.tech
|
||||
scmos/scmos.tech
|
||||
scmos/scmosWR.tech
|
||||
tcltk/magic.sh
|
||||
tcltk/magic.tcl
|
||||
tcltk/magicdnull
|
||||
tcltk/magicexec
|
||||
|
|
|
|||
2
INSTALL
2
INSTALL
|
|
@ -7,6 +7,8 @@ Autoconf Capsule Summary:
|
|||
make
|
||||
make install
|
||||
|
||||
Note: Remember to use 'gmake' on FreeBSD.
|
||||
|
||||
Autoconf options (use "./configure --help" for a complete list):
|
||||
|
||||
--prefix=DIR Indicates the install directory. Determines the
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
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.
|
||||
20
Makefile
20
Makefile
|
|
@ -13,7 +13,7 @@ MODULES = bplane cmwind commands database dbwind debug drc extflat \
|
|||
MAKEFLAGS =
|
||||
INSTALL_CAD_DIRS = windows doc ${TECH}
|
||||
|
||||
include defs.mak
|
||||
-include defs.mak
|
||||
|
||||
all: $(ALL_TARGET)
|
||||
|
||||
|
|
@ -66,8 +66,8 @@ depend: database/database.h
|
|||
install: $(INSTALL_TARGET)
|
||||
|
||||
install-magic:
|
||||
@echo --- installing executable to $(DESTDIR)${BINDIR}
|
||||
@echo --- installing runtime files to $(DESTDIR)${LIBDIR}
|
||||
@echo --- installing executable to $(DESTDIR)${INSTALL_BINDIR}
|
||||
@echo --- installing runtime files to $(DESTDIR)${INSTALL_LIBDIR}
|
||||
@${MAKE} install-real 2>&1 >> install.log
|
||||
|
||||
install-real: install-dirs
|
||||
|
|
@ -77,16 +77,18 @@ install-real: install-dirs
|
|||
(cd $$dir && ${MAKE} install); done
|
||||
|
||||
install-tcl-dirs:
|
||||
${MAGICDIR}/scripts/mkdirs $(DESTDIR)${BINDIR} $(DESTDIR)${MANDIR} \
|
||||
$(DESTDIR)${SYSDIR} $(DESTDIR)${TCLDIR} $(DESTDIR)${TCLDIR}/bitmaps
|
||||
${MAGICDIR}/scripts/mkdirs $(DESTDIR)${INSTALL_BINDIR} \
|
||||
$(DESTDIR)${INSTALL_MANDIR} $(DESTDIR)${INSTALL_SYSDIR} \
|
||||
$(DESTDIR)${INSTALL_TCLDIR} $(DESTDIR)${INSTALL_TCLDIR}/bitmaps
|
||||
|
||||
install-dirs:
|
||||
${MAGICDIR}/scripts/mkdirs $(DESTDIR)${BINDIR} $(DESTDIR)${MANDIR} \
|
||||
$(DESTDIR)${SYSDIR} $(DESTDIR)${SCMDIR}
|
||||
${MAGICDIR}/scripts/mkdirs $(DESTDIR)${INSTALL_BINDIR} \
|
||||
$(DESTDIR)${INSTALL_MANDIR} $(DESTDIR)${INSTALL_SYSDIR} \
|
||||
$(DESTDIR)${INSTALL_SCMDIR}
|
||||
|
||||
install-tcl:
|
||||
@echo --- installing executable to $(DESTDIR)${BINDIR}
|
||||
@echo --- installing runtime files to $(DESTDIR)${LIBDIR}
|
||||
@echo --- installing executable to $(DESTDIR)${INSTALL_BINDIR}
|
||||
@echo --- installing runtime files to $(DESTDIR)${INSTALL_LIBDIR}
|
||||
@${MAKE} install-tcl-real 2>&1 >> install.log
|
||||
|
||||
install-tcl-real: install-tcl-dirs
|
||||
|
|
|
|||
20
TODO
20
TODO
|
|
@ -1,8 +1,16 @@
|
|||
I. Bugs to fix (also in magic-7.5 [stable]):
|
||||
I. Bugs to fix
|
||||
|
||||
1. The "extresist" code only recognizes original "fet" types, not
|
||||
the new "device" types in the extract file.
|
||||
1. The "extresist" code needs to extract substrate networks. Moreover,
|
||||
the "extresist" code really needs to have the dependence on
|
||||
ext2sim removed, and instead read directly from .ext files. The
|
||||
.sim format has no substrate connections, so this cannot be properly
|
||||
represented. Also, there is nothing that is read from the .sim file
|
||||
that is not already present in the .ext file.
|
||||
|
||||
2. "plow" has been broken for some time. It should derive its rules
|
||||
from the DRC decks (using the new routines that are meant for just
|
||||
that sort of thing).
|
||||
2. "plow" should derive its rules from the DRC decks (using the new
|
||||
routines that are meant for just that sort of thing).
|
||||
|
||||
3. It is possible to trick the net selection into an infinite loop in
|
||||
unusual geometry situations. That these situations would be DRC
|
||||
errors does not excuse the infinite loop behavior. The geometry
|
||||
required is unusual enough that this is not a high priority item.
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ calmaParseStructure(filename)
|
|||
{
|
||||
static int structs[] = { CALMA_STRCLASS, CALMA_STRTYPE, -1 };
|
||||
int nbytes, rtype, nsrefs, osrefs, npaths;
|
||||
char *strname = NULL, newname[CALMANAMELENGTH*2];
|
||||
char *strname = NULL;
|
||||
HashEntry *he;
|
||||
int suffix;
|
||||
int mfactor;
|
||||
|
|
@ -327,15 +327,21 @@ calmaParseStructure(filename)
|
|||
}
|
||||
else
|
||||
{
|
||||
char *newname;
|
||||
|
||||
CalmaReadError("Cell \"%s\" was already defined in this file.\n",
|
||||
strname);
|
||||
newname = (char *)mallocMagic(strlen(strname) + 20);
|
||||
for (suffix = 1; HashGetValue(he) != NULL; suffix++)
|
||||
{
|
||||
(void) sprintf(newname, "%s_%d", strname, suffix);
|
||||
he = HashFind(&calmaDefInitHash, newname);
|
||||
}
|
||||
CalmaReadError("Giving this cell a new name: %s\n", newname);
|
||||
strncpy(strname, newname, CALMANAMELENGTH*2);
|
||||
freeMagic(strname);
|
||||
strname = mallocMagic(strlen(newname) + 1);
|
||||
strcpy(strname, newname);
|
||||
freeMagic(newname);
|
||||
}
|
||||
}
|
||||
cifReadCellDef = calmaFindCell(strname, &was_called);
|
||||
|
|
@ -405,17 +411,18 @@ calmaParseStructure(filename)
|
|||
*/
|
||||
if (CalmaFlattenUses && (!was_called) && (npaths < 10) && (nsrefs == 0))
|
||||
{
|
||||
/* To-do: If CDFLATGDS is already set, need to remove */
|
||||
/* If CDFLATGDS is already set, may need to remove */
|
||||
/* existing planes and free memory. */
|
||||
|
||||
if (cifReadCellDef->cd_flags & CDFLATGDS)
|
||||
if ((cifReadCellDef->cd_client != (ClientData)CLIENTDEFAULT) &&
|
||||
(cifReadCellDef->cd_flags & CDFLATGDS))
|
||||
{
|
||||
Plane **cifplanes = (Plane **)cifReadCellDef->cd_client;
|
||||
int pNum;
|
||||
|
||||
for (pNum = 0; pNum < MAXCIFRLAYERS; pNum++)
|
||||
{
|
||||
if (cifplanes[pNum] != NULL)
|
||||
if (cifplanes[pNum] != NULL)
|
||||
{
|
||||
DBFreePaintPlane(cifplanes[pNum]);
|
||||
TiFreePlane(cifplanes[pNum]);
|
||||
|
|
@ -903,7 +910,8 @@ calmaElementSref(filename)
|
|||
|
||||
for (pNum = 0; pNum < MAXCIFRLAYERS; pNum++)
|
||||
{
|
||||
if (gdsplanes[pNum] != NULL)
|
||||
if ((def->cd_client != (ClientData)CLIENTDEFAULT) &&
|
||||
(gdsplanes[pNum] != NULL))
|
||||
{
|
||||
gdsCopyRec.plane = cifCurReadPlanes[pNum];
|
||||
if (isArray)
|
||||
|
|
|
|||
|
|
@ -291,10 +291,10 @@ calmaElementBoundary()
|
|||
|
||||
/* Convert rp to magic database units to compare to label rects */
|
||||
rpc = rp->r_r;
|
||||
rpc.r_xbot /= calmaReadScale1;
|
||||
rpc.r_xtop /= calmaReadScale1;
|
||||
rpc.r_ybot /= calmaReadScale1;
|
||||
rpc.r_ytop /= calmaReadScale1;
|
||||
rpc.r_xbot /= cifCurReadStyle->crs_scaleFactor;
|
||||
rpc.r_xtop /= cifCurReadStyle->crs_scaleFactor;
|
||||
rpc.r_ybot /= cifCurReadStyle->crs_scaleFactor;
|
||||
rpc.r_ytop /= cifCurReadStyle->crs_scaleFactor;
|
||||
|
||||
if ((ciftype >= 0) &&
|
||||
(cifCurReadStyle->crs_labelSticky[ciftype] != LABEL_TYPE_NONE))
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ done:
|
|||
if (mw != NULL)
|
||||
{
|
||||
if (calmaLookCell(libname, NULL) != (CellDef *)NULL)
|
||||
DBWloadWindow(mw, libname, FALSE);
|
||||
DBWloadWindow(mw, libname, FALSE, FALSE);
|
||||
}
|
||||
freeMagic(libname);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -372,10 +372,10 @@ calmaDumpStructure(def, outf, calmaDefHash, filename)
|
|||
char *filename;
|
||||
{
|
||||
int nbytes, rtype;
|
||||
char *strname = NULL, *newnameptr, newname[CALMANAMELENGTH*2];
|
||||
char *strname = NULL, *newnameptr;
|
||||
HashEntry *he, *he2;
|
||||
CellDef *edef;
|
||||
char *prefix;
|
||||
char *prefix = NULL;
|
||||
|
||||
/* Make sure this is a structure; if not, let the caller know we're done */
|
||||
PEEKRH(nbytes, rtype);
|
||||
|
|
@ -397,23 +397,35 @@ calmaDumpStructure(def, outf, calmaDefHash, filename)
|
|||
calmaOutDate(def->cd_timestamp, outf);
|
||||
calmaOutDate(time((time_t *) 0), outf);
|
||||
|
||||
/* Find the structure's unique prefix, in case structure calls subcells */
|
||||
/* that are not yet defined. */
|
||||
|
||||
he2 = HashFind(&calmaLibHash, filename);
|
||||
if (he2 == NULL)
|
||||
TxError("Fatal error: Library %s not recorded!\n", filename);
|
||||
else
|
||||
prefix = (char *)HashGetValue(he2);
|
||||
|
||||
/* Prefix structure name with def name, and output new structure name */
|
||||
he = HashFind(calmaDefHash, strname);
|
||||
if ((newnameptr = (char *)HashGetValue(he)) != NULL)
|
||||
{
|
||||
/* Structure is defined more than once */
|
||||
TxError("Structure %s defined redundantly in GDS\n", strname);
|
||||
if (*newnameptr != '0')
|
||||
TxError("Structure %s defined redundantly in GDS\n", strname);
|
||||
else
|
||||
*newnameptr = '1';
|
||||
/* To be considered: Should the structure be output more than once? */
|
||||
calmaOutStringRecord(CALMA_STRNAME, newnameptr, outf);
|
||||
calmaOutStringRecord(CALMA_STRNAME, newnameptr + 1, outf);
|
||||
}
|
||||
else if (!strcmp(strname, def->cd_name))
|
||||
{
|
||||
/* This is the top level cell being defined. Its name */
|
||||
/* does not get modified. */
|
||||
|
||||
newnameptr = mallocMagic(strlen(strname) + 1);
|
||||
sprintf(newnameptr, "%s", strname);
|
||||
calmaOutStringRecord(CALMA_STRNAME, newnameptr, outf);
|
||||
newnameptr = mallocMagic(strlen(strname) + 2);
|
||||
sprintf(newnameptr, "1%s", strname);
|
||||
calmaOutStringRecord(CALMA_STRNAME, newnameptr + 1, outf);
|
||||
HashSetValue(he, (char *)newnameptr);
|
||||
}
|
||||
else
|
||||
|
|
@ -444,26 +456,20 @@ calmaDumpStructure(def, outf, calmaDefHash, filename)
|
|||
/* Same library, so keep the cellname and mark the cell */
|
||||
/* as having been written to GDS. */
|
||||
|
||||
newnameptr = mallocMagic(strlen(strname) + 1);
|
||||
sprintf(newnameptr, "%s", strname);
|
||||
newnameptr = mallocMagic(strlen(strname) + 2);
|
||||
sprintf(newnameptr, "1%s", strname);
|
||||
HashSetValue(he, (char *)newnameptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Find the unique library prefix and prepend it to the cell name */
|
||||
|
||||
he2 = HashFind(&calmaLibHash, filename);
|
||||
if (he2 == NULL)
|
||||
{
|
||||
/* Should never happen */
|
||||
TxError("Fatal error: Library %s not recorded!\n", filename);
|
||||
newnameptr = strname;
|
||||
}
|
||||
if (prefix == NULL)
|
||||
newnameptr = strname; /* Should never happen */
|
||||
else
|
||||
{
|
||||
prefix = (char *)HashGetValue(he2);
|
||||
newnameptr = mallocMagic(strlen(strname) + strlen(prefix) + 8);
|
||||
sprintf(newnameptr, "%s_%s", prefix, strname);
|
||||
newnameptr = mallocMagic(strlen(strname) + strlen(prefix) + 9);
|
||||
sprintf(newnameptr, "1%s_%s", prefix, strname);
|
||||
HashSetValue(he, (char *)newnameptr);
|
||||
}
|
||||
}
|
||||
|
|
@ -472,22 +478,16 @@ calmaDumpStructure(def, outf, calmaDefHash, filename)
|
|||
{
|
||||
/* Find the unique library prefix and prepend it to the cell name */
|
||||
|
||||
he2 = HashFind(&calmaLibHash, filename);
|
||||
if (he2 == NULL)
|
||||
{
|
||||
/* Should never happen */
|
||||
TxError("Fatal error: Library %s not recorded!\n", filename);
|
||||
newnameptr = strname;
|
||||
}
|
||||
if (prefix == NULL)
|
||||
newnameptr = strname; /* Should never happen */
|
||||
else
|
||||
{
|
||||
prefix = (char *)HashGetValue(he2);
|
||||
newnameptr = mallocMagic(strlen(strname) + strlen(prefix) + 8);
|
||||
sprintf(newnameptr, "%s_%s", prefix, strname);
|
||||
newnameptr = mallocMagic(strlen(strname) + strlen(prefix) + 9);
|
||||
sprintf(newnameptr, "1%s_%s", prefix, strname);
|
||||
HashSetValue(he, (char *)newnameptr);
|
||||
}
|
||||
}
|
||||
calmaOutStringRecord(CALMA_STRNAME, newnameptr, outf);
|
||||
calmaOutStringRecord(CALMA_STRNAME, newnameptr + 1, outf);
|
||||
}
|
||||
freeMagic(strname);
|
||||
|
||||
|
|
@ -525,7 +525,7 @@ calmaDumpStructure(def, outf, calmaDefHash, filename)
|
|||
newnameptr = (char *)HashGetValue(he);
|
||||
if (newnameptr != NULL)
|
||||
{
|
||||
calmaOutStringRecord(CALMA_SNAME, newnameptr, outf);
|
||||
calmaOutStringRecord(CALMA_SNAME, newnameptr + 1, outf);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -535,14 +535,14 @@ calmaDumpStructure(def, outf, calmaDefHash, filename)
|
|||
/* the same way used for structure definitions. */
|
||||
|
||||
newnameptr = (char *)mallocMagic(strlen(strname) +
|
||||
strlen(prefix) + 8);
|
||||
sprintf(newnameptr, "%s_%s", prefix, strname);
|
||||
strlen(prefix) + 9);
|
||||
sprintf(newnameptr, "0%s_%s", prefix, strname);
|
||||
|
||||
edef = DBCellLookDef(newnameptr);
|
||||
edef = DBCellLookDef(newnameptr + 1);
|
||||
if (edef != NULL)
|
||||
sprintf(newnameptr, "%s_%s[[0]]", prefix, strname);
|
||||
sprintf(newnameptr, "0%s_%s[[0]]", prefix, strname);
|
||||
HashSetValue(he, (char *)newnameptr);
|
||||
calmaOutStringRecord(CALMA_SNAME, newnameptr, outf);
|
||||
calmaOutStringRecord(CALMA_SNAME, newnameptr + 1, outf);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -746,8 +746,11 @@ calmaProcessDef(def, outf)
|
|||
|
||||
/* Read the cell in if it is not already available. */
|
||||
if ((def->cd_flags & CDAVAILABLE) == 0)
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, NULL))
|
||||
{
|
||||
bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, dereference, NULL))
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Output the definitions for any of our descendants that have
|
||||
|
|
@ -1024,7 +1027,7 @@ calmaOutFunc(def, f, cliprect)
|
|||
((lab->lab_flags & PORT_NUM_MASK) == i))
|
||||
{
|
||||
calmaWriteLabelFunc(lab, type, f);
|
||||
break;
|
||||
/* break; */ /* Do not limit to unique labels! */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1316,7 +1319,7 @@ calmaOutStructName(type, def, f)
|
|||
CellDef *def;
|
||||
FILE *f;
|
||||
{
|
||||
char defname[CALMANAMELENGTH+1];
|
||||
char *defname;
|
||||
unsigned char c;
|
||||
char *cp;
|
||||
int calmanum;
|
||||
|
|
@ -1341,10 +1344,11 @@ calmaOutStructName(type, def, f)
|
|||
}
|
||||
/* We really should ensure that the new name is unique. . . */
|
||||
}
|
||||
if (cp <= def->cd_name + CALMANAMELENGTH)
|
||||
if ((!(CIFCurStyle->cs_flags & CWF_STRING_LIMIT)) ||
|
||||
(cp <= def->cd_name + CALMANAMELENGTH))
|
||||
{
|
||||
/* Yes, it's legal: use it */
|
||||
(void) strcpy(defname, def->cd_name);
|
||||
defname = StrDup(NULL, def->cd_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1352,12 +1356,14 @@ calmaOutStructName(type, def, f)
|
|||
bad:
|
||||
calmanum = (int) def->cd_client;
|
||||
if (calmanum < 0) calmanum = -calmanum;
|
||||
defname = (char *)mallocMagic(32);
|
||||
(void) sprintf(defname, "XXXXX%d", calmanum);
|
||||
TxError("Warning: string in output unprintable; changed to \'%s\'\n",
|
||||
defname);
|
||||
}
|
||||
|
||||
calmaOutStringRecord(type, defname, f);
|
||||
freeMagic(defname);
|
||||
}
|
||||
|
||||
/* Added by NP 8/21/2004 */
|
||||
|
|
@ -2734,7 +2740,7 @@ calmaOutDate(t, f)
|
|||
void
|
||||
calmaOutStringRecord(type, str, f)
|
||||
int type; /* Type of this record (data type is ASCII string) */
|
||||
char *str; /* String to be output (<= CALMANAMELENGTH chars) */
|
||||
char *str; /* String to be output */
|
||||
FILE *f; /* Stream file */
|
||||
{
|
||||
int len;
|
||||
|
|
@ -2759,9 +2765,16 @@ calmaOutStringRecord(type, str, f)
|
|||
* last CALMANAMELENGTH characters (since cell names are more
|
||||
* likely to be unique in the last characters than in the first
|
||||
* characters).
|
||||
*
|
||||
* NOTE: GDS format has not used CALMANAMELENGTH restrictions
|
||||
* for ages. Since this is a 2-byte record, then is it not
|
||||
* worth checking the 65536 - 4 character limit. The CALMANAMELENGTH
|
||||
* restriction must be enabled in the cifoutput flags.
|
||||
*/
|
||||
|
||||
|
||||
if (len & 01) len++;
|
||||
if (len > CALMANAMELENGTH)
|
||||
if ((CIFCurStyle->cs_flags & CWF_STRING_LIMIT) && (len > CALMANAMELENGTH))
|
||||
{
|
||||
TxError("Warning: Cellname %s truncated ", str);
|
||||
TxError("to %s (GDS format limit)\n", str + len - CALMANAMELENGTH);
|
||||
|
|
|
|||
461
cif/CIFgen.c
461
cif/CIFgen.c
|
|
@ -111,6 +111,177 @@ cifPaintFunc(tile, table)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifGrowMinFunc --
|
||||
*
|
||||
* Called for each relevant tile during grow-min operations.
|
||||
*
|
||||
* Results:
|
||||
* Always returns 0 to keep the search alive.
|
||||
*
|
||||
* Side effects:
|
||||
* May paint into cifNewPlane
|
||||
*
|
||||
* Algorithm (based on maximum horizontal stripes rule):
|
||||
* Scan top and bottom boundaries from left to right. For any
|
||||
* distance (including distance zero) sharing the same type (0 or 1)
|
||||
* on both the tile top and bottom, find the diagonal length. If
|
||||
* less than co_distance, then expand this area and paint.
|
||||
* NOTE: This algorithm does not cover a number of geometry cases
|
||||
* and needs to be reworked. It should be restricted to cases of
|
||||
* layers that have "rect_only" DRC rules. Since the rule is usually
|
||||
* needed for implants on FET gates to maintain the implant width for
|
||||
* small gates, the "rect_only" requirement is not particularly
|
||||
* constraining.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifGrowMinFunc(tile, table)
|
||||
Tile *tile;
|
||||
PaintResultType *table; /* Table to be used for painting. */
|
||||
{
|
||||
Rect area, parea;
|
||||
int locDist, width, height, h;
|
||||
TileType type, tptype;
|
||||
Tile *tp, *tp2;
|
||||
|
||||
TiToRect(tile, &area);
|
||||
|
||||
area.r_xbot *= cifScale;
|
||||
area.r_xtop *= cifScale;
|
||||
area.r_ybot *= cifScale;
|
||||
area.r_ytop *= cifScale;
|
||||
|
||||
parea = area;
|
||||
|
||||
/* Check whole tile for minimum width */
|
||||
width = area.r_xtop - area.r_xbot;
|
||||
if (width < growDistance)
|
||||
{
|
||||
locDist = (growDistance - width) / 2;
|
||||
area.r_xbot -= locDist;
|
||||
area.r_xtop += locDist;
|
||||
|
||||
/* If there is another tile on top or bottom, and the height is */
|
||||
/* less than minimum, then extend height in the direction of */
|
||||
/* the bordering tile. Otherwise, if the height is less than */
|
||||
/* minimum, then grow halfway in both directions. */
|
||||
|
||||
height = area.r_ytop - area.r_ybot;
|
||||
if (height < growDistance)
|
||||
{
|
||||
bool freeTop, freeBot;
|
||||
|
||||
freeTop = freeBot = TRUE;
|
||||
|
||||
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
||||
if (TiGetTopType(tp) == TiGetBottomType(tile))
|
||||
{
|
||||
freeBot = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
for (tp2 = RT(tile); RIGHT(tp2) > LEFT(tile); tp2 = BL(tp2))
|
||||
if (TiGetBottomType(tp2) == TiGetTopType(tile))
|
||||
{
|
||||
freeTop = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* In the following, value h ensures that the euclidean */
|
||||
/* distance between inside corners of the layer */
|
||||
/* satisfies growDistance. */
|
||||
|
||||
if (freeTop == TRUE && freeBot == FALSE)
|
||||
{
|
||||
locDist = (growDistance - height) / 2;
|
||||
h = (int)sqrt((double)(growDistance * growDistance) -
|
||||
0.25 * (double)((growDistance + width) *
|
||||
(growDistance + width)) + 0.5);
|
||||
area.r_ybot -= h;
|
||||
}
|
||||
else if (freeTop == FALSE && freeBot == TRUE)
|
||||
{
|
||||
h = (int)sqrt((double)(growDistance * growDistance) -
|
||||
0.25 * (double)((growDistance + width) *
|
||||
(growDistance + width)) + 0.5);
|
||||
area.r_ytop += h;
|
||||
}
|
||||
else {
|
||||
locDist = (growDistance - height) / 2;
|
||||
area.r_ybot -= locDist;
|
||||
area.r_ytop += locDist;
|
||||
}
|
||||
}
|
||||
}
|
||||
DBPaintPlane(cifPlane, &area, table, (PaintUndoInfo *) NULL);
|
||||
|
||||
area = parea;
|
||||
|
||||
/* Scan bottom from left to right */
|
||||
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
||||
{
|
||||
tptype = TiGetTopType(tp);
|
||||
/* Scan top from right to left across range of tp */
|
||||
for (tp2 = RT(tile); RIGHT(tp2) > LEFT(tile); tp2 = BL(tp2))
|
||||
if (TiGetBottomType(tp2) == tptype)
|
||||
{
|
||||
/* Set range to length of overlap */
|
||||
if ((LEFT(tp2) <= RIGHT(tp)) && (LEFT(tp2) >= LEFT(tp)))
|
||||
{
|
||||
area.r_xbot = LEFT(tp2) < LEFT(tile) ? LEFT(tile) : LEFT(tp2);
|
||||
area.r_xtop = RIGHT(tp) > RIGHT(tile) ? RIGHT(tile) : RIGHT(tp);
|
||||
}
|
||||
else if ((RIGHT(tp2) >= LEFT(tp)) && (RIGHT(tp2) <= RIGHT(tp)))
|
||||
{
|
||||
area.r_xbot = LEFT(tp) < LEFT(tile) ? LEFT(tile) : LEFT(tp);
|
||||
area.r_xtop = RIGHT(tp2) > RIGHT(tile) ? RIGHT(tile) : RIGHT(tp2);
|
||||
}
|
||||
else continue;
|
||||
|
||||
area.r_xbot *= cifScale;
|
||||
area.r_xtop *= cifScale;
|
||||
|
||||
/* Does area violate minimum width requirement? */
|
||||
width = area.r_xtop - area.r_xbot;
|
||||
height = area.r_ytop - area.r_ybot;
|
||||
|
||||
/* Manhattan requirement (to-do: Euclidean) */
|
||||
if (width < growDistance)
|
||||
{
|
||||
locDist = (growDistance - width) / 2;
|
||||
parea.r_xbot = area.r_xbot - locDist;
|
||||
parea.r_xtop = area.r_xtop + locDist;
|
||||
}
|
||||
else
|
||||
{
|
||||
parea.r_xbot = area.r_xbot;
|
||||
parea.r_xtop = area.r_xtop;
|
||||
}
|
||||
if (height < growDistance)
|
||||
{
|
||||
locDist = (growDistance - height) / 2;
|
||||
parea.r_ybot = area.r_ybot - locDist;
|
||||
parea.r_ytop = area.r_ytop + locDist;
|
||||
}
|
||||
else
|
||||
{
|
||||
parea.r_ybot = area.r_ybot;
|
||||
parea.r_ytop = area.r_ytop;
|
||||
}
|
||||
if ((width < growDistance) || (height < growDistance))
|
||||
DBPaintPlane(cifPlane, &parea, table, (PaintUndoInfo *) NULL);
|
||||
}
|
||||
}
|
||||
|
||||
CIFTileOps += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -514,7 +685,7 @@ cifGrowFunc(tile, table)
|
|||
CIFTileOps += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -842,6 +1013,46 @@ endbloat:
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define CIF_PENDING 0
|
||||
#define CIF_UNPROCESSED CLIENTDEFAULT
|
||||
#define CIF_PROCESSED 1
|
||||
#define CIF_IGNORE 2
|
||||
|
||||
#define PUSHTILE(tp, stack) \
|
||||
if ((tp)->ti_client == (ClientData) CIF_UNPROCESSED) { \
|
||||
(tp)->ti_client = (ClientData) CIF_PENDING; \
|
||||
STACKPUSH((ClientData) (tp), stack); \
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------
|
||||
*
|
||||
* cifFoundFunc --
|
||||
*
|
||||
* Find the first tile in the given area.
|
||||
*
|
||||
* Results:
|
||||
* Return 1 to stop the search and process.
|
||||
* Set clientData to the tile found.
|
||||
*
|
||||
*-------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifFoundFunc(tile, BloatStackPtr)
|
||||
Tile *tile;
|
||||
Stack **BloatStackPtr;
|
||||
{
|
||||
PUSHTILE(tile, *BloatStackPtr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Data structure for bloat-all function */
|
||||
typedef struct _bloatStruct {
|
||||
CIFOp *op;
|
||||
CellDef *def;
|
||||
} BloatStruct;
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -861,30 +1072,26 @@ endbloat:
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define CIF_PENDING 0
|
||||
#define CIF_UNPROCESSED CLIENTDEFAULT
|
||||
#define CIF_PROCESSED 1
|
||||
#define CIF_IGNORE 2
|
||||
|
||||
#define PUSHTILE(tp, stack) \
|
||||
if ((tp)->ti_client == (ClientData) CIF_UNPROCESSED) { \
|
||||
(tp)->ti_client = (ClientData) CIF_PENDING; \
|
||||
STACKPUSH((ClientData) (tp), stack); \
|
||||
}
|
||||
|
||||
int
|
||||
cifBloatAllFunc(tile, op)
|
||||
cifBloatAllFunc(tile, bls)
|
||||
Tile *tile; /* The tile to be processed. */
|
||||
CIFOp *op; /* Describes the operation to be performed */
|
||||
BloatStruct *bls;
|
||||
{
|
||||
Rect area;
|
||||
TileTypeBitMask connect;
|
||||
Tile *t, *tp;
|
||||
TileType type;
|
||||
BloatData *bloats = (BloatData *)op->co_client;
|
||||
int i;
|
||||
BloatData *bloats;
|
||||
int i, locScale;
|
||||
PlaneMask pmask;
|
||||
CIFOp *op;
|
||||
CellDef *def;
|
||||
static Stack *BloatStack = (Stack *)NULL;
|
||||
|
||||
op = bls->op;
|
||||
def = bls->def;
|
||||
bloats = (BloatData *)op->co_client;
|
||||
|
||||
/* Create a mask of all connecting types (these must be in a single
|
||||
* plane), then call a search function to find all connecting material
|
||||
* of these types.
|
||||
|
|
@ -900,7 +1107,38 @@ cifBloatAllFunc(tile, op)
|
|||
if (BloatStack == (Stack *)NULL)
|
||||
BloatStack = StackNew(64);
|
||||
|
||||
PUSHTILE(tile, BloatStack);
|
||||
/* If the type of the tile to be processed is not in the same plane */
|
||||
/* as the bloat type(s), then find any tile under the tile to be */
|
||||
/* processed that belongs to the connect mask, and use that as the */
|
||||
/* starting tile. */
|
||||
|
||||
t = tile;
|
||||
type = TiGetType(tile);
|
||||
if (type == CIF_SOLIDTYPE)
|
||||
{
|
||||
pmask = 0;
|
||||
locScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
|
||||
|
||||
/* Get the tile into magic database coordinates if it's in CIF coords */
|
||||
TiToRect(tile, &area);
|
||||
area.r_xbot /= locScale;
|
||||
area.r_xtop /= locScale;
|
||||
area.r_ybot /= locScale;
|
||||
area.r_ytop /= locScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
int pNum = DBPlane(type);
|
||||
pmask = CoincidentPlanes(&connect, PlaneNumToMaskBit(pNum));
|
||||
if (pmask == 0) TiToRect(tile, &area);
|
||||
locScale = cifScale;
|
||||
}
|
||||
if (pmask == 0)
|
||||
DBSrPaintArea((Tile *)NULL, def->cd_planes[bloats->bl_plane], &area,
|
||||
&connect, cifFoundFunc, (ClientData)(&BloatStack));
|
||||
else
|
||||
PUSHTILE(t, BloatStack);
|
||||
|
||||
while (!StackEmpty(BloatStack))
|
||||
{
|
||||
t = (Tile *) STACKPOP(BloatStack);
|
||||
|
|
@ -910,10 +1148,10 @@ cifBloatAllFunc(tile, op)
|
|||
/* Get the tile into CIF coordinates. */
|
||||
|
||||
TiToRect(t, &area);
|
||||
area.r_xbot *= cifScale;
|
||||
area.r_ybot *= cifScale;
|
||||
area.r_xtop *= cifScale;
|
||||
area.r_ytop *= cifScale;
|
||||
area.r_xbot *= locScale;
|
||||
area.r_ybot *= locScale;
|
||||
area.r_xtop *= locScale;
|
||||
area.r_ytop *= locScale;
|
||||
|
||||
DBNMPaintPlane(cifPlane, TiGetTypeExact(t), &area,
|
||||
CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
|
|
@ -982,6 +1220,134 @@ cifBloatAllFunc(tile, op)
|
|||
return 0; /* Keep the search alive. . . */
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifCloseFunc --
|
||||
*
|
||||
* Called for each relevant tile during close operations.
|
||||
*
|
||||
* Results:
|
||||
* Always returns 0 to keep the search alive.
|
||||
*
|
||||
* Side effects:
|
||||
* Paints into cifNewPlane. Tiles in old plane are tagged with
|
||||
* a static value in ClientData, which does not need to be reset
|
||||
* since the old plane will be free'd.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define CLOSE_SEARCH 0
|
||||
#define CLOSE_FILL 1
|
||||
#define CLOSE_DONE 2
|
||||
|
||||
int
|
||||
cifCloseFunc(tile, plane)
|
||||
Tile *tile;
|
||||
Plane *plane;
|
||||
{
|
||||
Rect area, newarea;
|
||||
int atotal;
|
||||
int cifGatherFunc();
|
||||
|
||||
/* If tile is marked, then it has been handled, so ignore it */
|
||||
if (tile->ti_client != (ClientData)CIF_UNPROCESSED) return 0;
|
||||
|
||||
atotal = 0;
|
||||
|
||||
/* Search all sides for connected space tiles, and accumulate the total */
|
||||
/* area. If any connected tile borders infinity, then stop searching */
|
||||
/* because the area is not enclosed. */
|
||||
|
||||
cifGatherFunc(tile, &atotal, CLOSE_SEARCH);
|
||||
|
||||
/* If the total area is smaller than the rule area, then paint all the */
|
||||
/* tile areas into the destination plane. */
|
||||
|
||||
if ((atotal != INFINITY) && (atotal < growDistance))
|
||||
cifGatherFunc(tile, &atotal, CLOSE_FILL);
|
||||
else
|
||||
cifGatherFunc(tile, &atotal, CLOSE_DONE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
cifGatherFunc(tile, atotal, mode)
|
||||
Tile *tile;
|
||||
int *atotal;
|
||||
bool mode;
|
||||
{
|
||||
Tile *tp;
|
||||
TileType type;
|
||||
dlong locarea;
|
||||
Rect area, newarea;
|
||||
ClientData cdata = (mode == CLOSE_SEARCH) ? (ClientData)CIF_UNPROCESSED :
|
||||
(ClientData)CIF_PENDING;
|
||||
|
||||
/* Ignore if tile has already been processed */
|
||||
if (tile->ti_client != cdata) return 0;
|
||||
|
||||
TiToRect(tile, &area);
|
||||
|
||||
/* Boundary tiles indicate an unclosed area, so set the area total to */
|
||||
/* INFINITY and don't try to run calculations on it. */
|
||||
|
||||
if ((area.r_xbot == TiPlaneRect.r_xbot) || (area.r_ybot == TiPlaneRect.r_ybot) ||
|
||||
(area.r_xtop == TiPlaneRect.r_xtop) || (area.r_ytop == TiPlaneRect.r_ytop))
|
||||
*atotal = INFINITY;
|
||||
|
||||
/* Stop accumulating if already larger than growDistance to avoid the */
|
||||
/* possibility of integer overflow. */
|
||||
if (mode == CLOSE_SEARCH)
|
||||
{
|
||||
if ((*atotal != INFINITY) && (*atotal < growDistance))
|
||||
locarea = (dlong)(area.r_xtop - area.r_xbot)
|
||||
* (dlong)(area.r_ytop - area.r_ybot);
|
||||
if (locarea > (dlong)INFINITY)
|
||||
*atotal = INFINITY;
|
||||
else
|
||||
*atotal += (int)locarea;
|
||||
}
|
||||
else if (mode == CLOSE_FILL)
|
||||
{
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *)NULL);
|
||||
CIFTileOps++;
|
||||
}
|
||||
|
||||
if (mode == CLOSE_SEARCH)
|
||||
tile->ti_client = (ClientData)CIF_PENDING;
|
||||
else
|
||||
tile->ti_client = (ClientData)CIF_PROCESSED;
|
||||
|
||||
/* Look for additional neighboring space tiles */
|
||||
/* Check top */
|
||||
if (area.r_ytop != TiPlaneRect.r_ytop)
|
||||
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
|
||||
if (tp->ti_client == cdata && TiGetType(tp) == TT_SPACE)
|
||||
cifGatherFunc(tp, atotal, mode);
|
||||
|
||||
/* Check bottom */
|
||||
if (area.r_ybot != TiPlaneRect.r_ybot)
|
||||
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
||||
if (tp->ti_client == cdata && TiGetType(tp) == TT_SPACE)
|
||||
cifGatherFunc(tp, atotal, mode);
|
||||
|
||||
/* Check left */
|
||||
if (area.r_xbot != TiPlaneRect.r_xbot)
|
||||
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
||||
if (tp->ti_client == cdata && TiGetType(tp) == TT_SPACE)
|
||||
cifGatherFunc(tp, atotal, mode);
|
||||
|
||||
/* Check right */
|
||||
if (area.r_xtop != TiPlaneRect.r_xtop)
|
||||
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
|
||||
if (tp->ti_client == cdata && TiGetType(tp) == TT_SPACE)
|
||||
cifGatherFunc(tp, atotal, mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Support routines and definitions for cifSquaresFillArea */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
|
@ -1310,7 +1676,7 @@ cifRectBoundingBox(op, cellDef, plane)
|
|||
}
|
||||
else
|
||||
{
|
||||
maxr = FindMaxRectangle2(&bbox, tile, plane);
|
||||
maxr = FindMaxRectangle2(&bbox, tile, plane, NULL);
|
||||
DBPaintPlane(cifPlane, maxr, CIFPaintTable, (PaintUndoInfo *)NULL);
|
||||
CIFTileOps++;
|
||||
}
|
||||
|
|
@ -1723,7 +2089,7 @@ cifSlotsFillArea(op, cellDef, plane)
|
|||
{
|
||||
Tile *tile, *t, *tp;
|
||||
Rect bbox, area, square, cut, llcut;
|
||||
int nAcross, nUp, left, spitch, lpitch, ssize, lsize;
|
||||
int nAcross, nUp, left, spitch, lpitch, ssize, lsize, offset;
|
||||
int diff, right;
|
||||
int xpitch, ypitch, xborder, yborder, xdiff, ydiff;
|
||||
int i, j, k, savecount;
|
||||
|
|
@ -1944,16 +2310,17 @@ cifSlotsFillArea(op, cellDef, plane)
|
|||
|
||||
cifSlotFunc(&bbox, op, &nUp, &nAcross, &llcut, vertical);
|
||||
|
||||
cut.r_ybot = llcut.r_ybot;
|
||||
cut.r_ytop = llcut.r_ytop;
|
||||
cut.r_ybot = llcut.r_ybot + slots->sl_start;
|
||||
cut.r_ytop = llcut.r_ytop + slots->sl_start;
|
||||
|
||||
/* For each contact cut area, check that there is */
|
||||
/* no whitespace */
|
||||
|
||||
offset = slots->sl_start;
|
||||
for (i = 0; i < nUp; i++)
|
||||
{
|
||||
cut.r_xbot = llcut.r_xbot;
|
||||
cut.r_xtop = llcut.r_xtop;
|
||||
cut.r_xbot = llcut.r_xbot + offset;
|
||||
cut.r_xtop = llcut.r_xtop + offset;
|
||||
|
||||
square.r_ybot = cut.r_ybot - yborder;
|
||||
square.r_ytop = cut.r_ytop + yborder;
|
||||
|
|
@ -1980,6 +2347,8 @@ cifSlotsFillArea(op, cellDef, plane)
|
|||
}
|
||||
cut.r_ybot += ypitch;
|
||||
cut.r_ytop += ypitch;
|
||||
offset += slots->sl_offset;
|
||||
if (offset >= xpitch) offset -= xpitch;
|
||||
}
|
||||
if (savecount != CIFTileOps) break;
|
||||
|
||||
|
|
@ -2688,6 +3057,7 @@ cifSrTiles(cifOp, area, cellDef, temps, func, cdArg)
|
|||
{
|
||||
TileTypeBitMask maskBits;
|
||||
TileType t;
|
||||
Tile *tp;
|
||||
int i;
|
||||
BloatData *bloats;
|
||||
|
||||
|
|
@ -2699,7 +3069,7 @@ cifSrTiles(cifOp, area, cellDef, temps, func, cdArg)
|
|||
|
||||
cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
|
||||
|
||||
/* Bloat operations have to be in a single plane */
|
||||
/* Bloat operations (except bloat-all) have to be in a single plane */
|
||||
|
||||
switch (cifOp->co_opcode) {
|
||||
case CIFOP_BLOAT:
|
||||
|
|
@ -2783,6 +3153,7 @@ CIFGenLayer(op, area, cellDef, temps, clientdata)
|
|||
SearchContext scx;
|
||||
TileType ttype;
|
||||
char *netname;
|
||||
BloatStruct bls;
|
||||
int (*cifGrowFuncPtr)() = (CIFCurStyle->cs_flags & CWF_GROW_EUCLIDEAN) ?
|
||||
cifGrowEuclideanFunc : cifGrowFunc;
|
||||
|
||||
|
|
@ -2926,6 +3297,20 @@ CIFGenLayer(op, area, cellDef, temps, clientdata)
|
|||
nextPlane = temp;
|
||||
break;
|
||||
|
||||
/* GROWMIN grows non-uniformly to ensure minimum dimensions */
|
||||
|
||||
case CIFOP_GROWMIN:
|
||||
growDistance = op->co_distance;
|
||||
DBClearPaintPlane(nextPlane);
|
||||
cifPlane = nextPlane;
|
||||
cifScale = 1;
|
||||
(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
|
||||
&CIFSolidBits, cifGrowMinFunc, (ClientData)CIFPaintTable);
|
||||
temp = curPlane;
|
||||
curPlane = nextPlane;
|
||||
nextPlane = temp;
|
||||
break;
|
||||
|
||||
/* GROW_G grows non-uniformly to the indicated grid. */
|
||||
|
||||
case CIFOP_GROW_G:
|
||||
|
|
@ -2956,6 +3341,22 @@ CIFGenLayer(op, area, cellDef, temps, clientdata)
|
|||
nextPlane = temp;
|
||||
break;
|
||||
|
||||
case CIFOP_CLOSE:
|
||||
growDistance = op->co_distance;
|
||||
DBClearPaintPlane(nextPlane);
|
||||
cifPlane = nextPlane;
|
||||
cifScale = 1;
|
||||
/* First copy the existing paint into the target plane */
|
||||
(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
|
||||
&CIFSolidBits, cifPaintFunc, (ClientData)CIFPaintTable);
|
||||
|
||||
(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
|
||||
&DBSpaceBits, cifCloseFunc, (ClientData)&curPlane);
|
||||
temp = curPlane;
|
||||
curPlane = nextPlane;
|
||||
nextPlane = temp;
|
||||
break;
|
||||
|
||||
case CIFOP_BLOAT:
|
||||
cifPlane = curPlane;
|
||||
cifSrTiles(op, area, cellDef, temps,
|
||||
|
|
@ -2971,8 +3372,10 @@ CIFGenLayer(op, area, cellDef, temps, clientdata)
|
|||
|
||||
case CIFOP_BLOATALL:
|
||||
cifPlane = curPlane;
|
||||
bls.op = op;
|
||||
bls.def = cellDef;
|
||||
cifSrTiles(op, area, cellDef, temps,
|
||||
cifBloatAllFunc, (ClientData) op);
|
||||
cifBloatAllFunc, (ClientData)&bls);
|
||||
break;
|
||||
|
||||
case CIFOP_SQUARES:
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
37
cif/CIFint.h
37
cif/CIFint.h
|
|
@ -69,6 +69,7 @@ typedef struct slots_data
|
|||
int sl_lsize;
|
||||
int sl_lsep;
|
||||
int sl_offset;
|
||||
int sl_start;
|
||||
} SlotsData;
|
||||
|
||||
typedef struct cifop
|
||||
|
|
@ -95,6 +96,7 @@ typedef struct cifop
|
|||
* the masks.
|
||||
* CIFOP_GROW - Grow the current results uniformly by co_distance.
|
||||
* CIFOP_GROW_G - Grow the current results to snap to the indicated grid.
|
||||
* CIFOP_GROWMIN - Grow result such that no dimension is less than co_distance.
|
||||
* CIFOP_SHRINK - Shrink the current results uniformly by co_distance.
|
||||
* CIFOP_BLOAT - Find layers in paintMask, then bloat selectively
|
||||
* according to bl_distance, and OR the results into
|
||||
|
|
@ -130,26 +132,29 @@ typedef struct cifop
|
|||
* CIFOP_COPYUP - Added 5/5/16---make and keep a copy the resulting layer,
|
||||
* which will be painted into parent cells instead of the
|
||||
* current cell. This replaces the "fault" method.
|
||||
* CIFOP_CLOSE - Added 11/25/19---close up areas smaller than indicated
|
||||
*/
|
||||
|
||||
#define CIFOP_AND 1
|
||||
#define CIFOP_OR 2
|
||||
#define CIFOP_GROW 3
|
||||
#define CIFOP_GROW_G 4
|
||||
#define CIFOP_SHRINK 5
|
||||
#define CIFOP_BLOAT 6
|
||||
#define CIFOP_SQUARES 7
|
||||
#define CIFOP_SLOTS 8
|
||||
#define CIFOP_BLOATMAX 9
|
||||
#define CIFOP_BLOATMIN 10
|
||||
#define CIFOP_BLOATALL 11
|
||||
#define CIFOP_ANDNOT 12
|
||||
#define CIFOP_SQUARES_G 13
|
||||
#define CIFOP_BBOX 14
|
||||
#define CIFOP_BOUNDARY 15
|
||||
#define CIFOP_NET 16
|
||||
#define CIFOP_MAXRECT 17
|
||||
#define CIFOP_COPYUP 18
|
||||
#define CIFOP_GROWMIN 4
|
||||
#define CIFOP_GROW_G 5
|
||||
#define CIFOP_SHRINK 6
|
||||
#define CIFOP_BLOAT 7
|
||||
#define CIFOP_SQUARES 8
|
||||
#define CIFOP_SLOTS 9
|
||||
#define CIFOP_BLOATMAX 10
|
||||
#define CIFOP_BLOATMIN 11
|
||||
#define CIFOP_BLOATALL 12
|
||||
#define CIFOP_ANDNOT 13
|
||||
#define CIFOP_SQUARES_G 14
|
||||
#define CIFOP_BBOX 15
|
||||
#define CIFOP_BOUNDARY 16
|
||||
#define CIFOP_NET 17
|
||||
#define CIFOP_MAXRECT 18
|
||||
#define CIFOP_COPYUP 19
|
||||
#define CIFOP_CLOSE 20
|
||||
|
||||
/* Added by Tim 10/21/2004 */
|
||||
/* The following structure is used to pass information on how to draw
|
||||
|
|
@ -292,6 +297,7 @@ typedef struct cifstyle
|
|||
#define CWF_GROW_EUCLIDEAN 0x08
|
||||
#define CWF_SEE_VENDOR 0x10 /* Override vendor GDS flag in cells */
|
||||
#define CWF_NO_ERRORS 0x20 /* Do not generate error msgs and fdbk */
|
||||
#define CWF_STRING_LIMIT 0x40 /* Use older Calma format character limit */
|
||||
|
||||
/* procedures */
|
||||
|
||||
|
|
@ -310,6 +316,7 @@ extern void CIFLoadStyle();
|
|||
extern Plane *CIFPlanes[]; /* Normal place to store CIF. */
|
||||
extern CIFKeep *CIFStyleList; /* List of all CIF styles. */
|
||||
extern CIFStyle *CIFCurStyle; /* Current style being used. */
|
||||
extern CIFStyle *CIFDRCStyle; /* CIF style for DRC checking (optional) */
|
||||
extern CellUse *CIFComponentUse; /* Flatten stuff in here if needed. */
|
||||
extern CellDef *CIFComponentDef; /* Corresponds to CIFComponentUse. */
|
||||
extern CellUse *CIFDummyUse; /* Used to dummy up a CellUse for a
|
||||
|
|
|
|||
|
|
@ -752,7 +752,7 @@ cifMakeBoundaryFunc(tile, clientdata)
|
|||
CIFReadError("Warning: Cell %s boundary was redefined.\n",
|
||||
cifReadCellDef->cd_name);
|
||||
else
|
||||
CalmaError("Warning: Cell %s boundary was redefined.\n",
|
||||
CalmaReadError("Warning: Cell %s boundary was redefined.\n",
|
||||
cifReadCellDef->cd_name);
|
||||
}
|
||||
}
|
||||
|
|
@ -1508,13 +1508,18 @@ CIFReadCellCleanup(filetype)
|
|||
freeMagic((char *)def->cd_client);
|
||||
def->cd_client = (ClientData)CLIENTDEFAULT;
|
||||
|
||||
#if 0
|
||||
/* If the CDFLATTENED flag was not set, then this geometry */
|
||||
/* was never instantiated, and should generate a warning. */
|
||||
/* was never instantiated, and should generate a message. */
|
||||
/* However, this is not an error condition as there are a */
|
||||
/* number of useful reasons to copy lots of information up */
|
||||
/* the GDS hierarchy for "just in case" scenarios. */
|
||||
|
||||
if (!(def->cd_flags & CDFLATTENED))
|
||||
CIFReadError("%s read error: Unresolved geometry in cell"
|
||||
CIFReadWarning("%s read: Unresolved geometry in cell"
|
||||
" %s maps to no magic layers\n",
|
||||
(filetype == FILE_CIF) ? "CIF" : "GDS", def->cd_name);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* Remove the cell if it has no parents, no children, and no geometry */
|
||||
|
|
|
|||
|
|
@ -621,8 +621,10 @@ CIFReadTechLine(sectionName, argc, argv)
|
|||
|
||||
if (argc >= 3)
|
||||
{
|
||||
if(!strncmp(argv[argc - 1], "nanom", 5))
|
||||
if (!strncmp(argv[argc - 1], "nanom", 5))
|
||||
cifCurReadStyle->crs_multiplier = 10;
|
||||
else if (!strncmp(argv[argc - 1], "angstr", 6))
|
||||
cifCurReadStyle->crs_multiplier = 100;
|
||||
}
|
||||
|
||||
if (cifCurReadStyle->crs_scaleFactor <= 0)
|
||||
|
|
|
|||
|
|
@ -120,7 +120,10 @@ CIFReadError(char *format, ...)
|
|||
if (CIFWarningLevel == CIF_WARN_NONE) return;
|
||||
if ((cifTotalErrors < 100) || (CIFWarningLevel != CIF_WARN_LIMIT))
|
||||
{
|
||||
TxError("Error at line %d of CIF file: ", cifLineNumber);
|
||||
if (cifLineNumber > 0)
|
||||
TxError("Error at line %d of CIF file: ", cifLineNumber);
|
||||
else
|
||||
TxError("CIF file read error: ", cifLineNumber);
|
||||
va_start(args, format);
|
||||
Vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
|
|
@ -141,7 +144,10 @@ CIFReadWarning(char *format, ...)
|
|||
if (CIFWarningLevel == CIF_WARN_NONE) return;
|
||||
if ((cifTotalWarnings < 100) || (CIFWarningLevel != CIF_WARN_LIMIT))
|
||||
{
|
||||
TxError("Warning at line %d of CIF file: ", cifLineNumber);
|
||||
if (cifLineNumber > 0)
|
||||
TxError("Warning at line %d of CIF file: ", cifLineNumber);
|
||||
else
|
||||
TxError("CIF file read warning: ");
|
||||
va_start(args, format);
|
||||
Vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
|
|
|
|||
|
|
@ -994,6 +994,8 @@ CIFTechLine(sectionName, argc, argv)
|
|||
CIFCurStyle->cs_flags |= CWF_SEE_VENDOR;
|
||||
else if (strcmp(argv[i], "no-errors") == 0)
|
||||
CIFCurStyle->cs_flags |= CWF_NO_ERRORS;
|
||||
else if (strcmp(argv[i], "string-limit") == 0)
|
||||
CIFCurStyle->cs_flags |= CWF_STRING_LIMIT;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -1023,6 +1025,8 @@ CIFTechLine(sectionName, argc, argv)
|
|||
newOp->co_opcode = CIFOP_OR;
|
||||
else if (strcmp(argv[0], "grow") == 0)
|
||||
newOp->co_opcode = CIFOP_GROW;
|
||||
else if (strcmp(argv[0], "grow-min") == 0)
|
||||
newOp->co_opcode = CIFOP_GROWMIN;
|
||||
else if (strcmp(argv[0], "grow-grid") == 0)
|
||||
newOp->co_opcode = CIFOP_GROW_G;
|
||||
else if (strcmp(argv[0], "shrink") == 0)
|
||||
|
|
@ -1049,6 +1053,8 @@ CIFTechLine(sectionName, argc, argv)
|
|||
newOp->co_opcode = CIFOP_MAXRECT;
|
||||
else if (strcmp(argv[0], "boundary") == 0)
|
||||
newOp->co_opcode = CIFOP_BOUNDARY;
|
||||
else if (strcmp(argv[0], "close") == 0)
|
||||
newOp->co_opcode = CIFOP_CLOSE;
|
||||
else
|
||||
{
|
||||
TechError("Unknown statement \"%s\".\n", argv[0]);
|
||||
|
|
@ -1066,8 +1072,10 @@ CIFTechLine(sectionName, argc, argv)
|
|||
break;
|
||||
|
||||
case CIFOP_GROW:
|
||||
case CIFOP_GROWMIN:
|
||||
case CIFOP_GROW_G:
|
||||
case CIFOP_SHRINK:
|
||||
case CIFOP_CLOSE:
|
||||
if (argc != 2) goto wrongNumArgs;
|
||||
newOp->co_distance = atoi(argv[1]);
|
||||
if (newOp->co_distance <= 0)
|
||||
|
|
@ -1080,14 +1088,18 @@ CIFTechLine(sectionName, argc, argv)
|
|||
case CIFOP_BLOATALL:
|
||||
if (argc != 3) goto wrongNumArgs;
|
||||
cifParseLayers(argv[1], CIFCurStyle, &newOp->co_paintMask,
|
||||
(TileTypeBitMask *)NULL, FALSE);
|
||||
bloatLayers = newOp->co_paintMask;
|
||||
&newOp->co_cifMask, FALSE);
|
||||
bloats = (BloatData *)mallocMagic(sizeof(BloatData));
|
||||
for (i = 0; i < TT_MAXTYPES; i++)
|
||||
bloats->bl_distance[i] = 0;
|
||||
newOp->co_client = (ClientData)bloats;
|
||||
|
||||
cifParseLayers(argv[2], CIFCurStyle, &mask, &tempMask, TRUE);
|
||||
|
||||
/* 10/15/2019: Lifting restriction that the types that */
|
||||
/* trigger the bloating must be in the same plane as the */
|
||||
/* types that are bloated into. */
|
||||
|
||||
TTMaskZero(&bloatLayers);
|
||||
TTMaskSetMask(&bloatLayers, &mask);
|
||||
if (!TTMaskEqual(&tempMask, &DBZeroTypeBits))
|
||||
TechError("Can't use templayers in bloat statement.\n");
|
||||
|
|
@ -1323,6 +1335,7 @@ bloatCheck:
|
|||
slots->sl_lsize = 0;
|
||||
slots->sl_lsep = 0;
|
||||
slots->sl_offset = 0;
|
||||
slots->sl_start = 0;
|
||||
}
|
||||
if (argc >= 5)
|
||||
{
|
||||
|
|
@ -1357,7 +1370,7 @@ bloatCheck:
|
|||
goto errorReturn;
|
||||
}
|
||||
}
|
||||
if (argc == 8)
|
||||
if (argc >= 8)
|
||||
{
|
||||
i = atoi(argv[7]);
|
||||
slots->sl_offset = i;
|
||||
|
|
@ -1367,7 +1380,17 @@ bloatCheck:
|
|||
goto errorReturn;
|
||||
}
|
||||
}
|
||||
if ((argc < 4) || (argc == 6) || (argc > 8))
|
||||
if (argc == 9)
|
||||
{
|
||||
i = atoi(argv[8]);
|
||||
slots->sl_start = i;
|
||||
if (i < 0)
|
||||
{
|
||||
TechError("Slot start must be non-negative.\n");
|
||||
goto errorReturn;
|
||||
}
|
||||
}
|
||||
if ((argc < 4) || (argc == 6) || (argc > 9))
|
||||
goto wrongNumArgs;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1481,6 +1504,7 @@ cifComputeRadii(layer, des)
|
|||
case CIFOP_OR: break;
|
||||
|
||||
case CIFOP_GROW:
|
||||
case CIFOP_GROWMIN:
|
||||
case CIFOP_GROW_G:
|
||||
grow += op->co_distance;
|
||||
break;
|
||||
|
|
@ -1681,7 +1705,7 @@ CIFTechFinal()
|
|||
{
|
||||
slots = (SlotsData *)op->co_client;
|
||||
|
||||
for (j = 0; j < 7; j++)
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
switch (j) {
|
||||
case 0: bvalue = slots->sl_sborder; break;
|
||||
|
|
@ -1691,6 +1715,7 @@ CIFTechFinal()
|
|||
case 4: bvalue = slots->sl_lsize; break;
|
||||
case 5: bvalue = slots->sl_lsep; break;
|
||||
case 6: bvalue = slots->sl_offset; break;
|
||||
case 7: bvalue = slots->sl_start; break;
|
||||
}
|
||||
if (bvalue != 0)
|
||||
{
|
||||
|
|
@ -1945,7 +1970,7 @@ CIFLoadStyle(stylename)
|
|||
{
|
||||
SectionID invcif;
|
||||
|
||||
if (CIFCurStyle->cs_name == stylename) return;
|
||||
if (CIFCurStyle && (CIFCurStyle->cs_name == stylename)) return;
|
||||
|
||||
cifTechNewStyle();
|
||||
CIFCurStyle->cs_name = stylename;
|
||||
|
|
@ -2092,7 +2117,7 @@ CIFTechOutputScale(n, d)
|
|||
SquaresData *squares;
|
||||
SlotsData *slots;
|
||||
BloatData *bloats;
|
||||
bool has_odd_space;
|
||||
bool has_odd_space = FALSE;
|
||||
|
||||
if (ostyle == NULL) return;
|
||||
|
||||
|
|
@ -2189,7 +2214,7 @@ CIFTechOutputScale(n, d)
|
|||
else if (op->co_opcode == CIFOP_SLOTS)
|
||||
{
|
||||
slots = (SlotsData *)op->co_client;
|
||||
for (j = 0; j < 7; j++)
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
switch (j) {
|
||||
case 0: bptr = &slots->sl_sborder; break;
|
||||
|
|
@ -2199,6 +2224,7 @@ CIFTechOutputScale(n, d)
|
|||
case 4: bptr = &slots->sl_lsize; break;
|
||||
case 5: bptr = &slots->sl_lsep; break;
|
||||
case 6: bptr = &slots->sl_offset; break;
|
||||
case 7: bptr = &slots->sl_start; break;
|
||||
}
|
||||
if (*bptr != 0)
|
||||
{
|
||||
|
|
@ -2315,6 +2341,8 @@ CIFTechOutputScale(n, d)
|
|||
slots->sl_lsep /= lexpand;
|
||||
if (slots->sl_offset != 0)
|
||||
slots->sl_offset /= lexpand;
|
||||
if (slots->sl_start != 0)
|
||||
slots->sl_start /= lexpand;
|
||||
break;
|
||||
case CIFOP_SQUARES_G:
|
||||
squares = (SquaresData *)op->co_client;
|
||||
|
|
|
|||
|
|
@ -312,7 +312,8 @@ cifOut(outf)
|
|||
/* Read the cell in if it is not already available. */
|
||||
if ((def->cd_flags & CDAVAILABLE) == 0)
|
||||
{
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, NULL)) continue;
|
||||
bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, dereference, NULL)) continue;
|
||||
}
|
||||
|
||||
/* Add any subcells to the stack. This must be done before
|
||||
|
|
|
|||
|
|
@ -1434,7 +1434,7 @@ CmdCif(w, cmd)
|
|||
if (!ToolGetBox(&rootDef, &box))
|
||||
{
|
||||
TxError("Use the box to select the area in");
|
||||
TxError(" which you want to see CIF.\n");
|
||||
TxError(" which you want to paint CIF.\n");
|
||||
return;
|
||||
}
|
||||
if (argc == 5)
|
||||
|
|
@ -3079,7 +3079,7 @@ CmdDown(w, cmd)
|
|||
GeoTransRect(&EditToRootTransform, &(EditCellUse->cu_def->cd_bbox), &area);
|
||||
(void) WindSearch(DBWclientID, (ClientData) NULL,
|
||||
(Rect *) NULL, cmdEditRedisplayFunc, (ClientData) &area);
|
||||
DBWloadWindow(w, EditCellUse->cu_def->cd_name, TRUE, FALSE);
|
||||
DBWloadWindow(w, EditCellUse->cu_def->cd_name, TRUE, FALSE, FALSE);
|
||||
}
|
||||
|
||||
/* Search function to find the new edit cell: look for a cell use
|
||||
|
|
@ -3182,7 +3182,7 @@ CmdDrc(w, cmd)
|
|||
bool doforall = FALSE;
|
||||
bool dolist = FALSE;
|
||||
int count_total;
|
||||
DRCCountList *dcl, *dclsrch;
|
||||
DRCCountList *dcl;
|
||||
int argc = cmd->tx_argc;
|
||||
char **argv = cmd->tx_argv;
|
||||
#ifdef MAGIC_WRAPPER
|
||||
|
|
@ -3197,9 +3197,9 @@ CmdDrc(w, cmd)
|
|||
"*stepsize [d] change DRC step size to d units",
|
||||
"catchup run checker and wait for it to complete",
|
||||
"check recheck area under box in all cells",
|
||||
"count count error tiles in each cell under box",
|
||||
"count [total] count error tiles in each cell under box",
|
||||
"euclidean on|off enable/disable Euclidean geometry checking",
|
||||
"find [nth] locate next (or nth) error in the layout",
|
||||
"find [nth] locate next (or nth) error in the layout",
|
||||
"help print this help information",
|
||||
"off turn off background checker",
|
||||
"on reenable background checker",
|
||||
|
|
@ -3313,7 +3313,6 @@ CmdDrc(w, cmd)
|
|||
#ifdef MAGIC_WRAPPER
|
||||
if (count_total == -1) lobj = Tcl_NewListObj(0, NULL);
|
||||
#endif
|
||||
|
||||
if ((window = w) == NULL)
|
||||
{
|
||||
window = ToolGetBoxWindow(&rootArea, (int *) NULL);
|
||||
|
|
@ -3323,7 +3322,7 @@ CmdDrc(w, cmd)
|
|||
rootArea = w->w_surfaceArea;
|
||||
|
||||
rootUse = (CellUse *) window->w_surfaceID;
|
||||
dcl = DRCCount(rootUse, &rootArea);
|
||||
dcl = DRCCount(rootUse, &rootArea, doforall);
|
||||
while (dcl != NULL)
|
||||
{
|
||||
if (count_total >= 0)
|
||||
|
|
@ -3343,7 +3342,6 @@ CmdDrc(w, cmd)
|
|||
else
|
||||
{
|
||||
#endif
|
||||
|
||||
if (dcl->dcl_count > 1)
|
||||
TxPrintf("Cell %s has %d error tiles.\n",
|
||||
dcl->dcl_def->cd_name, dcl->dcl_count);
|
||||
|
|
@ -3372,11 +3370,12 @@ CmdDrc(w, cmd)
|
|||
}
|
||||
}
|
||||
else if (dolist)
|
||||
Tcl_SetObjResult(magicinterp, lobj);
|
||||
Tcl_SetObjResult(magicinterp, lobj);
|
||||
|
||||
#else
|
||||
if ((DRCBackGround != DRC_SET_OFF) && (count_total == -1))
|
||||
count_total = 0;
|
||||
if (count_total >= 0)
|
||||
if (count_gotal >= 0)
|
||||
TxPrintf("Total DRC errors found: %d\n", count_total);
|
||||
#endif
|
||||
break;
|
||||
|
|
@ -3677,7 +3676,7 @@ cmdDumpParseArgs(cmdName, w, cmd, dummy, scx)
|
|||
{
|
||||
Point childPoint, editPoint, rootPoint;
|
||||
CellDef *def, *rootDef, *editDef;
|
||||
bool hasChild, hasRoot, hasTrans;
|
||||
bool hasChild, hasRoot, hasTrans, dereference;
|
||||
Rect rootBox, bbox;
|
||||
Transform *tx_cell, trans_cell;
|
||||
char **av;
|
||||
|
|
@ -3777,7 +3776,8 @@ cmdDumpParseArgs(cmdName, w, cmd, dummy, scx)
|
|||
* looked for then no new error message will be printed.
|
||||
*/
|
||||
def->cd_flags &= ~CDNOTFOUND;
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, NULL))
|
||||
dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, dereference, NULL))
|
||||
return (FALSE);
|
||||
DBReComputeBbox(def);
|
||||
dummy->cu_def = def;
|
||||
|
|
|
|||
|
|
@ -130,7 +130,11 @@ CmdEdit(w, cmd)
|
|||
return;
|
||||
}
|
||||
else if (!(EditCellUse->cu_def->cd_flags & CDAVAILABLE))
|
||||
DBCellRead(EditCellUse->cu_def, (char *)NULL, TRUE, NULL);
|
||||
{
|
||||
bool dereference = (EditCellUse->cu_def->cd_flags & CDDEREFERENCE) ?
|
||||
TRUE : FALSE;
|
||||
DBCellRead(EditCellUse->cu_def, (char *)NULL, TRUE, dereference, NULL);
|
||||
}
|
||||
|
||||
if (EditCellUse->cu_def->cd_flags & CDNOEDIT)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1452,7 +1452,11 @@ CmdIdentify(w, cmd)
|
|||
return;
|
||||
}
|
||||
|
||||
if (CmdIllegalChars(cmd->tx_argv[1], "[],/", "Cell use id"))
|
||||
/* NOTE: Relaxing the definition of illegal characters in cell use IDs */
|
||||
/* by allowing brackets. Possibly the list can be reduced further. */
|
||||
|
||||
/* if (CmdIllegalChars(cmd->tx_argv[1], "[],/", "Cell use id")) */
|
||||
if (CmdIllegalChars(cmd->tx_argv[1], ",/", "Cell use id"))
|
||||
return;
|
||||
|
||||
if (SelEnumCells(FALSE, (int *) NULL, (SearchContext *) NULL,
|
||||
|
|
@ -1789,6 +1793,7 @@ FlatCopyAllLabels(scx, mask, xMask, targetUse)
|
|||
char pathstring[FLATTERMSIZE];
|
||||
TerminalPath tpath;
|
||||
|
||||
pathstring[0] = '\0';
|
||||
tpath.tp_first = tpath.tp_next = pathstring;
|
||||
tpath.tp_last = pathstring + FLATTERMSIZE;
|
||||
|
||||
|
|
|
|||
|
|
@ -318,7 +318,7 @@ CmdLabel(w, cmd)
|
|||
* Implement the "load" command.
|
||||
*
|
||||
* Usage:
|
||||
* load [name [scaled n [d]]] [-force]
|
||||
* load [name [scaled n [d]]] [-force] [-nowindow] [-dereference]
|
||||
*
|
||||
* If name is supplied, then the window containing the point tool is
|
||||
* remapped so as to edit the cell with the given name.
|
||||
|
|
@ -331,6 +331,13 @@ CmdLabel(w, cmd)
|
|||
* An input file can be scaled by specifying the "scaled" option, for
|
||||
* which the geometry of the input file is multiplied by n/d.
|
||||
*
|
||||
* Magic saves the path to instances to ensure correct versioning. But
|
||||
* this interferes with attempts to re-link instances from a different
|
||||
* location (such as an abstract view instead of a full view, or vice
|
||||
* versa). So the "-dereference" option strips the instance paths from
|
||||
* the input file and relies only on the search locations set up by the
|
||||
* "path" command to find the location of instances.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
|
|
@ -350,6 +357,7 @@ CmdLoad(w, cmd)
|
|||
int locargc = cmd->tx_argc;
|
||||
bool ignoreTech = FALSE;
|
||||
bool noWindow = FALSE;
|
||||
bool dereference = FALSE;
|
||||
int keepGoing(); /* forward declaration */
|
||||
|
||||
if (locargc > 2)
|
||||
|
|
@ -359,29 +367,38 @@ CmdLoad(w, cmd)
|
|||
locargc--;
|
||||
noWindow = TRUE;
|
||||
}
|
||||
if (!strncmp(cmd->tx_argv[locargc - 1], "-deref", 5))
|
||||
{
|
||||
locargc--;
|
||||
dereference = TRUE;
|
||||
}
|
||||
if (!strncmp(cmd->tx_argv[locargc - 1], "-force", 6))
|
||||
{
|
||||
locargc--;
|
||||
ignoreTech = TRUE;
|
||||
}
|
||||
if (locargc >= 4 && !strncmp(cmd->tx_argv[2], "scale", 5) &&
|
||||
if ((locargc >= 4) && !strncmp(cmd->tx_argv[2], "scale", 5) &&
|
||||
StrIsInt(cmd->tx_argv[3]))
|
||||
{
|
||||
n = atoi(cmd->tx_argv[3]);
|
||||
if (cmd->tx_argc == 5 && StrIsInt(cmd->tx_argv[4]))
|
||||
if ((locargc == 5) && StrIsInt(cmd->tx_argv[4]))
|
||||
d = atoi(cmd->tx_argv[4]);
|
||||
else if (locargc != 4)
|
||||
{
|
||||
TxError("Usage: %s name scaled n [d]\n", cmd->tx_argv[0]);
|
||||
TxError("Usage: %s name scaled n [d] [-force] "
|
||||
"[-nowindow] [-dereference]\n",
|
||||
cmd->tx_argv[0]);
|
||||
return;
|
||||
}
|
||||
DBLambda[0] *= d;
|
||||
DBLambda[1] *= n;
|
||||
ReduceFraction(&DBLambda[0], &DBLambda[1]);
|
||||
}
|
||||
else if (!ignoreTech && !noWindow)
|
||||
else if (!ignoreTech && !noWindow && !dereference)
|
||||
{
|
||||
TxError("Usage: %s [name [scaled n [d]]]\n", cmd->tx_argv[0]);
|
||||
TxError("Usage: %s name [scaled n [d]] [-force] "
|
||||
"[-nowindow] [-dereference]\n",
|
||||
cmd->tx_argv[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -406,7 +423,7 @@ CmdLoad(w, cmd)
|
|||
}
|
||||
#endif
|
||||
DBWloadWindow((noWindow == TRUE) ? NULL : w, cmd->tx_argv[1],
|
||||
ignoreTech, FALSE);
|
||||
ignoreTech, FALSE, dereference);
|
||||
|
||||
if ((n > 1) || (d > 1))
|
||||
{
|
||||
|
|
@ -439,7 +456,7 @@ CmdLoad(w, cmd)
|
|||
ReduceFraction(&DBLambda[0], &DBLambda[1]);
|
||||
}
|
||||
}
|
||||
else DBWloadWindow(w, (char *) NULL, TRUE, FALSE);
|
||||
else DBWloadWindow(w, (char *) NULL, TRUE, FALSE, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1882,8 +1899,16 @@ printPropertiesFunc(name, value)
|
|||
#ifdef MAGIC_WRAPPER
|
||||
char *keyvalue;
|
||||
|
||||
keyvalue = (char *)mallocMagic(strlen(name) + strlen((char *)value) + 2);
|
||||
sprintf(keyvalue, "%s %s", name, (char *)value);
|
||||
if (value == NULL)
|
||||
{
|
||||
keyvalue = (char *)mallocMagic(strlen(name) + 4);
|
||||
sprintf(keyvalue, "%s {}", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
keyvalue = (char *)mallocMagic(strlen(name) + strlen((char *)value) + 2);
|
||||
sprintf(keyvalue, "%s %s", name, (char *)value);
|
||||
}
|
||||
Tcl_AppendElement(magicinterp, keyvalue);
|
||||
freeMagic(keyvalue);
|
||||
|
||||
|
|
|
|||
|
|
@ -288,6 +288,7 @@ cmdFlushCell(def)
|
|||
CellDef *def;
|
||||
{
|
||||
CellUse *parentUse;
|
||||
bool dereference;
|
||||
|
||||
/* Disallow flushing a cell that contains the edit cell as a child */
|
||||
if (EditCellUse && (EditCellUse->cu_parent == def))
|
||||
|
|
@ -309,7 +310,8 @@ cmdFlushCell(def)
|
|||
}
|
||||
DBCellClearDef(def);
|
||||
DBCellClearAvail(def);
|
||||
(void) DBCellRead(def, (char *) NULL, TRUE, NULL);
|
||||
dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
(void) DBCellRead(def, (char *) NULL, TRUE, dereference, NULL);
|
||||
DBCellSetAvail(def);
|
||||
DBReComputeBbox(def);
|
||||
DBCellSetModified(def, FALSE);
|
||||
|
|
|
|||
|
|
@ -1885,9 +1885,9 @@ CmdXload(w, cmd)
|
|||
{
|
||||
if (CmdIllegalChars(cmd->tx_argv[1], "[],", "Cell name"))
|
||||
return;
|
||||
DBWloadWindow(w, cmd->tx_argv[1], FALSE, TRUE);
|
||||
DBWloadWindow(w, cmd->tx_argv[1], FALSE, TRUE, FALSE);
|
||||
}
|
||||
else DBWloadWindow(w, (char *) NULL, FALSE, TRUE);
|
||||
else DBWloadWindow(w, (char *) NULL, FALSE, TRUE, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -234,7 +234,10 @@ dbCellPlaneSrFunc(scx, fp)
|
|||
if (!DBDescendSubcell(scx->scx_use, fp->tf_xmask))
|
||||
return 0;
|
||||
if ((def->cd_flags & CDAVAILABLE) == 0)
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, NULL)) return 0;
|
||||
{
|
||||
bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, dereference, NULL)) return 0;
|
||||
}
|
||||
|
||||
context.tc_scx = scx;
|
||||
context.tc_filter = fp;
|
||||
|
|
@ -353,7 +356,10 @@ dbCellUniqueTileSrFunc(scx, fp)
|
|||
if (!DBDescendSubcell(scx->scx_use, fp->tf_xmask))
|
||||
return 0;
|
||||
if ((def->cd_flags & CDAVAILABLE) == 0)
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, NULL)) return 0;
|
||||
{
|
||||
bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, dereference, NULL)) return 0;
|
||||
}
|
||||
|
||||
context.tc_scx = scx;
|
||||
context.tc_filter = fp;
|
||||
|
|
@ -462,7 +468,10 @@ DBNoTreeSrTiles(scx, mask, xMask, func, cdarg)
|
|||
return 0;
|
||||
|
||||
if ((def->cd_flags & CDAVAILABLE) == 0)
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, NULL)) return 0;
|
||||
{
|
||||
bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, dereference, NULL)) return 0;
|
||||
}
|
||||
|
||||
filter.tf_func = func;
|
||||
filter.tf_arg = cdarg;
|
||||
|
|
@ -570,7 +579,10 @@ DBTreeSrLabels(scx, mask, xMask, tpath, flags, func, cdarg)
|
|||
ASSERT(def != (CellDef *) NULL, "DBTreeSrLabels");
|
||||
if (!DBDescendSubcell(cellUse, xMask)) return 0;
|
||||
if ((def->cd_flags & CDAVAILABLE) == 0)
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, NULL)) return 0;
|
||||
{
|
||||
bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, dereference, NULL)) return 0;
|
||||
}
|
||||
|
||||
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
||||
{
|
||||
|
|
@ -613,8 +625,11 @@ DBTreeSrLabels(scx, mask, xMask, tpath, flags, func, cdarg)
|
|||
else
|
||||
is_touching = GEO_TOUCH(&lab->lab_rect, r);
|
||||
}
|
||||
if (!is_touching && (flags & TF_LABEL_DISPLAY) && (lab->lab_font >= 0))
|
||||
if (!is_touching && (flags & TF_LABEL_DISPLAY) && lab->lab_font >= 0)
|
||||
{
|
||||
/* Check against bounds of the rendered label text */
|
||||
is_touching = GEO_TOUCH(&lab->lab_bbox, r);
|
||||
}
|
||||
|
||||
if (is_touching && TTMaskHasType(mask, lab->lab_type))
|
||||
if ((*func)(scx, lab, tpath, cdarg))
|
||||
|
|
@ -671,7 +686,10 @@ dbCellLabelSrFunc(scx, fp)
|
|||
ASSERT(def != (CellDef *) NULL, "dbCellLabelSrFunc");
|
||||
if (!DBDescendSubcell(scx->scx_use, fp->tf_xmask)) return 0;
|
||||
if ((def->cd_flags & CDAVAILABLE) == 0)
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, NULL)) return 0;
|
||||
{
|
||||
bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, dereference, NULL)) return 0;
|
||||
}
|
||||
|
||||
if (fp->tf_tpath != (TerminalPath *) NULL)
|
||||
{
|
||||
|
|
@ -785,8 +803,11 @@ DBTreeSrCells(scx, xMask, func, cdarg)
|
|||
if (!DBDescendSubcell(cellUse, xMask))
|
||||
return 0;
|
||||
if ((cellUse->cu_def->cd_flags & CDAVAILABLE) == 0)
|
||||
if (!DBCellRead(cellUse->cu_def, (char *) NULL, TRUE, NULL))
|
||||
{
|
||||
bool dereference = (cellUse->cu_def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
if (!DBCellRead(cellUse->cu_def, (char *) NULL, TRUE, dereference, NULL))
|
||||
return 0;
|
||||
}
|
||||
|
||||
context.tc_scx = scx;
|
||||
context.tc_filter = &filter;
|
||||
|
|
@ -831,8 +852,11 @@ dbTreeCellSrFunc(scx, fp)
|
|||
else
|
||||
{
|
||||
if ((use->cu_def->cd_flags & CDAVAILABLE) == 0)
|
||||
if (!DBCellRead(use->cu_def, (char *) NULL, TRUE, NULL))
|
||||
{
|
||||
bool dereference = (use->cu_def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
if (!DBCellRead(use->cu_def, (char *) NULL, TRUE, dereference, NULL))
|
||||
return 0;
|
||||
}
|
||||
result = DBCellSrArea(scx, dbTreeCellSrFunc, (ClientData) fp);
|
||||
}
|
||||
return result;
|
||||
|
|
@ -1082,8 +1106,12 @@ DBCellSrArea(scx, func, cdarg)
|
|||
context.tc_scx = scx;
|
||||
|
||||
if ((scx->scx_use->cu_def->cd_flags & CDAVAILABLE) == 0)
|
||||
if (!DBCellRead(scx->scx_use->cu_def, (char *) NULL, TRUE, NULL))
|
||||
{
|
||||
bool dereference = (scx->scx_use->cu_def->cd_flags & CDDEREFERENCE) ?
|
||||
TRUE : FALSE;
|
||||
if (!DBCellRead(scx->scx_use->cu_def, (char *) NULL, TRUE, dereference, NULL))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (DBSrCellPlaneArea(scx->scx_use->cu_def->cd_cellPlane,
|
||||
&scx->scx_area, dbCellSrFunc, (ClientData) &context))
|
||||
|
|
@ -1205,7 +1233,10 @@ DBCellEnum(cellDef, func, cdarg)
|
|||
filter.tf_func = func;
|
||||
filter.tf_arg = cdarg;
|
||||
if ((cellDef->cd_flags & CDAVAILABLE) == 0)
|
||||
if (!DBCellRead(cellDef, (char *) NULL, TRUE, NULL)) return 0;
|
||||
{
|
||||
bool dereference = (cellDef->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
if (!DBCellRead(cellDef, (char *) NULL, TRUE, dereference, NULL)) return 0;
|
||||
}
|
||||
if (DBSrCellPlaneArea(cellDef->cd_cellPlane,
|
||||
&TiPlaneRect, dbEnumFunc, (ClientData) &filter))
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -73,8 +73,12 @@ DBDescendSubcell(use, xMask)
|
|||
|
||||
case CU_DESCEND_NO_SUBCKT:
|
||||
if ((use->cu_def->cd_flags & CDAVAILABLE) == 0)
|
||||
if (!DBCellRead(use->cu_def, (char *) NULL, TRUE, NULL))
|
||||
{
|
||||
bool dereference = (use->cu_def->cd_flags & CDDEREFERENCE) ?
|
||||
TRUE : FALSE;
|
||||
if (!DBCellRead(use->cu_def, (char *) NULL, TRUE, dereference, NULL))
|
||||
return FALSE;
|
||||
}
|
||||
return (DBIsSubcircuit(use->cu_def)) ? FALSE : TRUE;
|
||||
|
||||
case CU_DESCEND_NO_LOCK:
|
||||
|
|
|
|||
|
|
@ -661,6 +661,9 @@ dbcUnconnectFunc(tile, clientData)
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* To do: Make the tpath entries dynamically allocated */
|
||||
#define FLATTERMSIZE 1024
|
||||
|
||||
int
|
||||
dbcConnectLabelFunc(scx, lab, tpath, csa2)
|
||||
SearchContext *scx;
|
||||
|
|
@ -672,6 +675,8 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2)
|
|||
Rect r;
|
||||
Point offset;
|
||||
int pos, rotate;
|
||||
char newlabtext[FLATTERMSIZE];
|
||||
char *newlabptr;
|
||||
int dbcConnectFunc(); /* Forward declaration */
|
||||
|
||||
GeoTransRect(&scx->scx_trans, &lab->lab_rect, &r);
|
||||
|
|
@ -683,12 +688,29 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2)
|
|||
/* the top level (Note: Could alter label to be placed with */
|
||||
/* tpath). */
|
||||
|
||||
if (csa2->csa2_topscx->scx_use == scx->scx_use)
|
||||
if (scx->scx_use != csa2->csa2_topscx->scx_use)
|
||||
{
|
||||
DBEraseLabelsByContent(def, &r, -1, lab->lab_text);
|
||||
DBPutFontLabel(def, &r, lab->lab_font, lab->lab_size, rotate, &offset,
|
||||
pos, lab->lab_text, lab->lab_type, lab->lab_flags);
|
||||
int newllen = tpath->tp_next - tpath->tp_first;
|
||||
newlabtext[0] = '\0';
|
||||
if (newllen > 0)
|
||||
strncpy(newlabtext, tpath->tp_first, newllen);
|
||||
sprintf(newlabtext + newllen, "%s", lab->lab_text);
|
||||
newlabptr = newlabtext;
|
||||
}
|
||||
else
|
||||
newlabptr = lab->lab_text;
|
||||
|
||||
/* Do not repeat a label copy; check that the label doesn't */
|
||||
/* already exist in the destination def first. */
|
||||
if (DBCheckLabelsByContent(def, &r, lab->lab_type, lab->lab_text))
|
||||
return 0;
|
||||
|
||||
if (DBCheckLabelsByContent(def, &r, lab->lab_type, newlabptr))
|
||||
return 0;
|
||||
|
||||
DBEraseLabelsByContent(def, &r, -1, lab->lab_text);
|
||||
DBPutFontLabel(def, &r, lab->lab_font, lab->lab_size, rotate, &offset,
|
||||
pos, newlabptr, lab->lab_type, lab->lab_flags);
|
||||
|
||||
if (lab->lab_flags & PORT_DIR_MASK)
|
||||
{
|
||||
|
|
@ -1024,6 +1046,13 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, destUse)
|
|||
DBTreeSrTiles(scx, mask, xMask, dbcConnectFunc, (ClientData) &csa2);
|
||||
while (csa2.csa2_top >= 0)
|
||||
{
|
||||
char pathstring[FLATTERMSIZE];
|
||||
TerminalPath tpath;
|
||||
|
||||
tpath.tp_first = tpath.tp_next = pathstring;
|
||||
tpath.tp_last = pathstring + FLATTERMSIZE;
|
||||
pathstring[0] = '\0';
|
||||
|
||||
newmask = csa2.csa2_list[csa2.csa2_top].connectMask;
|
||||
scx->scx_area = csa2.csa2_list[csa2.csa2_top].area;
|
||||
newtype = csa2.csa2_list[csa2.csa2_top].dinfo;
|
||||
|
|
@ -1064,7 +1093,7 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, destUse)
|
|||
searchtype |= TF_LABEL_ATTACH_NOT_SE;
|
||||
}
|
||||
}
|
||||
DBTreeSrLabels(scx, newmask, xMask, NULL, searchtype,
|
||||
DBTreeSrLabels(scx, newmask, xMask, &tpath, searchtype,
|
||||
dbcConnectLabelFunc, (ClientData) &csa2);
|
||||
}
|
||||
freeMagic((char *)csa2.csa2_list);
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
*/
|
||||
struct expandArg
|
||||
{
|
||||
bool ea_deref; /* TRUE if root def dereference flag is set */
|
||||
int ea_xmask; /* Expand mask. */
|
||||
int (*ea_func)(); /* Function to call for each cell whose
|
||||
* status is changed.
|
||||
|
|
@ -81,7 +82,8 @@ DBExpand(cellUse, expandMask, expandFlag)
|
|||
def = cellUse->cu_def;
|
||||
if ((def->cd_flags & CDAVAILABLE) == 0)
|
||||
{
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, NULL))
|
||||
bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, dereference, NULL))
|
||||
return;
|
||||
/* Note: we don't have to recompute the bbox here, because
|
||||
* if it changed, then a timestamp violation must have occurred
|
||||
|
|
@ -142,9 +144,13 @@ DBExpandAll(rootUse, rootRect, expandMask, expandFlag, func, cdarg)
|
|||
int dbExpandFunc(), dbUnexpandFunc();
|
||||
SearchContext scontext;
|
||||
struct expandArg arg;
|
||||
bool dereference = (rootUse->cu_def->cd_flags & CDDEREFERENCE) ?
|
||||
TRUE : FALSE;
|
||||
|
||||
if ((rootUse->cu_def->cd_flags & CDAVAILABLE) == 0)
|
||||
(void) DBCellRead(rootUse->cu_def, (char *) NULL, TRUE, NULL);
|
||||
{
|
||||
(void) DBCellRead(rootUse->cu_def, (char *) NULL, TRUE, dereference, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk through the area and set the expansion state
|
||||
|
|
@ -154,6 +160,7 @@ DBExpandAll(rootUse, rootRect, expandMask, expandFlag, func, cdarg)
|
|||
arg.ea_xmask = expandMask;
|
||||
arg.ea_func = func;
|
||||
arg.ea_arg = cdarg;
|
||||
arg.ea_deref = dereference;
|
||||
|
||||
scontext.scx_use = rootUse;
|
||||
scontext.scx_trans = GeoIdentityTransform;
|
||||
|
|
@ -193,7 +200,7 @@ dbExpandFunc(scx, arg)
|
|||
/* If the cell is unavailable, then don't expand it.
|
||||
*/
|
||||
if ((childUse->cu_def->cd_flags & CDAVAILABLE) == 0)
|
||||
if(!DBCellRead(childUse->cu_def, (char *) NULL, TRUE, NULL))
|
||||
if(!DBCellRead(childUse->cu_def, (char *) NULL, TRUE, arg->ea_deref, NULL))
|
||||
{
|
||||
TxError("Cell %s is unavailable. It could not be expanded.\n",
|
||||
childUse->cu_def->cd_name);
|
||||
|
|
@ -303,7 +310,8 @@ dbReadAreaFunc(scx)
|
|||
|
||||
if ((def->cd_flags & CDAVAILABLE) == 0)
|
||||
{
|
||||
(void) DBCellRead(def, (char *) NULL, TRUE, NULL);
|
||||
bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
(void) DBCellRead(def, (char *) NULL, TRUE, dereference, NULL);
|
||||
/* Note: we don't have to invoke DBReComputeBbox here because
|
||||
* if the bbox changed then there was a timestamp mismatch and
|
||||
* the timestamp code will take care of the bounding box later.
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ file_is_not_writeable(name)
|
|||
*/
|
||||
|
||||
bool
|
||||
dbCellReadDef(f, cellDef, name, ignoreTech)
|
||||
dbCellReadDef(f, cellDef, name, ignoreTech, dereference)
|
||||
FILE *f; /* The file, already opened by the caller */
|
||||
CellDef *cellDef; /* Pointer to definition of cell to be read in */
|
||||
char *name; /* Name of file from which to read definition.
|
||||
|
|
@ -279,6 +279,7 @@ dbCellReadDef(f, cellDef, name, ignoreTech)
|
|||
* names do not match, but an attempt will be
|
||||
* made to read the file anyway.
|
||||
*/
|
||||
bool dereference; /* If TRUE, ignore path references in the input */
|
||||
{
|
||||
int cellStamp = 0, rectCount = 0, rectReport = 10000;
|
||||
char line[2048], tech[50], layername[50];
|
||||
|
|
@ -437,7 +438,7 @@ dbCellReadDef(f, cellDef, name, ignoreTech)
|
|||
*/
|
||||
if (sscanf(line, "<< %s >>", layername) != 1)
|
||||
{
|
||||
if (!dbReadUse(cellDef, line, sizeof line, f, n, d))
|
||||
if (!dbReadUse(cellDef, line, sizeof line, f, n, d, dereference))
|
||||
goto badfile;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -619,6 +620,9 @@ done:
|
|||
}
|
||||
}
|
||||
}
|
||||
/* Update timestamp flags */
|
||||
DBFlagMismatches(cellDef);
|
||||
|
||||
cellDef->cd_timestamp = cellStamp;
|
||||
if (cellStamp == 0)
|
||||
{
|
||||
|
|
@ -860,7 +864,7 @@ DBReadBackup(name)
|
|||
cellDef->cd_flags &= ~CDNOTFOUND;
|
||||
cellDef->cd_flags |= CDAVAILABLE;
|
||||
|
||||
if (dbCellReadDef(f, cellDef, filename, TRUE) == FALSE)
|
||||
if (dbCellReadDef(f, cellDef, filename, TRUE, FALSE) == FALSE)
|
||||
return FALSE;
|
||||
|
||||
if (dbFgets(line, sizeof(line), f) == NULL)
|
||||
|
|
@ -869,6 +873,8 @@ DBReadBackup(name)
|
|||
name);
|
||||
return FALSE;
|
||||
}
|
||||
/* Update timestamp flags from dbCellReadDef() */
|
||||
DBFlagMismatches(cellDef);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -914,7 +920,7 @@ DBReadBackup(name)
|
|||
*/
|
||||
|
||||
bool
|
||||
DBCellRead(cellDef, name, ignoreTech, errptr)
|
||||
DBCellRead(cellDef, name, ignoreTech, dereference, errptr)
|
||||
CellDef *cellDef; /* Pointer to definition of cell to be read in */
|
||||
char *name; /* Name of file from which to read definition.
|
||||
* If NULL, then use cellDef->cd_file; if that
|
||||
|
|
@ -928,6 +934,7 @@ DBCellRead(cellDef, name, ignoreTech, errptr)
|
|||
* names do not match, but an attempt will be
|
||||
* made to read the file anyway.
|
||||
*/
|
||||
bool dereference; /* If TRUE then ignore path argument to uses */
|
||||
int *errptr; /* Copy of errno set by file reading routine
|
||||
* is placed here, unless NULL.
|
||||
*/
|
||||
|
|
@ -945,7 +952,7 @@ DBCellRead(cellDef, name, ignoreTech, errptr)
|
|||
|
||||
else
|
||||
{
|
||||
result = (dbCellReadDef(f, cellDef, name, ignoreTech));
|
||||
result = (dbCellReadDef(f, cellDef, name, ignoreTech, dereference));
|
||||
|
||||
#ifdef FILE_LOCKS
|
||||
/* Close files that were locked by another user */
|
||||
|
|
@ -1188,13 +1195,14 @@ DBTestOpen(name, fullPath)
|
|||
*/
|
||||
|
||||
bool
|
||||
dbReadUse(cellDef, line, len, f, scalen, scaled)
|
||||
dbReadUse(cellDef, line, len, f, scalen, scaled, dereference)
|
||||
CellDef *cellDef; /* Cell whose cells are being read */
|
||||
char *line; /* Line containing "use ..." */
|
||||
int len; /* Size of buffer pointed to by line */
|
||||
FILE *f; /* Input file */
|
||||
int scalen; /* Multiply values in file by this */
|
||||
int scaled; /* Divide values in file by this */
|
||||
bool dereference; /* If TRUE, ignore path references */
|
||||
{
|
||||
int xlo, xhi, ylo, yhi, xsep, ysep, childStamp;
|
||||
int absa, absb, absd, abse, nconv;
|
||||
|
|
@ -1225,7 +1233,7 @@ dbReadUse(cellDef, line, len, f, scalen, scaled)
|
|||
|
||||
pathptr = &path[0];
|
||||
while (*pathptr == ' ' || *pathptr == '\t') pathptr++;
|
||||
if (*pathptr == '\n') *pathptr = '\0';
|
||||
if ((dereference == TRUE) || (*pathptr == '\n')) *pathptr = '\0';
|
||||
|
||||
locked = (useid[0] == CULOCKCHAR) ? TRUE : FALSE;
|
||||
|
||||
|
|
@ -1432,9 +1440,22 @@ badTransform:
|
|||
slashptr = strrchr(subCellDef->cd_file, '/');
|
||||
if (slashptr != NULL)
|
||||
{
|
||||
bool pathOK = FALSE;
|
||||
*slashptr = '\0';
|
||||
|
||||
if (strcmp(subCellDef->cd_file, pathptr))
|
||||
/* Avoid generating error message if pathptr starts with '~' */
|
||||
/* and the tilde-expanded name matches the subCellDef name */
|
||||
|
||||
if (*pathptr == '~')
|
||||
{
|
||||
char *homedir = getenv("HOME");
|
||||
if (!strncmp(subCellDef->cd_file, homedir, strlen(homedir))
|
||||
&& (!strcmp(subCellDef->cd_file + strlen(homedir),
|
||||
pathptr + 1)))
|
||||
pathOK = TRUE;
|
||||
}
|
||||
|
||||
if ((pathOK == FALSE) && strcmp(subCellDef->cd_file, pathptr))
|
||||
{
|
||||
TxError("Duplicate cell in %s: Instance of cell %s is from "
|
||||
"path %s but cell was previously read from %s.\n",
|
||||
|
|
@ -2345,6 +2366,8 @@ DBCellWriteFile(cellDef, f)
|
|||
int reducer;
|
||||
char *estring;
|
||||
char lstring[256];
|
||||
char *propvalue;
|
||||
bool propfound;
|
||||
|
||||
#define FPRINTF(f,s)\
|
||||
{\
|
||||
|
|
@ -2537,12 +2560,43 @@ DBCellWriteFile(cellDef, f)
|
|||
}
|
||||
|
||||
/* And any properties */
|
||||
|
||||
/* NOTE: FIXED_BBOX is treated specially; values are database */
|
||||
/* values and should be divided by reducer. Easiest to do it */
|
||||
/* here and revert values after. */
|
||||
|
||||
propvalue = (char *)DBPropGet(cellDef, "FIXED_BBOX", &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
char *proporig, *propscaled;
|
||||
Rect scalebox, bbox;
|
||||
|
||||
proporig = StrDup((char **)NULL, propvalue);
|
||||
propscaled = mallocMagic(strlen(propvalue) + 5);
|
||||
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
|
||||
&bbox.r_xtop, &bbox.r_ytop) == 4)
|
||||
{
|
||||
scalebox.r_xbot = bbox.r_xbot / reducer;
|
||||
scalebox.r_xtop = bbox.r_xtop / reducer;
|
||||
scalebox.r_ybot = bbox.r_ybot / reducer;
|
||||
scalebox.r_ytop = bbox.r_ytop / reducer;
|
||||
sprintf(propscaled, "%d %d %d %d",
|
||||
bbox.r_xbot / reducer, bbox.r_ybot / reducer,
|
||||
bbox.r_xtop / reducer, bbox.r_ytop / reducer);
|
||||
|
||||
DBPropPut(cellDef, "FIXED_BBOX", propscaled);
|
||||
propvalue = proporig;
|
||||
}
|
||||
}
|
||||
|
||||
if (cellDef->cd_props != (ClientData)NULL)
|
||||
{
|
||||
FPRINTF(f, "<< properties >>\n");
|
||||
DBPropEnum(cellDef, dbWritePropFunc, (ClientData)f);
|
||||
}
|
||||
|
||||
if (propfound) DBPropPut(cellDef, "FIXED_BBOX", propvalue);
|
||||
|
||||
FPRINTF(f, "<< end >>\n");
|
||||
|
||||
if (fflush(f) == EOF || ferror(f))
|
||||
|
|
@ -2801,8 +2855,11 @@ DBCellWrite(cellDef, fileName)
|
|||
|
||||
#ifdef FILE_LOCKS
|
||||
else
|
||||
{
|
||||
bool dereference = (cellDef->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
/* Re-aquire the lock on the new file by opening it. */
|
||||
DBCellRead(cellDef, NULL, TRUE, NULL);
|
||||
DBCellRead(cellDef, NULL, TRUE, dereference, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -313,7 +313,55 @@ DBEraseLabel(cellDef, area, mask, areaReturn)
|
|||
cellDef->cd_flags |= CDMODIFIED|CDGETNEWSTAMP;
|
||||
return (erasedAny);
|
||||
}
|
||||
|
||||
|
||||
#define RECTEQUAL(r1, r2) ((r1)->r_xbot == (r2)->r_xbot \
|
||||
&& (r1)->r_ybot == (r2)->r_ybot \
|
||||
&& (r1)->r_xtop == (r2)->r_xtop \
|
||||
&& (r1)->r_ytop == (r2)->r_ytop)
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* DBCheckLabelsByContent --
|
||||
*
|
||||
* Return any label found on the label list for the given
|
||||
* CellDef that matches the given specification.
|
||||
*
|
||||
* Results:
|
||||
* Returns a label if a match is found, otherwise returns NULL.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Label *
|
||||
DBCheckLabelsByContent(def, rect, type, text)
|
||||
CellDef *def; /* Where to look for label to delete. */
|
||||
Rect *rect; /* Coordinates of label. If NULL, then
|
||||
* labels are searched regardless of coords.
|
||||
*/
|
||||
TileType type; /* Layer label is attached to. If < 0, then
|
||||
* labels are searched regardless of type.
|
||||
*/
|
||||
char *text; /* Text associated with label. If NULL, then
|
||||
* labels are searched regardless of text.
|
||||
*/
|
||||
{
|
||||
Label *lab;
|
||||
|
||||
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
||||
{
|
||||
if ((rect != NULL) && !(RECTEQUAL(&lab->lab_rect, rect))) continue;
|
||||
if ((type >= 0) && (type != lab->lab_type)) continue;
|
||||
if ((text != NULL) && (strcmp(text, lab->lab_text) != 0)) continue;
|
||||
|
||||
return lab;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -348,11 +396,6 @@ DBEraseLabelsByContent(def, rect, type, text)
|
|||
{
|
||||
Label *lab, *labPrev;
|
||||
|
||||
#define RECTEQUAL(r1, r2) ((r1)->r_xbot == (r2)->r_xbot \
|
||||
&& (r1)->r_ybot == (r2)->r_ybot \
|
||||
&& (r1)->r_xtop == (r2)->r_xtop \
|
||||
&& (r1)->r_ytop == (r2)->r_ytop)
|
||||
|
||||
for (labPrev = NULL, lab = def->cd_labels;
|
||||
lab != NULL;
|
||||
labPrev = lab, lab = lab->lab_next)
|
||||
|
|
|
|||
|
|
@ -294,20 +294,31 @@ DBTreeFindUse(name, use, scx)
|
|||
* is read in from disk.
|
||||
*/
|
||||
if ((def->cd_flags & CDAVAILABLE) == 0)
|
||||
(void) DBCellRead(def, (char *) NULL, TRUE, NULL);
|
||||
{
|
||||
bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
(void) DBCellRead(def, (char *) NULL, TRUE, dereference, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pull off the next component of path up to but not including
|
||||
* any array subscripts.
|
||||
*/
|
||||
for (cp = name; *cp && *cp != '[' && *cp != '/'; cp++)
|
||||
/* Nothing */;
|
||||
csave = *cp;
|
||||
*cp = '\0';
|
||||
cp = name;
|
||||
he = HashLookOnly(&def->cd_idHash, name);
|
||||
*cp = csave;
|
||||
if (he == NULL || HashGetValue(he) == NULL)
|
||||
return;
|
||||
{
|
||||
/*
|
||||
* Pull off the next component of path up to but not including
|
||||
* any array subscripts.
|
||||
* NOTE: This should check the array bounds and only remove
|
||||
* array components that are expected, not array components
|
||||
* embedded in the name.
|
||||
*/
|
||||
for (; *cp && *cp != '[' && *cp != '/'; cp++)
|
||||
/* Nothing */;
|
||||
csave = *cp;
|
||||
*cp = '\0';
|
||||
he = HashLookOnly(&def->cd_idHash, name);
|
||||
*cp = csave;
|
||||
if (he == NULL || HashGetValue(he) == NULL)
|
||||
return;
|
||||
}
|
||||
use = (CellUse *) HashGetValue(he);
|
||||
def = use->cu_def;
|
||||
|
||||
|
|
@ -335,7 +346,10 @@ DBTreeFindUse(name, use, scx)
|
|||
/* Ensure that the leaf cell is read in */
|
||||
def = use->cu_def;
|
||||
if ((def->cd_flags & CDAVAILABLE) == 0)
|
||||
(void) DBCellRead(def, (char *) NULL, TRUE, NULL);
|
||||
{
|
||||
bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
(void) DBCellRead(def, (char *) NULL, dereference, NULL);
|
||||
}
|
||||
|
||||
scx->scx_use = use;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,11 +66,23 @@ DBPropPut(cellDef, name, value)
|
|||
HashInit( (HashTable *) cellDef->cd_props, 8, 0);
|
||||
}
|
||||
htab = (HashTable *) cellDef->cd_props;
|
||||
|
||||
/* Special handling of FIXED_BBOX, which uses CDFIXEDBBOX as a quick lookup */
|
||||
if (!strcmp(name, "FIXED_BBOX"))
|
||||
{
|
||||
if (value == (ClientData)NULL)
|
||||
cellDef->cd_flags &= ~CDFIXEDBBOX;
|
||||
else
|
||||
cellDef->cd_flags |= CDFIXEDBBOX;
|
||||
}
|
||||
|
||||
entry = HashFind(htab, name);
|
||||
oldvalue = (char *)HashGetValue(entry);
|
||||
if (oldvalue != NULL) freeMagic(oldvalue);
|
||||
HashSetValue(entry, value);
|
||||
if (value == (ClientData)NULL)
|
||||
HashRemove(htab, name);
|
||||
else
|
||||
HashSetValue(entry, value);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
|
|
@ -202,4 +214,8 @@ DBPropClearAll(cellDef)
|
|||
HashKill(htab);
|
||||
freeMagic((char *) htab);
|
||||
cellDef->cd_props = (ClientData) NULL;
|
||||
|
||||
/* Since CDFIXEDBBOX requires a FIXED_BBOX property, clearing all */
|
||||
/* properties necessarily means this flag must be clear. */
|
||||
cellDef->cd_flags &= ~CDFIXEDBBOX;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ DBTechInitPlane()
|
|||
for (dpp = dbTechDefaultPlanes; dpp->dp_names; dpp++)
|
||||
{
|
||||
cp = dbTechNameAdd(dpp->dp_names, (ClientData) dpp->dp_plane,
|
||||
&dbPlaneNameLists);
|
||||
&dbPlaneNameLists, FALSE);
|
||||
if (cp == NULL)
|
||||
{
|
||||
TxError("DBTechInit: can't add plane names %s\n", dpp->dp_names);
|
||||
|
|
@ -224,7 +224,7 @@ DBTechInitType()
|
|||
for (dtp = dbTechDefaultTypes; dtp->dt_names; dtp++)
|
||||
{
|
||||
cp = dbTechNameAdd(dtp->dt_names, (ClientData) dtp->dt_type,
|
||||
&dbTypeNameLists);
|
||||
&dbTypeNameLists, FALSE);
|
||||
if (cp == NULL)
|
||||
{
|
||||
TxError("DBTechInit: can't add type names %s\n", dtp->dt_names);
|
||||
|
|
@ -283,7 +283,7 @@ DBTechAddPlane(sectionName, argc, argv)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
cp = dbTechNameAdd(argv[0], (ClientData) DBNumPlanes, &dbPlaneNameLists);
|
||||
cp = dbTechNameAdd(argv[0], (ClientData) DBNumPlanes, &dbPlaneNameLists, FALSE);
|
||||
if (cp == NULL)
|
||||
return FALSE;
|
||||
DBPlaneLongNameTbl[DBNumPlanes++] = cp;
|
||||
|
|
@ -315,7 +315,7 @@ DBTechAddNameToType(newname, ttype, canonical)
|
|||
{
|
||||
char *cp;
|
||||
|
||||
cp = dbTechNameAdd(newname, (ClientData) ttype, &dbTypeNameLists);
|
||||
cp = dbTechNameAdd(newname, (ClientData) ttype, &dbTypeNameLists, TRUE);
|
||||
if (canonical)
|
||||
DBTypeLongNameTbl[ttype] = cp;
|
||||
}
|
||||
|
|
@ -455,7 +455,7 @@ DBTechAddType(sectionName, argc, argv)
|
|||
}
|
||||
else
|
||||
{
|
||||
cp = dbTechNameAdd(argv[1], (ClientData) DBNumTypes, &dbTypeNameLists);
|
||||
cp = dbTechNameAdd(argv[1], (ClientData) DBNumTypes, &dbTypeNameLists, FALSE);
|
||||
if (cp == NULL)
|
||||
return FALSE;
|
||||
|
||||
|
|
@ -513,7 +513,7 @@ dbTechNewStackedType(type1, type2)
|
|||
}
|
||||
|
||||
sprintf(buf, "%s+%s", DBTypeShortName(type1), DBTypeShortName(type2));
|
||||
cp = dbTechNameAdd(buf, (ClientData) DBNumTypes, &dbTypeNameLists);
|
||||
cp = dbTechNameAdd(buf, (ClientData) DBNumTypes, &dbTypeNameLists, FALSE);
|
||||
if (cp == NULL)
|
||||
{
|
||||
TechError("Couldn't generate new stacking type %s\n", buf);
|
||||
|
|
@ -730,10 +730,11 @@ dbTechNameLookup(str, table)
|
|||
*/
|
||||
|
||||
char *
|
||||
dbTechNameAdd(name, cdata, ptable)
|
||||
dbTechNameAdd(name, cdata, ptable, alias)
|
||||
char *name; /* Comma-separated list of names to be added */
|
||||
ClientData cdata; /* Value to be stored with each name above */
|
||||
NameList *ptable; /* Table to which we will add names */
|
||||
int alias; /* 1 if this is an alias (never make primary) */
|
||||
{
|
||||
char *cp;
|
||||
char onename[BUFSIZ];
|
||||
|
|
@ -769,7 +770,7 @@ dbTechNameAdd(name, cdata, ptable)
|
|||
}
|
||||
}
|
||||
|
||||
if (primary)
|
||||
if (primary && (alias == 0))
|
||||
primary->sn_primary = TRUE;
|
||||
return (first);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,6 +126,8 @@ DBFixMismatch()
|
|||
|
||||
while (mismatch != NULL)
|
||||
{
|
||||
bool dereference;
|
||||
|
||||
/* Be careful to remove the front element from the mismatch
|
||||
* list before processing it, because while processing it we
|
||||
* may add new elements to the list.
|
||||
|
|
@ -137,7 +139,8 @@ DBFixMismatch()
|
|||
mismatch = mismatch->mm_next;
|
||||
if (cellDef->cd_flags & CDPROCESSED) continue;
|
||||
|
||||
(void) DBCellRead(cellDef, (char *) NULL, TRUE, NULL);
|
||||
dereference = (cellDef->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
(void) DBCellRead(cellDef, (char *) NULL, TRUE, dereference, NULL);
|
||||
|
||||
/* Jimmy up the cell's current bounding box, so the following
|
||||
* procedure call will absolutely and positively know that
|
||||
|
|
@ -267,6 +270,16 @@ dbStampFunc(cellDef)
|
|||
* processing. When DBFixMismatch is called, it will notify
|
||||
* the design-rule checker to recheck both wrongArea, and
|
||||
* the cell's eventual correct area.
|
||||
*
|
||||
* This routine has been modified from a poor implementation. Previously
|
||||
* the parent def of all uses of the cell being checked would be marked
|
||||
* for a stamp mismatch check. However, when reading a cell with large
|
||||
* numbers of instances, the list of instances would be parsed for every
|
||||
* instance added, leading to an O(N^2) computation. Routine DBStampMismatch()
|
||||
* has been broken into two parts. DBStampMismatch() only records the
|
||||
* area to be checked. DBFlagMismatches() looks at the parents of each
|
||||
* celldef only once, after all instances have been read.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
|
@ -278,16 +291,27 @@ DBStampMismatch(cellDef, wrongArea)
|
|||
*/
|
||||
{
|
||||
Mismatch *mm;
|
||||
CellUse *parentUse;
|
||||
|
||||
mm = (Mismatch *) mallocMagic((unsigned) (sizeof (Mismatch)));
|
||||
mm->mm_cellDef = cellDef;
|
||||
mm->mm_oldArea = *wrongArea;
|
||||
mm->mm_next = mismatch;
|
||||
mismatch = mm;
|
||||
}
|
||||
|
||||
for (parentUse = cellDef->cd_parents; parentUse != NULL;
|
||||
parentUse = parentUse->cu_nextuse)
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
DBFlagMismatches(checkDef)
|
||||
CellDef *checkDef;
|
||||
{
|
||||
CellUse *parentUse;
|
||||
|
||||
for (parentUse = checkDef->cd_parents; parentUse != NULL;
|
||||
parentUse = parentUse->cu_nextuse)
|
||||
{
|
||||
if (parentUse->cu_parent == NULL) continue;
|
||||
parentUse->cu_parent->cd_flags |= CDSTAMPSCHANGED;
|
||||
|
|
|
|||
|
|
@ -396,6 +396,9 @@ typedef struct celldef
|
|||
* with the option "gds readonly true".
|
||||
* CDVISITED indicates that at least one instance of the cell was
|
||||
* already output during a file write.
|
||||
* CDDEREFERENCE is a flag indicating that when loading or expanding
|
||||
* children of a cell, the path should be ignored and the cell
|
||||
* path should be searched for the location.
|
||||
*/
|
||||
|
||||
#define CDAVAILABLE 0x0001
|
||||
|
|
@ -413,6 +416,7 @@ typedef struct celldef
|
|||
#define CDPROCESSEDGDS 0x1000
|
||||
#define CDVENDORGDS 0x2000
|
||||
#define CDVISITED 0x4000
|
||||
#define CDDEREFERENCE 0x8000
|
||||
|
||||
/*
|
||||
* Description of an array.
|
||||
|
|
|
|||
|
|
@ -199,6 +199,7 @@ extern void DBUndoPutLabel();
|
|||
extern void DBUndoEraseLabel();
|
||||
extern void DBUndoCellUse();
|
||||
extern void DBStampMismatch();
|
||||
extern void DBFlagMismatches();
|
||||
extern void DBTechAddNameToType();
|
||||
|
||||
extern void dbComputeBbox();
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
* Standard DBWind command set
|
||||
*/
|
||||
|
||||
extern void CmdAddPath(), CmdArray();
|
||||
extern void CmdAddPath(), CmdAntennaCheck(), CmdArray();
|
||||
extern void CmdBox(), CmdCellname(), CmdClockwise();
|
||||
extern void CmdContact(), CmdCopy(), CmdCorner();
|
||||
extern void CmdCrash(), CmdCrosshair();
|
||||
|
|
@ -222,6 +222,9 @@ DBWInitCommands()
|
|||
WindAddCommand(DBWclientID,
|
||||
"addpath [path] append to current search path",
|
||||
CmdAddPath, FALSE);
|
||||
WindAddCommand(DBWclientID,
|
||||
"antennacheck [path] check for antenna violations",
|
||||
CmdAntennaCheck, FALSE);
|
||||
WindAddCommand(DBWclientID,
|
||||
"array xsize ysize OR\n"
|
||||
"array xlo xhi ylo yhi\n"
|
||||
|
|
|
|||
|
|
@ -418,7 +418,7 @@ DBWredisplay(w, rootArea, clipArea)
|
|||
/* Set style information beforehand */
|
||||
GrSetStuff(STYLE_LABEL);
|
||||
(void) DBTreeSrLabels(&scontext, &DBAllTypeBits, bitMask,
|
||||
(TerminalPath *) NULL, TF_LABEL_DISPLAY,
|
||||
(TerminalPath *) NULL, TF_LABEL_DISPLAY | TF_LABEL_ATTACH,
|
||||
dbwLabelFunc, (ClientData) NULL);
|
||||
GrClipTo(&rootClip);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,10 +127,10 @@ DBWcreate(window, argc, argv)
|
|||
|
||||
window->w_clientData = (ClientData) crec;
|
||||
if (argc > 0)
|
||||
DBWloadWindow(window, argv[0], TRUE, FALSE);
|
||||
DBWloadWindow(window, argv[0], TRUE, FALSE, FALSE);
|
||||
else if (ToolGetBox(&boxDef, &box))
|
||||
{
|
||||
DBWloadWindow(window, boxDef->cd_name, TRUE, FALSE);
|
||||
DBWloadWindow(window, boxDef->cd_name, TRUE, FALSE, FALSE);
|
||||
|
||||
/* Zoom in on the box, leaving a 10% border or at least 2 units
|
||||
* on each side.
|
||||
|
|
@ -148,7 +148,7 @@ DBWcreate(window, argc, argv)
|
|||
}
|
||||
else
|
||||
{
|
||||
DBWloadWindow(window, (char *) NULL, TRUE, FALSE);
|
||||
DBWloadWindow(window, (char *) NULL, TRUE, FALSE, FALSE);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -249,7 +249,7 @@ dbwReloadFunc(w, name)
|
|||
MagWindow *w;
|
||||
char *name;
|
||||
{
|
||||
DBWloadWindow(w, name, TRUE, FALSE);
|
||||
DBWloadWindow(w, name, TRUE, FALSE, FALSE);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
@ -274,26 +274,29 @@ dbwReloadFunc(w, name)
|
|||
* cell doesn't change.
|
||||
*
|
||||
* If "expand" is true, unexpands all subcells of the root cell.
|
||||
* If "dereference" is true, ignore path reference in the input file.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
DBWloadWindow(window, name, ignoreTech, expand)
|
||||
DBWloadWindow(window, name, ignoreTech, expand, dereference)
|
||||
MagWindow *window; /* Identifies window to which cell is to be bound */
|
||||
char *name; /* Name of new cell to be bound to this window */
|
||||
bool ignoreTech; /* If FALSE, indicates that the technology of
|
||||
* the layout must match the current technology.
|
||||
*/
|
||||
bool expand; /* Indicates whether or not to expand the cell */
|
||||
bool dereference; /* If TRUE, ignore path references in the input */
|
||||
{
|
||||
CellDef *newEditDef;
|
||||
CellDef *newEditDef, *deleteDef;
|
||||
CellUse *newEditUse;
|
||||
void DisplayWindow();
|
||||
int res, newEdit, error_val;
|
||||
int xadd, yadd;
|
||||
Rect loadBox;
|
||||
char *rootname;
|
||||
bool isUnnamed;
|
||||
int UnexpandFunc(); /* forward declaration */
|
||||
|
||||
loadBox.r_xbot = loadBox.r_ybot = 0;
|
||||
|
|
@ -303,6 +306,19 @@ DBWloadWindow(window, name, ignoreTech, expand)
|
|||
newEdit = !WindSearch((WindClient) DBWclientID, (ClientData) NULL,
|
||||
(Rect *) NULL, dbwLoadFunc, (ClientData) window);
|
||||
|
||||
/* The (UNNAMED) cell generally gets in the way, so delete it if */
|
||||
/* any new cell is loaded and (UNNAMED) has no contents. */
|
||||
|
||||
if (window->w_surfaceID == (ClientData)NULL)
|
||||
deleteDef = NULL;
|
||||
else
|
||||
{
|
||||
deleteDef = ((CellUse *)window->w_surfaceID)->cu_def;
|
||||
if (strcmp(deleteDef->cd_name, "(UNNAMED)") ||
|
||||
deleteDef->cd_flags & (CDMODIFIED|CDBOXESCHANGED|CDSTAMPSCHANGED))
|
||||
deleteDef = NULL;
|
||||
}
|
||||
|
||||
if ((name == (char *) NULL) || (name[0] == '\0'))
|
||||
{
|
||||
/*
|
||||
|
|
@ -383,7 +399,9 @@ DBWloadWindow(window, name, ignoreTech, expand)
|
|||
if (newEditDef == (CellDef *) NULL)
|
||||
newEditDef = DBCellNewDef(rootname, (char *) NULL);
|
||||
|
||||
if (!DBCellRead(newEditDef, name, ignoreTech, &error_val))
|
||||
if (dereference) newEditDef->cd_flags |= CDDEREFERENCE;
|
||||
|
||||
if (!DBCellRead(newEditDef, name, ignoreTech, dereference, &error_val))
|
||||
{
|
||||
if (error_val == ENOENT)
|
||||
{
|
||||
|
|
@ -499,6 +517,12 @@ DBWloadWindow(window, name, ignoreTech, expand)
|
|||
if (newEdit)
|
||||
DBWAreaChanged(newEditDef, &newEditDef->cd_bbox, DBW_ALLWINDOWS,
|
||||
&DBAllButSpaceBits);
|
||||
|
||||
/* If the cell before loading was (UNNAMED) and it was */
|
||||
/* never modified, then delete it now. */
|
||||
|
||||
if (deleteDef != NULL)
|
||||
DBCellDelete(deleteDef->cd_name, TRUE);
|
||||
}
|
||||
|
||||
/* This function is called for each cell whose expansion status changed.
|
||||
|
|
|
|||
98
defs.mak
98
defs.mak
|
|
@ -1,98 +0,0 @@
|
|||
# defs.mak.in --
|
||||
# source file for autoconf-generated "defs.mak" for magic
|
||||
|
||||
# defs.mak. Generated from defs.mak.in by configure.
|
||||
# Feel free to change the values in here to suit your needs.
|
||||
# Be aware that running scripts/configure again will overwrite
|
||||
# any changes!
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
prefix = /usr/local
|
||||
exec_prefix = ${prefix}
|
||||
bindir = ${exec_prefix}/bin
|
||||
libdir = ${exec_prefix}/lib
|
||||
mandir = ${prefix}/share/man
|
||||
|
||||
SCRIPTS = ${MAGICDIR}/scripts
|
||||
|
||||
INSTALL = /bin/install -c
|
||||
INSTALL_PROGRAM = ${INSTALL}
|
||||
INSTALL_DATA = ${INSTALL} -m 644
|
||||
INSTALL_SCRIPT = ${INSTALL}
|
||||
|
||||
# Override standard "make" target when compiling under TCL
|
||||
ALL_TARGET = tcl
|
||||
INSTALL_TARGET = install-tcl
|
||||
|
||||
# Change libdir to install in a different place
|
||||
BINDIR = ${bindir}
|
||||
MANDIR = ${mandir}
|
||||
LIBDIR = ${libdir}
|
||||
SYSDIR = ${libdir}/magic/sys
|
||||
SCMDIR = ${libdir}/magic/scm
|
||||
TCLDIR = ${libdir}/magic/tcl
|
||||
|
||||
MAIN_EXTRA_LIBS = ${MAGICDIR}/ext2sim/libext2sim.o ${MAGICDIR}/ext2spice/libext2spice.o ${MAGICDIR}/calma/libcalma.o ${MAGICDIR}/cif/libcif.o ${MAGICDIR}/plot/libplot.o ${MAGICDIR}/lef/liblef.o ${MAGICDIR}/extflat/libextflat.o ${MAGICDIR}/garouter/libgarouter.o ${MAGICDIR}/mzrouter/libmzrouter.o ${MAGICDIR}/router/librouter.o ${MAGICDIR}/irouter/libirouter.o ${MAGICDIR}/grouter/libgrouter.o ${MAGICDIR}/gcr/libgcr.o ${MAGICDIR}/tcltk/libtcltk.o
|
||||
LD_EXTRA_LIBS =
|
||||
LD_SHARED =
|
||||
TOP_EXTRA_LIBS =
|
||||
SUB_EXTRA_LIBS =
|
||||
|
||||
MODULES += ext2sim ext2spice calma cif plot lef garouter grouter irouter mzrouter router gcr tcltk
|
||||
UNUSED_MODULES += readline lisp
|
||||
PROGRAMS += net2ir tcltk
|
||||
INSTALL_CAD_DIRS += graphics tcltk
|
||||
|
||||
RM = rm -f
|
||||
CP = cp
|
||||
AR = ar
|
||||
ARFLAGS = crv
|
||||
LINK = ld -r
|
||||
LD = /bin/ld
|
||||
M4 = /bin/m4
|
||||
MCPP = ${MAGICDIR}/scripts/preproc.py
|
||||
SCPP = gcc -E -x c
|
||||
RANLIB = ranlib
|
||||
SHDLIB_EXT = .so
|
||||
LDDL_FLAGS = ${LDFLAGS} -shared -Wl,-soname,$@ -Wl,--version-script=${MAGICDIR}/magic/symbol.map
|
||||
LD_RUN_PATH =
|
||||
LIB_SPECS = -L/usr/lib64 -ltkstub8.6 -L/usr/lib64 -ltclstub8.6
|
||||
LIB_SPECS_NOSTUB = -L/usr/lib64 -ltk8.6 -L/usr/lib64 -ltcl8.6
|
||||
WISH_EXE = /usr/bin/wish
|
||||
TCL_LIB_DIR = /usr/lib
|
||||
MAGIC_VERSION = 8.2
|
||||
MAGIC_REVISION = 101
|
||||
|
||||
CC = gcc
|
||||
CPP = gcc -E
|
||||
CXX = g++
|
||||
|
||||
CPPFLAGS = -I. -I${MAGICDIR}
|
||||
DFLAGS = -DCAD_DIR=\"${LIBDIR}\" -DBIN_DIR=\"${BINDIR}\" -DTCL_DIR=\"${TCLDIR}\" -DUSE_TCL_STUBS -DUSE_TK_STUBS -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DMAGIC_VERSION=\"8.2\" -DMAGIC_REVISION=\"101\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_SYS_MMAN_H=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_PATHS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DFILE_LOCKS=1 -DCALMA_MODULE=1 -DCIF_MODULE=1 -DPLOT_MODULE=1 -DLEF_MODULE=1 -DROUTE_MODULE=1 -DUSE_NEW_MACROS=1 -DHAVE_LIBGL=1 -DHAVE_LIBGLU=1 -DVECTOR_FONTS=1 -DHAVE_LIBCAIRO=1 -DMAGIC_WRAPPER=1 -DTHREE_D=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DGCORE=\"/bin/gcore\"
|
||||
DFLAGS += -DSHDLIB_EXT=\".so\" -DNDEBUG
|
||||
DFLAGS_NOSTUB = -DCAD_DIR=\"${LIBDIR}\" -DBIN_DIR=\"${BINDIR}\" -DTCL_DIR=\"${TCLDIR}\" -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DMAGIC_VERSION=\"8.2\" -DMAGIC_REVISION=\"101\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_SYS_MMAN_H=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_PATHS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DFILE_LOCKS=1 -DCALMA_MODULE=1 -DCIF_MODULE=1 -DPLOT_MODULE=1 -DLEF_MODULE=1 -DROUTE_MODULE=1 -DUSE_NEW_MACROS=1 -DHAVE_LIBGL=1 -DHAVE_LIBGLU=1 -DVECTOR_FONTS=1 -DHAVE_LIBCAIRO=1 -DMAGIC_WRAPPER=1 -DTHREE_D=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DGCORE=\"/bin/gcore\"
|
||||
DFLAGS_NOSTUB += -DSHDLIB_EXT=\".so\" -DNDEBUG
|
||||
CFLAGS = -g -m64 -fPIC -Wimplicit-int -fPIC
|
||||
|
||||
READLINE_DEFS =
|
||||
READLINE_LIBS =
|
||||
|
||||
DEPEND_FILE = Depend
|
||||
DEPEND_FLAG = -MM
|
||||
EXEEXT =
|
||||
|
||||
GR_CFLAGS =
|
||||
GR_DFLAGS = -DX11 -DXLIB -DOGL -DCAIRO -DNDEBUG
|
||||
GR_LIBS = -lX11 -lGL -lGLU -lXi -lXmu -lXext -lm -lcairo -lfontconfig -lfreetype -lstdc++ ${X11_LDFLAGS}
|
||||
GR_SRCS = ${TK_SRCS} ${TOGL_SRCS} ${TCAIRO_SRCS} ${TKCOMMON_SRCS}
|
||||
GR_HELPER_SRCS =
|
||||
GR_HELPER_PROG =
|
||||
|
||||
OA =
|
||||
OA_LIBS =
|
||||
|
||||
DEPSRCS = ${SRCS}
|
||||
OBJS = ${SRCS:.c=.o} ${CXXSRCS:.cpp=.o}
|
||||
LIB_OBJS = ${LIB_SRCS:.c=.o}
|
||||
CLEANS = ${OBJS} ${LIB_OBJS} lib${MODULE}.a lib${MODULE}.o ${MODULE}
|
||||
|
|
@ -2,7 +2,7 @@ MAGICDIR = ../..
|
|||
|
||||
include $(MAGICDIR)/defs.mak
|
||||
|
||||
HTML_INSTDIR=$(LIBDIR)/magic/doc/html
|
||||
HTML_INSTDIR=$(INSTALL_LIBDIR)/magic/doc/html
|
||||
|
||||
install: $(DESTDIR)${HTML_INSTDIR}
|
||||
tar cf - . | (cd $(DESTDIR)${HTML_INSTDIR}; tar xf - )
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ Define or print a macro called char
|
|||
|
||||
Buttons are treated just like keys for the purpose of
|
||||
defining macros. While the official names for buttons
|
||||
in <TT>keysymdef.h</TT> are "<B>XK_Pointer_Button_1</B>",
|
||||
in <TT>keysymdef.h</TT> are "<B>XK_Pointer_Button1</B>",
|
||||
etc., the <B>macro</B> command accepts the abbreviated
|
||||
forms <B>Button1</B>, and so forth. <P>
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ MAGICDIR = ../..
|
|||
include $(MAGICDIR)/defs.mak
|
||||
|
||||
PS_SRCDIR=../psfiles
|
||||
PS_INSTDIR=$(LIBDIR)/magic/doc
|
||||
PS_INSTDIR=$(INSTALL_LIBDIR)/magic/doc
|
||||
|
||||
.SUFFIXES: .dvi .tex .ps
|
||||
|
||||
|
|
|
|||
|
|
@ -15,36 +15,36 @@ EQN=eqn -Ppsc
|
|||
include ${MAGICDIR}/defs.mak
|
||||
|
||||
MANFILES = \
|
||||
$(DESTDIR)${MANDIR}/man1/ext2spice.1 \
|
||||
$(DESTDIR)${MANDIR}/man1/extcheck.1 \
|
||||
$(DESTDIR)${MANDIR}/man1/ext2sim.1 \
|
||||
$(DESTDIR)${MANDIR}/man1/magic.1 \
|
||||
$(DESTDIR)${MANDIR}/man5/cmap.5 \
|
||||
$(DESTDIR)${MANDIR}/man5/displays.5 \
|
||||
$(DESTDIR)${MANDIR}/man5/dlys.5 \
|
||||
$(DESTDIR)${MANDIR}/man5/dstyle.5 \
|
||||
$(DESTDIR)${MANDIR}/man5/ext.5 \
|
||||
$(DESTDIR)${MANDIR}/man5/glyphs.5 \
|
||||
$(DESTDIR)${MANDIR}/man5/mag.5 \
|
||||
$(DESTDIR)${MANDIR}/man5/net.5 \
|
||||
$(DESTDIR)${MANDIR}/man5/sim.5
|
||||
$(DESTDIR)${INSTALL_MANDIR}/man1/ext2spice.1 \
|
||||
$(DESTDIR)${INSTALL_MANDIR}/man1/extcheck.1 \
|
||||
$(DESTDIR)${INSTALL_MANDIR}/man1/ext2sim.1 \
|
||||
$(DESTDIR)${INSTALL_MANDIR}/man1/magic.1 \
|
||||
$(DESTDIR)${INSTALL_MANDIR}/man5/cmap.5 \
|
||||
$(DESTDIR)${INSTALL_MANDIR}/man5/displays.5 \
|
||||
$(DESTDIR)${INSTALL_MANDIR}/man5/dlys.5 \
|
||||
$(DESTDIR)${INSTALL_MANDIR}/man5/dstyle.5 \
|
||||
$(DESTDIR)${INSTALL_MANDIR}/man5/ext.5 \
|
||||
$(DESTDIR)${INSTALL_MANDIR}/man5/glyphs.5 \
|
||||
$(DESTDIR)${INSTALL_MANDIR}/man5/mag.5 \
|
||||
$(DESTDIR)${INSTALL_MANDIR}/man5/net.5 \
|
||||
$(DESTDIR)${INSTALL_MANDIR}/man5/sim.5
|
||||
|
||||
install: ${MANFILES}
|
||||
|
||||
$(DESTDIR)${MANDIR}:
|
||||
${SCRIPTS}/mkdirs $(DESTDIR)${MANDIR}
|
||||
$(DESTDIR)${INSTALL_MANDIR}:
|
||||
${SCRIPTS}/mkdirs $(DESTDIR)${INSTALL_MANDIR}
|
||||
|
||||
$(DESTDIR)${MANDIR}/man1: $(DESTDIR)${MANDIR}
|
||||
${SCRIPTS}/mkdirs $(DESTDIR)${MANDIR}/man1
|
||||
$(DESTDIR)${INSTALL_MANDIR}/man1: $(DESTDIR)${INSTALL_MANDIR}
|
||||
${SCRIPTS}/mkdirs $(DESTDIR)${INSTALL_MANDIR}/man1
|
||||
|
||||
$(DESTDIR)${MANDIR}/man1/%: % $(DESTDIR)${MANDIR}/man1
|
||||
${CP} $* $(DESTDIR)${MANDIR}/man1/$*
|
||||
$(DESTDIR)${INSTALL_MANDIR}/man1/%: % $(DESTDIR)${INSTALL_MANDIR}/man1
|
||||
${CP} $* $(DESTDIR)${INSTALL_MANDIR}/man1/$*
|
||||
|
||||
$(DESTDIR)${MANDIR}/man5: $(DESTDIR)${MANDIR}
|
||||
${SCRIPTS}/mkdirs $(DESTDIR)${MANDIR}/man5
|
||||
$(DESTDIR)${INSTALL_MANDIR}/man5: $(DESTDIR)${INSTALL_MANDIR}
|
||||
${SCRIPTS}/mkdirs $(DESTDIR)${INSTALL_MANDIR}/man5
|
||||
|
||||
$(DESTDIR)${MANDIR}/man5/%: % $(DESTDIR)${MANDIR}/man5
|
||||
${CP} $* $(DESTDIR)${MANDIR}/man5/$*
|
||||
$(DESTDIR)${INSTALL_MANDIR}/man5/%: % $(DESTDIR)${INSTALL_MANDIR}/man5
|
||||
${CP} $* $(DESTDIR)${INSTALL_MANDIR}/man5/$*
|
||||
|
||||
mans:
|
||||
${SCRIPTS}/printmans "${TROFF} ${MANMACS} -" *.1 *.5
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ MAGICDIR = ../..
|
|||
|
||||
include ${MAGICDIR}/defs.mak
|
||||
|
||||
TUTDIR = ${LIBDIR}/magic/tutorial
|
||||
TUTDIR = ${INSTALL_LIBDIR}/magic/tutorial
|
||||
|
||||
TUTFILES= m3a.mag maint2a.mag tut1.mag \
|
||||
tut2a.mag tut2b.mag tut2c.mag tut2d.mag \
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ static DRCCookie drcArrayCookie = {
|
|||
0, 0, 0, 0,
|
||||
{ 0 }, { 0 },
|
||||
0, 0, 0,
|
||||
"This layer can't abut or partially overlap between array elements",
|
||||
DRC_ARRAY_OVERLAP_TAG,
|
||||
(DRCCookie *) NULL
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ static DRCCookie drcOverlapCookie = {
|
|||
0, 0, 0, 0,
|
||||
{ 0 }, { 0 },
|
||||
0, 0, 0,
|
||||
"Can't overlap those layers",
|
||||
DRC_OVERLAP_TAG,
|
||||
(DRCCookie *) NULL
|
||||
};
|
||||
|
||||
|
|
@ -484,6 +484,7 @@ drcTile (tile, arg)
|
|||
int edgeX = LEFT(tile);
|
||||
|
||||
firsttile = TRUE;
|
||||
mrd = NULL;
|
||||
for (tpleft = BL(tile); BOTTOM(tpleft) < top; tpleft = RT(tpleft))
|
||||
{
|
||||
/* Get the tile types to the left and right of the edge */
|
||||
|
|
@ -554,8 +555,6 @@ drcTile (tile, arg)
|
|||
mrd = drcCanonicalMaxwidth(tpleft, GEO_WEST, arg, cptr);
|
||||
else if (firsttile)
|
||||
mrd = drcCanonicalMaxwidth(tile, GEO_EAST, arg, cptr);
|
||||
else
|
||||
mrd = NULL;
|
||||
if (!trigpending || (DRCCurStyle->DRCFlags
|
||||
& DRC_FLAGS_WIDEWIDTH_NONINCLUSIVE))
|
||||
cptr->drcc_dist--;
|
||||
|
|
@ -610,7 +609,6 @@ drcTile (tile, arg)
|
|||
drcCheckMaxwidth(tile, arg, cptr);
|
||||
continue;
|
||||
}
|
||||
else if (!triggered) mrd = NULL;
|
||||
|
||||
if (cptr->drcc_flags & DRC_RECTSIZE)
|
||||
{
|
||||
|
|
@ -625,6 +623,7 @@ drcTile (tile, arg)
|
|||
|
||||
result = 0;
|
||||
arg->dCD_radial = 0;
|
||||
arg->dCD_entries = 0;
|
||||
do {
|
||||
if (triggered)
|
||||
{
|
||||
|
|
@ -870,6 +869,7 @@ checkbottom:
|
|||
|
||||
/* Go right across bottom of tile */
|
||||
firsttile = TRUE;
|
||||
mrd = NULL;
|
||||
for (tpbot = LB(tile); LEFT(tpbot) < right; tpbot = TR(tpbot))
|
||||
{
|
||||
/* Get the tile types to the top and bottom of the edge */
|
||||
|
|
@ -936,8 +936,6 @@ checkbottom:
|
|||
mrd = drcCanonicalMaxwidth(tpbot, GEO_SOUTH, arg, cptr);
|
||||
else if (firsttile)
|
||||
mrd = drcCanonicalMaxwidth(tile, GEO_NORTH, arg, cptr);
|
||||
else
|
||||
mrd = NULL;
|
||||
if (!trigpending || (DRCCurStyle->DRCFlags
|
||||
& DRC_FLAGS_WIDEWIDTH_NONINCLUSIVE))
|
||||
cptr->drcc_dist--;
|
||||
|
|
@ -992,10 +990,10 @@ checkbottom:
|
|||
if (trigpending) cptr = cptr->drcc_next;
|
||||
continue;
|
||||
}
|
||||
else if (!triggered) mrd = NULL;
|
||||
|
||||
result = 0;
|
||||
arg->dCD_radial = 0;
|
||||
arg->dCD_entries = 0;
|
||||
do {
|
||||
if (triggered)
|
||||
{
|
||||
|
|
|
|||
76
drc/DRCcif.c
76
drc/DRCcif.c
|
|
@ -48,7 +48,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "utils/malloc.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
extern char *drcWhyDup();
|
||||
extern int drcCifTile();
|
||||
extern int areaCifCheck();
|
||||
extern void drcCheckCifMaxwidth();
|
||||
|
|
@ -67,9 +66,10 @@ extern bool DRCForceReload;
|
|||
TileTypeBitMask drcCifGenLayers;
|
||||
|
||||
DRCCookie *drcCifRules[MAXCIFLAYERS][2];
|
||||
DRCCookie *drcCifCur=NULL;
|
||||
DRCCookie *drcCifCur = NULL;
|
||||
int drcCifValid = FALSE;
|
||||
int beenWarned;
|
||||
bool beenWarned = FALSE;
|
||||
char *drcNeedStyle = NULL;
|
||||
|
||||
#define DRC_CIF_SPACE 0
|
||||
#define DRC_CIF_SOLID 1
|
||||
|
|
@ -112,14 +112,12 @@ drcCifSetStyle(argc, argv)
|
|||
{
|
||||
if (!strcmp(new->cs_name, argv[1]))
|
||||
{
|
||||
drcNeedStyle = new->cs_name;
|
||||
DRCForceReload = TRUE;
|
||||
if (!strcmp(new->cs_name, CIFCurStyle->cs_name))
|
||||
drcCifStyle = CIFCurStyle;
|
||||
else
|
||||
{
|
||||
TechError("DRC cif extensions are not enabled.\n\t"
|
||||
"Use \"cif ostyle %s\" to enable them.\n",
|
||||
new->cs_name);
|
||||
drcCifStyle = NULL;
|
||||
beenWarned = TRUE; /* post no more error messages */
|
||||
}
|
||||
|
|
@ -170,7 +168,7 @@ drcCifWidth(argc, argv)
|
|||
char *layername = argv[1];
|
||||
int scalefactor;
|
||||
int centidistance = atoi(argv[2]);
|
||||
char *why = drcWhyDup(argv[3]);
|
||||
int why = drcWhyCreate(argv[3]);
|
||||
TileTypeBitMask set, setC, tmp1;
|
||||
int thislayer = -1;
|
||||
DRCCookie *dpnew,*dpnext;
|
||||
|
|
@ -200,7 +198,7 @@ drcCifWidth(argc, argv)
|
|||
|
||||
dpnext = drcCifRules[thislayer][DRC_CIF_SPACE];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
||||
drcAssign(dpnew, centidistance, dpnext, &CIFSolidBits,
|
||||
drcCifAssign(dpnew, centidistance, dpnext, &CIFSolidBits,
|
||||
&CIFSolidBits, why, centidistance,
|
||||
DRC_FORWARD, thislayer, 0);
|
||||
drcCifRules[thislayer][DRC_CIF_SPACE] = dpnew;
|
||||
|
|
@ -229,7 +227,7 @@ drcCifSpacing(argc, argv)
|
|||
char *argv[];
|
||||
{
|
||||
char *adjacency = argv[4];
|
||||
char *why = drcWhyDup(argv[5]);
|
||||
int why = drcWhyCreate(argv[5]);
|
||||
DRCCookie *dpnext, *dpnew;
|
||||
int needReverse = FALSE;
|
||||
TileType i, j;
|
||||
|
|
@ -292,7 +290,7 @@ drcCifSpacing(argc, argv)
|
|||
centidistance *= drcCifStyle->cs_expander; // BSI
|
||||
dpnext = drcCifRules[layer[0]][DRC_CIF_SOLID];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) sizeof (DRCCookie));
|
||||
drcAssign(dpnew, centidistance, dpnext, &DBSpaceBits,
|
||||
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits,
|
||||
&cmask, why, centidistance, DRC_FORWARD, layer[1], 0);
|
||||
drcCifRules[layer[0]][DRC_CIF_SOLID] = dpnew;
|
||||
if (needReverse) dpnew->drcc_flags |= DRC_BOTHCORNERS;
|
||||
|
|
@ -300,7 +298,7 @@ drcCifSpacing(argc, argv)
|
|||
// Add rule in reverse direction
|
||||
dpnext = drcCifRules[layer[0]][DRC_CIF_SPACE];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) sizeof (DRCCookie));
|
||||
drcAssign(dpnew, centidistance, dpnext, &DBSpaceBits,
|
||||
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits,
|
||||
&cmask, why, centidistance, DRC_REVERSE, layer[1], 0);
|
||||
drcCifRules[layer[0]][DRC_CIF_SPACE] = dpnew;
|
||||
|
||||
|
|
@ -312,14 +310,14 @@ drcCifSpacing(argc, argv)
|
|||
dpnew->drcc_flags |= DRC_BOTHCORNERS;
|
||||
dpnext = drcCifRules[layer[1]][DRC_CIF_SOLID];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
||||
drcAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask,
|
||||
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask,
|
||||
why, centidistance, DRC_FORWARD|DRC_BOTHCORNERS, layer[0], 0);
|
||||
drcCifRules[layer[1]][DRC_CIF_SOLID] = dpnew;
|
||||
|
||||
// Add rule in reverse direction
|
||||
dpnext = drcCifRules[layer[1]][DRC_CIF_SPACE];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) sizeof (DRCCookie));
|
||||
drcAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask,
|
||||
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask,
|
||||
why, centidistance, DRC_REVERSE|DRC_BOTHCORNERS, layer[0], 0);
|
||||
drcCifRules[layer[1]][DRC_CIF_SPACE] = dpnew;
|
||||
|
||||
|
|
@ -327,14 +325,14 @@ drcCifSpacing(argc, argv)
|
|||
{
|
||||
dpnext = drcCifRules[layer[1]][DRC_CIF_SPACE];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
||||
drcAssign(dpnew, centidistance, dpnext, &DBSpaceBits,
|
||||
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits,
|
||||
&cmask, why, centidistance, DRC_REVERSE | DRC_BOTHCORNERS,
|
||||
layer[0], 0);
|
||||
drcCifRules[layer[1]][DRC_CIF_SPACE] = dpnew;
|
||||
|
||||
dpnext = drcCifRules[layer[0]][DRC_CIF_SPACE];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
||||
drcAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask,
|
||||
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask,
|
||||
why, centidistance, DRC_REVERSE | DRC_BOTHCORNERS,
|
||||
layer[1], 0);
|
||||
drcCifRules[layer[0]][DRC_CIF_SPACE] = dpnew;
|
||||
|
|
@ -345,13 +343,13 @@ drcCifSpacing(argc, argv)
|
|||
{
|
||||
dpnext = drcCifRules[layer[1]][DRC_CIF_SPACE];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
||||
drcAssign(dpnew, scalefactor, dpnext, &DBSpaceBits, &DBZeroTypeBits,
|
||||
drcCifAssign(dpnew, scalefactor, dpnext, &DBSpaceBits, &DBZeroTypeBits,
|
||||
why, scalefactor, DRC_FORWARD, layer[0], 0);
|
||||
drcCifRules[layer[1]][DRC_CIF_SPACE] = dpnew;
|
||||
|
||||
dpnext = drcCifRules[layer[0]][DRC_CIF_SPACE];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
||||
drcAssign(dpnew, scalefactor, dpnext, &DBSpaceBits, &DBZeroTypeBits,
|
||||
drcCifAssign(dpnew, scalefactor, dpnext, &DBSpaceBits, &DBZeroTypeBits,
|
||||
why, scalefactor, DRC_FORWARD, layer[1], 0);
|
||||
drcCifRules[layer[0]][DRC_CIF_SPACE] = dpnew;
|
||||
}
|
||||
|
|
@ -501,9 +499,37 @@ drcCifCheck(arg)
|
|||
int scale;
|
||||
int i,j;
|
||||
int oldTiles;
|
||||
CIFStyle *CIFSaveStyle = NULL;
|
||||
|
||||
if (drcCifValid == FALSE) return;
|
||||
else if (CIFCurStyle != drcCifStyle) return;
|
||||
if (CIFCurStyle != drcCifStyle)
|
||||
{
|
||||
if (drcNeedStyle == NULL) return;
|
||||
|
||||
CIFSaveStyle = CIFCurStyle;
|
||||
|
||||
if (drcCifStyle == NULL)
|
||||
{
|
||||
TxPrintf("Loading DRC CIF style.\n");
|
||||
CIFCurStyle = NULL;
|
||||
CIFLoadStyle(drcNeedStyle);
|
||||
if (drcCifValid != FALSE)
|
||||
CIFCurStyle = CIFSaveStyle;
|
||||
else
|
||||
drcCifStyle = CIFCurStyle;
|
||||
}
|
||||
if (drcCifStyle == NULL)
|
||||
{
|
||||
TxError("Error: Failed to load CIF DRC style.\n");
|
||||
return;
|
||||
}
|
||||
CIFCurStyle = drcCifStyle;
|
||||
}
|
||||
if (drcCifValid == FALSE)
|
||||
{
|
||||
if (CIFSaveStyle != NULL)
|
||||
CIFCurStyle = CIFSaveStyle;
|
||||
return;
|
||||
}
|
||||
|
||||
scale = drcCifStyle->cs_scaleFactor;
|
||||
cifrect = *checkRect;
|
||||
|
|
@ -534,6 +560,9 @@ drcCifCheck(arg)
|
|||
}
|
||||
arg->dCD_rect = checkRect;
|
||||
DRCstatCifTiles += DRCstatTiles - oldTiles;
|
||||
|
||||
/* Put it back the way you found it */
|
||||
if (CIFSaveStyle != NULL) CIFCurStyle = CIFSaveStyle;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1035,7 +1064,7 @@ drcCifArea(argc, argv)
|
|||
char *layers = argv[1];
|
||||
int centiarea = atoi(argv[2]);
|
||||
int centihorizon = atoi(argv[3]);
|
||||
char *why = drcWhyDup(argv[4]);
|
||||
int why = drcWhyCreate(argv[4]);
|
||||
TileTypeBitMask set, setC, tmp1;
|
||||
DRCCookie *dpnext, *dpnew;
|
||||
TileType i, j;
|
||||
|
|
@ -1066,7 +1095,7 @@ drcCifArea(argc, argv)
|
|||
centiarea *= (drcCifStyle->cs_expander * drcCifStyle->cs_expander);
|
||||
dpnext = drcCifRules[thislayer][DRC_CIF_SPACE];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
||||
drcAssign(dpnew, centihorizon, dpnext, &CIFSolidBits, &CIFSolidBits,
|
||||
drcCifAssign(dpnew, centihorizon, dpnext, &CIFSolidBits, &CIFSolidBits,
|
||||
why, centiarea, DRC_AREA | DRC_FORWARD, thislayer, 0);
|
||||
drcCifRules[thislayer][DRC_CIF_SPACE] = dpnew;
|
||||
|
||||
|
|
@ -1096,7 +1125,7 @@ drcCifMaxwidth(argc, argv)
|
|||
char *layers = argv[1];
|
||||
int centidistance = atoi(argv[2]);
|
||||
char *bends = argv[3];
|
||||
char *why = drcWhyDup(argv[4]);
|
||||
int why = drcWhyCreate(argv[4]);
|
||||
TileTypeBitMask set, setC, tmp1;
|
||||
DRCCookie *dpnext, *dpnew;
|
||||
TileType i, j;
|
||||
|
|
@ -1136,11 +1165,10 @@ drcCifMaxwidth(argc, argv)
|
|||
centidistance *= drcCifStyle->cs_expander; // BSI
|
||||
dpnext = drcCifRules[thislayer][DRC_CIF_SPACE];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
||||
drcAssign(dpnew, centidistance, dpnext, &CIFSolidBits, &CIFSolidBits,
|
||||
drcCifAssign(dpnew, centidistance, dpnext, &CIFSolidBits, &CIFSolidBits,
|
||||
why, centidistance, DRC_MAXWIDTH | bend, thislayer, 0);
|
||||
drcCifRules[thislayer][DRC_CIF_SPACE] = dpnew;
|
||||
|
||||
|
||||
return ((centidistance+scalefactor-1)/scalefactor);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,9 +69,8 @@ TileType DRCErrorType; /* Type of error tile to paint. */
|
|||
|
||||
/* Used by drcPrintError: */
|
||||
|
||||
HashTable DRCErrorTable; /* Hash table used to eliminate duplicate
|
||||
* error strings.
|
||||
*/
|
||||
int *DRCErrorList; /* List of DRC error type counts */
|
||||
HashTable DRCErrorTable; /* Table of DRC errors and geometry */
|
||||
|
||||
/* Global variables used by all DRC modules to record statistics.
|
||||
* For each statistic we keep two values, the count since stats
|
||||
|
|
@ -183,11 +182,12 @@ drcSubstitute (cptr)
|
|||
DRCCookie * cptr; /* Design rule violated */
|
||||
{
|
||||
static char *why_out = NULL;
|
||||
char *whyptr = cptr->drcc_why, *sptr, *wptr;
|
||||
char *whyptr, *sptr, *wptr;
|
||||
int subscnt = 0, whylen;
|
||||
float oscale, value;
|
||||
extern float CIFGetOutputScale();
|
||||
|
||||
whyptr = DRCCurStyle->DRCWhyList[cptr->drcc_tag];
|
||||
while ((sptr = strchr(whyptr, '%')) != NULL)
|
||||
{
|
||||
subscnt++;
|
||||
|
|
@ -195,7 +195,7 @@ drcSubstitute (cptr)
|
|||
}
|
||||
if (subscnt == 0) return whyptr; /* No substitutions */
|
||||
|
||||
whyptr = cptr->drcc_why;
|
||||
whyptr = DRCCurStyle->DRCWhyList[cptr->drcc_tag];
|
||||
whylen = strlen(whyptr) + 20 * subscnt;
|
||||
if (why_out != NULL) freeMagic(why_out);
|
||||
why_out = (char *)mallocMagic(whylen * sizeof(char));
|
||||
|
|
@ -256,7 +256,7 @@ drcSubstitute (cptr)
|
|||
*
|
||||
* Side effects:
|
||||
* DRCErrorCount is incremented. The text associated with
|
||||
* the error is entered into DRCErrorTable, and, if this is
|
||||
* the error is entered into DRCErrorList, and, if this is
|
||||
* the first time that entry has been seen, then the error
|
||||
* text is printed. If the area parameter is non-NULL, then
|
||||
* only errors intersecting that area are considered.
|
||||
|
|
@ -279,12 +279,11 @@ drcPrintError (celldef, rect, cptr, scx)
|
|||
area = &scx->scx_area;
|
||||
if ((area != NULL) && (!GEO_OVERLAP(area, rect))) return;
|
||||
DRCErrorCount += 1;
|
||||
h = HashFind(&DRCErrorTable, cptr->drcc_why);
|
||||
i = (spointertype) HashGetValue(h);
|
||||
|
||||
i = DRCErrorList[cptr->drcc_tag];
|
||||
if (i == 0)
|
||||
TxPrintf("%s\n", drcSubstitute(cptr));
|
||||
i++;
|
||||
HashSetValue(h, (spointertype)i);
|
||||
DRCErrorList[cptr->drcc_tag] = i + 1;
|
||||
}
|
||||
|
||||
/* Same routine as above, but output goes to a Tcl list and is appended */
|
||||
|
|
@ -308,8 +307,7 @@ drcListError (celldef, rect, cptr, scx)
|
|||
area = &scx->scx_area;
|
||||
if ((area != NULL) && (!GEO_OVERLAP(area, rect))) return;
|
||||
DRCErrorCount += 1;
|
||||
h = HashFind(&DRCErrorTable, cptr->drcc_why);
|
||||
i = (spointertype) HashGetValue(h);
|
||||
i = DRCErrorList[cptr->drcc_tag];
|
||||
if (i == 0)
|
||||
{
|
||||
Tcl_Obj *lobj;
|
||||
|
|
@ -318,8 +316,7 @@ drcListError (celldef, rect, cptr, scx)
|
|||
Tcl_NewStringObj(drcSubstitute(cptr), -1));
|
||||
Tcl_SetObjResult(magicinterp, lobj);
|
||||
}
|
||||
i += 1;
|
||||
HashSetValue(h, (spointertype)i);
|
||||
DRCErrorList[cptr->drcc_tag] = i + 1;
|
||||
}
|
||||
|
||||
/* Same routine as above, but output for every single error is recorded */
|
||||
|
|
@ -343,7 +340,7 @@ drcListallError (celldef, rect, cptr, scx)
|
|||
area = &scx->scx_area;
|
||||
if ((area != NULL) && (!GEO_OVERLAP(area, rect))) return;
|
||||
DRCErrorCount += 1;
|
||||
h = HashFind(&DRCErrorTable, cptr->drcc_why);
|
||||
h = HashFind(&DRCErrorTable, drcSubstitute(cptr));
|
||||
lobj = (Tcl_Obj *) HashGetValue(h);
|
||||
if (lobj == NULL)
|
||||
lobj = Tcl_NewListObj(0, NULL);
|
||||
|
|
@ -475,11 +472,15 @@ DRCWhy(dolist, use, area)
|
|||
{
|
||||
SearchContext scx;
|
||||
Rect box;
|
||||
int i;
|
||||
extern int drcWhyFunc(); /* Forward reference. */
|
||||
|
||||
/* Create a hash table to used for eliminating duplicate messages. */
|
||||
/* Create a hash table to eliminate duplicate messages. */
|
||||
|
||||
DRCErrorList = (int *)mallocMagic((DRCCurStyle->DRCWhySize + 1) * sizeof(int));
|
||||
for (i = 0; i <= DRCCurStyle->DRCWhySize; i++)
|
||||
DRCErrorList[i] = 0;
|
||||
|
||||
HashInit(&DRCErrorTable, 16, HT_STRINGKEYS);
|
||||
DRCErrorCount = 0;
|
||||
box = DRCdef->cd_bbox;
|
||||
|
||||
|
|
@ -494,12 +495,9 @@ DRCWhy(dolist, use, area)
|
|||
drcWhyFunc(&scx, (pointertype)dolist);
|
||||
UndoEnable();
|
||||
|
||||
/* Delete the hash table now that we're finished (otherwise there
|
||||
* will be a core leak.
|
||||
*/
|
||||
|
||||
HashKill(&DRCErrorTable);
|
||||
|
||||
/* Delete the error list */
|
||||
freeMagic(DRCErrorList);
|
||||
|
||||
/* Redisplay the DRC yank definition in case anyone is looking
|
||||
* at it.
|
||||
*/
|
||||
|
|
@ -532,7 +530,7 @@ DRCWhyAll(use, area, fout)
|
|||
HashEntry *he;
|
||||
Tcl_Obj *lobj, *robj;
|
||||
|
||||
/* Create a hash table to used for eliminating duplicate messages. */
|
||||
/* Create a hash table for storing all of the results */
|
||||
|
||||
HashInit(&DRCErrorTable, 16, HT_STRINGKEYS);
|
||||
DRCErrorCount = 0;
|
||||
|
|
@ -566,10 +564,7 @@ DRCWhyAll(use, area, fout)
|
|||
}
|
||||
Tcl_SetObjResult(magicinterp, robj);
|
||||
|
||||
/* Delete the hash table now that we're finished (otherwise there
|
||||
* will be a core leak.
|
||||
*/
|
||||
|
||||
/* Delete the error table now that we're finished */
|
||||
HashKill(&DRCErrorTable);
|
||||
|
||||
/* Redisplay the DRC yank definition in case anyone is looking
|
||||
|
|
@ -748,9 +743,10 @@ drcCheckFunc(scx, cdarg)
|
|||
*/
|
||||
|
||||
DRCCountList *
|
||||
DRCCount(use, area)
|
||||
DRCCount(use, area, recurse)
|
||||
CellUse *use; /* Top-level use of hierarchy. */
|
||||
Rect *area; /* Area in which violations are counted. */
|
||||
bool recurse; /* If TRUE, count errors in all subcells */
|
||||
{
|
||||
DRCCountList *dcl, *newdcl;
|
||||
HashTable dupTable;
|
||||
|
|
@ -758,7 +754,11 @@ DRCCount(use, area)
|
|||
HashSearch hs;
|
||||
int count;
|
||||
SearchContext scx;
|
||||
extern int drcCountFunc(); /* Forward reference. */
|
||||
CellDef *def;
|
||||
extern int drcCountFunc();
|
||||
|
||||
/* Shouldn't happen? */
|
||||
if (!(use->cu_def->cd_flags & CDAVAILABLE)) return NULL;
|
||||
|
||||
/* Use a hash table to make sure that we don't output information
|
||||
* for any cell more than once.
|
||||
|
|
@ -766,6 +766,10 @@ DRCCount(use, area)
|
|||
|
||||
HashInit(&dupTable, 16, HT_WORDKEYS);
|
||||
|
||||
/* Clearing CDAVAILABLE from cd_flags keeps the count from recursing */
|
||||
if (recurse == FALSE)
|
||||
use->cu_def->cd_flags &= ~CDAVAILABLE;
|
||||
|
||||
scx.scx_use = use;
|
||||
scx.scx_x = use->cu_xlo;
|
||||
scx.scx_y = use->cu_ylo;
|
||||
|
|
@ -781,7 +785,7 @@ DRCCount(use, area)
|
|||
HashStartSearch(&hs);
|
||||
while ((he = HashNext(&dupTable, &hs)) != (HashEntry *)NULL)
|
||||
{
|
||||
count = (spointertype)HashGetValue(he);
|
||||
count = (spointertype)HashGetValue(he);
|
||||
if (count > 1)
|
||||
{
|
||||
newdcl = (DRCCountList *)mallocMagic(sizeof(DRCCountList));
|
||||
|
|
@ -793,15 +797,20 @@ DRCCount(use, area)
|
|||
}
|
||||
}
|
||||
HashKill(&dupTable);
|
||||
|
||||
/* Restore the CDAVAILABLE flag */
|
||||
if (recurse == FALSE)
|
||||
use->cu_def->cd_flags |= CDAVAILABLE;
|
||||
|
||||
return dcl;
|
||||
}
|
||||
|
||||
int
|
||||
drcCountFunc(scx, dupTable)
|
||||
SearchContext *scx;
|
||||
HashTable *dupTable; /* Passed as client data, used to
|
||||
* avoid searching any cell twice.
|
||||
*/
|
||||
HashTable *dupTable; /* Passed as client data, used to
|
||||
* avoid searching any cell twice.
|
||||
*/
|
||||
{
|
||||
int count;
|
||||
HashEntry *h;
|
||||
|
|
@ -821,7 +830,7 @@ drcCountFunc(scx, dupTable)
|
|||
|
||||
count = 0;
|
||||
(void) DBSrPaintArea((Tile *) NULL, def->cd_planes[PL_DRC_ERROR],
|
||||
&def->cd_bbox, &DBAllButSpaceBits, drcCountFunc2, (ClientData) &count);
|
||||
&def->cd_bbox, &DBAllButSpaceBits, drcCountFunc2, (ClientData)(&count));
|
||||
HashSetValue(h, (spointertype)count + 1);
|
||||
|
||||
/* Ignore children that have not been loaded---we will only report */
|
||||
|
|
@ -832,26 +841,26 @@ drcCountFunc(scx, dupTable)
|
|||
|
||||
if ((scx->scx_use->cu_def->cd_flags & CDAVAILABLE) == 0) return 0;
|
||||
|
||||
/* New behavior: Don't search children, instead propagate errors up. */
|
||||
/* (void) DBCellSrArea(scx, drcCountFunc, (ClientData) dupTable); */
|
||||
/* Scan children recursively. */
|
||||
|
||||
DBCellSrArea(scx, drcCountFunc, (ClientData)dupTable);
|
||||
|
||||
/* As a special performance hack, if the complete cell area is
|
||||
* handled here, don't bother to look at any more array elements.
|
||||
*/
|
||||
|
||||
done: if (GEO_SURROUND(&scx->scx_area, &def->cd_bbox)) return 2;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
int
|
||||
drcCountFunc2(tile, pCount)
|
||||
Tile *tile; /* Tile found in error plane. */
|
||||
int *pCount; /* Address of count word. */
|
||||
drcCountFunc2(tile, countptr)
|
||||
Tile *tile; /* Tile found in error plane. */
|
||||
int *countptr; /* Address of count word. */
|
||||
{
|
||||
if (TiGetType(tile) != (TileType) TT_SPACE) *pCount += 1;
|
||||
if (TiGetType(tile) != (TileType) TT_SPACE) (*countptr)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -963,13 +972,15 @@ drcFindFunc(scx, finddata)
|
|||
CellDef *def;
|
||||
HashEntry *h;
|
||||
int drcFindFunc2();
|
||||
bool dereference;
|
||||
|
||||
def = scx->scx_use->cu_def;
|
||||
h = HashFind(finddata->deft, (char *)def);
|
||||
if (HashGetValue(h) != 0) return 0;
|
||||
HashSetValue(h, 1);
|
||||
|
||||
(void) DBCellRead(def, (char *) NULL, TRUE, NULL);
|
||||
dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
(void) DBCellRead(def, (char *) NULL, TRUE, dereference, NULL);
|
||||
|
||||
if (DBSrPaintArea((Tile *) NULL, def->cd_planes[PL_DRC_ERROR],
|
||||
&def->cd_bbox, &DBAllButSpaceBits, drcFindFunc2,
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ static DRCCookie drcSubcellCookie = {
|
|||
0, 0, 0, 0,
|
||||
{ 0 }, { 0 },
|
||||
0, 0, 0,
|
||||
"This layer can't abut or partially overlap between subcells",
|
||||
DRC_SUBCELL_OVERLAP_TAG,
|
||||
(DRCCookie *) NULL
|
||||
};
|
||||
|
||||
|
|
|
|||
167
drc/DRCtech.c
167
drc/DRCtech.c
|
|
@ -40,6 +40,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
|
||||
CIFStyle *drcCifStyle = NULL;
|
||||
bool DRCForceReload = FALSE;
|
||||
HashTable DRCWhyErrorTable; /* Table of DRC errors */
|
||||
|
||||
/*
|
||||
* DRC interaction radius being used (not necessarily the same as
|
||||
|
|
@ -61,6 +62,11 @@ global int DRCRuleOptimization = TRUE;
|
|||
static int drcRulesSpecified = 0;
|
||||
static int drcRulesOptimized = 0;
|
||||
|
||||
/* Rules with unique names are tagged with a reference number */
|
||||
/* for use in placing errors into the DRC error plane. */
|
||||
|
||||
static int DRCtag = 0;
|
||||
|
||||
/*
|
||||
* Forward declarations.
|
||||
*/
|
||||
|
|
@ -281,21 +287,14 @@ drcTechFreeStyle()
|
|||
dp = DRCCurStyle->DRCRulesTbl[i][j];
|
||||
while (dp != NULL)
|
||||
{
|
||||
char *old = (char *) dp;
|
||||
char *old = (char *)dp;
|
||||
dp = dp->drcc_next;
|
||||
freeMagic(old);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the DRCWhyList */
|
||||
|
||||
while (DRCCurStyle->DRCWhyList != NULL)
|
||||
{
|
||||
old = (char *) DRCCurStyle->DRCWhyList;
|
||||
StrDup(&(DRCCurStyle->DRCWhyList->dwl_string), (char *) NULL);
|
||||
DRCCurStyle->DRCWhyList = DRCCurStyle->DRCWhyList->dwl_next;
|
||||
freeMagic(old);
|
||||
}
|
||||
/* Clear the Why string list */
|
||||
freeMagic(DRCCurStyle->DRCWhyList);
|
||||
|
||||
freeMagic(DRCCurStyle);
|
||||
DRCCurStyle = NULL;
|
||||
|
|
@ -329,31 +328,55 @@ drcTechNewStyle()
|
|||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* drcWhyDup --
|
||||
* drcWhyCreate --
|
||||
*
|
||||
* Duplicate a shared "why" string using StrDup() and remember it so we can
|
||||
* free it sometime later, in drcWhyClear().
|
||||
* Create a hash entry for the DRC "why" string, if it does not already
|
||||
* exist.
|
||||
*
|
||||
* Returns:
|
||||
* A copy of the given string.
|
||||
* A pointer to the drcWhy structure containing the string and tag.
|
||||
*
|
||||
* Side effects:
|
||||
* Adds to the DRCWhyList. Calls StrDup().
|
||||
* Adds to the DRCWhyList if whystring has not been used before.
|
||||
* Calls StrDup() and increments DRCWhySize. DRCWhyList is allocated
|
||||
* in blocks of 50 at a time and only expands when filled.
|
||||
* Temporary hash table DRCWhyErrorTable is used to determine if a
|
||||
* string entry is unique. It is cleared after the technology file
|
||||
* has been processed.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
char *
|
||||
drcWhyDup(why)
|
||||
char * why;
|
||||
int
|
||||
drcWhyCreate(whystring)
|
||||
char *whystring;
|
||||
{
|
||||
struct drcwhylist * new;
|
||||
HashEntry *he;
|
||||
|
||||
new = (struct drcwhylist *) mallocMagic((unsigned) (sizeof *new));
|
||||
new->dwl_string = StrDup((char **) NULL, why);
|
||||
new->dwl_next = DRCCurStyle->DRCWhyList;
|
||||
DRCCurStyle->DRCWhyList = new;
|
||||
he = HashLookOnly(&DRCWhyErrorTable, whystring);
|
||||
if (he != NULL)
|
||||
return (int)((pointertype)HashGetValue(he));
|
||||
|
||||
return new->dwl_string;
|
||||
/* Grow the list in increments of 50 */
|
||||
if ((DRCCurStyle->DRCWhySize % 50) == 0)
|
||||
{
|
||||
int i;
|
||||
char **newList;
|
||||
newList = (char **)mallocMagic((DRCCurStyle->DRCWhySize + 51) * sizeof(char *));
|
||||
newList[0] = (char *)NULL;
|
||||
for (i = 1; i <= DRCCurStyle->DRCWhySize; i++)
|
||||
newList[i] = DRCCurStyle->DRCWhyList[i];
|
||||
if (DRCCurStyle->DRCWhySize > 0)
|
||||
freeMagic((char *)DRCCurStyle->DRCWhyList);
|
||||
DRCCurStyle->DRCWhyList = newList;
|
||||
}
|
||||
DRCCurStyle->DRCWhySize++;
|
||||
|
||||
he = HashFind(&DRCWhyErrorTable, whystring);
|
||||
HashSetValue(he, (char *)((pointertype)DRCCurStyle->DRCWhySize));
|
||||
|
||||
DRCCurStyle->DRCWhyList[DRCCurStyle->DRCWhySize] = StrDup((char **)NULL, whystring);
|
||||
|
||||
return DRCCurStyle->DRCWhySize;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -535,12 +558,29 @@ DRCTechStyleInit()
|
|||
DRCCurStyle->ds_status = TECH_NOT_LOADED;
|
||||
|
||||
TTMaskZero(&DRCCurStyle->DRCExactOverlapTypes);
|
||||
DRCCurStyle->DRCWhyList = NULL;
|
||||
DRCCurStyle->DRCTechHalo = 0;
|
||||
DRCCurStyle->DRCScaleFactorN = 1;
|
||||
DRCCurStyle->DRCScaleFactorD = 1;
|
||||
DRCCurStyle->DRCStepSize = 0;
|
||||
DRCCurStyle->DRCFlags = (char)0;
|
||||
DRCCurStyle->DRCWhySize = 0;
|
||||
|
||||
HashInit(&DRCWhyErrorTable, 16, HT_STRINGKEYS);
|
||||
|
||||
/* First DRC entry is associated with the statically-allocated */
|
||||
/* drcArrayCookie and has a tag of DRC_ARRAY_OVERLAP_TAG = 1 */
|
||||
/* (see DRCarray.c). */
|
||||
drcWhyCreate("This layer can't abut or partially overlap between array elements");
|
||||
|
||||
/* Second DRC entry is associated with the statically-allocated */
|
||||
/* drcOverlapCookie and has a tag of DRC_OVERLAP_TAG = 2 */
|
||||
/* (see DRCbasic.c). */
|
||||
drcWhyCreate("Can't overlap those layers");
|
||||
|
||||
/* Third DRC entry is associated with the statically-allocated */
|
||||
/* drcSubcellCookie and has a tag of DRC_SUBCELL_OVERLAP_TAG = 3 */
|
||||
/* (see DRCsubcell.c). */
|
||||
drcWhyCreate("This layer can't abut or partially overlap between subcells");
|
||||
|
||||
DRCTechHalo = 0;
|
||||
|
||||
|
|
@ -872,22 +912,18 @@ DRCTechLine(sectionName, argc, argv)
|
|||
}
|
||||
|
||||
void
|
||||
drcAssign(cookie, dist, next, mask, corner, why, cdist, flags, planeto, planefrom)
|
||||
drcCifAssign(cookie, dist, next, mask, corner, tag, cdist, flags, planeto, planefrom)
|
||||
DRCCookie *cookie, *next;
|
||||
int dist, cdist;
|
||||
TileTypeBitMask *mask, *corner;
|
||||
char *why;
|
||||
int tag;
|
||||
int flags, planeto, planefrom;
|
||||
{
|
||||
/* Diagnostic */
|
||||
if (planeto >= DBNumPlanes) {
|
||||
TxError("Bad plane in DRC assign!\n");
|
||||
}
|
||||
(cookie)->drcc_dist = dist;
|
||||
(cookie)->drcc_next = next;
|
||||
(cookie)->drcc_mask = *mask;
|
||||
(cookie)->drcc_corner = *corner;
|
||||
(cookie)->drcc_why = why;
|
||||
(cookie)->drcc_tag = tag;
|
||||
(cookie)->drcc_cdist = cdist;
|
||||
(cookie)->drcc_flags = flags;
|
||||
(cookie)->drcc_edgeplane = planefrom;
|
||||
|
|
@ -896,6 +932,27 @@ drcAssign(cookie, dist, next, mask, corner, why, cdist, flags, planeto, planefro
|
|||
(cookie)->drcc_cmod = 0;
|
||||
}
|
||||
|
||||
// This is like drcCifAssign, but checks for bad plane numbers in planeto and
|
||||
// planefrom
|
||||
|
||||
void
|
||||
drcAssign(cookie, dist, next, mask, corner, why, cdist, flags, planeto, planefrom)
|
||||
DRCCookie *cookie, *next;
|
||||
int dist, cdist;
|
||||
TileTypeBitMask *mask, *corner;
|
||||
int why;
|
||||
int flags, planeto, planefrom;
|
||||
{
|
||||
/* Diagnostic */
|
||||
if (planeto >= DBNumPlanes)
|
||||
TechError("Bad plane in DRC assignment.\n");
|
||||
if (planefrom >= DBNumPlanes)
|
||||
TechError("Bad edge plane in DRC assignment.\n");
|
||||
|
||||
drcCifAssign(cookie, dist, next, mask, corner, why, cdist, flags, planeto,
|
||||
planefrom);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -1071,7 +1128,7 @@ drcExtend(argc, argv)
|
|||
char *layers1 = argv[1];
|
||||
char *layers2 = argv[2];
|
||||
int distance = atoi(argv[3]);
|
||||
char *why;
|
||||
int why;
|
||||
TileTypeBitMask set1, setC;
|
||||
DRCCookie *dp, *dpnew, *dptrig;
|
||||
TileType i, j;
|
||||
|
|
@ -1083,10 +1140,10 @@ drcExtend(argc, argv)
|
|||
if (!strncmp(argv[4], "exact_", 6))
|
||||
{
|
||||
exact = TRUE;
|
||||
why = drcWhyDup(argv[5]);
|
||||
why = drcWhyCreate(argv[5]);
|
||||
}
|
||||
else
|
||||
why = drcWhyDup(argv[4]);
|
||||
why = drcWhyCreate(argv[4]);
|
||||
|
||||
ptest = DBTechNoisyNameMask(layers1, &set1);
|
||||
pMask1 = CoincidentPlanes(&set1, ptest);
|
||||
|
|
@ -1240,7 +1297,7 @@ drcWidth(argc, argv)
|
|||
{
|
||||
char *layers = argv[1];
|
||||
int distance = atoi(argv[2]);
|
||||
char *why = drcWhyDup(argv[3]);
|
||||
int why = drcWhyCreate(argv[3]);
|
||||
TileTypeBitMask set, setC;
|
||||
PlaneMask pmask, pset, ptest;
|
||||
DRCCookie *dp, *dpnew;
|
||||
|
|
@ -1325,7 +1382,7 @@ drcArea(argc, argv)
|
|||
char *layers = argv[1];
|
||||
int distance = atoi(argv[2]);
|
||||
int horizon = atoi(argv[3]);
|
||||
char *why = drcWhyDup(argv[4]);
|
||||
int why = drcWhyCreate(argv[4]);
|
||||
TileTypeBitMask set, setC;
|
||||
DRCCookie *dp, *dpnew;
|
||||
TileType i, j;
|
||||
|
|
@ -1425,7 +1482,7 @@ drcMaxwidth(argc, argv)
|
|||
char *layers = argv[1];
|
||||
int distance = atoi(argv[2]);
|
||||
char *bends = argv[3];
|
||||
char *why;
|
||||
int why;
|
||||
TileTypeBitMask set, setC;
|
||||
DRCCookie *dp, *dpnew;
|
||||
TileType i, j;
|
||||
|
|
@ -1452,7 +1509,7 @@ drcMaxwidth(argc, argv)
|
|||
bend = 0;
|
||||
else
|
||||
bend = DRC_BENDS;
|
||||
why = drcWhyDup(argv[3]);
|
||||
why = drcWhyCreate(argv[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1463,7 +1520,7 @@ drcMaxwidth(argc, argv)
|
|||
TechError("unknown bend option %s\n",bends);
|
||||
return (0);
|
||||
}
|
||||
why = drcWhyDup(argv[4]);
|
||||
why = drcWhyCreate(argv[4]);
|
||||
}
|
||||
|
||||
for (i = 0; i < DBNumTypes; i++)
|
||||
|
|
@ -1514,7 +1571,7 @@ drcAngles(argc, argv)
|
|||
{
|
||||
char *layers = argv[1];
|
||||
int angles = atoi(argv[2]);
|
||||
char *why = drcWhyDup(argv[3]);
|
||||
int why = drcWhyCreate(argv[3]);
|
||||
TileTypeBitMask set;
|
||||
DRCCookie *dp, *dpnew;
|
||||
int plane;
|
||||
|
|
@ -1582,7 +1639,7 @@ drcSpacing3(argc, argv)
|
|||
char *layers3 = argv[5];
|
||||
int distance = atoi(argv[3]);
|
||||
char *adjacency = argv[4];
|
||||
char *why = drcWhyDup(argv[6]);
|
||||
int why = drcWhyCreate(argv[6]);
|
||||
TileTypeBitMask set1, set2, set3;
|
||||
int plane;
|
||||
DRCCookie *dp, *dpnew;
|
||||
|
|
@ -2134,7 +2191,7 @@ drcSpacing(argc, argv)
|
|||
{
|
||||
char *layers1 = argv[1], *layers2;
|
||||
char *adjacency;
|
||||
char *why;
|
||||
int why;
|
||||
TileTypeBitMask set1, set2, tmp1, tmp2;
|
||||
PlaneMask pmask1, pmask2, pmaskA, pmaskB, ptest;
|
||||
int wwidth, distance, plane, plane2, runlength;
|
||||
|
|
@ -2155,7 +2212,7 @@ drcSpacing(argc, argv)
|
|||
layers2 = argv[4];
|
||||
distance = atoi(argv[5]);
|
||||
adjacency = argv[6];
|
||||
why = drcWhyDup(argv[7]);
|
||||
why = drcWhyCreate(argv[7]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2163,7 +2220,7 @@ drcSpacing(argc, argv)
|
|||
distance = atoi(argv[4]);
|
||||
runlength = distance;
|
||||
adjacency = argv[5];
|
||||
why = drcWhyDup(argv[6]);
|
||||
why = drcWhyCreate(argv[6]);
|
||||
}
|
||||
/* TxPrintf("Info: DRCtech: widespacing rule for %s width %d:"
|
||||
" spacing must be %d\n", layers1, wwidth, distance); */
|
||||
|
|
@ -2174,7 +2231,7 @@ drcSpacing(argc, argv)
|
|||
distance = atoi(argv[3]);
|
||||
adjacency = argv[4];
|
||||
wwidth = distance;
|
||||
why = drcWhyDup(argv[5]);
|
||||
why = drcWhyCreate(argv[5]);
|
||||
runlength = distance;
|
||||
if (argc >= 7)
|
||||
{
|
||||
|
|
@ -2308,7 +2365,7 @@ drcEdge(argc, argv)
|
|||
int distance = atoi(argv[3]);
|
||||
char *okTypes = argv[4], *cornerTypes = argv[5];
|
||||
int cdist = atoi(argv[6]);
|
||||
char *why = drcWhyDup(argv[7]);
|
||||
int why = drcWhyCreate(argv[7]);
|
||||
bool fourway = (strcmp(argv[0], "edge4way") == 0);
|
||||
TileTypeBitMask set1, set2, setC, setM;
|
||||
DRCCookie *dp, *dpnew;
|
||||
|
|
@ -2474,7 +2531,7 @@ drcOverhang(argc, argv)
|
|||
{
|
||||
char *layers2 = argv[1], *layers1 = argv[2];
|
||||
int distance = atoi(argv[3]);
|
||||
char *why = drcWhyDup(argv[4]);
|
||||
int why = drcWhyCreate(argv[4]);
|
||||
TileTypeBitMask set1, set2, setM, setC, setN, set2inv;
|
||||
DRCCookie *dp, *dpnew, *dptrig;
|
||||
int plane, plane2;
|
||||
|
|
@ -2610,7 +2667,7 @@ drcRectOnly(argc, argv)
|
|||
char *argv[];
|
||||
{
|
||||
char *layers = argv[1];
|
||||
char *why = drcWhyDup(argv[2]);
|
||||
int why = drcWhyCreate(argv[2]);
|
||||
TileTypeBitMask set1, set2, setC;
|
||||
PlaneMask pmask, pset, ptest;
|
||||
DRCCookie *dp, *dpnew;
|
||||
|
|
@ -2710,7 +2767,7 @@ drcSurround(argc, argv)
|
|||
char *layers1 = argv[1], *layers2 = argv[2];
|
||||
int distance = atoi(argv[3]);
|
||||
char *presence = argv[4];
|
||||
char *why = drcWhyDup(argv[5]);
|
||||
int why = drcWhyCreate(argv[5]);
|
||||
TileTypeBitMask set1, set2, setM, invM, setR;
|
||||
DRCCookie *dp, *dpnew, *dptrig;
|
||||
int plane1, plane2;
|
||||
|
|
@ -3083,7 +3140,7 @@ drcRectangle(argc, argv)
|
|||
char *argv[];
|
||||
{
|
||||
char *layers = argv[1];
|
||||
char *why = drcWhyDup(argv[4]);
|
||||
int why = drcWhyCreate(argv[4]);
|
||||
TileTypeBitMask types, nottypes;
|
||||
int maxwidth;
|
||||
static char *drcRectOpt[4] = {"any", "even", "odd", 0};
|
||||
|
|
@ -3449,6 +3506,9 @@ drcTechFinalStyle(style)
|
|||
DRCCookie **dpp, **dp2back;
|
||||
TileType i, j;
|
||||
|
||||
/* Done with DRCWhyErrorTable */
|
||||
HashKill(&DRCWhyErrorTable);
|
||||
|
||||
/* If the scale factor is not 1, then divide all distances by */
|
||||
/* the scale factor, take the ceiling, and save the (negative) */
|
||||
/* remainder. */
|
||||
|
|
@ -3570,7 +3630,6 @@ drcTechFinalStyle(style)
|
|||
}
|
||||
else
|
||||
{
|
||||
/* Don't free the shared drcc_why string here! */
|
||||
freeMagic((char *)dptest);
|
||||
drcRulesOptimized++;
|
||||
}
|
||||
|
|
@ -3665,7 +3724,8 @@ drcTechFinalStyle(style)
|
|||
|
||||
/* TxPrintf("For edge %s-%s, \"%s\" covers \"%s\"\n",
|
||||
DBTypeShortName(i), DBTypeShortName(j),
|
||||
next->drcc_why, dp->drcc_why);
|
||||
DRCCurStyle->DRCWhyList[next->drcc_tag],
|
||||
DRCCurStyle->DRCWhyList[dp->drcc_tag]);
|
||||
*/
|
||||
dp2back = &(style->DRCRulesTbl[i][j]);
|
||||
while (*dp2back != dp)
|
||||
|
|
@ -3687,7 +3747,6 @@ drcTechFinalStyle(style)
|
|||
else
|
||||
*dp2back = dp->drcc_next;
|
||||
|
||||
/* Don't free the shared drcc_why string here! */
|
||||
freeMagic((char *) dp);
|
||||
drcRulesOptimized += 1;
|
||||
}
|
||||
|
|
|
|||
35
drc/drc.h
35
drc/drc.h
|
|
@ -39,10 +39,15 @@ typedef struct drccookie
|
|||
int drcc_edgeplane; /* Plane of edge */
|
||||
int drcc_plane; /* Index of plane on which to check
|
||||
* legal types. */
|
||||
char *drcc_why; /* Explanation of error found */
|
||||
int drcc_tag; /* Tag to explanation of error found */
|
||||
struct drccookie *drcc_next;
|
||||
} DRCCookie;
|
||||
|
||||
/* These DRC tags in DRCcookie are predefined. */
|
||||
#define DRC_ARRAY_OVERLAP_TAG 1
|
||||
#define DRC_OVERLAP_TAG 2
|
||||
#define DRC_SUBCELL_OVERLAP_TAG 3
|
||||
|
||||
/* *This is size "int" because it holds an area for DRC_AREA rules, */
|
||||
/* and therefore may have twice the bit length of a normal rule distance. */
|
||||
|
||||
|
|
@ -129,9 +134,9 @@ typedef struct drcpendingcookie
|
|||
|
||||
typedef struct drccountlist
|
||||
{
|
||||
CellDef *dcl_def;
|
||||
int dcl_count;
|
||||
struct drccountlist *dcl_next;
|
||||
CellDef *dcl_def;
|
||||
int dcl_count;
|
||||
struct drccountlist *dcl_next;
|
||||
} DRCCountList;
|
||||
|
||||
/* Structure used to keep information about the current DRC style */
|
||||
|
|
@ -142,22 +147,6 @@ typedef struct drckeep
|
|||
char *ds_name;
|
||||
} DRCKeep;
|
||||
|
||||
/*
|
||||
* DRC "why" strings are potentially referred to hundreds of times by
|
||||
* DRC cookies in the rule table. Rather than creating hundreds of
|
||||
* copies of each string, we create just one copy and let all the cookies
|
||||
* point to that one copy.
|
||||
*
|
||||
* Since we can't free these shared "why" strings when we delete a cookie,
|
||||
* we keep a list of these strings and free them all when convenient.
|
||||
*/
|
||||
|
||||
typedef struct drcwhylist
|
||||
{
|
||||
char * dwl_string;
|
||||
struct drcwhylist * dwl_next;
|
||||
} drcWhyList;
|
||||
|
||||
/*
|
||||
* Structure defining a DRC style
|
||||
*/
|
||||
|
|
@ -173,7 +162,8 @@ typedef struct drcstyle
|
|||
int DRCTechHalo; /* largest action distance of design rules */
|
||||
int DRCStepSize; /* chunk size for decomposing large areas */
|
||||
char DRCFlags; /* Option flags */
|
||||
drcWhyList *DRCWhyList;
|
||||
char **DRCWhyList; /* Indexed list of "why" text strings */
|
||||
int DRCWhySize; /* Length of DRCWhyList */
|
||||
PaintResultType DRCPaintTable[NP][NT][NT];
|
||||
} DRCStyle;
|
||||
|
||||
|
|
@ -239,6 +229,9 @@ extern void drcPrintError();
|
|||
extern int drcIncludeArea();
|
||||
extern int drcExactOverlapTile();
|
||||
extern void drcInitRulesTbl();
|
||||
extern void drcAssign();
|
||||
extern void drcCifAssign();
|
||||
extern int drcWhyCreate();
|
||||
|
||||
/*
|
||||
* Exported procedures
|
||||
|
|
|
|||
|
|
@ -26,12 +26,12 @@ exttosim${SHDLIB_EXT}: simwrap.o ${MAGICDIR}/extflat/libextflat.o
|
|||
${CC} ${CFLAGS} ${CPPFLAGS} -o $@ ${LDDL_FLAGS} simwrap.o \
|
||||
${MAGICDIR}/extflat/libextflat.o ${LD_SHARED} -lc ${LIBS}
|
||||
|
||||
install: $(DESTDIR)${BINDIR}/${MODULE}${EXEEXT}
|
||||
install: $(DESTDIR)${INSTALL_BINDIR}/${MODULE}${EXEEXT}
|
||||
|
||||
install-tcl: $(DESTDIR)${TCLDIR}/exttosim${SHDLIB_EXT}
|
||||
install-tcl: $(DESTDIR)${INSTALL_TCLDIR}/exttosim${SHDLIB_EXT}
|
||||
|
||||
$(DESTDIR)${TCLDIR}/exttosim${SHDLIB_EXT}: exttosim${SHDLIB_EXT}
|
||||
${RM} $(DESTDIR)${TCLDIR}/exttosim${SHDLIB_EXT}
|
||||
${CP} exttosim${SHDLIB_EXT} $(DESTDIR)${TCLDIR}/exttosim${SHDLIB_EXT}
|
||||
$(DESTDIR)${INSTALL_TCLDIR}/exttosim${SHDLIB_EXT}: exttosim${SHDLIB_EXT}
|
||||
${RM} $(DESTDIR)${INSTALL_TCLDIR}/exttosim${SHDLIB_EXT}
|
||||
${CP} exttosim${SHDLIB_EXT} $(DESTDIR)${INSTALL_TCLDIR}/exttosim${SHDLIB_EXT}
|
||||
|
||||
include ${MAGICDIR}/rules.mak
|
||||
|
|
|
|||
|
|
@ -1078,7 +1078,7 @@ simdevVisit(dev, hierName, scale, trans)
|
|||
{
|
||||
putc(' ', esSimF);
|
||||
simdevSubstrate(hierName, subnode->efnode_name->efnn_hier,
|
||||
dev->dev_type, 0, FALSE, esSimF);
|
||||
dev->dev_type, 0.0, FALSE, esSimF);
|
||||
}
|
||||
|
||||
GeoTransRect(trans, &dev->dev_rect, &r);
|
||||
|
|
@ -1196,7 +1196,8 @@ int
|
|||
simdevSubstrate( prefix, suffix, type, scale, doAP, outf)
|
||||
HierName *prefix;
|
||||
HierName *suffix;
|
||||
int type, scale;
|
||||
int type;
|
||||
float scale;
|
||||
bool doAP;
|
||||
FILE *outf;
|
||||
{
|
||||
|
|
@ -1264,7 +1265,8 @@ FILE *outf;
|
|||
|
||||
bool simnAP(node, resClass, scale, outf)
|
||||
EFNode *node;
|
||||
int resClass, scale;
|
||||
int resClass;
|
||||
float scale;
|
||||
FILE *outf;
|
||||
{
|
||||
int a, p;
|
||||
|
|
@ -1277,8 +1279,8 @@ FILE *outf;
|
|||
return FALSE;
|
||||
}
|
||||
markVisited((nodeClient *)node->efnode_client, resClass);
|
||||
a = node->efnode_pa[resClass].pa_area*scale*scale;
|
||||
p = node->efnode_pa[resClass].pa_perim*scale;
|
||||
a = (int)(node->efnode_pa[resClass].pa_area*scale*scale);
|
||||
p = (int)(node->efnode_pa[resClass].pa_perim*scale);
|
||||
if ( a < 0 ) a = 0;
|
||||
if ( p < 0 ) p = 0;
|
||||
fprintf(outf,"A_%d,P_%d", a, p);
|
||||
|
|
@ -1288,7 +1290,8 @@ FILE *outf;
|
|||
bool simnAPHier(dterm, hierName, resClass, scale, outf)
|
||||
DevTerm *dterm;
|
||||
HierName *hierName;
|
||||
int resClass, scale;
|
||||
int resClass;
|
||||
float scale;
|
||||
FILE *outf;
|
||||
{
|
||||
EFNode *node = dterm->dterm_node;
|
||||
|
|
@ -1308,8 +1311,8 @@ bool simnAPHier(dterm, hierName, resClass, scale, outf)
|
|||
return FALSE;
|
||||
}
|
||||
markVisited((nodeClientHier *)node->efnode_client, resClass);
|
||||
a = node->efnode_pa[resClass].pa_area*scale*scale;
|
||||
p = node->efnode_pa[resClass].pa_perim*scale;
|
||||
a = (int)(node->efnode_pa[resClass].pa_area*scale*scale);
|
||||
p = (int)(node->efnode_pa[resClass].pa_perim*scale);
|
||||
if ( a < 0 ) a = 0;
|
||||
if ( p < 0 ) p = 0;
|
||||
fprintf(outf,"A_%d,P_%d", a, p);
|
||||
|
|
|
|||
|
|
@ -29,16 +29,16 @@ exttospice${SHDLIB_EXT}: spicewrap.o spicehier.o ${MAGICDIR}/extflat/libextflat.
|
|||
${CC} ${CFLAGS} ${CPPFLAGS} -o $@ ${LDDL_FLAGS} spicewrap.o spicehier.o \
|
||||
${MAGICDIR}/extflat/libextflat.o ${LD_SHARED} -lc ${LIBS}
|
||||
|
||||
install: $(DESTDIR)${BINDIR}/${MODULE}${EXEEXT} $(DESTDIR)${BINDIR}/spice2sim
|
||||
install: $(DESTDIR)${INSTALL_BINDIR}/${MODULE}${EXEEXT} $(DESTDIR)${INSTALL_BINDIR}/spice2sim
|
||||
|
||||
install-tcl: $(DESTDIR)${TCLDIR}/exttospice${SHDLIB_EXT} $(DESTDIR)${BINDIR}/spice2sim
|
||||
install-tcl: $(DESTDIR)${INSTALL_TCLDIR}/exttospice${SHDLIB_EXT} $(DESTDIR)${INSTALL_BINDIR}/spice2sim
|
||||
|
||||
$(DESTDIR)${TCLDIR}/exttospice${SHDLIB_EXT}: exttospice${SHDLIB_EXT}
|
||||
${RM} $(DESTDIR)${TCLDIR}/exttospice${SHDLIB_EXT}
|
||||
${CP} exttospice${SHDLIB_EXT} $(DESTDIR)${TCLDIR}/exttospice${SHDLIB_EXT}
|
||||
$(DESTDIR)${INSTALL_TCLDIR}/exttospice${SHDLIB_EXT}: exttospice${SHDLIB_EXT}
|
||||
${RM} $(DESTDIR)${INSTALL_TCLDIR}/exttospice${SHDLIB_EXT}
|
||||
${CP} exttospice${SHDLIB_EXT} $(DESTDIR)${INSTALL_TCLDIR}/exttospice${SHDLIB_EXT}
|
||||
|
||||
$(DESTDIR)${BINDIR}/spice2sim: spice2sim
|
||||
${RM} $(DESTDIR)${BINDIR}/spice2sim
|
||||
${CP} spice2sim $(DESTDIR)${BINDIR}/spice2sim
|
||||
$(DESTDIR)${INSTALL_BINDIR}/spice2sim: spice2sim
|
||||
${RM} $(DESTDIR)${INSTALL_BINDIR}/spice2sim
|
||||
${CP} spice2sim $(DESTDIR)${INSTALL_BINDIR}/spice2sim
|
||||
|
||||
include ${MAGICDIR}/rules.mak
|
||||
|
|
|
|||
|
|
@ -1159,13 +1159,11 @@ spcresistHierVisit(hc, hierName1, hierName2, res)
|
|||
HierContext *hc;
|
||||
HierName *hierName1;
|
||||
HierName *hierName2;
|
||||
int res;
|
||||
float res;
|
||||
{
|
||||
res = (res + 500) / 1000;
|
||||
|
||||
fprintf(esSpiceF, "R%d %s %s %d\n", esResNum++,
|
||||
fprintf(esSpiceF, "R%d %s %s %g\n", esResNum++,
|
||||
nodeSpiceHierName(hc, hierName1),
|
||||
nodeSpiceHierName(hc, hierName2), res);
|
||||
nodeSpiceHierName(hc, hierName2), res / 1000.);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1572,27 +1570,39 @@ esMakePorts(hc, cdata)
|
|||
|
||||
while (tptr != NULL)
|
||||
{
|
||||
/* Ignore array information for the purpose of tracing */
|
||||
/* the cell definition hierarchy. */
|
||||
int idum[6];
|
||||
bool is_array;
|
||||
|
||||
aptr = strchr(portname, '[');
|
||||
if ((aptr == NULL) || (aptr > tptr))
|
||||
*tptr = '\0';
|
||||
else
|
||||
*aptr = '\0';
|
||||
/* Ignore array information for the purpose of tracing */
|
||||
/* the cell definition hierarchy. If a cell use name */
|
||||
/* contains a bracket, check first if the complete name */
|
||||
/* matches a use. If not, then check if the part */
|
||||
/* the last opening bracket matches a known use. */
|
||||
|
||||
aptr = strrchr(portname, '[');
|
||||
*tptr = '\0';
|
||||
is_array = FALSE;
|
||||
if (aptr != NULL)
|
||||
{
|
||||
he = HashLookOnly(&updef->def_uses, portname);
|
||||
if (he == NULL)
|
||||
{
|
||||
*aptr = '\0';
|
||||
is_array = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the cell for the instance
|
||||
portdef = NULL;
|
||||
he = HashFind(&updef->def_uses, portname);
|
||||
he = HashLookOnly(&updef->def_uses, portname);
|
||||
if (he != NULL)
|
||||
{
|
||||
use = (Use *)HashGetValue(he);
|
||||
portdef = use->use_def;
|
||||
}
|
||||
if ((aptr == NULL) || (aptr > tptr))
|
||||
*tptr = '/';
|
||||
else
|
||||
if (is_array)
|
||||
*aptr = '[';
|
||||
*tptr = '/';
|
||||
portname = tptr + 1;
|
||||
|
||||
// Find the net of portname in the subcell and
|
||||
|
|
@ -1613,6 +1623,10 @@ esMakePorts(hc, cdata)
|
|||
{
|
||||
nn->efnn_node->efnode_flags |= EF_PORT;
|
||||
nn->efnn_port = -1; // Will be sorted later
|
||||
|
||||
// Diagnostic
|
||||
// TxPrintf("Port connection in %s from net %s to net %s (%s)\n",
|
||||
// def->def_name, locname, name, portname);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1622,9 +1636,6 @@ esMakePorts(hc, cdata)
|
|||
|
||||
updef = portdef;
|
||||
}
|
||||
// Diagnostic
|
||||
// TxPrintf("Connection in %s to net %s (%s)\n", def->def_name,
|
||||
// name, portname);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1644,34 +1655,46 @@ esMakePorts(hc, cdata)
|
|||
// In particular, this keeps parasitics out of the netlist for
|
||||
// LVS purposes if "cthresh" is set to "infinite".
|
||||
|
||||
if (fabs((double)conn->conn_cap) < EFCapThreshold) continue;
|
||||
if (fabs((double)conn->conn_cap / 1000) < EFCapThreshold) continue;
|
||||
|
||||
portname = name;
|
||||
updef = def;
|
||||
|
||||
while (tptr != NULL)
|
||||
{
|
||||
int idum[6];
|
||||
bool is_array;
|
||||
|
||||
/* Ignore array information for the purpose of tracing */
|
||||
/* the cell definition hierarchy. */
|
||||
|
||||
aptr = strchr(portname, '[');
|
||||
if ((aptr == NULL) || (aptr > tptr))
|
||||
*tptr = '\0';
|
||||
else
|
||||
if (aptr && (aptr < tptr) &&
|
||||
(sscanf(aptr, "[%d:%d:%d][%d:%d:%d]",
|
||||
&idum[0], &idum[1], &idum[2],
|
||||
&idum[3], &idum[4], &idum[5]) == 6))
|
||||
{
|
||||
*aptr = '\0';
|
||||
is_array = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*tptr = '\0';
|
||||
is_array = FALSE;
|
||||
}
|
||||
|
||||
// Find the cell for the instance
|
||||
portdef = NULL;
|
||||
he = HashFind(&updef->def_uses, portname);
|
||||
he = HashLookOnly(&updef->def_uses, portname);
|
||||
if (he != NULL)
|
||||
{
|
||||
use = (Use *)HashGetValue(he);
|
||||
portdef = use->use_def;
|
||||
}
|
||||
if ((aptr == NULL) || (aptr > tptr))
|
||||
*tptr = '/';
|
||||
else
|
||||
if (is_array)
|
||||
*aptr = '[';
|
||||
else
|
||||
*tptr = '/';
|
||||
portname = tptr + 1;
|
||||
|
||||
// Find the net of portname in the subcell and
|
||||
|
|
@ -1747,7 +1770,8 @@ esHierVisit(hc, cdata)
|
|||
|
||||
if (def != topdef)
|
||||
{
|
||||
if ((def->def_devs == NULL) && (HashGetNumEntries(&def->def_uses) == 0))
|
||||
if ((HashGetNumEntries(&def->def_devs) == 0) &&
|
||||
(HashGetNumEntries(&def->def_uses) == 0))
|
||||
{
|
||||
if (locDoSubckt == AUTO)
|
||||
{
|
||||
|
|
@ -1859,6 +1883,9 @@ esHierVisit(hc, cdata)
|
|||
EFHierVisitNodes(hcf, spcnodeHierVisit, (ClientData) NULL);
|
||||
freeMagic(resstr);
|
||||
}
|
||||
|
||||
/* Reset device merge index for next cell */
|
||||
if (esMergeDevsA || esMergeDevsC) esFMIndex = 0;
|
||||
}
|
||||
|
||||
if ((def != topdef) || (def->def_flags & DEF_SUBCIRCUIT) || (locDoSubckt == TRUE))
|
||||
|
|
|
|||
|
|
@ -140,9 +140,16 @@ esFormatSubs(outf, suf)
|
|||
if ((EFTrimFlags & EF_TRIMGLOB ) && suf[l] == '!' ||
|
||||
(EFTrimFlags & EF_TRIMLOCAL) && suf[l] == '#')
|
||||
suf[l] = '\0' ;
|
||||
if (EFTrimFlags & EF_CONVERTCOMMAS)
|
||||
if (EFTrimFlags & EF_CONVERTCOMMA)
|
||||
while ((specchar = strchr(suf, ',')) != NULL)
|
||||
*specchar = ';';
|
||||
*specchar = '|';
|
||||
if (EFTrimFlags & EF_CONVERTBRACKETS)
|
||||
{
|
||||
while ((specchar = strchr(suf, '[')) != NULL)
|
||||
*specchar = '_';
|
||||
while ((specchar = strchr(suf, ']')) != NULL)
|
||||
*specchar = '_';
|
||||
}
|
||||
if (EFTrimFlags & EF_CONVERTEQUAL)
|
||||
while ((specchar = strchr(suf, '=')) != NULL)
|
||||
*specchar = ':';
|
||||
|
|
@ -257,7 +264,8 @@ CmdExtToSpice(w, cmd)
|
|||
"extresist [on|off] incorporate information from extresist",
|
||||
"resistor tee [on|off] model resistor capacitance as a T-network",
|
||||
"scale [on|off] use .option card for scaling",
|
||||
"subcircuits [on|off] standard cells become subcircuit calls",
|
||||
"subcircuits [top|descend] [on|off|auto]\n"
|
||||
" standard cells become subcircuit calls",
|
||||
"hierarchy [on|off] output hierarchical spice for LVS",
|
||||
"blackbox [on|off] output abstract views as black-box entries",
|
||||
"renumber [on|off] on = number instances X1, X2, etc.\n"
|
||||
|
|
@ -607,7 +615,7 @@ CmdExtToSpice(w, cmd)
|
|||
case EXTTOSPC_DEFAULT:
|
||||
LocCapThreshold = 2;
|
||||
LocResistThreshold = INFINITE_THRESHOLD;
|
||||
EFTrimFlags = EF_CONVERTCOMMAS | EF_CONVERTEQUAL;
|
||||
EFTrimFlags = EF_CONVERTCOMMA | EF_CONVERTEQUAL;
|
||||
EFScale = 0.0;
|
||||
if (EFArgTech)
|
||||
{
|
||||
|
|
@ -821,7 +829,7 @@ runexttospice:
|
|||
|
||||
// This forces options TRIMGLOB and CONVERTEQUAL, not sure that's such a
|
||||
// good idea. . .
|
||||
EFTrimFlags |= EF_TRIMGLOB | EF_CONVERTEQUAL;
|
||||
EFTrimFlags |= EF_TRIMGLOB | EF_CONVERTEQUAL | EF_CONVERTCOMMA;
|
||||
if (IS_FINITE_F(EFCapThreshold)) flatFlags |= EF_FLATCAPS;
|
||||
if (esFormat == HSPICE)
|
||||
EFTrimFlags |= EF_TRIMLOCAL;
|
||||
|
|
@ -1140,6 +1148,17 @@ spcmainArgs(pargc, pargv)
|
|||
char **argv = *pargv, *cp;
|
||||
int argc = *pargc;
|
||||
|
||||
char usage_text[] = "Usage: ext2spice "
|
||||
"[-B] [-o spicefile] [-M|-m] [-y cap_digits] "
|
||||
"[-J flat|hier]\n"
|
||||
"[-f spice2|spice3|hspice|ngspice] [-M] [-m] "
|
||||
#ifdef MAGIC_WRAPPER
|
||||
"[file]\n";
|
||||
#else
|
||||
"[-j device:sdRclass[/subRclass]/defaultSubstrate]\n"
|
||||
"file\n\n or else see options to extcheck(1)\n";
|
||||
#endif
|
||||
|
||||
switch (argv[0][1])
|
||||
{
|
||||
case 'd':
|
||||
|
|
@ -1236,6 +1255,9 @@ spcmainArgs(pargc, pargv)
|
|||
break;
|
||||
}
|
||||
#endif /* MAGIC_WRAPPER */
|
||||
case 'h': /* -h or -help, as suggested by "ext2spice help" */
|
||||
TxPrintf(usage_text);
|
||||
break;
|
||||
default:
|
||||
TxError("Unrecognized flag: %s\n", argv[0]);
|
||||
goto usage;
|
||||
|
|
@ -1246,16 +1268,7 @@ spcmainArgs(pargc, pargv)
|
|||
return 0;
|
||||
|
||||
usage:
|
||||
TxError("Usage: ext2spice [-B] [-o spicefile] [-M|-m] [-y cap_digits] "
|
||||
"[-J flat|hier]\n"
|
||||
"[-f spice2|spice3|hspice] [-M] [-m] "
|
||||
#ifdef MAGIC_WRAPPER
|
||||
"[file]\n"
|
||||
#else
|
||||
"[-j device:sdRclass[/subRclass]/defaultSubstrate]\n"
|
||||
"file\n\n or else see options to extcheck(1)\n"
|
||||
#endif
|
||||
);
|
||||
TxError(usage_text);
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
return 1;
|
||||
|
|
@ -1359,10 +1372,11 @@ subcktVisit(use, hierName, is_top)
|
|||
EFNode *snode;
|
||||
Def *def = use->use_def;
|
||||
EFNodeName *nodeName;
|
||||
int portorder, portmax, imp_max, tchars;
|
||||
int portorder, portmax, portidx, imp_max, tchars;
|
||||
char stmp[MAX_STR_SIZE];
|
||||
char *instname, *subcktname;
|
||||
DevParam *plist, *pptr;
|
||||
EFNodeName **nodeList;
|
||||
|
||||
if (is_top == TRUE) return 0; /* Ignore the top-level cell */
|
||||
|
||||
|
|
@ -1379,7 +1393,7 @@ subcktVisit(use, hierName, is_top)
|
|||
else
|
||||
{
|
||||
int savflags = EFTrimFlags;
|
||||
EFTrimFlags = 0; // Do no substitutions on subcircuit names
|
||||
EFTrimFlags = EF_CONVERTCOMMA; // Only substitute commas on subcircuit names
|
||||
|
||||
/* Use full hierarchical decomposition for name */
|
||||
/* (not just use->use_id. hierName already has use->use_id at end) */
|
||||
|
|
@ -1454,35 +1468,58 @@ subcktVisit(use, hierName, is_top)
|
|||
/* Port numbers need not start at zero or be contiguous. */
|
||||
/* They will be printed in numerical order. */
|
||||
|
||||
portorder = 0;
|
||||
while (portorder <= portmax)
|
||||
{
|
||||
for (snode = (EFNode *) def->def_firstn.efnode_next;
|
||||
nodeList = (EFNodeName **)mallocMagic((portmax + 1) * sizeof(EFNodeName *));
|
||||
for (portidx = 0; portidx <= portmax; portidx++)
|
||||
nodeList[portidx] = (EFNodeName *)NULL;
|
||||
|
||||
for (snode = (EFNode *) def->def_firstn.efnode_next;
|
||||
snode != &def->def_firstn;
|
||||
snode = (EFNode *) snode->efnode_next)
|
||||
{
|
||||
if (!(snode->efnode_flags & EF_PORT)) continue;
|
||||
for (nodeName = snode->efnode_name; nodeName != NULL;
|
||||
{
|
||||
if (!(snode->efnode_flags & EF_PORT)) continue;
|
||||
for (nodeName = snode->efnode_name; nodeName != NULL;
|
||||
nodeName = nodeName->efnn_next)
|
||||
{
|
||||
EFNodeName *nn;
|
||||
HashEntry *he;
|
||||
char *pname;
|
||||
|
||||
portidx = nodeName->efnn_port;
|
||||
if (portidx < 0) continue;
|
||||
if (nodeList[portidx] == NULL)
|
||||
{
|
||||
int portidx = nodeName->efnn_port;
|
||||
if (portidx == portorder)
|
||||
{
|
||||
if (tchars > 80)
|
||||
{
|
||||
fprintf(esSpiceF, "\n+");
|
||||
tchars = 1;
|
||||
}
|
||||
tchars += spcdevOutNode(hierName, nodeName->efnn_hier,
|
||||
"subcircuit", esSpiceF);
|
||||
break;
|
||||
}
|
||||
nodeList[portidx] = nodeName;
|
||||
}
|
||||
else if (EFHNBest(nodeName->efnn_hier, nodeList[portidx]->efnn_hier))
|
||||
{
|
||||
nodeList[portidx] = nodeName;
|
||||
}
|
||||
if (nodeName != NULL) break;
|
||||
}
|
||||
portorder++;
|
||||
}
|
||||
|
||||
for (portidx = 0; portidx <= portmax; portidx++)
|
||||
{
|
||||
nodeName = nodeList[portidx];
|
||||
|
||||
if (nodeName != NULL)
|
||||
{
|
||||
if (tchars > 80)
|
||||
{
|
||||
fprintf(esSpiceF, "\n+");
|
||||
tchars = 1;
|
||||
}
|
||||
tchars += spcdevOutNode(hierName, nodeName->efnn_hier,
|
||||
"subcircuit", esSpiceF);
|
||||
}
|
||||
else
|
||||
{
|
||||
// As port indexes do not have to be contiguous, this does not
|
||||
// necessarily indicate an error condition. No need to report?
|
||||
// TxError("No port connection on port %d; need to resolve.\n", portidx);
|
||||
}
|
||||
}
|
||||
freeMagic(nodeList);
|
||||
|
||||
/* Look for all implicit substrate connections that are */
|
||||
/* declared as local node names, and put them last. */
|
||||
|
||||
|
|
@ -1602,7 +1639,7 @@ topVisit(def, doStub)
|
|||
Def *def;
|
||||
bool doStub;
|
||||
{
|
||||
EFNode *snode;
|
||||
EFNode *snode, *basenode;
|
||||
EFNodeName *sname, *nodeName;
|
||||
HashSearch hs;
|
||||
HashEntry *he;
|
||||
|
|
@ -1655,7 +1692,9 @@ topVisit(def, doStub)
|
|||
snode = sname->efnn_node;
|
||||
|
||||
if (snode->efnode_flags & EF_PORT)
|
||||
if (snode->efnode_name->efnn_port < 0)
|
||||
{
|
||||
pname = nodeSpiceName(snode->efnode_name->efnn_hier, &basenode);
|
||||
if (basenode->efnode_name->efnn_port < 0)
|
||||
{
|
||||
if (tchars > 80)
|
||||
{
|
||||
|
|
@ -1663,11 +1702,12 @@ topVisit(def, doStub)
|
|||
fprintf(esSpiceF, "\n+");
|
||||
tchars = 1;
|
||||
}
|
||||
pname = nodeSpiceName(snode->efnode_name->efnn_hier);
|
||||
fprintf(esSpiceF, " %s", pname);
|
||||
tchars += strlen(pname) + 1;
|
||||
snode->efnode_name->efnn_port = portorder++;
|
||||
basenode->efnode_name->efnn_port = portorder++;
|
||||
}
|
||||
snode->efnode_name->efnn_port = basenode->efnode_name->efnn_port;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1681,6 +1721,7 @@ topVisit(def, doStub)
|
|||
HashStartSearch(&hs);
|
||||
while (he = HashNext(&def->def_nodes, &hs))
|
||||
{
|
||||
char stmp[MAX_STR_SIZE];
|
||||
int portidx;
|
||||
EFNodeName *unnumbered;
|
||||
|
||||
|
|
@ -1701,7 +1742,17 @@ topVisit(def, doStub)
|
|||
fprintf(esSpiceF, "\n+");
|
||||
tchars = 1;
|
||||
}
|
||||
pname = nodeSpiceName(snode->efnode_name->efnn_hier);
|
||||
// If view is abstract, rely on the given port name, not
|
||||
// the node. Otherwise, artifacts of the abstract view
|
||||
// may cause nodes to be merged and the names lost.
|
||||
|
||||
if (def->def_flags & DEF_ABSTRACT)
|
||||
{
|
||||
EFHNSprintf(stmp, nodeName->efnn_hier);
|
||||
pname = stmp;
|
||||
}
|
||||
else
|
||||
pname = nodeSpiceName(snode->efnode_name->efnn_hier, NULL);
|
||||
fprintf(esSpiceF, " %s", pname);
|
||||
tchars += strlen(pname) + 1;
|
||||
break;
|
||||
|
|
@ -2083,6 +2134,56 @@ esOutputResistor(dev, hierName, scale, term1, term2, has_model, l, w, dscale)
|
|||
}
|
||||
}
|
||||
|
||||
/* Report if device at index n has been deleted due to merging */
|
||||
|
||||
bool
|
||||
devIsKilled(n)
|
||||
int n;
|
||||
{
|
||||
return (esFMult[(n)] <= (float)0.0) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/* Add a dev's multiplier to the table and grow it if necessary */
|
||||
|
||||
void
|
||||
addDevMult(f)
|
||||
float f;
|
||||
{
|
||||
int i;
|
||||
float *op;
|
||||
|
||||
if (esFMult == NULL) {
|
||||
esFMult = (float *) mallocMagic((unsigned) (esFMSize*sizeof(float)));
|
||||
}
|
||||
else if (esFMIndex >= esFMSize)
|
||||
{
|
||||
op = esFMult;
|
||||
esFMSize *= 2;
|
||||
esFMult = (float *)mallocMagic((unsigned)(esFMSize * sizeof(float)));
|
||||
for (i = 0; i < esFMSize / 2; i++) esFMult[i] = op[i];
|
||||
if (op) freeMagic(op);
|
||||
}
|
||||
esFMult[esFMIndex++] = f;
|
||||
}
|
||||
|
||||
/* Set the multiplier value f of device at index i */
|
||||
|
||||
void
|
||||
setDevMult(i, f)
|
||||
int i;
|
||||
float f;
|
||||
{
|
||||
esFMult[i] = f;
|
||||
}
|
||||
|
||||
/* Get the multiplier value of the device at the current index esFMIndex */
|
||||
|
||||
float
|
||||
getCurDevMult()
|
||||
{
|
||||
return (esFMult && (esFMIndex > 0)) ? esFMult[esFMIndex-1] : (float)1.0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -2708,13 +2809,16 @@ FILE *outf;
|
|||
/* Canonical name */
|
||||
nn = (EFNodeName *) HashGetValue(he);
|
||||
if (outf)
|
||||
fprintf(outf, "%s", nodeSpiceName(nn->efnn_node->efnode_name->efnn_hier));
|
||||
fprintf(outf, "%s", nodeSpiceName(nn->efnn_node->efnode_name->efnn_hier,
|
||||
NULL));
|
||||
|
||||
/* Mark node as visited */
|
||||
if ((nodeClient *)nn->efnn_node->efnode_client == (ClientData)NULL)
|
||||
initNodeClientHier(nn->efnn_node);
|
||||
|
||||
((nodeClient *)nn->efnn_node->efnode_client)->m_w.visitMask |= DEV_CONNECT_MASK;
|
||||
if (!esDistrJunct)
|
||||
((nodeClient *)nn->efnn_node->efnode_client)->m_w.visitMask |=
|
||||
DEV_CONNECT_MASK;
|
||||
return nn->efnn_node;
|
||||
}
|
||||
}
|
||||
|
|
@ -2769,7 +2873,14 @@ int spcnAP(node, resClass, scale, asterm, psterm, m, outf, w)
|
|||
|
||||
if (!esDistrJunct || w == -1) goto oldFmt;
|
||||
|
||||
dsc = w / ((nodeClient*)node->efnode_client)->m_w.widths[resClass];
|
||||
if (((nodeClient*)node->efnode_client)->m_w.widths != NULL)
|
||||
dsc = w / ((nodeClient*)node->efnode_client)->m_w.widths[resClass];
|
||||
else
|
||||
{
|
||||
TxError("Device missing records for source/drain area/perim.\n");
|
||||
dsc = w;
|
||||
}
|
||||
|
||||
if (esScale < 0)
|
||||
{
|
||||
if (asterm)
|
||||
|
|
@ -2917,10 +3028,13 @@ spcdevOutNode(prefix, suffix, name, outf)
|
|||
return 0;
|
||||
}
|
||||
nn = (EFNodeName *) HashGetValue(he);
|
||||
nname = nodeSpiceName(nn->efnn_node->efnode_name->efnn_hier);
|
||||
nname = nodeSpiceName(nn->efnn_node->efnode_name->efnn_hier, NULL);
|
||||
fprintf(outf, " %s", nname);
|
||||
|
||||
/* Mark node as visited */
|
||||
((nodeClient *)nn->efnn_node->efnode_client)->m_w.visitMask |= DEV_CONNECT_MASK;
|
||||
if (!esDistrJunct)
|
||||
((nodeClient *)nn->efnn_node->efnode_client)->m_w.visitMask |= DEV_CONNECT_MASK;
|
||||
|
||||
return (1 + strlen(nname));
|
||||
}
|
||||
|
||||
|
|
@ -2960,8 +3074,8 @@ spccapVisit(hierName1, hierName2, cap)
|
|||
if (cap <= EFCapThreshold)
|
||||
return 0;
|
||||
|
||||
fprintf(esSpiceF, esSpiceCapFormat ,esCapNum++,nodeSpiceName(hierName1),
|
||||
nodeSpiceName(hierName2), cap);
|
||||
fprintf(esSpiceF, esSpiceCapFormat ,esCapNum++,nodeSpiceName(hierName1, NULL),
|
||||
nodeSpiceName(hierName2, NULL), cap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2996,8 +3110,8 @@ spcresistVisit(hierName1, hierName2, res)
|
|||
HierName *hierName2;
|
||||
float res;
|
||||
{
|
||||
fprintf(esSpiceF, "R%d %s %s %g\n", esResNum++, nodeSpiceName(hierName1),
|
||||
nodeSpiceName(hierName2), res / 1000.);
|
||||
fprintf(esSpiceF, "R%d %s %s %g\n", esResNum++, nodeSpiceName(hierName1, NULL),
|
||||
nodeSpiceName(hierName2, NULL), res / 1000.);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3032,7 +3146,7 @@ spcsubVisit(node, res, cap, resstr)
|
|||
if (node->efnode_flags & EF_SUBS_NODE)
|
||||
{
|
||||
hierName = (HierName *) node->efnode_name->efnn_hier;
|
||||
nsn = nodeSpiceName(hierName);
|
||||
nsn = nodeSpiceName(hierName, NULL);
|
||||
*resstr = StrDup((char **)NULL, nsn);
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -3082,7 +3196,7 @@ spcnodeVisit(node, res, cap)
|
|||
if (!isConnected && node->efnode_flags & EF_PORT) isConnected = TRUE;
|
||||
|
||||
hierName = (HierName *) node->efnode_name->efnn_hier;
|
||||
nsn = nodeSpiceName(hierName);
|
||||
nsn = nodeSpiceName(hierName, NULL);
|
||||
|
||||
if (esFormat == SPICE2 || esFormat == HSPICE && strncmp(nsn, "z@", 2)==0 ) {
|
||||
static char ntmp[MAX_STR_SIZE];
|
||||
|
|
@ -3127,7 +3241,7 @@ nodeVisitDebug(node, res, cap)
|
|||
EFAttr *ap;
|
||||
|
||||
hierName = (HierName *) node->efnode_name->efnn_hier;
|
||||
nsn = nodeSpiceName(hierName);
|
||||
nsn = nodeSpiceName(hierName, NULL);
|
||||
TxError("** %s (%x)\n", nsn, node);
|
||||
|
||||
printf("\t client.name=%s, client.m_w=%p\n",
|
||||
|
|
@ -3150,23 +3264,27 @@ nodeVisitDebug(node, res, cap)
|
|||
*
|
||||
* Side effects:
|
||||
* Allocates nodeClients for the node.
|
||||
* Returns the node in the "rnode" pointer, if non-NULL.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
static char esTempName[MAX_STR_SIZE];
|
||||
|
||||
char *nodeSpiceName(hname)
|
||||
char *nodeSpiceName(hname, rnode)
|
||||
HierName *hname;
|
||||
EFNode **rnode;
|
||||
{
|
||||
EFNodeName *nn;
|
||||
HashEntry *he;
|
||||
EFNode *node;
|
||||
|
||||
if (rnode) *rnode = (EFNode *)NULL;
|
||||
he = EFHNLook(hname, (char *) NULL, "nodeName");
|
||||
if ( he == NULL )
|
||||
return "errGnd!";
|
||||
nn = (EFNodeName *) HashGetValue(he);
|
||||
node = nn->efnn_node;
|
||||
if (rnode) *rnode = node;
|
||||
|
||||
if ( (nodeClient *) (node->efnode_client) == NULL ) {
|
||||
initNodeClient(node);
|
||||
|
|
@ -3215,7 +3333,7 @@ EFHNSprintf(str, hierName)
|
|||
char *str;
|
||||
HierName *hierName;
|
||||
{
|
||||
bool trimGlob, trimLocal, convertComma, convertEqual;
|
||||
bool trimGlob, trimLocal, convertComma, convertEqual, convertBrackets;
|
||||
char *s, *cp, c;
|
||||
char *efHNSprintfPrefix(HierName *, char *);
|
||||
|
||||
|
|
@ -3226,8 +3344,9 @@ EFHNSprintf(str, hierName)
|
|||
cp = hierName->hn_name;
|
||||
trimGlob = (EFTrimFlags & EF_TRIMGLOB);
|
||||
trimLocal = (EFTrimFlags & EF_TRIMLOCAL);
|
||||
convertComma = (EFTrimFlags & EF_CONVERTCOMMAS);
|
||||
convertComma = (EFTrimFlags & EF_CONVERTCOMMA);
|
||||
convertEqual = (EFTrimFlags & EF_CONVERTEQUAL);
|
||||
convertBrackets = (EFTrimFlags & EF_CONVERTBRACKETS);
|
||||
while (c = *cp++)
|
||||
{
|
||||
switch (c)
|
||||
|
|
@ -3235,7 +3354,9 @@ EFHNSprintf(str, hierName)
|
|||
case '!': if (!trimGlob) *str++ = c; break;
|
||||
case '.': *str++ = (esFormat == HSPICE)?'@':'.'; break;
|
||||
case '=': if (convertEqual) *str++ = ':'; break;
|
||||
case ',': if (convertComma) *str++ = ';'; break;
|
||||
case ',': if (convertComma) *str++ = '|'; break;
|
||||
case '[': *str++ = (convertBrackets) ? '_' : '['; break;
|
||||
case ']': *str++ = (convertBrackets) ? '_' : ']'; break;
|
||||
case '#': if (trimLocal) break; // else fall through
|
||||
default: *str++ = c; break;
|
||||
}
|
||||
|
|
@ -3252,6 +3373,8 @@ char *efHNSprintfPrefix(hierName, str)
|
|||
{
|
||||
char *cp, c;
|
||||
bool convertEqual = (EFTrimFlags & EF_CONVERTEQUAL) ? TRUE : FALSE;
|
||||
bool convertComma = (EFTrimFlags & EF_CONVERTCOMMA) ? TRUE : FALSE;
|
||||
bool convertBrackets = (EFTrimFlags & EF_CONVERTBRACKETS) ? TRUE : FALSE;
|
||||
|
||||
if (hierName->hn_parent)
|
||||
str = efHNSprintfPrefix(hierName->hn_parent, str);
|
||||
|
|
@ -3260,6 +3383,13 @@ char *efHNSprintfPrefix(hierName, str)
|
|||
while (1) {
|
||||
if (convertEqual && (*cp == '='))
|
||||
*str = ':';
|
||||
else if (convertBrackets && ((*cp == '[') || (*cp == ']')))
|
||||
*str = '_';
|
||||
else if (*cp == ',')
|
||||
{
|
||||
if (convertComma) *str = '|';
|
||||
else str--;
|
||||
}
|
||||
else
|
||||
*str = *cp;
|
||||
if (!(*str)) break;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,11 @@ extern char *nodeSpiceHierName();
|
|||
extern devMerge *mkDevMerge();
|
||||
extern bool extHierSDAttr();
|
||||
|
||||
extern bool devIsKilled();
|
||||
extern float getCurDevMult();
|
||||
extern void addDevMult();
|
||||
extern void setDevMult();
|
||||
|
||||
/* Options specific to ext2spice */
|
||||
extern bool esDoExtResis;
|
||||
extern bool esDoPorts;
|
||||
|
|
@ -166,7 +171,7 @@ typedef struct {
|
|||
|
||||
/*
|
||||
*---------------------------------------------------------
|
||||
* Variables & macros used for merging parallel devs
|
||||
* Variables used for merging parallel devs
|
||||
* The merging of devs is based on the fact that spcdevVisit
|
||||
* visits the devs in the same order all the time so the
|
||||
* value of esFMult[i] keeps the multiplier for the ith dev
|
||||
|
|
@ -174,31 +179,8 @@ typedef struct {
|
|||
*/
|
||||
#define DEV_KILLED ((float) -1.0)
|
||||
#define FMULT_SIZE (1<<10)
|
||||
|
||||
#define devIsKilled(n) ( esFMult[(n)] <=(float)0.0 )
|
||||
|
||||
#define DEV_KILLED ((float) -1.0)
|
||||
|
||||
|
||||
/* macro to add a dev's multiplier to the table and grow it if necessary */
|
||||
#define addDevMult(f) \
|
||||
{ \
|
||||
if ( esFMult == NULL ) { \
|
||||
esFMult = (float *) mallocMagic((unsigned) (esFMSize*sizeof(float))); \
|
||||
} else if ( esFMIndex >= esFMSize ) { \
|
||||
int i; \
|
||||
float *op = esFMult ; \
|
||||
esFMult = (float *) mallocMagic((unsigned) ((esFMSize = esFMSize*2)*sizeof(float))); \
|
||||
for ( i = 0 ; i < esFMSize/2 ; i++ ) esFMult[i] = op[i]; \
|
||||
if (op) freeMagic(op); \
|
||||
} \
|
||||
esFMult[esFMIndex++] = (float)(f); \
|
||||
}
|
||||
|
||||
#define setDevMult(i,f) { esFMult[(i)] = (float)(f); }
|
||||
|
||||
#define getCurDevMult() ((esFMult && (esFMIndex > 0)) ? esFMult[esFMIndex-1] : (float)1.0)
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
#define atoCap(s) ((EFCapValue)atof(s))
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -23,10 +23,16 @@ EFread.o: EFread.c ../tcltk/tclmagic.h ../utils/magic.h ../utils/malloc.h \
|
|||
../bplane/bplane.h ../bplane/bpOpaque.h ../utils/ihash.h \
|
||||
../bplane/bpEnum.h ../utils/geofast.h ../bplane/bplaneInt.h \
|
||||
../extflat/extflat.h ../extflat/EFint.h ../extract/extract.h \
|
||||
../utils/paths.h
|
||||
../extract/extractInt.h ../extract/extDebugInt.h ../utils/paths.h
|
||||
EFsym.o: EFsym.c ../utils/magic.h ../utils/geometry.h ../utils/geofast.h \
|
||||
../utils/hash.h ../utils/malloc.h ../utils/utils.h ../extflat/extflat.h \
|
||||
../extflat/EFint.h
|
||||
EFvisit.o: EFvisit.c ../utils/magic.h ../utils/geometry.h \
|
||||
../utils/geofast.h ../utils/hash.h ../utils/malloc.h ../utils/utils.h \
|
||||
../extflat/extflat.h ../extflat/EFint.h ../extract/extract.h
|
||||
EFantenna.o: EFantenna.c ../tcltk/tclmagic.h ../utils/magic.h \
|
||||
../utils/geometry.h ../utils/hash.h ../utils/utils.h ../utils/styles.h \
|
||||
../tiles/tile.h ../database/database.h ../windows/windows.h \
|
||||
../textio/textio.h ../dbwind/dbwind.h ../textio/txcommands.h \
|
||||
../extflat/extflat.h ../extract/extract.h ../extract/extractInt.h \
|
||||
../extract/extDebugInt.h ../utils/malloc.h
|
||||
|
|
|
|||
|
|
@ -0,0 +1,844 @@
|
|||
/*
|
||||
* EFantenna.c --
|
||||
*
|
||||
* Program to flatten hierarchical .ext files and then execute an
|
||||
* antenna violation check for every MOSFET device in the flattened
|
||||
* design.
|
||||
*
|
||||
* Flattens the tree rooted at file.ext, reading in additional .ext
|
||||
* files as specified by "use" lines in file.ext.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* for atof() */
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h> /* for INFINITY */
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
#include "tcltk/tclmagic.h"
|
||||
#endif
|
||||
#include "utils/magic.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "utils/hash.h"
|
||||
#include "utils/utils.h"
|
||||
#include "utils/styles.h"
|
||||
#include "tiles/tile.h"
|
||||
#include "database/database.h"
|
||||
#include "windows/windows.h"
|
||||
#include "textio/textio.h"
|
||||
#include "dbwind/dbwind.h"
|
||||
#include "textio/txcommands.h"
|
||||
#include "extflat/extflat.h"
|
||||
#include "extract/extract.h"
|
||||
#include "extract/extractInt.h"
|
||||
#include "utils/malloc.h"
|
||||
|
||||
/* Forward declarations */
|
||||
int antennacheckArgs();
|
||||
int antennacheckVisit();
|
||||
|
||||
typedef struct {
|
||||
long visitMask:MAXDEVTYPES;
|
||||
} nodeClient;
|
||||
|
||||
typedef struct {
|
||||
HierName *lastPrefix;
|
||||
long visitMask:MAXDEVTYPES;
|
||||
} nodeClientHier;
|
||||
|
||||
#define NO_RESCLASS -1
|
||||
|
||||
#define markVisited(client, rclass) \
|
||||
{ (client)->visitMask |= (1<<rclass); }
|
||||
|
||||
#define clearVisited(client) \
|
||||
{ (client)->visitMask = (long)0; }
|
||||
|
||||
#define beenVisited(client, rclass) \
|
||||
( (client)->visitMask & (1<<rclass))
|
||||
|
||||
#define initNodeClient(node) \
|
||||
{ \
|
||||
(node)->efnode_client = (ClientData) mallocMagic((unsigned) (sizeof(nodeClient))); \
|
||||
(( nodeClient *)(node)->efnode_client)->visitMask = (long) 0; \
|
||||
}
|
||||
|
||||
|
||||
#define initNodeClientHier(node) \
|
||||
{ \
|
||||
(node)->efnode_client = (ClientData) mallocMagic((unsigned) (sizeof(nodeClientHier))); \
|
||||
((nodeClientHier *) (node)->efnode_client)->visitMask = (long) 0; \
|
||||
}
|
||||
|
||||
/* Diagnostic */
|
||||
int efGates;
|
||||
static int efAntennaDebug = FALSE;
|
||||
|
||||
/* The extract file is designed to be independent of the magic database, */
|
||||
/* but that means that the device types do not match magic database types. */
|
||||
/* A lookup table is needed to cross-reference the device types. */
|
||||
|
||||
TileType *EFDeviceTypes;
|
||||
|
||||
typedef struct _aas {
|
||||
int *accum; /* Pointer to array of accumulated areas per type */
|
||||
int pNum; /* Plane of check */
|
||||
Rect r; /* Holds any one visited rectangle */
|
||||
CellDef *def; /* CellDef for adding feedback */
|
||||
} AntennaAccumStruct;
|
||||
|
||||
typedef struct _gdas {
|
||||
int accum; /* Accumulated area of all gates/diff */
|
||||
Rect r; /* Holds any one visited rectangle */
|
||||
CellDef *def; /* CellDef for adding feedback */
|
||||
} GateDiffAccumStruct;
|
||||
|
||||
typedef struct _ams {
|
||||
int pNum; /* Plane of check */
|
||||
CellDef *def; /* CellDef for adding feedback */
|
||||
} AntennaMarkStruct;
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* Main Tcl callback for command "magic::antennacheck"
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define ANTENNACHECK_RUN 0
|
||||
#define ANTENNACHECK_DEBUG 1
|
||||
#define ANTENNACHECK_HELP 2
|
||||
|
||||
void
|
||||
CmdAntennaCheck(w, cmd)
|
||||
MagWindow *w;
|
||||
TxCommand *cmd;
|
||||
{
|
||||
int i, flatFlags;
|
||||
char *inName;
|
||||
FILE *f;
|
||||
TileType t;
|
||||
|
||||
int option = ANTENNACHECK_RUN;
|
||||
int value;
|
||||
int argc = cmd->tx_argc;
|
||||
char **argv = cmd->tx_argv;
|
||||
char **msg;
|
||||
bool err_result;
|
||||
|
||||
short sd_rclass;
|
||||
short sub_rclass;
|
||||
char *devname;
|
||||
char *subname;
|
||||
int idx;
|
||||
|
||||
CellUse *editUse;
|
||||
|
||||
static char *cmdAntennaCheckOption[] = {
|
||||
"[run] [options] run antennacheck on current cell\n"
|
||||
" use \"run -help\" to get standard options",
|
||||
"debug print detailed information about each error",
|
||||
"help print help information",
|
||||
NULL
|
||||
};
|
||||
|
||||
if (cmd->tx_argc > 1)
|
||||
{
|
||||
option = Lookup(cmd->tx_argv[1], cmdAntennaCheckOption);
|
||||
if (option < 0) option = ANTENNACHECK_RUN;
|
||||
else argv++;
|
||||
}
|
||||
|
||||
switch (option)
|
||||
{
|
||||
case ANTENNACHECK_RUN:
|
||||
goto runantennacheck;
|
||||
break;
|
||||
case ANTENNACHECK_DEBUG:
|
||||
efAntennaDebug = TRUE;
|
||||
break;
|
||||
case ANTENNACHECK_HELP:
|
||||
usage:
|
||||
for (msg = &(cmdAntennaCheckOption[0]); *msg != NULL; msg++)
|
||||
{
|
||||
TxPrintf(" %s\n", *msg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
|
||||
runantennacheck:
|
||||
|
||||
if (ExtCurStyle->exts_planeOrderStatus == noPlaneOrder)
|
||||
{
|
||||
TxError("No planeorder specified for this process: "
|
||||
"Cannot run antenna checks!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
EFInit();
|
||||
EFCapThreshold = INFINITY;
|
||||
EFResistThreshold = INFINITY;
|
||||
|
||||
/* Process command line arguments */
|
||||
inName = EFArgs(argc, argv, &err_result, antennacheckArgs, (ClientData) NULL);
|
||||
|
||||
if (err_result == TRUE)
|
||||
{
|
||||
EFDone();
|
||||
return /* TCL_ERROR */;
|
||||
}
|
||||
|
||||
if (inName == NULL)
|
||||
{
|
||||
/* Assume that we want to do exttospice on the currently loaded cell */
|
||||
|
||||
if (w == (MagWindow *) NULL)
|
||||
windCheckOnlyWindow(&w, DBWclientID);
|
||||
|
||||
if (w == (MagWindow *) NULL)
|
||||
{
|
||||
TxError("Point to a window or specify a cell name.\n");
|
||||
EFDone();
|
||||
return /* TCL_ERROR */;
|
||||
}
|
||||
inName = ((CellUse *) w->w_surfaceID)->cu_def->cd_name;
|
||||
}
|
||||
editUse = (CellUse *)w->w_surfaceID;
|
||||
|
||||
/*
|
||||
* Initializations specific to this program.
|
||||
*/
|
||||
|
||||
/* Read the hierarchical description of the input circuit */
|
||||
TxPrintf("Reading extract file.\n");
|
||||
if (EFReadFile(inName, FALSE, FALSE, FALSE) == FALSE)
|
||||
{
|
||||
EFDone();
|
||||
return /* TCL_ERROR */;
|
||||
}
|
||||
|
||||
/* Convert the hierarchical description to a flat one */
|
||||
flatFlags = EF_FLATNODES;
|
||||
TxPrintf("Building flattened netlist.\n");
|
||||
EFFlatBuild(inName, flatFlags);
|
||||
|
||||
/* Build device lookup table */
|
||||
EFDeviceTypes = (TileType *)mallocMagic(MAXDEVTYPES * sizeof(TileType));
|
||||
for (i = 0; i < MAXDEVTYPES; i++)
|
||||
if (EFDevTypes[i])
|
||||
EFDeviceTypes[i] = extGetDevType(EFDevTypes[i]);
|
||||
|
||||
efGates = 0;
|
||||
TxPrintf("Running antenna checks.\n");
|
||||
EFVisitDevs(antennacheckVisit, (ClientData)editUse);
|
||||
EFFlatDone();
|
||||
EFDone();
|
||||
|
||||
TxPrintf("antennacheck finished.\n");
|
||||
freeMagic(EFDeviceTypes);
|
||||
efAntennaDebug = FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* antennacheckArgs --
|
||||
*
|
||||
* Process those arguments that are specific to antennacheck.
|
||||
* Assumes that *pargv[0][0] is '-', indicating a flag
|
||||
* argument.
|
||||
*
|
||||
* Results:
|
||||
* None. TCL version returns False if an error is encountered
|
||||
* while parsing arguments, True otherwise.
|
||||
*
|
||||
* Side effects:
|
||||
* After processing an argument, updates *pargc and *pargv
|
||||
* to point to after the argument.
|
||||
*
|
||||
* May initialize various global variables based on the
|
||||
* arguments given to us.
|
||||
*
|
||||
* Exits in the event of an improper argument.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
antennacheckArgs(pargc, pargv)
|
||||
int *pargc;
|
||||
char ***pargv;
|
||||
{
|
||||
char **argv = *pargv, *cp;
|
||||
int argc = *pargc;
|
||||
|
||||
switch (argv[0][1])
|
||||
{
|
||||
default:
|
||||
TxError("Unrecognized flag: %s\n", argv[0]);
|
||||
goto usage;
|
||||
}
|
||||
|
||||
*pargv = argv;
|
||||
*pargc = argc;
|
||||
return 0;
|
||||
|
||||
usage:
|
||||
TxError("Usage: antennacheck\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* AntennaGetNode --
|
||||
*
|
||||
* function to find a node given its hierarchical prefix and suffix
|
||||
*
|
||||
* Results:
|
||||
* a pointer to the node struct or NULL
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
EFNode *
|
||||
AntennaGetNode(prefix, suffix)
|
||||
HierName *prefix;
|
||||
HierName *suffix;
|
||||
{
|
||||
HashEntry *he;
|
||||
|
||||
he = EFHNConcatLook(prefix, suffix, "output");
|
||||
return(((EFNodeName *) HashGetValue(he))->efnn_node);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* antennacheckVisit --
|
||||
*
|
||||
* Procedure to check for antenna violations from a single device.
|
||||
* Called by EFVisitDevs().
|
||||
*
|
||||
* Results:
|
||||
* Returns 0 always.
|
||||
*
|
||||
* Side effects:
|
||||
* May tag other device records to avoid double-counting devices.
|
||||
* Generates feedback entries if an antenna violation is found.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
antennacheckVisit(dev, hierName, scale, trans, editUse)
|
||||
Dev *dev; /* Device being output */
|
||||
HierName *hierName; /* Hierarchical path down to this device */
|
||||
float scale; /* Scale transform for output */
|
||||
Transform *trans; /* Coordinate transform */
|
||||
CellUse *editUse; /* ClientData is edit cell use */
|
||||
{
|
||||
DevTerm *gate;
|
||||
TileType t, conType;
|
||||
int pos, pNum, pNum2, pmax, p, i, j, gatearea, diffarea, total;
|
||||
double anttotal;
|
||||
float saveRatio, ratioTotal;
|
||||
int *antennaarea;
|
||||
Rect r, gaterect;
|
||||
EFNode *gnode;
|
||||
SearchContext scx;
|
||||
TileTypeBitMask gatemask, saveConMask;
|
||||
bool antennaError;
|
||||
|
||||
extern CellDef *extPathDef; /* see extract/ExtLength.c */
|
||||
extern CellUse *extPathUse; /* see extract/ExtLength.c */
|
||||
|
||||
extern int areaAccumFunc(), antennaAccumFunc(), areaMarkFunc();
|
||||
|
||||
antennaarea = (int *)mallocMagic(DBNumTypes * sizeof(int));
|
||||
|
||||
switch(dev->dev_class)
|
||||
{
|
||||
case DEV_FET:
|
||||
case DEV_MOSFET:
|
||||
case DEV_MSUBCKT:
|
||||
case DEV_ASYMMETRIC:
|
||||
|
||||
/* Procedure:
|
||||
*
|
||||
* 1. If device gate node is marked visited, return.
|
||||
* 2. Mark device gate node visited
|
||||
* 3. For each plane from metal1 up (determined by planeorder):
|
||||
* a. Run DBTreeCopyConnect()
|
||||
* b. Accumulate gate area of connected devices
|
||||
* c. Accumulate diffusion area of connected devices
|
||||
* d. Accumulate metal area of connected devices
|
||||
* e. Check against antenna ratio(s)
|
||||
* f. Generate feedback if in violation of antenna rule
|
||||
*
|
||||
* NOTE: DBTreeCopyConnect() is used cumulatively, so that
|
||||
* additional searching only needs to be done for the additional
|
||||
* layer being searched.
|
||||
*/
|
||||
|
||||
GeoTransRect(trans, &dev->dev_rect, &r);
|
||||
gate = &dev->dev_terms[0];
|
||||
gnode = AntennaGetNode(hierName, gate->dterm_node->efnode_name->efnn_hier);
|
||||
if (gnode->efnode_client == (ClientData) NULL)
|
||||
initNodeClient(gnode);
|
||||
if (beenVisited((nodeClient *)gnode->efnode_client, 0))
|
||||
return 0;
|
||||
else
|
||||
markVisited((nodeClient *)gnode->efnode_client, 0);
|
||||
|
||||
/* Diagnostic stuff */
|
||||
efGates++;
|
||||
if (efGates % 100 == 0) TxPrintf(" %d gates analyzed.\n", efGates);
|
||||
|
||||
/* Find the plane of the gate type */
|
||||
t = EFDeviceTypes[dev->dev_type];
|
||||
pNum = DBPlane(t);
|
||||
pos = ExtCurStyle->exts_planeOrder[pNum];
|
||||
pmax = ++pos;
|
||||
|
||||
/* Find the highest plane in the technology */
|
||||
for (p = PL_TECHDEPBASE; p < DBNumPlanes; p++)
|
||||
if (ExtCurStyle->exts_planeOrder[p] > pmax)
|
||||
pmax = ExtCurStyle->exts_planeOrder[p];
|
||||
|
||||
/* Create the yank cell if it doesn't already exist */
|
||||
if (extPathDef == (CellDef *) NULL)
|
||||
DBNewYank("__PATHYANK__", &extPathUse, &extPathDef);
|
||||
|
||||
/* Use the cellDef reserved for extraction */
|
||||
/* DBCellClearDef(extPathDef); */ /* See below */
|
||||
scx.scx_use = editUse;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
scx.scx_area = r;
|
||||
|
||||
/* gatemask is a mask of all gate types for MOSFET devices */
|
||||
|
||||
TTMaskZero(&gatemask);
|
||||
for (i = 0; i < DBNumTypes; i++)
|
||||
{
|
||||
ExtDevice *ed;
|
||||
char devclass;
|
||||
|
||||
if (ExtCurStyle->exts_device[i] != NULL)
|
||||
{
|
||||
for (ed = ExtCurStyle->exts_device[i]; ed; ed = ed->exts_next)
|
||||
{
|
||||
devclass = ed->exts_deviceClass;
|
||||
switch (devclass)
|
||||
{
|
||||
case DEV_MOSFET:
|
||||
case DEV_FET:
|
||||
case DEV_ASYMMETRIC:
|
||||
case DEV_MSUBCKT:
|
||||
TTMaskSetType(&gatemask, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (; pos <= pmax; pos++)
|
||||
{
|
||||
GateDiffAccumStruct gdas;
|
||||
AntennaAccumStruct aas;
|
||||
AntennaMarkStruct ams;
|
||||
|
||||
/* Find the plane of pos */
|
||||
|
||||
for (p = 0; p < DBNumPlanes; p++)
|
||||
if (ExtCurStyle->exts_planeOrder[p] == pos)
|
||||
pNum2 = p;
|
||||
|
||||
/* Find the tiletype which is a contact and whose base is pNum2 */
|
||||
/* (NOTE: Need to extend to all such contacts, as there may be */
|
||||
/* more than one.) (Also should find these types up top, not */
|
||||
/* within the loop.) */
|
||||
|
||||
/* Modify DBConnectTbl to limit connectivity to the plane */
|
||||
/* of the antenna check and below */
|
||||
|
||||
conType = -1;
|
||||
for (i = 0; i < DBNumTypes; i++)
|
||||
if (DBIsContact(i) && DBPlane(i) == pNum2)
|
||||
{
|
||||
conType = i;
|
||||
TTMaskZero(&saveConMask);
|
||||
TTMaskSetMask(&saveConMask, &DBConnectTbl[i]);
|
||||
TTMaskZero(&DBConnectTbl[i]);
|
||||
for (j = 0; j < DBNumTypes; j++)
|
||||
if (TTMaskHasType(&saveConMask, j) &&
|
||||
(DBPlane(j) <= pNum2))
|
||||
TTMaskSetType(&DBConnectTbl[i], j);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < DBNumTypes; i++) antennaarea[i] = 0;
|
||||
gatearea = 0;
|
||||
diffarea = 0;
|
||||
|
||||
/* Note: Ideally, the addition of material in the next */
|
||||
/* metal plane is additive. But that requires enumerating */
|
||||
/* all the vias and using those as starting points for the */
|
||||
/* next connectivity search, which needs to be coded. */
|
||||
|
||||
DBCellClearDef(extPathDef);
|
||||
|
||||
/* To do: Mark tiles so area count can be progressive */
|
||||
|
||||
DBTreeCopyConnect(&scx, &DBConnectTbl[t], 0,
|
||||
DBConnectTbl, &TiPlaneRect, extPathUse);
|
||||
|
||||
/* Search planes of tie types and accumulate all tiedown areas */
|
||||
gdas.accum = 0;
|
||||
for (p = 0; p < DBNumPlanes; p++)
|
||||
DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[p],
|
||||
&TiPlaneRect, &ExtCurStyle->exts_antennaTieTypes,
|
||||
areaAccumFunc, (ClientData)&gdas);
|
||||
diffarea = gdas.accum;
|
||||
|
||||
/* Search plane of gate type and accumulate all gate area */
|
||||
gdas.accum = 0;
|
||||
DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[pNum],
|
||||
&TiPlaneRect, &gatemask, areaAccumFunc, (ClientData)&gdas);
|
||||
gatearea = gdas.accum;
|
||||
|
||||
/* Search metal planes and accumulate all antenna areas */
|
||||
for (p = 0; p < DBNumPlanes; p++)
|
||||
{
|
||||
if (ExtCurStyle->exts_antennaModel & ANTENNAMODEL_PARTIAL)
|
||||
if (p != pNum2) continue;
|
||||
|
||||
aas.pNum = p;
|
||||
aas.accum = &antennaarea[0];
|
||||
if (ExtCurStyle->exts_planeOrder[p] <= pos)
|
||||
DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[p],
|
||||
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
|
||||
antennaAccumFunc, (ClientData)&aas);
|
||||
}
|
||||
|
||||
antennaError = FALSE;
|
||||
if (diffarea == 0)
|
||||
{
|
||||
anttotal = 0.0;
|
||||
saveRatio = 0.0;
|
||||
for (i = 0; i < DBNumTypes; i++)
|
||||
{
|
||||
if (ExtCurStyle->exts_antennaRatio[i].ratioGate > 0)
|
||||
{
|
||||
anttotal += (double)antennaarea[i] /
|
||||
(double)ExtCurStyle->exts_antennaRatio[i].ratioGate;
|
||||
}
|
||||
if (ExtCurStyle->exts_antennaRatio[i].ratioGate > saveRatio)
|
||||
saveRatio = ExtCurStyle->exts_antennaRatio[i].ratioGate;
|
||||
}
|
||||
|
||||
if (anttotal > (double)gatearea)
|
||||
{
|
||||
antennaError = TRUE;
|
||||
if (efAntennaDebug == TRUE)
|
||||
{
|
||||
TxError("Antenna violation detected at plane %s\n",
|
||||
DBPlaneLongNameTbl[pNum2]);
|
||||
TxError("Effective antenna ratio %g > limit %g\n",
|
||||
saveRatio * (float)anttotal / (float)gatearea,
|
||||
saveRatio);
|
||||
TxError("Gate rect (%d %d) to (%d %d)\n",
|
||||
gdas.r.r_xbot, gdas.r.r_ybot,
|
||||
gdas.r.r_xtop, gdas.r.r_ytop);
|
||||
TxError("Antenna rect (%d %d) to (%d %d)\n",
|
||||
aas.r.r_xbot, aas.r.r_ybot,
|
||||
aas.r.r_xtop, aas.r.r_ytop);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
anttotal = 0.0;
|
||||
saveRatio = 0.0;
|
||||
for (i = 0; i < DBNumTypes; i++)
|
||||
if (ExtCurStyle->exts_antennaRatio[i].ratioDiffB != INFINITY)
|
||||
{
|
||||
ratioTotal = ExtCurStyle->exts_antennaRatio[i].ratioDiffB +
|
||||
diffarea * ExtCurStyle->exts_antennaRatio[i].ratioDiffA;
|
||||
|
||||
if (ratioTotal > 0)
|
||||
anttotal += (double)antennaarea[i] / (double)ratioTotal;
|
||||
if (ratioTotal > saveRatio)
|
||||
saveRatio = ratioTotal;
|
||||
}
|
||||
|
||||
if (anttotal > (double)gatearea)
|
||||
{
|
||||
antennaError = TRUE;
|
||||
if (efAntennaDebug == TRUE)
|
||||
{
|
||||
TxError("Antenna violation detected at plane %s\n",
|
||||
DBPlaneLongNameTbl[pNum2]);
|
||||
TxError("Effective antenna ratio %g > limit %g\n",
|
||||
saveRatio * (float)anttotal / (float)gatearea,
|
||||
saveRatio);
|
||||
TxError("Gate rect (%d %d) to (%d %d)\n",
|
||||
gdas.r.r_xbot, gdas.r.r_ybot,
|
||||
gdas.r.r_xtop, gdas.r.r_ytop);
|
||||
TxError("Antenna rect (%d %d) to (%d %d)\n",
|
||||
aas.r.r_xbot, aas.r.r_ybot,
|
||||
aas.r.r_xtop, aas.r.r_ytop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (antennaError)
|
||||
{
|
||||
/* Search plane of gate type and mark all gate areas */
|
||||
ams.def = editUse->cu_def;
|
||||
ams.pNum = pNum2;
|
||||
DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[pNum],
|
||||
&TiPlaneRect, &gatemask, areaMarkFunc, (ClientData)&ams);
|
||||
|
||||
/* Search metal planes and accumulate all antenna areas */
|
||||
for (p = 0; p < DBNumPlanes; p++)
|
||||
{
|
||||
if (ExtCurStyle->exts_antennaModel & ANTENNAMODEL_PARTIAL)
|
||||
if (p != pNum2) continue;
|
||||
|
||||
if (ExtCurStyle->exts_planeOrder[p] <= pos)
|
||||
DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[p],
|
||||
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
|
||||
areaMarkFunc, (ClientData)&ams);
|
||||
}
|
||||
}
|
||||
|
||||
/* Put the connect table back the way it was */
|
||||
if (conType >= 0)
|
||||
TTMaskSetMask(&DBConnectTbl[conType], &saveConMask);
|
||||
}
|
||||
}
|
||||
freeMagic(antennaarea);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* areaMarkFunc --
|
||||
*
|
||||
* Mark the tile areas searched with feedback entries
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
areaMarkFunc(tile, ams)
|
||||
Tile *tile;
|
||||
AntennaMarkStruct *ams;
|
||||
{
|
||||
Rect rect;
|
||||
char msg[200];
|
||||
|
||||
TiToRect(tile, &rect);
|
||||
sprintf(msg, "Antenna error at plane %s\n", DBPlaneLongNameTbl[ams->pNum]);
|
||||
DBWFeedbackAdd(&rect, msg, ams->def, 1, STYLE_PALEHIGHLIGHTS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* areaAccumFunc --
|
||||
*
|
||||
* Accumulate the total tile area searched
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
areaAccumFunc(tile, gdas)
|
||||
Tile *tile;
|
||||
GateDiffAccumStruct *gdas;
|
||||
{
|
||||
Rect *rect = &(gdas->r);
|
||||
int area, type;
|
||||
|
||||
TiToRect(tile, rect);
|
||||
area = (rect->r_xtop - rect->r_xbot) * (rect->r_ytop - rect->r_ybot);
|
||||
gdas->accum += area;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* antennaAccumFunc --
|
||||
*
|
||||
* Accumulate the total tile area searched, keeping an individual
|
||||
* count for each tile type. If the antenna model is SIDEWALL, then
|
||||
* calculate the area of the tile sidewall (tile perimeter * layer
|
||||
* thickness), rather than the drawn tile area.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
antennaAccumFunc(tile, aaptr)
|
||||
Tile *tile;
|
||||
AntennaAccumStruct *aaptr;
|
||||
{
|
||||
Rect *rect = &(aaptr->r);
|
||||
int area;
|
||||
int type;
|
||||
int *typeareas = aaptr->accum;
|
||||
int plane = aaptr->pNum;
|
||||
float thick;
|
||||
|
||||
type = TiGetType(tile);
|
||||
|
||||
TiToRect(tile, rect);
|
||||
|
||||
if (ExtCurStyle->exts_antennaRatio[type].areaType & ANTENNAMODEL_SIDEWALL)
|
||||
{
|
||||
/* Accumulate perimeter of tile where tile abuts space */
|
||||
|
||||
Tile *tp;
|
||||
int perimeter = 0, pmax, pmin;
|
||||
|
||||
/* Top */
|
||||
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
|
||||
{
|
||||
if (TiGetBottomType(tp) == TT_SPACE)
|
||||
{
|
||||
pmin = MAX(LEFT(tile), LEFT(tp));
|
||||
pmax = MIN(RIGHT(tile), RIGHT(tp));
|
||||
perimeter += (pmax - pmin);
|
||||
}
|
||||
}
|
||||
/* Bottom */
|
||||
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
||||
{
|
||||
if (TiGetTopType(tp) == TT_SPACE)
|
||||
{
|
||||
pmin = MAX(LEFT(tile), LEFT(tp));
|
||||
pmax = MIN(RIGHT(tile), RIGHT(tp));
|
||||
perimeter += (pmax - pmin);
|
||||
}
|
||||
}
|
||||
/* Left */
|
||||
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
||||
{
|
||||
if (TiGetRightType(tp) == TT_SPACE)
|
||||
{
|
||||
pmin = MAX(BOTTOM(tile), BOTTOM(tp));
|
||||
pmax = MIN(TOP(tile), TOP(tp));
|
||||
perimeter += (pmax - pmin);
|
||||
}
|
||||
}
|
||||
/* Right */
|
||||
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
|
||||
{
|
||||
if (TiGetLeftType(tp) == TT_SPACE)
|
||||
{
|
||||
pmin = MAX(BOTTOM(tile), BOTTOM(tp));
|
||||
pmax = MIN(TOP(tile), TOP(tp));
|
||||
perimeter += (pmax - pmin);
|
||||
}
|
||||
}
|
||||
|
||||
if (DBIsContact(type))
|
||||
{
|
||||
int cperim;
|
||||
TileType ttype;
|
||||
TileTypeBitMask sMask;
|
||||
float thick;
|
||||
|
||||
cperim = ((rect->r_xtop - rect->r_xbot) + (rect->r_ytop - rect->r_ybot)) << 1;
|
||||
|
||||
/* For contacts, add the area of the perimeter to the */
|
||||
/* residue (metal) type on the plane being searched. */
|
||||
/* Then, if the plane is the same as the base type of */
|
||||
/* the contact, add the entire perimeter area of the */
|
||||
/* tile to the total for the contact type itself. */
|
||||
|
||||
DBFullResidueMask(type, &sMask);
|
||||
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
|
||||
if (TTMaskHasType(&sMask, ttype))
|
||||
if (DBTypeOnPlane(ttype, plane))
|
||||
{
|
||||
thick = ExtCurStyle->exts_thick[ttype];
|
||||
typeareas[ttype] += (int)((float)perimeter * thick);
|
||||
}
|
||||
|
||||
if (type >= DBNumUserLayers)
|
||||
{
|
||||
DBResidueMask(type, &sMask);
|
||||
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
|
||||
if (TTMaskHasType(&sMask, ttype))
|
||||
if (DBTypeOnPlane(ttype, plane))
|
||||
{
|
||||
thick = ExtCurStyle->exts_thick[ttype];
|
||||
typeareas[ttype] += (int)((float)perimeter * thick);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
thick = ExtCurStyle->exts_thick[type];
|
||||
typeareas[type] += (int)((float)perimeter * thick);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Area is perimeter times layer thickness */
|
||||
thick = ExtCurStyle->exts_thick[type];
|
||||
typeareas[type] += (int)((float)perimeter * thick);
|
||||
}
|
||||
}
|
||||
else if (ExtCurStyle->exts_antennaRatio[type].areaType & ANTENNAMODEL_SURFACE)
|
||||
{
|
||||
/* Simple tile area calculation */
|
||||
area = (rect->r_xtop - rect->r_xbot) * (rect->r_ytop - rect->r_ybot);
|
||||
|
||||
/* If type is a contact, then add area to both residues as well */
|
||||
/* as the contact type. */
|
||||
|
||||
/* NOTE: Restrict area counts per plane so areas of contacts */
|
||||
/* are not double-counted. */
|
||||
|
||||
if (DBIsContact(type))
|
||||
{
|
||||
TileType ttype;
|
||||
TileTypeBitMask sMask;
|
||||
|
||||
DBFullResidueMask(type, &sMask);
|
||||
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
|
||||
if (TTMaskHasType(&sMask, ttype))
|
||||
if (DBTypeOnPlane(ttype, plane))
|
||||
typeareas[ttype] += area;
|
||||
|
||||
if (type >= DBNumUserLayers)
|
||||
{
|
||||
DBResidueMask(type, &sMask);
|
||||
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
|
||||
if (TTMaskHasType(&sMask, ttype))
|
||||
if (DBTypeOnPlane(ttype, plane))
|
||||
{
|
||||
typeareas[ttype] += area;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
typeareas[type] += area;
|
||||
}
|
||||
else
|
||||
typeareas[type] += area;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -160,6 +160,15 @@ EFArgs(argc, argv, err_result, argsProc, cdata)
|
|||
HierName *hierName;
|
||||
FILE *f;
|
||||
|
||||
char usage_text[] =
|
||||
"Standard arguments: [-R] [-C] [-r rthresh] [-c cthresh] [-v]\n"
|
||||
"[-p searchpath] [-s sym=value] [-S symfile] [-t trimchars]\n"
|
||||
#ifdef MAGIC_WRAPPER
|
||||
"[rootfile]\n";
|
||||
#else
|
||||
"[-T techname] rootfile\n";
|
||||
#endif
|
||||
|
||||
if (err_result != NULL) *err_result = FALSE;
|
||||
|
||||
/* Hash table of nodes we're going to watch if -N given */
|
||||
|
|
@ -209,8 +218,10 @@ EFArgs(argc, argv, err_result, argsProc, cdata)
|
|||
goto usage;
|
||||
if (strchr(cp, '!')) EFTrimFlags |= EF_TRIMGLOB;
|
||||
if (strchr(cp, '#')) EFTrimFlags |= EF_TRIMLOCAL;
|
||||
if (strchr(cp, ',')) EFTrimFlags |= EF_CONVERTCOMMAS;
|
||||
if (strchr(cp, ',')) EFTrimFlags |= EF_CONVERTCOMMA;
|
||||
if (strchr(cp, '=')) EFTrimFlags |= EF_CONVERTEQUAL;
|
||||
if (strchr(cp, '[')) EFTrimFlags |= EF_CONVERTBRACKETS;
|
||||
if (strchr(cp, ']')) EFTrimFlags |= EF_CONVERTBRACKETS;
|
||||
break;
|
||||
case 'C':
|
||||
EFCapThreshold = (EFCapValue)INFINITE_THRESHOLD_F;
|
||||
|
|
@ -268,6 +279,11 @@ EFArgs(argc, argv, err_result, argsProc, cdata)
|
|||
case 'z':
|
||||
efHNStats = TRUE;
|
||||
break;
|
||||
case 'h':
|
||||
if (argsProc != NULL) (*argsProc)(&argc, &argv, cdata);
|
||||
TxPrintf(usage_text);
|
||||
if (err_result != NULL) *err_result = TRUE;
|
||||
return NULL;
|
||||
|
||||
/*** Try a caller-supplied argument processing function ***/
|
||||
default:
|
||||
|
|
@ -310,19 +326,15 @@ EFArgs(argc, argv, err_result, argsProc, cdata)
|
|||
realIn[cp - inname] = '\0';
|
||||
inname = realIn;
|
||||
}
|
||||
|
||||
return inname;
|
||||
|
||||
usage:
|
||||
TxError("Standard arguments: [-R] [-C] [-r rthresh] [-c cthresh] [-v]\n"
|
||||
"[-p searchpath] [-s sym=value] [-S symfile] [-t trimchars]\n"
|
||||
TxError(usage_text);
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
"[rootfile]\n");
|
||||
if (err_result != NULL) *err_result = TRUE;
|
||||
return NULL;
|
||||
#else
|
||||
"[-T techname] rootfile\n");
|
||||
exit (1);
|
||||
/*NOTREACHED*/
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ void efNodeMerge();
|
|||
bool efConnBuildName();
|
||||
bool efConnInitSubs();
|
||||
|
||||
extern float locScale;
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
|
|
@ -172,15 +174,15 @@ efBuildNode(def, isSubsnode, nodeName, nodeCap, x, y, layerName, av, ac)
|
|||
HashSetValue(he, (char *) newname);
|
||||
|
||||
/* New node itself */
|
||||
size = sizeof (EFNode) + (efNumResistClasses - 1) * sizeof (PerimArea);
|
||||
size = sizeof (EFNode) + (efNumResistClasses - 1) * sizeof (EFPerimArea);
|
||||
newnode = (EFNode *) mallocMagic((unsigned)(size));
|
||||
newnode->efnode_flags = (isSubsnode == TRUE) ? EF_SUBS_NODE : 0;
|
||||
newnode->efnode_cap = nodeCap;
|
||||
newnode->efnode_attrs = (EFAttr *) NULL;
|
||||
newnode->efnode_loc.r_xbot = x;
|
||||
newnode->efnode_loc.r_ybot = y;
|
||||
newnode->efnode_loc.r_xtop = x + 1;
|
||||
newnode->efnode_loc.r_ytop = y + 1;
|
||||
newnode->efnode_loc.r_xbot = (int)(0.5 + (float)x * locScale);
|
||||
newnode->efnode_loc.r_ybot = (int)(0.5 + (float)y * locScale);
|
||||
newnode->efnode_loc.r_xtop = newnode->efnode_loc.r_xbot + 1;
|
||||
newnode->efnode_loc.r_ytop = newnode->efnode_loc.r_ybot + 1;
|
||||
newnode->efnode_client = (ClientData) NULL;
|
||||
if (layerName) newnode->efnode_type =
|
||||
efBuildAddStr(EFLayerNames, &EFLayerNumNames, MAXTYPES, layerName);
|
||||
|
|
@ -553,8 +555,8 @@ efBuildDeviceParams(name, argc, argv)
|
|||
if (name[0] == ':')
|
||||
{
|
||||
newparm->parm_name = StrDup((char **)NULL, argv[n]);
|
||||
newparm->parm_type[1] = '0' + n / 10;
|
||||
newparm->parm_type[0] = '0' + n % 10;
|
||||
newparm->parm_type[0] = '0' + n / 10;
|
||||
newparm->parm_type[1] = '0' + n % 10;
|
||||
}
|
||||
else
|
||||
newparm->parm_name = StrDup((char **)NULL, pptr + 1);
|
||||
|
|
@ -591,23 +593,28 @@ efBuildDevice(def, class, type, r, argc, argv)
|
|||
Rect *r; /* Coordinates of 1x1 rectangle entirely inside device */
|
||||
int argc; /* Size of argv */
|
||||
char *argv[]; /* Tokens for the rest of the dev line.
|
||||
* The first depend on the type of device. The rest
|
||||
* are taken in groups of 3, one for each terminal.
|
||||
* Each group of 3 consists of the node name to which
|
||||
* the terminal connects, the length of the terminal,
|
||||
* and an attribute list (or the token 0).
|
||||
* Starts with the last two position values, used to
|
||||
* hash the device record. The next arguments depend
|
||||
* on the type of device. The rest are taken in groups
|
||||
* of 3, one for each terminal. Each group of 3 consists
|
||||
* of the node name to which the terminal connects, the
|
||||
* length of the terminal, and an attribute list (or the
|
||||
* token 0).
|
||||
*/
|
||||
{
|
||||
int n, nterminals, pn;
|
||||
HashEntry *he;
|
||||
DevTerm *term;
|
||||
Dev *newdev, devtmp;
|
||||
DevParam *newparm, *devp, *sparm;
|
||||
char ptype, *pptr, **av;
|
||||
char devhash[64];
|
||||
int argstart = 1; /* start of terminal list in argv[] */
|
||||
bool hasModel = strcmp(type, "None") ? TRUE : FALSE;
|
||||
|
||||
int area, perim; /* Total area, perimeter of primary type (i.e., channel) */
|
||||
|
||||
newdev = (Dev *)NULL;
|
||||
devtmp.dev_subsnode = NULL;
|
||||
devtmp.dev_cap = 0.0;
|
||||
devtmp.dev_res = 0.0;
|
||||
|
|
@ -681,7 +688,8 @@ efBuildDevice(def, class, type, r, argc, argv)
|
|||
{
|
||||
pn = *(argv[argstart] + 1) - '0';
|
||||
if (pn == 0)
|
||||
devtmp.dev_area = atoi(pptr);
|
||||
devtmp.dev_area = (int)(0.5 + (float)atoi(pptr)
|
||||
* locScale * locScale);
|
||||
/* Otherwise, punt */
|
||||
}
|
||||
break;
|
||||
|
|
@ -692,15 +700,15 @@ efBuildDevice(def, class, type, r, argc, argv)
|
|||
{
|
||||
pn = *(argv[argstart] + 1) - '0';
|
||||
if (pn == 0)
|
||||
devtmp.dev_perim = atoi(pptr);
|
||||
devtmp.dev_perim = (int)(0.5 + (float)atoi(pptr) * locScale);
|
||||
/* Otherwise, use verbatim */
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
devtmp.dev_length = atoi(pptr);
|
||||
devtmp.dev_length = (int)(0.5 + (float)atoi(pptr) * locScale);
|
||||
break;
|
||||
case 'w':
|
||||
devtmp.dev_width = atoi(pptr);
|
||||
devtmp.dev_width = (int)(0.5 + (float)atoi(pptr) * locScale);
|
||||
break;
|
||||
case 'c':
|
||||
devtmp.dev_cap = (float)atof(pptr);
|
||||
|
|
@ -713,7 +721,6 @@ efBuildDevice(def, class, type, r, argc, argv)
|
|||
}
|
||||
|
||||
/* Check for optional substrate node */
|
||||
|
||||
switch (class)
|
||||
{
|
||||
case DEV_RES:
|
||||
|
|
@ -743,93 +750,149 @@ efBuildDevice(def, class, type, r, argc, argv)
|
|||
|
||||
nterminals = (argc - argstart) / 3;
|
||||
|
||||
newdev = (Dev *) mallocMagic((unsigned) DevSize(nterminals));
|
||||
newdev->dev_subsnode = devtmp.dev_subsnode;
|
||||
newdev->dev_cap = devtmp.dev_cap;
|
||||
newdev->dev_res = devtmp.dev_res;
|
||||
newdev->dev_area = devtmp.dev_area;
|
||||
newdev->dev_perim = devtmp.dev_perim;
|
||||
newdev->dev_length = devtmp.dev_length;
|
||||
newdev->dev_width = devtmp.dev_width;
|
||||
newdev->dev_params = devtmp.dev_params;
|
||||
/* Determine if this device has been seen before */
|
||||
|
||||
newdev->dev_nterm = nterminals;
|
||||
newdev->dev_rect = *r;
|
||||
newdev->dev_type = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, type);
|
||||
newdev->dev_class = class;
|
||||
sprintf(devhash, "%dx%d%s", r->r_xbot, r->r_ybot, type);
|
||||
he = HashFind(&def->def_devs, devhash);
|
||||
newdev = (Dev *)HashGetValue(he);
|
||||
if (newdev)
|
||||
{
|
||||
/* Duplicate device. Duplicates will only appear in res.ext files
|
||||
* where a device has nodes changed. Merge all properties of the
|
||||
* original device with nodes from the new device. Keep the
|
||||
* original device and discard the new one.
|
||||
*
|
||||
* Check that the device is actually the same device type and number
|
||||
* of terminals. If not, throw an error and abandon the new device.
|
||||
*/
|
||||
|
||||
if ((newdev->dev_class != class) ||
|
||||
(strcmp(EFDevTypes[newdev->dev_type], type)))
|
||||
{
|
||||
TxError("Device %s %s at (%d, %d) overlaps incompatible device %s %s!\n",
|
||||
extDevTable[class], type, r->r_xbot, r->r_ybot,
|
||||
extDevTable[newdev->dev_class], EFDevTypes[newdev->dev_type]);
|
||||
return 0;
|
||||
}
|
||||
else if (newdev->dev_nterm != nterminals)
|
||||
{
|
||||
TxError("Device %s %s at (%d, %d) overlaps device with incompatible"
|
||||
" number of terminals (%d vs. %d)!\n",
|
||||
extDevTable[class], type, r->r_xbot, r->r_ybot, nterminals,
|
||||
newdev->dev_nterm);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newdev = (Dev *) mallocMagic((unsigned) DevSize(nterminals));
|
||||
|
||||
/* Add this dev to the hash table for def */
|
||||
HashSetValue(he, (ClientData)newdev);
|
||||
|
||||
newdev->dev_cap = devtmp.dev_cap;
|
||||
newdev->dev_res = devtmp.dev_res;
|
||||
newdev->dev_area = devtmp.dev_area;
|
||||
newdev->dev_perim = devtmp.dev_perim;
|
||||
newdev->dev_length = devtmp.dev_length;
|
||||
newdev->dev_width = devtmp.dev_width;
|
||||
newdev->dev_params = devtmp.dev_params;
|
||||
|
||||
newdev->dev_nterm = nterminals;
|
||||
newdev->dev_rect = *r;
|
||||
newdev->dev_type = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, type);
|
||||
newdev->dev_class = class;
|
||||
|
||||
switch (class)
|
||||
{
|
||||
case DEV_FET: /* old-style "fet" record */
|
||||
newdev->dev_area = atoi(argv[0]);
|
||||
newdev->dev_perim = atoi(argv[1]);
|
||||
break;
|
||||
case DEV_MOSFET: /* new-style "device mosfet" record */
|
||||
case DEV_ASYMMETRIC:
|
||||
case DEV_BJT:
|
||||
newdev->dev_length = atoi(argv[0]);
|
||||
newdev->dev_width = atoi(argv[1]);
|
||||
break;
|
||||
case DEV_RES:
|
||||
if (hasModel && StrIsInt(argv[0]) && StrIsInt(argv[1]))
|
||||
{
|
||||
newdev->dev_length = atoi(argv[0]);
|
||||
newdev->dev_width = atoi(argv[1]);
|
||||
}
|
||||
else if (StrIsNumeric(argv[0]))
|
||||
{
|
||||
newdev->dev_res = (float)atof(argv[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasModel)
|
||||
{
|
||||
efReadError("Error: expected L and W, got %s %s\n", argv[0],
|
||||
argv[1]);
|
||||
newdev->dev_length = 0;
|
||||
newdev->dev_width = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
efReadError("Error: expected resistance value, got %s\n",
|
||||
argv[0]);
|
||||
newdev->dev_res = 0.0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DEV_CAP:
|
||||
case DEV_CAPREV:
|
||||
if (hasModel && StrIsInt(argv[0]) && StrIsInt(argv[1]))
|
||||
{
|
||||
newdev->dev_length = atoi(argv[0]);
|
||||
newdev->dev_width = atoi(argv[1]);
|
||||
}
|
||||
else if (StrIsNumeric(argv[0]))
|
||||
{
|
||||
newdev->dev_cap = (float)atof(argv[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasModel)
|
||||
{
|
||||
efReadError("Error: expected L and W, got %s %s\n", argv[0],
|
||||
argv[1]);
|
||||
newdev->dev_length = 0;
|
||||
newdev->dev_width = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
efReadError("Error: expected capacitance value, got %s\n",
|
||||
argv[0]);
|
||||
newdev->dev_cap = 0.0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
newdev->dev_subsnode = devtmp.dev_subsnode;
|
||||
switch (class)
|
||||
{
|
||||
case DEV_FET: /* old-style "fet" record */
|
||||
newdev->dev_area = atoi(argv[0]);
|
||||
newdev->dev_perim = atoi(argv[1]);
|
||||
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
|
||||
break;
|
||||
case DEV_MOSFET: /* new-style "device mosfet" record */
|
||||
case DEV_ASYMMETRIC:
|
||||
case DEV_BJT:
|
||||
newdev->dev_length = atoi(argv[0]);
|
||||
newdev->dev_width = atoi(argv[1]);
|
||||
|
||||
/* "None" in the place of the substrate name means substrate is ignored */
|
||||
if ((argstart == 3) && (strncmp(argv[2], "None", 4) != 0))
|
||||
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
|
||||
break;
|
||||
case DEV_RES:
|
||||
if (hasModel && StrIsInt(argv[0]) && StrIsInt(argv[1]))
|
||||
{
|
||||
newdev->dev_length = atoi(argv[0]);
|
||||
newdev->dev_width = atoi(argv[1]);
|
||||
}
|
||||
else if (StrIsNumeric(argv[0]))
|
||||
{
|
||||
newdev->dev_res = (float)atof(argv[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasModel)
|
||||
{
|
||||
efReadError("Error: expected L and W, got %s %s\n", argv[0],
|
||||
argv[1]);
|
||||
newdev->dev_length = 0;
|
||||
newdev->dev_width = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
efReadError("Error: expected resistance value, got %s\n", argv[0]);
|
||||
newdev->dev_res = 0.0;
|
||||
}
|
||||
}
|
||||
if ((argstart == 3) && (strncmp(argv[2], "None", 4) != 0))
|
||||
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
|
||||
|
||||
break;
|
||||
case DEV_CAP:
|
||||
case DEV_CAPREV:
|
||||
if (hasModel && StrIsInt(argv[0]) && StrIsInt(argv[1]))
|
||||
{
|
||||
newdev->dev_length = atoi(argv[0]);
|
||||
newdev->dev_width = atoi(argv[1]);
|
||||
}
|
||||
else if (StrIsNumeric(argv[0]))
|
||||
{
|
||||
newdev->dev_cap = (float)atof(argv[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasModel)
|
||||
{
|
||||
efReadError("Error: expected L and W, got %s %s\n", argv[0],
|
||||
argv[1]);
|
||||
newdev->dev_length = 0;
|
||||
newdev->dev_width = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
efReadError("Error: expected capacitance value, got %s\n", argv[0]);
|
||||
newdev->dev_cap = 0.0;
|
||||
}
|
||||
}
|
||||
if ((argstart == 3) && (strncmp(argv[2], "None", 4) != 0))
|
||||
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
|
||||
|
||||
|
|
@ -859,10 +922,6 @@ efBuildDevice(def, class, type, r, argc, argv)
|
|||
#undef TERM_PERIM
|
||||
#undef TERM_ATTRS
|
||||
|
||||
/* Add this dev to the list for def */
|
||||
newdev->dev_next = def->def_devs;
|
||||
def->def_devs = newdev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1123,12 +1182,26 @@ efBuildUse(def, subDefName, subUseId, ta, tb, tc, td, te, tf)
|
|||
}
|
||||
else
|
||||
{
|
||||
*cp = '\0';
|
||||
newuse->use_id = StrDup((char **) NULL, subUseId);
|
||||
*cp = '[';
|
||||
(void) sscanf(cp, "[%d:%d:%d][%d:%d:%d]",
|
||||
/* Note: Preserve any use of brackets as-is other than the */
|
||||
/* standard magic array notation below. This allows, for */
|
||||
/* example, verilog instance arrays read from DEF files to */
|
||||
/* be passed through correctly. */
|
||||
|
||||
if ((sscanf(cp, "[%d:%d:%d][%d:%d:%d]",
|
||||
&newuse->use_xlo, &newuse->use_xhi, &newuse->use_xsep,
|
||||
&newuse->use_ylo, &newuse->use_yhi, &newuse->use_ysep);
|
||||
&newuse->use_ylo, &newuse->use_yhi, &newuse->use_ysep)) == 6)
|
||||
{
|
||||
*cp = '\0';
|
||||
newuse->use_id = StrDup((char **) NULL, subUseId);
|
||||
*cp = '[';
|
||||
}
|
||||
else
|
||||
{
|
||||
newuse->use_id = StrDup((char **) NULL, subUseId);
|
||||
newuse->use_xlo = newuse->use_xhi = 0;
|
||||
newuse->use_ylo = newuse->use_yhi = 0;
|
||||
newuse->use_xsep = newuse->use_ysep = 0;
|
||||
}
|
||||
}
|
||||
|
||||
he = HashFind(&def->def_uses, newuse->use_id);
|
||||
|
|
@ -1168,7 +1241,7 @@ efBuildConnect(def, nodeName1, nodeName2, deltaC, av, ac)
|
|||
int n;
|
||||
Connection *conn;
|
||||
unsigned size = sizeof (Connection)
|
||||
+ (efNumResistClasses - 1) * sizeof (PerimArea);
|
||||
+ (efNumResistClasses - 1) * sizeof (EFPerimArea);
|
||||
|
||||
conn = (Connection *) mallocMagic((unsigned)(size));
|
||||
|
||||
|
|
@ -1178,8 +1251,9 @@ efBuildConnect(def, nodeName1, nodeName2, deltaC, av, ac)
|
|||
conn->conn_next = def->def_conns;
|
||||
for (n = 0; n < efNumResistClasses && ac > 1; n++, ac -= 2)
|
||||
{
|
||||
conn->conn_pa[n].pa_area = atoi(*av++);
|
||||
conn->conn_pa[n].pa_perim = atoi(*av++);
|
||||
conn->conn_pa[n].pa_area = (int)(0.5 + (float)atoi(*av++)
|
||||
* locScale * locScale);
|
||||
conn->conn_pa[n].pa_perim = (int)(0.5 + (float)atoi(*av++) * locScale);
|
||||
}
|
||||
for ( ; n < efNumResistClasses; n++)
|
||||
conn->conn_pa[n].pa_area = conn->conn_pa[n].pa_perim = 0;
|
||||
|
|
@ -1211,14 +1285,14 @@ efBuildResistor(def, nodeName1, nodeName2, resistance)
|
|||
Def *def; /* Def to which this connection is to be added */
|
||||
char *nodeName1; /* Name of first node in resistor */
|
||||
char *nodeName2; /* Name of second node in resistor */
|
||||
float resistance; /* Resistor value */
|
||||
int resistance; /* Resistor value */
|
||||
{
|
||||
Connection *conn;
|
||||
|
||||
conn = (Connection *) mallocMagic((unsigned)(sizeof (Connection)));
|
||||
if (efConnInitSubs(conn, nodeName1, nodeName2))
|
||||
{
|
||||
conn->conn_res = resistance;
|
||||
conn->conn_res = (float)resistance;
|
||||
conn->conn_next = def->def_resistors;
|
||||
def->def_resistors = conn;
|
||||
}
|
||||
|
|
@ -1682,6 +1756,36 @@ efFreeUseTable(table)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* efFreeDevTable --
|
||||
*
|
||||
* Free the device records allocated for each entry in the device hash table,
|
||||
* the memory allocated by the device, leaving the hash entry null.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
efFreeDevTable(table)
|
||||
HashTable *table;
|
||||
{
|
||||
Dev *dev;
|
||||
HashSearch hs;
|
||||
HashEntry *he;
|
||||
int n;
|
||||
|
||||
HashStartSearch(&hs);
|
||||
while (he = HashNext(table, &hs))
|
||||
{
|
||||
dev = (Dev *)HashGetValue(he);
|
||||
for (n = 0; n < (int)dev->dev_nterm; n++)
|
||||
if (dev->dev_terms[n].dterm_attrs)
|
||||
freeMagic((char *) dev->dev_terms[n].dterm_attrs);
|
||||
freeMagic((char *) dev);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -103,7 +103,6 @@ EFDone()
|
|||
Kill *kill;
|
||||
Def *def;
|
||||
Use *use;
|
||||
Dev *dev;
|
||||
int n;
|
||||
|
||||
HashStartSearch(&hs);
|
||||
|
|
@ -114,22 +113,18 @@ EFDone()
|
|||
efFreeNodeTable(&def->def_nodes);
|
||||
efFreeNodeList(&def->def_firstn);
|
||||
efFreeUseTable(&def->def_uses);
|
||||
efFreeDevTable(&def->def_devs);
|
||||
HashKill(&def->def_nodes);
|
||||
HashKill(&def->def_dists);
|
||||
HashKill(&def->def_uses);
|
||||
HashKill(&def->def_devs);
|
||||
for (conn = def->def_conns; conn; conn = conn->conn_next)
|
||||
efFreeConn(conn);
|
||||
for (conn = def->def_caps; conn; conn = conn->conn_next)
|
||||
efFreeConn(conn);
|
||||
for (conn = def->def_resistors; conn; conn = conn->conn_next)
|
||||
efFreeConn(conn);
|
||||
for (dev = def->def_devs; dev; dev = dev->dev_next)
|
||||
{
|
||||
for (n = 0; n < (int)dev->dev_nterm; n++)
|
||||
if (dev->dev_terms[n].dterm_attrs)
|
||||
freeMagic((char *) dev->dev_terms[n].dterm_attrs);
|
||||
freeMagic((char *) dev);
|
||||
}
|
||||
|
||||
for (kill = def->def_kills; kill; kill = kill->kill_next)
|
||||
{
|
||||
freeMagic(kill->kill_name);
|
||||
|
|
@ -151,13 +146,6 @@ EFDone()
|
|||
EFTech = (char *)NULL;
|
||||
}
|
||||
|
||||
/* Free up all HierNames that were stored in efFreeHashTable */
|
||||
/*
|
||||
HashStartSearch(&hs);
|
||||
while (he = HashNext(&efFreeHashTable, &hs))
|
||||
freeMagic(he->h_key.h_ptr);
|
||||
*/
|
||||
|
||||
/* Free up the parameter name tables for each device */
|
||||
|
||||
HashStartSearch(&hs);
|
||||
|
|
@ -244,7 +232,6 @@ efDefNew(name)
|
|||
newdef->def_conns = (Connection *) NULL;
|
||||
newdef->def_caps = (Connection *) NULL;
|
||||
newdef->def_resistors = (Connection *) NULL;
|
||||
newdef->def_devs = (Dev *) NULL;
|
||||
newdef->def_kills = (Kill *) NULL;
|
||||
|
||||
/* Initialize circular list of nodes */
|
||||
|
|
@ -257,6 +244,9 @@ efDefNew(name)
|
|||
/* Initialize hash table of node names */
|
||||
HashInit(&newdef->def_nodes, INITNODESIZE, HT_STRINGKEYS);
|
||||
|
||||
/* Initialize hash table of devices */
|
||||
HashInit(&newdef->def_devs, INITNODESIZE, HT_STRINGKEYS);
|
||||
|
||||
/* Initialize hash table of distances */
|
||||
HashInitClient(&newdef->def_dists, INITNODESIZE, HT_CLIENTKEYS,
|
||||
efHNDistCompare, efHNDistCopy, efHNDistHash, efHNDistKill);
|
||||
|
|
|
|||
|
|
@ -59,7 +59,8 @@ bool efFlatGlobCmp(HierName *, HierName *);
|
|||
char *efFlatGlobCopy(HierName *);
|
||||
void efFlatGlobError(EFNodeName *, EFNodeName *);
|
||||
int efAddNodes(HierContext *, bool);
|
||||
int efAddOneConn(HierContext *, char *, char *, Connection *);
|
||||
int efAddConns(HierContext *, bool);
|
||||
int efAddOneConn(HierContext *, char *, char *, Connection *, bool);
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -126,7 +127,7 @@ EFFlatBuild(name, flags)
|
|||
if (flags & EF_NOFLATSUBCKT)
|
||||
efFlatNodesStdCell(&efFlatContext);
|
||||
else
|
||||
efFlatNodes(&efFlatContext);
|
||||
efFlatNodes(&efFlatContext, FALSE, TRUE);
|
||||
efFlatKills(&efFlatContext);
|
||||
if (!(flags & EF_NONAMEMERGE))
|
||||
efFlatGlob();
|
||||
|
|
@ -193,8 +194,8 @@ EFFlatBuildOneLevel(def, flags)
|
|||
efFlatContext.hc_x = efFlatContext.hc_y = 0;
|
||||
efFlatRootUse.use_def = efFlatRootDef;
|
||||
|
||||
/* Record all nodes of the next level in the hierarchy */
|
||||
efHierSrUses(&efFlatContext, efAddNodes, (ClientData)TRUE);
|
||||
/* Record all nodes down the hierarchy from here */
|
||||
efFlatNodes(&efFlatContext, (ClientData)TRUE, (ClientData)FALSE);
|
||||
|
||||
/* Expand all subcells that contain connectivity information but */
|
||||
/* no active devices (including those in subcells). */
|
||||
|
|
@ -205,12 +206,12 @@ EFFlatBuildOneLevel(def, flags)
|
|||
if (usecount > 0)
|
||||
efHierSrUses(&efFlatContext, efFlatNodesDeviceless, (ClientData)&usecount);
|
||||
|
||||
if ((usecount == 0) && (efFlatRootUse.use_def->def_devs == NULL))
|
||||
if ((usecount == 0) && (HashGetNumEntries(&efFlatRootUse.use_def->def_devs) == 0))
|
||||
efFlatRootUse.use_def->def_flags |= DEF_NODEVICES;
|
||||
|
||||
/* Record all local nodes */
|
||||
efAddNodes(&efFlatContext, FALSE);
|
||||
efAddConns(&efFlatContext);
|
||||
efAddConns(&efFlatContext, TRUE);
|
||||
|
||||
efFlatKills(&efFlatContext);
|
||||
if (!(flags & EF_NONAMEMERGE))
|
||||
|
|
@ -291,16 +292,16 @@ EFFlatDone()
|
|||
*/
|
||||
|
||||
int
|
||||
efFlatNodes(hc)
|
||||
efFlatNodes(hc, stdcell, doWarn)
|
||||
HierContext *hc;
|
||||
{
|
||||
(void) efHierSrUses(hc, efFlatNodes);
|
||||
|
||||
/* Add all our own nodes to the table */
|
||||
efAddNodes(hc, FALSE);
|
||||
efAddNodes(hc, stdcell);
|
||||
|
||||
/* Process our own connections and adjustments */
|
||||
(void) efAddConns(hc);
|
||||
(void) efAddConns(hc, doWarn);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -352,7 +353,7 @@ efFlatNodesStdCell(hc)
|
|||
|
||||
/* Process our own connections and adjustments */
|
||||
if (!(hc->hc_use->use_def->def_flags & DEF_SUBCIRCUIT))
|
||||
(void) efAddConns(hc);
|
||||
(void) efAddConns(hc, TRUE);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -372,13 +373,13 @@ efFlatNodesDeviceless(hc, cdata)
|
|||
if (newcount > 0)
|
||||
efHierSrUses(hc, efFlatNodesDeviceless, (ClientData)&newcount);
|
||||
|
||||
if ((hc->hc_use->use_def->def_devs == NULL) && (newcount == 0))
|
||||
if ((HashGetNumEntries(&hc->hc_use->use_def->def_devs) == 0) && (newcount == 0))
|
||||
{
|
||||
/* Add all our own nodes to the table */
|
||||
efAddNodes(hc, TRUE);
|
||||
|
||||
/* Process our own connections and adjustments */
|
||||
efAddConns(hc);
|
||||
efAddConns(hc, TRUE);
|
||||
|
||||
/* Mark this definition as having no devices, so it will not be visited */
|
||||
hc->hc_use->use_def->def_flags |= DEF_NODEVICES;
|
||||
|
|
@ -430,7 +431,7 @@ efAddNodes(hc, stdcell)
|
|||
bool is_subcircuit = (def->def_flags & DEF_SUBCIRCUIT) ? TRUE : FALSE;
|
||||
|
||||
scale = def->def_scale;
|
||||
size = sizeof (EFNode) + (efNumResistClasses-1) * sizeof (PerimArea);
|
||||
size = sizeof (EFNode) + (efNumResistClasses-1) * sizeof (EFPerimArea);
|
||||
|
||||
for (node = (EFNode *) def->def_firstn.efnode_next;
|
||||
node != &def->def_firstn;
|
||||
|
|
@ -467,10 +468,10 @@ efAddNodes(hc, stdcell)
|
|||
newnode->efnode_type = node->efnode_type;
|
||||
if (!stdcell)
|
||||
bcopy((char *) node->efnode_pa, (char *) newnode->efnode_pa,
|
||||
efNumResistClasses * sizeof (PerimArea));
|
||||
efNumResistClasses * sizeof (EFPerimArea));
|
||||
else
|
||||
bzero((char *) newnode->efnode_pa,
|
||||
efNumResistClasses * sizeof (PerimArea));
|
||||
efNumResistClasses * sizeof (EFPerimArea));
|
||||
GeoTransRect(&hc->hc_trans, &node->efnode_loc, &newnode->efnode_loc);
|
||||
|
||||
/* Scale the result by "scale" --- hopefully we end up with an integer */
|
||||
|
|
@ -527,6 +528,7 @@ efAddNodes(hc, stdcell)
|
|||
HashSetValue(he, (char *) newname);
|
||||
newname->efnn_node = newnode;
|
||||
newname->efnn_hier = hierName;
|
||||
newname->efnn_port = -1;
|
||||
if (newnode->efnode_name)
|
||||
{
|
||||
newname->efnn_next = newnode->efnode_name->efnn_next;
|
||||
|
|
@ -561,8 +563,9 @@ efAddNodes(hc, stdcell)
|
|||
*/
|
||||
|
||||
int
|
||||
efAddConns(hc)
|
||||
efAddConns(hc, doWarn)
|
||||
HierContext *hc;
|
||||
bool doWarn;
|
||||
{
|
||||
Connection *conn;
|
||||
|
||||
|
|
@ -575,9 +578,9 @@ efAddConns(hc)
|
|||
{
|
||||
/* Special case for speed when no array info is present */
|
||||
if (conn->conn_1.cn_nsubs == 0)
|
||||
efAddOneConn(hc, conn->conn_name1, conn->conn_name2, conn);
|
||||
efAddOneConn(hc, conn->conn_name1, conn->conn_name2, conn, doWarn);
|
||||
else
|
||||
efHierSrArray(hc, conn, efAddOneConn, (ClientData) NULL);
|
||||
efHierSrArray(hc, conn, efAddOneConn, (ClientData)doWarn);
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
|
@ -604,16 +607,17 @@ efAddConns(hc)
|
|||
*/
|
||||
|
||||
int
|
||||
efAddOneConn(hc, name1, name2, conn)
|
||||
efAddOneConn(hc, name1, name2, conn, doWarn)
|
||||
HierContext *hc;
|
||||
char *name1, *name2; /* These are strings, not HierNames */
|
||||
Connection *conn;
|
||||
bool doWarn;
|
||||
{
|
||||
HashEntry *he1, *he2;
|
||||
EFNode *node, *newnode;
|
||||
int n;
|
||||
|
||||
he1 = EFHNLook(hc->hc_hierName, name1, "connect(1)");
|
||||
he1 = EFHNLook(hc->hc_hierName, name1, (doWarn) ? "connect(1)" : NULL);
|
||||
if (he1 == NULL)
|
||||
return 0;
|
||||
|
||||
|
|
@ -629,7 +633,7 @@ efAddOneConn(hc, name1, name2, conn)
|
|||
/* Merge this node with conn_name2 if one was specified */
|
||||
if (name2)
|
||||
{
|
||||
he2 = EFHNLook(hc->hc_hierName, name2, "connect(2)");
|
||||
he2 = EFHNLook(hc->hc_hierName, name2, (doWarn) ? "connect(2)" : NULL);
|
||||
if (he2 == NULL)
|
||||
return 0;
|
||||
newnode = ((EFNodeName *) HashGetValue(he2))->efnn_node;
|
||||
|
|
@ -1018,14 +1022,23 @@ efFlatSingleCap(hc, name1, name2, conn)
|
|||
EFNode *n1, *n2;
|
||||
HashEntry *he;
|
||||
EFCoupleKey ck;
|
||||
static char msg0[] = "cap(1)";
|
||||
static char msg1[] = "cap(2)";
|
||||
char *msg;
|
||||
|
||||
/* Connections that are below threshold (ext2spice hierarchy only) */
|
||||
/* will be missing. Do not generate errors for these. */
|
||||
|
||||
if ((he = EFHNLook(hc->hc_hierName, name1, "cap(1)")) == NULL)
|
||||
msg = (fabs((double)conn->conn_cap / 1000) < EFCapThreshold) ? NULL : msg0;
|
||||
|
||||
if ((he = EFHNLook(hc->hc_hierName, name1, msg)) == NULL)
|
||||
return 0;
|
||||
n1 = ((EFNodeName *) HashGetValue(he))->efnn_node;
|
||||
if (n1->efnode_flags & EF_KILLED)
|
||||
return 0;
|
||||
|
||||
if ((he = EFHNLook(hc->hc_hierName, name2, "cap(2)")) == NULL)
|
||||
if (msg) msg = msg1;
|
||||
if ((he = EFHNLook(hc->hc_hierName, name2, msg)) == NULL)
|
||||
return 0;
|
||||
n2 = ((EFNodeName *) HashGetValue(he))->efnn_node;
|
||||
if (n2->efnode_flags & EF_KILLED)
|
||||
|
|
|
|||
|
|
@ -471,6 +471,8 @@ efHierVisitDevs(hc, ca)
|
|||
{
|
||||
Def *def = hc->hc_use->use_def;
|
||||
Dev *dev;
|
||||
HashSearch hs;
|
||||
HashEntry *he;
|
||||
float scale;
|
||||
|
||||
/*
|
||||
|
|
@ -482,8 +484,10 @@ efHierVisitDevs(hc, ca)
|
|||
scale = (efScaleChanged && def->def_scale != 1.0) ? def->def_scale : 1.0;
|
||||
|
||||
/* Visit all devices */
|
||||
for (dev = def->def_devs; dev; dev = dev->dev_next)
|
||||
HashStartSearch(&hs);
|
||||
while (he = HashNext(&def->def_devs, &hs))
|
||||
{
|
||||
dev = (Dev *)HashGetValue(he);
|
||||
if (efHierDevKilled(hc, dev, hc->hc_hierName))
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ typedef struct conn
|
|||
} conn_value;
|
||||
|
||||
struct conn *conn_next; /* Next connection in list */
|
||||
PerimArea conn_pa[1]; /* Dummy; each connection actually has
|
||||
EFPerimArea conn_pa[1]; /* Dummy; each connection actually has
|
||||
* efNumResistClasses array elements
|
||||
* allocated to it.
|
||||
*/
|
||||
|
|
@ -156,6 +156,7 @@ typedef struct def
|
|||
HashTable def_nodes; /* Map names into EFNodeNames */
|
||||
HashTable def_dists; /* Map pairs of names into Distances */
|
||||
HashTable def_uses; /* Hash children of this def by name */
|
||||
HashTable def_devs; /* Devices (hash by position) */
|
||||
EFNode def_firstn; /* Head of circular list of nodes */
|
||||
|
||||
/* The following are all NULL-terminated lists */
|
||||
|
|
@ -163,7 +164,6 @@ typedef struct def
|
|||
Connection *def_conns; /* Hierarchical connections/adjustments */
|
||||
Connection *def_caps; /* Two-terminal capacitors */
|
||||
Connection *def_resistors; /* Two-terminal resistors */
|
||||
Dev *def_devs; /* Devices */
|
||||
Kill *def_kills; /* Used to modify hierarchical structure
|
||||
* using information present only in the
|
||||
* parent, e.g, to kill an old node and
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "extflat/extflat.h"
|
||||
#include "extflat/EFint.h"
|
||||
#include "extract/extract.h"
|
||||
#include "extract/extractInt.h"
|
||||
#include "utils/paths.h"
|
||||
|
||||
#ifndef MAGIC_WRAPPER
|
||||
|
|
@ -96,6 +97,7 @@ keyTable[] =
|
|||
/* Data shared with EFerror.c */
|
||||
char *efReadFileName; /* Name of file currently being read */
|
||||
int efReadLineNum; /* Current line number in above file */
|
||||
float locScale; /* Multiply values in the file by this on read-in */
|
||||
|
||||
/* Data local to this file */
|
||||
static bool efReadDef();
|
||||
|
|
@ -139,6 +141,7 @@ EFReadFile(name, dosubckt, resist, noscale)
|
|||
if (def == NULL)
|
||||
def = efDefNew(name);
|
||||
|
||||
locScale = 1.0;
|
||||
rc = efReadDef(def, dosubckt, resist, noscale, TRUE);
|
||||
if (EFArgTech) EFTech = StrDup((char **) NULL, EFArgTech);
|
||||
if (EFScale == 0.0) EFScale = 1.0;
|
||||
|
|
@ -265,6 +268,11 @@ readfile:
|
|||
cscale = 1;
|
||||
}
|
||||
lscale = (float)atof(argv[3]);
|
||||
if (lscale != ExtCurStyle->exts_unitsPerLambda)
|
||||
{
|
||||
locScale = lscale / ExtCurStyle->exts_unitsPerLambda;
|
||||
lscale = ExtCurStyle->exts_unitsPerLambda;
|
||||
}
|
||||
if (lscale == 0.0)
|
||||
{
|
||||
efReadError("Bad linear scaling = 0; reset to 1.\n");
|
||||
|
|
@ -283,10 +291,10 @@ readfile:
|
|||
|
||||
/* attr node xlo ylo xhi yhi type text */
|
||||
case ATTR:
|
||||
r.r_xbot = atoi(argv[2]);
|
||||
r.r_ybot = atoi(argv[3]);
|
||||
r.r_xtop = atoi(argv[4]);
|
||||
r.r_ytop = atoi(argv[5]),
|
||||
r.r_xbot = (int)(0.5 + (float)atoi(argv[2]) * locScale);
|
||||
r.r_ybot = (int)(0.5 + (float)atoi(argv[3]) * locScale);
|
||||
r.r_xtop = (int)(0.5 + (float)atoi(argv[4]) * locScale);
|
||||
r.r_ytop = (int)(0.5 + (float)atoi(argv[5]) * locScale),
|
||||
efBuildAttr(def, argv[1], &r, argv[6], argv[7]);
|
||||
break;
|
||||
|
||||
|
|
@ -351,13 +359,12 @@ readfile:
|
|||
break; /* we will deal with in efBuildDevice(). */
|
||||
}
|
||||
|
||||
r.r_xbot = atoi(argv[3]);
|
||||
r.r_ybot = atoi(argv[4]);
|
||||
r.r_xtop = atoi(argv[5]);
|
||||
r.r_ytop = atoi(argv[6]);
|
||||
r.r_xbot = (int)(0.5 + (float)atoi(argv[3]) * locScale);
|
||||
r.r_ybot = (int)(0.5 + (float)atoi(argv[4]) * locScale);
|
||||
r.r_xtop = (int)(0.5 + (float)atoi(argv[5]) * locScale);
|
||||
r.r_ytop = (int)(0.5 + (float)atoi(argv[6]) * locScale);
|
||||
|
||||
if (efBuildDevice(def, (char)n, argv[2], &r, argc - 7,
|
||||
&argv[7]) != 0)
|
||||
if (efBuildDevice(def, (char)n, argv[2], &r, argc - 7, &argv[7]) != 0)
|
||||
{
|
||||
efReadError("Incomplete terminal description for device\n");
|
||||
continue;
|
||||
|
|
@ -367,10 +374,10 @@ readfile:
|
|||
/* for backwards compatibility */
|
||||
/* fet type xlo ylo xhi yhi area perim substrate GATE T1 T2 ... */
|
||||
case FET:
|
||||
r.r_xbot = atoi(argv[2]);
|
||||
r.r_ybot = atoi(argv[3]);
|
||||
r.r_xtop = atoi(argv[4]);
|
||||
r.r_ytop = atoi(argv[5]);
|
||||
r.r_xbot = (int)(0.5 + (float)atoi(argv[2]) * locScale);
|
||||
r.r_ybot = (int)(0.5 + (float)atoi(argv[3]) * locScale);
|
||||
r.r_xtop = (int)(0.5 + (float)atoi(argv[4]) * locScale);
|
||||
r.r_ytop = (int)(0.5 + (float)atoi(argv[5]) * locScale);
|
||||
if (efBuildDevice(def, DEV_FET, argv[1], &r, argc - 6, &argv[6]) != 0)
|
||||
{
|
||||
efReadError("Incomplete terminal description for fet\n");
|
||||
|
|
@ -426,10 +433,8 @@ readfile:
|
|||
/* port name num xl yl xh yh type */
|
||||
case PORT:
|
||||
if (DoSubCircuit)
|
||||
{
|
||||
DoResist = FALSE;
|
||||
def->def_flags |= DEF_SUBCIRCUIT;
|
||||
}
|
||||
|
||||
efBuildPortNode(def, argv[1], atoi(argv[2]), atoi(argv[3]),
|
||||
atoi(argv[4]), argv[7], toplevel);
|
||||
break;
|
||||
|
|
@ -566,8 +571,8 @@ resistChanged:
|
|||
/* distance driver receiver min max */
|
||||
case DIST:
|
||||
efBuildDist(def, argv[1], argv[2],
|
||||
(int)(lscale*atoi(argv[3])),
|
||||
(int)(lscale*atoi(argv[4])));
|
||||
(int)(lscale*atoi(argv[3])*locScale),
|
||||
(int)(lscale*atoi(argv[4])*locScale));
|
||||
break;
|
||||
|
||||
/* killnode nodename */
|
||||
|
|
@ -576,8 +581,12 @@ resistChanged:
|
|||
break;
|
||||
|
||||
/* resistor node1 node2 resistance */
|
||||
/* NOTE: Value changed to floating-point 12/16/2019; */
|
||||
/* (value * rscale) is in milliohms which is integer as */
|
||||
/* resolution finer than milliohms is deemed unnecessary. */
|
||||
case RESISTOR:
|
||||
efBuildResistor(def, argv[1], argv[2], rscale*atoi(argv[3]));
|
||||
efBuildResistor(def, argv[1], argv[2],
|
||||
(int)(0.5 + (double)rscale * atof(argv[3])));
|
||||
break;
|
||||
|
||||
/* abstract (no options/arguments) */
|
||||
|
|
@ -719,11 +728,15 @@ start:
|
|||
}
|
||||
}
|
||||
|
||||
if (*get == '\\') /* Process quoted characters literally */
|
||||
{
|
||||
get++;
|
||||
if (*get == '\0') break;
|
||||
}
|
||||
/* Process backslash characters literally unless they */
|
||||
/* are followed by the end-of-line. */
|
||||
|
||||
if (*get == '\\')
|
||||
if (*(get + 1) == '\0')
|
||||
{
|
||||
get++;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Copy into token receiving area */
|
||||
*put++ = *get++;
|
||||
|
|
|
|||
|
|
@ -300,6 +300,8 @@ efVisitDevs(hc, ca)
|
|||
Dev *dev;
|
||||
float scale;
|
||||
Transform t;
|
||||
HashSearch hs;
|
||||
HashEntry *he;
|
||||
|
||||
if (def->def_flags & DEF_SUBCIRCUIT) return 0;
|
||||
|
||||
|
|
@ -311,15 +313,17 @@ efVisitDevs(hc, ca)
|
|||
t = hc->hc_trans;
|
||||
|
||||
/* Visit our own devices */
|
||||
for (dev = def->def_devs; dev; dev = dev->dev_next)
|
||||
|
||||
HashStartSearch(&hs);
|
||||
while (he = HashNext(&def->def_devs, &hs))
|
||||
{
|
||||
dev = (Dev *)HashGetValue(he);
|
||||
if (efDevKilled(dev, hc->hc_hierName))
|
||||
continue;
|
||||
|
||||
if ((*ca->ca_proc)(dev, hc->hc_hierName, scale, &t, ca->ca_cdata))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -859,7 +863,7 @@ EFHNOut(hierName, outf)
|
|||
HierName *hierName;
|
||||
FILE *outf;
|
||||
{
|
||||
bool trimGlob, trimLocal, trimComma;
|
||||
bool trimGlob, trimLocal, convComma, convBrackets;
|
||||
char *cp, c;
|
||||
|
||||
if (hierName->hn_parent) efHNOutPrefix(hierName->hn_parent, outf);
|
||||
|
|
@ -868,13 +872,19 @@ EFHNOut(hierName, outf)
|
|||
cp = hierName->hn_name;
|
||||
trimGlob = (EFTrimFlags & EF_TRIMGLOB);
|
||||
trimLocal = (EFTrimFlags & EF_TRIMLOCAL);
|
||||
trimComma = (EFTrimFlags & EF_CONVERTCOMMAS);
|
||||
convComma = (EFTrimFlags & EF_CONVERTCOMMA);
|
||||
convBrackets = (EFTrimFlags & EF_CONVERTBRACKETS);
|
||||
while (c = *cp++)
|
||||
{
|
||||
if (*cp)
|
||||
{
|
||||
if (trimComma && (c == ','))
|
||||
putc(';', outf);
|
||||
if (c == ',')
|
||||
{
|
||||
if (convComma)
|
||||
putc('|', outf);
|
||||
}
|
||||
else if (convBrackets && ((c == '[') || (c == ']')))
|
||||
putc('_', outf);
|
||||
else
|
||||
putc(c, outf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
MODULE = extflat
|
||||
MAGICDIR = ..
|
||||
SRCS = EFargs.c EFbuild.c EFdef.c EFerr.c EFflat.c EFhier.c EFname.c \
|
||||
EFread.c EFsym.c EFvisit.c
|
||||
EFread.c EFsym.c EFvisit.c EFantenna.c
|
||||
|
||||
include ${MAGICDIR}/defs.mak
|
||||
include ${MAGICDIR}/rules.mak
|
||||
|
|
|
|||
|
|
@ -40,8 +40,9 @@ typedef unsigned char U_char;
|
|||
/* Flags to control output of node names. Stored in EFTrimFlags */
|
||||
#define EF_TRIMGLOB 0x01 /* Delete trailing '!' from names */
|
||||
#define EF_TRIMLOCAL 0x02 /* Delete trailing '#' from names */
|
||||
#define EF_CONVERTCOMMAS 0x04 /* Change ',' to ';' in names */
|
||||
#define EF_CONVERTEQUAL 0x08 /* Change '=' to ':' in names */
|
||||
#define EF_CONVERTCOMMA 0x04 /* Change ',' to '|' in names, else remove */
|
||||
#define EF_CONVERTEQUAL 0x08 /* Change '=' to ':' in names, else remove */
|
||||
#define EF_CONVERTBRACKETS 0x10 /* Change '[' and ']' to '_' in names */
|
||||
|
||||
/*
|
||||
* capacitance type now set to float
|
||||
|
|
@ -141,7 +142,7 @@ typedef struct
|
|||
{
|
||||
int pa_area;
|
||||
int pa_perim;
|
||||
} PerimArea;
|
||||
} EFPerimArea;
|
||||
|
||||
typedef struct efnhdr
|
||||
{
|
||||
|
|
@ -218,7 +219,7 @@ typedef struct efnode
|
|||
*/
|
||||
EFAttr *efnode_attrs; /* Node attribute list */
|
||||
ClientData efnode_client; /* For hire */
|
||||
PerimArea efnode_pa[1]; /* Dummy; each node actually has
|
||||
EFPerimArea efnode_pa[1]; /* Dummy; each node actually has
|
||||
* efNumResistClasses array elements
|
||||
* allocated to it.
|
||||
*/
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -424,7 +424,10 @@ extTreeSrPaintArea(scx, func, cdarg)
|
|||
int pNum;
|
||||
|
||||
if ((def->cd_flags & CDAVAILABLE) == 0)
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, NULL)) return 0;
|
||||
{
|
||||
bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, dereference, NULL)) return 0;
|
||||
}
|
||||
|
||||
filter.tf_func = func;
|
||||
filter.tf_arg = cdarg;
|
||||
|
|
@ -461,7 +464,10 @@ extTreeSrFunc(scx, fp)
|
|||
int pNum;
|
||||
|
||||
if ((def->cd_flags & CDAVAILABLE) == 0)
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, NULL)) return (0);
|
||||
{
|
||||
bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, dereference, NULL)) return (0);
|
||||
}
|
||||
|
||||
context.tc_scx = scx;
|
||||
context.tc_filter = fp;
|
||||
|
|
@ -480,3 +486,176 @@ extTreeSrFunc(scx, fp)
|
|||
return (DBCellSrArea(scx, extTreeSrFunc, (ClientData) fp));
|
||||
}
|
||||
|
||||
int
|
||||
extCellSrArea(scx, func, cdarg)
|
||||
SearchContext *scx;
|
||||
/* Pointer to search context specifying a cell use to
|
||||
* search, an area in the coordinates of the cell's
|
||||
* def, and a transform back to "root" coordinates.
|
||||
* The area may have zero size.
|
||||
*/
|
||||
int (*func)(); /* Function to apply at every tile found */
|
||||
ClientData cdarg; /* Argument to pass to function */
|
||||
{
|
||||
int xlo, xhi, ylo, yhi, xbase, ybase, xsep, ysep, clientResult;
|
||||
int srchBot, srchRight;
|
||||
Plane *plane = scx->scx_use->cu_def->cd_planes[PL_CELL];
|
||||
Tile *tp, *tpnew;
|
||||
Rect *rect, *bbox;
|
||||
CellUse *use;
|
||||
SearchContext newScx;
|
||||
CellTileBody *body;
|
||||
Transform t, tinv;
|
||||
TreeFilter filter;
|
||||
Rect expanded;
|
||||
Point start;
|
||||
|
||||
filter.tf_func = func;
|
||||
filter.tf_arg = cdarg;
|
||||
|
||||
if ((scx->scx_use->cu_def->cd_flags & CDAVAILABLE) == 0)
|
||||
{
|
||||
bool dereference = (scx->scx_use->cu_def->cd_flags & CDDEREFERENCE) ?
|
||||
TRUE : FALSE;
|
||||
if (!DBCellRead(scx->scx_use->cu_def, (char *) NULL, TRUE, dereference, NULL))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* In order to make this work with zero-size areas, we first expand
|
||||
* the area by before searching the tile plane. extCellSrFunc will
|
||||
* check carefully to throw out things that don't overlap the original
|
||||
* area. The expansion is tricky because we mustn't expand infinities.
|
||||
*/
|
||||
|
||||
expanded = scx->scx_area;
|
||||
if (expanded.r_xbot > TiPlaneRect.r_xbot) expanded.r_xbot -= 1;
|
||||
if (expanded.r_ybot > TiPlaneRect.r_ybot) expanded.r_ybot -= 1;
|
||||
if (expanded.r_xtop < TiPlaneRect.r_xtop) expanded.r_xtop += 1;
|
||||
if (expanded.r_ytop < TiPlaneRect.r_ytop) expanded.r_ytop += 1;
|
||||
rect = &expanded;
|
||||
|
||||
/* Start along the top of the LHS of the search area */
|
||||
start.p_x = rect->r_xbot;
|
||||
start.p_y = rect->r_ytop - 1;
|
||||
tp = plane->pl_hint;
|
||||
GOTOPOINT(tp, &start);
|
||||
|
||||
/* Each iteration visits another tile on the LHS of the search area */
|
||||
while (TOP(tp) > rect->r_ybot)
|
||||
{
|
||||
/* Each iteration enumerates another tile */
|
||||
enumerate:
|
||||
plane->pl_hint = tp;
|
||||
if (SigInterruptPending)
|
||||
return (1);
|
||||
|
||||
/*
|
||||
* Since subcells are allowed to overlap, a single tile body may
|
||||
* refer to many subcells and a single subcell may be referred to
|
||||
* by many tile bodies. To insure that each CellUse is enumerated
|
||||
* exactly once, the procedure given to DBCellSrArea is only applied
|
||||
* to a CellUse when its lower right corner is contained in the
|
||||
* tile to dbCellSrFunc (or otherwise at the last tile encountered
|
||||
* in the event the lower right corner of the CellUse is outside the
|
||||
* search rectangle).
|
||||
*/
|
||||
srchBot = scx->scx_area.r_ybot;
|
||||
srchRight = scx->scx_area.r_xtop;
|
||||
for (body = (CellTileBody *) TiGetBody(tp);
|
||||
body != NULL;
|
||||
body = body->ctb_next)
|
||||
{
|
||||
use = newScx.scx_use = body->ctb_use;
|
||||
ASSERT(use != (CellUse *) NULL, "dbCellSrFunc");
|
||||
|
||||
/*
|
||||
* The check below is to ensure that we only enumerate each
|
||||
* cell once, even though it appears in many different tiles
|
||||
* in the subcell plane.
|
||||
*/
|
||||
bbox = &use->cu_bbox;
|
||||
if ( (BOTTOM(tp) <= bbox->r_ybot ||
|
||||
(BOTTOM(tp) <= srchBot && bbox->r_ybot < srchBot))
|
||||
&& (RIGHT(tp) >= bbox->r_xtop ||
|
||||
(RIGHT(tp) >= srchRight && bbox->r_xtop >= srchRight)))
|
||||
{
|
||||
/*
|
||||
* Make sure that this cell really does overlap the
|
||||
* search area (it could be just touching because of
|
||||
* the expand-by-one in DBCellSrArea).
|
||||
*/
|
||||
if (!GEO_OVERLAP(&scx->scx_area, bbox)) continue;
|
||||
|
||||
/* If not an array element, it's much simpler */
|
||||
if (use->cu_xlo == use->cu_xhi && use->cu_ylo == use->cu_yhi)
|
||||
{
|
||||
newScx.scx_x = use->cu_xlo, newScx.scx_y = use->cu_yhi;
|
||||
if (SigInterruptPending) return 1;
|
||||
GEOINVERTTRANS(&use->cu_transform, &tinv);
|
||||
GEOTRANSTRANS(&use->cu_transform, &scx->scx_trans,
|
||||
&newScx.scx_trans);
|
||||
GEOTRANSRECT(&tinv, &scx->scx_area, &newScx.scx_area);
|
||||
if ((*func)(&newScx, filter.tf_arg) == 1)
|
||||
return 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* More than a single array element;
|
||||
* check to see which ones overlap our search area.
|
||||
*/
|
||||
DBArrayOverlap(use, &scx->scx_area, &xlo, &xhi, &ylo, &yhi);
|
||||
xsep = (use->cu_xlo > use->cu_xhi)
|
||||
? -use->cu_xsep : use->cu_xsep;
|
||||
ysep = (use->cu_ylo > use->cu_yhi)
|
||||
? -use->cu_ysep : use->cu_ysep;
|
||||
for (newScx.scx_y = ylo; newScx.scx_y<=yhi; newScx.scx_y++)
|
||||
for (newScx.scx_x = xlo; newScx.scx_x<=xhi; newScx.scx_x++)
|
||||
{
|
||||
if (SigInterruptPending) return 1;
|
||||
xbase = xsep * (newScx.scx_x - use->cu_xlo);
|
||||
ybase = ysep * (newScx.scx_y - use->cu_ylo);
|
||||
GEOTRANSTRANSLATE(xbase, ybase, &use->cu_transform, &t);
|
||||
GEOINVERTTRANS(&t, &tinv);
|
||||
GEOTRANSTRANS(&t, &scx->scx_trans, &newScx.scx_trans);
|
||||
GEOTRANSRECT(&tinv, &scx->scx_area, &newScx.scx_area);
|
||||
clientResult = (*func)(&newScx, filter.tf_arg);
|
||||
if (clientResult == 2) goto skipArray;
|
||||
else if (clientResult == 1) return 1;
|
||||
}
|
||||
}
|
||||
skipArray: continue;
|
||||
}
|
||||
|
||||
tpnew = TR(tp);
|
||||
if (LEFT(tpnew) < rect->r_xtop)
|
||||
{
|
||||
while (BOTTOM(tpnew) >= rect->r_ytop) tpnew = LB(tpnew);
|
||||
if (BOTTOM(tpnew) >= BOTTOM(tp) || BOTTOM(tp) <= rect->r_ybot)
|
||||
{
|
||||
tp = tpnew;
|
||||
goto enumerate;
|
||||
}
|
||||
}
|
||||
|
||||
/* Each iteration returns one tile further to the left */
|
||||
while (LEFT(tp) > rect->r_xbot)
|
||||
{
|
||||
if (BOTTOM(tp) <= rect->r_ybot)
|
||||
return (0);
|
||||
tpnew = LB(tp);
|
||||
tp = BL(tp);
|
||||
if (BOTTOM(tpnew) >= BOTTOM(tp) || BOTTOM(tp) <= rect->r_ybot)
|
||||
{
|
||||
tp = tpnew;
|
||||
goto enumerate;
|
||||
}
|
||||
}
|
||||
|
||||
/* At left edge -- walk down to next tile along the left edge */
|
||||
for (tp = LB(tp); RIGHT(tp) <= rect->r_xbot; tp = TR(tp))
|
||||
/* Nothing */;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ typedef enum
|
|||
AREAC, CONTACT, CSCALE,
|
||||
DEFAULTAREACAP, DEFAULTOVERLAP, DEFAULTPERIMETER, DEFAULTSIDEOVERLAP,
|
||||
DEFAULTSIDEWALL,
|
||||
DEVICE, FET, FETRESIST, HEIGHT, LAMBDA, OVERC,
|
||||
DEVICE, FET, FETRESIST, HEIGHT, ANTENNA, MODEL, TIEDOWN, LAMBDA, OVERC,
|
||||
PERIMC, PLANEORDER, NOPLANEORDER, RESIST, RSCALE, SIDEHALO, SIDEOVERLAP,
|
||||
SIDEWALL, STEP, STYLE, SUBSTRATE, UNITS, VARIANT
|
||||
} Key;
|
||||
|
|
@ -122,6 +122,15 @@ static keydesc keyTable[] = {
|
|||
"height", HEIGHT, 4, 4,
|
||||
"type height-above-subtrate thickness",
|
||||
|
||||
"antenna", ANTENNA, 4, 6,
|
||||
"type [calc-type] [antenna-ratio-proportional] antenna-ratio-const",
|
||||
|
||||
"model", MODEL, 2, 3,
|
||||
"partial-cumulative [area-sidewall]",
|
||||
|
||||
"tiedown", TIEDOWN, 2, 2,
|
||||
"types",
|
||||
|
||||
"lambda", LAMBDA, 2, 2,
|
||||
"units-per-lambda",
|
||||
|
||||
|
|
@ -157,7 +166,7 @@ static keydesc keyTable[] = {
|
|||
"style", STYLE, 2, 4,
|
||||
"stylename",
|
||||
|
||||
"substrate", SUBSTRATE, 3, 3,
|
||||
"substrate", SUBSTRATE, 3, 4,
|
||||
"types plane",
|
||||
|
||||
"units", UNITS, 2, 2,
|
||||
|
|
@ -298,37 +307,47 @@ ExtGetDevInfo(idx, devnameptr, sd_rclassptr, sub_rclassptr, subnameptr)
|
|||
TileType t;
|
||||
TileTypeBitMask *rmask, *tmask;
|
||||
int n, i = 0, j;
|
||||
bool repeat;
|
||||
bool repeat, found;
|
||||
ExtDevice *devptr;
|
||||
char *locdname;
|
||||
char **uniquenamelist = (char **)mallocMagic(DBNumTypes * sizeof(char *));
|
||||
|
||||
|
||||
found = FALSE;
|
||||
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
|
||||
{
|
||||
locdname = ExtCurStyle->exts_transName[t];
|
||||
if (locdname != NULL)
|
||||
for (devptr = ExtCurStyle->exts_device[t]; devptr; devptr = devptr->exts_next)
|
||||
{
|
||||
repeat = FALSE;
|
||||
for (j = 0; j < i; j++)
|
||||
if (!strcmp(uniquenamelist[j], locdname))
|
||||
{
|
||||
repeat = TRUE;
|
||||
break;
|
||||
}
|
||||
if (repeat == FALSE)
|
||||
locdname = devptr->exts_deviceName;
|
||||
if (locdname != NULL)
|
||||
{
|
||||
if (i == idx) break;
|
||||
uniquenamelist[i] = locdname;
|
||||
i++;
|
||||
repeat = FALSE;
|
||||
for (j = 0; j < i; j++)
|
||||
if (!strcmp(uniquenamelist[j], locdname))
|
||||
{
|
||||
repeat = TRUE;
|
||||
break;
|
||||
}
|
||||
if (repeat == FALSE)
|
||||
{
|
||||
if (i == idx)
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
uniquenamelist[i] = locdname;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found == TRUE) break;
|
||||
}
|
||||
if (t == DBNumTypes) return FALSE;
|
||||
if (devptr == NULL) return FALSE;
|
||||
|
||||
*devnameptr = locdname;
|
||||
*subnameptr = ExtCurStyle->exts_transSubstrateName[t];
|
||||
*subnameptr = devptr->exts_deviceSubstrateName;
|
||||
|
||||
tmask = &ExtCurStyle->exts_transSDTypes[t][0];
|
||||
tmask = &devptr->exts_deviceSDTypes[0];
|
||||
*sd_rclassptr = (short)(-1); /* NO_RESCLASS */
|
||||
|
||||
for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++)
|
||||
|
|
@ -341,7 +360,7 @@ ExtGetDevInfo(idx, devnameptr, sd_rclassptr, sub_rclassptr, subnameptr)
|
|||
}
|
||||
}
|
||||
|
||||
tmask = &ExtCurStyle->exts_transSubstrateTypes[t];
|
||||
tmask = &devptr->exts_deviceSubstrateTypes;
|
||||
*sub_rclassptr = (short)(-1); /* NO_RESCLASS */
|
||||
|
||||
for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++)
|
||||
|
|
@ -360,6 +379,35 @@ ExtGetDevInfo(idx, devnameptr, sd_rclassptr, sub_rclassptr, subnameptr)
|
|||
|
||||
#endif /* MAGIC_WRAPPER */
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* extGetDevType --
|
||||
*
|
||||
* Given an extraction model device name (devname), return the associated
|
||||
* magic tiletype for the device.
|
||||
*
|
||||
* Results:
|
||||
* Tile type that represents the device "devname" in the magic database.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
TileType
|
||||
extGetDevType(devname)
|
||||
char *devname;
|
||||
{
|
||||
TileType t;
|
||||
ExtDevice *devptr;
|
||||
|
||||
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
|
||||
for (devptr = ExtCurStyle->exts_device[t]; devptr; devptr = devptr->exts_next)
|
||||
if (!strcmp(devptr->exts_deviceName, devname))
|
||||
return t;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef THREE_D
|
||||
/*
|
||||
|
|
@ -538,23 +586,10 @@ extTechStyleAlloc()
|
|||
TileType r;
|
||||
|
||||
style = (ExtStyle *) mallocMagic(sizeof (ExtStyle));
|
||||
|
||||
/* Make sure that the memory for character strings is NULL, */
|
||||
/* because we want the Init section to free memory if it */
|
||||
/* has been previously allocated. */
|
||||
|
||||
for (r = 0; r < NT; r++)
|
||||
{
|
||||
style->exts_transSubstrateName[r] = (char *) NULL;
|
||||
style->exts_transName[r] = (char *) NULL;
|
||||
style->exts_transSDTypes[r] = (TileTypeBitMask *) NULL;
|
||||
style->exts_deviceParams[r] = (ParamList *) NULL;
|
||||
style->exts_deviceClass[r] = (char) 0;
|
||||
style->exts_transResist[r].ht_table = (HashEntry **) NULL;
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -575,7 +610,7 @@ extTechStyleInit(style)
|
|||
style->exts_status = TECH_NOT_LOADED;
|
||||
|
||||
style->exts_sidePlanes = style->exts_overlapPlanes = 0;
|
||||
TTMaskZero(&style->exts_transMask);
|
||||
TTMaskZero(&style->exts_deviceMask);
|
||||
style->exts_activeTypes = DBAllButSpaceAndDRCBits;
|
||||
|
||||
for (r = 0; r < NP; r++)
|
||||
|
|
@ -589,7 +624,7 @@ extTechStyleInit(style)
|
|||
{
|
||||
TTMaskZero(&style->exts_nodeConn[r]);
|
||||
TTMaskZero(&style->exts_resistConn[r]);
|
||||
TTMaskZero(&style->exts_transConn[r]);
|
||||
TTMaskZero(&style->exts_deviceConn[r]);
|
||||
style->exts_allConn[r] = DBAllTypeBits;
|
||||
|
||||
style->exts_sheetResist[r] = 0;
|
||||
|
|
@ -620,43 +655,41 @@ extTechStyleInit(style)
|
|||
#ifdef ARIEL
|
||||
TTMaskZero(&style->exts_subsTransistorTypes[r]);
|
||||
#endif
|
||||
if (style->exts_transSDTypes[r] != NULL)
|
||||
freeMagic(style->exts_transSDTypes[r]);
|
||||
style->exts_transSDTypes[r] = NULL;
|
||||
style->exts_transSDCount[r] = 0;
|
||||
style->exts_transGateCap[r] = (CapValue) 0;
|
||||
style->exts_transSDCap[r] = (CapValue) 0;
|
||||
if (style->exts_transSubstrateName[r] != (char *) NULL)
|
||||
if (style->exts_device[r] != NULL)
|
||||
{
|
||||
freeMagic(style->exts_transSubstrateName[r]);
|
||||
style->exts_transSubstrateName[r] = (char *) NULL;
|
||||
}
|
||||
if (style->exts_transName[r] != (char *) NULL)
|
||||
{
|
||||
freeMagic(style->exts_transName[r]);
|
||||
style->exts_transName[r] = (char *) NULL;
|
||||
}
|
||||
while (style->exts_deviceParams[r] != (ParamList *) NULL)
|
||||
{
|
||||
/* Parameter lists are shared. Only free the last one! */
|
||||
ExtDevice *devptr;
|
||||
for (devptr = style->exts_device[r]; devptr; devptr = devptr->exts_next)
|
||||
{
|
||||
|
||||
if (style->exts_deviceParams[r]->pl_count > 1)
|
||||
{
|
||||
style->exts_deviceParams[r]->pl_count--;
|
||||
style->exts_deviceParams[r] = (ParamList *)NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
freeMagic(style->exts_deviceParams[r]->pl_name);
|
||||
freeMagic(style->exts_deviceParams[r]);
|
||||
style->exts_deviceParams[r] = style->exts_deviceParams[r]->pl_next;
|
||||
if (devptr->exts_deviceSDTypes != NULL)
|
||||
freeMagic(devptr->exts_deviceSDTypes);
|
||||
if (devptr->exts_deviceSubstrateName != (char *) NULL)
|
||||
freeMagic(devptr->exts_deviceSubstrateName);
|
||||
if (devptr->exts_deviceName != (char *) NULL)
|
||||
freeMagic(devptr->exts_deviceName);
|
||||
while (devptr->exts_deviceParams != (ParamList *) NULL)
|
||||
{
|
||||
/* Parameter lists are shared. Only free the last one! */
|
||||
|
||||
if (devptr->exts_deviceParams->pl_count > 1)
|
||||
{
|
||||
devptr->exts_deviceParams->pl_count--;
|
||||
devptr->exts_deviceParams = (ParamList *)NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
freeMagic(devptr->exts_deviceParams->pl_name);
|
||||
freeMagic(devptr->exts_deviceParams);
|
||||
devptr->exts_deviceParams = devptr->exts_deviceParams->pl_next;
|
||||
}
|
||||
}
|
||||
if (devptr->exts_deviceResist.ht_table != (HashEntry **) NULL)
|
||||
HashKill(&devptr->exts_deviceResist);
|
||||
|
||||
freeMagic(devptr);
|
||||
}
|
||||
style->exts_device[r] = (ExtDevice *)NULL;
|
||||
}
|
||||
style->exts_deviceClass[r] = (char)0;
|
||||
if (style->exts_transResist[r].ht_table != (HashEntry **) NULL)
|
||||
HashKill(&style->exts_transResist[r]);
|
||||
HashInit(&style->exts_transResist[r], 8, HT_STRINGKEYS);
|
||||
style->exts_linearResist[r] = 0;
|
||||
}
|
||||
|
||||
style->exts_sideCoupleHalo = 0;
|
||||
|
|
@ -667,14 +700,20 @@ extTechStyleInit(style)
|
|||
style->exts_numResistClasses = 0;
|
||||
|
||||
style->exts_planeOrderStatus = needPlaneOrder ;
|
||||
TTMaskZero(&style->exts_antennaTieTypes);
|
||||
|
||||
for (r = 0; r < DBNumTypes; r++)
|
||||
{
|
||||
style->exts_antennaRatio[r].areaType = (char)0;
|
||||
style->exts_antennaRatio[r].ratioGate = 0.0;
|
||||
style->exts_antennaRatio[r].ratioDiffA = 0.0;
|
||||
style->exts_antennaRatio[r].ratioDiffB = 0.0;
|
||||
style->exts_resistByResistClass[r] = 0;
|
||||
TTMaskZero(&style->exts_typesByResistClass[r]);
|
||||
style->exts_typesResistChanged[r] = DBAllButSpaceAndDRCBits;
|
||||
TTMaskSetType(&style->exts_typesResistChanged[r], TT_SPACE);
|
||||
style->exts_typeToResistClass[r] = -1;
|
||||
|
||||
}
|
||||
doConvert = FALSE;
|
||||
|
||||
|
|
@ -685,6 +724,7 @@ extTechStyleInit(style)
|
|||
|
||||
style->exts_globSubstratePlane = -1;
|
||||
TTMaskZero(&style->exts_globSubstrateTypes);
|
||||
TTMaskZero(&style->exts_globSubstrateShieldTypes);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -798,14 +838,6 @@ ExtTechInit()
|
|||
if (ExtCurStyle != NULL)
|
||||
{
|
||||
extTechStyleInit(ExtCurStyle);
|
||||
|
||||
/* Everything has been freed except the hash tables, which */
|
||||
/* were just reinitialized by extTechStyleInit(). */
|
||||
for (r = 0; r < NT; r++)
|
||||
{
|
||||
if (ExtCurStyle->exts_transResist[r].ht_table != (HashEntry **) NULL)
|
||||
HashKill(&ExtCurStyle->exts_transResist[r]);
|
||||
}
|
||||
ExtCurStyle = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1569,7 +1601,7 @@ ExtTechLine(sectionName, argc, argv)
|
|||
PlaneMask pshield, pov;
|
||||
CapValue capVal, gscap, gccap;
|
||||
TileTypeBitMask types1, types2, termtypes[MAXSD];
|
||||
TileTypeBitMask near, far, ov, shield, subsTypes;
|
||||
TileTypeBitMask near, far, ov, shield, subsTypes, idTypes;
|
||||
char *subsName, *transName, *cp, *endptr, *paramName;
|
||||
TileType s, t, r, o;
|
||||
keydesc *kp, *dv;
|
||||
|
|
@ -1578,6 +1610,7 @@ ExtTechLine(sectionName, argc, argv)
|
|||
EdgeCap *cnew;
|
||||
ExtKeep *es, *newStyle;
|
||||
ParamList *subcktParams, *newParam;
|
||||
ExtDevice *devptr;
|
||||
int refcnt;
|
||||
double dhalo;
|
||||
bool bad;
|
||||
|
|
@ -1796,6 +1829,8 @@ ExtTechLine(sectionName, argc, argv)
|
|||
case FET:
|
||||
case FETRESIST:
|
||||
case HEIGHT:
|
||||
case ANTENNA:
|
||||
case TIEDOWN:
|
||||
case OVERC:
|
||||
case PERIMC:
|
||||
case RESIST:
|
||||
|
|
@ -1888,24 +1923,32 @@ ExtTechLine(sectionName, argc, argv)
|
|||
gccap = (argc > 7) ? aToCap(argv[7]) : (CapValue) 0;
|
||||
}
|
||||
|
||||
TTMaskSetMask(&ExtCurStyle->exts_transMask, &types1);
|
||||
TTMaskSetMask(&ExtCurStyle->exts_deviceMask, &types1);
|
||||
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
|
||||
if (TTMaskHasType(&types1, t))
|
||||
{
|
||||
TTMaskSetMask(ExtCurStyle->exts_transConn+t,&types1);
|
||||
ExtCurStyle->exts_transSDTypes[t] = (TileTypeBitMask *)
|
||||
devptr = (ExtDevice *)mallocMagic(sizeof(ExtDevice));
|
||||
devptr->exts_deviceSDTypes = (TileTypeBitMask *)
|
||||
mallocMagic(2 * sizeof(TileTypeBitMask));
|
||||
ExtCurStyle->exts_transSDTypes[t][0] = termtypes[0];
|
||||
ExtCurStyle->exts_transSDTypes[t][1] = DBZeroTypeBits;
|
||||
ExtCurStyle->exts_transSDCount[t] = nterm;
|
||||
ExtCurStyle->exts_transSDCap[t] = gscap;
|
||||
ExtCurStyle->exts_transGateCap[t] = gccap;
|
||||
ExtCurStyle->exts_deviceClass[t] = DEV_FET;
|
||||
ExtCurStyle->exts_transName[t] =
|
||||
StrDup((char **) NULL, transName);
|
||||
ExtCurStyle->exts_transSubstrateName[t] =
|
||||
devptr->exts_deviceSDTypes[0] = termtypes[0];
|
||||
devptr->exts_deviceSDTypes[1] = DBZeroTypeBits;
|
||||
devptr->exts_deviceSDCount = nterm;
|
||||
devptr->exts_deviceSDCap = gscap;
|
||||
devptr->exts_deviceGateCap = gccap;
|
||||
devptr->exts_deviceClass = DEV_FET;
|
||||
devptr->exts_deviceName = StrDup((char **) NULL, transName);
|
||||
devptr->exts_deviceSubstrateName =
|
||||
StrDup((char **) NULL, subsName);
|
||||
ExtCurStyle->exts_transSubstrateTypes[t] = subsTypes;
|
||||
devptr->exts_deviceSubstrateTypes = subsTypes;
|
||||
devptr->exts_deviceIdentifierTypes = DBZeroTypeBits;
|
||||
devptr->exts_deviceParams = (ParamList *) NULL;
|
||||
devptr->exts_deviceResist.ht_table = (HashEntry **) NULL;
|
||||
HashInit(&devptr->exts_deviceResist, 8, HT_STRINGKEYS);
|
||||
|
||||
TTMaskSetMask(ExtCurStyle->exts_deviceConn + t, &types1);
|
||||
|
||||
devptr->exts_next = ExtCurStyle->exts_device[t];
|
||||
ExtCurStyle->exts_device[t] = devptr;
|
||||
#ifdef ARIEL
|
||||
{
|
||||
int z;
|
||||
|
|
@ -1936,12 +1979,11 @@ ExtTechLine(sectionName, argc, argv)
|
|||
case DEFAULTSIDEWALL:
|
||||
ExtTechSimpleSidewallCap(argv);
|
||||
break;
|
||||
|
||||
case DEVICE:
|
||||
|
||||
/* Parse second argument for device type */
|
||||
|
||||
n = LookupStruct(argv[1], (LookupTable *) devTable, sizeof devTable[0]);
|
||||
n = LookupStruct(argv[1], (LookupTable *)devTable, sizeof devTable[0]);
|
||||
if (n < 0)
|
||||
{
|
||||
TechError("Illegal device. Legal devices are:\n\t");
|
||||
|
|
@ -1999,6 +2041,18 @@ ExtTechLine(sectionName, argc, argv)
|
|||
argc--;
|
||||
}
|
||||
|
||||
/* If the last entry before any parameters starts with '+', */
|
||||
/* then use it to set the identity marker. Otherwise, the */
|
||||
/* identity marker is NULL. */
|
||||
|
||||
idTypes = DBZeroTypeBits;
|
||||
if (*argv[argc - 1] == '+')
|
||||
{
|
||||
if ((DBTechNameMask(argv[argc - 1] + 1, &idTypes)) == 0)
|
||||
idTypes = DBZeroTypeBits;
|
||||
argc--;
|
||||
}
|
||||
|
||||
/* Check the number of arguments after splitting out */
|
||||
/* parameter entries. There is no limit on arguments in */
|
||||
/* DEV_SUBCKT and DEV_MSUBCKT. */
|
||||
|
|
@ -2194,31 +2248,47 @@ ExtTechLine(sectionName, argc, argv)
|
|||
break;
|
||||
}
|
||||
|
||||
TTMaskSetMask(&ExtCurStyle->exts_transMask, &types1);
|
||||
TTMaskSetMask(&ExtCurStyle->exts_deviceMask, &types1);
|
||||
|
||||
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
|
||||
{
|
||||
if (TTMaskHasType(&types1, t))
|
||||
{
|
||||
TTMaskSetMask(ExtCurStyle->exts_transConn + t, &types1);
|
||||
devptr = (ExtDevice *)mallocMagic(sizeof(ExtDevice));
|
||||
|
||||
for (i = 0; !TTMaskIsZero(&termtypes[i]); i++);
|
||||
ExtCurStyle->exts_transSDTypes[t] = (TileTypeBitMask *)
|
||||
devptr->exts_deviceSDTypes = (TileTypeBitMask *)
|
||||
mallocMagic((i + 1) * sizeof(TileTypeBitMask));
|
||||
|
||||
for (i = 0; !TTMaskIsZero(&termtypes[i]); i++)
|
||||
ExtCurStyle->exts_transSDTypes[t][i] = termtypes[i];
|
||||
ExtCurStyle->exts_transSDTypes[t][i] = DBZeroTypeBits;
|
||||
devptr->exts_deviceSDTypes[i] = termtypes[i];
|
||||
devptr->exts_deviceSDTypes[i] = DBZeroTypeBits;
|
||||
|
||||
ExtCurStyle->exts_transSDCount[t] = nterm;
|
||||
ExtCurStyle->exts_transSDCap[t] = gscap;
|
||||
ExtCurStyle->exts_transGateCap[t] = gccap;
|
||||
ExtCurStyle->exts_deviceClass[t] = class;
|
||||
ExtCurStyle->exts_transName[t] =
|
||||
StrDup((char **) NULL, transName);
|
||||
devptr->exts_deviceSDCount = nterm;
|
||||
devptr->exts_deviceSDCap = gscap;
|
||||
devptr->exts_deviceGateCap = gccap;
|
||||
devptr->exts_deviceClass = class;
|
||||
devptr->exts_deviceName = StrDup((char **) NULL, transName);
|
||||
if (subsName != NULL)
|
||||
ExtCurStyle->exts_transSubstrateName[t] =
|
||||
devptr->exts_deviceSubstrateName =
|
||||
StrDup((char **) NULL, subsName);
|
||||
ExtCurStyle->exts_transSubstrateTypes[t] = subsTypes;
|
||||
else
|
||||
devptr->exts_deviceSubstrateName = (char *)NULL;
|
||||
devptr->exts_deviceSubstrateTypes = subsTypes;
|
||||
devptr->exts_deviceIdentifierTypes = idTypes;
|
||||
devptr->exts_deviceParams = (ParamList *) NULL;
|
||||
if (subcktParams != NULL)
|
||||
{
|
||||
devptr->exts_deviceParams = subcktParams;
|
||||
subcktParams->pl_count++;
|
||||
}
|
||||
devptr->exts_deviceResist.ht_table = (HashEntry **) NULL;
|
||||
HashInit(&devptr->exts_deviceResist, 8, HT_STRINGKEYS);
|
||||
|
||||
devptr->exts_next = ExtCurStyle->exts_device[t];
|
||||
ExtCurStyle->exts_device[t] = devptr;
|
||||
|
||||
TTMaskSetMask(ExtCurStyle->exts_deviceConn + t, &types1);
|
||||
#ifdef ARIEL
|
||||
{
|
||||
int z;
|
||||
|
|
@ -2231,11 +2301,6 @@ ExtTechLine(sectionName, argc, argv)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
if (subcktParams != NULL)
|
||||
{
|
||||
ExtCurStyle->exts_deviceParams[t] = subcktParams;
|
||||
subcktParams->pl_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -2249,13 +2314,19 @@ ExtTechLine(sectionName, argc, argv)
|
|||
val = atoi(argv[3]);
|
||||
isLinear = (strcmp(argv[2], "linear") == 0);
|
||||
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
|
||||
{
|
||||
ExtDevice *devptr;
|
||||
if (TTMaskHasType(&types1, t))
|
||||
{
|
||||
he = HashFind(&ExtCurStyle->exts_transResist[t], argv[2]);
|
||||
HashSetValue(he, (spointertype)val);
|
||||
if (isLinear)
|
||||
ExtCurStyle->exts_linearResist[t] = val;
|
||||
for (devptr = ExtCurStyle->exts_device[t]; devptr; devptr = devptr->exts_next)
|
||||
{
|
||||
he = HashFind(&devptr->exts_deviceResist, argv[2]);
|
||||
HashSetValue(he, (spointertype)val);
|
||||
if (isLinear)
|
||||
devptr->exts_linearResist = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HEIGHT: {
|
||||
float height, thick;
|
||||
|
|
@ -2280,6 +2351,122 @@ ExtTechLine(sectionName, argc, argv)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case ANTENNA: {
|
||||
float antennaratio;
|
||||
char areaType;
|
||||
bool hasModel = FALSE;
|
||||
int argidx = 2;
|
||||
|
||||
if (!StrIsNumeric(argv[2]))
|
||||
{
|
||||
if (!strcmp(argv[2], "surface") || !strcmp(argv[2], "area"))
|
||||
{
|
||||
areaType = ANTENNAMODEL_SURFACE;
|
||||
hasModel = TRUE;
|
||||
}
|
||||
else if (!strcmp(argv[2], "sidewall") || !strcmp(argv[2], "perimeter"))
|
||||
{
|
||||
areaType = ANTENNAMODEL_SIDEWALL;
|
||||
hasModel = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
TechError("Error in layer antenna calculation type \"%s\"; "
|
||||
" must be \"surface\" or \"sidewall\"\n", argv[2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasModel == FALSE)
|
||||
{
|
||||
if (ExtCurStyle->exts_antennaModel & ANTENNAMODEL_SURFACE)
|
||||
areaType = ANTENNAMODEL_SURFACE;
|
||||
else if (ExtCurStyle->exts_antennaModel & ANTENNAMODEL_SIDEWALL)
|
||||
areaType = ANTENNAMODEL_SIDEWALL;
|
||||
else
|
||||
TechError("No antenna calculation type given for layer(s) %s "
|
||||
" and no default calculation type found.\n", argv[1]);
|
||||
}
|
||||
|
||||
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
|
||||
if (TTMaskHasType(&types1, t))
|
||||
ExtCurStyle->exts_antennaRatio[t].areaType = areaType;
|
||||
|
||||
if (hasModel == TRUE) argidx = 3;
|
||||
|
||||
if (!StrIsNumeric(argv[argidx]))
|
||||
{
|
||||
TechError("Gate layer antenna ratio %s must be numeric\n", argv[argidx]);
|
||||
break;
|
||||
}
|
||||
antennaratio = (float)strtod(argv[argidx], NULL);
|
||||
|
||||
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
|
||||
if (TTMaskHasType(&types1, t))
|
||||
ExtCurStyle->exts_antennaRatio[t].ratioGate = antennaratio;
|
||||
|
||||
argidx++;
|
||||
if (!StrIsNumeric(argv[argidx]))
|
||||
{
|
||||
if (!strcasecmp(argv[argidx], "none"))
|
||||
antennaratio = INFINITY;
|
||||
else
|
||||
{
|
||||
TechError("Diff layer antenna ratio %s must be numeric\n",
|
||||
argv[argidx]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
antennaratio = (float)strtod(argv[argidx], NULL);
|
||||
|
||||
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
|
||||
if (TTMaskHasType(&types1, t))
|
||||
ExtCurStyle->exts_antennaRatio[t].ratioDiffB = antennaratio;
|
||||
|
||||
argidx++;
|
||||
if (argidx < argc)
|
||||
{
|
||||
if (!StrIsNumeric(argv[argidx]))
|
||||
{
|
||||
TechError("Diff layer antenna ratio %s must be numeric\n",
|
||||
argv[argidx]);
|
||||
break;
|
||||
}
|
||||
antennaratio = (float)strtod(argv[argidx], NULL);
|
||||
}
|
||||
else
|
||||
antennaratio = 0;
|
||||
|
||||
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
|
||||
if (TTMaskHasType(&types1, t))
|
||||
ExtCurStyle->exts_antennaRatio[t].ratioDiffA = antennaratio;
|
||||
|
||||
break;
|
||||
}
|
||||
case MODEL:
|
||||
if (!strcmp(argv[1], "partial"))
|
||||
ExtCurStyle->exts_antennaModel |= ANTENNAMODEL_PARTIAL;
|
||||
else if (!strcmp(argv[1], "cumulative"))
|
||||
ExtCurStyle->exts_antennaModel |= ANTENNAMODEL_CUMULATIVE;
|
||||
else
|
||||
TxError("Unknown antenna model \"%s\": Use \"partial\" or "
|
||||
"\"cumulative\"");
|
||||
|
||||
if (argc > 2)
|
||||
{
|
||||
if (!strcmp(argv[2], "surface") || !strcmp(argv[2], "area"))
|
||||
ExtCurStyle->exts_antennaModel |= ANTENNAMODEL_SURFACE;
|
||||
else if (!strcmp(argv[2], "sidewall") || !strcmp(argv[2], "perimeter"))
|
||||
ExtCurStyle->exts_antennaModel |= ANTENNAMODEL_SIDEWALL;
|
||||
else
|
||||
TxError("Unknown antenna model \"%s\": Use \"surface\" or "
|
||||
"\"sidewall\"");
|
||||
}
|
||||
break;
|
||||
|
||||
case TIEDOWN:
|
||||
TTMaskSetMask(&ExtCurStyle->exts_antennaTieTypes, &types1);
|
||||
break;
|
||||
case UNITS:
|
||||
if (!strcmp(argv[1], "microns"))
|
||||
doConvert = TRUE;
|
||||
|
|
@ -2569,8 +2756,22 @@ ExtTechLine(sectionName, argc, argv)
|
|||
ExtCurStyle->exts_stepSize = val;
|
||||
break;
|
||||
case SUBSTRATE:
|
||||
/* If the last entry starts with '-', then use it to set */
|
||||
/* the shield types. Otherwise, the shield types mask is */
|
||||
/* NULL. */
|
||||
|
||||
idTypes = DBZeroTypeBits;
|
||||
if (*argv[argc - 1] == '-')
|
||||
{
|
||||
if ((DBTechNameMask(argv[argc - 1] + 1, &idTypes)) == 0)
|
||||
idTypes = DBZeroTypeBits;
|
||||
argc--;
|
||||
}
|
||||
|
||||
TTMaskZero(&ExtCurStyle->exts_globSubstrateTypes);
|
||||
TTMaskZero(&ExtCurStyle->exts_globSubstrateShieldTypes);
|
||||
TTMaskSetMask(&ExtCurStyle->exts_globSubstrateTypes, &types1);
|
||||
ExtCurStyle->exts_globSubstrateShieldTypes = idTypes;
|
||||
ExtCurStyle->exts_globSubstratePlane = DBTechNoisyNamePlane(argv[2]);
|
||||
break;
|
||||
case NOPLANEORDER: {
|
||||
|
|
@ -2619,7 +2820,7 @@ diffplane:
|
|||
*
|
||||
* Postprocess the technology specific information for extraction.
|
||||
* Builds the connectivity tables exts_nodeConn[], exts_resistConn[],
|
||||
* and exts_transConn[].
|
||||
* and exts_deviceConn[].
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
|
|
@ -2664,9 +2865,9 @@ extTechFinalStyle(style)
|
|||
for (r = TT_TECHDEPBASE; r < DBNumTypes; r++)
|
||||
{
|
||||
maskBits = style->exts_nodeConn[r] = DBConnectTbl[r];
|
||||
if (!TTMaskHasType(&style->exts_transMask, r))
|
||||
if (!TTMaskHasType(&style->exts_deviceMask, r))
|
||||
{
|
||||
TTMaskZero(&style->exts_transConn[r]);
|
||||
TTMaskZero(&style->exts_deviceConn[r]);
|
||||
}
|
||||
for (s = TT_TECHDEPBASE; s < DBNumTypes; s++)
|
||||
{
|
||||
|
|
@ -2870,10 +3071,15 @@ zinit:
|
|||
|
||||
for (r = 0; r < DBNumTypes; r++)
|
||||
{
|
||||
style->exts_areaCap[r] *= sqfac;
|
||||
style->exts_transSDCap[r] *= sqfac;
|
||||
style->exts_transGateCap[r] *= sqfac;
|
||||
ExtDevice *devptr;
|
||||
|
||||
for (devptr = style->exts_device[r]; devptr; devptr = devptr->exts_next)
|
||||
{
|
||||
devptr->exts_deviceSDCap *= sqfac;
|
||||
devptr->exts_deviceGateCap *= sqfac;
|
||||
}
|
||||
|
||||
style->exts_areaCap[r] *= sqfac;
|
||||
for (s = 0; s < DBNumTypes; s++)
|
||||
{
|
||||
EdgeCap *ec;
|
||||
|
|
@ -2899,6 +3105,10 @@ zinit:
|
|||
ec = ec->ec_next)
|
||||
ec->ec_cap *= 0.5;
|
||||
}
|
||||
|
||||
/* Layer thickness and height are in microns, but are floating-point */
|
||||
style->exts_thick[r] /= dscale;
|
||||
style->exts_height[r] /= dscale;
|
||||
}
|
||||
|
||||
/* side halo and step size are also in microns */
|
||||
|
|
@ -2953,13 +3163,18 @@ ExtTechScale(scalen, scaled)
|
|||
|
||||
for (i = 0; i < DBNumTypes; i++)
|
||||
{
|
||||
ExtDevice *devptr;
|
||||
|
||||
style->exts_areaCap[i] *= sqn;
|
||||
style->exts_areaCap[i] /= sqd;
|
||||
|
||||
style->exts_transSDCap[i] *= sqn;
|
||||
style->exts_transSDCap[i] /= sqd;
|
||||
style->exts_transGateCap[i] *= sqn;
|
||||
style->exts_transGateCap[i] /= sqd;
|
||||
for (devptr = style->exts_device[i]; devptr; devptr = devptr->exts_next)
|
||||
{
|
||||
devptr->exts_deviceSDCap *= sqn;
|
||||
devptr->exts_deviceSDCap /= sqd;
|
||||
devptr->exts_deviceGateCap *= sqn;
|
||||
devptr->exts_deviceGateCap /= sqd;
|
||||
}
|
||||
|
||||
style->exts_height[i] *= scaled;
|
||||
style->exts_height[i] /= scalen;
|
||||
|
|
|
|||
|
|
@ -361,7 +361,7 @@ extShowTech(name)
|
|||
}
|
||||
}
|
||||
|
||||
extShowTrans("Transistor", &ExtCurStyle->exts_transMask, out);
|
||||
extShowTrans("Transistor", &ExtCurStyle->exts_deviceMask, out);
|
||||
|
||||
fprintf(out, "\nNode resistance and capacitance:\n");
|
||||
fprintf(out, "type R-ohm/sq AreaC-ff/l**2\n");
|
||||
|
|
@ -472,7 +472,7 @@ extShowTech(name)
|
|||
|
||||
extShowConnect("\nNode connectivity", ExtCurStyle->exts_nodeConn, out);
|
||||
extShowConnect("\nResistive region connectivity", ExtCurStyle->exts_resistConn, out);
|
||||
extShowConnect("\nTransistor connectivity", ExtCurStyle->exts_transConn, out);
|
||||
extShowConnect("\nTransistor connectivity", ExtCurStyle->exts_deviceConn, out);
|
||||
|
||||
if (out != stdout)
|
||||
(void) fclose(out);
|
||||
|
|
@ -493,12 +493,17 @@ extShowTrans(name, mask, out)
|
|||
for (t = 0; t < DBNumTypes; t++)
|
||||
if (TTMaskHasType(mask, t))
|
||||
{
|
||||
fprintf(out, " %-8.8s %d terminals: ",
|
||||
DBTypeShortName(t), ExtCurStyle->exts_transSDCount[t]);
|
||||
extShowMask(&ExtCurStyle->exts_transSDTypes[t][0], out);
|
||||
fprintf(out, "\n\tcap (gate-sd/gate-ch) = %lf/%lf\n",
|
||||
ExtCurStyle->exts_transSDCap[t],
|
||||
ExtCurStyle->exts_transGateCap[t]);
|
||||
ExtDevice *devptr;
|
||||
|
||||
for (devptr = ExtCurStyle->exts_device[t]; devptr; devptr = devptr->exts_next)
|
||||
{
|
||||
fprintf(out, " %-8.8s %d terminals: ",
|
||||
DBTypeShortName(t), devptr->exts_deviceSDCount);
|
||||
extShowMask(&devptr->exts_deviceSDTypes[0], out);
|
||||
fprintf(out, "\n\tcap (gate-sd/gate-ch) = %lf/%lf\n",
|
||||
devptr->exts_deviceSDCap,
|
||||
devptr->exts_deviceGateCap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -348,7 +348,7 @@ extTimesCellFunc(cs)
|
|||
|
||||
/* Count the number of transistors */
|
||||
transList = (TransRegion *) ExtFindRegions(def, &TiPlaneRect,
|
||||
&ExtCurStyle->exts_transMask, ExtCurStyle->exts_transConn,
|
||||
&ExtCurStyle->exts_deviceMask, ExtCurStyle->exts_deviceConn,
|
||||
extUnInit, extTransFirst, extTransEach);
|
||||
ExtResetTiles(def, extUnInit);
|
||||
for (tl = transList; tl; tl = tl->treg_next)
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ extern void ExtSetStyle();
|
|||
extern void ExtPrintStyle();
|
||||
extern void ExtCell();
|
||||
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
extern bool ExtGetDevInfo();
|
||||
extern bool ExtCompareStyle();
|
||||
|
|
|
|||
|
|
@ -48,6 +48,19 @@ typedef int ResValue; /* Warning: in some places resistances are stored
|
|||
* as ints. This is here for documentation only.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
char areaType; /* ANTENNAMODEL_SURFACE or ANTENNAMODEL_SIDEWALL */
|
||||
float ratioGate;
|
||||
float ratioDiffA; /* Proportional */
|
||||
float ratioDiffB; /* Constant */
|
||||
} RatioValues;
|
||||
|
||||
/* Antenna models */
|
||||
#define ANTENNAMODEL_PARTIAL 0x01
|
||||
#define ANTENNAMODEL_CUMULATIVE 0x02
|
||||
#define ANTENNAMODEL_SURFACE 0x04
|
||||
#define ANTENNAMODEL_SIDEWALL 0x08
|
||||
|
||||
/* ------------------------ Parameter lists --------------------------- */
|
||||
|
||||
/* These lists keep track of what parameter names subcircuit definitions
|
||||
|
|
@ -483,6 +496,82 @@ typedef struct extkeep
|
|||
char *exts_name;
|
||||
} ExtKeep;
|
||||
|
||||
/*
|
||||
* Structure used to define transistors and other extracted devices
|
||||
* One of these records is kept per tile type. However, the record
|
||||
* can link to additional records through the "exts_next" record,
|
||||
* so that multiple extraction devices can be defined for the same
|
||||
* tile type, provided that each definition has a unique combination
|
||||
* of exts_deviceSDTypes and exts_deviceSubstrateTypes.
|
||||
*/
|
||||
|
||||
typedef struct extDevice
|
||||
{
|
||||
/* Name of each transistor type as output in .ext file */
|
||||
char *exts_deviceName;
|
||||
|
||||
/* List of parameter names for each subcircuit type */
|
||||
ParamList *exts_deviceParams;
|
||||
|
||||
/* Device class for each layer type */
|
||||
char exts_deviceClass;
|
||||
|
||||
/*
|
||||
* Per-square resistances for each possible transistor type,
|
||||
* in the various regions that such a type might operate.
|
||||
* The only operating region currently used is "linear",
|
||||
* which the resistance extractor uses in its thresholding
|
||||
* operation. NOTE: resistances in this table are in OHMS
|
||||
* per square, not MILLIOHMS!
|
||||
*/
|
||||
|
||||
HashTable exts_deviceResist;
|
||||
ResValue exts_linearResist;
|
||||
|
||||
/*
|
||||
* Mask of the types of tiles that connect to the channel terminals
|
||||
* of a transistor type. The intent is that these will be the
|
||||
* diffusion terminals of a transistor, ie, its source and drain.
|
||||
* UPDATED May, 2008: Record is a list of type masks, allowing
|
||||
* multiple terminal types in the case of, e.g., high-voltage
|
||||
* or other asymmetric devices. The last entry in the list should
|
||||
* be equal to DBSpaceBits.
|
||||
*/
|
||||
TileTypeBitMask *exts_deviceSDTypes;
|
||||
|
||||
/*
|
||||
* Maximum number of terminals (source/drains) per transistor type.
|
||||
* This table exists to allow the possibility of transistors with
|
||||
* more than two diffusion terminals at some point in the future.
|
||||
*/
|
||||
int exts_deviceSDCount;
|
||||
|
||||
/* Currently unused: gate-source capacitance per unit perimeter */
|
||||
CapValue exts_deviceSDCap;
|
||||
|
||||
/* Currently unused: gate-channel capacitance per unit area */
|
||||
CapValue exts_deviceGateCap;
|
||||
|
||||
/*
|
||||
* Each type of transistor has a substrate node. By default,
|
||||
* it is the one given by exts_deviceSubstrateName[t]. However,
|
||||
* if the mask exts_deviceSubstrateTypes is non-zero, and if
|
||||
* the transistor overlaps material of one of the types in the
|
||||
* mask, then the transistor substrate node is the node of the
|
||||
* material it overlaps.
|
||||
*/
|
||||
char *exts_deviceSubstrateName;
|
||||
TileTypeBitMask exts_deviceSubstrateTypes;
|
||||
|
||||
/*
|
||||
* Each device type can have any number of extract models based
|
||||
* on identifier layers (such as thickox, esd, etc.)
|
||||
*/
|
||||
TileTypeBitMask exts_deviceIdentifierTypes;
|
||||
|
||||
struct extDevice *exts_next;
|
||||
} ExtDevice;
|
||||
|
||||
/*
|
||||
* Parameters for the process being extracted.
|
||||
* We try to use use integers here, rather than floats, to be nice to
|
||||
|
|
@ -524,11 +613,11 @@ typedef struct extstyle
|
|||
TileTypeBitMask exts_resistConn[NT];
|
||||
|
||||
/*
|
||||
* Connectivity for determining transistors.
|
||||
* Each transistor type should connect only to itself.
|
||||
* Connectivity for determining devices.
|
||||
* Each devices type should connect only to itself.
|
||||
* Nothing else should connect to anything else.
|
||||
*/
|
||||
TileTypeBitMask exts_transConn[NT];
|
||||
TileTypeBitMask exts_deviceConn[NT];
|
||||
|
||||
/*
|
||||
* Set of types to be considered for extraction. Types not in
|
||||
|
|
@ -580,6 +669,14 @@ typedef struct extstyle
|
|||
float exts_height[NT];
|
||||
float exts_thick[NT];
|
||||
|
||||
char exts_antennaModel;
|
||||
|
||||
/* Antenna area ratio for each layer */
|
||||
RatioValues exts_antennaRatio[NT];
|
||||
|
||||
/* Mask of types that tie down antennas */
|
||||
TileTypeBitMask exts_antennaTieTypes;
|
||||
|
||||
/*
|
||||
* Capacitance to substrate for each tile type, in units of
|
||||
* attofarads per square lambda.
|
||||
|
|
@ -779,65 +876,14 @@ typedef struct extstyle
|
|||
*/
|
||||
TileTypeBitMask exts_sideEdges[NT];
|
||||
|
||||
/* Transistors */
|
||||
/* Devices */
|
||||
|
||||
/* Name of each transistor type as output in .ext file */
|
||||
char *exts_transName[NT];
|
||||
/* Contains one for each type of device, zero for all other tile types */
|
||||
TileTypeBitMask exts_deviceMask;
|
||||
|
||||
/* List of parameter names for each subcircuit type */
|
||||
ParamList *exts_deviceParams[NT];
|
||||
/* All information about a device goes in this record (see above) */
|
||||
ExtDevice *exts_device[NT];
|
||||
|
||||
/* Device class for each layer type */
|
||||
char exts_deviceClass[NT];
|
||||
|
||||
/* Contains one for each type of fet, zero for all other types */
|
||||
TileTypeBitMask exts_transMask;
|
||||
|
||||
/*
|
||||
* Per-square resistances for each possible transistor type,
|
||||
* in the various regions that such a type might operate.
|
||||
* The only operating region currently used is "linear",
|
||||
* which the resistance extractor uses in its thresholding
|
||||
* operation. NOTE: resistances in this table are in OHMS
|
||||
* per square, not MILLIOHMS!
|
||||
*/
|
||||
HashTable exts_transResist[NT];
|
||||
ResValue exts_linearResist[NT];
|
||||
|
||||
/*
|
||||
* Mask of the types of tiles that connect to the channel terminals
|
||||
* of a transistor type. The intent is that these will be the
|
||||
* diffusion terminals of a transistor, ie, its source and drain.
|
||||
* UPDATED May, 2008: Record is a list of type masks, allowing
|
||||
* multiple terminal types in the case of, e.g., high-voltage
|
||||
* or other asymmetric devices. The last entry in the list should
|
||||
* be equal to DBSpaceBits.
|
||||
*/
|
||||
TileTypeBitMask *exts_transSDTypes[NT];
|
||||
|
||||
/*
|
||||
* Maximum number of terminals (source/drains) per transistor type.
|
||||
* This table exists to allow the possibility of transistors with
|
||||
* more than two diffusion terminals at some point in the future.
|
||||
*/
|
||||
int exts_transSDCount[NT];
|
||||
|
||||
/* Currently unused: gate-source capacitance per unit perimeter */
|
||||
CapValue exts_transSDCap[NT];
|
||||
|
||||
/* Currently unused: gate-channel capacitance per unit area */
|
||||
CapValue exts_transGateCap[NT];
|
||||
|
||||
/*
|
||||
* Each type of transistor has a substrate node. By default,
|
||||
* it is the one given by exts_transSubstrateName[t]. However,
|
||||
* if the mask exts_transSubstrateTypes[t] is non-zero, and if
|
||||
* the transistor overlaps material of one of the types in the
|
||||
* mask, then the transistor substrate node is the node of the
|
||||
* material it overlaps. If exts_transSub
|
||||
*/
|
||||
char *exts_transSubstrateName[NT];
|
||||
TileTypeBitMask exts_transSubstrateTypes[NT];
|
||||
#ifdef ARIEL
|
||||
TileTypeBitMask exts_subsTransistorTypes[NT];
|
||||
#endif /* ARIEL */
|
||||
|
|
@ -847,11 +893,16 @@ typedef struct extstyle
|
|||
* types that connect to the substrate. Since for non-SOI
|
||||
* processes, this generally is used to specify that space on
|
||||
* the well plane is the substrate, the plane number for the
|
||||
* well plane is given, too.
|
||||
* well plane is given, too. The "shield types" mask is a
|
||||
* mask of types that prevent any types in exts_globSubstrateTypes
|
||||
* from contacting the substrate (e.g., deep nwell might be a
|
||||
* shielding type, or it could be a special marker layer like
|
||||
* "not_substrate").
|
||||
*/
|
||||
char *exts_globSubstrateName;
|
||||
TileTypeBitMask exts_globSubstrateTypes;
|
||||
int exts_globSubstratePlane;
|
||||
TileTypeBitMask exts_globSubstrateShieldTypes;
|
||||
|
||||
/* Scaling */
|
||||
/*
|
||||
|
|
@ -1024,6 +1075,7 @@ extern NodeRegion *extBasic();
|
|||
extern NodeRegion *extFindNodes();
|
||||
extern ExtTree *extHierNewOne();
|
||||
extern int extNbrPushFunc();
|
||||
extern TileType extGetDevType();
|
||||
|
||||
/* --------------------- Miscellaneous globals ------------------------ */
|
||||
|
||||
|
|
|
|||
|
|
@ -40,22 +40,22 @@ ${GR_HELPER_PROG}: ${GR_HELPER_SRCS}
|
|||
${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} ${GR_HELPER_SRCS} \
|
||||
-o ${GR_HELPER_PROG} ${LIBS}
|
||||
|
||||
install: $(DESTDIR)${BINDIR}/${GR_HELPER_PROG} glyphs fonts
|
||||
install: $(DESTDIR)${INSTALL_BINDIR}/${GR_HELPER_PROG} glyphs fonts
|
||||
|
||||
install-tcl: glyphs fonts
|
||||
|
||||
$(DESTDIR)${BINDIR}/${GR_HELPER_PROG}: ${GR_HELPER_PROG}
|
||||
${RM} $(DESTDIR)${BINDIR}/${GR_HELPER_PROG}
|
||||
${CP} ${GR_HELPER_PROG} $(DESTDIR)${BINDIR}
|
||||
$(DESTDIR)${INSTALL_BINDIR}/${GR_HELPER_PROG}: ${GR_HELPER_PROG}
|
||||
${RM} $(DESTDIR)${INSTALL_BINDIR}/${GR_HELPER_PROG}
|
||||
${CP} ${GR_HELPER_PROG} $(DESTDIR)${INSTALL_BINDIR}
|
||||
|
||||
glyphs: ${GLYPHS}
|
||||
for i in ${GLYPHS}; do \
|
||||
${RM} $(DESTDIR)${SYSDIR}/$$i; \
|
||||
${CP} $$i $(DESTDIR)${SYSDIR}; done
|
||||
${RM} $(DESTDIR)${INSTALL_SYSDIR}/$$i; \
|
||||
${CP} $$i $(DESTDIR)${INSTALL_SYSDIR}; done
|
||||
|
||||
fonts: ${OUTLINE_FONTS}
|
||||
for i in ${OUTLINE_FONTS}; do \
|
||||
${RM} $(DESTDIR)${SYSDIR}/$$i; \
|
||||
${CP} $$i $(DESTDIR)${SYSDIR}; done
|
||||
${RM} $(DESTDIR)${INSTALL_SYSDIR}/$$i; \
|
||||
${CP} $$i $(DESTDIR)${INSTALL_SYSDIR}; done
|
||||
|
||||
include ${MAGICDIR}/rules.mak
|
||||
|
|
|
|||
|
|
@ -1389,12 +1389,14 @@ W3DloadWindow(window, name)
|
|||
CellDef *newEditDef;
|
||||
CellUse *newEditUse;
|
||||
Rect loadBox;
|
||||
bool dereference;
|
||||
|
||||
newEditDef = DBCellLookDef(name);
|
||||
if (newEditDef == (CellDef *)NULL)
|
||||
return FALSE;
|
||||
|
||||
if (!DBCellRead(newEditDef, (char *)NULL, TRUE, NULL))
|
||||
dereference = (newEditDef->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
if (!DBCellRead(newEditDef, (char *)NULL, TRUE, dereference, NULL))
|
||||
return FALSE;
|
||||
|
||||
DBReComputeBbox(newEditDef);
|
||||
|
|
|
|||
|
|
@ -370,6 +370,9 @@ GrTCairoPlotSVG (char *filename, MagWindow *mw)
|
|||
wind_context = tcairodata->context;
|
||||
tcairodata->surface = (cairo_surface_t *)cairo_svg_surface_create(filename,
|
||||
(double)screenw, (double)screenh);
|
||||
cairo_svg_surface_restrict_to_version(tcairodata->surface,
|
||||
CAIRO_SVG_VERSION_1_2);
|
||||
|
||||
tcairodata->context = cairo_create(tcairodata->surface);
|
||||
WindRedisplay(mw);
|
||||
WindUpdate();
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@ magiclef${SHDLIB_EXT}: tcllef.o ${OBJS}
|
|||
${CC} ${CFLAGS} ${CPPFLAGS} -o $@ ${LDDL_FLAGS} tcllef.o ${OBJS} \
|
||||
${EXTRA_LIBS} -lc ${LIBS}
|
||||
|
||||
install-tcl: $(DESTDIR)${TCLDIR}/magiclef${SHDLIB_EXT}
|
||||
install-tcl: $(DESTDIR)${INSTALL_TCLDIR}/magiclef${SHDLIB_EXT}
|
||||
|
||||
$(DESTDIR)${TCLDIR}/magiclef${SHDLIB_EXT}: magiclef${SHDLIB_EXT}
|
||||
${RM} $(DESTDIR)${TCLDIR}/magiclef${SHDLIB_EXT}
|
||||
${CP} magiclef${SHDLIB_EXT} $(DESTDIR)${TCLDIR}/magiclef${SHDLIB_EXT}
|
||||
$(DESTDIR)${INSTALL_TCLDIR}/magiclef${SHDLIB_EXT}: magiclef${SHDLIB_EXT}
|
||||
${RM} $(DESTDIR)${INSTALL_TCLDIR}/magiclef${SHDLIB_EXT}
|
||||
${CP} magiclef${SHDLIB_EXT} $(DESTDIR)${INSTALL_TCLDIR}/magiclef${SHDLIB_EXT}
|
||||
|
||||
include ${MAGICDIR}/rules.mak
|
||||
|
|
|
|||
145
lef/defRead.c
145
lef/defRead.c
|
|
@ -26,6 +26,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "tiles/tile.h"
|
||||
#include "utils/hash.h"
|
||||
#include "utils/undo.h"
|
||||
#include "utils/utils.h"
|
||||
#include "database/database.h"
|
||||
#include "windows/windows.h"
|
||||
#include "dbwind/dbwind.h"
|
||||
|
|
@ -73,11 +74,12 @@ enum def_netspecial_shape_keys {
|
|||
DEF_SPECNET_SHAPE_DRCFILL};
|
||||
|
||||
char *
|
||||
DefAddRoutes(rootDef, f, oscale, special, defLayerMap)
|
||||
DefAddRoutes(rootDef, f, oscale, special, netname, defLayerMap)
|
||||
CellDef *rootDef; /* Cell to paint */
|
||||
FILE *f; /* Input file */
|
||||
float oscale; /* Scale factor between LEF and magic units */
|
||||
bool special; /* True if this section is SPECIALNETS */
|
||||
char *netname; /* Name of the net, if net is to be labeled */
|
||||
LefMapping *defLayerMap; /* magic-to-lef layer mapping array */
|
||||
{
|
||||
char *token;
|
||||
|
|
@ -85,6 +87,7 @@ DefAddRoutes(rootDef, f, oscale, special, defLayerMap)
|
|||
Point refp; /* reference point */
|
||||
bool valid = FALSE; /* is there a valid reference point? */
|
||||
bool initial = TRUE;
|
||||
bool labeled = TRUE;
|
||||
Rect locarea;
|
||||
int extend, lextend, hextend;
|
||||
float x, y, z, w;
|
||||
|
|
@ -124,6 +127,8 @@ DefAddRoutes(rootDef, f, oscale, special, defLayerMap)
|
|||
NULL
|
||||
};
|
||||
|
||||
if (netname != NULL) labeled = FALSE;
|
||||
|
||||
while (initial || (token = LefNextToken(f, TRUE)) != NULL)
|
||||
{
|
||||
/* Get next point, token "NEW", or via name */
|
||||
|
|
@ -605,6 +610,16 @@ endCoord:
|
|||
/* paint */
|
||||
DBPaint(rootDef, &routeTop->r_r, routeTop->r_type);
|
||||
|
||||
/* label */
|
||||
if (labeled == FALSE)
|
||||
{
|
||||
Rect r;
|
||||
r.r_xbot = r.r_xtop = (routeTop->r_r.r_xbot + routeTop->r_r.r_xtop) / 2;
|
||||
r.r_ybot = r.r_ytop = (routeTop->r_r.r_ybot + routeTop->r_r.r_ytop) / 2;
|
||||
DBPutLabel(rootDef, &r, GEO_CENTER, netname, routeTop->r_type, 0);
|
||||
labeled = TRUE;
|
||||
}
|
||||
|
||||
/* advance to next point and free record (1-delayed) */
|
||||
freeMagic((char *)routeTop);
|
||||
routeTop = routeTop->r_next;
|
||||
|
|
@ -636,15 +651,17 @@ enum def_netprop_keys {
|
|||
DEF_NETPROP_PROPERTY};
|
||||
|
||||
void
|
||||
DefReadNets(f, rootDef, sname, oscale, special, total)
|
||||
DefReadNets(f, rootDef, sname, oscale, special, dolabels, total)
|
||||
FILE *f;
|
||||
CellDef *rootDef;
|
||||
char *sname;
|
||||
float oscale;
|
||||
bool special; /* True if this section is SPECIALNETS */
|
||||
bool dolabels; /* If true, create a label for each net */
|
||||
int total;
|
||||
{
|
||||
char *token;
|
||||
char *netname = NULL;
|
||||
int keyword, subkey;
|
||||
int processed = 0;
|
||||
LefMapping *defLayerMap;
|
||||
|
|
@ -684,8 +701,8 @@ DefReadNets(f, rootDef, sname, oscale, special, total)
|
|||
case DEF_NET_START:
|
||||
|
||||
/* Get net name */
|
||||
/* Presently, we ignore net names completely. */
|
||||
token = LefNextToken(f, TRUE);
|
||||
if (dolabels) netname = StrDup((char **)NULL, token);
|
||||
|
||||
/* Update the record of the number of nets processed */
|
||||
/* and spit out a message for every 5% finished. */
|
||||
|
|
@ -725,10 +742,11 @@ DefReadNets(f, rootDef, sname, oscale, special, total)
|
|||
case DEF_NETPROP_FIXED:
|
||||
case DEF_NETPROP_COVER:
|
||||
token = DefAddRoutes(rootDef, f, oscale, special,
|
||||
defLayerMap);
|
||||
netname, defLayerMap);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dolabels) freeMagic(netname);
|
||||
break;
|
||||
|
||||
case DEF_NET_END:
|
||||
|
|
@ -775,11 +793,12 @@ enum def_orient {DEF_NORTH, DEF_SOUTH, DEF_EAST, DEF_WEST,
|
|||
DEF_FLIPPED_WEST};
|
||||
|
||||
int
|
||||
DefReadLocation(use, f, oscale, tptr)
|
||||
DefReadLocation(use, f, oscale, tptr, noplace)
|
||||
CellUse *use;
|
||||
FILE *f;
|
||||
float oscale;
|
||||
Transform *tptr;
|
||||
bool noplace;
|
||||
{
|
||||
Rect *r, tr, rect;
|
||||
int keyword;
|
||||
|
|
@ -791,21 +810,32 @@ DefReadLocation(use, f, oscale, tptr)
|
|||
"N", "S", "E", "W", "FN", "FS", "FE", "FW"
|
||||
};
|
||||
|
||||
token = LefNextToken(f, TRUE);
|
||||
if (*token != '(') goto parse_error;
|
||||
token = LefNextToken(f, TRUE);
|
||||
if (sscanf(token, "%f", &x) != 1) goto parse_error;
|
||||
token = LefNextToken(f, TRUE);
|
||||
if (sscanf(token, "%f", &y) != 1) goto parse_error;
|
||||
token = LefNextToken(f, TRUE);
|
||||
if (*token != ')') goto parse_error;
|
||||
token = LefNextToken(f, TRUE);
|
||||
|
||||
keyword = Lookup(token, orientations);
|
||||
if (keyword < 0)
|
||||
if (noplace)
|
||||
{
|
||||
LefError(DEF_ERROR, "Unknown macro orientation \"%s\".\n", token);
|
||||
return -1;
|
||||
LefError(DEF_WARNING, "Unplaced component \"%s\" will be put at origin.\n",
|
||||
use->cu_id);
|
||||
x = 0;
|
||||
y = 0;
|
||||
keyword = DEF_NORTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
token = LefNextToken(f, TRUE);
|
||||
if (*token != '(') goto parse_error;
|
||||
token = LefNextToken(f, TRUE);
|
||||
if (sscanf(token, "%f", &x) != 1) goto parse_error;
|
||||
token = LefNextToken(f, TRUE);
|
||||
if (sscanf(token, "%f", &y) != 1) goto parse_error;
|
||||
token = LefNextToken(f, TRUE);
|
||||
if (*token != ')') goto parse_error;
|
||||
token = LefNextToken(f, TRUE);
|
||||
|
||||
keyword = Lookup(token, orientations);
|
||||
if (keyword < 0)
|
||||
{
|
||||
LefError(DEF_ERROR, "Unknown macro orientation \"%s\".\n", token);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* The standard transformations are all defined to rotate */
|
||||
|
|
@ -1062,7 +1092,7 @@ DefReadPins(f, rootDef, sname, oscale, total)
|
|||
break;
|
||||
case DEF_PINS_PROP_FIXED:
|
||||
case DEF_PINS_PROP_PLACED:
|
||||
DefReadLocation(NULL, f, oscale, &t);
|
||||
DefReadLocation(NULL, f, oscale, &t, FALSE);
|
||||
if (curlayer == -1)
|
||||
pending = TRUE;
|
||||
else
|
||||
|
|
@ -1275,6 +1305,35 @@ DefReadVias(f, sname, oscale, total)
|
|||
blayer = LefReadLayer(f, FALSE);
|
||||
clayer = LefReadLayer(f, FALSE);
|
||||
tlayer = LefReadLayer(f, FALSE);
|
||||
|
||||
/* Provisional behavior: A known tool generating */
|
||||
/* DEF uses the order (bottom, top, cut). This may */
|
||||
/* be a bug in the tool and an issue is being */
|
||||
/* raised. However, there is no harm in detecting */
|
||||
/* which layer is the cut and swapping as needed. */
|
||||
|
||||
if (!DBIsContact(clayer))
|
||||
{
|
||||
TileType swaplayer;
|
||||
LefError(DEF_WARNING, "Improper layer order for"
|
||||
" VIARULE.\n");
|
||||
if (DBIsContact(tlayer))
|
||||
{
|
||||
swaplayer = clayer;
|
||||
clayer = tlayer;
|
||||
tlayer = swaplayer;
|
||||
}
|
||||
else if (DBIsContact(blayer))
|
||||
{
|
||||
swaplayer = clayer;
|
||||
clayer = blayer;
|
||||
blayer = swaplayer;
|
||||
}
|
||||
else
|
||||
LefError(DEF_ERROR, "No cut layer specified in"
|
||||
" VIARULE.\n");
|
||||
}
|
||||
|
||||
generated = TRUE;
|
||||
break;
|
||||
case DEF_VIAS_PROP_CUTSPACING:
|
||||
|
|
@ -1450,18 +1509,22 @@ DefReadComponents(f, rootDef, sname, oscale, total)
|
|||
|
||||
/* Does use name contain brackets? If so, this can */
|
||||
/* interfere with magic's use of arrays. */
|
||||
/* NOTE: This has been commented out. I think */
|
||||
/* the only confusion is in ext2spice and can be */
|
||||
/* avoided by allowing any bracket notation in an */
|
||||
/* instance name other than that used by the .ext */
|
||||
/* file for dealing with arrays, which uses the */
|
||||
/* specific syntax [xlo:xsep:xhi][ylo:ysep:yhi] and */
|
||||
/* is easy enough to distinguish. */
|
||||
|
||||
/* NOTE: It is not clear that this needs to be */
|
||||
/* done during DEF read. The only confusion comes */
|
||||
/* from the arrays being parsed by ExtFlat when */
|
||||
/* doing ext2spice. */
|
||||
|
||||
dptr = strchr(usename, '[');
|
||||
if (dptr != NULL) {
|
||||
*dptr = '_';
|
||||
dptr = strchr(dptr + 1, ']');
|
||||
if (dptr != NULL) *dptr = '_';
|
||||
}
|
||||
/*
|
||||
dptr = strchr(usename, '[');
|
||||
if (dptr != NULL) {
|
||||
*dptr = '_';
|
||||
dptr = strchr(dptr + 1, ']');
|
||||
if (dptr != NULL) *dptr = '_';
|
||||
}
|
||||
*/
|
||||
|
||||
token = LefNextToken(f, TRUE);
|
||||
|
||||
|
|
@ -1471,11 +1534,14 @@ DefReadComponents(f, rootDef, sname, oscale, total)
|
|||
|
||||
if (defMacro == (CellDef *)NULL)
|
||||
{
|
||||
bool dereference;
|
||||
|
||||
/* Before giving up, assume that this cell has a */
|
||||
/* magic .mag layout file. */
|
||||
defMacro = DBCellNewDef(token, (char *)NULL);
|
||||
defMacro->cd_flags &= ~CDNOTFOUND;
|
||||
if (!DBCellRead(defMacro, (char *)NULL, TRUE, NULL))
|
||||
dereference = (defMacro->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
if (!DBCellRead(defMacro, (char *)NULL, TRUE, dereference, NULL))
|
||||
{
|
||||
LefError(DEF_ERROR, "Cell %s is not defined. Maybe you "
|
||||
"have not read the corresponding LEF file?\n",
|
||||
|
|
@ -1518,10 +1584,12 @@ DefReadComponents(f, rootDef, sname, oscale, total)
|
|||
switch (subkey)
|
||||
{
|
||||
case DEF_PROP_PLACED:
|
||||
case DEF_PROP_UNPLACED:
|
||||
case DEF_PROP_FIXED:
|
||||
case DEF_PROP_COVER:
|
||||
DefReadLocation(defUse, f, oscale, &t);
|
||||
DefReadLocation(defUse, f, oscale, &t, FALSE);
|
||||
break;
|
||||
case DEF_PROP_UNPLACED:
|
||||
DefReadLocation(defUse, f, oscale, &t, TRUE);
|
||||
break;
|
||||
case DEF_PROP_SOURCE:
|
||||
case DEF_PROP_WEIGHT:
|
||||
|
|
@ -1598,8 +1666,9 @@ enum def_sections {DEF_VERSION = 0, DEF_NAMESCASESENSITIVE,
|
|||
DEF_END};
|
||||
|
||||
void
|
||||
DefRead(inName)
|
||||
DefRead(inName, dolabels)
|
||||
char *inName;
|
||||
bool dolabels;
|
||||
{
|
||||
CellDef *rootDef;
|
||||
FILE *f;
|
||||
|
|
@ -1775,13 +1844,15 @@ DefRead(inName)
|
|||
token = LefNextToken(f, TRUE);
|
||||
if (sscanf(token, "%d", &total) != 1) total = 0;
|
||||
LefEndStatement(f);
|
||||
DefReadNets(f, rootDef, sections[DEF_SPECIALNETS], oscale, TRUE, total);
|
||||
DefReadNets(f, rootDef, sections[DEF_SPECIALNETS], oscale, TRUE,
|
||||
dolabels, total);
|
||||
break;
|
||||
case DEF_NETS:
|
||||
token = LefNextToken(f, TRUE);
|
||||
if (sscanf(token, "%d", &total) != 1) total = 0;
|
||||
LefEndStatement(f);
|
||||
DefReadNets(f, rootDef, sections[DEF_NETS], oscale, FALSE, total);
|
||||
DefReadNets(f, rootDef, sections[DEF_NETS], oscale, FALSE,
|
||||
dolabels, total);
|
||||
break;
|
||||
case DEF_IOTIMINGS:
|
||||
LefSkipSection(f, sections[DEF_IOTIMINGS]);
|
||||
|
|
|
|||
46
lef/lefCmd.c
46
lef/lefCmd.c
|
|
@ -87,6 +87,15 @@ CmdLef(w, cmd)
|
|||
* the macro other than pin area
|
||||
* immediately surrounding labels.
|
||||
*/
|
||||
bool recurse = FALSE; /* If TRUE, recurse on all subcells
|
||||
* during "writeall". By default,
|
||||
* only the immediate children of the
|
||||
* top level cell are output.
|
||||
*/
|
||||
bool defLabelNets = FALSE; /* If TRUE, attach a label to the
|
||||
* center of the first rectangle
|
||||
* found on that net.
|
||||
*/
|
||||
|
||||
static char *cmdLefOption[] =
|
||||
{
|
||||
|
|
@ -95,7 +104,9 @@ CmdLef(w, cmd)
|
|||
"write [filename] [-tech] write LEF for current cell\n"
|
||||
" write [filename] -hide hide all details other than ports",
|
||||
"writeall write all cells including the top-level cell\n"
|
||||
" writeall -notop write all subcells of the top-level cell",
|
||||
" writeall -notop write all children of the top-level cell\n"
|
||||
" writeall -all recurse on all subcells of the top-level cell\n",
|
||||
" writeall -hide hide all details other than ports",
|
||||
"help print this help information",
|
||||
NULL
|
||||
};
|
||||
|
|
@ -103,7 +114,8 @@ CmdLef(w, cmd)
|
|||
static char *cmdDefOption[] =
|
||||
{
|
||||
"read [filename] read a DEF file filename[.def]",
|
||||
"write [cell] [-allspecial] write DEF for current or indicated cell",
|
||||
"write [cell] [-allspecial] write DEF for current or indicated cell\n",
|
||||
"write -labels label every net in NETS with the net name",
|
||||
"writeall (use \"flatten -nosubckt\" + \"def"
|
||||
" write\" instead)",
|
||||
"help print this help information",
|
||||
|
|
@ -151,22 +163,32 @@ CmdLef(w, cmd)
|
|||
switch (option)
|
||||
{
|
||||
case LEF_READ:
|
||||
if (cmd->tx_argc != 3)
|
||||
if (cmd->tx_argc > 3)
|
||||
{
|
||||
if (cmd->tx_argc == 4)
|
||||
for (i = 3; i < cmd->tx_argc; i++)
|
||||
{
|
||||
if (*(cmd->tx_argv[3]) == '-')
|
||||
if (!strncmp(cmd->tx_argv[3], "-import", 7))
|
||||
if (*(cmd->tx_argv[i]) == '-')
|
||||
{
|
||||
if (!strncmp(cmd->tx_argv[i], "-import", 7))
|
||||
lefImport = TRUE;
|
||||
else if (!strncmp(cmd->tx_argv[i], "-label", 6))
|
||||
{
|
||||
if (is_lef)
|
||||
TxPrintf("The \"-labels\" option is only for def read\n");
|
||||
else
|
||||
defLabelNets = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
goto wrongNumArgs;
|
||||
}
|
||||
else if (cmd->tx_argc < 3)
|
||||
goto wrongNumArgs;
|
||||
|
||||
namep = cmd->tx_argv[2];
|
||||
if (is_lef)
|
||||
LefRead(namep, lefImport);
|
||||
else
|
||||
DefRead(namep);
|
||||
DefRead(namep, defLabelNets);
|
||||
break;
|
||||
case LEF_WRITEALL:
|
||||
if (!is_lef)
|
||||
|
|
@ -184,11 +206,15 @@ CmdLef(w, cmd)
|
|||
lefTopCell = FALSE;
|
||||
else if (!strncmp(cmd->tx_argv[i], "-tech", 5))
|
||||
lefTech = TRUE;
|
||||
else if (!strncmp(cmd->tx_argv[i], "-hide", 5))
|
||||
lefHide = TRUE;
|
||||
else if (!strncmp(cmd->tx_argv[i], "-all", 4))
|
||||
recurse = TRUE;
|
||||
else goto wrongNumArgs;
|
||||
}
|
||||
else goto wrongNumArgs;
|
||||
}
|
||||
LefWriteAll(selectedUse, lefTopCell, lefTech);
|
||||
LefWriteAll(selectedUse, lefTopCell, lefTech, lefHide, recurse);
|
||||
}
|
||||
break;
|
||||
case LEF_WRITE:
|
||||
|
|
|
|||
|
|
@ -1212,18 +1212,21 @@ LefReadGeometry(lefMacro, f, oscale, do_list)
|
|||
*
|
||||
* Side Effects:
|
||||
* Reads input from file f;
|
||||
* Paints into the CellDef lefMacro.
|
||||
* Generates a new label entry in the CellDef lefMacro.
|
||||
* If "lanno" is not NULL, then the label pointed to by
|
||||
* lanno is modified.
|
||||
*
|
||||
*------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
LefReadPort(lefMacro, f, pinName, pinNum, pinDir, pinUse, oscale)
|
||||
LefReadPort(lefMacro, f, pinName, pinNum, pinDir, pinUse, oscale, lanno)
|
||||
CellDef *lefMacro;
|
||||
FILE *f;
|
||||
char *pinName;
|
||||
int pinNum, pinDir, pinUse;
|
||||
float oscale;
|
||||
Label *lanno;
|
||||
{
|
||||
Label *newlab;
|
||||
LinkedRect *rectList;
|
||||
|
|
@ -1235,7 +1238,15 @@ LefReadPort(lefMacro, f, pinName, pinNum, pinDir, pinUse, oscale)
|
|||
if (pinNum >= 0)
|
||||
{
|
||||
/* Label this area */
|
||||
DBPutLabel(lefMacro, &rectList->r_r, -1, pinName, rectList->r_type, 0);
|
||||
if (lanno != NULL)
|
||||
{
|
||||
/* Modify an existing label */
|
||||
lanno->lab_rect = rectList->r_r;
|
||||
lanno->lab_type = rectList->r_type;
|
||||
}
|
||||
else
|
||||
/* Create a new label (non-rendered) */
|
||||
DBPutLabel(lefMacro, &rectList->r_r, -1, pinName, rectList->r_type, 0);
|
||||
|
||||
/* Set this label to be a port */
|
||||
|
||||
|
|
@ -1243,13 +1254,16 @@ LefReadPort(lefMacro, f, pinName, pinNum, pinDir, pinUse, oscale)
|
|||
LefError(LEF_ERROR, "Internal error: No labels in cell!\n");
|
||||
else
|
||||
{
|
||||
newlab = lefMacro->cd_lastLabel;
|
||||
newlab = (lanno != NULL) ? lanno : lefMacro->cd_lastLabel;
|
||||
if (strcmp(newlab->lab_text, pinName))
|
||||
LefError(LEF_ERROR, "Internal error: Can't find the label!\n");
|
||||
else /* Make this a port */
|
||||
newlab->lab_flags = pinNum | pinUse | pinDir | PORT_DIR_MASK;
|
||||
}
|
||||
/* DBAdjustLabels(lefMacro, &rectList->area); */
|
||||
/* If lanno is non-NULL then the first rectangle in the LEF */
|
||||
/* port list is used to modify it. All other LEF port geometry */
|
||||
/* generates new labels in the CellDef. */
|
||||
if (lanno != NULL) lanno = NULL;
|
||||
}
|
||||
|
||||
freeMagic((char *)rectList);
|
||||
|
|
@ -1383,24 +1397,43 @@ LefReadPin(lefMacro, f, pinname, pinNum, oscale, is_imported)
|
|||
case LEF_PORT:
|
||||
if (is_imported)
|
||||
{
|
||||
bool needRect = TRUE;
|
||||
Label *lab;
|
||||
|
||||
LefSkipSection(f, NULL);
|
||||
/* Skip the port geometry but find the pin name and */
|
||||
/* annotate with the use and direction. Note that */
|
||||
/* there may be multiple instances of the label. */
|
||||
/* However, if the label is a point label, then */
|
||||
/* replace it with the geometry from the LEF file. */
|
||||
for (lab = lefMacro->cd_labels; lab; lab = lab->lab_next)
|
||||
{
|
||||
if (!strcmp(lab->lab_text, pinname))
|
||||
{
|
||||
lab->lab_flags &= ~(PORT_USE_MASK | PORT_DIR_MASK |
|
||||
if (GEO_RECTNULL(&lab->lab_rect))
|
||||
break;
|
||||
else
|
||||
{
|
||||
needRect = FALSE;
|
||||
lab->lab_flags &= ~(PORT_USE_MASK | PORT_DIR_MASK |
|
||||
PORT_CLASS_MASK);
|
||||
lab->lab_flags = pinNum | pinUse | pinDir | PORT_DIR_MASK;
|
||||
lab->lab_flags = pinNum | pinUse | pinDir |
|
||||
PORT_DIR_MASK;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (needRect)
|
||||
{
|
||||
if (lab == NULL)
|
||||
DBEraseLabelsByContent(lefMacro, NULL, -1, pinname);
|
||||
LefReadPort(lefMacro, f, pinname, pinNum, pinDir, pinUse,
|
||||
oscale, lab);
|
||||
}
|
||||
else
|
||||
LefSkipSection(f, NULL);
|
||||
}
|
||||
else
|
||||
LefReadPort(lefMacro, f, pinname, pinNum, pinDir, pinUse, oscale);
|
||||
LefReadPort(lefMacro, f, pinname, pinNum, pinDir, pinUse, oscale,
|
||||
NULL);
|
||||
break;
|
||||
case LEF_CAPACITANCE:
|
||||
case LEF_ANTENNADIFF:
|
||||
|
|
@ -1737,10 +1770,18 @@ origin_error:
|
|||
*
|
||||
* For LEF contact types matching magic contact types, size the
|
||||
* LEF contact cut to cover the minimum rectangle in the other
|
||||
* layers that satisfies the CIF/GDS contact generation. Use
|
||||
* the "cifinput" style to determine how much the via layer
|
||||
* needs to grow to make a contact area. If the "cifinput"
|
||||
* style is not defined, then determine rules from "cifoutput".
|
||||
* layers that satisfies the CIF/GDS contact generation.
|
||||
*
|
||||
* NOTE: If a "cifinput" style is defined, then the via
|
||||
* remains the size declared in LEF or DEF file, and the
|
||||
* magic view of the via is generated by applying "cifinput"
|
||||
* rules when painting into the magic database. If no input
|
||||
* style is defined, then the output style rules are used to
|
||||
* modify the cut size to match the way the via is defined in
|
||||
* magic, and the result is painted directly.
|
||||
*
|
||||
* If a "cifinput" style exists, then this routine does
|
||||
* nothing and has no side effects.
|
||||
*
|
||||
*------------------------------------------------------------
|
||||
*/
|
||||
|
|
@ -1750,36 +1791,10 @@ void LefGrowVia(curlayer, currect, lefl)
|
|||
Rect *currect;
|
||||
lefLayer *lefl;
|
||||
{
|
||||
if (DBIsContact(curlayer) && cifCurReadStyle != NULL)
|
||||
{
|
||||
int growSize;
|
||||
/* To be completed: This should be deprecated by moving the entire */
|
||||
/* LEF and DEF read routines to use the cifinput style. */
|
||||
|
||||
/* Get the amount (in magic units) that the layer needs to */
|
||||
/* expand according to the "cifinput" style rules to convert */
|
||||
/* a contact cut to a magic contact layer. */
|
||||
|
||||
growSize = CIFReadGetGrowSize(curlayer);
|
||||
|
||||
/* All internal LEF via geometry values are doubled */
|
||||
growSize <<= 1;
|
||||
|
||||
if (growSize % cifCurReadStyle->crs_scaleFactor == 0)
|
||||
growSize /= cifCurReadStyle->crs_scaleFactor;
|
||||
else
|
||||
growSize = growSize / cifCurReadStyle->crs_scaleFactor + 1;
|
||||
|
||||
if (growSize > 0)
|
||||
{
|
||||
/* cifinput styles expect the cut size to be correct, so */
|
||||
/* there is no check for correctness of the layer. */
|
||||
|
||||
currect->r_xbot = currect->r_xbot - growSize;
|
||||
currect->r_ybot = currect->r_ybot - growSize;
|
||||
currect->r_xtop = currect->r_xtop + growSize;
|
||||
currect->r_ytop = currect->r_ytop + growSize;
|
||||
}
|
||||
}
|
||||
else if (DBIsContact(curlayer) && CIFCurStyle != NULL)
|
||||
if (DBIsContact(curlayer) && CIFCurStyle != NULL)
|
||||
{
|
||||
int edgeSize = 0, contSize, halfSize;
|
||||
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ LefTechLine(sectionName, argc, argv)
|
|||
isContact = DBIsContact(mtype);
|
||||
if (option == LEFTECH_LAYER)
|
||||
option = (isContact) ? LEFTECH_CUT : LEFTECH_ROUTE;
|
||||
else if (isContact && (option != LEFTECH_CUT && option != LEFTECH_CONTACT))
|
||||
else if (isContact && (option != LEFTECH_CUT && option != LEFTECH_CONTACT && option != LEFTECH_OBS))
|
||||
TechError("Attempt to define cut type %s as %s.\n",
|
||||
DBTypeLongNameTbl[mtype], keywords[option]);
|
||||
else if (!isContact && (option == LEFTECH_CUT || option == LEFTECH_CONTACT))
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ lefFileOpen(def, file, suffix, mode, prealfile)
|
|||
*/
|
||||
{
|
||||
char namebuf[512], *name, *endp, *ends;
|
||||
char *locsuffix;
|
||||
char *pptr;
|
||||
int len;
|
||||
FILE *rfile;
|
||||
|
||||
|
|
@ -108,21 +110,26 @@ lefFileOpen(def, file, suffix, mode, prealfile)
|
|||
|
||||
if (endp = strrchr(ends, '.'))
|
||||
{
|
||||
if (!strcmp(endp, suffix))
|
||||
if (strcmp(endp, suffix))
|
||||
{
|
||||
len = endp - name;
|
||||
if (len > sizeof namebuf - 1) len = sizeof namebuf - 1;
|
||||
(void) strncpy(namebuf, name, len);
|
||||
namebuf[len] = '\0';
|
||||
name = namebuf;
|
||||
locsuffix = suffix;
|
||||
}
|
||||
else
|
||||
locsuffix = NULL;
|
||||
}
|
||||
else
|
||||
locsuffix = suffix;
|
||||
|
||||
/* Try once as-is, and if this fails, try stripping any leading */
|
||||
/* path information in case cell is in a read-only directory (mode */
|
||||
/* "read" only, and if def is non-NULL). */
|
||||
|
||||
if ((rfile = PaOpen(name, mode, suffix, Path, CellLibPath, prealfile)) != NULL)
|
||||
if ((rfile = PaOpen(name, mode, locsuffix, Path, CellLibPath, prealfile)) != NULL)
|
||||
return rfile;
|
||||
|
||||
if (def)
|
||||
|
|
@ -634,7 +641,7 @@ lefWriteMacro(def, f, scale, hide)
|
|||
{
|
||||
bool propfound;
|
||||
char *propvalue, *class = NULL;
|
||||
Label *lab;
|
||||
Label *lab, *tlab;
|
||||
Rect boundary, labr;
|
||||
SearchContext scx;
|
||||
CellDef *lefFlatDef;
|
||||
|
|
@ -772,6 +779,20 @@ lefWriteMacro(def, f, scale, hide)
|
|||
else
|
||||
boundary = def->cd_bbox;
|
||||
|
||||
/* If a bounding box has been declared with the FIXED_BBOX property */
|
||||
/* then it takes precedence over def->cd_bbox. */
|
||||
|
||||
if (def->cd_flags & CDFIXEDBBOX)
|
||||
{
|
||||
char *propvalue;
|
||||
bool found;
|
||||
|
||||
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &found);
|
||||
if (found)
|
||||
sscanf(propvalue, "%d %d %d %d", &boundary.r_xbot,
|
||||
&boundary.r_ybot, &boundary.r_xtop, &boundary.r_ytop);
|
||||
}
|
||||
|
||||
/* Write position and size information */
|
||||
|
||||
fprintf(f, " ORIGIN %.4f %.4f ;\n",
|
||||
|
|
@ -927,7 +948,18 @@ lefWriteMacro(def, f, scale, hide)
|
|||
SelectClear();
|
||||
|
||||
if (hide)
|
||||
{
|
||||
SelectChunk(&scx, lab->lab_type, 0, NULL, FALSE);
|
||||
|
||||
/* Note that a sticky label could be placed over multiple */
|
||||
/* tile types, which would cause SelectChunk to fail. So */
|
||||
/* always paint the label type into the label area in */
|
||||
/* SelectDef. */
|
||||
|
||||
pNum = DBPlane(lab->lab_type);
|
||||
DBPaintPlane(SelectDef->cd_planes[pNum], &lab->lab_rect,
|
||||
DBStdPaintTbl(lab->lab_type, pNum), (PaintUndoInfo *) NULL);
|
||||
}
|
||||
else
|
||||
SelectNet(&scx, lab->lab_type, 0, NULL, FALSE);
|
||||
|
||||
|
|
@ -964,15 +996,21 @@ lefWriteMacro(def, f, scale, hide)
|
|||
|
||||
if (maxport >= 0)
|
||||
{
|
||||
/* Sanity check to see if port number is a duplicate */
|
||||
for (lab = lab->lab_next; lab != NULL; lab = lab->lab_next)
|
||||
/* Sanity check to see if port number is a duplicate. ONLY */
|
||||
/* flag this if the other index has a different text, as it */
|
||||
/* is perfectly legal to have multiple ports with the same */
|
||||
/* name and index. */
|
||||
|
||||
for (tlab = lab->lab_next; tlab != NULL; tlab = tlab->lab_next)
|
||||
{
|
||||
if (lab->lab_flags & PORT_DIR_MASK)
|
||||
if ((lab->lab_flags & PORT_NUM_MASK) == idx)
|
||||
{
|
||||
TxError("Port index %d is used more than once\n", idx);
|
||||
idx--;
|
||||
}
|
||||
if (tlab->lab_flags & PORT_DIR_MASK)
|
||||
if ((tlab->lab_flags & PORT_NUM_MASK) == idx)
|
||||
if (strcmp(lab->lab_text, lab->lab_text))
|
||||
{
|
||||
TxError("Index %d is used for ports \"%s\" and \"%s\"\n",
|
||||
idx, lab->lab_text, tlab->lab_text);
|
||||
idx--;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1030,6 +1068,7 @@ lefWriteMacro(def, f, scale, hide)
|
|||
scx.scx_area = labr;
|
||||
SelectClear();
|
||||
SelectChunk(&scx, lab->lab_type, 0, &carea, FALSE);
|
||||
if (GEO_RECTNULL(&carea)) carea = lab->lab_rect;
|
||||
lspace = DRCGetDefaultLayerSpacing(lab->lab_type, lab->lab_type);
|
||||
carea.r_xbot -= lspace;
|
||||
carea.r_ybot -= lspace;
|
||||
|
|
@ -1094,10 +1133,12 @@ lefWriteMacro(def, f, scale, hide)
|
|||
*/
|
||||
|
||||
void
|
||||
LefWriteAll(rootUse, writeTopCell, lefTech)
|
||||
LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, recurse)
|
||||
CellUse *rootUse;
|
||||
bool writeTopCell;
|
||||
bool lefTech;
|
||||
bool lefHide;
|
||||
bool recurse;
|
||||
{
|
||||
CellDef *def, *rootdef;
|
||||
FILE *f;
|
||||
|
|
@ -1116,8 +1157,12 @@ LefWriteAll(rootUse, writeTopCell, lefTech)
|
|||
(void) DBCellSrDefs(0, lefDefInitFunc, (ClientData) 0);
|
||||
|
||||
/* Recursively visit all defs in the tree and push on stack */
|
||||
/* If "recurse" is false, then only the children of the root use */
|
||||
/* are pushed (this is the default behavior). */
|
||||
lefDefStack = StackNew(100);
|
||||
(void) lefDefPushFunc(rootUse);
|
||||
if (writeTopCell)
|
||||
lefDefPushFunc(rootUse, (bool *)NULL);
|
||||
DBCellEnum(rootUse->cu_def, lefDefPushFunc, (ClientData)&recurse);
|
||||
|
||||
/* Open the file for output */
|
||||
|
||||
|
|
@ -1146,8 +1191,7 @@ LefWriteAll(rootUse, writeTopCell, lefTech)
|
|||
{
|
||||
def->cd_client = (ClientData) 0;
|
||||
if (!SigInterruptPending)
|
||||
if ((writeTopCell == TRUE) || (def != rootdef))
|
||||
lefWriteMacro(def, f, scale);
|
||||
lefWriteMacro(def, f, scale, lefHide);
|
||||
}
|
||||
|
||||
/* End the LEF file */
|
||||
|
|
@ -1178,8 +1222,9 @@ lefDefInitFunc(def)
|
|||
*/
|
||||
|
||||
int
|
||||
lefDefPushFunc(use)
|
||||
lefDefPushFunc(use, recurse)
|
||||
CellUse *use;
|
||||
bool *recurse;
|
||||
{
|
||||
CellDef *def = use->cu_def;
|
||||
|
||||
|
|
@ -1188,7 +1233,8 @@ lefDefPushFunc(use)
|
|||
|
||||
def->cd_client = (ClientData) 1;
|
||||
StackPush((ClientData) def, lefDefStack);
|
||||
(void) DBCellEnum(def, lefDefPushFunc, (ClientData) 0);
|
||||
if (recurse && (*recurse))
|
||||
(void) DBCellEnum(def, lefDefPushFunc, (ClientData)recurse);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,11 +13,11 @@ SCMSRC = default.scm box.scm label.scm draw.scm drc.scm \
|
|||
|
||||
include ${MAGICDIR}/defs.mak
|
||||
|
||||
INST_SCMSRC = ${SCMSRC:%=$(DESTDIR)${SCMDIR}/%}
|
||||
INST_SCMSRC = ${SCMSRC:%=$(DESTDIR)${INSTALL_SCMDIR}/%}
|
||||
|
||||
install: ${INST_SCMSRC}
|
||||
|
||||
$(DESTDIR)${SCMDIR}/%: scm/%
|
||||
${CP} scm/$* $(DESTDIR)$(SCMDIR)/$*
|
||||
${CP} scm/$* $(DESTDIR)$(INSTALL_SCMDIR)/$*
|
||||
|
||||
include ${MAGICDIR}/rules.mak
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ EXTRA_LIBS = ${MAGICDIR}/bplane/libbplane.o \
|
|||
${MAGICDIR}/utils/libutils.o \
|
||||
${MAIN_EXTRA_LIBS}
|
||||
|
||||
BITMAPS = up.xbm down.xbm left.xbm right.xbm zoom.xbm lock.xbm
|
||||
DEST_XBM = $(BITMAPS:%=$(DESTDIR)${TCLDIR}/bitmaps/%)
|
||||
BITMAPS = up.gif down.gif left.gif right.gif zoom.gif lock.xbm
|
||||
DEST_XBM = $(BITMAPS:%=$(DESTDIR)${INSTALL_TCLDIR}/bitmaps/%)
|
||||
|
||||
DFLAGS += -DMAGIC_DATE="\"`date`\"" -DCAD_DIR="${LIBDIR}"
|
||||
LIBS += ${GR_LIBS} ${READLINE_LIBS} -lm ${LD_EXTRA_LIBS} \
|
||||
|
|
@ -49,32 +49,32 @@ tclmagic${SHDLIB_EXT}: ${EXTRA_LIBS}
|
|||
-lc ${LIBS} ${LIB_SPECS} ${LDFLAGS}
|
||||
|
||||
proto.magicrc: proto.magicrc.in
|
||||
${SCPP} ${GR_DFLAGS} ${DFLAGS} proto.magicrc.in > proto.magicrc
|
||||
${MCPP} ${GR_DFLAGS} ${DFLAGS} proto.magicrc.in > proto.magicrc
|
||||
|
||||
install: $(DESTDIR)${BINDIR}/${MODULE}${EXEEXT} $(DESTDIR)${SYSDIR}/.magicrc \
|
||||
$(DESTDIR)${SYSDIR}/magicps.pro
|
||||
install: $(DESTDIR)${INSTALL_BINDIR}/${MODULE}${EXEEXT} $(DESTDIR)${INSTALL_SYSDIR}/.magicrc \
|
||||
$(DESTDIR)${INSTALL_SYSDIR}/magicps.pro
|
||||
|
||||
install-tcl: $(DESTDIR)${TCLDIR}/tclmagic${SHDLIB_EXT} $(DESTDIR)${SYSDIR}/.magicrc \
|
||||
$(DESTDIR)${SYSDIR}/.initrc $(DESTDIR)${SYSDIR}/magicps.pro ${DEST_XBM}
|
||||
install-tcl: $(DESTDIR)${INSTALL_TCLDIR}/tclmagic${SHDLIB_EXT} $(DESTDIR)${INSTALL_SYSDIR}/.magicrc \
|
||||
$(DESTDIR)${INSTALL_SYSDIR}/.initrc $(DESTDIR)${INSTALL_SYSDIR}/magicps.pro ${DEST_XBM}
|
||||
|
||||
$(DESTDIR)${TCLDIR}/tclmagic${SHDLIB_EXT}: tclmagic${SHDLIB_EXT}
|
||||
${RM} $(DESTDIR)${TCLDIR}/tclmagic${SHDLIB_EXT}
|
||||
${CP} tclmagic${SHDLIB_EXT} $(DESTDIR)${TCLDIR}/tclmagic${SHDLIB_EXT}
|
||||
$(DESTDIR)${INSTALL_TCLDIR}/tclmagic${SHDLIB_EXT}: tclmagic${SHDLIB_EXT}
|
||||
${RM} $(DESTDIR)${INSTALL_TCLDIR}/tclmagic${SHDLIB_EXT}
|
||||
${CP} tclmagic${SHDLIB_EXT} $(DESTDIR)${INSTALL_TCLDIR}/tclmagic${SHDLIB_EXT}
|
||||
|
||||
$(DESTDIR)${TCLDIR}/bitmaps/%: bitmaps/%
|
||||
${RM} $(DESTDIR)${TCLDIR}/bitmaps/$*
|
||||
${CP} bitmaps/$* $(DESTDIR)${TCLDIR}/bitmaps/$*
|
||||
$(DESTDIR)${INSTALL_TCLDIR}/bitmaps/%: bitmaps/%
|
||||
${RM} $(DESTDIR)${INSTALL_TCLDIR}/bitmaps/$*
|
||||
${CP} bitmaps/$* $(DESTDIR)${INSTALL_TCLDIR}/bitmaps/$*
|
||||
|
||||
$(DESTDIR)${SYSDIR}/.magicrc: proto.magicrc
|
||||
${RM} $(DESTDIR)${SYSDIR}/.magicrc
|
||||
${CP} proto.magicrc $(DESTDIR)${SYSDIR}/.magicrc
|
||||
$(DESTDIR)${INSTALL_SYSDIR}/.magicrc: proto.magicrc
|
||||
${RM} $(DESTDIR)${INSTALL_SYSDIR}/.magicrc
|
||||
${CP} proto.magicrc $(DESTDIR)${INSTALL_SYSDIR}/.magicrc
|
||||
|
||||
$(DESTDIR)${SYSDIR}/.initrc: proto.initrc
|
||||
${RM} $(DESTDIR)${SYSDIR}/.initrc
|
||||
${CP} proto.initrc $(DESTDIR)${SYSDIR}/.initrc
|
||||
$(DESTDIR)${INSTALL_SYSDIR}/.initrc: proto.initrc
|
||||
${RM} $(DESTDIR)${INSTALL_SYSDIR}/.initrc
|
||||
${CP} proto.initrc $(DESTDIR)${INSTALL_SYSDIR}/.initrc
|
||||
|
||||
$(DESTDIR)${SYSDIR}/magicps.pro: magicps.pro
|
||||
${RM} $(DESTDIR)${SYSDIR}/magicps.pro
|
||||
${CP} magicps.pro $(DESTDIR)${SYSDIR}/magicps.pro
|
||||
$(DESTDIR)${INSTALL_SYSDIR}/magicps.pro: magicps.pro
|
||||
${RM} $(DESTDIR)${INSTALL_SYSDIR}/magicps.pro
|
||||
${CP} magicps.pro $(DESTDIR)${INSTALL_SYSDIR}/magicps.pro
|
||||
|
||||
include ${MAGICDIR}/rules.mak
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 103 B |
Binary file not shown.
|
After Width: | Height: | Size: 103 B |
Binary file not shown.
|
After Width: | Height: | Size: 102 B |
Binary file not shown.
|
After Width: | Height: | Size: 102 B |
Binary file not shown.
|
After Width: | Height: | Size: 103 B |
|
|
@ -15,7 +15,7 @@ tcl-main:
|
|||
|
||||
main: net2ir
|
||||
|
||||
install: $(DESTDIR)${BINDIR}/${MODULE}${EXEEXT}
|
||||
install: $(DESTDIR)${INSTALL_BINDIR}/${MODULE}${EXEEXT}
|
||||
|
||||
install-tcl:
|
||||
echo "Nothing to do here"
|
||||
|
|
|
|||
|
|
@ -28,10 +28,10 @@ tclplot${SHDLIB_EXT}: tclplot.o ${OBJS}
|
|||
${CC} ${CFLAGS} ${CPPFLAGS} -o $@ ${LDDL_FLAGS} tclplot.o ${OBJS} \
|
||||
${EXTRA_LIBS} -lc ${LIBS}
|
||||
|
||||
install-tcl: $(DESTDIR)${TCLDIR}/tclplot${SHDLIB_EXT}
|
||||
install-tcl: $(DESTDIR)${INSTALL_TCLDIR}/tclplot${SHDLIB_EXT}
|
||||
|
||||
$(DESTDIR)${TCLDIR}/tclplot${SHDLIB_EXT}: tclplot${SHDLIB_EXT}
|
||||
${RM} $(DESTDIR)${TCLDIR}/tclplot${SHDLIB_EXT}
|
||||
${CP} tclplot${SHDLIB_EXT} $(DESTDIR)${TCLDIR}/tclplot${SHDLIB_EXT}
|
||||
$(DESTDIR)${INSTALL_TCLDIR}/tclplot${SHDLIB_EXT}: tclplot${SHDLIB_EXT}
|
||||
${RM} $(DESTDIR)${INSTALL_TCLDIR}/tclplot${SHDLIB_EXT}
|
||||
${CP} tclplot${SHDLIB_EXT} $(DESTDIR)${INSTALL_TCLDIR}/tclplot${SHDLIB_EXT}
|
||||
|
||||
include ${MAGICDIR}/rules.mak
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ ResMakeRes.o: ResMakeRes.c ../utils/magic.h ../utils/geometry.h \
|
|||
../bplane/bplaneInt.h ../utils/malloc.h ../textio/textio.h \
|
||||
../extract/extract.h ../extract/extractInt.h ../extract/extDebugInt.h \
|
||||
../windows/windows.h ../dbwind/dbwind.h ../utils/tech.h \
|
||||
../textio/txcommands.h ../resis/resis.h
|
||||
../textio/txcommands.h ../resis/resis.h ../cif/CIFint.h
|
||||
ResSimple.o: ResSimple.c ../utils/magic.h ../utils/geometry.h \
|
||||
../utils/geofast.h ../tiles/tile.h ../utils/hash.h ../utils/heap.h \
|
||||
../database/database.h ../bplane/bplane.h ../bplane/bpOpaque.h \
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "textio/txcommands.h"
|
||||
#include "resis/resis.h"
|
||||
|
||||
int resSubTranFunc();
|
||||
int resSubDevFunc();
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
|
|
@ -113,13 +113,13 @@ resAllPortNodes(tile, list)
|
|||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* ResEachTile--for each tile, make a list of all possible current sources/
|
||||
* sinks including contacts, transistors, and junctions. Once this
|
||||
* sinks including contacts, devices, and junctions. Once this
|
||||
* list is made, calculate the resistor nextwork for the tile.
|
||||
*
|
||||
* Results: returns TRUE or FALSE depending on whether a node was
|
||||
* involved in a merge.
|
||||
*
|
||||
* Side Effects: creates Nodes, transistors, junctions, and breakpoints.
|
||||
* Side Effects: creates Nodes, devices, junctions, and breakpoints.
|
||||
*
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
|
|
@ -139,6 +139,7 @@ ResEachTile(tile, startpoint)
|
|||
bool merged;
|
||||
tElement *tcell;
|
||||
tileJunk *tstructs= (tileJunk *)(tile->ti_client);
|
||||
ExtDevice *devptr;
|
||||
|
||||
ResTileCount++;
|
||||
|
||||
|
|
@ -165,24 +166,24 @@ ResEachTile(tile, startpoint)
|
|||
resNodeIsPort(resptr, x, y, tile);
|
||||
}
|
||||
|
||||
if TTMaskHasType(&(ExtCurStyle->exts_transMask), t1)
|
||||
if TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t1)
|
||||
{
|
||||
/*
|
||||
* The transistor is put in the center of the tile. This is fine
|
||||
* for single tile transistors, but not as good for multiple ones.
|
||||
* The device is put in the center of the tile. This is fine
|
||||
* for single tile device, but not as good for multiple ones.
|
||||
*/
|
||||
|
||||
if (tstructs->tj_status & RES_TILE_TRAN)
|
||||
if (tstructs->tj_status & RES_TILE_DEV)
|
||||
{
|
||||
if (tstructs->transistorList->rt_gate == NULL)
|
||||
if (tstructs->deviceList->rd_fet_gate == NULL)
|
||||
{
|
||||
int x = (LEFT(tile) + RIGHT(tile)) >> 1;
|
||||
int y = (TOP(tile) + BOTTOM(tile)) >> 1;
|
||||
|
||||
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
||||
tstructs->transistorList->rt_gate = resptr;
|
||||
tstructs->deviceList->rd_fet_gate = resptr;
|
||||
tcell = (tElement *) mallocMagic((unsigned)(sizeof(tElement)));
|
||||
tcell->te_thist = tstructs->transistorList;
|
||||
tcell->te_thist = tstructs->deviceList;
|
||||
tcell->te_nextt = NULL;
|
||||
|
||||
InitializeNode(resptr, x, y, RES_NODE_JUNCTION);
|
||||
|
|
@ -219,7 +220,7 @@ ResEachTile(tile, startpoint)
|
|||
{
|
||||
(void)DBSrPaintArea((Tile *) NULL,
|
||||
ResUse->cu_def->cd_planes[pNum],
|
||||
&tileArea, mask, resSubTranFunc, (ClientData) tile);
|
||||
&tileArea, mask, resSubDevFunc, (ClientData) tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -250,13 +251,14 @@ ResEachTile(tile, startpoint)
|
|||
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp))
|
||||
{
|
||||
t2 = TiGetRightType(tp);
|
||||
if(TTMaskHasType(&(ExtCurStyle->exts_transMask), t2) &&
|
||||
TTMaskHasType(&(ExtCurStyle->exts_transSDTypes[t2][0]), t1))
|
||||
/* found transistor */
|
||||
devptr = ExtCurStyle->exts_device[t2];
|
||||
if(TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2) &&
|
||||
TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), t1))
|
||||
/* found device */
|
||||
{
|
||||
xj = LEFT(tile);
|
||||
yj = (TOP(tp) + BOTTOM(tp)) >> 1;
|
||||
ResNewSDTransistor(tile, tp, xj, yj, RIGHTEDGE, &ResNodeQueue);
|
||||
ResNewSDDevice(tile, tp, xj, yj, RIGHTEDGE, &ResNodeQueue);
|
||||
}
|
||||
if TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2)
|
||||
/* tile is junction */
|
||||
|
|
@ -272,13 +274,14 @@ ResEachTile(tile, startpoint)
|
|||
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp=LB(tp))
|
||||
{
|
||||
t2 = TiGetLeftType(tp);
|
||||
if(TTMaskHasType(&(ExtCurStyle->exts_transMask), t2) &&
|
||||
TTMaskHasType(&(ExtCurStyle->exts_transSDTypes[t2][0]), t1))
|
||||
/* found transistor */
|
||||
devptr = ExtCurStyle->exts_device[t2];
|
||||
if(TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2) &&
|
||||
TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), t1))
|
||||
/* found device */
|
||||
{
|
||||
xj = RIGHT(tile);
|
||||
yj = (TOP(tp)+BOTTOM(tp))>>1;
|
||||
ResNewSDTransistor(tile, tp, xj, yj, LEFTEDGE, &ResNodeQueue);
|
||||
ResNewSDDevice(tile, tp, xj, yj, LEFTEDGE, &ResNodeQueue);
|
||||
}
|
||||
if TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1], t2)
|
||||
/* tile is junction */
|
||||
|
|
@ -294,13 +297,14 @@ ResEachTile(tile, startpoint)
|
|||
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp=BL(tp))
|
||||
{
|
||||
t2 = TiGetBottomType(tp);
|
||||
if(TTMaskHasType(&(ExtCurStyle->exts_transMask),t2) &&
|
||||
TTMaskHasType(&(ExtCurStyle->exts_transSDTypes[t2][0]),t1))
|
||||
/* found transistor */
|
||||
devptr = ExtCurStyle->exts_device[t2];
|
||||
if(TTMaskHasType(&(ExtCurStyle->exts_deviceMask),t2) &&
|
||||
TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),t1))
|
||||
/* found device */
|
||||
{
|
||||
yj = TOP(tile);
|
||||
xj = (LEFT(tp)+RIGHT(tp))>>1;
|
||||
ResNewSDTransistor(tile,tp,xj,yj,BOTTOMEDGE, &ResNodeQueue);
|
||||
ResNewSDDevice(tile,tp,xj,yj,BOTTOMEDGE, &ResNodeQueue);
|
||||
}
|
||||
if TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1],t2)
|
||||
/* tile is junction */
|
||||
|
|
@ -315,13 +319,14 @@ ResEachTile(tile, startpoint)
|
|||
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp))
|
||||
{
|
||||
t2 = TiGetTopType(tp);
|
||||
if(TTMaskHasType(&(ExtCurStyle->exts_transMask), t2) &&
|
||||
TTMaskHasType(&(ExtCurStyle->exts_transSDTypes[t2][0]), t1))
|
||||
/* found transistor */
|
||||
devptr = ExtCurStyle->exts_device[t2];
|
||||
if(TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2) &&
|
||||
TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), t1))
|
||||
/* found device */
|
||||
{
|
||||
yj = BOTTOM(tile);
|
||||
xj = (LEFT(tp) + RIGHT(tp)) >> 1;
|
||||
ResNewSDTransistor(tile, tp, xj, yj, TOPEDGE, &ResNodeQueue);
|
||||
ResNewSDDevice(tile, tp, xj, yj, TOPEDGE, &ResNodeQueue);
|
||||
}
|
||||
if TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2)
|
||||
/* tile is junction */
|
||||
|
|
@ -344,7 +349,7 @@ ResEachTile(tile, startpoint)
|
|||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* resSubTranFunc -- called when DBSrPaintArea finds a transistor within
|
||||
* resSubDevFunc -- called when DBSrPaintArea finds a device within
|
||||
* a substrate area.
|
||||
*
|
||||
* Results: always returns 0 to keep search going.
|
||||
|
|
@ -355,7 +360,7 @@ ResEachTile(tile, startpoint)
|
|||
*/
|
||||
|
||||
int
|
||||
resSubTranFunc(tile,tp)
|
||||
resSubDevFunc(tile,tp)
|
||||
Tile *tile,*tp;
|
||||
|
||||
|
||||
|
|
@ -365,13 +370,13 @@ resSubTranFunc(tile,tp)
|
|||
tElement *tcell;
|
||||
int x,y;
|
||||
|
||||
if (junk->transistorList->rt_subs== NULL)
|
||||
if (junk->deviceList->rd_fet_subs == NULL)
|
||||
{
|
||||
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
||||
junk->transistorList->rt_subs = resptr;
|
||||
junk->tj_status |= RES_TILE_TRAN;
|
||||
junk->deviceList->rd_fet_subs = resptr;
|
||||
junk->tj_status |= RES_TILE_DEV;
|
||||
tcell = (tElement *) mallocMagic((unsigned)(sizeof(tElement)));
|
||||
tcell->te_thist = junk->transistorList;
|
||||
tcell->te_thist = junk->deviceList;
|
||||
tcell->te_nextt = NULL;
|
||||
x = (LEFT(tile)+RIGHT(tile))>>1;
|
||||
y = (TOP(tile)+BOTTOM(tile))>>1;
|
||||
|
|
|
|||
|
|
@ -43,16 +43,16 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
*/
|
||||
|
||||
void
|
||||
ResSanityChecks(nodename,resistorList,nodeList,tranlist)
|
||||
ResSanityChecks(nodename,resistorList,nodeList,devlist)
|
||||
char *nodename;
|
||||
resResistor *resistorList;
|
||||
resNode *nodeList;
|
||||
resTransistor *tranlist;
|
||||
resDevice *devlist;
|
||||
|
||||
{
|
||||
resResistor *resistor;
|
||||
resNode *node;
|
||||
resTransistor *tran;
|
||||
resDevice *dev;
|
||||
resElement *rcell;
|
||||
static Stack *resSanityStack = NULL;
|
||||
int reached,foundorigin;
|
||||
|
|
@ -107,29 +107,29 @@ ResSanityChecks(nodename,resistorList,nodeList,tranlist)
|
|||
}
|
||||
resistor->rr_status &= ~RES_REACHED_RESISTOR;
|
||||
}
|
||||
for (tran = tranlist; tran != NULL; tran = tran->rt_nextTran)
|
||||
for (dev = devlist; dev != NULL; dev = dev->rd_nextDev)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (tran->rt_status & RES_TRAN_PLUG) continue;
|
||||
if (dev->rd_status & RES_DEV_PLUG) continue;
|
||||
reached = FALSE;
|
||||
for (i=0;i != RT_TERMCOUNT;i++)
|
||||
for (i=0;i != dev->rd_nterms;i++)
|
||||
{
|
||||
if (tran->rt_terminals[i] != NULL)
|
||||
if (dev->rd_terminals[i] != NULL)
|
||||
{
|
||||
reached = TRUE;
|
||||
if ((tran->rt_terminals[i]->rn_status & RES_REACHED_NODE) == 0)
|
||||
if ((dev->rd_terminals[i]->rn_status & RES_REACHED_NODE) == 0)
|
||||
{
|
||||
TxError("Transistor node %d unreached in %s\n",i,nodename);
|
||||
TxError("Device node %d unreached in %s\n",i,nodename);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (reached == 0)
|
||||
{
|
||||
TxError("Unreached transistor in %s at %d %d\n",
|
||||
TxError("Unreached device in %s at %d %d\n",
|
||||
nodename,
|
||||
tran->rt_inside.r_xbot,
|
||||
tran->rt_inside.r_ybot);
|
||||
dev->rd_inside.r_xbot,
|
||||
dev->rd_inside.r_ybot);
|
||||
}
|
||||
}
|
||||
foundorigin = 0;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ extern int dbcConnectFuncDCS();
|
|||
extern int resSubSearchFunc();
|
||||
#endif
|
||||
|
||||
static ResTranTile *TransList = NULL;
|
||||
static ResDevTile *DevList = NULL;
|
||||
static TileTypeBitMask DiffTypeBitMask;
|
||||
TileTypeBitMask ResSubsTypeBitMask;
|
||||
|
||||
|
|
@ -73,14 +73,14 @@ extern void ResCalcPerimOverlap();
|
|||
*
|
||||
* dbcConnectFuncDCS -- the same as dbcConnectFunc, except that it does
|
||||
* some extra searching around diffusion tiles looking for
|
||||
* transistors.
|
||||
* devices.
|
||||
*
|
||||
* Results:
|
||||
* Always returns 0 to keep the search from aborting.
|
||||
*
|
||||
* Side effects:
|
||||
* Adds a new record to the current check list. May also add new
|
||||
* ResTranTile structures.
|
||||
* ResDevTile structures.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
@ -92,8 +92,8 @@ dbcConnectFuncDCS(tile, cx)
|
|||
|
||||
{
|
||||
struct conSrArg2 *csa2;
|
||||
Rect tileArea, *srArea, tranArea, newarea;
|
||||
ResTranTile *thisTran;
|
||||
Rect tileArea, *srArea, devArea, newarea;
|
||||
ResDevTile *thisDev;
|
||||
TileTypeBitMask notConnectMask, *connectMask;
|
||||
Tile *tp;
|
||||
TileType t2, t1, loctype, ctype;
|
||||
|
|
@ -102,6 +102,7 @@ dbcConnectFuncDCS(tile, cx)
|
|||
SearchContext scx2;
|
||||
int pNum;
|
||||
CellDef *def;
|
||||
ExtDevice *devptr;
|
||||
|
||||
TiToRect(tile, &tileArea);
|
||||
srArea = &scx->scx_area;
|
||||
|
|
@ -121,79 +122,83 @@ dbcConnectFuncDCS(tile, cx)
|
|||
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp))
|
||||
{
|
||||
t2 = TiGetType(tp);
|
||||
if (TTMaskHasType(&(ExtCurStyle->exts_transMask),t2) &&
|
||||
TTMaskHasType(&(ExtCurStyle->exts_transSDTypes[t2][0]),t1))
|
||||
devptr = ExtCurStyle->exts_device[t2];
|
||||
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask),t2) &&
|
||||
TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),t1))
|
||||
{
|
||||
TiToRect(tp, &tranArea);
|
||||
thisTran = (ResTranTile *) mallocMagic((unsigned)(sizeof(ResTranTile)));
|
||||
ResCalcPerimOverlap(thisTran,tp);
|
||||
GeoTransRect(&scx->scx_trans, &tranArea, &thisTran->area);
|
||||
thisTran->type = TiGetType(tp);
|
||||
thisTran->nextTran = TransList;
|
||||
TransList = thisTran;
|
||||
TiToRect(tp, &devArea);
|
||||
thisDev = (ResDevTile *) mallocMagic((unsigned)(sizeof(ResDevTile)));
|
||||
ResCalcPerimOverlap(thisDev,tp);
|
||||
GeoTransRect(&scx->scx_trans, &devArea, &thisDev->area);
|
||||
thisDev->type = TiGetType(tp);
|
||||
thisDev->nextDev = DevList;
|
||||
DevList = thisDev;
|
||||
}
|
||||
}
|
||||
/*right*/
|
||||
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp=LB(tp))
|
||||
{
|
||||
t2 = TiGetType(tp);
|
||||
if (TTMaskHasType(&(ExtCurStyle->exts_transMask),t2) &&
|
||||
TTMaskHasType(&(ExtCurStyle->exts_transSDTypes[t2][0]),t1))
|
||||
devptr = ExtCurStyle->exts_device[t2];
|
||||
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask),t2) &&
|
||||
TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),t1))
|
||||
{
|
||||
TiToRect(tp, &tranArea);
|
||||
thisTran = (ResTranTile *) mallocMagic((unsigned)(sizeof(ResTranTile)));
|
||||
GeoTransRect(&scx->scx_trans, &tranArea, &thisTran->area);
|
||||
thisTran->type = TiGetType(tp);
|
||||
thisTran->nextTran = TransList;
|
||||
TransList = thisTran;
|
||||
ResCalcPerimOverlap(thisTran,tp);
|
||||
TiToRect(tp, &devArea);
|
||||
thisDev = (ResDevTile *) mallocMagic((unsigned)(sizeof(ResDevTile)));
|
||||
GeoTransRect(&scx->scx_trans, &devArea, &thisDev->area);
|
||||
thisDev->type = TiGetType(tp);
|
||||
thisDev->nextDev = DevList;
|
||||
DevList = thisDev;
|
||||
ResCalcPerimOverlap(thisDev,tp);
|
||||
}
|
||||
}
|
||||
/*top*/
|
||||
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp=BL(tp))
|
||||
{
|
||||
t2 = TiGetType(tp);
|
||||
if (TTMaskHasType(&(ExtCurStyle->exts_transMask),t2) &&
|
||||
TTMaskHasType(&(ExtCurStyle->exts_transSDTypes[t2][0]),t1))
|
||||
devptr = ExtCurStyle->exts_device[t2];
|
||||
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask),t2) &&
|
||||
TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),t1))
|
||||
{
|
||||
TiToRect(tp, &tranArea);
|
||||
thisTran = (ResTranTile *) mallocMagic((unsigned)(sizeof(ResTranTile)));
|
||||
GeoTransRect(&scx->scx_trans, &tranArea, &thisTran->area);
|
||||
thisTran->type = TiGetType(tp);
|
||||
thisTran->nextTran = TransList;
|
||||
TransList = thisTran;
|
||||
ResCalcPerimOverlap(thisTran,tp);
|
||||
TiToRect(tp, &devArea);
|
||||
thisDev = (ResDevTile *) mallocMagic((unsigned)(sizeof(ResDevTile)));
|
||||
GeoTransRect(&scx->scx_trans, &devArea, &thisDev->area);
|
||||
thisDev->type = TiGetType(tp);
|
||||
thisDev->nextDev = DevList;
|
||||
DevList = thisDev;
|
||||
ResCalcPerimOverlap(thisDev,tp);
|
||||
}
|
||||
}
|
||||
/*bottom */
|
||||
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp))
|
||||
{
|
||||
t2 = TiGetType(tp);
|
||||
if (TTMaskHasType(&(ExtCurStyle->exts_transMask),t2) &&
|
||||
TTMaskHasType(&(ExtCurStyle->exts_transSDTypes[t2][0]),t1))
|
||||
devptr = ExtCurStyle->exts_device[t2];
|
||||
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask),t2) &&
|
||||
TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),t1))
|
||||
{
|
||||
TiToRect(tp, &tranArea);
|
||||
thisTran = (ResTranTile *) mallocMagic((unsigned)(sizeof(ResTranTile)));
|
||||
GeoTransRect(&scx->scx_trans, &tranArea, &thisTran->area);
|
||||
thisTran->type = TiGetType(tp);
|
||||
thisTran->nextTran = TransList;
|
||||
TransList = thisTran;
|
||||
ResCalcPerimOverlap(thisTran,tp);
|
||||
TiToRect(tp, &devArea);
|
||||
thisDev = (ResDevTile *) mallocMagic((unsigned)(sizeof(ResDevTile)));
|
||||
GeoTransRect(&scx->scx_trans, &devArea, &thisDev->area);
|
||||
thisDev->type = TiGetType(tp);
|
||||
thisDev->nextDev = DevList;
|
||||
DevList = thisDev;
|
||||
ResCalcPerimOverlap(thisDev,tp);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if TTMaskHasType(&(ExtCurStyle->exts_transMask),t1)
|
||||
else if TTMaskHasType(&(ExtCurStyle->exts_deviceMask),t1)
|
||||
{
|
||||
TiToRect(tile, &tranArea);
|
||||
thisTran = (ResTranTile *) mallocMagic((unsigned)(sizeof(ResTranTile)));
|
||||
ResCalcPerimOverlap(thisTran,tile);
|
||||
GeoTransRect(&scx->scx_trans, &tranArea, &thisTran->area);
|
||||
thisTran->type = TiGetType(tile);
|
||||
thisTran->nextTran = TransList;
|
||||
TransList = thisTran;
|
||||
TiToRect(tile, &devArea);
|
||||
thisDev = (ResDevTile *) mallocMagic((unsigned)(sizeof(ResDevTile)));
|
||||
ResCalcPerimOverlap(thisDev,tile);
|
||||
GeoTransRect(&scx->scx_trans, &devArea, &thisDev->area);
|
||||
thisDev->type = TiGetType(tile);
|
||||
thisDev->nextDev = DevList;
|
||||
DevList = thisDev;
|
||||
}
|
||||
/* in some cases (primarily bipolar technology), we'll want to extract
|
||||
transistors whose substrate terminals are part of the given region.
|
||||
devices whose substrate terminals are part of the given region.
|
||||
The following does that check. (10-11-88)
|
||||
*/
|
||||
#ifdef ARIEL
|
||||
|
|
@ -333,8 +338,8 @@ dbcConnectFuncDCS(tile, cx)
|
|||
*/
|
||||
|
||||
void
|
||||
ResCalcPerimOverlap(trans, tile)
|
||||
ResTranTile *trans;
|
||||
ResCalcPerimOverlap(dev, tile)
|
||||
ResDevTile *dev;
|
||||
Tile *tile;
|
||||
|
||||
{
|
||||
|
|
@ -342,7 +347,7 @@ ResCalcPerimOverlap(trans, tile)
|
|||
int t1;
|
||||
int overlap;
|
||||
|
||||
trans->perim = (TOP(tile)-BOTTOM(tile)-LEFT(tile)+RIGHT(tile))<<1;
|
||||
dev->perim = (TOP(tile)-BOTTOM(tile)-LEFT(tile)+RIGHT(tile))<<1;
|
||||
overlap =0;
|
||||
|
||||
t1 = TiGetType(tile);
|
||||
|
|
@ -386,7 +391,7 @@ ResCalcPerimOverlap(trans, tile)
|
|||
}
|
||||
|
||||
}
|
||||
trans->overlap = overlap;
|
||||
dev->overlap = overlap;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -399,7 +404,7 @@ ResCalcPerimOverlap(trans, tile)
|
|||
* dbcConnectFuncDCS.
|
||||
*
|
||||
* Results:
|
||||
* Linked list of transistors.
|
||||
* Linked list of devices.
|
||||
*
|
||||
* Side effects:
|
||||
* The contents of the result cell are modified.
|
||||
|
|
@ -407,7 +412,7 @@ ResCalcPerimOverlap(trans, tile)
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
ResTranTile *
|
||||
ResDevTile *
|
||||
DBTreeCopyConnectDCS(scx, mask, xMask, connect, area, destUse)
|
||||
SearchContext *scx;
|
||||
TileTypeBitMask *mask;
|
||||
|
|
@ -419,12 +424,13 @@ DBTreeCopyConnectDCS(scx, mask, xMask, connect, area, destUse)
|
|||
{
|
||||
static int first = 1;
|
||||
struct conSrArg2 csa2;
|
||||
int tran, pNum;
|
||||
char *tran_name;
|
||||
int dev, pNum;
|
||||
char *dev_name;
|
||||
TileTypeBitMask *newmask;
|
||||
ResTranTile *CurrentT;
|
||||
ResDevTile *CurrentT;
|
||||
CellDef *def = destUse->cu_def;
|
||||
TileType newtype;
|
||||
ExtDevice *devptr;
|
||||
|
||||
csa2.csa2_use = destUse;
|
||||
csa2.csa2_xMask = xMask;
|
||||
|
|
@ -441,21 +447,22 @@ DBTreeCopyConnectDCS(scx, mask, xMask, connect, area, destUse)
|
|||
{
|
||||
TTMaskZero(&DiffTypeBitMask);
|
||||
TTMaskZero(&ResSubsTypeBitMask);
|
||||
for (tran = TT_TECHDEPBASE; tran < TT_MAXTYPES; tran++)
|
||||
for (dev = TT_TECHDEPBASE; dev < TT_MAXTYPES; dev++)
|
||||
{
|
||||
tran_name = (ExtCurStyle->exts_transName)[tran];
|
||||
if ((tran_name != NULL) && (strcmp(tran_name, "None")))
|
||||
devptr = ExtCurStyle->exts_device[dev];
|
||||
if ((devptr != NULL) && ((dev_name = devptr->exts_deviceName) != NULL)
|
||||
&& (strcmp(dev_name, "None")))
|
||||
{
|
||||
TTMaskSetMask(&DiffTypeBitMask,
|
||||
&(ExtCurStyle->exts_transSDTypes[tran][0]));
|
||||
&(devptr->exts_deviceSDTypes[0]));
|
||||
TTMaskSetMask(&ResSubsTypeBitMask,
|
||||
&(ExtCurStyle->exts_transSubstrateTypes[tran]));
|
||||
&(devptr->exts_deviceSubstrateTypes));
|
||||
}
|
||||
}
|
||||
first = 0;
|
||||
}
|
||||
|
||||
TransList = NULL;
|
||||
DevList = NULL;
|
||||
DBTreeSrTiles(scx, mask, xMask, dbcConnectFuncDCS, (ClientData) &csa2);
|
||||
while (csa2.csa2_top >= 0)
|
||||
{
|
||||
|
|
@ -471,7 +478,7 @@ DBTreeCopyConnectDCS(scx, mask, xMask, connect, area, destUse)
|
|||
}
|
||||
freeMagic((char *)csa2.csa2_list);
|
||||
|
||||
for (CurrentT = TransList; CurrentT != NULL; CurrentT=CurrentT->nextTran)
|
||||
for (CurrentT = DevList; CurrentT != NULL; CurrentT=CurrentT->nextDev)
|
||||
{
|
||||
TileType t = CurrentT->type;
|
||||
TileType nt;
|
||||
|
|
@ -489,7 +496,7 @@ DBTreeCopyConnectDCS(scx, mask, xMask, connect, area, destUse)
|
|||
}
|
||||
|
||||
DBReComputeBbox(def);
|
||||
return(TransList);
|
||||
return(DevList);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -499,7 +506,7 @@ DBTreeCopyConnectDCS(scx, mask, xMask, connect, area, destUse)
|
|||
*
|
||||
* resSubSearchFunc --
|
||||
*
|
||||
* called when DBSrPaintArea finds a transistor within
|
||||
* called when DBSrPaintArea finds a device within
|
||||
* a substrate area.
|
||||
*
|
||||
* Results:
|
||||
|
|
@ -517,22 +524,24 @@ resSubSearchFunc(tile,cx)
|
|||
|
||||
|
||||
{
|
||||
ResTranTile *thisTran;
|
||||
Rect tranArea;
|
||||
ResDevTile *thisDev;
|
||||
Rect devArea;
|
||||
TileType t = TiGetType(tile);
|
||||
ExtDevice *devptr;
|
||||
|
||||
/* Right now, we're only going to extract substrate terminals for
|
||||
devices with only one diffusion terminal, principally bipolar
|
||||
devices.
|
||||
*/
|
||||
if (ExtCurStyle->exts_transSDCount[t] >1) return 0;
|
||||
TiToRect(tile, &tranArea);
|
||||
thisTran = (ResTranTile *) mallocMagic((unsigned)(sizeof(ResTranTile)));
|
||||
GeoTransRect(&cx->tc_scx->scx_trans, &tranArea, &thisTran->area);
|
||||
thisTran->type = t;
|
||||
thisTran->nextTran = TransList;
|
||||
TransList = thisTran;
|
||||
ResCalcPerimOverlap(thisTran,tile);
|
||||
devptr = ExtCurStyle->exts_device[t]
|
||||
if (devptr->exts_deviceSDCount >1) return 0;
|
||||
TiToRect(tile, &devArea);
|
||||
thisDev = (ResDevTile *) mallocMagic((unsigned)(sizeof(ResDevTile)));
|
||||
GeoTransRect(&cx->tc_scx->scx_trans, &devArea, &thisDev->area);
|
||||
thisDev->type = t;
|
||||
thisDev->nextDev = DevList;
|
||||
DevList = thisDev;
|
||||
ResCalcPerimOverlap(thisDev,tile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,42 +101,42 @@ ResPrintResistorList(fp,list)
|
|||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResPrintTransistorList--
|
||||
* ResPrintDeviceList--
|
||||
*
|
||||
*
|
||||
* Results: none
|
||||
*
|
||||
* Side effects: prints out transistors in list to file fp.
|
||||
* Side effects: prints out devices in list to file fp.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
ResPrintTransistorList(fp,list)
|
||||
ResPrintDeviceList(fp,list)
|
||||
FILE *fp;
|
||||
resTransistor *list;
|
||||
resDevice *list;
|
||||
|
||||
{
|
||||
static char termtype[] = {'g','s','d','c'};
|
||||
int i;
|
||||
for (; list != NULL; list = list->rt_nextTran)
|
||||
for (; list != NULL; list = list->rd_nextDev)
|
||||
{
|
||||
if (list->rt_status & RES_TRAN_PLUG) continue;
|
||||
if (list->rd_status & RES_DEV_PLUG) continue;
|
||||
if (fp == stdout)
|
||||
TxPrintf("t w %d l %d ", list->rt_width, list->rt_length);
|
||||
TxPrintf("t w %d l %d ", list->rd_width, list->rd_length);
|
||||
else
|
||||
fprintf(fp, "t w %d l %d ", list->rt_width, list->rt_length);
|
||||
for (i=0; i!= RT_TERMCOUNT;i++)
|
||||
fprintf(fp, "t w %d l %d ", list->rd_width, list->rd_length);
|
||||
for (i = 0; i != list->rd_nterms; i++)
|
||||
{
|
||||
if (list->rt_terminals[i] == NULL) continue;
|
||||
if (list->rd_terminals[i] == NULL) continue;
|
||||
if (fp == stdout)
|
||||
TxPrintf("%c (%d,%d) ",termtype[i],
|
||||
list->rt_terminals[i]->rn_loc.p_x,
|
||||
list->rt_terminals[i]->rn_loc.p_y);
|
||||
list->rd_terminals[i]->rn_loc.p_x,
|
||||
list->rd_terminals[i]->rn_loc.p_y);
|
||||
else
|
||||
fprintf(fp, "%c (%d,%d) ",termtype[i],
|
||||
list->rt_terminals[i]->rn_loc.p_x,
|
||||
list->rt_terminals[i]->rn_loc.p_y);
|
||||
list->rd_terminals[i]->rn_loc.p_x,
|
||||
list->rd_terminals[i]->rn_loc.p_y);
|
||||
|
||||
}
|
||||
if (fp == stdout)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue