Merge branch 'master' of https://github.com/RTimothyEdwards/magic into spice_hier
Bringing branch up to date with master
This commit is contained in:
commit
765c1abd11
2
Makefile
2
Makefile
|
|
@ -107,7 +107,7 @@ distclean:
|
|||
${RM} ${MAGICDIR}/scripts/default.conf
|
||||
${RM} ${MAGICDIR}/scripts/config.log ${MAGICDIR}/scripts/config.status
|
||||
${RM} scripts/magic.spec magic-`cat VERSION` magic-`cat VERSION`.tgz
|
||||
${RM} *.log
|
||||
${RM} *.log */Depend
|
||||
|
||||
dist:
|
||||
${RM} scripts/magic.spec magic-`cat VERSION` magic-`cat VERSION`.tgz
|
||||
|
|
|
|||
|
|
@ -53,9 +53,11 @@ static char rcsid[] __attribute__ ((unused)) ="$Header: /usr/cvsroot/magic-8.0/c
|
|||
#include "utils/stack.h"
|
||||
|
||||
/* Exports */
|
||||
bool CalmaDoLibrary = FALSE; /* If TRUE, do not output the top level */
|
||||
bool CalmaDoLabels = TRUE; /* If FALSE, don't output labels with GDS-II */
|
||||
bool CalmaDoLower = TRUE; /* If TRUE, allow lowercase labels. */
|
||||
bool CalmaFlattenArrays = FALSE; /* If TRUE, output arrays as individual uses */
|
||||
bool CalmaAddendum = FALSE; /* If TRUE, do not output readonly cell defs */
|
||||
|
||||
/* Experimental stuff---not thoroughly tested (as of Sept. 2007)! */
|
||||
bool CalmaContactArrays = FALSE; /* If TRUE, output contacts as subcell arrays */
|
||||
|
|
@ -328,7 +330,7 @@ CalmaWrite(rootDef, f)
|
|||
* to insure that each child cell is output before it is used. The
|
||||
* root cell is output last.
|
||||
*/
|
||||
(void) calmaProcessDef(rootDef, f);
|
||||
(void) calmaProcessDef(rootDef, f, CalmaDoLibrary);
|
||||
|
||||
/* Finish up by outputting the end-of-library marker */
|
||||
calmaOutRH(4, CALMA_ENDLIB, CALMA_NODATA, f);
|
||||
|
|
@ -741,13 +743,14 @@ calmaProcessUse(use, outf)
|
|||
CellUse *use; /* Process use->cu_def */
|
||||
FILE *outf; /* Stream file */
|
||||
{
|
||||
return (calmaProcessDef(use->cu_def, outf));
|
||||
return (calmaProcessDef(use->cu_def, outf, FALSE));
|
||||
}
|
||||
|
||||
int
|
||||
calmaProcessDef(def, outf)
|
||||
calmaProcessDef(def, outf, do_library)
|
||||
CellDef *def; /* Output this def's children, then the def itself */
|
||||
FILE *outf; /* Stream file */
|
||||
bool do_library; /* If TRUE, output only children of def, but not def */
|
||||
{
|
||||
char *filename;
|
||||
bool isReadOnly, oldStyle, hasContent, isAbstract, hasGDSEnd;
|
||||
|
|
@ -772,13 +775,6 @@ calmaProcessDef(def, outf)
|
|||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Output the definitions for any of our descendants that have
|
||||
* not already been output. Numbers are assigned to the subcells
|
||||
* as they are output.
|
||||
*/
|
||||
(void) DBCellEnum(def, calmaProcessUse, (ClientData) outf);
|
||||
|
||||
/*
|
||||
* Check if this is a read-only file that is supposed to be copied
|
||||
* verbatim from input to output. If so, do the direct copy. If
|
||||
|
|
@ -797,6 +793,19 @@ calmaProcessDef(def, outf)
|
|||
DBPropGet(def, "GDS_END", &hasGDSEnd);
|
||||
filename = (char *)DBPropGet(def, "GDS_FILE", &isReadOnly);
|
||||
|
||||
/* When used with "calma addendum true", don't output the read-only */
|
||||
/* cells. This makes the library incomplete and dependent on the */
|
||||
/* vendor libraries, so use with caution. */
|
||||
|
||||
if (isReadOnly && hasContent && CalmaAddendum) return (0);
|
||||
|
||||
/*
|
||||
* Output the definitions for any of our descendants that have
|
||||
* not already been output. Numbers are assigned to the subcells
|
||||
* as they are output.
|
||||
*/
|
||||
(void) DBCellEnum(def, calmaProcessUse, (ClientData) outf);
|
||||
|
||||
if (isReadOnly && hasContent)
|
||||
{
|
||||
char *buffer, *offptr, *retfilename;
|
||||
|
|
@ -907,7 +916,8 @@ calmaProcessDef(def, outf)
|
|||
|
||||
/* Output this cell definition from the Magic database */
|
||||
if (!isReadOnly)
|
||||
calmaOutFunc(def, outf, &TiPlaneRect);
|
||||
if (!do_library)
|
||||
calmaOutFunc(def, outf, &TiPlaneRect);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@
|
|||
extern bool CalmaSubcellPolygons;
|
||||
extern bool CalmaSubcellPaths;
|
||||
extern bool CalmaDoLabels;
|
||||
extern bool CalmaDoLibrary;
|
||||
extern bool CalmaDoLower;
|
||||
extern bool CalmaAddendum;
|
||||
extern bool CalmaMergeTiles;
|
||||
extern bool CalmaFlattenArrays;
|
||||
extern bool CalmaNoDRCCheck;
|
||||
|
|
|
|||
10
cif/CIFgen.c
10
cif/CIFgen.c
|
|
@ -3444,7 +3444,10 @@ calcX:
|
|||
delta = abs(*sxbot) % CIFCurStyle->cs_gridLimit;
|
||||
if (delta > 0)
|
||||
{
|
||||
*axtop -= 2 * delta;
|
||||
if (*sxbot >= 0)
|
||||
*axtop -= 2 * delta;
|
||||
else
|
||||
*axtop += 2 * delta;
|
||||
goto calcX;
|
||||
}
|
||||
}
|
||||
|
|
@ -3471,7 +3474,10 @@ calcY:
|
|||
delta = abs(*sybot) % CIFCurStyle->cs_gridLimit;
|
||||
if (delta > 0)
|
||||
{
|
||||
*aytop -= 2 * delta;
|
||||
if (*sybot >= 0)
|
||||
*aytop -= 2 * delta;
|
||||
else
|
||||
*aytop += 2 * delta;
|
||||
goto calcY;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,6 +145,28 @@ CIFGetOutputScale(convert)
|
|||
(float)(CIFCurStyle->cs_expander * convert));
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CIFGetScale --
|
||||
*
|
||||
* Same as the above routine, but provides the scalefactor to get CIF
|
||||
* units from centimicrons (which generally means just returning the
|
||||
* expander value to show if units have been declared in nanometers or
|
||||
* angstroms).
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
float
|
||||
CIFGetScale(convert)
|
||||
int convert;
|
||||
{
|
||||
if (CIFCurStyle == NULL) return 1.0;
|
||||
|
||||
return (1.0 / (float)(CIFCurStyle->cs_expander * convert));
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ FILE *cifErrorFile;
|
|||
int cifLineNumber; /* Number of current line. */
|
||||
int cifTotalWarnings; /* Number of warnings detected */
|
||||
int cifTotalErrors; /* Number of errors detected */
|
||||
bool cifSeenSnapWarning; /* Track this to prevent excessive messaging */
|
||||
|
||||
/* The variables used below hold general information about what
|
||||
* we're currently working on.
|
||||
|
|
@ -218,8 +219,10 @@ CIFScaleCoord(cifCoord, snap_type)
|
|||
switch (snap_type)
|
||||
{
|
||||
case COORD_EXACT:
|
||||
CIFReadWarning("Input off lambda grid by %d/%d; grid redefined.\n",
|
||||
if (!cifSeenSnapWarning)
|
||||
CIFReadWarning("Input off lambda grid by %d/%d; grid redefined.\n",
|
||||
remain, denom);
|
||||
cifSeenSnapWarning = TRUE;
|
||||
|
||||
CIFTechInputScale(1, denom, FALSE);
|
||||
CIFTechOutputScale(1, denom);
|
||||
|
|
@ -243,8 +246,10 @@ CIFScaleCoord(cifCoord, snap_type)
|
|||
case COORD_HALF_U: case COORD_HALF_L:
|
||||
if (denom > 2)
|
||||
{
|
||||
CIFReadWarning("Input off lambda grid by %d/%d; grid redefined.\n",
|
||||
remain, denom);
|
||||
if (!cifSeenSnapWarning)
|
||||
CIFReadWarning("Input off lambda grid by %d/%d; "
|
||||
"grid redefined.\n", remain, denom);
|
||||
cifSeenSnapWarning = TRUE;
|
||||
|
||||
/* scale to nearest half-lambda */
|
||||
if (!(denom & 0x1)) denom >>= 1;
|
||||
|
|
@ -277,8 +282,10 @@ CIFScaleCoord(cifCoord, snap_type)
|
|||
|
||||
break;
|
||||
case COORD_ANY:
|
||||
CIFReadWarning("Input off lambda grid by %d/%d; snapped to grid.\n",
|
||||
abs(remain), abs(denom));
|
||||
if (!cifSeenSnapWarning)
|
||||
CIFReadWarning("Input off lambda grid by %d/%d; snapped to grid.\n",
|
||||
abs(remain), abs(denom));
|
||||
cifSeenSnapWarning = TRUE;
|
||||
|
||||
/* Careful: must round down a bit more for negative numbers, in
|
||||
* order to ensure that a point exactly halfway between Magic units
|
||||
|
|
@ -1591,6 +1598,7 @@ CIFReadFile(file)
|
|||
cifTotalWarnings = 0;
|
||||
cifTotalErrors = 0;
|
||||
CifPolygonCount = 0;
|
||||
cifSeenSnapWarning = FALSE;
|
||||
|
||||
cifInputFile = file;
|
||||
cifReadScale1 = 1;
|
||||
|
|
|
|||
|
|
@ -2143,7 +2143,11 @@ CIFGetContactSize(type, edge, spacing, border)
|
|||
|
||||
/* Anything other than an OR function will break */
|
||||
/* the relationship between magic layers and cuts. */
|
||||
else if (sop->co_opcode != CIFOP_OR)
|
||||
/* NOTE: Making an exception for AND_NOT, which is */
|
||||
/* used to distinguish between small and large via */
|
||||
/* areas. */
|
||||
else if ((sop->co_opcode != CIFOP_OR) &&
|
||||
(sop->co_opcode != CIFOP_ANDNOT))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ extern void CIFReadTechFinal();
|
|||
/* Externally-visible procedures: */
|
||||
|
||||
extern float CIFGetOutputScale();
|
||||
extern float CIFGetScale();
|
||||
extern float CIFGetInputScale();
|
||||
extern int CIFGetDefaultContactSize();
|
||||
|
||||
|
|
|
|||
|
|
@ -545,6 +545,8 @@ selGetArrayFunc(selUse, use, trans, arg)
|
|||
* box size [width height]
|
||||
* box position [llx lly] [-edit]
|
||||
* box values [llx lly urx ury] [-edit]
|
||||
* box remove
|
||||
* box select
|
||||
*
|
||||
* box <direction> <distance> | cursor
|
||||
*
|
||||
|
|
@ -580,13 +582,15 @@ selGetArrayFunc(selUse, use, trans, arg)
|
|||
#define BOX_SIZE 2
|
||||
#define BOX_POSITION 3
|
||||
#define BOX_VALUES 4
|
||||
#define BOX_MOVE 5
|
||||
#define BOX_GROW 6
|
||||
#define BOX_SHRINK 7
|
||||
#define BOX_CORNER 8
|
||||
#define BOX_EXISTS 9
|
||||
#define BOX_HELP 10
|
||||
#define BOX_DEFAULT 11
|
||||
#define BOX_REMOVE 5
|
||||
#define BOX_SELECT 6
|
||||
#define BOX_MOVE 7
|
||||
#define BOX_GROW 8
|
||||
#define BOX_SHRINK 9
|
||||
#define BOX_CORNER 10
|
||||
#define BOX_EXISTS 11
|
||||
#define BOX_HELP 12
|
||||
#define BOX_DEFAULT 13
|
||||
|
||||
void
|
||||
CmdBox(w, cmd)
|
||||
|
|
@ -599,6 +603,8 @@ CmdBox(w, cmd)
|
|||
"size [width height] set or return box size",
|
||||
"position [llx lly] [-edit] set or return box position",
|
||||
"values [llx lly urx ury] [-edit] set or return box coordinates",
|
||||
"remove remove cursor box from display",
|
||||
"select set box to selection bounding box",
|
||||
"move <direction> <distance> move box position",
|
||||
"grow <direction> <distance> expand box size",
|
||||
"shrink <direction> <distance> shrink box size",
|
||||
|
|
@ -658,6 +664,12 @@ CmdBox(w, cmd)
|
|||
|
||||
windCheckOnlyWindow(&w, DBWclientID);
|
||||
|
||||
if (option == BOX_REMOVE)
|
||||
{
|
||||
DBWSetBox((CellDef *)NULL, &GeoNullRect);
|
||||
return;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------*/
|
||||
/* Check for the command options which do not require a box */
|
||||
/* to be present. */
|
||||
|
|
@ -907,6 +919,19 @@ CmdBox(w, cmd)
|
|||
boxptr->r_ytop = boxptr->r_ybot + height;
|
||||
break;
|
||||
|
||||
case BOX_SELECT:
|
||||
if (argc == 2)
|
||||
{
|
||||
Rect selarea;
|
||||
GeoTransRect(&SelectUse->cu_transform, &SelectDef->cd_bbox, &selarea);
|
||||
boxptr->r_xbot = selarea.r_xbot;
|
||||
boxptr->r_ybot = selarea.r_ybot;
|
||||
boxptr->r_xtop = selarea.r_xtop;
|
||||
boxptr->r_ytop = selarea.r_ytop;
|
||||
}
|
||||
else goto badusage;
|
||||
break;
|
||||
|
||||
case BOX_VALUES:
|
||||
if (argc == 2)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -89,21 +89,23 @@ bool cmdDumpParseArgs();
|
|||
*/
|
||||
|
||||
#define CALMA_HELP 0
|
||||
#define CALMA_ARRAYS 1
|
||||
#define CALMA_CONTACTS 2
|
||||
#define CALMA_DRCCHECK 3
|
||||
#define CALMA_FLATTEN 4
|
||||
#define CALMA_ORDERING 5
|
||||
#define CALMA_LABELS 6
|
||||
#define CALMA_LOWER 7
|
||||
#define CALMA_MERGE 8
|
||||
#define CALMA_READ 9
|
||||
#define CALMA_READONLY 10
|
||||
#define CALMA_RESCALE 11
|
||||
#define CALMA_WARNING 12
|
||||
#define CALMA_WRITE 13
|
||||
#define CALMA_POLYS 14
|
||||
#define CALMA_PATHS 15
|
||||
#define CALMA_ADDENDUM 1
|
||||
#define CALMA_ARRAYS 2
|
||||
#define CALMA_CONTACTS 3
|
||||
#define CALMA_DRCCHECK 4
|
||||
#define CALMA_FLATTEN 5
|
||||
#define CALMA_ORDERING 6
|
||||
#define CALMA_LABELS 7
|
||||
#define CALMA_LIBRARY 8
|
||||
#define CALMA_LOWER 9
|
||||
#define CALMA_MERGE 10
|
||||
#define CALMA_READ 11
|
||||
#define CALMA_READONLY 12
|
||||
#define CALMA_RESCALE 13
|
||||
#define CALMA_WARNING 14
|
||||
#define CALMA_WRITE 15
|
||||
#define CALMA_POLYS 16
|
||||
#define CALMA_PATHS 17
|
||||
|
||||
#define CALMA_WARN_HELP CIF_WARN_END /* undefined by CIF module */
|
||||
|
||||
|
|
@ -126,12 +128,14 @@ CmdCalma(w, cmd)
|
|||
static char *cmdCalmaOption[] =
|
||||
{
|
||||
"help print this help information",
|
||||
"addendum [yes|no] output only cells that are not type \"readonly\"",
|
||||
"arrays [yes|no] output arrays as individual subuses (like in CIF)",
|
||||
"contacts [yes|no] optimize output by arraying contacts as subcells",
|
||||
"drccheck [yes|no] mark all cells as needing DRC checking",
|
||||
"flatten [yes|no|limit] flatten simple cells (e.g., contacts) on input",
|
||||
"ordering [on|off] cause cells to be read in post-order",
|
||||
"labels [yes|no] cause labels to be output when writing GDS-II",
|
||||
"library [yes|no] do not output the top level, only subcells",
|
||||
"lower [yes|no] allow both upper and lower case in labels",
|
||||
"merge [yes|no] merge tiles into polygons in the output",
|
||||
"read file read Calma GDS-II format from \"file\"\n"
|
||||
|
|
@ -227,6 +231,46 @@ CmdCalma(w, cmd)
|
|||
CalmaDoLabels = (option < 3) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_LIBRARY:
|
||||
if (cmd->tx_argc == 2)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(CalmaDoLibrary));
|
||||
#else
|
||||
TxPrintf("The top-level cell will %sbe output to the GDS file.\n",
|
||||
(CalmaDoLibrary) ? "not " : "");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
else if (cmd->tx_argc != 3)
|
||||
goto wrongNumArgs;
|
||||
|
||||
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaDoLibrary = (option < 3) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_ADDENDUM:
|
||||
if (cmd->tx_argc == 2)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(CalmaAddendum));
|
||||
#else
|
||||
TxPrintf("Read-only cell defs will %sbe output to the GDS file.\n",
|
||||
(CalmaAddendum) ? "not " : "");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
else if (cmd->tx_argc != 3)
|
||||
goto wrongNumArgs;
|
||||
|
||||
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaAddendum = (option < 3) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_CONTACTS:
|
||||
if (cmd->tx_argc == 2)
|
||||
{
|
||||
|
|
|
|||
181
commands/CmdLQ.c
181
commands/CmdLQ.c
|
|
@ -1115,6 +1115,7 @@ cmdPortLabelFunc2(scx, label, tpath, cdata)
|
|||
/* Find a label in the cell editDef. */
|
||||
/* */
|
||||
/* If "port" is true, then search only for labels that are ports. */
|
||||
/* If false, then search only for labels that are not ports. */
|
||||
/* If "unique" is true, then return a label only if exactly one label */
|
||||
/* is found in the edit box. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
|
@ -1123,10 +1124,10 @@ Label *
|
|||
portFindLabel(editDef, port, unique, nonEdit)
|
||||
CellDef *editDef;
|
||||
bool unique;
|
||||
bool port;
|
||||
bool port; // If TRUE, only look for labels that are ports
|
||||
bool *nonEdit; // TRUE if label is not in the edit cell
|
||||
{
|
||||
int found;
|
||||
int found, wrongkind;
|
||||
Label *lab, *sl;
|
||||
Rect editBox;
|
||||
|
||||
|
|
@ -1138,10 +1139,19 @@ portFindLabel(editDef, port, unique, nonEdit)
|
|||
|
||||
ToolGetEditBox(&editBox);
|
||||
found = 0;
|
||||
wrongkind = FALSE;
|
||||
if (nonEdit) *nonEdit = FALSE;
|
||||
lab = NULL;
|
||||
for (sl = editDef->cd_labels; sl != NULL; sl = sl->lab_next)
|
||||
{
|
||||
/* Ignore labels based on whether label is or is not a port */
|
||||
if (((port == TRUE) && !(sl->lab_flags & PORT_DIR_MASK)) ||
|
||||
((port == FALSE) && (sl->lab_flags & PORT_DIR_MASK)))
|
||||
{
|
||||
wrongkind = TRUE; /* Found at least one label of the wrong kind */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (GEO_OVERLAP(&editBox, &sl->lab_rect) ||
|
||||
GEO_SURROUND(&editBox, &sl->lab_rect))
|
||||
{
|
||||
|
|
@ -1167,11 +1177,13 @@ portFindLabel(editDef, port, unique, nonEdit)
|
|||
if (nonEdit) *nonEdit = FALSE;
|
||||
}
|
||||
}
|
||||
if ((found == 0) && (wrongkind == TRUE)) return NULL;
|
||||
|
||||
/* If no label was found, then search the hierarchy under the box. */
|
||||
/* The calling routine may determine whether a label that is not in */
|
||||
/* the edit cell may be valid for the command (e.g., if querying */
|
||||
/* but not changing values). */
|
||||
/* but not changing values). NOTE: Currently this does not apply */
|
||||
/* the "port" option. */
|
||||
|
||||
if (found == 0)
|
||||
{
|
||||
|
|
@ -1196,6 +1208,29 @@ portFindLabel(editDef, port, unique, nonEdit)
|
|||
|
||||
return lab;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* complabel() --
|
||||
*
|
||||
* qsort() callback routine used by CmdPort when renumbering ports.
|
||||
* Simply do a string comparison on the two labels. There is no special
|
||||
* meaning to the lexigraphic ordering; it is meant only to enforce a
|
||||
* consistent and repeatable port order. However, note that since SPICE
|
||||
* is case-insensitive, case-insensitive string comparison is used.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
complabel(const void *one, const void *two)
|
||||
{
|
||||
Label *l1 = *((Label **)one);
|
||||
Label *l2 = *((Label **)two);
|
||||
return strcasecmp(l1->lab_text, l2->lab_text);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -1207,7 +1242,9 @@ portFindLabel(editDef, port, unique, nonEdit)
|
|||
* usage, below).
|
||||
*
|
||||
* Usage:
|
||||
* port make|makeall [num] [connect_direction(s)]
|
||||
* port make [num] [connect_direction(s)]
|
||||
* or
|
||||
* port makeall|renumber [connect_direction(s)]
|
||||
* or
|
||||
* port [name|num] class|use|shape|index [value]
|
||||
*
|
||||
|
|
@ -1243,12 +1280,15 @@ portFindLabel(editDef, port, unique, nonEdit)
|
|||
#define PORT_EQUIV 4
|
||||
#define PORT_EXISTS 5
|
||||
#define PORT_CONNECT 6
|
||||
#define PORT_LAST 7
|
||||
#define PORT_MAKE 8
|
||||
#define PORT_MAKEALL 9
|
||||
#define PORT_NAME 10
|
||||
#define PORT_REMOVE 11
|
||||
#define PORT_HELP 12
|
||||
#define PORT_FIRST 7
|
||||
#define PORT_NEXT 8
|
||||
#define PORT_LAST 9
|
||||
#define PORT_MAKE 10
|
||||
#define PORT_MAKEALL 11
|
||||
#define PORT_NAME 12
|
||||
#define PORT_REMOVE 13
|
||||
#define PORT_RENUMBER 14
|
||||
#define PORT_HELP 15
|
||||
|
||||
void
|
||||
CmdPort(w, cmd)
|
||||
|
|
@ -1257,7 +1297,7 @@ CmdPort(w, cmd)
|
|||
{
|
||||
char **msg;
|
||||
int argstart;
|
||||
int i, idx, pos, type, option, argc;
|
||||
int i, refidx, idx, pos, type, option, argc;
|
||||
unsigned short dirmask;
|
||||
bool found;
|
||||
bool nonEdit = FALSE;
|
||||
|
|
@ -1274,11 +1314,14 @@ CmdPort(w, cmd)
|
|||
"equivalent [number] make port equivalent to another port",
|
||||
"exists report if a label is a port or not",
|
||||
"connections [dir...] get [set] port connection directions",
|
||||
"first report the lowest port number used",
|
||||
"next [number] report the next port number used",
|
||||
"last report the highest port number used",
|
||||
"make [index] [dir...] turn a label into a port",
|
||||
"makeall [index] [dir] turn all labels into ports",
|
||||
"name report the port name",
|
||||
"remove turn a port back into a label",
|
||||
"renumber renumber all ports",
|
||||
"help print this help information",
|
||||
NULL
|
||||
};
|
||||
|
|
@ -1376,7 +1419,7 @@ CmdPort(w, cmd)
|
|||
if (sl && ((sl->lab_flags & PORT_DIR_MASK) != 0))
|
||||
if ((sl->lab_flags & PORT_NUM_MASK) == portidx)
|
||||
{
|
||||
lab = sl;
|
||||
lab = sl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1388,7 +1431,8 @@ CmdPort(w, cmd)
|
|||
if (!strcmp(portname, sl->lab_text))
|
||||
{
|
||||
lab = sl;
|
||||
break;
|
||||
if (sl && ((sl->lab_flags & PORT_DIR_MASK) != 0))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lab == NULL)
|
||||
|
|
@ -1414,10 +1458,15 @@ CmdPort(w, cmd)
|
|||
{
|
||||
/* Check for options that require only one selected port */
|
||||
|
||||
if (option != PORT_LAST)
|
||||
if (option != PORT_LAST && option != PORT_FIRST)
|
||||
{
|
||||
if (lab == NULL)
|
||||
lab = portFindLabel(editDef, TRUE, TRUE, &nonEdit);
|
||||
{
|
||||
if (option == PORT_MAKE)
|
||||
lab = portFindLabel(editDef, FALSE, TRUE, &nonEdit);
|
||||
else
|
||||
lab = portFindLabel(editDef, TRUE, TRUE, &nonEdit);
|
||||
}
|
||||
|
||||
if (option == PORT_EXISTS)
|
||||
{
|
||||
|
|
@ -1435,9 +1484,10 @@ CmdPort(w, cmd)
|
|||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
if ((option != PORT_LAST) && (option != PORT_MAKEALL) && (lab == NULL))
|
||||
if ((option != PORT_LAST) && (option != PORT_FIRST) &&
|
||||
(option != PORT_MAKEALL) && (option != PORT_RENUMBER)
|
||||
&& (lab == NULL))
|
||||
{
|
||||
/* Let "port remove" fail without complaining. */
|
||||
if (option != PORT_REMOVE)
|
||||
|
|
@ -1452,7 +1502,8 @@ CmdPort(w, cmd)
|
|||
/* Check for options that require label to be a port */
|
||||
|
||||
if ((option != PORT_MAKE) && (option != PORT_MAKEALL)
|
||||
&& (option != PORT_EXISTS) && (option != PORT_LAST))
|
||||
&& (option != PORT_EXISTS) && (option != PORT_RENUMBER)
|
||||
&& (option != PORT_LAST) && (option != PORT_FIRST))
|
||||
{
|
||||
/* label "lab" must already be a port */
|
||||
if (!(lab->lab_flags & PORT_DIR_MASK))
|
||||
|
|
@ -1466,8 +1517,9 @@ CmdPort(w, cmd)
|
|||
/* Check for options that cannot operate on a non-edit cell label */
|
||||
if (nonEdit)
|
||||
{
|
||||
if ((option == PORT_MAKE) || (option == PORT_MAKEALL) ||
|
||||
(option == PORT_REMOVE) || (argc == 3))
|
||||
if ((option == PORT_MAKE) || (option == PORT_MAKEALL)
|
||||
|| (option == PORT_REMOVE) || (option == PORT_RENUMBER)
|
||||
|| (argc == 3))
|
||||
{
|
||||
TxError("Cannot modify a port in an non-edit cell.\n");
|
||||
return;
|
||||
|
|
@ -1491,6 +1543,44 @@ CmdPort(w, cmd)
|
|||
#endif
|
||||
break;
|
||||
|
||||
case PORT_FIRST:
|
||||
i = PORT_NUM_MASK + 1;
|
||||
for (sl = editDef->cd_labels; sl != NULL; sl = sl->lab_next)
|
||||
{
|
||||
if (sl->lab_flags & PORT_DIR_MASK)
|
||||
{
|
||||
idx = sl->lab_flags & PORT_NUM_MASK;
|
||||
if (idx < i) i = idx;
|
||||
}
|
||||
}
|
||||
if (i == PORT_NUM_MASK + 1) i = -1;
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(i));
|
||||
#else
|
||||
TxPrintf("%d\n", i);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case PORT_NEXT:
|
||||
refidx = lab->lab_flags & PORT_NUM_MASK;
|
||||
i = PORT_NUM_MASK + 1;
|
||||
for (sl = editDef->cd_labels; sl != NULL; sl = sl->lab_next)
|
||||
{
|
||||
if (sl->lab_flags & PORT_DIR_MASK)
|
||||
{
|
||||
idx = sl->lab_flags & PORT_NUM_MASK;
|
||||
if (idx > refidx)
|
||||
if (idx < i) i = idx;
|
||||
}
|
||||
}
|
||||
if (i == PORT_NUM_MASK + 1) i = -1;
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(i));
|
||||
#else
|
||||
TxPrintf("Index = %d\n", i);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case PORT_EXISTS:
|
||||
if (!(lab->lab_flags & PORT_DIR_MASK))
|
||||
{
|
||||
|
|
@ -1732,6 +1822,57 @@ CmdPort(w, cmd)
|
|||
editDef->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
|
||||
break;
|
||||
|
||||
case PORT_RENUMBER:
|
||||
/* Renumber ports in canonical order (by alphabetical
|
||||
* order of the label text). NOTE: Because SPICE is
|
||||
* case-insensitive, case-insensitive alphabetical order
|
||||
* is used.
|
||||
*/
|
||||
{
|
||||
int numlabels, n, p;
|
||||
Label **slablist, *tlab, *lastlab;
|
||||
extern int complabel();
|
||||
|
||||
/* Create a sortable list of labels */
|
||||
numlabels = 0;
|
||||
for (lab = editDef->cd_labels; lab; lab = lab->lab_next)
|
||||
numlabels++;
|
||||
|
||||
slablist = (Label **)mallocMagic(numlabels * sizeof(Label *));
|
||||
numlabels = 0;
|
||||
for (lab = editDef->cd_labels; lab; lab = lab->lab_next)
|
||||
{
|
||||
*(slablist + numlabels) = lab;
|
||||
numlabels++;
|
||||
}
|
||||
|
||||
/* Sort the list */
|
||||
qsort(slablist, numlabels, sizeof(Label *), complabel);
|
||||
|
||||
/* Number the ports by sorted order */
|
||||
p = 0;
|
||||
lastlab = NULL;
|
||||
for (n = 0; n < numlabels; n++)
|
||||
{
|
||||
tlab = *(slablist + n);
|
||||
if (tlab->lab_flags & PORT_DIR_MASK)
|
||||
{
|
||||
if (lastlab)
|
||||
if (!strcmp(lastlab->lab_text, tlab->lab_text))
|
||||
p--;
|
||||
|
||||
tlab->lab_flags &= ~PORT_NUM_MASK;
|
||||
tlab->lab_flags |= p;
|
||||
lastlab = tlab;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean up */
|
||||
freeMagic((char *)slablist);
|
||||
}
|
||||
break;
|
||||
|
||||
case PORT_MAKEALL:
|
||||
lab = editDef->cd_labels;
|
||||
// Fall through. . .
|
||||
|
|
|
|||
|
|
@ -680,12 +680,13 @@ CmdSelect(w, cmd)
|
|||
#define SEL_PICK 8
|
||||
#define SEL_SAVE 9
|
||||
#define SEL_FEEDBACK 10
|
||||
#define SEL_BOX 11
|
||||
#define SEL_CHUNK 12
|
||||
#define SEL_REGION 13
|
||||
#define SEL_NET 14
|
||||
#define SEL_SHORT 15
|
||||
#define SEL_DEFAULT 16
|
||||
#define SEL_BBOX 11
|
||||
#define SEL_BOX 12
|
||||
#define SEL_CHUNK 13
|
||||
#define SEL_REGION 14
|
||||
#define SEL_NET 15
|
||||
#define SEL_SHORT 16
|
||||
#define SEL_DEFAULT 17
|
||||
|
||||
static char *cmdSelectOption[] =
|
||||
{
|
||||
|
|
@ -700,6 +701,7 @@ CmdSelect(w, cmd)
|
|||
"pick",
|
||||
"save",
|
||||
"feedback",
|
||||
"bbox",
|
||||
"box",
|
||||
"chunk",
|
||||
"region",
|
||||
|
|
@ -724,6 +726,7 @@ CmdSelect(w, cmd)
|
|||
"pick delete selection from layout",
|
||||
"save file save selection on disk in file.mag",
|
||||
"feedback [style] copy selection to feedback",
|
||||
"bbox return the bounding box of the selection",
|
||||
"[more | less] box | chunk | region | net [layers]\n"
|
||||
" [de]select chunk/region/net specified by\n"
|
||||
" the lower left corner of the current box",
|
||||
|
|
@ -775,6 +778,7 @@ CmdSelect(w, cmd)
|
|||
bool more = FALSE, less = FALSE, samePlace = TRUE;
|
||||
#ifdef MAGIC_WRAPPER
|
||||
char *tclstr;
|
||||
Tcl_Obj *lobj;
|
||||
#endif
|
||||
|
||||
/* How close two clicks must be to be considered the same point: */
|
||||
|
|
@ -933,6 +937,32 @@ CmdSelect(w, cmd)
|
|||
TxPrintf(" select %s\n", *msg);
|
||||
return;
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
* Print or return the bounding box of the selection
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
case SEL_BBOX:
|
||||
GeoTransRect(&SelectUse->cu_transform, &SelectDef->cd_bbox, &selarea);
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
lobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewIntObj(selarea.r_xbot));
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewIntObj(selarea.r_ybot));
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewIntObj(selarea.r_xtop));
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewIntObj(selarea.r_ytop));
|
||||
Tcl_SetObjResult(magicinterp, lobj);
|
||||
#else
|
||||
TxPrintf("Select bounding box: %d %d %d %d\n",
|
||||
selarea.r_xbot, selarea.r_ybot,
|
||||
selarea.r_xtop, selarea.r_ytop);
|
||||
#endif
|
||||
return;
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
* Make a copy of the selection at its present loction but do not
|
||||
* clear the selection.
|
||||
|
|
|
|||
|
|
@ -774,6 +774,37 @@ again:
|
|||
return (returnname);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* nameEllipsis ---
|
||||
*
|
||||
* Truncate a string an append an ellipsis ("...") to the end if the string
|
||||
* will overflow a fixed array length.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static char *
|
||||
nameEllipsis(name, maxlen, prefix)
|
||||
char *name;
|
||||
int maxlen;
|
||||
char **prefix;
|
||||
{
|
||||
int l = strlen(name);
|
||||
|
||||
if (l < maxlen)
|
||||
{
|
||||
*prefix = "";
|
||||
return name;
|
||||
}
|
||||
else
|
||||
{
|
||||
*prefix = "...";
|
||||
return &name[l - maxlen + 3];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -804,12 +835,14 @@ cmdSaveWindSet(window, def)
|
|||
{
|
||||
char caption[200];
|
||||
CellDef *rootDef;
|
||||
char *name, *name_pfx;
|
||||
|
||||
rootDef = ((CellUse *) window->w_surfaceID)->cu_def;
|
||||
if (rootDef != def)
|
||||
return 0;
|
||||
|
||||
(void) sprintf(caption, "%s [NOT BEING EDITED]", def->cd_name);
|
||||
name = nameEllipsis(def->cd_name, 175, &name_pfx);
|
||||
(void) snprintf(caption, sizeof(caption), "%s%s [NOT BEING EDITED]", name_pfx, name);
|
||||
(void) StrDup(&window->w_iconname, def->cd_name);
|
||||
WindCaption(window, caption);
|
||||
return 0;
|
||||
|
|
@ -896,13 +929,22 @@ cmdWindSet(window)
|
|||
{
|
||||
char caption[200];
|
||||
CellDef *wDef;
|
||||
char *name[2], *name_pfx[2];
|
||||
|
||||
wDef = ((CellUse *) window->w_surfaceID)->cu_def;
|
||||
if (wDef != newRootDef)
|
||||
(void) sprintf(caption, "%s [NOT BEING EDITED]", wDef->cd_name);
|
||||
else {
|
||||
(void) sprintf(caption, "%s EDITING %s", wDef->cd_name,
|
||||
newEditDef->cd_name);
|
||||
|
||||
|
||||
|
||||
if (wDef != newRootDef) {
|
||||
name[0] = nameEllipsis(wDef->cd_name, 175, &name_pfx[0]);
|
||||
(void) snprintf(caption, sizeof(caption), "%s%s [NOT BEING EDITED]",
|
||||
name_pfx[0], name[0]);
|
||||
} else {
|
||||
name[0] = nameEllipsis(wDef->cd_name, 90, &name_pfx[0]);
|
||||
name[1] = nameEllipsis(newEditDef->cd_name, 90, &name_pfx[1]);
|
||||
(void) snprintf(caption, sizeof(caption), "%s%s EDITING %s%s",
|
||||
name_pfx[0], name[0], name_pfx[1], name[1]);
|
||||
|
||||
#ifdef SCHEME_INTERPRETER
|
||||
/* Add a binding to scheme variable "edit-cell" */
|
||||
LispSetEdit (newEditDef->cd_name);
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ DBDescendSubcell(use, xMask)
|
|||
*
|
||||
* Copies the contents of the CellDef pointed to by sourceDef into the
|
||||
* CellDef pointed to by destDef. Only the planes, labels, flags,
|
||||
* use-id hash table, and bounding box are copied.
|
||||
* cell plane, use-id hash table, and bounding box are copied.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
|
|
@ -131,6 +131,8 @@ DBCellCopyDefBody(sourceDef, destDef)
|
|||
for (i = 0; i < MAXPLANES; i++)
|
||||
destDef->cd_planes[i] = sourceDef->cd_planes[i];
|
||||
|
||||
destDef->cd_cellPlane = sourceDef->cd_cellPlane;
|
||||
|
||||
/* Be careful to update parent pointers in the children of dest.
|
||||
* Don't allow interrupts to wreck this.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -2986,7 +2986,7 @@ DBCellWrite(cellDef, fileName)
|
|||
if (realf == NULL)
|
||||
{
|
||||
cellDef->cd_flags |= CDMODIFIED;
|
||||
TxError("Warning: Cannot open file for writing!\n");
|
||||
TxError("Warning: Cannot open file \"%s\" for writing!\n", expandname);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2994,7 +2994,7 @@ DBCellWrite(cellDef, fileName)
|
|||
if (thestat.st_size != DBFileOffset)
|
||||
{
|
||||
cellDef->cd_flags |= CDMODIFIED;
|
||||
TxError("Warning: I/O error in writing file\n");
|
||||
TxError("Warning: I/O error in writing file \"%s\"\n", expandname);
|
||||
}
|
||||
fclose(realf);
|
||||
}
|
||||
|
|
@ -3173,7 +3173,13 @@ dbWriteCellFunc(cellUse, cdarg)
|
|||
}
|
||||
else
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* If there are no common components, then restore the leading '/' */
|
||||
if ((*pathorigin == '/') && (pathstart == pathorigin + 1))
|
||||
pathstart = pathorigin;
|
||||
|
||||
if (pathend != NULL)
|
||||
{
|
||||
*pathend = '\0';
|
||||
|
|
|
|||
|
|
@ -600,6 +600,7 @@ dbTechAddPaintErase(type, sectionName, argc, argv)
|
|||
int pNum;
|
||||
PlaneMask pMask, rMask;
|
||||
TileType t1, t2, tres;
|
||||
TileTypeBitMask tMask;
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
|
|
@ -609,7 +610,13 @@ dbTechAddPaintErase(type, sectionName, argc, argv)
|
|||
|
||||
if ((t1 = DBTechNoisyNameType(argv[0])) < 0) return FALSE;
|
||||
if ((t2 = DBTechNoisyNameType(argv[1])) < 0) return FALSE;
|
||||
if ((tres = DBTechNoisyNameType(argv[2])) < 0) return FALSE;
|
||||
|
||||
/* Modified 9/22/2020 to allow multiple types to paint, for example */
|
||||
/* to replace a contact type with types on both residue planes. */
|
||||
|
||||
rMask = DBTechNoisyNameMask(argv[2], &tMask);
|
||||
if (TTMaskIsZero(&tMask)) return FALSE;
|
||||
|
||||
if (argc == 3)
|
||||
{
|
||||
if (t1 == TT_SPACE)
|
||||
|
|
@ -629,51 +636,46 @@ dbTechAddPaintErase(type, sectionName, argc, argv)
|
|||
else
|
||||
pMask = PlaneNumToMaskBit(pNum);
|
||||
}
|
||||
rMask = LayerPlaneMask(tres);
|
||||
|
||||
/* (The plane mask of "tres" may be a subset of t1, but NOT vice */
|
||||
/* versa. Otherwise we will end up creating rules that are not */
|
||||
/* dependent on t1 in some planes.) */
|
||||
|
||||
/* This restriction lifted 5/11/04 with code in DBPaint() that */
|
||||
/* recursively paints image types onto planes where they may be */
|
||||
/* missed by the inability to generate the correct paint table for */
|
||||
/* the operation. */
|
||||
|
||||
// if (rMask & ~pMask)
|
||||
// {
|
||||
// TechError("Planes of result type must be a subset of those of have-type\n");
|
||||
// return FALSE;
|
||||
// }
|
||||
|
||||
pMask &= ~rMask;
|
||||
|
||||
for (tres = 0; tres < DBNumTypes; tres++)
|
||||
{
|
||||
if (TTMaskHasType(&tMask, tres))
|
||||
{
|
||||
if (type == RULE_PAINT)
|
||||
{
|
||||
/* Apply to all planes of rMask. */
|
||||
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
if (PlaneMaskHasPlane(rMask, pNum))
|
||||
if (DBTypeOnPlane(tres, pNum))
|
||||
dbSetPaintEntry(t1, t2, pNum, tres);
|
||||
}
|
||||
else /* (type == RULE_ERASE) */
|
||||
{
|
||||
/* Apply to all planes of rMask. */
|
||||
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
if (PlaneMaskHasPlane(rMask, pNum))
|
||||
if (DBTypeOnPlane(tres, pNum))
|
||||
dbSetEraseEntry(t1, t2, pNum, tres);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type == RULE_PAINT)
|
||||
{
|
||||
/* Apply to all planes of rMask. */
|
||||
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
if (PlaneMaskHasPlane(rMask, pNum))
|
||||
dbSetPaintEntry(t1, t2, pNum, tres);
|
||||
|
||||
/* For all planes of pMask which are not in rMask, result is space */
|
||||
|
||||
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
if (PlaneMaskHasPlane(pMask, pNum))
|
||||
dbSetPaintEntry(t1, t2, pNum, TT_SPACE);
|
||||
dbSetPaintEntry(t1, t2, pNum, TT_SPACE);
|
||||
}
|
||||
else /* (type == RULE_ERASE) */
|
||||
{
|
||||
/* Apply to all planes of rMask. */
|
||||
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
if (PlaneMaskHasPlane(rMask, pNum))
|
||||
dbSetEraseEntry(t1, t2, pNum, tres);
|
||||
|
||||
/* For all planes of pMask which are not in rMask, result is space */
|
||||
|
||||
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
if (PlaneMaskHasPlane(pMask, pNum))
|
||||
dbSetEraseEntry(t1, t2, pNum, TT_SPACE);
|
||||
|
|
|
|||
26
drc/DRCcif.c
26
drc/DRCcif.c
|
|
@ -200,7 +200,7 @@ drcCifWidth(argc, argv)
|
|||
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
||||
drcCifAssign(dpnew, centidistance, dpnext, &CIFSolidBits,
|
||||
&CIFSolidBits, why, centidistance,
|
||||
DRC_FORWARD, thislayer, 0);
|
||||
DRC_FORWARD | DRC_CIFRULE, thislayer, 0);
|
||||
drcCifRules[thislayer][DRC_CIF_SPACE] = dpnew;
|
||||
|
||||
return ((centidistance+scalefactor-1)/scalefactor);
|
||||
|
|
@ -291,7 +291,7 @@ drcCifSpacing(argc, argv)
|
|||
dpnext = drcCifRules[layer[0]][DRC_CIF_SOLID];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) sizeof (DRCCookie));
|
||||
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits,
|
||||
&cmask, why, centidistance, DRC_FORWARD, layer[1], 0);
|
||||
&cmask, why, centidistance, DRC_FORWARD | DRC_CIFRULE, layer[1], 0);
|
||||
drcCifRules[layer[0]][DRC_CIF_SOLID] = dpnew;
|
||||
if (needReverse) dpnew->drcc_flags |= DRC_BOTHCORNERS;
|
||||
|
||||
|
|
@ -299,7 +299,7 @@ drcCifSpacing(argc, argv)
|
|||
dpnext = drcCifRules[layer[0]][DRC_CIF_SPACE];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) sizeof (DRCCookie));
|
||||
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits,
|
||||
&cmask, why, centidistance, DRC_REVERSE, layer[1], 0);
|
||||
&cmask, why, centidistance, DRC_REVERSE | DRC_CIFRULE, layer[1], 0);
|
||||
drcCifRules[layer[0]][DRC_CIF_SPACE] = dpnew;
|
||||
|
||||
if (needReverse)
|
||||
|
|
@ -311,14 +311,16 @@ drcCifSpacing(argc, argv)
|
|||
dpnext = drcCifRules[layer[1]][DRC_CIF_SOLID];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
||||
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask,
|
||||
why, centidistance, DRC_FORWARD|DRC_BOTHCORNERS, layer[0], 0);
|
||||
why, centidistance, DRC_FORWARD|DRC_BOTHCORNERS | DRC_CIFRULE,
|
||||
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));
|
||||
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask,
|
||||
why, centidistance, DRC_REVERSE|DRC_BOTHCORNERS, layer[0], 0);
|
||||
why, centidistance, DRC_REVERSE|DRC_BOTHCORNERS | DRC_CIFRULE,
|
||||
layer[0], 0);
|
||||
drcCifRules[layer[1]][DRC_CIF_SPACE] = dpnew;
|
||||
|
||||
if (layer[0] == layer[1])
|
||||
|
|
@ -326,14 +328,16 @@ drcCifSpacing(argc, argv)
|
|||
dpnext = drcCifRules[layer[1]][DRC_CIF_SPACE];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
||||
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits,
|
||||
&cmask, why, centidistance, DRC_REVERSE | DRC_BOTHCORNERS,
|
||||
&cmask, why, centidistance,
|
||||
DRC_REVERSE | DRC_BOTHCORNERS | DRC_CIFRULE,
|
||||
layer[0], 0);
|
||||
drcCifRules[layer[1]][DRC_CIF_SPACE] = dpnew;
|
||||
|
||||
dpnext = drcCifRules[layer[0]][DRC_CIF_SPACE];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
||||
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask,
|
||||
why, centidistance, DRC_REVERSE | DRC_BOTHCORNERS,
|
||||
why, centidistance,
|
||||
DRC_REVERSE | DRC_BOTHCORNERS | DRC_CIFRULE,
|
||||
layer[1], 0);
|
||||
drcCifRules[layer[0]][DRC_CIF_SPACE] = dpnew;
|
||||
}
|
||||
|
|
@ -344,13 +348,13 @@ drcCifSpacing(argc, argv)
|
|||
dpnext = drcCifRules[layer[1]][DRC_CIF_SPACE];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
||||
drcCifAssign(dpnew, scalefactor, dpnext, &DBSpaceBits, &DBZeroTypeBits,
|
||||
why, scalefactor, DRC_FORWARD, layer[0], 0);
|
||||
why, scalefactor, DRC_FORWARD | DRC_CIFRULE, layer[0], 0);
|
||||
drcCifRules[layer[1]][DRC_CIF_SPACE] = dpnew;
|
||||
|
||||
dpnext = drcCifRules[layer[0]][DRC_CIF_SPACE];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
||||
drcCifAssign(dpnew, scalefactor, dpnext, &DBSpaceBits, &DBZeroTypeBits,
|
||||
why, scalefactor, DRC_FORWARD, layer[1], 0);
|
||||
why, scalefactor, DRC_FORWARD | DRC_CIFRULE, layer[1], 0);
|
||||
drcCifRules[layer[0]][DRC_CIF_SPACE] = dpnew;
|
||||
}
|
||||
|
||||
|
|
@ -1097,7 +1101,7 @@ drcCifArea(argc, argv)
|
|||
dpnext = drcCifRules[thislayer][DRC_CIF_SPACE];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
||||
drcCifAssign(dpnew, centihorizon, dpnext, &CIFSolidBits, &CIFSolidBits,
|
||||
why, centiarea, DRC_AREA | DRC_FORWARD, thislayer, 0);
|
||||
why, centiarea, DRC_AREA | DRC_FORWARD | DRC_CIFRULE, thislayer, 0);
|
||||
drcCifRules[thislayer][DRC_CIF_SPACE] = dpnew;
|
||||
|
||||
|
||||
|
|
@ -1167,7 +1171,7 @@ drcCifMaxwidth(argc, argv)
|
|||
dpnext = drcCifRules[thislayer][DRC_CIF_SPACE];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
||||
drcCifAssign(dpnew, centidistance, dpnext, &CIFSolidBits, &CIFSolidBits,
|
||||
why, centidistance, DRC_MAXWIDTH | bend, thislayer, 0);
|
||||
why, centidistance, DRC_MAXWIDTH | DRC_CIFRULE | bend, thislayer, 0);
|
||||
drcCifRules[thislayer][DRC_CIF_SPACE] = dpnew;
|
||||
|
||||
return ((centidistance+scalefactor-1)/scalefactor);
|
||||
|
|
|
|||
|
|
@ -197,14 +197,24 @@ DRCCheckThis (celldef, operation, area)
|
|||
* of CellDefs waiting for DRC
|
||||
*/
|
||||
|
||||
/* Ignore read-only, internal, and vendor GDS cells. None of these */
|
||||
/* can contain DRC errors that could be fixed in magic. */
|
||||
/* Ignore internal GDS cells. */
|
||||
/* Note that this rescinds the former behavior of ignoring DRC on */
|
||||
/* vendor and read-only cells. Such cells will be flattened in */
|
||||
/* interaction areas and show errors anyway, so not showing errors */
|
||||
/* in the cell is just confusing. */
|
||||
|
||||
if (celldef->cd_flags & (CDVENDORGDS | CDNOEDIT | CDINTERNAL)) return;
|
||||
if (celldef->cd_flags & CDINTERNAL) return;
|
||||
|
||||
/* Insert celldef into list of Defs waiting to be checked, unless */
|
||||
/* it is already there. */
|
||||
|
||||
#if (0)
|
||||
|
||||
/* The switch to copying up DRC errors from non-interacting */
|
||||
/* child cells means that the child cells must be processed */
|
||||
/* first. So this routine changes from prepending the cell */
|
||||
/* to the list to appending it. */
|
||||
|
||||
pback = &DRCPendingRoot;
|
||||
p = DRCPendingRoot;
|
||||
|
||||
|
|
@ -226,6 +236,33 @@ DRCCheckThis (celldef, operation, area)
|
|||
p->dpc_next = DRCPendingRoot;
|
||||
DRCPendingRoot = p;
|
||||
|
||||
#endif
|
||||
/* Append new cell to check to the pending list */
|
||||
if (DRCPendingRoot == NULL)
|
||||
{
|
||||
p = (DRCPendingCookie *) mallocMagic(sizeof (DRCPendingCookie));
|
||||
p->dpc_def = celldef;
|
||||
p->dpc_next = NULL;
|
||||
DRCPendingRoot = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
DRCPendingCookie *plast;
|
||||
plast = DRCPendingRoot;
|
||||
while (plast->dpc_next != NULL)
|
||||
{
|
||||
if (plast->dpc_def == celldef) break;
|
||||
plast = plast->dpc_next;
|
||||
}
|
||||
if (plast->dpc_next == NULL)
|
||||
{
|
||||
p = (DRCPendingCookie *) mallocMagic(sizeof (DRCPendingCookie));
|
||||
p->dpc_def = celldef;
|
||||
p->dpc_next = NULL;
|
||||
plast->dpc_next = p;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark the area in this celldef (but don't worry about this stuff
|
||||
* for undo purposes). Also, it's important to disable interrupts
|
||||
* in here, or the paint operation could get aborted underneath us.
|
||||
|
|
@ -683,7 +720,7 @@ drcCheckTile(tile, arg)
|
|||
|
||||
DRCErrorType = TT_ERROR_S;
|
||||
(void) DRCInteractionCheck(celldef, &square, &erasebox,
|
||||
drcPaintError, (ClientData) drcTempPlane);
|
||||
drcPaintError, (ClientData)drcTempPlane);
|
||||
|
||||
/* Check #3: check for array formation errors in the area. */
|
||||
|
||||
|
|
@ -707,7 +744,7 @@ drcCheckTile(tile, arg)
|
|||
DBPaintPlane(celldef->cd_planes[PL_DRC_CHECK], &erasebox,
|
||||
DBStdEraseTbl(TiGetType(tile), PL_DRC_CHECK),
|
||||
(PaintUndoInfo *) NULL);
|
||||
DBPaintPlane(celldef->cd_planes[PL_DRC_ERROR], &checkbox,
|
||||
DBPaintPlane(celldef->cd_planes[PL_DRC_ERROR], &erasebox,
|
||||
DBStdEraseTbl(TT_ERROR_P, PL_DRC_ERROR),
|
||||
(PaintUndoInfo *) NULL);
|
||||
DBPaintPlane(celldef->cd_planes[PL_DRC_ERROR], &checkbox,
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "windows/windows.h"
|
||||
#include "dbwind/dbwind.h"
|
||||
#include "drc/drc.h"
|
||||
#include "cif/cif.h"
|
||||
#include "utils/undo.h"
|
||||
|
||||
/* The global variables defined below are parameters between
|
||||
|
|
@ -201,7 +202,10 @@ drcSubstitute (cptr)
|
|||
why_out = (char *)mallocMagic(whylen * sizeof(char));
|
||||
strcpy(why_out, whyptr);
|
||||
|
||||
oscale = CIFGetOutputScale(1000); /* 1000 for conversion to um */
|
||||
if (cptr->drcc_flags & DRC_CIFRULE)
|
||||
oscale = CIFGetScale(100); /* 100 = microns to centimicrons */
|
||||
else
|
||||
oscale = CIFGetOutputScale(1000); /* 1000 for conversion to um */
|
||||
wptr = why_out;
|
||||
|
||||
while ((sptr = strchr(whyptr, '%')) != NULL)
|
||||
|
|
@ -611,11 +615,9 @@ drcWhyFunc(scx, cdarg)
|
|||
/* Check paint and interactions in this subcell. */
|
||||
|
||||
(void) DRCInteractionCheck(def, &scx->scx_area, &scx->scx_area,
|
||||
(dolist) ? drcListError : drcPrintError,
|
||||
(ClientData) scx);
|
||||
(dolist) ? drcListError : drcPrintError, (ClientData) scx);
|
||||
(void) DRCArrayCheck(def, &scx->scx_area,
|
||||
(dolist) ? drcListError : drcPrintError,
|
||||
(ClientData) scx);
|
||||
(dolist) ? drcListError : drcPrintError, (ClientData) scx);
|
||||
|
||||
/* New behavior: Don't search children, instead propagate errors up. */
|
||||
/* (void) DBCellSrArea(scx, drcWhyFunc, (ClientData)cdarg); */
|
||||
|
|
@ -635,9 +637,9 @@ drcWhyAllFunc(scx, cdarg)
|
|||
/* Check paint and interactions in this subcell. */
|
||||
|
||||
(void) DRCInteractionCheck(def, &scx->scx_area, &scx->scx_area,
|
||||
drcListallError, (ClientData)scx);
|
||||
drcListallError, (Plane *)NULL, (ClientData)scx);
|
||||
(void) DRCArrayCheck(def, &scx->scx_area,
|
||||
drcListallError, (ClientData)scx);
|
||||
drcListallError, (Plane *)NULL, (ClientData)scx);
|
||||
|
||||
/* New behavior: Don't search children, instead propagate errors up. */
|
||||
/* (void) DBCellSrArea(scx, drcWhyAllFunc, (ClientData)cdarg); */
|
||||
|
|
|
|||
|
|
@ -61,6 +61,19 @@ static DRCCookie drcSubcellCookie = {
|
|||
(DRCCookie *) NULL
|
||||
};
|
||||
|
||||
/* The cookie below is dummied up to provide an error message for
|
||||
* errors that are in a subcell non-interaction area and have been
|
||||
* copied up into the parent without flattening
|
||||
*/
|
||||
|
||||
static DRCCookie drcInSubCookie = {
|
||||
0, 0, 0, 0,
|
||||
{ 0 }, { 0 },
|
||||
0, 0, 0,
|
||||
DRC_IN_SUBCELL_TAG,
|
||||
(DRCCookie *) NULL
|
||||
};
|
||||
|
||||
extern int DRCErrorType;
|
||||
|
||||
/*
|
||||
|
|
@ -94,6 +107,33 @@ drcFindOtherCells(use, area)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* For each tile found in drcCopyErrorsFunc(), translate the */
|
||||
/* tile position into the coordinate system of the parent cell */
|
||||
/* (represented by the drcTemp plane in ClientData) and */
|
||||
/* copy (paint) into it. */
|
||||
|
||||
int
|
||||
drcSubCopyErrors(tile, cxp)
|
||||
Tile *tile;
|
||||
TreeContext *cxp;
|
||||
{
|
||||
Rect area;
|
||||
Rect destArea;
|
||||
struct drcClientData *arg = (struct drcClientData *)cxp->tc_filter->tf_arg;
|
||||
|
||||
// DBTreeSrTiles() checks its own tiles, which we want to ignore.
|
||||
if (arg->dCD_celldef == cxp->tc_scx->scx_use->cu_def) return 0;
|
||||
|
||||
TiToRect(tile, &area);
|
||||
GeoClip(&area, &cxp->tc_scx->scx_area);
|
||||
GeoTransRect(&cxp->tc_scx->scx_trans, &area, &destArea);
|
||||
|
||||
(*(arg->dCD_function))(arg->dCD_celldef, &destArea, arg->dCD_cptr,
|
||||
arg->dCD_clientData);
|
||||
(*(arg->dCD_errors))++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
|
|
@ -146,12 +186,24 @@ drcSubcellFunc(subUse, propagate)
|
|||
/* all cells are checked and errors propagate to the top level. */
|
||||
|
||||
subIntArea = GeoNullRect;
|
||||
|
||||
#if (0)
|
||||
/* NOTE: DRC errors inside a subcell should be ignored for */
|
||||
/* the purpose of finding interactions. Errors should only */
|
||||
/* be copied up into the parent when in a non-interaction */
|
||||
/* area. This is done below in DRCFindInteractions(). */
|
||||
/* (Method added by Tim, 10/15/2020) */
|
||||
|
||||
/* Maybe S and PS errors should be pulled here? */
|
||||
|
||||
DBSrPaintArea((Tile *) NULL, subUse->cu_def->cd_planes[PL_DRC_ERROR],
|
||||
&TiPlaneRect, &DBAllButSpaceBits, drcIncludeArea,
|
||||
(ClientData) &subIntArea);
|
||||
|
||||
GeoTransRect(&(subUse->cu_transform), &subIntArea, &locIntArea);
|
||||
GeoInclude(&locIntArea, &intArea);
|
||||
#endif
|
||||
|
||||
if (!GEO_RECTNULL(&subIntArea)) *propagate = TRUE;
|
||||
|
||||
drcCurSub = subUse;
|
||||
|
|
@ -555,12 +607,17 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
void (*savedPaintPlane)();
|
||||
struct drcClientData arg;
|
||||
SearchContext scx;
|
||||
TileTypeBitMask drcMask;
|
||||
|
||||
drcSubFunc = func;
|
||||
drcSubClientData = cdarg;
|
||||
oldTiles = DRCstatTiles;
|
||||
count = 0;
|
||||
|
||||
/* Create a mask with only TT_ERROR_P in it */
|
||||
TTMaskZero(&drcMask);
|
||||
TTMaskSetType(&drcMask, TT_ERROR_P);
|
||||
|
||||
/* Divide the area to be checked up into squares. Process each
|
||||
* square separately.
|
||||
*/
|
||||
|
|
@ -585,6 +642,16 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
cliparea = square;
|
||||
GeoClip(&cliparea, area);
|
||||
|
||||
/* Prepare for subcell search */
|
||||
DRCDummyUse->cu_def = def;
|
||||
scx.scx_use = DRCDummyUse;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
arg.dCD_celldef = def;
|
||||
arg.dCD_errors = &count;
|
||||
arg.dCD_cptr = &drcInSubCookie;
|
||||
arg.dCD_function = func;
|
||||
arg.dCD_clientData = cdarg;
|
||||
|
||||
/* Find all the interactions in the square, and clip to the error
|
||||
* area we're interested in. */
|
||||
|
||||
|
|
@ -600,6 +667,11 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
errorSaveType = DRCErrorType;
|
||||
DRCErrorType = TT_ERROR_P; // Basic check is always ERROR_P
|
||||
DRCBasicCheck(def, &intArea, &subArea, func, cdarg);
|
||||
|
||||
/* Copy errors up from all non-interacting children */
|
||||
scx.scx_area = subArea;
|
||||
DBTreeSrTiles(&scx, &drcMask, 0, drcSubCopyErrors, &arg);
|
||||
|
||||
DRCErrorType = errorSaveType;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -632,6 +704,9 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
subArea.r_ybot = intArea.r_ytop;
|
||||
GEO_EXPAND(&subArea, DRCTechHalo, &eraseHalo);
|
||||
DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg);
|
||||
/* Copy errors up from all non-interacting children */
|
||||
scx.scx_area = subArea;
|
||||
DBTreeSrTiles(&scx, &drcMask, 0, drcSubCopyErrors, &arg);
|
||||
}
|
||||
/* check below */
|
||||
if (intArea.r_ybot > eraseClip.r_ybot)
|
||||
|
|
@ -640,6 +715,9 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
subArea.r_ytop = intArea.r_ybot;
|
||||
GEO_EXPAND(&subArea, DRCTechHalo, &eraseHalo);
|
||||
DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg);
|
||||
/* Copy errors up from all non-interacting children */
|
||||
scx.scx_area = subArea;
|
||||
DBTreeSrTiles(&scx, &drcMask, 0, drcSubCopyErrors, &arg);
|
||||
}
|
||||
subArea.r_ytop = intArea.r_ytop;
|
||||
subArea.r_ybot = intArea.r_ybot;
|
||||
|
|
@ -650,6 +728,9 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
subArea.r_xbot = intArea.r_xtop;
|
||||
GEO_EXPAND(&subArea, DRCTechHalo, &eraseHalo);
|
||||
DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg);
|
||||
/* Copy errors up from all non-interacting children */
|
||||
scx.scx_area = subArea;
|
||||
DBTreeSrTiles(&scx, &drcMask, 0, drcSubCopyErrors, &arg);
|
||||
}
|
||||
/* check left */
|
||||
if (intArea.r_xbot > eraseClip.r_xbot)
|
||||
|
|
@ -658,6 +739,9 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
subArea.r_xbot = eraseClip.r_xbot;
|
||||
GEO_EXPAND(&subArea, DRCTechHalo, &eraseHalo);
|
||||
DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg);
|
||||
/* Copy errors up from all non-interacting children */
|
||||
scx.scx_area = subArea;
|
||||
DBTreeSrTiles(&scx, &drcMask, 0, drcSubCopyErrors, &arg);
|
||||
}
|
||||
DRCErrorType = errorSaveType;
|
||||
}
|
||||
|
|
@ -672,9 +756,6 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
|
||||
DRCstatInteractions += 1;
|
||||
GEO_EXPAND(&intArea, DRCTechHalo, &scx.scx_area);
|
||||
DRCDummyUse->cu_def = def;
|
||||
scx.scx_use = DRCDummyUse;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
DBCellClearDef(DRCdef);
|
||||
|
||||
savedPaintTable = DBNewPaintTable(DRCCurStyle->DRCPaintTable);
|
||||
|
|
@ -696,15 +777,10 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
|
||||
/* Check for illegal partial overlaps. */
|
||||
|
||||
scx.scx_use = DRCDummyUse;
|
||||
scx.scx_area = intArea;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
arg.dCD_celldef = DRCdef;
|
||||
arg.dCD_clip = &intArea;
|
||||
arg.dCD_errors = &count;
|
||||
arg.dCD_celldef = DRCdef;
|
||||
arg.dCD_cptr = &drcSubcellCookie;
|
||||
arg.dCD_function = func;
|
||||
arg.dCD_clientData = cdarg;
|
||||
(void) DBTreeSrUniqueTiles(&scx, &DRCCurStyle->DRCExactOverlapTypes,
|
||||
0, drcExactOverlapTile, (ClientData) &arg);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -582,6 +582,11 @@ DRCTechStyleInit()
|
|||
/* (see DRCsubcell.c). */
|
||||
drcWhyCreate("This layer can't abut or partially overlap between subcells");
|
||||
|
||||
/* Fourth DRC entry is associated with the statically-allocated */
|
||||
/* drcSubcellCookie and has a tag of DRC_IN_SUBCELL_TAG = 4 */
|
||||
/* (see DRCsubcell.c). */
|
||||
drcWhyCreate("See error definition in the subcell");
|
||||
|
||||
DRCTechHalo = 0;
|
||||
|
||||
/* Put a dummy rule at the beginning of the rules table for each entry */
|
||||
|
|
@ -1762,7 +1767,7 @@ drcMaskSpacing(set1, set2, pmask1, pmask2, wwidth, distance, adjacency,
|
|||
{
|
||||
needtrigger = TRUE;
|
||||
touchingok = FALSE;
|
||||
|
||||
needReverse = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2000,6 +2005,9 @@ drcMaskSpacing(set1, set2, pmask1, pmask2, wwidth, distance, adjacency,
|
|||
TTMaskClearMask3(&tmp1, &DBPlaneTypes[plane2], set1);
|
||||
TTMaskAndMask3(&tmp2, &DBPlaneTypes[plane], &setRreverse);
|
||||
|
||||
/* NOTE: This is needed for some situation, but I */
|
||||
/* do not recall the exact nature of it. In other */
|
||||
/* cases only the simple rule check is needed. */
|
||||
if (needtrigger)
|
||||
{
|
||||
DRCCookie *dptrig;
|
||||
|
|
@ -2036,6 +2044,7 @@ drcMaskSpacing(set1, set2, pmask1, pmask2, wwidth, distance, adjacency,
|
|||
dp = drcFindBucket(j, i, distance);
|
||||
dpnew = (DRCCookie *) mallocMagic(sizeof (DRCCookie));
|
||||
|
||||
/* See above */
|
||||
if (needtrigger)
|
||||
{
|
||||
DRCCookie *dptrig;
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ typedef struct drccookie
|
|||
unsigned char drcc_cmod; /* Fractional part of drcc_cdist */
|
||||
TileTypeBitMask drcc_mask; /* Legal types on RHS */
|
||||
TileTypeBitMask drcc_corner; /* Types that trigger corner check */
|
||||
unsigned char drcc_flags; /* Miscellaneous flags, see below. */
|
||||
unsigned short drcc_flags; /* Miscellaneous flags, see below. */
|
||||
int drcc_edgeplane; /* Plane of edge */
|
||||
int drcc_plane; /* Index of plane on which to check
|
||||
* legal types. */
|
||||
|
|
@ -47,6 +47,7 @@ typedef struct drccookie
|
|||
#define DRC_ARRAY_OVERLAP_TAG 1
|
||||
#define DRC_OVERLAP_TAG 2
|
||||
#define DRC_SUBCELL_OVERLAP_TAG 3
|
||||
#define DRC_IN_SUBCELL_TAG 4
|
||||
|
||||
/* *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. */
|
||||
|
|
@ -74,6 +75,9 @@ typedef struct drccookie
|
|||
#define DRC_ANGLES 0x80
|
||||
#define DRC_NONSTANDARD (DRC_AREA|DRC_MAXWIDTH|DRC_RECTSIZE|DRC_ANGLES)
|
||||
|
||||
/* More flags for indicating what the rule type represents */
|
||||
#define DRC_CIFRULE 0x100
|
||||
|
||||
#define DRC_PENDING 0
|
||||
#define DRC_UNPROCESSED CLIENTDEFAULT
|
||||
#define DRC_PROCESSED 1
|
||||
|
|
@ -263,6 +267,7 @@ extern DRCCountList *DRCCount();
|
|||
extern int DRCFind();
|
||||
extern void DRCCatchUp();
|
||||
extern bool DRCFindInteractions();
|
||||
extern int DRCBasicCheck();
|
||||
|
||||
extern void DRCPrintStyle();
|
||||
extern void DRCSetStyle();
|
||||
|
|
|
|||
|
|
@ -92,7 +92,8 @@ FILE *esLabF = NULL;
|
|||
static unsigned short esFormat = MIT ;
|
||||
|
||||
struct {
|
||||
short resClassSD ; /* the resistance class of the src/drn of the dev */
|
||||
short resClassSource ; /* the resistance class of the source of the dev */
|
||||
short resClassDrain ; /* the resistance class of the drain of the dev */
|
||||
short resClassSub ; /* the resistance class of the substrate of the dev */
|
||||
char *defSubs ; /* the default substrate node */
|
||||
} fetInfo[MAXDEVTYPES];
|
||||
|
|
@ -262,8 +263,7 @@ CmdExtToSim(w, cmd)
|
|||
char **msg;
|
||||
bool err_result;
|
||||
|
||||
short sd_rclass;
|
||||
short sub_rclass;
|
||||
short s_rclass, d_rclass, sub_rclass;
|
||||
char *devname;
|
||||
char *subname;
|
||||
int idx;
|
||||
|
|
@ -572,7 +572,8 @@ runexttosim:
|
|||
|
||||
for ( i = 0 ; i < MAXDEVTYPES ; i++ )
|
||||
{
|
||||
fetInfo[i].resClassSD = NO_RESCLASS;
|
||||
fetInfo[i].resClassSource = NO_RESCLASS;
|
||||
fetInfo[i].resClassDrain = NO_RESCLASS;
|
||||
fetInfo[i].resClassSub = NO_RESCLASS;
|
||||
fetInfo[i].defSubs = NULL;
|
||||
}
|
||||
|
|
@ -582,7 +583,7 @@ runexttosim:
|
|||
/* command) */
|
||||
|
||||
idx = 0;
|
||||
while (ExtGetDevInfo(idx++, &devname, &sd_rclass, &sub_rclass, &subname))
|
||||
while (ExtGetDevInfo(idx++, &devname, &s_rclass, &d_rclass, &sub_rclass, &subname))
|
||||
{
|
||||
if (idx == MAXDEVTYPES)
|
||||
{
|
||||
|
|
@ -593,7 +594,8 @@ runexttosim:
|
|||
|
||||
if (EFStyle != NULL)
|
||||
{
|
||||
fetInfo[i].resClassSD = sd_rclass;
|
||||
fetInfo[i].resClassSource = s_rclass;
|
||||
fetInfo[i].resClassDrain = d_rclass;
|
||||
fetInfo[i].resClassSub = sub_rclass;
|
||||
fetInfo[i].defSubs = subname;
|
||||
}
|
||||
|
|
@ -670,24 +672,25 @@ main(argc, argv)
|
|||
/* create default fetinfo entries (MOSIS) which can be overriden by
|
||||
the command line arguments */
|
||||
for ( i = 0 ; i < MAXDEVTYPES ; i++ ) {
|
||||
fetInfo[i].resClassSD = NO_RESCLASS;
|
||||
fetInfo[i].resClassSource = NO_RESCLASS;
|
||||
fetInfo[i].resClassDrain = NO_RESCLASS;
|
||||
fetInfo[i].resClassSub = NO_RESCLASS;
|
||||
fetInfo[i].defSubs = NULL;
|
||||
}
|
||||
i = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, "nfet");
|
||||
fetInfo[i].resClassSD = 0 ;
|
||||
fetInfo[i].resClassSource = fetInfo[i].resClassDrain = 0 ;
|
||||
fetInfo[i].resClassSub = NO_RESCLASS ;
|
||||
fetInfo[i].defSubs = "Gnd!";
|
||||
i = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, "pfet");
|
||||
fetInfo[i].resClassSD = 1 ;
|
||||
fetInfo[i].resClassSource = fetInfo[i].resClassDrain = 1 ;
|
||||
fetInfo[i].resClassSub = 6 ;
|
||||
fetInfo[i].defSubs = "Vdd!";
|
||||
i = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, "nmos");
|
||||
fetInfo[i].resClassSD = 0 ;
|
||||
fetInfo[i].resClassSource = fetInfo[i].resClassDrain = 0 ;
|
||||
fetInfo[i].resClassSub = NO_RESCLASS ;
|
||||
fetInfo[i].defSubs = "Gnd!";
|
||||
i = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, "pmos");
|
||||
fetInfo[i].resClassSD = 1 ;
|
||||
fetInfo[i].resClassSource = fetInfo[i].resClassDrain = 1 ;
|
||||
fetInfo[i].resClassSub = 6 ;
|
||||
fetInfo[i].defSubs = "Vdd!";
|
||||
/* Process command line arguments */
|
||||
|
|
@ -888,7 +891,8 @@ simmainArgs(pargc, pargv)
|
|||
if ( sscanf(rp, "%d/%s", &rClass, subsNode) != 2 ) goto usage;
|
||||
}
|
||||
ndx = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, cp);
|
||||
fetInfo[ndx].resClassSD = rClass;
|
||||
fetInfo[ndx].resClassSource = rClass;
|
||||
fetInfo[ndx].resClassDrain = rClass;
|
||||
fetInfo[ndx].resClassSub = rClassSub;
|
||||
fetInfo[ndx].defSubs = (char *) mallocMagic((unsigned) (strlen(subsNode)+1));
|
||||
strcpy(fetInfo[ndx].defSubs,subsNode);
|
||||
|
|
@ -1160,12 +1164,12 @@ simdevVisit(dev, hc, scale, trans)
|
|||
if ( esFormat == SU ) {
|
||||
fprintf(esSimF, "%s", (source->dterm_attrs) ? "," : " s=" );
|
||||
if (hierS)
|
||||
simnAPHier(source, hierName, fetInfo[dev->dev_type].resClassSD,
|
||||
simnAPHier(source, hierName, fetInfo[dev->dev_type].resClassSource,
|
||||
scale, esSimF);
|
||||
else {
|
||||
snode= SimGetNode(hierName,
|
||||
source->dterm_node->efnode_name->efnn_hier);
|
||||
simnAP(snode, fetInfo[dev->dev_type].resClassSD, scale, esSimF);
|
||||
simnAP(snode, fetInfo[dev->dev_type].resClassSource, scale, esSimF);
|
||||
}
|
||||
}
|
||||
if (drain->dterm_attrs) {
|
||||
|
|
@ -1178,12 +1182,12 @@ simdevVisit(dev, hc, scale, trans)
|
|||
if ( esFormat == SU ) {
|
||||
fprintf(esSimF, "%s", (drain->dterm_attrs) ? "," : " d=" );
|
||||
if (hierD)
|
||||
simnAPHier(drain, hierName, fetInfo[dev->dev_type].resClassSD,
|
||||
simnAPHier(drain, hierName, fetInfo[dev->dev_type].resClassDrain,
|
||||
scale, esSimF);
|
||||
else {
|
||||
dnode = SimGetNode(hierName,
|
||||
drain->dterm_node->efnode_name->efnn_hier);
|
||||
simnAP(dnode, fetInfo[dev->dev_type].resClassSD,
|
||||
simnAP(dnode, fetInfo[dev->dev_type].resClassDrain,
|
||||
scale, esSimF);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -172,9 +172,11 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
|
|||
}
|
||||
else
|
||||
{
|
||||
int pn;
|
||||
int pn, resclass;
|
||||
pn = plist->parm_type[1] - '0';
|
||||
if (pn >= dev->dev_nterm) pn = dev->dev_nterm - 1;
|
||||
resclass = (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain :
|
||||
esFetInfo[dev->dev_type].resClassSource;
|
||||
|
||||
dnode = GetHierNode(hc,
|
||||
dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier);
|
||||
|
|
@ -186,16 +188,14 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
|
|||
'p' && plist->parm_next->parm_type[1] ==
|
||||
plist->parm_type[1])
|
||||
{
|
||||
spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD,
|
||||
scale, plist->parm_name,
|
||||
spcnAP(dnode, resclass, scale, plist->parm_name,
|
||||
plist->parm_next->parm_name, sdM,
|
||||
esSpiceF, w);
|
||||
plist = plist->parm_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD,
|
||||
scale, plist->parm_name, NULL, sdM,
|
||||
spcnAP(dnode, resclass, scale, plist->parm_name, NULL, sdM,
|
||||
esSpiceF, w);
|
||||
}
|
||||
}
|
||||
|
|
@ -218,9 +218,11 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
|
|||
}
|
||||
else
|
||||
{
|
||||
int pn;
|
||||
int pn, resclass;
|
||||
pn = plist->parm_type[1] - '0';
|
||||
if (pn >= dev->dev_nterm) pn = dev->dev_nterm - 1;
|
||||
resclass = (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain :
|
||||
esFetInfo[dev->dev_type].resClassSource;
|
||||
|
||||
dnode = GetHierNode(hc,
|
||||
dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier);
|
||||
|
|
@ -232,15 +234,13 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
|
|||
'a' && plist->parm_next->parm_type[1] ==
|
||||
plist->parm_type[1])
|
||||
{
|
||||
spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD,
|
||||
scale, plist->parm_next->parm_name,
|
||||
spcnAP(dnode, resclass, scale, plist->parm_next->parm_name,
|
||||
plist->parm_name, sdM, esSpiceF, w);
|
||||
plist = plist->parm_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD,
|
||||
scale, NULL, plist->parm_name, sdM,
|
||||
spcnAP(dnode, resclass, scale, NULL, plist->parm_name, sdM,
|
||||
esSpiceF, w);
|
||||
}
|
||||
}
|
||||
|
|
@ -485,7 +485,7 @@ spcdevHierVisit(hc, dev, scale)
|
|||
EFNode *subnode, *snode, *dnode, *subnodeFlat = NULL;
|
||||
int l, w, i, parmval;
|
||||
Rect r;
|
||||
bool subAP= FALSE, hierS, hierD, extHierSDAttr() ;
|
||||
bool subAP = FALSE, hierS, hierD, extHierSDAttr(), swapped = FALSE;
|
||||
float sdM;
|
||||
char devchar;
|
||||
bool has_model = TRUE;
|
||||
|
|
@ -515,10 +515,10 @@ spcdevHierVisit(hc, dev, scale)
|
|||
!strcmp(dev->dev_terms[1].dterm_attrs, "D")) ||
|
||||
(dev->dev_terms[2].dterm_attrs &&
|
||||
!strcmp(dev->dev_terms[2].dterm_attrs, "S")))
|
||||
{
|
||||
drain = &dev->dev_terms[1];
|
||||
source = &dev->dev_terms[2];
|
||||
}
|
||||
{
|
||||
swapDrainSource(dev, &source, &drain);
|
||||
swapped = TRUE;
|
||||
}
|
||||
else
|
||||
drain = &dev->dev_terms[2];
|
||||
}
|
||||
|
|
@ -553,7 +553,7 @@ spcdevHierVisit(hc, dev, scale)
|
|||
case DEV_FET:
|
||||
if (source == drain)
|
||||
{
|
||||
if (esFormat == NGSPICE) fprintf(esSpiceF, "; ");
|
||||
if (esFormat == NGSPICE) fprintf(esSpiceF, "$ ");
|
||||
fprintf(esSpiceF, "** SOURCE/DRAIN TIED\n");
|
||||
}
|
||||
break;
|
||||
|
|
@ -561,7 +561,7 @@ spcdevHierVisit(hc, dev, scale)
|
|||
default:
|
||||
if (gate == source)
|
||||
{
|
||||
if (esFormat == NGSPICE) fprintf(esSpiceF, "; ");
|
||||
if (esFormat == NGSPICE) fprintf(esSpiceF, "$ ");
|
||||
fprintf(esSpiceF, "** SHORTED DEVICE\n");
|
||||
}
|
||||
break;
|
||||
|
|
@ -666,12 +666,12 @@ spcdevHierVisit(hc, dev, scale)
|
|||
break;
|
||||
|
||||
case DEV_MSUBCKT:
|
||||
/* msubcircuit is "Xnnn source gate [drain [sub]]]" */
|
||||
/* msubcircuit is "Xnnn drain gate [source [sub]]]" */
|
||||
/* to more conveniently handle situations where MOSFETs */
|
||||
/* are modeled by subcircuits with the same pin ordering. */
|
||||
|
||||
spcdevOutNode(hc->hc_hierName,
|
||||
source->dterm_node->efnode_name->efnn_hier,
|
||||
drain->dterm_node->efnode_name->efnn_hier,
|
||||
"subckt", esSpiceF);
|
||||
|
||||
/* Drop through to below (no break statement) */
|
||||
|
|
@ -693,15 +693,21 @@ spcdevHierVisit(hc, dev, scale)
|
|||
/* except that the "gate" node is treated as an identifier */
|
||||
/* only and is not output. */
|
||||
|
||||
if ((dev->dev_nterm > 1) && (dev->dev_class != DEV_MSUBCKT))
|
||||
spcdevOutNode(hc->hc_hierName,
|
||||
source->dterm_node->efnode_name->efnn_hier,
|
||||
"subckt", esSpiceF);
|
||||
if (dev->dev_nterm > 2)
|
||||
spcdevOutNode(hc->hc_hierName,
|
||||
drain->dterm_node->efnode_name->efnn_hier,
|
||||
"subckt", esSpiceF);
|
||||
|
||||
if (dev->dev_class != DEV_MSUBCKT)
|
||||
{
|
||||
if (dev->dev_nterm > 1)
|
||||
spcdevOutNode(hc->hc_hierName, source->dterm_node->efnode_name->efnn_hier,
|
||||
"subckt", esSpiceF);
|
||||
if (dev->dev_nterm > 2)
|
||||
spcdevOutNode(hc->hc_hierName, drain->dterm_node->efnode_name->efnn_hier,
|
||||
"subckt", esSpiceF);
|
||||
}
|
||||
else /* class DEV_MSUBCKT */
|
||||
{
|
||||
if (dev->dev_nterm > 2)
|
||||
spcdevOutNode(hc->hc_hierName, source->dterm_node->efnode_name->efnn_hier,
|
||||
"subckt", esSpiceF);
|
||||
}
|
||||
/* The following only applies to DEV_SUBCKT*, which may define as */
|
||||
/* many terminal types as it wants. */
|
||||
|
||||
|
|
@ -959,10 +965,10 @@ spcdevHierVisit(hc, dev, scale)
|
|||
|
||||
fprintf(esSpiceF, "\n+ ");
|
||||
dnode = GetHierNode(hc, drain->dterm_node->efnode_name->efnn_hier);
|
||||
spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD, scale,
|
||||
spcnAP(dnode, esFetInfo[dev->dev_type].resClassDrain, scale,
|
||||
"ad", "pd", sdM, esSpiceF, w);
|
||||
snode= GetHierNode(hc, source->dterm_node->efnode_name->efnn_hier);
|
||||
spcnAP(snode, esFetInfo[dev->dev_type].resClassSD, scale,
|
||||
spcnAP(snode, esFetInfo[dev->dev_type].resClassSource, scale,
|
||||
"as", "ps", sdM, esSpiceF, w);
|
||||
if (subAP)
|
||||
{
|
||||
|
|
@ -979,22 +985,33 @@ spcdevHierVisit(hc, dev, scale)
|
|||
else
|
||||
fprintf(esSpiceF, "asub=0 psub=0");
|
||||
}
|
||||
|
||||
/* Now output attributes, if present */
|
||||
if (!esNoAttrs)
|
||||
{
|
||||
if (gate->dterm_attrs || source->dterm_attrs || drain->dterm_attrs)
|
||||
fprintf(esSpiceF,"\n**devattr");
|
||||
if (gate->dterm_attrs)
|
||||
fprintf(esSpiceF, " g=%s", gate->dterm_attrs);
|
||||
if (source->dterm_attrs)
|
||||
fprintf(esSpiceF, " s=%s", source->dterm_attrs);
|
||||
if (drain->dterm_attrs)
|
||||
fprintf(esSpiceF, " d=%s", drain->dterm_attrs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Output attributes, if present - it looks more convenient here, as other device types may be added */
|
||||
switch (dev->dev_class)
|
||||
{
|
||||
case DEV_FET:
|
||||
case DEV_MOSFET:
|
||||
case DEV_ASYMMETRIC:
|
||||
case DEV_MSUBCKT:
|
||||
if (!esNoAttrs)
|
||||
{
|
||||
if (gate->dterm_attrs || source->dterm_attrs || drain->dterm_attrs)
|
||||
fprintf(esSpiceF,"\n**devattr");
|
||||
if (gate->dterm_attrs)
|
||||
fprintf(esSpiceF, " g=%s", gate->dterm_attrs);
|
||||
if (source->dterm_attrs)
|
||||
fprintf(esSpiceF, " s=%s", source->dterm_attrs);
|
||||
if (drain->dterm_attrs)
|
||||
fprintf(esSpiceF, " d=%s", drain->dterm_attrs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
fprintf(esSpiceF, "\n");
|
||||
|
||||
/* If S/D parameters were swapped, then put them back */
|
||||
if (swapped) swapDrainSource(dev, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1254,7 +1271,7 @@ spcnodeHierVisit(hc, node, res, cap)
|
|||
static char ntmp[MAX_STR_SIZE];
|
||||
|
||||
EFHNSprintf(ntmp, hierName);
|
||||
if (esFormat == NGSPICE) fprintf(esSpiceF, " ; ");
|
||||
if (esFormat == NGSPICE) fprintf(esSpiceF, " $ ");
|
||||
fprintf(esSpiceF, "** %s == %s\n", ntmp, nsn);
|
||||
}
|
||||
cap = cap / 1000;
|
||||
|
|
@ -1262,12 +1279,12 @@ spcnodeHierVisit(hc, node, res, cap)
|
|||
{
|
||||
fprintf(esSpiceF, esSpiceCapFormat, esCapNum++, nsn, cap,
|
||||
(isConnected) ? "" :
|
||||
(esFormat == NGSPICE) ? " ; **FLOATING" :
|
||||
(esFormat == NGSPICE) ? " $ **FLOATING" :
|
||||
" **FLOATING");
|
||||
}
|
||||
if (node->efnode_attrs && !esNoAttrs)
|
||||
{
|
||||
if (esFormat == NGSPICE) fprintf(esSpiceF, " ; ");
|
||||
if (esFormat == NGSPICE) fprintf(esSpiceF, " $ ");
|
||||
fprintf(esSpiceF, "**nodeattr %s :",nsn );
|
||||
for (fmt = " %s", ap = node->efnode_attrs; ap; ap = ap->efa_next)
|
||||
{
|
||||
|
|
@ -1521,7 +1538,10 @@ devDistJunctHierVisit(hc, dev, scale)
|
|||
for (i = 1; i<dev->dev_nterm; i++)
|
||||
{
|
||||
n = GetHierNode(hc, dev->dev_terms[i].dterm_node->efnode_name->efnn_hier);
|
||||
update_w(esFetInfo[dev->dev_type].resClassSD, w, n);
|
||||
if (i == 1)
|
||||
update_w(esFetInfo[dev->dev_type].resClassSource, w, n);
|
||||
else
|
||||
update_w(esFetInfo[dev->dev_type].resClassDrain, w, n);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -239,8 +239,7 @@ CmdExtToSpice(w, cmd)
|
|||
char *substr = NULL;
|
||||
bool err_result, locDoSubckt;
|
||||
|
||||
short sd_rclass;
|
||||
short sub_rclass;
|
||||
short s_rclass, d_rclass, sub_rclass;
|
||||
char *devname;
|
||||
char *subname;
|
||||
int idx, idx2;
|
||||
|
|
@ -729,7 +728,8 @@ runexttospice:
|
|||
the command line arguments */
|
||||
|
||||
for ( i = 0 ; i < MAXDEVTYPES ; i++ ) {
|
||||
esFetInfo[i].resClassSD = NO_RESCLASS;
|
||||
esFetInfo[i].resClassSource = NO_RESCLASS;
|
||||
esFetInfo[i].resClassDrain = NO_RESCLASS;
|
||||
esFetInfo[i].resClassSub = NO_RESCLASS;
|
||||
esFetInfo[i].defSubs = NULL;
|
||||
}
|
||||
|
|
@ -739,7 +739,7 @@ runexttospice:
|
|||
/* command) */
|
||||
|
||||
idx = 0;
|
||||
while (ExtGetDevInfo(idx++, &devname, &sd_rclass, &sub_rclass, &subname))
|
||||
while (ExtGetDevInfo(idx++, &devname, &s_rclass, &d_rclass, &sub_rclass, &subname))
|
||||
{
|
||||
if (idx == MAXDEVTYPES)
|
||||
{
|
||||
|
|
@ -751,7 +751,8 @@ runexttospice:
|
|||
esNoModelType = i;
|
||||
if (EFStyle != NULL)
|
||||
{
|
||||
esFetInfo[i].resClassSD = sd_rclass;
|
||||
esFetInfo[i].resClassSource = s_rclass;
|
||||
esFetInfo[i].resClassDrain = d_rclass;
|
||||
esFetInfo[i].resClassSub = sub_rclass;
|
||||
esFetInfo[i].defSubs = subname;
|
||||
}
|
||||
|
|
@ -992,24 +993,25 @@ main(argc, argv)
|
|||
/* create default devinfo entries (MOSIS) which can be overriden by
|
||||
the command line arguments */
|
||||
for ( i = 0 ; i < MAXDEVTYPES ; i++ ) {
|
||||
esFetInfo[i].resClassSD = NO_RESCLASS;
|
||||
esFetInfo[i].resClassSource = NO_RESCLASS;
|
||||
esFetInfo[i].resClassDrain = NO_RESCLASS;
|
||||
esFetInfo[i].resClassSub = NO_RESCLASS;
|
||||
esFetInfo[i].defSubs = NULL;
|
||||
}
|
||||
i = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, "ndev");
|
||||
esFetInfo[i].resClassSD = 0 ;
|
||||
esFetInfo[i].resClassSource = esFetInfo[i].resClassDrain = 0 ;
|
||||
esFetInfo[i].resClassSub = NO_RESCLASS ;
|
||||
esFetInfo[i].defSubs = "Gnd!";
|
||||
i = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, "pdev");
|
||||
esFetInfo[i].resClassSD = 1 ;
|
||||
esFetInfo[i].resClassSource = esFetInfo[i].resClassDrain = 1 ;
|
||||
esFetInfo[i].resClassSub = 8 ;
|
||||
esFetInfo[i].defSubs = "Vdd!";
|
||||
i = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, "nmos");
|
||||
esFetInfo[i].resClassSD = 0 ;
|
||||
esFetInfo[i].resClassSource = esFetInfo[i].resClassDrain = 0 ;
|
||||
esFetInfo[i].resClassSub = NO_RESCLASS ;
|
||||
esFetInfo[i].defSubs = "Gnd!";
|
||||
i = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, "pmos");
|
||||
esFetInfo[i].resClassSD = 1 ;
|
||||
esFetInfo[i].resClassSource = esFetInfo[i].resClassDrain = 1 ;
|
||||
esFetInfo[i].resClassSub = 8 ;
|
||||
esFetInfo[i].defSubs = "Vdd!";
|
||||
/* Process command line arguments */
|
||||
|
|
@ -1237,7 +1239,7 @@ spcmainArgs(pargc, pargv)
|
|||
if ( sscanf(rp, "%d/%s", &rClass, subsNode) != 2 ) goto usage;
|
||||
}
|
||||
ndx = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, cp);
|
||||
esFetInfo[ndx].resClassSD = rClass;
|
||||
esFetInfo[ndx].resClassSource = esFetInfo[ndx].resClassDrain = rClass;
|
||||
esFetInfo[ndx].resClassSub = rClassSub;
|
||||
if ( ((1<<rClass) & DEV_CONNECT_MASK) ||
|
||||
((1<<rClass) & DEV_CONNECT_MASK) ) {
|
||||
|
|
@ -1249,9 +1251,9 @@ spcmainArgs(pargc, pargv)
|
|||
}
|
||||
esFetInfo[ndx].defSubs = (char *)mallocMagic((unsigned)(strlen(subsNode)+1));
|
||||
strcpy(esFetInfo[ndx].defSubs,subsNode);
|
||||
TxError("info: dev %s(%d) sdRclass=%d subRclass=%d dSub=%s\n",
|
||||
cp, ndx, esFetInfo[ndx].resClassSD, esFetInfo[ndx].resClassSub,
|
||||
esFetInfo[ndx].defSubs);
|
||||
TxError("info: dev %s(%d) srcRclass=%d drnRclass=%d subRclass=%d dSub=%s\n",
|
||||
cp, ndx, esFetInfo[ndx].resClassSource, esFetInfo[ndx].resClassDrain,
|
||||
esFetInfo[ndx].resClassSub, esFetInfo[ndx].defSubs);
|
||||
break;
|
||||
}
|
||||
#endif /* MAGIC_WRAPPER */
|
||||
|
|
@ -1882,13 +1884,16 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
}
|
||||
else
|
||||
{
|
||||
int pn;
|
||||
int pn, resclass;
|
||||
|
||||
pn = plist->parm_type[1] - '0';
|
||||
if (pn >= dev->dev_nterm) pn = dev->dev_nterm - 1;
|
||||
|
||||
hierD = extHierSDAttr(&dev->dev_terms[pn]);
|
||||
|
||||
resclass == (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain :
|
||||
esFetInfo[dev->dev_type].resClassSource;
|
||||
|
||||
// For parameter a<n> followed by parameter p<n>,
|
||||
// process both at the same time.
|
||||
|
||||
|
|
@ -1898,16 +1903,14 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
{
|
||||
if (hierD)
|
||||
spcnAPHier(&dev->dev_terms[pn], hierName,
|
||||
esFetInfo[dev->dev_type].resClassSD,
|
||||
scale, plist->parm_type,
|
||||
resclass, scale, plist->parm_type,
|
||||
plist->parm_next->parm_type,
|
||||
sdM, esSpiceF);
|
||||
else
|
||||
{
|
||||
dnode = SpiceGetNode(hierName,
|
||||
dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier);
|
||||
spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD,
|
||||
scale, plist->parm_name,
|
||||
spcnAP(dnode, resclass, scale, plist->parm_name,
|
||||
plist->parm_next->parm_name,
|
||||
sdM, esSpiceF, w);
|
||||
}
|
||||
|
|
@ -1917,15 +1920,13 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
{
|
||||
if (hierD)
|
||||
spcnAPHier(&dev->dev_terms[pn], hierName,
|
||||
esFetInfo[dev->dev_type].resClassSD,
|
||||
scale, plist->parm_type, NULL,
|
||||
resclass, scale, plist->parm_type, NULL,
|
||||
sdM, esSpiceF);
|
||||
else
|
||||
{
|
||||
dnode = SpiceGetNode(hierName,
|
||||
dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier);
|
||||
spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD,
|
||||
scale, plist->parm_name, NULL,
|
||||
spcnAP(dnode, resclass, scale, plist->parm_name, NULL,
|
||||
sdM, esSpiceF, w);
|
||||
}
|
||||
}
|
||||
|
|
@ -1948,11 +1949,14 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
}
|
||||
else
|
||||
{
|
||||
int pn;
|
||||
int pn, resclass;
|
||||
|
||||
pn = plist->parm_type[1] - '0';
|
||||
if (pn >= dev->dev_nterm) pn = dev->dev_nterm - 1;
|
||||
|
||||
resclass == (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain :
|
||||
esFetInfo[dev->dev_type].resClassSource;
|
||||
|
||||
hierD = extHierSDAttr(&dev->dev_terms[pn]);
|
||||
|
||||
// For parameter p<n> followed by parameter a<n>,
|
||||
|
|
@ -1964,15 +1968,13 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
{
|
||||
if (hierD)
|
||||
spcnAPHier(&dev->dev_terms[pn], hierName,
|
||||
esFetInfo[dev->dev_type].resClassSD,
|
||||
scale, plist->parm_next->parm_type,
|
||||
resclass, scale, plist->parm_next->parm_type,
|
||||
plist->parm_type, sdM, esSpiceF);
|
||||
else
|
||||
{
|
||||
dnode = SpiceGetNode(hierName,
|
||||
dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier);
|
||||
spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD,
|
||||
scale, plist->parm_next->parm_name,
|
||||
spcnAP(dnode, resclass, scale, plist->parm_next->parm_name,
|
||||
plist->parm_name, sdM, esSpiceF, w);
|
||||
}
|
||||
plist = plist->parm_next;
|
||||
|
|
@ -1981,15 +1983,13 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
{
|
||||
if (hierD)
|
||||
spcnAPHier(&dev->dev_terms[pn], hierName,
|
||||
esFetInfo[dev->dev_type].resClassSD,
|
||||
scale, NULL, plist->parm_type,
|
||||
resclass, scale, NULL, plist->parm_type,
|
||||
sdM, esSpiceF);
|
||||
else
|
||||
{
|
||||
dnode = SpiceGetNode(hierName,
|
||||
dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier);
|
||||
spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD,
|
||||
scale, NULL, plist->parm_name,
|
||||
spcnAP(dnode, resclass, scale, NULL, plist->parm_name,
|
||||
sdM, esSpiceF, w);
|
||||
}
|
||||
}
|
||||
|
|
@ -2184,6 +2184,52 @@ getCurDevMult()
|
|||
return (esFMult && (esFMIndex > 0)) ? esFMult[esFMIndex-1] : (float)1.0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* swapDrainSource
|
||||
*
|
||||
* Swap drain and source ordering and the related stuff
|
||||
* including the drain/source area parameters
|
||||
*
|
||||
* This is typycally called if any terminal is marked with attribute "D" or "S"
|
||||
* (label "D$" or "S$" at poly-diffusion interface),
|
||||
* then swap order of source and drain compared to the default ordering.
|
||||
*
|
||||
*/
|
||||
void
|
||||
swapDrainSource(dev, source, drain)
|
||||
Dev *dev;
|
||||
DevTerm **source, **drain;
|
||||
{
|
||||
DevParam *plist;
|
||||
|
||||
/* swap drain/source ordering */
|
||||
if (drain) *drain = &dev->dev_terms[1];
|
||||
if (source) *source = &dev->dev_terms[2];
|
||||
|
||||
/* Swap drain/source-related parameters. Note that the parameter */
|
||||
/* *definitions* are swapped, so if this is done, it must be */
|
||||
/* reverted before the next device is processed. */
|
||||
|
||||
plist = efGetDeviceParams(EFDevTypes[dev->dev_type]);
|
||||
while (plist != NULL)
|
||||
{
|
||||
// Diagnostic
|
||||
// TxPrintf(" * param: %s; type: %c%c\n", plist->parm_name, plist->parm_type[0], plist->parm_type[1]);
|
||||
|
||||
/* Swap drain/source parameters only */
|
||||
if (!(strcmp(plist->parm_type, "a1")) || !(strcmp(plist->parm_type, "p1")))
|
||||
plist->parm_type[1] = '0' + 2;
|
||||
|
||||
else if (!(strcmp(plist->parm_type, "a2")) || !(strcmp(plist->parm_type, "p2")))
|
||||
plist->parm_type[1] = '0' + 1;
|
||||
|
||||
/* move pointer */
|
||||
plist = plist->parm_next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -2230,7 +2276,7 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
DevTerm *gate, *source, *drain;
|
||||
EFNode *subnode, *snode, *dnode, *subnodeFlat = NULL;
|
||||
int l, w, i, parmval;
|
||||
bool subAP= FALSE, hierS, hierD, extHierSDAttr() ;
|
||||
bool subAP= FALSE, hierS, hierD, extHierSDAttr(), swapped = FALSE ;
|
||||
float sdM;
|
||||
char name[12], devchar;
|
||||
bool has_model = TRUE;
|
||||
|
|
@ -2263,8 +2309,8 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
(dev->dev_terms[2].dterm_attrs &&
|
||||
!strcmp(dev->dev_terms[2].dterm_attrs, "S")))
|
||||
{
|
||||
drain = &dev->dev_terms[1];
|
||||
source = &dev->dev_terms[2];
|
||||
swapDrainSource(dev, &source, &drain);
|
||||
swapped = True;
|
||||
}
|
||||
else
|
||||
drain = &dev->dev_terms[2];
|
||||
|
|
@ -2328,7 +2374,7 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
case DEV_FET:
|
||||
if (source == drain)
|
||||
{
|
||||
if (esFormat == NGSPICE) fprintf(esSpiceF, "; ");
|
||||
if (esFormat == NGSPICE) fprintf(esSpiceF, "$ ");
|
||||
fprintf(esSpiceF, "** SOURCE/DRAIN TIED\n");
|
||||
}
|
||||
break;
|
||||
|
|
@ -2336,7 +2382,7 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
default:
|
||||
if (gate == source)
|
||||
{
|
||||
if (esFormat == NGSPICE) fprintf(esSpiceF, "; ");
|
||||
if (esFormat == NGSPICE) fprintf(esSpiceF, "$ ");
|
||||
fprintf(esSpiceF, "** SHORTED DEVICE\n");
|
||||
}
|
||||
break;
|
||||
|
|
@ -2443,11 +2489,11 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
|
||||
case DEV_MSUBCKT:
|
||||
|
||||
/* MOS-like subcircuit is "Xnnn source gate [drain [sub]]" */
|
||||
/* MOS-like subcircuit is "Xnnn drain gate [source [sub]]" */
|
||||
/* to more conveniently handle cases where MOS devices are */
|
||||
/* modeled by subcircuits with the same pin ordering. */
|
||||
|
||||
spcdevOutNode(hierName, source->dterm_node->efnode_name->efnn_hier,
|
||||
spcdevOutNode(hierName, drain->dterm_node->efnode_name->efnn_hier,
|
||||
name, esSpiceF);
|
||||
|
||||
/* Drop through to below (no break statement) */
|
||||
|
|
@ -2468,12 +2514,21 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
/* except that the "gate" node is treated as an identifier */
|
||||
/* only and is not output. */
|
||||
|
||||
if ((dev->dev_nterm > 1) && (dev->dev_class != DEV_MSUBCKT))
|
||||
spcdevOutNode(hierName, source->dterm_node->efnode_name->efnn_hier,
|
||||
name, esSpiceF);
|
||||
if (dev->dev_nterm > 2)
|
||||
spcdevOutNode(hierName, drain->dterm_node->efnode_name->efnn_hier,
|
||||
name, esSpiceF);
|
||||
if (dev->dev_class != DEV_MSUBCKT)
|
||||
{
|
||||
if (dev->dev_nterm > 1)
|
||||
spcdevOutNode(hierName, source->dterm_node->efnode_name->efnn_hier,
|
||||
name, esSpiceF);
|
||||
if (dev->dev_nterm > 2)
|
||||
spcdevOutNode(hierName, drain->dterm_node->efnode_name->efnn_hier,
|
||||
name, esSpiceF);
|
||||
}
|
||||
else /* class DEV_MSUBCKT */
|
||||
{
|
||||
if (dev->dev_nterm > 2)
|
||||
spcdevOutNode(hierName, source->dterm_node->efnode_name->efnn_hier,
|
||||
name, esSpiceF);
|
||||
}
|
||||
|
||||
/* The following only applies to DEV_SUBCKT*, which may define as */
|
||||
/* many terminal types as it wants. */
|
||||
|
|
@ -2716,20 +2771,20 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
|
||||
fprintf(esSpiceF, "\n+ ");
|
||||
if (hierD)
|
||||
spcnAPHier(drain, hierName, esFetInfo[dev->dev_type].resClassSD,
|
||||
spcnAPHier(drain, hierName, esFetInfo[dev->dev_type].resClassDrain,
|
||||
scale, "ad", "pd", sdM, esSpiceF);
|
||||
else
|
||||
{
|
||||
dnode = SpiceGetNode(hierName, drain->dterm_node->efnode_name->efnn_hier);
|
||||
spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD, scale,
|
||||
spcnAP(dnode, esFetInfo[dev->dev_type].resClassDrain, scale,
|
||||
"ad", "pd", sdM, esSpiceF, w);
|
||||
}
|
||||
if (hierS)
|
||||
spcnAPHier(source, hierName, esFetInfo[dev->dev_type].resClassSD,
|
||||
spcnAPHier(source, hierName, esFetInfo[dev->dev_type].resClassSource,
|
||||
scale, "as", "ps", sdM, esSpiceF);
|
||||
else {
|
||||
snode= SpiceGetNode(hierName, source->dterm_node->efnode_name->efnn_hier);
|
||||
spcnAP(snode, esFetInfo[dev->dev_type].resClassSD, scale,
|
||||
spcnAP(snode, esFetInfo[dev->dev_type].resClassSource, scale,
|
||||
"as", "ps", sdM, esSpiceF, w);
|
||||
}
|
||||
if (subAP)
|
||||
|
|
@ -2763,6 +2818,10 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
break;
|
||||
}
|
||||
fprintf(esSpiceF, "\n");
|
||||
|
||||
/* If S/D parameters on a subcircuit were swapped, put them back */
|
||||
if (swapped) swapDrainSource(dev, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -3203,7 +3262,7 @@ spcnodeVisit(node, res, cap)
|
|||
static char ntmp[MAX_STR_SIZE];
|
||||
|
||||
EFHNSprintf(ntmp, hierName);
|
||||
if (esFormat == NGSPICE) fprintf(esSpiceF, "; ");
|
||||
if (esFormat == NGSPICE) fprintf(esSpiceF, "$ ");
|
||||
fprintf(esSpiceF, "** %s == %s\n", ntmp, nsn);
|
||||
}
|
||||
cap = cap / 1000;
|
||||
|
|
@ -3211,12 +3270,12 @@ spcnodeVisit(node, res, cap)
|
|||
{
|
||||
fprintf(esSpiceF, esSpiceCapFormat, esCapNum++, nsn, cap,
|
||||
(isConnected) ? "\n" :
|
||||
(esFormat == NGSPICE) ? " ; **FLOATING\n" :
|
||||
(esFormat == NGSPICE) ? " $ **FLOATING\n" :
|
||||
" **FLOATING\n");
|
||||
}
|
||||
if (node->efnode_attrs && !esNoAttrs)
|
||||
{
|
||||
if (esFormat == NGSPICE) fprintf(esSpiceF, " ; ");
|
||||
if (esFormat == NGSPICE) fprintf(esSpiceF, " $ ");
|
||||
fprintf(esSpiceF, "**nodeattr %s :",nsn );
|
||||
for (fmt = " %s", ap = node->efnode_attrs; ap; ap = ap->efa_next)
|
||||
{
|
||||
|
|
@ -4038,7 +4097,10 @@ devDistJunctVisit(dev, hc, scale, trans)
|
|||
{
|
||||
n = SpiceGetNode(hierName,
|
||||
dev->dev_terms[i].dterm_node->efnode_name->efnn_hier);
|
||||
update_w(esFetInfo[dev->dev_type].resClassSD, w, n);
|
||||
if (i == 1)
|
||||
update_w(esFetInfo[dev->dev_type].resClassSource, w, n);
|
||||
else
|
||||
update_w(esFetInfo[dev->dev_type].resClassDrain, w, n);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ extern EFNode *spcdevSubstrate();
|
|||
extern char *nodeSpiceName();
|
||||
extern int nodeVisitDebug();
|
||||
extern void topVisit();
|
||||
extern void swapDrainSource();
|
||||
extern int _ext2spice_start();
|
||||
|
||||
extern EFNode *spcdevHierSubstrate();
|
||||
|
|
@ -89,7 +90,8 @@ extern DQueue subcktNameQueue ; /* q used to print it sorted at the end*/
|
|||
|
||||
|
||||
typedef struct {
|
||||
short resClassSD ; /* the resistance class of the src/drn of the dev */
|
||||
short resClassSource ; /* the resistance class of the source of the dev */
|
||||
short resClassDrain ; /* the resistance class of the drain of the dev */
|
||||
short resClassSub ; /* the resistance class of the substrate of the dev */
|
||||
char *defSubs ; /* the default substrate node */
|
||||
} fetInfoList;
|
||||
|
|
|
|||
|
|
@ -155,23 +155,37 @@ efBuildNode(def, isSubsnode, nodeName, nodeCap, x, y, layerName, av, ac)
|
|||
if (efWarn)
|
||||
efReadError("Warning: duplicate node name %s\n", nodeName);
|
||||
|
||||
/* Just add to C, perim, area of existing node */
|
||||
newnode = newname->efnn_node;
|
||||
newnode->efnode_cap += (EFCapValue) nodeCap;
|
||||
for (n = 0; n < efNumResistClasses && ac > 1; n++, ac -= 2)
|
||||
/* newnode should exist if newname does. Having a NULL node */
|
||||
/* may be caused by detached labels "connected" to space. */
|
||||
|
||||
if ((newnode = newname->efnn_node) != NULL)
|
||||
{
|
||||
newnode->efnode_pa[n].pa_area += atoi(*av++);
|
||||
newnode->efnode_pa[n].pa_perim += atoi(*av++);
|
||||
/* Just add to C, perim, area of existing node */
|
||||
newnode->efnode_cap += (EFCapValue) nodeCap;
|
||||
for (n = 0; n < efNumResistClasses && ac > 1; n++, ac -= 2)
|
||||
{
|
||||
newnode->efnode_pa[n].pa_area += atoi(*av++);
|
||||
newnode->efnode_pa[n].pa_perim += atoi(*av++);
|
||||
}
|
||||
|
||||
/* If this node is identified as substrate, ensure that */
|
||||
/* the flag is set. */
|
||||
if (isSubsnode == TRUE)
|
||||
newnode->efnode_flags |= EF_SUBS_NODE;
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Allocate a new node with 'nodeName' as its single name */
|
||||
newname = (EFNodeName *) mallocMagic((unsigned)(sizeof (EFNodeName)));
|
||||
newname->efnn_hier = EFStrToHN((HierName *) NULL, nodeName);
|
||||
newname->efnn_port = -1; /* No port assignment */
|
||||
newname->efnn_next = NULL;
|
||||
HashSetValue(he, (char *) newname);
|
||||
if (!newname)
|
||||
{
|
||||
/* Allocate a new node with 'nodeName' as its single name */
|
||||
newname = (EFNodeName *) mallocMagic((unsigned)(sizeof (EFNodeName)));
|
||||
newname->efnn_hier = EFStrToHN((HierName *) NULL, nodeName);
|
||||
newname->efnn_port = -1; /* No port assignment */
|
||||
newname->efnn_next = NULL;
|
||||
HashSetValue(he, (char *) newname);
|
||||
}
|
||||
|
||||
/* New node itself */
|
||||
size = sizeof (EFNode) + (efNumResistClasses - 1) * sizeof (EFPerimArea);
|
||||
|
|
|
|||
|
|
@ -1724,7 +1724,14 @@ extOutputDevices(def, transList, outFile)
|
|||
continue; /* This terminal already found by perimeter search */
|
||||
|
||||
tmask = &devptr->exts_deviceSDTypes[termcount];
|
||||
if (TTMaskIsZero(tmask)) break; /* End of SD terminals */
|
||||
if (TTMaskIsZero(tmask)) {
|
||||
if (termcount < nsd) {
|
||||
/* See if there is another matching device record with */
|
||||
/* a different number of terminals, and try again. */
|
||||
devptr = extDevFindMatch(devptr, t);
|
||||
}
|
||||
break; /* End of SD terminals */
|
||||
}
|
||||
else if (!TTMaskIntersect(tmask, &DBPlaneTypes[reg->treg_pnum]))
|
||||
{
|
||||
node = NULL;
|
||||
|
|
@ -1736,7 +1743,7 @@ extOutputDevices(def, transList, outFile)
|
|||
break;
|
||||
}
|
||||
extTransRec.tr_devmatch |= (MATCH_TERM << termcount);
|
||||
extTransRec.tr_termnode[termcount++] = node;
|
||||
extTransRec.tr_termnode[termcount] = node;
|
||||
}
|
||||
else if (TTMaskHasType(tmask, TT_SPACE)) {
|
||||
/* Device node is specified as being the substrate */
|
||||
|
|
@ -1842,6 +1849,7 @@ extOutputDevices(def, transList, outFile)
|
|||
if (varsub != NULL) subsName = varsub;
|
||||
}
|
||||
#endif
|
||||
extTransRec.tr_devrec = devptr;
|
||||
|
||||
/* Original-style FET record backward compatibility */
|
||||
if (devptr->exts_deviceClass != DEV_FET)
|
||||
|
|
@ -1941,6 +1949,7 @@ extOutputDevices(def, transList, outFile)
|
|||
arg.fra_uninit = (ClientData) extTransRec.tr_gatenode;
|
||||
arg.fra_region = (Region *) reg;
|
||||
arg.fra_each = extAnnularTileFunc;
|
||||
|
||||
(void) ExtFindNeighbors(reg->treg_tile, arg.fra_pNum, &arg);
|
||||
|
||||
extSeparateBounds(n - 1); /* Handle MOScaps (if necessary) */
|
||||
|
|
@ -2253,7 +2262,7 @@ extTransFindSubs(tile, t, mask, def, sn, layerptr)
|
|||
NodeRegion **sn;
|
||||
TileType *layerptr;
|
||||
{
|
||||
Rect tileArea;
|
||||
Rect tileArea, tileAreaPlus;
|
||||
int pNum;
|
||||
int extTransFindSubsFunc1(); /* Forward declaration */
|
||||
NodeAndType noderec;
|
||||
|
|
@ -2262,11 +2271,16 @@ extTransFindSubs(tile, t, mask, def, sn, layerptr)
|
|||
noderec.layer = TT_SPACE;
|
||||
|
||||
TiToRect(tile, &tileArea);
|
||||
|
||||
/* Expand tile area by 1 in all directions. This catches terminals */
|
||||
/* on certain extended drain MOSFET devices. */
|
||||
GEO_EXPAND(&tileArea, 1, &tileAreaPlus);
|
||||
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
{
|
||||
if (TTMaskIntersect(&DBPlaneTypes[pNum], mask))
|
||||
{
|
||||
if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum], &tileArea,
|
||||
if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum], &tileAreaPlus,
|
||||
mask, extTransFindSubsFunc1, (ClientData)&noderec))
|
||||
{
|
||||
*sn = noderec.region;
|
||||
|
|
@ -2749,6 +2763,7 @@ extTransPerimFunc(bp)
|
|||
else
|
||||
{
|
||||
TxError("Error: Asymmetric device with multiple terminals!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Add the length to this terminal's perimeter */
|
||||
|
|
@ -3024,7 +3039,31 @@ extSpecialPerimFunc(bp, sense)
|
|||
if (toutside == TT_SPACE)
|
||||
if (glob_subsnode != NULL)
|
||||
diffNode = glob_subsnode;
|
||||
}
|
||||
|
||||
/* Check for terminal on different plane than the device */
|
||||
if (!needSurvey)
|
||||
{
|
||||
for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++)
|
||||
{
|
||||
TileTypeBitMask mmask;
|
||||
PlaneMask pmask;
|
||||
|
||||
mmask = devptr->exts_deviceSDTypes[i];
|
||||
if (toutside != TT_SPACE) TTMaskClearType(&mmask, TT_SPACE);
|
||||
pmask = DBTechTypesToPlanes(&mmask);
|
||||
|
||||
if (!PlaneMaskHasPlane(pmask, DBPlane(tinside)))
|
||||
{
|
||||
diffNode = extTransRec.tr_termnode[i];
|
||||
needSurvey = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!sense || needSurvey)
|
||||
{
|
||||
/*
|
||||
* Since we're repeating the search, all terminals should be there.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -308,6 +308,8 @@ extHeader(def, f)
|
|||
bool propfound;
|
||||
char *propvalue;
|
||||
|
||||
ASSERT(DBTechName != NULL, "extHeader");
|
||||
|
||||
/* Output a timestamp (should be first) */
|
||||
fprintf(f, "timestamp %d\n", def->cd_timestamp);
|
||||
|
||||
|
|
|
|||
|
|
@ -340,6 +340,7 @@ extHardSetLabel(scx, reg, arg)
|
|||
}
|
||||
GeoTransRect(&scx->scx_trans, &r, &newlab->lab_rect);
|
||||
newlab->lab_type = oldlab->lab_type;
|
||||
newlab->lab_flags = oldlab->lab_flags;
|
||||
text = oldlab->lab_text;
|
||||
|
||||
/* Don't care, really, which orientation the label has */
|
||||
|
|
|
|||
|
|
@ -291,7 +291,12 @@ extHierConnectFunc1(oneTile, ha)
|
|||
// node only describes a single point.
|
||||
|
||||
for (lab = cumDef->cd_labels; lab; lab = lab->lab_next)
|
||||
if (GEO_TOUCH(&r, &lab->lab_rect) && (lab->lab_flags & LABEL_STICKY))
|
||||
{
|
||||
// All sticky labels are at the front of the list in cumDef, so
|
||||
// stop when we see the first non-sticky label.
|
||||
if (!(lab->lab_flags & LABEL_STICKY)) break;
|
||||
|
||||
if (GEO_TOUCH(&r, &lab->lab_rect))
|
||||
if (TTMaskHasType(connected, lab->lab_type))
|
||||
{
|
||||
HashTable *table = &ha->ha_connHash;
|
||||
|
|
@ -350,6 +355,7 @@ extHierConnectFunc1(oneTile, ha)
|
|||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/magic.h"
|
||||
|
|
@ -42,6 +43,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "debug/debug.h"
|
||||
#include "extract/extract.h"
|
||||
#include "extract/extractInt.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "utils/signals.h"
|
||||
#include "windows/windows.h"
|
||||
#include "dbwind/dbwind.h"
|
||||
|
|
@ -168,6 +170,10 @@ extSubtree(parentUse, reg, f)
|
|||
float pdone, plast;
|
||||
SearchContext scx;
|
||||
|
||||
/* Use the display timer to force a 5-second progress check */
|
||||
GrDisplayStatus = DISPLAY_IN_PROGRESS;
|
||||
SigSetTimer(5); /* Print at 5-second intervals */
|
||||
|
||||
if ((ExtOptions & (EXT_DOCOUPLING|EXT_DOADJUST))
|
||||
!= (EXT_DOCOUPLING|EXT_DOADJUST))
|
||||
halo = 1;
|
||||
|
|
@ -264,9 +270,16 @@ extSubtree(parentUse, reg, f)
|
|||
cuts++;
|
||||
pdone = 100.0 * ((float)cuts / (float)totcuts);
|
||||
if ((((pdone - plast) > 5.0) || (cuts == totcuts)) && (cuts > 1)) {
|
||||
TxPrintf("Completed %d%%\n", (int)(pdone + 0.5));
|
||||
plast = pdone;
|
||||
TxFlushOut();
|
||||
/* Only print something if the 5-second timer has expired */
|
||||
if (GrDisplayStatus == DISPLAY_BREAK_PENDING)
|
||||
{
|
||||
TxPrintf("Completed %d%%\n", (int)(pdone + 0.5));
|
||||
plast = pdone;
|
||||
TxFlushOut();
|
||||
|
||||
GrDisplayStatus = DISPLAY_IN_PROGRESS;
|
||||
SigSetTimer(5);
|
||||
}
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
/* We need to let Tk paint the console display */
|
||||
|
|
@ -313,6 +326,8 @@ done:
|
|||
/* Output connections and node adjustments */
|
||||
extOutputConns(&ha.ha_connHash, f);
|
||||
HashKill(&ha.ha_connHash);
|
||||
GrDisplayStatus = DISPLAY_IDLE;
|
||||
SigRemoveTimer();
|
||||
|
||||
/* Clear the CU_SUB_EXTRACTED flag from all children instances */
|
||||
DBCellEnum(def, extClearUseFlags, (ClientData)NULL);
|
||||
|
|
@ -766,6 +781,8 @@ extSubtreeFunc(scx, ha)
|
|||
|
||||
for (lab = cumDef->cd_labels; lab ; lab = lab->lab_next)
|
||||
{
|
||||
if (!(lab->lab_flags & LABEL_STICKY)) continue;
|
||||
|
||||
n = sizeof (Label) + strlen(lab->lab_text)
|
||||
- sizeof lab->lab_text + 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -293,14 +293,22 @@ ExtCompareStyle(stylename)
|
|||
*
|
||||
* Side Effects:
|
||||
* Fills values in the argument list.
|
||||
*
|
||||
* Notes:
|
||||
* The original sd_rclassptr has been expanded to s_rclassptr and
|
||||
* d_rclassptr to capture asymmetric devices, bipolars, etc. Note
|
||||
* that this is not a general-purpose method extending beyond two
|
||||
* (non-gate) terminals, and should be updated.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bool
|
||||
ExtGetDevInfo(idx, devnameptr, sd_rclassptr, sub_rclassptr, subnameptr)
|
||||
ExtGetDevInfo(idx, devnameptr, s_rclassptr, d_rclassptr, sub_rclassptr, subnameptr)
|
||||
int idx;
|
||||
char **devnameptr;
|
||||
short *sd_rclassptr; /* First SD type only---needs to be updated! */
|
||||
short *s_rclassptr; /* Source (1st terminal) type only */
|
||||
short *d_rclassptr; /* Drain (2nd terminal) type only */
|
||||
short *sub_rclassptr;
|
||||
char **subnameptr;
|
||||
{
|
||||
|
|
@ -348,18 +356,39 @@ ExtGetDevInfo(idx, devnameptr, sd_rclassptr, sub_rclassptr, subnameptr)
|
|||
*subnameptr = devptr->exts_deviceSubstrateName;
|
||||
|
||||
tmask = &devptr->exts_deviceSDTypes[0];
|
||||
*sd_rclassptr = (short)(-1); /* NO_RESCLASS */
|
||||
*s_rclassptr = (short)(-1); /* NO_RESCLASS */
|
||||
|
||||
for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++)
|
||||
{
|
||||
rmask = &ExtCurStyle->exts_typesByResistClass[n];
|
||||
if (TTMaskIntersect(rmask, tmask))
|
||||
{
|
||||
*sd_rclassptr = (short)n;
|
||||
*s_rclassptr = (short)n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tmask = &devptr->exts_deviceSDTypes[1];
|
||||
if (TTMaskIsZero(tmask))
|
||||
{
|
||||
/* Set source and drain resistance classes to be the same */
|
||||
*d_rclassptr = (short)n;
|
||||
}
|
||||
else
|
||||
{
|
||||
*d_rclassptr = (short)(-1); /* NO_RESCLASS */
|
||||
|
||||
for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++)
|
||||
{
|
||||
rmask = &ExtCurStyle->exts_typesByResistClass[n];
|
||||
if (TTMaskIntersect(rmask, tmask))
|
||||
{
|
||||
*d_rclassptr = (short)n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tmask = &devptr->exts_deviceSubstrateTypes;
|
||||
*sub_rclassptr = (short)(-1); /* NO_RESCLASS */
|
||||
|
||||
|
|
@ -2280,7 +2309,7 @@ ExtTechLine(sectionName, argc, argv)
|
|||
|
||||
/* terminals */
|
||||
for (i = iterm; i < iterm + nterm; i++)
|
||||
DBTechNoisyNameMask(argv[iterm], &termtypes[i - iterm]);
|
||||
DBTechNoisyNameMask(argv[i], &termtypes[i - iterm]);
|
||||
termtypes[nterm] = DBZeroTypeBits;
|
||||
|
||||
if (nterm == 0) i++;
|
||||
|
|
|
|||
|
|
@ -1025,6 +1025,7 @@ DefReadPins(f, rootDef, sname, oscale, total)
|
|||
break;
|
||||
}
|
||||
pending = FALSE;
|
||||
curlayer = -1;
|
||||
|
||||
/* Now do a search through the line for "+" entries */
|
||||
/* And process each. */
|
||||
|
|
|
|||
|
|
@ -902,7 +902,7 @@ defNetGeometryFunc(tile, plane, defdata)
|
|||
/* Layer names are taken from the LEF database. */
|
||||
|
||||
lefName = MagicToLefTable[ttype].lefName;
|
||||
ASSERT(lefName, "Valid ttype");
|
||||
if (lefName == NULL) return 0; /* Do not write types not in LEF definition */
|
||||
lefType = MagicToLefTable[ttype].lefInfo;
|
||||
|
||||
orient = GEO_EAST;
|
||||
|
|
@ -1393,6 +1393,7 @@ defCountViaFunc(tile, cviadata)
|
|||
/* Generate a via name from the layer name and tile size */
|
||||
|
||||
lname = MagicToLefTable[ctype].lefName;
|
||||
if (lname == NULL) return 0; /* Do not output undefined LEF layers */
|
||||
TiToRect(tile, &r);
|
||||
|
||||
/* Boundary search. WARNING: This code is quite naive. The */
|
||||
|
|
@ -1551,7 +1552,8 @@ defGetType(ttype, lefptr)
|
|||
while (he = HashNext(&LefInfo, &hs))
|
||||
{
|
||||
lefl = (lefLayer *)HashGetValue(he);
|
||||
if (lefl && (contact == lefl->lefClass))
|
||||
if (lefl && ((contact == lefl->lefClass) ||
|
||||
((contact == CLASS_ROUTE) && (lefl->lefClass == CLASS_MASTER))))
|
||||
if ((lefl->type == ttype) || (lefl->obsType == ttype))
|
||||
{
|
||||
if (lefptr) *lefptr = lefl;
|
||||
|
|
@ -1560,9 +1562,9 @@ defGetType(ttype, lefptr)
|
|||
}
|
||||
}
|
||||
|
||||
/* If we got here, there is no entry; use the database name */
|
||||
/* If we got here, there is no entry; return NULL. */
|
||||
if (lefptr) *lefptr = (lefLayer *)NULL;
|
||||
return DBTypeLongNameTbl[ttype];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
77
lef/lefCmd.c
77
lef/lefCmd.c
|
|
@ -22,6 +22,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "windows/windows.h"
|
||||
#include "dbwind/dbwind.h"
|
||||
#include "utils/main.h"
|
||||
#include "utils/utils.h"
|
||||
#include "textio/txcommands.h"
|
||||
#include "commands/commands.h"
|
||||
|
||||
|
|
@ -71,6 +72,10 @@ CmdLef(w, cmd)
|
|||
* when the FOREIGN statement
|
||||
* is encountered in a macro.
|
||||
*/
|
||||
bool lefAnnotate = FALSE; /* Indicates that no celldefs should be
|
||||
* created from any LEF files, which
|
||||
* will be used for annotation only.
|
||||
*/
|
||||
bool lefTopCell = TRUE; /* Indicates whether or not we
|
||||
* write the top-level cell to
|
||||
* LEF, or just the subcells.
|
||||
|
|
@ -83,9 +88,16 @@ CmdLef(w, cmd)
|
|||
* will be output along with the
|
||||
* lef macro.
|
||||
*/
|
||||
bool lefHide = FALSE; /* If TRUE, hide all details of
|
||||
* the macro other than pin area
|
||||
* immediately surrounding labels.
|
||||
int lefHide = -1; /* If >= 0, hide all details of the macro
|
||||
* other than pin area surrounding labels,
|
||||
* with the indicated setback distance.
|
||||
*/
|
||||
bool lefTopLayer = FALSE; /* If TRUE, only output the topmost
|
||||
* layer used by a pin, and make
|
||||
* all layers below it obstructions.
|
||||
*/
|
||||
bool lefDoMaster = TRUE; /* If TRUE, output masterslice layers;
|
||||
* If FALSE, ignore masterslice layers.
|
||||
*/
|
||||
bool recurse = FALSE; /* If TRUE, recurse on all subcells
|
||||
* during "writeall". By default,
|
||||
|
|
@ -100,13 +112,16 @@ CmdLef(w, cmd)
|
|||
static char *cmdLefOption[] =
|
||||
{
|
||||
"read [filename] read a LEF file filename[.lef]\n"
|
||||
" read [filename] -import read a LEF file; import cells from .mag files",
|
||||
" read [filename] -import read a LEF file; import cells from .mag files\n",
|
||||
" read [filename] -annotate read a LEF file for cell annotation only.",
|
||||
"write [filename] [-tech] write LEF for current cell\n"
|
||||
" write [filename] -hide hide all details other than ports",
|
||||
" write [filename] -hide hide all details other than ports\n",
|
||||
" write [filename] -hide <d> hide details in area set back distance <d>",
|
||||
"writeall write all cells including the top-level cell\n"
|
||||
" 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",
|
||||
" writeall -hide hide all details other than ports\n",
|
||||
" writeall -hide [dist] hide details in area set back distance dist",
|
||||
"help print this help information",
|
||||
NULL
|
||||
};
|
||||
|
|
@ -171,6 +186,8 @@ CmdLef(w, cmd)
|
|||
{
|
||||
if (!strncmp(cmd->tx_argv[i], "-import", 7))
|
||||
lefImport = TRUE;
|
||||
else if (!strncmp(cmd->tx_argv[i], "-anno", 5))
|
||||
lefAnnotate = TRUE;
|
||||
else if (!strncmp(cmd->tx_argv[i], "-label", 6))
|
||||
{
|
||||
if (is_lef)
|
||||
|
|
@ -186,7 +203,7 @@ CmdLef(w, cmd)
|
|||
|
||||
namep = cmd->tx_argv[2];
|
||||
if (is_lef)
|
||||
LefRead(namep, lefImport);
|
||||
LefRead(namep, lefImport, lefAnnotate);
|
||||
else
|
||||
DefRead(namep, defLabelNets);
|
||||
break;
|
||||
|
|
@ -207,14 +224,28 @@ CmdLef(w, cmd)
|
|||
else if (!strncmp(cmd->tx_argv[i], "-tech", 5))
|
||||
lefTech = TRUE;
|
||||
else if (!strncmp(cmd->tx_argv[i], "-hide", 5))
|
||||
lefHide = TRUE;
|
||||
{
|
||||
lefHide = 0;
|
||||
if ((i < (cmd->tx_argc - 1)) &&
|
||||
StrIsNumeric(cmd->tx_argv[i + 1]))
|
||||
{
|
||||
lefHide = cmdParseCoord(w, cmd->tx_argv[i + 1],
|
||||
FALSE, TRUE);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else if (!strncmp(cmd->tx_argv[i], "-toplayer", 9))
|
||||
lefTopLayer = TRUE;
|
||||
else if (!strncmp(cmd->tx_argv[i], "-nomaster", 9))
|
||||
lefDoMaster = FALSE;
|
||||
else if (!strncmp(cmd->tx_argv[i], "-all", 4))
|
||||
recurse = TRUE;
|
||||
else goto wrongNumArgs;
|
||||
}
|
||||
else goto wrongNumArgs;
|
||||
}
|
||||
LefWriteAll(selectedUse, lefTopCell, lefTech, lefHide, recurse);
|
||||
LefWriteAll(selectedUse, lefTopCell, lefTech, lefHide, lefTopLayer,
|
||||
lefDoMaster, recurse);
|
||||
}
|
||||
break;
|
||||
case LEF_WRITE:
|
||||
|
|
@ -241,10 +272,34 @@ CmdLef(w, cmd)
|
|||
else if (!strncmp(cmd->tx_argv[i], "-hide", 5))
|
||||
{
|
||||
if (is_lef)
|
||||
lefHide = TRUE;
|
||||
{
|
||||
lefHide = 0;
|
||||
if ((i < (cmd->tx_argc - 1)) &&
|
||||
StrIsNumeric(cmd->tx_argv[i + 1]))
|
||||
{
|
||||
lefHide = cmdParseCoord(w, cmd->tx_argv[i + 1],
|
||||
FALSE, TRUE);
|
||||
cargs--;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
TxPrintf("The \"-hide\" option is only for lef write\n");
|
||||
}
|
||||
else if (!strncmp(cmd->tx_argv[i], "-toplayer", 9))
|
||||
{
|
||||
if (is_lef)
|
||||
lefTopLayer = TRUE;
|
||||
else
|
||||
TxPrintf("The \"-toplayer\" option is only for lef write\n");
|
||||
}
|
||||
else if (!strncmp(cmd->tx_argv[i], "-nomaster", 9))
|
||||
{
|
||||
if (is_lef)
|
||||
lefDoMaster = FALSE;
|
||||
else
|
||||
TxPrintf("The \"-nomaster\" option is only for lef write\n");
|
||||
}
|
||||
else if (!strncmp(cmd->tx_argv[i], "-units", 5))
|
||||
{
|
||||
if (is_lef)
|
||||
|
|
@ -284,7 +339,7 @@ CmdLef(w, cmd)
|
|||
DefWriteCell(selectedUse->cu_def, namep, allSpecial, units);
|
||||
else
|
||||
LefWriteCell(selectedUse->cu_def, namep, selectedUse->cu_def
|
||||
== EditRootDef, lefTech, lefHide);
|
||||
== EditRootDef, lefTech, lefHide, lefTopLayer, lefDoMaster);
|
||||
break;
|
||||
case LEF_HELP:
|
||||
wrongNumArgs:
|
||||
|
|
|
|||
|
|
@ -1568,19 +1568,40 @@ LefReadPin(lefMacro, f, pinname, pinNum, oscale, is_imported)
|
|||
if (is_imported)
|
||||
{
|
||||
bool needRect = TRUE;
|
||||
bool hasPort = FALSE;
|
||||
Label *lab;
|
||||
|
||||
/* Conflicting interests: One purpose of annotation */
|
||||
/* is to make ports where none existed. But if the */
|
||||
/* cell has both port and non-port labels with the */
|
||||
/* same string, then don't mess with the non-port */
|
||||
/* label. */
|
||||
|
||||
for (lab = firstlab; lab; lab = lab->lab_next)
|
||||
if (lab->lab_flags & PORT_DIR_MASK)
|
||||
if (!strcmp(lab->lab_text, testpin))
|
||||
{
|
||||
hasPort = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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 = firstlab; lab; lab = lab->lab_next)
|
||||
if (hasPort == FALSE) lab = firstlab;
|
||||
for (; lab; lab = lab->lab_next)
|
||||
{
|
||||
if (!strcmp(lab->lab_text, testpin))
|
||||
{
|
||||
if (GEO_RECTNULL(&lab->lab_rect))
|
||||
/* If there is at least one port label with this */
|
||||
/* name, then ignore all non-port labels with the */
|
||||
/* same name. */
|
||||
if ((hasPort) && (!(lab->lab_flags & PORT_DIR_MASK)))
|
||||
break;
|
||||
else if (GEO_RECTNULL(&lab->lab_rect))
|
||||
break;
|
||||
else
|
||||
{
|
||||
|
|
@ -1692,13 +1713,16 @@ enum lef_macro_keys {LEF_CLASS = 0, LEF_SIZE, LEF_ORIGIN,
|
|||
LEF_TIMING, LEF_FOREIGN, LEF_PROPERTY, LEF_MACRO_END};
|
||||
|
||||
void
|
||||
LefReadMacro(f, mname, oscale, importForeign)
|
||||
LefReadMacro(f, mname, oscale, importForeign, doAnnotate)
|
||||
FILE *f; /* LEF file being read */
|
||||
char *mname; /* name of the macro */
|
||||
float oscale; /* scale factor um->magic units */
|
||||
bool importForeign; /* Whether we should try to read
|
||||
* in a cell.
|
||||
*/
|
||||
bool doAnnotate; /* If true, ignore all macros that are
|
||||
* not already CellDefs.
|
||||
*/
|
||||
{
|
||||
CellDef *lefMacro;
|
||||
HashEntry *he;
|
||||
|
|
@ -1743,6 +1767,12 @@ LefReadMacro(f, mname, oscale, importForeign)
|
|||
lefMacro = DBCellLookDef(newname);
|
||||
if (lefMacro == NULL)
|
||||
{
|
||||
if (doAnnotate)
|
||||
{
|
||||
/* Ignore any macro that does not correspond to an existing cell */
|
||||
LefSkipSection(f, "MACRO");
|
||||
return;
|
||||
}
|
||||
lefMacro = lefFindCell(newname);
|
||||
DBCellClearDef(lefMacro);
|
||||
DBCellSetAvail(lefMacro);
|
||||
|
|
@ -1839,8 +1869,8 @@ origin_error:
|
|||
break;
|
||||
case LEF_SOURCE:
|
||||
token = LefNextToken(f, TRUE);
|
||||
if (*token != '\n')
|
||||
DBPropPut(lefMacro, "LEFsource", StrDup((char **)NULL, token));
|
||||
/* Ignore "SOURCE" as it is deprecated from LEF 5.6, and */
|
||||
/* magic will write LEF version 5.7. */
|
||||
LefEndStatement(f);
|
||||
break;
|
||||
case LEF_SITE:
|
||||
|
|
@ -2487,9 +2517,10 @@ enum lef_sections {LEF_VERSION = 0,
|
|||
LEF_END};
|
||||
|
||||
void
|
||||
LefRead(inName, importForeign)
|
||||
LefRead(inName, importForeign, doAnnotate)
|
||||
char *inName;
|
||||
bool importForeign;
|
||||
bool doAnnotate;
|
||||
{
|
||||
FILE *f;
|
||||
char *filename;
|
||||
|
|
@ -2713,7 +2744,7 @@ LefRead(inName, importForeign)
|
|||
TxPrintf("LEF file: Defines new cell %s\n", token);
|
||||
*/
|
||||
sprintf(tsave, "%.127s", token);
|
||||
LefReadMacro(f, tsave, oscale, importForeign);
|
||||
LefReadMacro(f, tsave, oscale, importForeign, doAnnotate);
|
||||
break;
|
||||
case LEF_END:
|
||||
if (LefParseEndStatement(f, "LIBRARY") == 0)
|
||||
|
|
|
|||
247
lef/lefWrite.c
247
lef/lefWrite.c
|
|
@ -186,6 +186,11 @@ lefFileOpen(def, file, suffix, mode, prealfile)
|
|||
{
|
||||
if (strcmp(endp, suffix))
|
||||
{
|
||||
/* Try once as-is, with the given extension. That takes care */
|
||||
/* of some less-usual extensions like ".tlef". */
|
||||
if ((rfile = PaOpen(name, mode, NULL, Path, CellLibPath, prealfile)) != NULL)
|
||||
return rfile;
|
||||
|
||||
len = endp - name;
|
||||
if (len > sizeof namebuf - 1) len = sizeof namebuf - 1;
|
||||
(void) strncpy(namebuf, name, len);
|
||||
|
|
@ -256,7 +261,6 @@ lefWriteHeader(def, f, lefTech, propTable, siteTable)
|
|||
/* Reference version 5.7 (November 2009). */
|
||||
|
||||
fprintf(f, "VERSION 5.7 ;\n");
|
||||
fprintf(f, IN0 "NAMESCASESENSITIVE ON ;\n");
|
||||
fprintf(f, IN0 "NOWIREEXTENSIONATPIN ON ;\n");
|
||||
fprintf(f, IN0 "DIVIDERCHAR \"/\" ;\n");
|
||||
fprintf(f, IN0 "BUSBITCHARS \"[]\" ;\n");
|
||||
|
|
@ -281,10 +285,13 @@ lefWriteHeader(def, f, lefTech, propTable, siteTable)
|
|||
}
|
||||
}
|
||||
|
||||
fprintf(f, "UNITS\n");
|
||||
fprintf(f, IN0 "DATABASE MICRONS %d ;\n", LEFdbUnits);
|
||||
fprintf(f, "END UNITS\n");
|
||||
fprintf(f, "\n");
|
||||
if (lefTech)
|
||||
{
|
||||
fprintf(f, "UNITS\n");
|
||||
fprintf(f, IN0 "DATABASE MICRONS %d ;\n", LEFdbUnits);
|
||||
fprintf(f, "END UNITS\n");
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
HashStartSearch(&hs);
|
||||
nprops = 0;
|
||||
|
|
@ -503,7 +510,12 @@ lefEraseGeometry(tile, cdata)
|
|||
ttype = otype;
|
||||
|
||||
/* Erase the tile area out of lefFlat */
|
||||
DBErase(flatDef, &area, ttype);
|
||||
/* Use DBNMPaintPlane, NOT DBErase(). This erases contacts one */
|
||||
/* plane at a time, which normally is bad, but since every plane */
|
||||
/* gets erased eventually during "lef write", this is okay. */
|
||||
/* DBErase(flatDef, &area, ttype); */
|
||||
DBNMPaintPlane(flatDef->cd_planes[lefdata->pNum], otype, &area,
|
||||
DBStdEraseTbl(ttype, lefdata->pNum), NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -563,6 +575,25 @@ lefAccumulateArea(tile, cdata)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* lefFindTopmost --
|
||||
*
|
||||
* Function called to find the topmost layer used by a pin network
|
||||
*
|
||||
* Return 0 to keep the search going.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
lefFindTopmost(tile, cdata)
|
||||
Tile *tile;
|
||||
ClientData cdata;
|
||||
{
|
||||
return 1; /* Stop processing on the first tile found */
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -630,7 +661,7 @@ lefYankGeometry(tile, cdata)
|
|||
while (ttype < DBNumUserLayers)
|
||||
{
|
||||
lefMagicToLefLayer = lefdata->lefMagicMap;
|
||||
if (lefMagicToLefLayer[ttype].lefInfo != NULL)
|
||||
if (lefMagicToLefLayer[ttype].lefName != NULL)
|
||||
{
|
||||
if (IsSplit(tile))
|
||||
// Set only the side being yanked
|
||||
|
|
@ -793,7 +824,7 @@ lefWriteGeometry(tile, cdata)
|
|||
lefdata->numWrites++;
|
||||
|
||||
if (ttype != lefdata->lastType)
|
||||
if (lefMagicToLefLayer[ttype].lefInfo != NULL)
|
||||
if (lefMagicToLefLayer[ttype].lefName != NULL)
|
||||
{
|
||||
fprintf(f, IN2 "LAYER %s ;\n",
|
||||
lefMagicToLefLayer[ttype].lefName);
|
||||
|
|
@ -1064,23 +1095,26 @@ LefWritePinHeader(f, lab)
|
|||
*/
|
||||
|
||||
void
|
||||
lefWriteMacro(def, f, scale, hide)
|
||||
lefWriteMacro(def, f, scale, setback, toplayer, domaster)
|
||||
CellDef *def; /* Def for which to generate LEF output */
|
||||
FILE *f; /* Output to this file */
|
||||
float scale; /* Output distance units conversion factor */
|
||||
bool hide; /* If TRUE, hide all detail except pins */
|
||||
int setback; /* If >= 0, hide all detail except pins inside setback */
|
||||
bool toplayer; /* If TRUE, only output topmost layer of pins */
|
||||
bool domaster; /* If TRUE, write masterslice layers */
|
||||
{
|
||||
bool propfound, ispwrrail;
|
||||
char *propvalue, *class = NULL;
|
||||
Label *lab, *tlab, *reflab;
|
||||
Rect boundary, labr;
|
||||
PlaneMask pmask;
|
||||
SearchContext scx;
|
||||
CellDef *lefFlatDef;
|
||||
CellUse lefFlatUse, lefSourceUse;
|
||||
TileTypeBitMask lmask, boundmask, *lrmask, gatetypemask, difftypemask;
|
||||
TileType ttype;
|
||||
lefClient lc;
|
||||
int idx, pNum, maxport, curport;
|
||||
int idx, pNum, pTop, maxport, curport;
|
||||
char leffmt[2][10];
|
||||
char *LEFtext;
|
||||
HashSearch hs;
|
||||
|
|
@ -1102,11 +1136,27 @@ lefWriteMacro(def, f, scale, hide)
|
|||
lefFlatUse.cu_id = StrDup((char **)NULL, "Flattened cell");
|
||||
lefFlatUse.cu_expandMask = CU_DESCEND_SPECIAL;
|
||||
lefFlatUse.cu_def = lefFlatDef;
|
||||
lefFlatUse.cu_parent = (CellDef *)NULL;
|
||||
lefFlatUse.cu_xlo = 0;
|
||||
lefFlatUse.cu_ylo = 0;
|
||||
lefFlatUse.cu_xhi = 0;
|
||||
lefFlatUse.cu_yhi = 0;
|
||||
lefFlatUse.cu_xsep = 0;
|
||||
lefFlatUse.cu_ysep = 0;
|
||||
lefFlatUse.cu_client = (ClientData)CLIENTDEFAULT;
|
||||
DBSetTrans(&lefFlatUse, &GeoIdentityTransform);
|
||||
|
||||
lefSourceUse.cu_id = StrDup((char **)NULL, "Source cell");
|
||||
lefSourceUse.cu_expandMask = CU_DESCEND_ALL;
|
||||
lefSourceUse.cu_def = def;
|
||||
lefSourceUse.cu_parent = (CellDef *)NULL;
|
||||
lefSourceUse.cu_xlo = 0;
|
||||
lefSourceUse.cu_ylo = 0;
|
||||
lefSourceUse.cu_xhi = 0;
|
||||
lefSourceUse.cu_yhi = 0;
|
||||
lefSourceUse.cu_xsep = 0;
|
||||
lefSourceUse.cu_ysep = 0;
|
||||
lefSourceUse.cu_client = (ClientData)CLIENTDEFAULT;
|
||||
DBSetTrans(&lefSourceUse, &GeoIdentityTransform);
|
||||
|
||||
scx.scx_use = &lefSourceUse;
|
||||
|
|
@ -1132,6 +1182,7 @@ lefWriteMacro(def, f, scale, hide)
|
|||
TTMaskZero(&lc.rmask);
|
||||
TTMaskZero(&boundmask);
|
||||
TTMaskZero(&lmask);
|
||||
pmask = 0;
|
||||
|
||||
/* Any layer which has a port label attached to it should by */
|
||||
/* necessity be considered a routing layer. Usually this will not */
|
||||
|
|
@ -1145,7 +1196,9 @@ lefWriteMacro(def, f, scale, hide)
|
|||
while (he = HashNext(&LefInfo, &hs))
|
||||
{
|
||||
lefLayer *lefl = (lefLayer *)HashGetValue(he);
|
||||
if (lefl && (lefl->lefClass == CLASS_ROUTE || lefl->lefClass == CLASS_VIA))
|
||||
if (lefl && (lefl->lefClass == CLASS_ROUTE || lefl->lefClass == CLASS_VIA
|
||||
|| (domaster && lefl->lefClass == CLASS_MASTER)))
|
||||
{
|
||||
if (lefl->type != -1)
|
||||
{
|
||||
TTMaskSetType(&lc.rmask, lefl->type);
|
||||
|
|
@ -1160,6 +1213,10 @@ lefWriteMacro(def, f, scale, hide)
|
|||
if (lefl->obsType != -1)
|
||||
TTMaskSetType(&lc.rmask, lefl->obsType);
|
||||
|
||||
if (domaster && lefl->lefClass == CLASS_MASTER)
|
||||
pmask |= DBTypePlaneMaskTbl[lefl->type];
|
||||
}
|
||||
|
||||
if (lefl && (lefl->lefClass == CLASS_BOUND))
|
||||
if (lefl->type != -1)
|
||||
TTMaskSetType(&boundmask, lefl->type);
|
||||
|
|
@ -1194,10 +1251,6 @@ lefWriteMacro(def, f, scale, hide)
|
|||
fprintf(f, IN0 "CLASS BLOCK ;\n");
|
||||
}
|
||||
|
||||
propvalue = (char *)DBPropGet(def, "LEFsource", &propfound);
|
||||
if (propfound)
|
||||
fprintf(f, IN0 "SOURCE %s ;\n", propvalue);
|
||||
|
||||
fprintf(f, IN0 "FOREIGN %s ;\n", def->cd_name);
|
||||
|
||||
/* If a boundary class was declared in the LEF section, then use */
|
||||
|
|
@ -1231,6 +1284,14 @@ lefWriteMacro(def, f, scale, hide)
|
|||
&boundary.r_ybot, &boundary.r_xtop, &boundary.r_ytop);
|
||||
}
|
||||
|
||||
/* Check if (boundry less setback) is degenerate. If so, then */
|
||||
/* there is no effect of the "-hide" option. */
|
||||
if (setback > 0)
|
||||
{
|
||||
if ((boundary.r_xtop - boundary.r_xbot) < (2 * setback)) setback = -1;
|
||||
if ((boundary.r_ytop - boundary.r_ybot) < (2 * setback)) setback = -1;
|
||||
}
|
||||
|
||||
/* Write position and size information */
|
||||
/* Note: Using "0.0 - X" prevents fprintf from generating "negative */
|
||||
/* zeros" in the output. */
|
||||
|
|
@ -1355,7 +1416,7 @@ lefWriteMacro(def, f, scale, hide)
|
|||
scx.scx_area = labr;
|
||||
SelectClear();
|
||||
|
||||
if (hide)
|
||||
if (setback == 0)
|
||||
{
|
||||
Rect carea;
|
||||
labelLinkedList *newlll;
|
||||
|
|
@ -1379,6 +1440,18 @@ lefWriteMacro(def, f, scale, hide)
|
|||
newlll->lll_next = lll;
|
||||
lll = newlll;
|
||||
}
|
||||
else if (setback > 0)
|
||||
{
|
||||
Rect carea;
|
||||
|
||||
/* For -hide with setback, select the entire net and then */
|
||||
/* remove the part inside the setback area. Note that this */
|
||||
/* does not check if this causes the label to disappear. */
|
||||
|
||||
SelectNet(&scx, lab->lab_type, 0, NULL, FALSE);
|
||||
GEO_EXPAND(&boundary, -setback, &carea);
|
||||
SelRemoveArea(&carea, &DBAllButSpaceAndDRCBits);
|
||||
}
|
||||
else
|
||||
SelectNet(&scx, lab->lab_type, 0, NULL, FALSE);
|
||||
|
||||
|
|
@ -1410,6 +1483,17 @@ lefWriteMacro(def, f, scale, hide)
|
|||
if (antdiffarea > 0) break;
|
||||
}
|
||||
|
||||
if (toplayer)
|
||||
{
|
||||
for (pTop = DBNumPlanes - 1; pTop >= PL_TECHDEPBASE; pTop--)
|
||||
{
|
||||
if (DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pTop],
|
||||
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
|
||||
lefFindTopmost, (ClientData)NULL) == 1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// For all geometry in the selection, write LEF records,
|
||||
// and mark the corresponding tiles in lefFlatDef as
|
||||
// visited.
|
||||
|
|
@ -1418,6 +1502,22 @@ lefWriteMacro(def, f, scale, hide)
|
|||
lc.lastType = TT_SPACE;
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
{
|
||||
/* Option to output only the topmost layer of a network */
|
||||
/* as PIN geometry. All layers below it are considered */
|
||||
/* obstructions. Masterslice layers are considered an */
|
||||
/* exception, as they are often needed for ensuring */
|
||||
/* connectivity between power supply and wells. */
|
||||
|
||||
if (toplayer && (pNum != pTop))
|
||||
{
|
||||
if (domaster & (pmask != 0))
|
||||
{
|
||||
if (!PlaneMaskHasPlane(pmask, pNum))
|
||||
continue;
|
||||
}
|
||||
else continue;
|
||||
}
|
||||
|
||||
lc.pNum = pNum;
|
||||
DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum],
|
||||
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
|
||||
|
|
@ -1516,7 +1616,7 @@ lefWriteMacro(def, f, scale, hide)
|
|||
|
||||
/* Restrict to routing planes only */
|
||||
|
||||
if (hide)
|
||||
if (setback >= 0)
|
||||
{
|
||||
/* If details of the cell are to be hidden, then first paint */
|
||||
/* all route layers with an obstruction rectangle the size of */
|
||||
|
|
@ -1536,6 +1636,7 @@ lefWriteMacro(def, f, scale, hide)
|
|||
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
|
||||
if (TTMaskHasType(&lmask, ttype))
|
||||
{
|
||||
Rect r;
|
||||
layerBound.r_xbot = layerBound.r_xtop = 0;
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
if (TTMaskHasType(&DBPlaneTypes[pNum], ttype))
|
||||
|
|
@ -1545,6 +1646,10 @@ lefWriteMacro(def, f, scale, hide)
|
|||
lefGetBound, (ClientData)(&layerBound));
|
||||
}
|
||||
|
||||
/* Clip layerBound to setback boundary */
|
||||
GEO_EXPAND(&boundary, -setback, &r);
|
||||
GeoClip(&layerBound, &r);
|
||||
|
||||
DBPaint(lc.lefYank, &layerBound, ttype);
|
||||
}
|
||||
|
||||
|
|
@ -1568,6 +1673,43 @@ lefWriteMacro(def, f, scale, hide)
|
|||
DBErase(lc.lefYank, &thislll->lll_area, lab->lab_type);
|
||||
freeMagic(thislll);
|
||||
}
|
||||
|
||||
if (setback > 0)
|
||||
{
|
||||
/* For -hide with setback, yank everything in the area outside */
|
||||
/* the setback. */
|
||||
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
{
|
||||
Rect r;
|
||||
lc.pNum = pNum;
|
||||
|
||||
r = def->cd_bbox;
|
||||
r.r_ytop = boundary.r_ybot + setback;
|
||||
DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum],
|
||||
&r, &DBAllButSpaceAndDRCBits,
|
||||
lefYankGeometry, (ClientData) &lc);
|
||||
r = def->cd_bbox;
|
||||
r.r_ybot = boundary.r_ytop - setback;
|
||||
DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum],
|
||||
&r, &DBAllButSpaceAndDRCBits,
|
||||
lefYankGeometry, (ClientData) &lc);
|
||||
r = def->cd_bbox;
|
||||
r.r_ybot = boundary.r_ybot + setback;
|
||||
r.r_ytop = boundary.r_ytop - setback;
|
||||
r.r_xtop = boundary.r_xbot + setback;
|
||||
DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum],
|
||||
&r, &DBAllButSpaceAndDRCBits,
|
||||
lefYankGeometry, (ClientData) &lc);
|
||||
r = def->cd_bbox;
|
||||
r.r_ybot = boundary.r_ybot + setback;
|
||||
r.r_ytop = boundary.r_ytop - setback;
|
||||
r.r_xbot = boundary.r_xtop - setback;
|
||||
DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum],
|
||||
&r, &DBAllButSpaceAndDRCBits,
|
||||
lefYankGeometry, (ClientData) &lc);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1590,7 +1732,7 @@ lefWriteMacro(def, f, scale, hide)
|
|||
lefWriteGeometry, (ClientData) &lc);
|
||||
|
||||
/* Additional yank & write for contacts (although ignore contacts for -hide) */
|
||||
if (!hide)
|
||||
if (setback < 0)
|
||||
{
|
||||
lc.lefMode = LEF_MODE_OBS_CONTACT;
|
||||
DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum],
|
||||
|
|
@ -1601,6 +1743,51 @@ lefWriteMacro(def, f, scale, hide)
|
|||
lefWriteGeometry, (ClientData) &lc);
|
||||
lc.lefMode = LEF_MODE_OBSTRUCT;
|
||||
}
|
||||
else if (setback > 0)
|
||||
{
|
||||
Rect r;
|
||||
|
||||
/* Apply only to area outside setback. */
|
||||
lc.lefMode = LEF_MODE_OBS_CONTACT;
|
||||
|
||||
r = def->cd_bbox;
|
||||
r.r_ytop = boundary.r_ybot + setback;
|
||||
DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum],
|
||||
&r, &DBAllButSpaceAndDRCBits,
|
||||
lefYankContacts, (ClientData) &lc);
|
||||
DBSrPaintArea((Tile *)NULL, lc.lefYank->cd_planes[pNum],
|
||||
&r, &lc.rmask, lefWriteGeometry, (ClientData) &lc);
|
||||
|
||||
r = def->cd_bbox;
|
||||
r.r_ybot = boundary.r_ytop - setback;
|
||||
DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum],
|
||||
&r, &DBAllButSpaceAndDRCBits,
|
||||
lefYankContacts, (ClientData) &lc);
|
||||
DBSrPaintArea((Tile *)NULL, lc.lefYank->cd_planes[pNum],
|
||||
&r, &lc.rmask, lefWriteGeometry, (ClientData) &lc);
|
||||
|
||||
r = def->cd_bbox;
|
||||
r.r_ybot = boundary.r_ybot + setback;
|
||||
r.r_ytop = boundary.r_ytop - setback;
|
||||
r.r_xtop = boundary.r_xbot + setback;
|
||||
DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum],
|
||||
&r, &DBAllButSpaceAndDRCBits,
|
||||
lefYankContacts, (ClientData) &lc);
|
||||
DBSrPaintArea((Tile *)NULL, lc.lefYank->cd_planes[pNum],
|
||||
&r, &lc.rmask, lefWriteGeometry, (ClientData) &lc);
|
||||
|
||||
r = def->cd_bbox;
|
||||
r.r_ybot = boundary.r_ybot + setback;
|
||||
r.r_ytop = boundary.r_ytop - setback;
|
||||
r.r_xbot = boundary.r_xtop - setback;
|
||||
DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum],
|
||||
&r, &DBAllButSpaceAndDRCBits,
|
||||
lefYankContacts, (ClientData) &lc);
|
||||
DBSrPaintArea((Tile *)NULL, lc.lefYank->cd_planes[pNum],
|
||||
&r, &lc.rmask, lefWriteGeometry, (ClientData) &lc);
|
||||
|
||||
lc.lefMode = LEF_MODE_OBSTRUCT;
|
||||
}
|
||||
}
|
||||
|
||||
if (lc.numWrites > 0)
|
||||
|
|
@ -1777,11 +1964,13 @@ lefGetProperties(stackItem, i, clientData)
|
|||
*/
|
||||
|
||||
void
|
||||
LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, recurse)
|
||||
LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefTopLayer, lefDoMaster, recurse)
|
||||
CellUse *rootUse;
|
||||
bool writeTopCell;
|
||||
bool lefTech;
|
||||
bool lefHide;
|
||||
int lefHide;
|
||||
bool lefTopLayer;
|
||||
bool lefDoMaster;
|
||||
bool recurse;
|
||||
{
|
||||
HashTable propHashTbl, siteHashTbl;
|
||||
|
|
@ -1847,11 +2036,11 @@ LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, recurse)
|
|||
{
|
||||
def->cd_client = (ClientData) 0;
|
||||
if (!SigInterruptPending)
|
||||
lefWriteMacro(def, f, scale, lefHide);
|
||||
lefWriteMacro(def, f, scale, lefHide, lefTopLayer, lefDoMaster);
|
||||
}
|
||||
|
||||
/* End the LEF file */
|
||||
fprintf(f, "END LIBRARY ;\n");
|
||||
fprintf(f, "END LIBRARY\n\n");
|
||||
|
||||
fclose(f);
|
||||
StackFree(lefDefStack);
|
||||
|
|
@ -1911,12 +2100,14 @@ lefDefPushFunc(use, recurse)
|
|||
*/
|
||||
|
||||
void
|
||||
LefWriteCell(def, outName, isRoot, lefTech, lefHide)
|
||||
LefWriteCell(def, outName, isRoot, lefTech, lefHide, lefTopLayer, lefDoMaster)
|
||||
CellDef *def; /* Cell being written */
|
||||
char *outName; /* Name of output file, or NULL. */
|
||||
bool isRoot; /* Is this the root cell? */
|
||||
bool lefTech; /* Output layer information if TRUE */
|
||||
bool lefHide; /* Hide detail other than pins if TRUE */
|
||||
int lefHide; /* Hide detail other than pins if >= 0 */
|
||||
bool lefTopLayer; /* Use only topmost layer of pin if TRUE */
|
||||
bool lefDoMaster; /* Write masterslice layers if TRUE */
|
||||
{
|
||||
char *filename;
|
||||
FILE *f;
|
||||
|
|
@ -1950,7 +2141,11 @@ LefWriteCell(def, outName, isRoot, lefTech, lefHide)
|
|||
HashKill(&propHashTbl);
|
||||
HashKill(&siteHashTbl);
|
||||
}
|
||||
lefWriteMacro(def, f, scale, lefHide);
|
||||
lefWriteMacro(def, f, scale, lefHide, lefTopLayer, lefDoMaster);
|
||||
|
||||
/* End the LEF file */
|
||||
fprintf(f, "END LIBRARY\n\n");
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ CmdPlot(w, cmd)
|
|||
int iwidth, scale;
|
||||
|
||||
#ifdef HAVE_LIBCAIRO
|
||||
int flags;
|
||||
extern void GrTCairoPlotSVG();
|
||||
#endif
|
||||
|
||||
|
|
@ -175,11 +176,11 @@ CmdPlot(w, cmd)
|
|||
if ((!ToolGetBox(&boxRootDef, &scx.scx_area)) ||
|
||||
(scx.scx_use->cu_def != boxRootDef))
|
||||
{
|
||||
TxError("The box and cursor must appear in the same window\n");
|
||||
TxError(" for plotting. The box indicates the area to\n");
|
||||
TxError(" plot, and the cursor's window tells which\n");
|
||||
TxError(" cells are expanded and unexpanded).\n");
|
||||
return;
|
||||
/* If no box is specified, then use the cell in the layout */
|
||||
/* window, and plot the entire cell using the cell bounding */
|
||||
/* box as the area to plot. */
|
||||
|
||||
scx.scx_area = scx.scx_use->cu_def->cd_bbox;
|
||||
}
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
mask = crec->dbw_visibleLayers;
|
||||
|
|
@ -271,7 +272,15 @@ CmdPlot(w, cmd)
|
|||
cmdPlotOption[PLOTSVG]);
|
||||
return;
|
||||
}
|
||||
flags = window->w_flags;
|
||||
/* In case this is called from a non-GUI wrapper window, remove */
|
||||
/* the window border widgets from the rendered display. */
|
||||
window->w_flags &= ~(WIND_SCROLLABLE | WIND_SCROLLBARS | WIND_CAPTION
|
||||
| WIND_BORDER);
|
||||
DBWHLRemoveClient(DBWDrawBox); // Prevent drawing the cursor box
|
||||
GrTCairoPlotSVG(cmd->tx_argv[2], window);
|
||||
DBWHLAddClient(DBWDrawBox); // Restore drawing the cursor box
|
||||
window->w_flags = flags;
|
||||
return;
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ RM = rm -f
|
|||
CP = cp
|
||||
AR = ar
|
||||
ARFLAGS = crv
|
||||
LINK = ld -r
|
||||
LINK = @LD@ -r
|
||||
LD = @LD@
|
||||
MCPP = @MCPP@
|
||||
MSED = @MSED@
|
||||
|
|
|
|||
|
|
@ -57,8 +57,14 @@ proc readspice {netfile} {
|
|||
set fdata {}
|
||||
set lastline ""
|
||||
while {[gets $fnet line] >= 0} {
|
||||
if {[lindex $line 0] != "*"} {
|
||||
if {[lindex $line 0] == "+"} {
|
||||
# Handle CDL format *.PININFO (convert to .PININFO ...)
|
||||
if {$is_cdl && ([string range $line 0 1] == "*.")} {
|
||||
if {[string tolower [string range $line 2 8]] == "pininfo"} {
|
||||
set line [string range $line 1 end]
|
||||
}
|
||||
}
|
||||
if {[string index $line 0] != "*"} {
|
||||
if {[string index $line 0] == "+"} {
|
||||
if {[string range $line end end] != " "} {
|
||||
append lastline " "
|
||||
}
|
||||
|
|
@ -74,6 +80,9 @@ proc readspice {netfile} {
|
|||
|
||||
# Now look for all ".subckt" lines
|
||||
|
||||
set cell ""
|
||||
set status 0
|
||||
|
||||
suspendall
|
||||
foreach line $fdata {
|
||||
set ftokens [split $line]
|
||||
|
|
@ -90,12 +99,36 @@ proc readspice {netfile} {
|
|||
if {$keyword == ".subckt"} {
|
||||
set cell [lindex $ftokens 1]
|
||||
set status [cellname list exists $cell]
|
||||
set pindict [dict create]
|
||||
if {$status != 0} {
|
||||
load $cell
|
||||
box values 0 0 0 0
|
||||
set n 1
|
||||
set changed false
|
||||
|
||||
# Make sure pins aren't duplicated by first moving all pin
|
||||
# indexes above the number of pins to check.
|
||||
|
||||
set npins [expr {[llength $ftokens] - 1}]
|
||||
set highport [port last]
|
||||
set outport $highport
|
||||
if {$outport < $npins} {set outport $npins}
|
||||
set p [port first]
|
||||
while {$p != -1 && $p <= $highport} {
|
||||
set p1 [port $p next]
|
||||
set testpin [port $p name]
|
||||
if {$testpin != ""} {
|
||||
port $p index $outport
|
||||
incr outport
|
||||
}
|
||||
set p $p1
|
||||
}
|
||||
|
||||
foreach pin [lrange $ftokens 2 end] {
|
||||
# If "=" is in the name, then we have finished the pins
|
||||
# and are looking at parameters, and so parsing is done.
|
||||
if {[string first = $pin] >= 0} {break}
|
||||
|
||||
# Tcl "split" will not group spaces and tabs but leaves
|
||||
# empty strings.
|
||||
if {$pin == {}} {continue}
|
||||
|
|
@ -113,9 +146,6 @@ proc readspice {netfile} {
|
|||
set testpin $pin
|
||||
set pinidx [port $testpin index]
|
||||
|
||||
# Test a few common delimiter translations. This list
|
||||
# is by no means exhaustive.
|
||||
|
||||
if {$pinidx == ""} {
|
||||
set testpin [string map {\[ < \] >]} $pin]
|
||||
set pinidx [port $testpin index]
|
||||
|
|
@ -125,15 +155,37 @@ proc readspice {netfile} {
|
|||
set pinidx [port $testpin index]
|
||||
}
|
||||
|
||||
# Also test some case sensitivity issues (also not exhaustive)
|
||||
# Handle issues with case insensitivity by getting
|
||||
# a list of ports and doing a case comparison.
|
||||
|
||||
if {$pinidx == ""} {
|
||||
set testpin [string tolower $pin]
|
||||
set pinidx [port $testpin index]
|
||||
set highport [port last]
|
||||
for {set p 0} {$p <= $highport} {incr p} {
|
||||
set testpin [port $p name]
|
||||
if {[string tolower $testpin] == [string tolower $pin]} {
|
||||
set pinidx [port $testpin index]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Finally, check if there is a bare label that matches the
|
||||
# port name. If so, convert it into a port
|
||||
|
||||
if {$pinidx == ""} {
|
||||
set testpin [string toupper $pin]
|
||||
set pinidx [port $testpin index]
|
||||
select top cell
|
||||
select area labels
|
||||
set all [lindex [what -list] 1]
|
||||
select clear
|
||||
foreach labrec $all {
|
||||
set testpin [lindex $labrec 0]
|
||||
if {[string tolower $testpin] == [string tolower $pin]} {
|
||||
goto $testpin
|
||||
set pinidx -1
|
||||
port make $n
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if {$pinidx != ""} {
|
||||
|
|
@ -142,6 +194,8 @@ proc readspice {netfile} {
|
|||
set changed true
|
||||
}
|
||||
incr n
|
||||
# Record the original and modified pin names
|
||||
dict set pindict $pin $testpin
|
||||
} else {
|
||||
set layer [goto $pin]
|
||||
if {$layer != ""} {
|
||||
|
|
@ -149,6 +203,8 @@ proc readspice {netfile} {
|
|||
incr n
|
||||
set changed true
|
||||
}
|
||||
# Record the pin name as unmodified
|
||||
dict set pindict $pin $pin
|
||||
}
|
||||
}
|
||||
if {$changed} {
|
||||
|
|
@ -157,6 +213,26 @@ proc readspice {netfile} {
|
|||
} else {
|
||||
puts stdout "Cell $cell in netlist has not been loaded."
|
||||
}
|
||||
} elseif {$keyword == ".pininfo"} {
|
||||
if {($cell != "") && ($status != 0)} {
|
||||
foreach pininfo [lrange $ftokens 1 end] {
|
||||
set infopair [split $pininfo :]
|
||||
set pinname [lindex $infopair 0]
|
||||
set pindir [lindex $infopair 1]
|
||||
if {![catch {set pin [dict get $pindict $pinname]}]} {
|
||||
case $pindir {
|
||||
B {port $pin class inout}
|
||||
I {port $pin class input}
|
||||
O {port $pin class output}
|
||||
}
|
||||
} elseif {$pinname != ""} {
|
||||
puts stderr ".PININFO error: Pin $pinname not found."
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif {$keyword == ".ends"} {
|
||||
set cell ""
|
||||
set status 0
|
||||
}
|
||||
}
|
||||
resumeall
|
||||
|
|
|
|||
|
|
@ -614,6 +614,10 @@ proc magic::repaintwrapper { win } {
|
|||
proc magic::boxview {win {cmdstr ""}} {
|
||||
if {${cmdstr} == "exists" || ${cmdstr} == "help" || ${cmdstr} == ""} {
|
||||
# do nothing. . . informational only, no change to the box
|
||||
} elseif {${cmdstr} == "remove"} {
|
||||
set framename [winfo parent $win]
|
||||
if {$framename == "."} {return}
|
||||
${framename}.titlebar.pos configure -text "no box"
|
||||
} elseif {[info level] <= 1} {
|
||||
# For NULL window, find all layout windows and apply update to each.
|
||||
if {$win == {}} {
|
||||
|
|
|
|||
|
|
@ -940,7 +940,7 @@ mainInitFinal()
|
|||
}
|
||||
}
|
||||
|
||||
if (getcwd(cwd, 512) == NULL || strcmp(cwd, home))
|
||||
if (getcwd(cwd, 512) == NULL || strcmp(cwd, home) || (RCFileName[0] == '/'))
|
||||
{
|
||||
/* Read in the .magicrc file from the current directory, if */
|
||||
/* different from HOME. */
|
||||
|
|
@ -1153,7 +1153,7 @@ mainInitFinal()
|
|||
break;
|
||||
#ifdef LEF_MODULE
|
||||
case FN_LEF_FILE:
|
||||
LefRead(temporary->fn, FALSE);
|
||||
LefRead(temporary->fn, FALSE, FALSE);
|
||||
break;
|
||||
case FN_DEF_FILE:
|
||||
DefRead(temporary->fn, FALSE);
|
||||
|
|
|
|||
|
|
@ -74,8 +74,16 @@ static char *freeDelayedItem = NULL;
|
|||
#define MallocRoutine(a) ckalloc(a)
|
||||
#define FreeRoutine(a) ckfree(a)
|
||||
#else
|
||||
#define MallocRoutine(a) Tcl_Alloc(a)
|
||||
#define FreeRoutine(a) Tcl_Free(a)
|
||||
/* DO NOT USE: Tcl_Alloc is defined with argument (unsigned int) NOT
|
||||
* (size_t) and therefore limits memory allocation to the size of a
|
||||
* 32-bit integer. Just use the normal malloc() and free(). Left as-is
|
||||
* with TCL_MEM_DEBUG with the caveat that one should not use this to
|
||||
* debug a huge design. Valgrind works better anyway.
|
||||
*/
|
||||
/* #define MallocRoutine(a) Tcl_Alloc(a) */
|
||||
/* #define FreeRoutine(a) Tcl_Free(a) */
|
||||
#define MallocRoutine(a) malloc(a)
|
||||
#define FreeRoutine(a) free(a)
|
||||
#endif
|
||||
#else
|
||||
#define MallocRoutine(a) malloc(a)
|
||||
|
|
|
|||
|
|
@ -1104,7 +1104,7 @@ windDoMacro(w, cmd, interactive)
|
|||
if (interactive && !cMacro->interactive) continue;
|
||||
|
||||
if (do_help)
|
||||
cp = cMacro->helptext;
|
||||
cp = (cMacro->helptext == NULL) ? cMacro->macrotext : cMacro->helptext;
|
||||
else
|
||||
cp = cMacro->macrotext;
|
||||
|
||||
|
|
@ -1135,10 +1135,11 @@ windDoMacro(w, cmd, interactive)
|
|||
else
|
||||
{
|
||||
if (cMacro->interactive)
|
||||
TxPrintf("Interactive macro '%s' contains \"%s\"\n",
|
||||
cn, cp);
|
||||
TxPrintf("Interactive macro '%s' %s \"%s\"\n",
|
||||
cn, (do_help) ? "" : "contains", cp);
|
||||
else
|
||||
TxPrintf("Macro '%s' contains \"%s\"\n", cn, cp);
|
||||
TxPrintf("Macro '%s' %s \"%s\"\n",
|
||||
cn, (do_help) ? "" : "contains", cp);
|
||||
}
|
||||
freeMagic(cn);
|
||||
any = TRUE;
|
||||
|
|
|
|||
Loading…
Reference in New Issue