Merge branch 'master' of https://github.com/RTimothyEdwards/magic into spice_hier

Bringing branch up to date with master
This commit is contained in:
Dan Moore 2020-10-16 09:00:31 -07:00
commit 765c1abd11
47 changed files with 1416 additions and 4454 deletions

4094
DRCtech.c

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -1 +1 @@
8.3.27
8.3.67

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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));
}
/*
* ----------------------------------------------------------------------------
*

View File

@ -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;

View File

@ -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;
}
}

View File

@ -66,6 +66,7 @@ extern void CIFReadTechFinal();
/* Externally-visible procedures: */
extern float CIFGetOutputScale();
extern float CIFGetScale();
extern float CIFGetInputScale();
extern int CIFGetDefaultContactSize();

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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. . .

View File

@ -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.

View File

@ -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);

View File

@ -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.
*/

View File

@ -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';

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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); */

View File

@ -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);
}

View File

@ -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;

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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.
*/

View File

@ -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);

View File

@ -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 */

View File

@ -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);
}

View File

@ -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;

View File

@ -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++;

View File

@ -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. */

View File

@ -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;
}
/*

View File

@ -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:

View File

@ -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)

View File

@ -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);
}

View File

@ -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

View File

@ -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@

View File

@ -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

View File

@ -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 == {}} {

View File

@ -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);

View File

@ -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)

View File

@ -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;