2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ExtCell.c --
|
|
|
|
|
*
|
|
|
|
|
* Circuit extraction.
|
|
|
|
|
* Extract a single cell.
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
* * 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. *
|
2017-04-25 14:41:48 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/extract/ExtCell.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2023-06-14 19:55:59 +02:00
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <unistd.h>
|
2017-04-25 14:41:48 +02:00
|
|
|
#include <math.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include "utils/magic.h"
|
|
|
|
|
#include "utils/geometry.h"
|
|
|
|
|
#include "utils/styles.h"
|
|
|
|
|
#include "tiles/tile.h"
|
|
|
|
|
#include "utils/hash.h"
|
|
|
|
|
#include "database/database.h"
|
|
|
|
|
#include "utils/malloc.h"
|
|
|
|
|
#include "textio/textio.h"
|
|
|
|
|
#include "debug/debug.h"
|
|
|
|
|
#include "extract/extract.h"
|
|
|
|
|
#include "extract/extractInt.h"
|
|
|
|
|
#include "utils/signals.h"
|
|
|
|
|
#include "utils/stack.h"
|
|
|
|
|
#include "utils/utils.h"
|
|
|
|
|
#include "windows/windows.h"
|
|
|
|
|
#include "utils/main.h"
|
|
|
|
|
#include "utils/undo.h"
|
|
|
|
|
|
|
|
|
|
/* ------------------------ Data local to this file ------------------- */
|
|
|
|
|
|
|
|
|
|
/* Forward declarations */
|
|
|
|
|
int extOutputUsesFunc();
|
|
|
|
|
|
2021-04-05 22:03:54 +02:00
|
|
|
Plane* extCellFile();
|
2017-04-25 14:41:48 +02:00
|
|
|
void extHeader();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* ExtCell --
|
|
|
|
|
*
|
|
|
|
|
* Extract the cell 'def', plus all its interactions with its subcells.
|
|
|
|
|
* Place the result in the file named 'outName'.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Creates the file 'outName'.ext and writes to it.
|
|
|
|
|
* May leave feedback information where errors were encountered.
|
2021-12-31 20:02:58 +01:00
|
|
|
* Upon return, extNumErrors contains the number of (likely serious)
|
|
|
|
|
* errors encountered while extracting 'def', and extNumWarnings
|
|
|
|
|
* contains the number of warnings.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
2021-04-05 22:03:54 +02:00
|
|
|
Plane *
|
2017-04-25 14:41:48 +02:00
|
|
|
ExtCell(def, outName, doLength)
|
|
|
|
|
CellDef *def; /* Cell being extracted */
|
|
|
|
|
char *outName; /* Name of output file; if NULL, derive from def name */
|
|
|
|
|
bool doLength; /* If TRUE, extract pathlengths from drivers to
|
|
|
|
|
* receivers (the names are stored in ExtLength.c).
|
|
|
|
|
* Should only be TRUE for the root cell in a
|
|
|
|
|
* hierarchy.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
char *filename;
|
2022-04-06 03:33:15 +02:00
|
|
|
FILE *f = NULL;
|
2021-04-05 22:03:54 +02:00
|
|
|
Plane *savePlane;
|
2020-03-22 01:57:11 +01:00
|
|
|
|
2022-04-06 03:33:15 +02:00
|
|
|
/* Incremental extraction: If the cell is marked for no extraction,
|
|
|
|
|
* then just prepare the substrate plane and return it to the caller.
|
|
|
|
|
*/
|
|
|
|
|
if (def->cd_flags & CDNOEXTRACT)
|
|
|
|
|
return extPrepSubstrate(def);
|
|
|
|
|
|
2026-01-30 22:55:08 +01:00
|
|
|
f = ExtFileOpen(def, outName, "w", &filename);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
TxPrintf("Extracting %s into %s:\n", def->cd_name, filename);
|
|
|
|
|
|
|
|
|
|
if (f == NULL)
|
|
|
|
|
{
|
|
|
|
|
#ifdef MAGIC_WRAPPER
|
|
|
|
|
TxError("Cannot open output file.\n");
|
|
|
|
|
#else
|
|
|
|
|
TxError("Cannot open output file: ");
|
|
|
|
|
perror(filename);
|
|
|
|
|
#endif
|
2021-06-13 02:29:09 +02:00
|
|
|
return NULL;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-31 20:02:58 +01:00
|
|
|
extNumErrors = extNumWarnings = 0;
|
2021-04-05 22:03:54 +02:00
|
|
|
savePlane = extCellFile(def, f, doLength);
|
2022-04-06 03:33:15 +02:00
|
|
|
if (f != NULL) fclose(f);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2021-12-31 20:02:58 +01:00
|
|
|
if (extNumErrors > 0 || extNumWarnings > 0)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
TxPrintf("%s:", def->cd_name);
|
2021-12-31 20:02:58 +01:00
|
|
|
if (extNumErrors > 0)
|
2021-12-31 20:06:04 +01:00
|
|
|
TxPrintf(" %d error%s",
|
2021-12-31 20:02:58 +01:00
|
|
|
extNumErrors, extNumErrors != 1 ? "s" : "");
|
2017-04-25 14:41:48 +02:00
|
|
|
if (extNumWarnings > 0)
|
|
|
|
|
TxPrintf(" %d warning%s",
|
|
|
|
|
extNumWarnings, extNumWarnings != 1 ? "s" : "");
|
|
|
|
|
TxPrintf("\n");
|
|
|
|
|
}
|
2021-04-05 22:03:54 +02:00
|
|
|
return savePlane;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
2026-01-30 22:55:08 +01:00
|
|
|
* ExtFileOpen --
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* Open the .ext file corresponding to a .mag file.
|
|
|
|
|
* If def->cd_file is non-NULL, the .ext file is just def->cd_file with
|
|
|
|
|
* the trailing .mag replaced by .ext. Otherwise, the .ext file is just
|
|
|
|
|
* def->cd_name followed by .ext.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Return a pointer to an open FILE, or NULL if the .ext
|
|
|
|
|
* file could not be opened in the specified mode.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Opens a file.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
FILE *
|
2026-01-30 22:55:08 +01:00
|
|
|
ExtFileOpen(def, file, mode, prealfile)
|
2017-04-25 14:41:48 +02:00
|
|
|
CellDef *def; /* Cell whose .ext file is to be written */
|
|
|
|
|
char *file; /* If non-NULL, open 'name'.ext; otherwise,
|
|
|
|
|
* derive filename from 'def' as described
|
|
|
|
|
* above.
|
|
|
|
|
*/
|
|
|
|
|
char *mode; /* Either "r" or "w", the mode in which the .ext
|
|
|
|
|
* file is to be opened.
|
|
|
|
|
*/
|
|
|
|
|
char **prealfile; /* If this is non-NULL, it gets set to point to
|
|
|
|
|
* a string holding the name of the .ext file.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
char namebuf[512], *name, *endp, *ends;
|
|
|
|
|
int len;
|
|
|
|
|
FILE *rfile, *testf;
|
|
|
|
|
|
|
|
|
|
if (file) name = file;
|
2023-06-14 19:55:59 +02:00
|
|
|
else if (ExtLocalPath != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp(ExtLocalPath, "."))
|
|
|
|
|
name = def->cd_name; /* Save locally */
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
struct stat st = {0};
|
|
|
|
|
|
|
|
|
|
/* Test presence of the directory */
|
|
|
|
|
if (stat(ExtLocalPath, &st) == -1) {
|
|
|
|
|
TxError("Path \"%s\" does not exist; attempting to create it.\n",
|
|
|
|
|
ExtLocalPath);
|
|
|
|
|
mkdir(ExtLocalPath, 0755);
|
|
|
|
|
if (stat(ExtLocalPath, &st) == -1) {
|
|
|
|
|
TxError("Path \"%s\" does not exist; saving locally.\n",
|
|
|
|
|
ExtLocalPath);
|
|
|
|
|
name = def->cd_name; /* Save locally */
|
|
|
|
|
}
|
2023-07-28 15:40:41 +02:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Save locally in specified path, which was just created */
|
|
|
|
|
name = namebuf;
|
|
|
|
|
sprintf(namebuf, "%s/%s", ExtLocalPath, def->cd_name);
|
|
|
|
|
}
|
2023-06-14 19:55:59 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Save locally in specified path, which is assumed to exist */
|
|
|
|
|
name = namebuf;
|
|
|
|
|
sprintf(namebuf, "%s/%s", ExtLocalPath, def->cd_name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
else if (def->cd_file)
|
|
|
|
|
{
|
|
|
|
|
name = def->cd_file;
|
|
|
|
|
ends = strrchr(def->cd_file, '/');
|
|
|
|
|
if (ends == NULL) ends = def->cd_file;
|
2024-10-04 18:20:25 +02:00
|
|
|
if ((endp = strrchr(ends + 1, '.')))
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
name = namebuf;
|
|
|
|
|
len = endp - def->cd_file;
|
|
|
|
|
if (len > sizeof namebuf - 1) len = sizeof namebuf - 1;
|
|
|
|
|
(void) strncpy(namebuf, def->cd_file, len);
|
|
|
|
|
namebuf[len] = '\0';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else name = def->cd_name;
|
|
|
|
|
|
|
|
|
|
/* Try once as-is, and if this fails, try stripping any leading */
|
|
|
|
|
/* path information in case cell is in a read-only directory. */
|
|
|
|
|
|
|
|
|
|
if ((rfile = PaOpen(name, mode, ".ext", Path, CellLibPath, prealfile)) != NULL)
|
|
|
|
|
return rfile;
|
|
|
|
|
|
|
|
|
|
if (!strcmp(mode, "r")) return NULL; /* Not even readable */
|
|
|
|
|
|
|
|
|
|
/* Try writing to the cwd IF there is no .mag file by the */
|
|
|
|
|
/* same name in the cwd that would conflict. */
|
|
|
|
|
|
|
|
|
|
name = strrchr(def->cd_name, '/');
|
|
|
|
|
if (name != NULL)
|
|
|
|
|
name++;
|
|
|
|
|
else
|
|
|
|
|
name = def->cd_name;
|
|
|
|
|
|
2022-03-21 14:06:35 +01:00
|
|
|
if (def->cd_file)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2022-03-21 14:06:35 +01:00
|
|
|
ends = strrchr(def->cd_file, '/');
|
|
|
|
|
if (ends != NULL)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2022-03-21 14:06:35 +01:00
|
|
|
testf = PaOpen(ends + 1, "r", ".mag", ".", ".", NULL);
|
|
|
|
|
if (testf)
|
|
|
|
|
{
|
|
|
|
|
fclose(testf);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return (PaOpen(name, mode, ".ext", ".", ".", prealfile));
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2021-04-05 16:20:41 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* extPrepSubstrate ---
|
|
|
|
|
*
|
|
|
|
|
* Prepare a replacement plane for the plane representing the substrate, as
|
|
|
|
|
* defined in ExtCurStyle->exts_globSubstratePlane. The target CellDef is
|
|
|
|
|
* searched for types that shield (i.e., isolate) a section of the layout
|
|
|
|
|
* from the global substrate. The tile type that represents the substrate
|
|
|
|
|
* is painted into the isolated regions.
|
|
|
|
|
*
|
|
|
|
|
* The purpose of this method is to deal with the common methodology in
|
|
|
|
|
* which the substrate is not represented by any tile type, because no mask
|
|
|
|
|
* is defined for the substrate. Typically, an entire cell such as a digital
|
|
|
|
|
* standard cell may be placed on the default substrate or in a deep nwell
|
|
|
|
|
* region. It is therefore necessary to be able to detect what is underneath
|
|
|
|
|
* a cell on the plane representing the substrate to determine if the area is
|
|
|
|
|
* the default substrate or an isolated region. If an isolated region, it
|
|
|
|
|
* must be painted with a tile type so that the extraction code can tag the
|
2023-03-10 17:14:23 +01:00
|
|
|
* tiles with an ExtRegion and assign it a node. This code creates the substrate
|
2021-04-05 16:20:41 +02:00
|
|
|
* paint in the isolated regions for the duration of the extration, then
|
|
|
|
|
* reverts back to the original plane afterward.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns a Plane structure that is the original substrate plane from
|
|
|
|
|
* CellDef "def", with isolated substrate regions filled with the
|
|
|
|
|
* substrate tile type. If there are no isolated substrate regions,
|
|
|
|
|
* or if a substrate plane or substrate type is not defined by the
|
|
|
|
|
* technology, then the routine returns NULL.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* All modifications are limited to the returned plane structure.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Plane *
|
|
|
|
|
extPrepSubstrate(def)
|
|
|
|
|
CellDef *def;
|
|
|
|
|
{
|
|
|
|
|
SearchContext scx;
|
|
|
|
|
CellUse dummy;
|
|
|
|
|
TileType subType;
|
|
|
|
|
TileTypeBitMask subMask, notSubMask;
|
|
|
|
|
Plane *subPlane, *savePlane;
|
|
|
|
|
int pNum;
|
|
|
|
|
|
|
|
|
|
/* Determine if substrate copying is required. */
|
|
|
|
|
|
|
|
|
|
if (ExtCurStyle->exts_globSubstratePlane == -1) return NULL;
|
|
|
|
|
|
|
|
|
|
/* Find a type to use for the substrate, and the mask of all types */
|
|
|
|
|
/* in the same plane as the substrate that are not connected to the */
|
|
|
|
|
/* substrate. If there is not a simple type representing the substrate */
|
|
|
|
|
/* then do not attempt to resolve substrate regions. */
|
|
|
|
|
|
2022-02-23 21:02:40 +01:00
|
|
|
if ((subType = ExtCurStyle->exts_globSubstrateDefaultType) == -1) return NULL;
|
|
|
|
|
|
2021-04-05 16:20:41 +02:00
|
|
|
TTMaskZero(&subMask);
|
|
|
|
|
TTMaskSetMask(&subMask, &ExtCurStyle->exts_globSubstrateTypes);
|
|
|
|
|
TTMaskCom2(¬SubMask, &subMask);
|
|
|
|
|
TTMaskAndMask(¬SubMask, &DBPlaneTypes[ExtCurStyle->exts_globSubstratePlane]);
|
|
|
|
|
|
2023-02-28 04:22:09 +01:00
|
|
|
/* Generate the full flattened substrate into a new plane structure */
|
|
|
|
|
/* (called subPlane). This adds layer geometry for the substrate */
|
|
|
|
|
/* in the typical case where the substrate may be space (implicitly */
|
|
|
|
|
/* defined substrate). */
|
2021-04-05 16:20:41 +02:00
|
|
|
|
|
|
|
|
scx.scx_trans = GeoIdentityTransform;
|
|
|
|
|
scx.scx_area = def->cd_bbox;
|
|
|
|
|
scx.scx_use = &dummy;
|
|
|
|
|
dummy.cu_def = def;
|
|
|
|
|
dummy.cu_id = NULL;
|
|
|
|
|
|
|
|
|
|
subPlane = DBCellGenerateSubstrate(&scx, subType, ¬SubMask,
|
|
|
|
|
&ExtCurStyle->exts_globSubstrateShieldTypes, def);
|
|
|
|
|
if (subPlane != NULL)
|
|
|
|
|
{
|
|
|
|
|
pNum = ExtCurStyle->exts_globSubstratePlane;
|
|
|
|
|
savePlane = def->cd_planes[pNum];
|
|
|
|
|
def->cd_planes[pNum] = subPlane;
|
|
|
|
|
return savePlane;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-28 04:22:09 +01:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* extResPrepSubstrate ---
|
|
|
|
|
*
|
|
|
|
|
* This works similarly to extPrepSubstrate above, but is used for the
|
|
|
|
|
* "extresist" command, where the method is to make sure that the whole
|
|
|
|
|
* substrate area of the cell has non-space tiles, so that these can be
|
|
|
|
|
* used to estimate the resistance of the substrate from point to point,
|
|
|
|
|
* and to eliminate isolated substrate regions, since those represent an
|
|
|
|
|
* idealized cutoff of resistance that "extresist" is supposed to be
|
|
|
|
|
* replacing with an accurate resitance network.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns a Plane structure that is the original substrate plane from
|
|
|
|
|
* CellDef "def", with the entire substrate region filled with the
|
|
|
|
|
* substrate tile type. If a substrate plane or substrate type is not
|
|
|
|
|
* defined by the technology, then the routine returns NULL.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* All modifications are limited to the returned plane structure.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Plane *
|
|
|
|
|
extResPrepSubstrate(def)
|
|
|
|
|
CellDef *def;
|
|
|
|
|
{
|
|
|
|
|
SearchContext scx;
|
|
|
|
|
CellUse dummy;
|
|
|
|
|
TileType subType;
|
|
|
|
|
TileTypeBitMask subMask, notSubMask;
|
|
|
|
|
Plane *subPlane, *savePlane;
|
|
|
|
|
int pNum;
|
|
|
|
|
|
|
|
|
|
/* Determine if substrate copying is required. */
|
|
|
|
|
|
|
|
|
|
if (ExtCurStyle->exts_globSubstratePlane == -1) return NULL;
|
|
|
|
|
|
|
|
|
|
/* Find a type to use for the substrate, and the mask of all types */
|
|
|
|
|
/* in the same plane as the substrate that are not connected to the */
|
|
|
|
|
/* substrate. If there is not a simple type representing the substrate */
|
|
|
|
|
/* then do not attempt to resolve substrate regions. */
|
|
|
|
|
|
|
|
|
|
if ((subType = ExtCurStyle->exts_globSubstrateDefaultType) == -1) return NULL;
|
|
|
|
|
|
|
|
|
|
TTMaskZero(&subMask);
|
|
|
|
|
TTMaskSetMask(&subMask, &ExtCurStyle->exts_globSubstrateTypes);
|
|
|
|
|
TTMaskCom2(¬SubMask, &subMask);
|
|
|
|
|
TTMaskAndMask(¬SubMask, &DBPlaneTypes[ExtCurStyle->exts_globSubstratePlane]);
|
|
|
|
|
|
|
|
|
|
/* Generate the full flattened substrate into a new plane structure */
|
|
|
|
|
/* (called subPlane). This adds layer geometry for the substrate */
|
|
|
|
|
/* in the typical case where the substrate may be space (implicitly */
|
|
|
|
|
/* defined substrate). */
|
|
|
|
|
|
|
|
|
|
scx.scx_trans = GeoIdentityTransform;
|
|
|
|
|
scx.scx_area = def->cd_bbox;
|
|
|
|
|
scx.scx_use = &dummy;
|
|
|
|
|
dummy.cu_def = def;
|
|
|
|
|
dummy.cu_id = NULL;
|
|
|
|
|
|
|
|
|
|
subPlane = DBCellGenerateSimpleSubstrate(&scx, subType, ¬SubMask, def);
|
|
|
|
|
if (subPlane != NULL)
|
|
|
|
|
{
|
|
|
|
|
pNum = ExtCurStyle->exts_globSubstratePlane;
|
|
|
|
|
savePlane = def->cd_planes[pNum];
|
|
|
|
|
def->cd_planes[pNum] = subPlane;
|
|
|
|
|
return savePlane;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-05 16:20:41 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
2021-04-05 22:03:54 +02:00
|
|
|
* ExtRevertSubstrate ---
|
2021-04-05 16:20:41 +02:00
|
|
|
*
|
|
|
|
|
* This routine swaps the substrate plane of CellDef "def" with the plane
|
|
|
|
|
* structure provided in the argument "savePlane". It should be called at
|
|
|
|
|
* the end of extraction. "savePlane" should be the pointer to the substrate
|
|
|
|
|
* plane of "def" before it was swapped out for the modified plane created by
|
|
|
|
|
* the routine "extPrepSubstrate", above. The calling routine is responsible
|
|
|
|
|
* for knowing if extPrepSubstrate returned NULL in which case there is
|
|
|
|
|
* nothing to revert.
|
|
|
|
|
*
|
|
|
|
|
* Returns:
|
|
|
|
|
* Nothing.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The CellDef "def" has its substrate plane swapped out for "savePlane",
|
|
|
|
|
* and the original substrate plane and its contents are freed.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2021-04-05 22:03:54 +02:00
|
|
|
ExtRevertSubstrate(def, savePlane)
|
2021-04-05 16:20:41 +02:00
|
|
|
CellDef *def;
|
|
|
|
|
Plane *savePlane;
|
|
|
|
|
{
|
|
|
|
|
int pNum;
|
|
|
|
|
Plane *subPlane;
|
|
|
|
|
|
|
|
|
|
pNum = ExtCurStyle->exts_globSubstratePlane;
|
|
|
|
|
subPlane = def->cd_planes[pNum];
|
|
|
|
|
def->cd_planes[pNum] = savePlane;
|
|
|
|
|
DBFreePaintPlane(subPlane);
|
|
|
|
|
TiFreePlane(subPlane);
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* extCellFile --
|
|
|
|
|
*
|
|
|
|
|
* Internal interface for extracting a single cell.
|
|
|
|
|
* Extracts it to the open FILE 'f'. Doesn't print
|
|
|
|
|
* any messages.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* May leave feedback information where errors were encountered.
|
2021-12-31 20:02:58 +01:00
|
|
|
* Upon return, extNumErrors has been incremented by the number of
|
2017-04-25 14:41:48 +02:00
|
|
|
* fatal errors encountered while extracting 'def', and extNumWarnings
|
|
|
|
|
* by the number of warnings.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
2021-04-05 22:03:54 +02:00
|
|
|
Plane *
|
2017-04-25 14:41:48 +02:00
|
|
|
extCellFile(def, f, doLength)
|
|
|
|
|
CellDef *def; /* Def to be extracted */
|
|
|
|
|
FILE *f; /* Output to this file */
|
|
|
|
|
bool doLength; /* TRUE if we should extract driver-receiver path
|
|
|
|
|
* length information for this cell (see ExtCell
|
|
|
|
|
* for more details).
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
NodeRegion *reg;
|
2021-04-05 16:20:41 +02:00
|
|
|
Plane *saveSub;
|
2022-01-14 22:13:36 +01:00
|
|
|
Label *lab;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
UndoDisable();
|
|
|
|
|
|
2026-01-22 17:20:20 +01:00
|
|
|
/* If "extract do unique" was specified, then make labels in the
|
|
|
|
|
* cell unique.
|
|
|
|
|
*/
|
|
|
|
|
if (ExtOptions & EXT_DOUNIQUE)
|
|
|
|
|
extUniqueCell(def, EXT_UNIQ_TEMP);
|
|
|
|
|
|
2021-04-05 16:20:41 +02:00
|
|
|
/* Prep any isolated substrate areas */
|
2026-01-28 20:31:38 +01:00
|
|
|
if (ExtOptions & EXT_DOEXTRESIST)
|
|
|
|
|
saveSub = extResPrepSubstrate(def);
|
|
|
|
|
else
|
|
|
|
|
saveSub = extPrepSubstrate(def);
|
2021-04-05 16:20:41 +02:00
|
|
|
|
2022-01-14 22:13:36 +01:00
|
|
|
/* Remove any label markers that were made by a previous extraction */
|
|
|
|
|
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
|
|
|
|
if (lab->lab_port == INFINITY)
|
|
|
|
|
lab->lab_port = 0;
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Output the header: timestamp, technology, calls on cell uses */
|
|
|
|
|
if (!SigInterruptPending) extHeader(def, f);
|
|
|
|
|
|
|
|
|
|
/* Extract the mask information in this cell */
|
|
|
|
|
reg = (NodeRegion *) NULL;
|
|
|
|
|
if (!SigInterruptPending) reg = extBasic(def, f);
|
|
|
|
|
|
|
|
|
|
/* Do hierarchical extraction */
|
|
|
|
|
extParentUse->cu_def = def;
|
|
|
|
|
if (!SigInterruptPending) extSubtree(extParentUse, reg, f);
|
|
|
|
|
if (!SigInterruptPending) extArray(extParentUse, f);
|
|
|
|
|
|
|
|
|
|
/* Clean up from basic extraction */
|
|
|
|
|
if (reg) ExtFreeLabRegions((LabRegion *) reg);
|
2026-01-09 17:58:35 +01:00
|
|
|
ExtResetTiles(def, CLIENTDEFAULT);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* Final pass: extract length information if desired */
|
|
|
|
|
if (!SigInterruptPending && doLength && (ExtOptions & EXT_DOLENGTH))
|
|
|
|
|
extLength(extParentUse, f);
|
|
|
|
|
|
|
|
|
|
UndoEnable();
|
2021-04-05 22:03:54 +02:00
|
|
|
return saveSub;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* extHeader --
|
|
|
|
|
*
|
|
|
|
|
* Output header information to the .ext file for a cell.
|
|
|
|
|
* This information consists of:
|
|
|
|
|
*
|
|
|
|
|
* timestamp
|
|
|
|
|
* extractor version number
|
|
|
|
|
* technology
|
|
|
|
|
* scale factors for resistance, capacitance, and lambda
|
|
|
|
|
* calls on all subcells used by this cell (see extOutputUsesFunc)
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Writes to (FILE *) 'f'.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
extHeader(def, f)
|
|
|
|
|
CellDef *def; /* Cell being extracted */
|
|
|
|
|
FILE *f; /* Write to this file */
|
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
bool propfound;
|
|
|
|
|
char *propvalue;
|
|
|
|
|
|
2020-08-03 14:18:58 +02:00
|
|
|
ASSERT(DBTechName != NULL, "extHeader");
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Output a timestamp (should be first) */
|
|
|
|
|
fprintf(f, "timestamp %d\n", def->cd_timestamp);
|
|
|
|
|
|
|
|
|
|
/* Output our version number */
|
|
|
|
|
fprintf(f, "version %s\n", MagicVersion);
|
|
|
|
|
|
|
|
|
|
/* Output the technology */
|
|
|
|
|
fprintf(f, "tech %s\n", DBTechName);
|
|
|
|
|
|
|
|
|
|
/* Output the extract style name */
|
|
|
|
|
fprintf(f, "style %s\n", ExtCurStyle->exts_name);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Output scaling factors: R C D
|
|
|
|
|
* R = amount to multiply all resistances in the file by
|
|
|
|
|
* C = amount to multiply all capacitances by
|
|
|
|
|
* D = amount to multiply all linear distances by (areas
|
|
|
|
|
* should be multiplied by D**2).
|
|
|
|
|
*/
|
|
|
|
|
fprintf(f, "scale %d %d %g\n",
|
|
|
|
|
ExtCurStyle->exts_resistScale,
|
|
|
|
|
ExtCurStyle->exts_capScale,
|
|
|
|
|
ExtCurStyle->exts_unitsPerLambda);
|
|
|
|
|
|
|
|
|
|
/* Output the sheet resistivity classes */
|
|
|
|
|
fprintf(f, "resistclasses");
|
|
|
|
|
for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++)
|
|
|
|
|
fprintf(f, " %d", ExtCurStyle->exts_resistByResistClass[n]);
|
|
|
|
|
fprintf(f, "\n");
|
|
|
|
|
|
|
|
|
|
/* Output any parameters defined for this cell that */
|
|
|
|
|
/* are to be passed to instances of the cell */
|
|
|
|
|
/* (created by defining property "parameter") */
|
|
|
|
|
|
Extended the "property" command and modified the way that properties
are handled. Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy. The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double". All types except "string" can consist of multiple
values. Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted. In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 16:48:47 +01:00
|
|
|
propvalue = DBPropGetString(def, "parameter", &propfound);
|
2017-04-25 14:41:48 +02:00
|
|
|
if (propfound)
|
|
|
|
|
{
|
|
|
|
|
// Use device parameter table to store the cell def parameters,
|
|
|
|
|
// but preface name with ":" to avoid any conflict with device
|
|
|
|
|
// names.
|
|
|
|
|
fprintf(f, "parameters :%s %s\n", def->cd_name, propvalue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Output all calls on subcells */
|
|
|
|
|
(void) DBCellEnum(def, extOutputUsesFunc, (ClientData) f);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* extOutputUsesFunc --
|
|
|
|
|
*
|
|
|
|
|
* Filter function, called via DBCellEnum, that outputs all the
|
|
|
|
|
* cell uses contained in the parent's cell tile planes.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns 0, for DBCellEnum to keep going.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Writes a line for each use encountered to 'outf'.
|
|
|
|
|
* The line is of the following form:
|
|
|
|
|
*
|
|
|
|
|
* use defname useid Ta ... Tf
|
|
|
|
|
*
|
|
|
|
|
* where 'defname' is the name of the cell def referenced (cd_name),
|
|
|
|
|
* 'useid' is its use identifier (cu_id), and Ta ... Tf are the six
|
|
|
|
|
* components of the transform from coordinates of this use up to
|
|
|
|
|
* its parent. If the cell is an array, the use id may be followed by:
|
|
|
|
|
*
|
|
|
|
|
* [xlo,xhi,xsep][ylo,yhi,ysep]
|
|
|
|
|
*
|
|
|
|
|
* The indices are xlo through xhi inclusive, or ylo through yhi
|
|
|
|
|
* inclusive. The separation between adjacent elements is xsep
|
|
|
|
|
* or ysep; this is used in computing the transform for a particular
|
|
|
|
|
* array element. If arraying is not present in a given direction,
|
|
|
|
|
* the low and high indices are equal and the separation is ignored.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
extOutputUsesFunc(cu, outf)
|
|
|
|
|
CellUse *cu;
|
|
|
|
|
FILE *outf;
|
|
|
|
|
{
|
|
|
|
|
Transform *t = &cu->cu_transform;
|
|
|
|
|
|
2022-11-21 23:13:33 +01:00
|
|
|
if (cu->cu_def->cd_flags & CDDONTUSE) return 0;
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
fprintf(outf, "use %s %s", cu->cu_def->cd_name, cu->cu_id);
|
|
|
|
|
if (cu->cu_xlo != cu->cu_xhi || cu->cu_ylo != cu->cu_yhi)
|
|
|
|
|
{
|
|
|
|
|
fprintf(outf, "[%d:%d:%d]",
|
|
|
|
|
cu->cu_xlo, cu->cu_xhi, cu->cu_xsep);
|
|
|
|
|
fprintf(outf, "[%d:%d:%d]",
|
|
|
|
|
cu->cu_ylo, cu->cu_yhi, cu->cu_ysep);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Output transform to parent */
|
|
|
|
|
fprintf(outf, " %d %d %d %d %d %d\n",
|
|
|
|
|
t->t_a, t->t_b, t->t_c, t->t_d, t->t_e, t->t_f);
|
|
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
}
|