summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--VERSION2
-rw-r--r--calma/CalmaRdpt.c8
-rw-r--r--cif/CIFrdtech.c4
-rw-r--r--commands/CmdLQ.c12
-rw-r--r--debian/changelog6
-rw-r--r--drc/DRCbasic.c8
-rw-r--r--ext2spice/ext2hier.c15
-rw-r--r--ext2spice/ext2spice.c155
-rw-r--r--ext2spice/ext2spice.h30
-rw-r--r--extflat/Depend10
-rw-r--r--extflat/EFantenna.c446
-rw-r--r--extflat/EFbuild.c240
-rw-r--r--extflat/EFdef.c22
-rw-r--r--extflat/EFflat.c18
-rw-r--r--extflat/EFhier.c6
-rw-r--r--extflat/EFint.h2
-rw-r--r--extflat/EFread.c3
-rw-r--r--extflat/EFvisit.c8
-rw-r--r--extract/ExtTech.c83
-rw-r--r--extract/extract.h1
-rw-r--r--extract/extractInt.h16
-rw-r--r--lef/lefWrite.c32
-rw-r--r--resis/ResReadSim.c42
23 files changed, 892 insertions, 277 deletions
diff --git a/VERSION b/VERSION
index d27d557..a640e7e 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-8.2.149
+8.2.157
diff --git a/calma/CalmaRdpt.c b/calma/CalmaRdpt.c
index 61e6e87..f0edac7 100644
--- a/calma/CalmaRdpt.c
+++ b/calma/CalmaRdpt.c
@@ -291,10 +291,10 @@ calmaElementBoundary()
/* Convert rp to magic database units to compare to label rects */
rpc = rp->r_r;
- rpc.r_xbot /= calmaReadScale1;
- rpc.r_xtop /= calmaReadScale1;
- rpc.r_ybot /= calmaReadScale1;
- rpc.r_ytop /= calmaReadScale1;
+ rpc.r_xbot /= cifCurReadStyle->crs_scaleFactor;
+ rpc.r_xtop /= cifCurReadStyle->crs_scaleFactor;
+ rpc.r_ybot /= cifCurReadStyle->crs_scaleFactor;
+ rpc.r_ytop /= cifCurReadStyle->crs_scaleFactor;
if ((ciftype >= 0) &&
(cifCurReadStyle->crs_labelSticky[ciftype] != LABEL_TYPE_NONE))
diff --git a/cif/CIFrdtech.c b/cif/CIFrdtech.c
index 297ad7b..3777df9 100644
--- a/cif/CIFrdtech.c
+++ b/cif/CIFrdtech.c
@@ -621,8 +621,10 @@ CIFReadTechLine(sectionName, argc, argv)
if (argc >= 3)
{
- if(!strncmp(argv[argc - 1], "nanom", 5))
+ if (!strncmp(argv[argc - 1], "nanom", 5))
cifCurReadStyle->crs_multiplier = 10;
+ else if (!strncmp(argv[argc - 1], "angstr", 6))
+ cifCurReadStyle->crs_multiplier = 100;
}
if (cifCurReadStyle->crs_scaleFactor <= 0)
diff --git a/commands/CmdLQ.c b/commands/CmdLQ.c
index 1225081..02c04b6 100644
--- a/commands/CmdLQ.c
+++ b/commands/CmdLQ.c
@@ -318,7 +318,7 @@ CmdLabel(w, cmd)
* Implement the "load" command.
*
* Usage:
- * load [name [scaled n [d]]] [-force]
+ * load [name [scaled n [d]]] [-force] [-nowindow]
*
* If name is supplied, then the window containing the point tool is
* remapped so as to edit the cell with the given name.
@@ -364,15 +364,16 @@ CmdLoad(w, cmd)
locargc--;
ignoreTech = TRUE;
}
- if (locargc >= 4 && !strncmp(cmd->tx_argv[2], "scale", 5) &&
+ if ((locargc >= 4) && !strncmp(cmd->tx_argv[2], "scale", 5) &&
StrIsInt(cmd->tx_argv[3]))
{
n = atoi(cmd->tx_argv[3]);
- if (cmd->tx_argc == 5 && StrIsInt(cmd->tx_argv[4]))
+ if ((locargc == 5) && StrIsInt(cmd->tx_argv[4]))
d = atoi(cmd->tx_argv[4]);
else if (locargc != 4)
{
- TxError("Usage: %s name scaled n [d]\n", cmd->tx_argv[0]);
+ TxError("Usage: %s name scaled n [d] [-force] [-nowindow]\n",
+ cmd->tx_argv[0]);
return;
}
DBLambda[0] *= d;
@@ -381,7 +382,8 @@ CmdLoad(w, cmd)
}
else if (!ignoreTech && !noWindow)
{
- TxError("Usage: %s [name [scaled n [d]]]\n", cmd->tx_argv[0]);
+ TxError("Usage: %s name [scaled n [d]] [-force] [-nowindow]\n",
+ cmd->tx_argv[0]);
return;
}
}
diff --git a/debian/changelog b/debian/changelog
index d622aa0..7a92b94 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+magic (8.2.157+ds.1-1) unstable; urgency=low
+
+ * New upstream release
+
+ -- Ruben Undheim <ruben.undheim@gmail.com> Thu, 07 Nov 2019 21:14:45 +0100
+
magic (8.2.149+ds.1-1) unstable; urgency=medium
* Upload to unstable
diff --git a/drc/DRCbasic.c b/drc/DRCbasic.c
index a3d2cbb..78afd39 100644
--- a/drc/DRCbasic.c
+++ b/drc/DRCbasic.c
@@ -484,6 +484,7 @@ drcTile (tile, arg)
int edgeX = LEFT(tile);
firsttile = TRUE;
+ mrd = NULL;
for (tpleft = BL(tile); BOTTOM(tpleft) < top; tpleft = RT(tpleft))
{
/* Get the tile types to the left and right of the edge */
@@ -554,8 +555,6 @@ drcTile (tile, arg)
mrd = drcCanonicalMaxwidth(tpleft, GEO_WEST, arg, cptr);
else if (firsttile)
mrd = drcCanonicalMaxwidth(tile, GEO_EAST, arg, cptr);
- else
- mrd = NULL;
if (!trigpending || (DRCCurStyle->DRCFlags
& DRC_FLAGS_WIDEWIDTH_NONINCLUSIVE))
cptr->drcc_dist--;
@@ -610,7 +609,6 @@ drcTile (tile, arg)
drcCheckMaxwidth(tile, arg, cptr);
continue;
}
- else if (!triggered) mrd = NULL;
if (cptr->drcc_flags & DRC_RECTSIZE)
{
@@ -870,6 +868,7 @@ checkbottom:
/* Go right across bottom of tile */
firsttile = TRUE;
+ mrd = NULL;
for (tpbot = LB(tile); LEFT(tpbot) < right; tpbot = TR(tpbot))
{
/* Get the tile types to the top and bottom of the edge */
@@ -936,8 +935,6 @@ checkbottom:
mrd = drcCanonicalMaxwidth(tpbot, GEO_SOUTH, arg, cptr);
else if (firsttile)
mrd = drcCanonicalMaxwidth(tile, GEO_NORTH, arg, cptr);
- else
- mrd = NULL;
if (!trigpending || (DRCCurStyle->DRCFlags
& DRC_FLAGS_WIDEWIDTH_NONINCLUSIVE))
cptr->drcc_dist--;
@@ -992,7 +989,6 @@ checkbottom:
if (trigpending) cptr = cptr->drcc_next;
continue;
}
- else if (!triggered) mrd = NULL;
result = 0;
arg->dCD_radial = 0;
diff --git a/ext2spice/ext2hier.c b/ext2spice/ext2hier.c
index 07143cb..6f6fc55 100644
--- a/ext2spice/ext2hier.c
+++ b/ext2spice/ext2hier.c
@@ -1625,6 +1625,10 @@ esMakePorts(hc, cdata)
{
nn->efnn_node->efnode_flags |= EF_PORT;
nn->efnn_port = -1; // Will be sorted later
+
+ // Diagnostic
+ // TxPrintf("Port connection in %s from net %s to net %s (%s)\n",
+ // def->def_name, locname, name, portname);
}
}
@@ -1634,9 +1638,6 @@ esMakePorts(hc, cdata)
updef = portdef;
}
- // Diagnostic
- // TxPrintf("Connection in %s to net %s (%s)\n", def->def_name,
- // name, portname);
}
}
@@ -1656,7 +1657,7 @@ esMakePorts(hc, cdata)
// In particular, this keeps parasitics out of the netlist for
// LVS purposes if "cthresh" is set to "infinite".
- if (fabs((double)conn->conn_cap) < EFCapThreshold) continue;
+ if (fabs((double)conn->conn_cap / 1000) < EFCapThreshold) continue;
portname = name;
updef = def;
@@ -1771,7 +1772,8 @@ esHierVisit(hc, cdata)
if (def != topdef)
{
- if ((def->def_devs == NULL) && (HashGetNumEntries(&def->def_uses) == 0))
+ if ((HashGetNumEntries(&def->def_devs) == 0) &&
+ (HashGetNumEntries(&def->def_uses) == 0))
{
if (locDoSubckt == AUTO)
{
@@ -1883,6 +1885,9 @@ esHierVisit(hc, cdata)
EFHierVisitNodes(hcf, spcnodeHierVisit, (ClientData) NULL);
freeMagic(resstr);
}
+
+ /* Reset device merge index for next cell */
+ if (esMergeDevsA || esMergeDevsC) esFMIndex = 0;
}
if ((def != topdef) || (def->def_flags & DEF_SUBCIRCUIT) || (locDoSubckt == TRUE))
diff --git a/ext2spice/ext2spice.c b/ext2spice/ext2spice.c
index 8885bdc..65eb732 100644
--- a/ext2spice/ext2spice.c
+++ b/ext2spice/ext2spice.c
@@ -264,7 +264,8 @@ CmdExtToSpice(w, cmd)
"extresist [on|off] incorporate information from extresist",
"resistor tee [on|off] model resistor capacitance as a T-network",
"scale [on|off] use .option card for scaling",
- "subcircuits [on|off] standard cells become subcircuit calls",
+ "subcircuits [top|descend] [on|off|auto]\n"
+ " standard cells become subcircuit calls",
"hierarchy [on|off] output hierarchical spice for LVS",
"blackbox [on|off] output abstract views as black-box entries",
"renumber [on|off] on = number instances X1, X2, etc.\n"
@@ -1371,10 +1372,11 @@ subcktVisit(use, hierName, is_top)
EFNode *snode;
Def *def = use->use_def;
EFNodeName *nodeName;
- int portorder, portmax, imp_max, tchars;
+ int portorder, portmax, portidx, imp_max, tchars;
char stmp[MAX_STR_SIZE];
char *instname, *subcktname;
DevParam *plist, *pptr;
+ EFNodeName **nodeList;
if (is_top == TRUE) return 0; /* Ignore the top-level cell */
@@ -1466,35 +1468,54 @@ subcktVisit(use, hierName, is_top)
/* Port numbers need not start at zero or be contiguous. */
/* They will be printed in numerical order. */
- portorder = 0;
- while (portorder <= portmax)
- {
- for (snode = (EFNode *) def->def_firstn.efnode_next;
+ nodeList = (EFNodeName **)mallocMagic((portmax + 1) * sizeof(EFNodeName *));
+ for (portidx = 0; portidx <= portmax; portidx++)
+ nodeList[portidx] = (EFNodeName *)NULL;
+
+ for (snode = (EFNode *) def->def_firstn.efnode_next;
snode != &def->def_firstn;
snode = (EFNode *) snode->efnode_next)
- {
- if (!(snode->efnode_flags & EF_PORT)) continue;
- for (nodeName = snode->efnode_name; nodeName != NULL;
+ {
+ if (!(snode->efnode_flags & EF_PORT)) continue;
+ for (nodeName = snode->efnode_name; nodeName != NULL;
nodeName = nodeName->efnn_next)
+ {
+ EFNodeName *nn;
+ HashEntry *he;
+ char *pname;
+
+ portidx = nodeName->efnn_port;
+ if (portidx < 0) continue;
+ if (nodeList[portidx] == NULL)
{
- int portidx = nodeName->efnn_port;
- if (portidx == portorder)
- {
- if (tchars > 80)
- {
- fprintf(esSpiceF, "\n+");
- tchars = 1;
- }
- tchars += spcdevOutNode(hierName, nodeName->efnn_hier,
- "subcircuit", esSpiceF);
- break;
- }
+ nodeList[portidx] = nodeName;
+ }
+ else if (EFHNBest(nodeName->efnn_hier, nodeList[portidx]->efnn_hier))
+ {
+ nodeList[portidx] = nodeName;
}
- if (nodeName != NULL) break;
}
- portorder++;
}
+ for (portidx = 0; portidx <= portmax; portidx++)
+ {
+ nodeName = nodeList[portidx];
+
+ if (nodeName == NULL)
+ TxError("No port connection on port %d; need to resolve.\n", portidx);
+ else
+ {
+ if (tchars > 80)
+ {
+ fprintf(esSpiceF, "\n+");
+ tchars = 1;
+ }
+ tchars += spcdevOutNode(hierName, nodeName->efnn_hier,
+ "subcircuit", esSpiceF);
+ }
+ }
+ freeMagic(nodeList);
+
/* Look for all implicit substrate connections that are */
/* declared as local node names, and put them last. */
@@ -1614,7 +1635,7 @@ topVisit(def, doStub)
Def *def;
bool doStub;
{
- EFNode *snode;
+ EFNode *snode, *basenode;
EFNodeName *sname, *nodeName;
HashSearch hs;
HashEntry *he;
@@ -1667,7 +1688,9 @@ topVisit(def, doStub)
snode = sname->efnn_node;
if (snode->efnode_flags & EF_PORT)
- if (snode->efnode_name->efnn_port < 0)
+ {
+ pname = nodeSpiceName(snode->efnode_name->efnn_hier, &basenode);
+ if (basenode->efnode_name->efnn_port < 0)
{
if (tchars > 80)
{
@@ -1675,11 +1698,12 @@ topVisit(def, doStub)
fprintf(esSpiceF, "\n+");
tchars = 1;
}
- pname = nodeSpiceName(snode->efnode_name->efnn_hier);
fprintf(esSpiceF, " %s", pname);
tchars += strlen(pname) + 1;
- snode->efnode_name->efnn_port = portorder++;
+ basenode->efnode_name->efnn_port = portorder++;
}
+ snode->efnode_name->efnn_port = basenode->efnode_name->efnn_port;
+ }
}
}
else
@@ -1713,7 +1737,7 @@ topVisit(def, doStub)
fprintf(esSpiceF, "\n+");
tchars = 1;
}
- pname = nodeSpiceName(snode->efnode_name->efnn_hier);
+ pname = nodeSpiceName(snode->efnode_name->efnn_hier, NULL);
fprintf(esSpiceF, " %s", pname);
tchars += strlen(pname) + 1;
break;
@@ -2095,6 +2119,56 @@ esOutputResistor(dev, hierName, scale, term1, term2, has_model, l, w, dscale)
}
}
+/* Report if device at index n has been deleted due to merging */
+
+bool
+devIsKilled(n)
+ int n;
+{
+ return (esFMult[(n)] <= (float)0.0) ? TRUE : FALSE;
+}
+
+/* Add a dev's multiplier to the table and grow it if necessary */
+
+void
+addDevMult(f)
+ float f;
+{
+ int i;
+ float *op;
+
+ if (esFMult == NULL) {
+ esFMult = (float *) mallocMagic((unsigned) (esFMSize*sizeof(float)));
+ }
+ else if (esFMIndex >= esFMSize)
+ {
+ op = esFMult;
+ esFMSize *= 2;
+ esFMult = (float *)mallocMagic((unsigned)(esFMSize * sizeof(float)));
+ for (i = 0; i < esFMSize / 2; i++) esFMult[i] = op[i];
+ if (op) freeMagic(op);
+ }
+ esFMult[esFMIndex++] = f;
+}
+
+/* Set the multiplier value f of device at index i */
+
+void
+setDevMult(i, f)
+ int i;
+ float f;
+{
+ esFMult[i] = f;
+}
+
+/* Get the multiplier value of the device at the current index esFMIndex */
+
+float
+getCurDevMult()
+{
+ return (esFMult && (esFMIndex > 0)) ? esFMult[esFMIndex-1] : (float)1.0;
+}
+
/*
* ----------------------------------------------------------------------------
*
@@ -2720,7 +2794,8 @@ FILE *outf;
/* Canonical name */
nn = (EFNodeName *) HashGetValue(he);
if (outf)
- fprintf(outf, "%s", nodeSpiceName(nn->efnn_node->efnode_name->efnn_hier));
+ fprintf(outf, "%s", nodeSpiceName(nn->efnn_node->efnode_name->efnn_hier,
+ NULL));
/* Mark node as visited */
if ((nodeClient *)nn->efnn_node->efnode_client == (ClientData)NULL)
@@ -2931,7 +3006,7 @@ spcdevOutNode(prefix, suffix, name, outf)
return 0;
}
nn = (EFNodeName *) HashGetValue(he);
- nname = nodeSpiceName(nn->efnn_node->efnode_name->efnn_hier);
+ nname = nodeSpiceName(nn->efnn_node->efnode_name->efnn_hier, NULL);
fprintf(outf, " %s", nname);
/* Mark node as visited */
@@ -2977,8 +3052,8 @@ spccapVisit(hierName1, hierName2, cap)
if (cap <= EFCapThreshold)
return 0;
- fprintf(esSpiceF, esSpiceCapFormat ,esCapNum++,nodeSpiceName(hierName1),
- nodeSpiceName(hierName2), cap);
+ fprintf(esSpiceF, esSpiceCapFormat ,esCapNum++,nodeSpiceName(hierName1, NULL),
+ nodeSpiceName(hierName2, NULL), cap);
return 0;
}
@@ -3013,8 +3088,8 @@ spcresistVisit(hierName1, hierName2, res)
HierName *hierName2;
float res;
{
- fprintf(esSpiceF, "R%d %s %s %g\n", esResNum++, nodeSpiceName(hierName1),
- nodeSpiceName(hierName2), res / 1000.);
+ fprintf(esSpiceF, "R%d %s %s %g\n", esResNum++, nodeSpiceName(hierName1, NULL),
+ nodeSpiceName(hierName2, NULL), res / 1000.);
return 0;
}
@@ -3049,7 +3124,7 @@ spcsubVisit(node, res, cap, resstr)
if (node->efnode_flags & EF_SUBS_NODE)
{
hierName = (HierName *) node->efnode_name->efnn_hier;
- nsn = nodeSpiceName(hierName);
+ nsn = nodeSpiceName(hierName, NULL);
*resstr = StrDup((char **)NULL, nsn);
return 1;
}
@@ -3099,7 +3174,7 @@ spcnodeVisit(node, res, cap)
if (!isConnected && node->efnode_flags & EF_PORT) isConnected = TRUE;
hierName = (HierName *) node->efnode_name->efnn_hier;
- nsn = nodeSpiceName(hierName);
+ nsn = nodeSpiceName(hierName, NULL);
if (esFormat == SPICE2 || esFormat == HSPICE && strncmp(nsn, "z@", 2)==0 ) {
static char ntmp[MAX_STR_SIZE];
@@ -3144,7 +3219,7 @@ nodeVisitDebug(node, res, cap)
EFAttr *ap;
hierName = (HierName *) node->efnode_name->efnn_hier;
- nsn = nodeSpiceName(hierName);
+ nsn = nodeSpiceName(hierName, NULL);
TxError("** %s (%x)\n", nsn, node);
printf("\t client.name=%s, client.m_w=%p\n",
@@ -3167,23 +3242,27 @@ nodeVisitDebug(node, res, cap)
*
* Side effects:
* Allocates nodeClients for the node.
+ * Returns the node in the "rnode" pointer, if non-NULL.
*
* ----------------------------------------------------------------------------
*/
static char esTempName[MAX_STR_SIZE];
-char *nodeSpiceName(hname)
+char *nodeSpiceName(hname, rnode)
HierName *hname;
+ EFNode **rnode;
{
EFNodeName *nn;
HashEntry *he;
EFNode *node;
+ if (rnode) *rnode = (EFNode *)NULL;
he = EFHNLook(hname, (char *) NULL, "nodeName");
if ( he == NULL )
return "errGnd!";
nn = (EFNodeName *) HashGetValue(he);
node = nn->efnn_node;
+ if (rnode) *rnode = node;
if ( (nodeClient *) (node->efnode_client) == NULL ) {
initNodeClient(node);
diff --git a/ext2spice/ext2spice.h b/ext2spice/ext2spice.h
index 4247d61..065650d 100644
--- a/ext2spice/ext2spice.h
+++ b/ext2spice/ext2spice.h
@@ -36,6 +36,11 @@ extern char *nodeSpiceHierName();
extern devMerge *mkDevMerge();
extern bool extHierSDAttr();
+extern bool devIsKilled();
+extern float getCurDevMult();
+extern void addDevMult();
+extern void setDevMult();
+
/* Options specific to ext2spice */
extern bool esDoExtResis;
extern bool esDoPorts;
@@ -166,7 +171,7 @@ typedef struct {
/*
*---------------------------------------------------------
- * Variables & macros used for merging parallel devs
+ * Variables used for merging parallel devs
* The merging of devs is based on the fact that spcdevVisit
* visits the devs in the same order all the time so the
* value of esFMult[i] keeps the multiplier for the ith dev
@@ -174,31 +179,8 @@ typedef struct {
*/
#define DEV_KILLED ((float) -1.0)
#define FMULT_SIZE (1<<10)
-
-#define devIsKilled(n) ( esFMult[(n)] <=(float)0.0 )
-
#define DEV_KILLED ((float) -1.0)
-
-/* macro to add a dev's multiplier to the table and grow it if necessary */
-#define addDevMult(f) \
-{ \
- if ( esFMult == NULL ) { \
- esFMult = (float *) mallocMagic((unsigned) (esFMSize*sizeof(float))); \
- } else if ( esFMIndex >= esFMSize ) { \
- int i; \
- float *op = esFMult ; \
- esFMult = (float *) mallocMagic((unsigned) ((esFMSize = esFMSize*2)*sizeof(float))); \
- for ( i = 0 ; i < esFMSize/2 ; i++ ) esFMult[i] = op[i]; \
- if (op) freeMagic(op); \
- } \
- esFMult[esFMIndex++] = (float)(f); \
-}
-
-#define setDevMult(i,f) { esFMult[(i)] = (float)(f); }
-
-#define getCurDevMult() ((esFMult && (esFMIndex > 0)) ? esFMult[esFMIndex-1] : (float)1.0)
-
#ifdef MAGIC_WRAPPER
#define atoCap(s) ((EFCapValue)atof(s))
#endif
diff --git a/extflat/Depend b/extflat/Depend
index c2c8968..f4e4058 100644
--- a/extflat/Depend
+++ b/extflat/Depend
@@ -29,8 +29,8 @@ EFvisit.o: EFvisit.c ../utils/magic.h ../utils/geometry.h \
../utils/geofast.h ../utils/hash.h ../utils/malloc.h ../utils/utils.h \
../extflat/extflat.h ../extflat/EFint.h ../extract/extract.h
EFantenna.o: EFantenna.c ../tcltk/tclmagic.h ../utils/magic.h \
- ../utils/geometry.h ../utils/hash.h ../utils/utils.h ../tiles/tile.h \
- ../database/database.h ../windows/windows.h ../textio/textio.h \
- ../dbwind/dbwind.h ../textio/txcommands.h ../extflat/extflat.h \
- ../extract/extract.h ../extract/extractInt.h ../extract/extDebugInt.h \
- ../utils/malloc.h
+ ../utils/geometry.h ../utils/hash.h ../utils/utils.h ../utils/styles.h \
+ ../tiles/tile.h ../database/database.h ../windows/windows.h \
+ ../textio/textio.h ../dbwind/dbwind.h ../textio/txcommands.h \
+ ../extflat/extflat.h ../extract/extract.h ../extract/extractInt.h \
+ ../extract/extDebugInt.h ../utils/malloc.h
diff --git a/extflat/EFantenna.c b/extflat/EFantenna.c
index 4bbbd1c..470edfe 100644
--- a/extflat/EFantenna.c
+++ b/extflat/EFantenna.c
@@ -14,18 +14,20 @@
#include <stdlib.h> /* for atof() */
#include <string.h>
#include <ctype.h>
+#include <math.h> /* for INFINITY */
#include "tcltk/tclmagic.h"
#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/hash.h"
#include "utils/utils.h"
+#include "utils/styles.h"
#include "tiles/tile.h"
#ifdef MAGIC_WRAPPER
#include "database/database.h"
#include "windows/windows.h"
#include "textio/textio.h"
-#include "dbwind/dbwind.h" /* for DBWclientID */
+#include "dbwind/dbwind.h"
#include "textio/txcommands.h"
#endif
#include "extflat/extflat.h"
@@ -70,6 +72,34 @@ typedef struct {
((nodeClientHier *) (node)->efnode_client)->visitMask = (long) 0; \
}
+/* Diagnostic */
+int efGates;
+static int efAntennaDebug = FALSE;
+
+/* The extract file is designed to be independent of the magic database, */
+/* but that means that the device types do not match magic database types. */
+/* A lookup table is needed to cross-reference the device types. */
+
+TileType *EFDeviceTypes;
+
+typedef struct _aas {
+ int *accum; /* Pointer to array of accumulated areas per type */
+ int pNum; /* Plane of check */
+ Rect r; /* Holds any one visited rectangle */
+ CellDef *def; /* CellDef for adding feedback */
+} AntennaAccumStruct;
+
+typedef struct _gdas {
+ int accum; /* Accumulated area of all gates/diff */
+ Rect r; /* Holds any one visited rectangle */
+ CellDef *def; /* CellDef for adding feedback */
+} GateDiffAccumStruct;
+
+typedef struct _ams {
+ int pNum; /* Plane of check */
+ CellDef *def; /* CellDef for adding feedback */
+} AntennaMarkStruct;
+
/*
* ----------------------------------------------------------------------------
@@ -80,16 +110,18 @@ typedef struct {
*/
#define ANTENNACHECK_RUN 0
-#define ANTENNACHECK_HELP 1
+#define ANTENNACHECK_DEBUG 1
+#define ANTENNACHECK_HELP 2
void
CmdAntennaCheck(w, cmd)
MagWindow *w;
TxCommand *cmd;
{
- int i,flatFlags;
+ int i, flatFlags;
char *inName;
FILE *f;
+ TileType t;
int option = ANTENNACHECK_RUN;
int value;
@@ -109,6 +141,7 @@ CmdAntennaCheck(w, cmd)
static char *cmdAntennaCheckOption[] = {
"[run] [options] run antennacheck on current cell\n"
" use \"run -help\" to get standard options",
+ "debug print detailed information about each error",
"help print help information",
NULL
};
@@ -125,6 +158,9 @@ CmdAntennaCheck(w, cmd)
case ANTENNACHECK_RUN:
goto runantennacheck;
break;
+ case ANTENNACHECK_DEBUG:
+ efAntennaDebug = TRUE;
+ break;
case ANTENNACHECK_HELP:
usage:
for (msg = &(cmdAntennaCheckOption[0]); *msg != NULL; msg++)
@@ -179,6 +215,7 @@ runantennacheck:
*/
/* Read the hierarchical description of the input circuit */
+ TxPrintf("Reading extract file.\n");
if (EFReadFile(inName, FALSE, FALSE, FALSE) == FALSE)
{
EFDone();
@@ -187,13 +224,24 @@ runantennacheck:
/* Convert the hierarchical description to a flat one */
flatFlags = EF_FLATNODES;
+ TxPrintf("Building flattened netlist.\n");
EFFlatBuild(inName, flatFlags);
+ /* Build device lookup table */
+ EFDeviceTypes = (TileType *)mallocMagic(MAXDEVTYPES * sizeof(TileType));
+ for (i = 0; i < MAXDEVTYPES; i++)
+ if (EFDevTypes[i])
+ EFDeviceTypes[i] = extGetDevType(EFDevTypes[i]);
+
+ efGates = 0;
+ TxPrintf("Running antenna checks.\n");
EFVisitDevs(antennacheckVisit, (ClientData)editUse);
EFFlatDone();
EFDone();
TxPrintf("antennacheck finished.\n");
+ freeMagic(EFDeviceTypes);
+ efAntennaDebug = FALSE;
}
@@ -296,28 +344,30 @@ antennacheckVisit(dev, hierName, scale, trans, editUse)
CellUse *editUse; /* ClientData is edit cell use */
{
DevTerm *gate;
+ TileType t, conType;
int pos, pNum, pNum2, pmax, p, i, j, gatearea, diffarea, total;
- double difftotal;
+ double anttotal;
+ float saveRatio;
int *antennaarea;
- Rect r;
+ Rect r, gaterect;
EFNode *gnode;
SearchContext scx;
- TileTypeBitMask gatemask;
+ TileTypeBitMask gatemask, saveConMask;
+ bool antennaError;
extern CellDef *extPathDef; /* see extract/ExtLength.c */
extern CellUse *extPathUse; /* see extract/ExtLength.c */
- extern int areaAccumFunc(), antennaAccumFunc();
+ extern int areaAccumFunc(), antennaAccumFunc(), areaMarkFunc();
antennaarea = (int *)mallocMagic(DBNumTypes * sizeof(int));
- for (i = 0; i < DBNumTypes; i++) antennaarea[i] = 0;
-
switch(dev->dev_class)
{
case DEV_FET:
case DEV_MOSFET:
- GeoTransRect(trans, &dev->dev_rect, &r);
+ case DEV_MSUBCKT:
+ case DEV_ASYMMETRIC:
/* Procedure:
*
@@ -336,16 +386,23 @@ antennacheckVisit(dev, hierName, scale, trans, editUse)
* layer being searched.
*/
+ GeoTransRect(trans, &dev->dev_rect, &r);
gate = &dev->dev_terms[0];
-
gnode = AntennaGetNode(hierName, gate->dterm_node->efnode_name->efnn_hier);
+ if (gnode->efnode_client == (ClientData) NULL)
+ initNodeClient(gnode);
if (beenVisited((nodeClient *)gnode->efnode_client, 0))
return 0;
else
markVisited((nodeClient *)gnode->efnode_client, 0);
+ /* Diagnostic stuff */
+ efGates++;
+ if (efGates % 100 == 0) TxPrintf(" %d gates analyzed.\n", efGates);
+
/* Find the plane of the gate type */
- pNum = DBPlane(dev->dev_type);
+ t = EFDeviceTypes[dev->dev_type];
+ pNum = DBPlane(t);
pos = ExtCurStyle->exts_planeOrder[pNum];
pmax = ++pos;
@@ -354,10 +411,15 @@ antennacheckVisit(dev, hierName, scale, trans, editUse)
if (ExtCurStyle->exts_planeOrder[p] > pmax)
pmax = ExtCurStyle->exts_planeOrder[p];
+ /* Create the yank cell if it doesn't already exist */
+ if (extPathDef == (CellDef *) NULL)
+ DBNewYank("__PATHYANK__", &extPathUse, &extPathDef);
+
/* Use the cellDef reserved for extraction */
- DBCellClearDef(extPathDef);
+ /* DBCellClearDef(extPathDef); */ /* See below */
scx.scx_use = editUse;
scx.scx_trans = GeoIdentityTransform;
+ scx.scx_area = r;
/* gatemask is a mask of all gate types for MOSFET devices */
@@ -387,80 +449,227 @@ antennacheckVisit(dev, hierName, scale, trans, editUse)
for (; pos <= pmax; pos++)
{
+ GateDiffAccumStruct gdas;
+ AntennaAccumStruct aas;
+ AntennaMarkStruct ams;
+
+ /* Find the plane of pos */
+
+ for (p = 0; p < DBNumPlanes; p++)
+ if (ExtCurStyle->exts_planeOrder[p] == pos)
+ pNum2 = p;
+
+ /* Find the tiletype which is a contact and whose base is pNum2 */
+ /* (NOTE: Need to extend to all such contacts, as there may be */
+ /* more than one.) (Also should find these types up top, not */
+ /* within the loop.) */
+
/* Modify DBConnectTbl to limit connectivity to the plane */
/* of the antenna check and below */
- /* To be completed */
+ conType = -1;
+ for (i = 0; i < DBNumTypes; i++)
+ if (DBIsContact(i) && DBPlane(i) == pNum2)
+ {
+ conType = i;
+ TTMaskZero(&saveConMask);
+ TTMaskSetMask(&saveConMask, &DBConnectTbl[i]);
+ TTMaskZero(&DBConnectTbl[i]);
+ for (j = 0; j < DBNumTypes; j++)
+ if (TTMaskHasType(&saveConMask, j) &&
+ (DBPlane(j) <= pNum2))
+ TTMaskSetType(&DBConnectTbl[i], j);
+ break;
+ }
- DBTreeCopyConnect(&scx, &DBConnectTbl[dev->dev_type], 0,
- DBConnectTbl, &TiPlaneRect, extPathUse);
+ for (i = 0; i < DBNumTypes; i++) antennaarea[i] = 0;
+ gatearea = 0;
+ diffarea = 0;
- /* Search plane of gate type and accumulate all (new) gate area */
- DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[pNum],
- &TiPlaneRect, &gatemask, areaAccumFunc, (ClientData)&gatearea);
+ /* Note: Ideally, the addition of material in the next */
+ /* metal plane is additive. But that requires enumerating */
+ /* all the vias and using those as starting points for the */
+ /* next connectivity search, which needs to be coded. */
+
+ DBCellClearDef(extPathDef);
+
+ /* To do: Mark tiles so area count can be progressive */
+
+ DBTreeCopyConnect(&scx, &DBConnectTbl[t], 0,
+ DBConnectTbl, &TiPlaneRect, extPathUse);
- /* Search planes of tie type and accumulate all (new) tiedown areas */
+ /* Search planes of tie types and accumulate all tiedown areas */
+ gdas.accum = 0;
for (p = 0; p < DBNumPlanes; p++)
DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[p],
&TiPlaneRect, &ExtCurStyle->exts_antennaTieTypes,
- areaAccumFunc, (ClientData)&diffarea);
+ areaAccumFunc, (ClientData)&gdas);
+ diffarea = gdas.accum;
+
+ /* Search plane of gate type and accumulate all gate area */
+ gdas.accum = 0;
+ DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[pNum],
+ &TiPlaneRect, &gatemask, areaAccumFunc, (ClientData)&gdas);
+ gatearea = gdas.accum;
- /* Search metal planes and accumulate all (new) antenna areas */
+ /* Search metal planes and accumulate all antenna areas */
for (p = 0; p < DBNumPlanes; p++)
{
- if (ExtCurStyle->exts_planeOrder[p] == pos)
- {
- pNum2 = p;
- }
+ if (ExtCurStyle->exts_antennaModel & ANTENNAMODEL_PARTIAL)
+ if (p != pNum2) continue;
+
+ aas.pNum = p;
+ aas.accum = &antennaarea[0];
if (ExtCurStyle->exts_planeOrder[p] <= pos)
DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[p],
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
- antennaAccumFunc, (ClientData)&antennaarea);
+ antennaAccumFunc, (ClientData)&aas);
}
- /* To be elaborated. . . this encodes only one of several */
- /* methods of calculating antenna violations. */
-
+ antennaError = FALSE;
if (diffarea == 0)
{
- difftotal = 0.0;
+ anttotal = 0.0;
+ saveRatio = 0.0;
+ for (i = 0; i < DBNumTypes; i++)
+ {
+ if (ExtCurStyle->exts_antennaRatio[i].ratioGate > 0)
+ {
+ anttotal += (double)antennaarea[i] /
+ (double)ExtCurStyle->exts_antennaRatio[i].ratioGate;
+ }
+ if (ExtCurStyle->exts_antennaRatio[i].ratioGate > saveRatio)
+ saveRatio = ExtCurStyle->exts_antennaRatio[i].ratioGate;
+ }
+
+ if (anttotal > (double)gatearea)
+ {
+ antennaError = TRUE;
+ if (efAntennaDebug == TRUE)
+ {
+ TxError("Antenna violation detected at plane %s\n",
+ DBPlaneLongNameTbl[pNum2]);
+ TxError("Effective antenna ratio %g > limit %g\n",
+ saveRatio * (float)anttotal / (float)gatearea,
+ saveRatio);
+ TxError("Gate rect (%d %d) to (%d %d)\n",
+ gdas.r.r_xbot, gdas.r.r_ybot,
+ gdas.r.r_xtop, gdas.r.r_ytop);
+ TxError("Antenna rect (%d %d) to (%d %d)\n",
+ aas.r.r_xbot, aas.r.r_ybot,
+ aas.r.r_xtop, aas.r.r_ytop);
+ }
+ }
+ }
+ else
+ {
+ anttotal = 0.0;
+ saveRatio = 0.0;
for (i = 0; i < DBNumTypes; i++)
- difftotal += antennaarea[i] / ExtCurStyle->exts_antennaRatio[i];
+ if (ExtCurStyle->exts_antennaRatio[i].ratioDiff != INFINITY)
+ {
+ if (ExtCurStyle->exts_antennaRatio[i].ratioDiff > 0)
+ anttotal += (double)antennaarea[i] /
+ (double)ExtCurStyle->exts_antennaRatio[i].ratioDiff;
+ if (ExtCurStyle->exts_antennaRatio[i].ratioDiff > saveRatio)
+ saveRatio = ExtCurStyle->exts_antennaRatio[i].ratioDiff;
+ }
+
+ if (anttotal > (double)gatearea)
+ {
+ antennaError = TRUE;
+ if (efAntennaDebug == TRUE)
+ {
+ TxError("Antenna violation detected at plane %s\n",
+ DBPlaneLongNameTbl[pNum2]);
+ TxError("Effective antenna ratio %g > limit %g\n",
+ saveRatio * (float)anttotal / (float)gatearea,
+ saveRatio);
+ TxError("Gate rect (%d %d) to (%d %d)\n",
+ gdas.r.r_xbot, gdas.r.r_ybot,
+ gdas.r.r_xtop, gdas.r.r_ytop);
+ TxError("Antenna rect (%d %d) to (%d %d)\n",
+ aas.r.r_xbot, aas.r.r_ybot,
+ aas.r.r_xtop, aas.r.r_ytop);
+ }
+ }
+ }
+
+ if (antennaError)
+ {
+ /* Search plane of gate type and mark all gate areas */
+ ams.def = editUse->cu_def;
+ ams.pNum = pNum2;
+ DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[pNum],
+ &TiPlaneRect, &gatemask, areaMarkFunc, (ClientData)&ams);
+
+ /* Search metal planes and accumulate all antenna areas */
+ for (p = 0; p < DBNumPlanes; p++)
+ {
+ if (ExtCurStyle->exts_antennaModel & ANTENNAMODEL_PARTIAL)
+ if (p != pNum2) continue;
- if (difftotal > gatearea)
- TxError("Antenna violation detected at plane %s "
- "(violation to be elaborated)",
- DBPlaneLongNameTbl[pNum2]);
+ if (ExtCurStyle->exts_planeOrder[p] <= pos)
+ DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[p],
+ &TiPlaneRect, &DBAllButSpaceAndDRCBits,
+ areaMarkFunc, (ClientData)&ams);
+ }
}
+
+ /* Put the connect table back the way it was */
+ if (conType >= 0)
+ TTMaskSetMask(&DBConnectTbl[conType], &saveConMask);
}
}
+ freeMagic(antennaarea);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
- * areaAccumFunc --
+ * areaMarkFunc --
*
- * Accumulate the total tile area searched
+ * Mark the tile areas searched with feedback entries
*
* ----------------------------------------------------------------------------
*/
int
-areaAccumFunc(tile, totalarea)
+areaMarkFunc(tile, ams)
Tile *tile;
- int *totalarea;
+ AntennaMarkStruct *ams;
{
Rect rect;
- int area;
+ char msg[200];
TiToRect(tile, &rect);
+ sprintf(msg, "Antenna error at plane %s\n", DBPlaneLongNameTbl[ams->pNum]);
+ DBWFeedbackAdd(&rect, msg, ams->def, 1, STYLE_PALEHIGHLIGHTS);
+ return 0;
+}
- area += (rect.r_xtop - rect.r_xbot) * (rect.r_ytop - rect.r_ybot);
+/*
+ * ----------------------------------------------------------------------------
+ *
+ * areaAccumFunc --
+ *
+ * Accumulate the total tile area searched
+ *
+ * ----------------------------------------------------------------------------
+ */
- *totalarea += area;
+int
+areaAccumFunc(tile, gdas)
+ Tile *tile;
+ GateDiffAccumStruct *gdas;
+{
+ Rect *rect = &(gdas->r);
+ int area, type;
+ TiToRect(tile, rect);
+ area = (rect->r_xtop - rect->r_xbot) * (rect->r_ytop - rect->r_ybot);
+ gdas->accum += area;
return 0;
}
@@ -470,27 +679,164 @@ areaAccumFunc(tile, totalarea)
* antennaAccumFunc --
*
* Accumulate the total tile area searched, keeping an individual
- * count for each tile type.
+ * count for each tile type. If the antenna model is SIDEWALL, then
+ * calculate the area of the tile sidewall (tile perimeter * layer
+ * thickness), rather than the drawn tile area.
*
* ----------------------------------------------------------------------------
*/
int
-antennaAccumFunc(tile, typeareas)
+antennaAccumFunc(tile, aaptr)
Tile *tile;
- int **typeareas;
+ AntennaAccumStruct *aaptr;
{
- Rect rect;
+ Rect *rect = &(aaptr->r);
int area;
int type;
+ int *typeareas = aaptr->accum;
+ int plane = aaptr->pNum;
+ float thick;
type = TiGetType(tile);
- TiToRect(tile, &rect);
+ TiToRect(tile, rect);
+
+ if (ExtCurStyle->exts_antennaModel & ANTENNAMODEL_SIDEWALL)
+ {
+ /* Accumulate perimeter of tile where tile abuts space */
+
+ Tile *tp;
+ int perimeter = 0, pmax, pmin;
+
+ /* Top */
+ for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
+ {
+ if (TiGetBottomType(tp) == TT_SPACE)
+ {
+ pmin = MAX(LEFT(tile), LEFT(tp));
+ pmax = MIN(RIGHT(tile), RIGHT(tp));
+ perimeter += (pmax - pmin);
+ }
+ }
+ /* Bottom */
+ for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
+ {
+ if (TiGetTopType(tp) == TT_SPACE)
+ {
+ pmin = MAX(LEFT(tile), LEFT(tp));
+ pmax = MIN(RIGHT(tile), RIGHT(tp));
+ perimeter += (pmax - pmin);
+ }
+ }
+ /* Left */
+ for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
+ {
+ if (TiGetRightType(tp) == TT_SPACE)
+ {
+ pmin = MAX(BOTTOM(tile), BOTTOM(tp));
+ pmax = MIN(TOP(tile), TOP(tp));
+ perimeter += (pmax - pmin);
+ }
+ }
+ /* Right */
+ for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
+ {
+ if (TiGetLeftType(tp) == TT_SPACE)
+ {
+ pmin = MAX(BOTTOM(tile), BOTTOM(tp));
+ pmax = MIN(TOP(tile), TOP(tp));
+ perimeter += (pmax - pmin);
+ }
+ }
+
+ if (DBIsContact(type))
+ {
+ int cperim;
+ TileType ttype;
+ TileTypeBitMask sMask;
+ float thick;
+
+ cperim = ((rect->r_xtop - rect->r_xbot) + (rect->r_ytop - rect->r_ybot)) << 1;
+
+ /* For contacts, add the area of the perimeter to the */
+ /* residue (metal) type on the plane being searched. */
+ /* Then, if the plane is the same as the base type of */
+ /* the contact, add the entire perimeter area of the */
+ /* tile to the total for the contact type itself. */
+
+ DBFullResidueMask(type, &sMask);
+ for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
+ if (TTMaskHasType(&sMask, ttype))
+ if (DBTypeOnPlane(ttype, plane))
+ {
+ thick = ExtCurStyle->exts_thick[ttype];
+ typeareas[ttype] += (int)((float)perimeter * thick);
+ }
+
+ if (type >= DBNumUserLayers)
+ {
+ DBResidueMask(type, &sMask);
+ for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
+ if (TTMaskHasType(&sMask, ttype))
+ if (DBTypeOnPlane(ttype, plane))
+ {
+ thick = ExtCurStyle->exts_thick[ttype];
+ typeareas[ttype] += (int)((float)perimeter * thick);
+ break;
+ }
+ }
+ else
+ {
+ thick = ExtCurStyle->exts_thick[type];
+ typeareas[type] += (int)((float)perimeter * thick);
+ }
+ }
+ else
+ {
+ /* Area is perimeter times layer thickness */
+ thick = ExtCurStyle->exts_thick[type];
+ typeareas[type] += (int)((float)perimeter * thick);
+ }
+ }
+ else
+ {
+ /* Simple tile area calculation */
+ area = (rect->r_xtop - rect->r_xbot) * (rect->r_ytop - rect->r_ybot);
+
+ /* If type is a contact, then add area to both residues as well */
+ /* as the contact type. */
+
+ /* NOTE: Restrict area counts per plane so areas of contacts */
+ /* are not double-counted. */
- area += (rect.r_xtop - rect.r_xbot) * (rect.r_ytop - rect.r_ybot);
+ if (DBIsContact(type))
+ {
+ TileType ttype;
+ TileTypeBitMask sMask;
- *typeareas[type] += area;
+ DBFullResidueMask(type, &sMask);
+ for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
+ if (TTMaskHasType(&sMask, ttype))
+ if (DBTypeOnPlane(ttype, plane))
+ typeareas[ttype] += area;
+ if (type >= DBNumUserLayers)
+ {
+ DBResidueMask(type, &sMask);
+ for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
+ if (TTMaskHasType(&sMask, ttype))
+ if (DBTypeOnPlane(ttype, plane))
+ {
+ typeareas[ttype] += area;
+ break;
+ }
+ }
+ else
+ typeareas[type] += area;
+ }
+ else
+ typeareas[type] += area;
+ }
return 0;
}
diff --git a/extflat/EFbuild.c b/extflat/EFbuild.c
index dd2c700..6999f1a 100644
--- a/extflat/EFbuild.c
+++ b/extflat/EFbuild.c
@@ -591,23 +591,28 @@ efBuildDevice(def, class, type, r, argc, argv)
Rect *r; /* Coordinates of 1x1 rectangle entirely inside device */
int argc; /* Size of argv */
char *argv[]; /* Tokens for the rest of the dev line.
- * The first depend on the type of device. The rest
- * are taken in groups of 3, one for each terminal.
- * Each group of 3 consists of the node name to which
- * the terminal connects, the length of the terminal,
- * and an attribute list (or the token 0).
+ * Starts with the last two position values, used to
+ * hash the device record. The next arguments depend
+ * on the type of device. The rest are taken in groups
+ * of 3, one for each terminal. Each group of 3 consists
+ * of the node name to which the terminal connects, the
+ * length of the terminal, and an attribute list (or the
+ * token 0).
*/
{
int n, nterminals, pn;
+ HashEntry *he;
DevTerm *term;
Dev *newdev, devtmp;
DevParam *newparm, *devp, *sparm;
char ptype, *pptr, **av;
+ char devhash[24];
int argstart = 1; /* start of terminal list in argv[] */
bool hasModel = strcmp(type, "None") ? TRUE : FALSE;
int area, perim; /* Total area, perimeter of primary type (i.e., channel) */
+ newdev = (Dev *)NULL;
devtmp.dev_subsnode = NULL;
devtmp.dev_cap = 0.0;
devtmp.dev_res = 0.0;
@@ -713,7 +718,6 @@ efBuildDevice(def, class, type, r, argc, argv)
}
/* Check for optional substrate node */
-
switch (class)
{
case DEV_RES:
@@ -743,93 +747,149 @@ efBuildDevice(def, class, type, r, argc, argv)
nterminals = (argc - argstart) / 3;
- newdev = (Dev *) mallocMagic((unsigned) DevSize(nterminals));
- newdev->dev_subsnode = devtmp.dev_subsnode;
- newdev->dev_cap = devtmp.dev_cap;
- newdev->dev_res = devtmp.dev_res;
- newdev->dev_area = devtmp.dev_area;
- newdev->dev_perim = devtmp.dev_perim;
- newdev->dev_length = devtmp.dev_length;
- newdev->dev_width = devtmp.dev_width;
- newdev->dev_params = devtmp.dev_params;
-
- newdev->dev_nterm = nterminals;
- newdev->dev_rect = *r;
- newdev->dev_type = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, type);
- newdev->dev_class = class;
+ /* Determine if this device has been seen before */
+
+ sprintf(devhash, "%dx%d", r->r_xbot, r->r_ybot);
+ he = HashFind(&def->def_devs, devhash);
+ newdev = (Dev *)HashGetValue(he);
+ if (newdev)
+ {
+ /* Duplicate device. Duplicates will only appear in res.ext files
+ * where a device has nodes changed. Merge all properties of the
+ * original device with nodes from the new device. Keep the
+ * original device and discard the new one.
+ *
+ * Check that the device is actually the same device type and number
+ * of terminals. If not, throw an error and abandon the new device.
+ */
+
+ if ((newdev->dev_class != class) ||
+ (strcmp(EFDevTypes[newdev->dev_type], type)))
+ {
+ TxError("Device %s %s at (%d, %d) overlaps incompatible device %s %s!\n",
+ extDevTable[class], type, r->r_xbot, r->r_ybot,
+ extDevTable[newdev->dev_class], EFDevTypes[newdev->dev_type]);
+ return 0;
+ }
+ else if (newdev->dev_nterm != nterminals)
+ {
+ TxError("Device %s %s at (%d, %d) overlaps device with incompatible"
+ " number of terminals (%d vs. %d)!\n",
+ extDevTable[class], type, r->r_xbot, r->r_ybot, nterminals,
+ newdev->dev_nterm);
+ return 0;
+ }
+ }
+ else
+ {
+ newdev = (Dev *) mallocMagic((unsigned) DevSize(nterminals));
+
+ /* Add this dev to the hash table for def */
+ HashSetValue(he, (ClientData)newdev);
+
+ newdev->dev_cap = devtmp.dev_cap;
+ newdev->dev_res = devtmp.dev_res;
+ newdev->dev_area = devtmp.dev_area;
+ newdev->dev_perim = devtmp.dev_perim;
+ newdev->dev_length = devtmp.dev_length;
+ newdev->dev_width = devtmp.dev_width;
+ newdev->dev_params = devtmp.dev_params;
+
+ newdev->dev_nterm = nterminals;
+ newdev->dev_rect = *r;
+ newdev->dev_type = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, type);
+ newdev->dev_class = class;
+ switch (class)
+ {
+ case DEV_FET: /* old-style "fet" record */
+ newdev->dev_area = atoi(argv[0]);
+ newdev->dev_perim = atoi(argv[1]);
+ break;
+ case DEV_MOSFET: /* new-style "device mosfet" record */
+ case DEV_ASYMMETRIC:
+ case DEV_BJT:
+ newdev->dev_length = atoi(argv[0]);
+ newdev->dev_width = atoi(argv[1]);
+ break;
+ case DEV_RES:
+ if (hasModel && StrIsInt(argv[0]) && StrIsInt(argv[1]))
+ {
+ newdev->dev_length = atoi(argv[0]);
+ newdev->dev_width = atoi(argv[1]);
+ }
+ else if (StrIsNumeric(argv[0]))
+ {
+ newdev->dev_res = (float)atof(argv[0]);
+ }
+ else
+ {
+ if (hasModel)
+ {
+ efReadError("Error: expected L and W, got %s %s\n", argv[0],
+ argv[1]);
+ newdev->dev_length = 0;
+ newdev->dev_width = 0;
+ }
+ else
+ {
+ efReadError("Error: expected resistance value, got %s\n",
+ argv[0]);
+ newdev->dev_res = 0.0;
+ }
+ }
+ break;
+ case DEV_CAP:
+ case DEV_CAPREV:
+ if (hasModel && StrIsInt(argv[0]) && StrIsInt(argv[1]))
+ {
+ newdev->dev_length = atoi(argv[0]);
+ newdev->dev_width = atoi(argv[1]);
+ }
+ else if (StrIsNumeric(argv[0]))
+ {
+ newdev->dev_cap = (float)atof(argv[0]);
+ }
+ else
+ {
+ if (hasModel)
+ {
+ efReadError("Error: expected L and W, got %s %s\n", argv[0],
+ argv[1]);
+ newdev->dev_length = 0;
+ newdev->dev_width = 0;
+ }
+ else
+ {
+ efReadError("Error: expected capacitance value, got %s\n",
+ argv[0]);
+ newdev->dev_cap = 0.0;
+ }
+ }
+ break;
+ }
+ }
+
+ newdev->dev_subsnode = devtmp.dev_subsnode;
switch (class)
{
case DEV_FET: /* old-style "fet" record */
- newdev->dev_area = atoi(argv[0]);
- newdev->dev_perim = atoi(argv[1]);
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
break;
case DEV_MOSFET: /* new-style "device mosfet" record */
case DEV_ASYMMETRIC:
case DEV_BJT:
- newdev->dev_length = atoi(argv[0]);
- newdev->dev_width = atoi(argv[1]);
-
/* "None" in the place of the substrate name means substrate is ignored */
if ((argstart == 3) && (strncmp(argv[2], "None", 4) != 0))
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
break;
case DEV_RES:
- if (hasModel && StrIsInt(argv[0]) && StrIsInt(argv[1]))
- {
- newdev->dev_length = atoi(argv[0]);
- newdev->dev_width = atoi(argv[1]);
- }
- else if (StrIsNumeric(argv[0]))
- {
- newdev->dev_res = (float)atof(argv[0]);
- }
- else
- {
- if (hasModel)
- {
- efReadError("Error: expected L and W, got %s %s\n", argv[0],
- argv[1]);
- newdev->dev_length = 0;
- newdev->dev_width = 0;
- }
- else
- {
- efReadError("Error: expected resistance value, got %s\n", argv[0]);
- newdev->dev_res = 0.0;
- }
- }
if ((argstart == 3) && (strncmp(argv[2], "None", 4) != 0))
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
break;
case DEV_CAP:
case DEV_CAPREV:
- if (hasModel && StrIsInt(argv[0]) && StrIsInt(argv[1]))
- {
- newdev->dev_length = atoi(argv[0]);
- newdev->dev_width = atoi(argv[1]);
- }
- else if (StrIsNumeric(argv[0]))
- {
- newdev->dev_cap = (float)atof(argv[0]);
- }
- else
- {
- if (hasModel)
- {
- efReadError("Error: expected L and W, got %s %s\n", argv[0],
- argv[1]);
- newdev->dev_length = 0;
- newdev->dev_width = 0;
- }
- else
- {
- efReadError("Error: expected capacitance value, got %s\n", argv[0]);
- newdev->dev_cap = 0.0;
- }
- }
if ((argstart == 3) && (strncmp(argv[2], "None", 4) != 0))
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
@@ -859,10 +919,6 @@ efBuildDevice(def, class, type, r, argc, argv)
#undef TERM_PERIM
#undef TERM_ATTRS
- /* Add this dev to the list for def */
- newdev->dev_next = def->def_devs;
- def->def_devs = newdev;
-
return 0;
}
@@ -1696,6 +1752,36 @@ efFreeUseTable(table)
}
}
+/*
+ * ----------------------------------------------------------------------------
+ *
+ * efFreeDevTable --
+ *
+ * Free the device records allocated for each entry in the device hash table,
+ * the memory allocated by the device, leaving the hash entry null.
+ *
+ * ----------------------------------------------------------------------------
+ */
+
+void
+efFreeDevTable(table)
+ HashTable *table;
+{
+ Dev *dev;
+ HashSearch hs;
+ HashEntry *he;
+ int n;
+
+ HashStartSearch(&hs);
+ while (he = HashNext(table, &hs))
+ {
+ dev = (Dev *)HashGetValue(he);
+ for (n = 0; n < (int)dev->dev_nterm; n++)
+ if (dev->dev_terms[n].dterm_attrs)
+ freeMagic((char *) dev->dev_terms[n].dterm_attrs);
+ freeMagic((char *) dev);
+ }
+}
/*
* ----------------------------------------------------------------------------
diff --git a/extflat/EFdef.c b/extflat/EFdef.c
index 0ef549f..e0b7c30 100644
--- a/extflat/EFdef.c
+++ b/extflat/EFdef.c
@@ -103,7 +103,6 @@ EFDone()
Kill *kill;
Def *def;
Use *use;
- Dev *dev;
int n;
HashStartSearch(&hs);
@@ -114,22 +113,18 @@ EFDone()
efFreeNodeTable(&def->def_nodes);
efFreeNodeList(&def->def_firstn);
efFreeUseTable(&def->def_uses);
+ efFreeDevTable(&def->def_devs);
HashKill(&def->def_nodes);
HashKill(&def->def_dists);
HashKill(&def->def_uses);
+ HashKill(&def->def_devs);
for (conn = def->def_conns; conn; conn = conn->conn_next)
efFreeConn(conn);
for (conn = def->def_caps; conn; conn = conn->conn_next)
efFreeConn(conn);
for (conn = def->def_resistors; conn; conn = conn->conn_next)
efFreeConn(conn);
- for (dev = def->def_devs; dev; dev = dev->dev_next)
- {
- for (n = 0; n < (int)dev->dev_nterm; n++)
- if (dev->dev_terms[n].dterm_attrs)
- freeMagic((char *) dev->dev_terms[n].dterm_attrs);
- freeMagic((char *) dev);
- }
+
for (kill = def->def_kills; kill; kill = kill->kill_next)
{
freeMagic(kill->kill_name);
@@ -151,13 +146,6 @@ EFDone()
EFTech = (char *)NULL;
}
- /* Free up all HierNames that were stored in efFreeHashTable */
-/*
- HashStartSearch(&hs);
- while (he = HashNext(&efFreeHashTable, &hs))
- freeMagic(he->h_key.h_ptr);
-*/
-
/* Free up the parameter name tables for each device */
HashStartSearch(&hs);
@@ -244,7 +232,6 @@ efDefNew(name)
newdef->def_conns = (Connection *) NULL;
newdef->def_caps = (Connection *) NULL;
newdef->def_resistors = (Connection *) NULL;
- newdef->def_devs = (Dev *) NULL;
newdef->def_kills = (Kill *) NULL;
/* Initialize circular list of nodes */
@@ -257,6 +244,9 @@ efDefNew(name)
/* Initialize hash table of node names */
HashInit(&newdef->def_nodes, INITNODESIZE, HT_STRINGKEYS);
+ /* Initialize hash table of devices */
+ HashInit(&newdef->def_devs, INITNODESIZE, HT_STRINGKEYS);
+
/* Initialize hash table of distances */
HashInitClient(&newdef->def_dists, INITNODESIZE, HT_CLIENTKEYS,
efHNDistCompare, efHNDistCopy, efHNDistHash, efHNDistKill);
diff --git a/extflat/EFflat.c b/extflat/EFflat.c
index 9725def..bd02d9c 100644
--- a/extflat/EFflat.c
+++ b/extflat/EFflat.c
@@ -205,7 +205,7 @@ EFFlatBuildOneLevel(def, flags)
if (usecount > 0)
efHierSrUses(&efFlatContext, efFlatNodesDeviceless, (ClientData)&usecount);
- if ((usecount == 0) && (efFlatRootUse.use_def->def_devs == NULL))
+ if ((usecount == 0) && (HashGetNumEntries(&efFlatRootUse.use_def->def_devs) == 0))
efFlatRootUse.use_def->def_flags |= DEF_NODEVICES;
/* Record all local nodes */
@@ -372,7 +372,7 @@ efFlatNodesDeviceless(hc, cdata)
if (newcount > 0)
efHierSrUses(hc, efFlatNodesDeviceless, (ClientData)&newcount);
- if ((hc->hc_use->use_def->def_devs == NULL) && (newcount == 0))
+ if ((HashGetNumEntries(&hc->hc_use->use_def->def_devs) == 0) && (newcount == 0))
{
/* Add all our own nodes to the table */
efAddNodes(hc, TRUE);
@@ -527,6 +527,7 @@ efAddNodes(hc, stdcell)
HashSetValue(he, (char *) newname);
newname->efnn_node = newnode;
newname->efnn_hier = hierName;
+ newname->efnn_port = -1;
if (newnode->efnode_name)
{
newname->efnn_next = newnode->efnode_name->efnn_next;
@@ -1018,14 +1019,23 @@ efFlatSingleCap(hc, name1, name2, conn)
EFNode *n1, *n2;
HashEntry *he;
EFCoupleKey ck;
+ static char msg0[] = "cap(1)";
+ static char msg1[] = "cap(2)";
+ char *msg;
+
+ /* Connections that are below threshold (ext2spice hierarchy only) */
+ /* will be missing. Do not generate errors for these. */
- if ((he = EFHNLook(hc->hc_hierName, name1, "cap(1)")) == NULL)
+ msg = (fabs((double)conn->conn_cap / 1000) < EFCapThreshold) ? NULL : msg0;
+
+ if ((he = EFHNLook(hc->hc_hierName, name1, msg)) == NULL)
return 0;
n1 = ((EFNodeName *) HashGetValue(he))->efnn_node;
if (n1->efnode_flags & EF_KILLED)
return 0;
- if ((he = EFHNLook(hc->hc_hierName, name2, "cap(2)")) == NULL)
+ if (msg) msg = msg1;
+ if ((he = EFHNLook(hc->hc_hierName, name2, msg)) == NULL)
return 0;
n2 = ((EFNodeName *) HashGetValue(he))->efnn_node;
if (n2->efnode_flags & EF_KILLED)
diff --git a/extflat/EFhier.c b/extflat/EFhier.c
index 2b38443..cef6bd5 100644
--- a/extflat/EFhier.c
+++ b/extflat/EFhier.c
@@ -471,6 +471,8 @@ efHierVisitDevs(hc, ca)
{
Def *def = hc->hc_use->use_def;
Dev *dev;
+ HashSearch hs;
+ HashEntry *he;
float scale;
/*
@@ -482,8 +484,10 @@ efHierVisitDevs(hc, ca)
scale = (efScaleChanged && def->def_scale != 1.0) ? def->def_scale : 1.0;
/* Visit all devices */
- for (dev = def->def_devs; dev; dev = dev->dev_next)
+ HashStartSearch(&hs);
+ while (he = HashNext(&def->def_devs, &hs))
{
+ dev = (Dev *)HashGetValue(he);
if (efHierDevKilled(hc, dev, hc->hc_hierName))
continue;
diff --git a/extflat/EFint.h b/extflat/EFint.h
index 9c38052..a9cbf2c 100644
--- a/extflat/EFint.h
+++ b/extflat/EFint.h
@@ -156,6 +156,7 @@ typedef struct def
HashTable def_nodes; /* Map names into EFNodeNames */
HashTable def_dists; /* Map pairs of names into Distances */
HashTable def_uses; /* Hash children of this def by name */
+ HashTable def_devs; /* Devices (hash by position) */
EFNode def_firstn; /* Head of circular list of nodes */
/* The following are all NULL-terminated lists */
@@ -163,7 +164,6 @@ typedef struct def
Connection *def_conns; /* Hierarchical connections/adjustments */
Connection *def_caps; /* Two-terminal capacitors */
Connection *def_resistors; /* Two-terminal resistors */
- Dev *def_devs; /* Devices */
Kill *def_kills; /* Used to modify hierarchical structure
* using information present only in the
* parent, e.g, to kill an old node and
diff --git a/extflat/EFread.c b/extflat/EFread.c
index b57477f..c590129 100644
--- a/extflat/EFread.c
+++ b/extflat/EFread.c
@@ -356,8 +356,7 @@ readfile:
r.r_xtop = atoi(argv[5]);
r.r_ytop = atoi(argv[6]);
- if (efBuildDevice(def, (char)n, argv[2], &r, argc - 7,
- &argv[7]) != 0)
+ if (efBuildDevice(def, (char)n, argv[2], &r, argc - 7, &argv[7]) != 0)
{
efReadError("Incomplete terminal description for device\n");
continue;
diff --git a/extflat/EFvisit.c b/extflat/EFvisit.c
index 8d802ed..35de676 100644
--- a/extflat/EFvisit.c
+++ b/extflat/EFvisit.c
@@ -300,6 +300,8 @@ efVisitDevs(hc, ca)
Dev *dev;
float scale;
Transform t;
+ HashSearch hs;
+ HashEntry *he;
if (def->def_flags & DEF_SUBCIRCUIT) return 0;
@@ -311,15 +313,17 @@ efVisitDevs(hc, ca)
t = hc->hc_trans;
/* Visit our own devices */
- for (dev = def->def_devs; dev; dev = dev->dev_next)
+
+ HashStartSearch(&hs);
+ while (he = HashNext(&def->def_devs, &hs))
{
+ dev = (Dev *)HashGetValue(he);
if (efDevKilled(dev, hc->hc_hierName))
continue;
if ((*ca->ca_proc)(dev, hc->hc_hierName, scale, &t, ca->ca_cdata))
return 1;
}
-
return 0;
}
diff --git a/extract/ExtTech.c b/extract/ExtTech.c
index 94b74c7..96e3d4c 100644
--- a/extract/ExtTech.c
+++ b/extract/ExtTech.c
@@ -71,7 +71,7 @@ typedef enum
AREAC, CONTACT, CSCALE,
DEFAULTAREACAP, DEFAULTOVERLAP, DEFAULTPERIMETER, DEFAULTSIDEOVERLAP,
DEFAULTSIDEWALL,
- DEVICE, FET, FETRESIST, HEIGHT, ANTENNA, TIEDOWN, LAMBDA, OVERC,
+ DEVICE, FET, FETRESIST, HEIGHT, ANTENNA, MODEL, TIEDOWN, LAMBDA, OVERC,
PERIMC, PLANEORDER, NOPLANEORDER, RESIST, RSCALE, SIDEHALO, SIDEOVERLAP,
SIDEWALL, STEP, STYLE, SUBSTRATE, UNITS, VARIANT
} Key;
@@ -122,9 +122,12 @@ static keydesc keyTable[] = {
"height", HEIGHT, 4, 4,
"type height-above-subtrate thickness",
- "antenna", ANTENNA, 3, 3,
+ "antenna", ANTENNA, 4, 4,
"type antenna-ratio",
+ "model", MODEL, 3, 3,
+"partial-cumulative area-sidewall",
+
"tiedown", TIEDOWN, 2, 2,
"types",
@@ -376,6 +379,35 @@ ExtGetDevInfo(idx, devnameptr, sd_rclassptr, sub_rclassptr, subnameptr)
#endif /* MAGIC_WRAPPER */
+/*
+ * ----------------------------------------------------------------------------
+ *
+ * extGetDevType --
+ *
+ * Given an extraction model device name (devname), return the associated
+ * magic tiletype for the device.
+ *
+ * Results:
+ * Tile type that represents the device "devname" in the magic database.
+ *
+ * ----------------------------------------------------------------------------
+ */
+
+TileType
+extGetDevType(devname)
+ char *devname;
+{
+ TileType t;
+ ExtDevice *devptr;
+
+ for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
+ for (devptr = ExtCurStyle->exts_device[t]; devptr; devptr = devptr->exts_next)
+ if (!strcmp(devptr->exts_deviceName, devname))
+ return t;
+
+ return -1;
+}
+
#ifdef THREE_D
/*
@@ -672,7 +704,8 @@ extTechStyleInit(style)
for (r = 0; r < DBNumTypes; r++)
{
- style->exts_antennaRatio[r] = 0;
+ style->exts_antennaRatio[r].ratioGate = 0.0;
+ style->exts_antennaRatio[r].ratioDiff = 0.0;
style->exts_resistByResistClass[r] = 0;
TTMaskZero(&style->exts_typesByResistClass[r]);
style->exts_typesResistChanged[r] = DBAllButSpaceAndDRCBits;
@@ -2321,17 +2354,53 @@ ExtTechLine(sectionName, argc, argv)
if (!StrIsNumeric(argv[2]))
{
- TechError("Layer antenna ratio %s must be numeric\n", argv[2]);
+ TechError("Gate layer antenna ratio %s must be numeric\n", argv[2]);
break;
}
antennaratio = (float)strtod(argv[2], NULL);
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
if (TTMaskHasType(&types1, t))
{
- ExtCurStyle->exts_antennaRatio[t] = antennaratio;
+ ExtCurStyle->exts_antennaRatio[t].ratioGate = antennaratio;
+ }
+
+ if (!StrIsNumeric(argv[3]))
+ {
+ if (!strcasecmp(argv[3], "none"))
+ antennaratio = INFINITY;
+ else
+ {
+ TechError("Diff layer antenna ratio %s must be numeric\n", argv[3]);
+ break;
+ }
+ }
+ else
+ antennaratio = (float)strtod(argv[3], NULL);
+ for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
+ if (TTMaskHasType(&types1, t))
+ {
+ ExtCurStyle->exts_antennaRatio[t].ratioDiff = antennaratio;
}
}
break;
+ case MODEL:
+ if (!strcmp(argv[1], "partial"))
+ ExtCurStyle->exts_antennaModel |= ANTENNAMODEL_PARTIAL;
+ else if (!strcmp(argv[1], "cumulative"))
+ ExtCurStyle->exts_antennaModel |= ANTENNAMODEL_CUMULATIVE;
+ else
+ TxError("Unknown antenna model \"%s\": Use \"partial\" or "
+ "\"cumulative\"");
+
+ if (!strcmp(argv[2], "area"))
+ ExtCurStyle->exts_antennaModel |= ANTENNAMODEL_AREA;
+ else if (!strcmp(argv[2], "sidewall"))
+ ExtCurStyle->exts_antennaModel |= ANTENNAMODEL_SIDEWALL;
+ else
+ TxError("Unknown antenna model \"%s\": Use \"area\" or "
+ "\"sidewall\"");
+ break;
+
case TIEDOWN:
TTMaskSetMask(&ExtCurStyle->exts_antennaTieTypes, &types1);
break;
@@ -2973,6 +3042,10 @@ zinit:
ec = ec->ec_next)
ec->ec_cap *= 0.5;
}
+
+ /* Layer thickness and height are in microns, but are floating-point */
+ style->exts_thick[r] /= dscale;
+ style->exts_height[r] /= dscale;
}
/* side halo and step size are also in microns */
diff --git a/extract/extract.h b/extract/extract.h
index b63c4ac..82e143d 100644
--- a/extract/extract.h
+++ b/extract/extract.h
@@ -76,6 +76,7 @@ extern void ExtSetStyle();
extern void ExtPrintStyle();
extern void ExtCell();
+
#ifdef MAGIC_WRAPPER
extern bool ExtGetDevInfo();
extern bool ExtCompareStyle();
diff --git a/extract/extractInt.h b/extract/extractInt.h
index 44b7f7e..7e9c7a2 100644
--- a/extract/extractInt.h
+++ b/extract/extractInt.h
@@ -48,6 +48,17 @@ typedef int ResValue; /* Warning: in some places resistances are stored
* as ints. This is here for documentation only.
*/
+typedef struct {
+ float ratioGate;
+ float ratioDiff;
+} RatioValues;
+
+/* Antenna models */
+#define ANTENNAMODEL_PARTIAL 0x01
+#define ANTENNAMODEL_CUMULATIVE 0x02
+#define ANTENNAMODEL_AREA 0x04
+#define ANTENNAMODEL_SIDEWALL 0x08
+
/* ------------------------ Parameter lists --------------------------- */
/* These lists keep track of what parameter names subcircuit definitions
@@ -656,8 +667,10 @@ typedef struct extstyle
float exts_height[NT];
float exts_thick[NT];
+ char exts_antennaModel;
+
/* Antenna area ratio for each layer */
- float exts_antennaRatio[NT];
+ RatioValues exts_antennaRatio[NT];
/* Mask of types that tie down antennas */
TileTypeBitMask exts_antennaTieTypes;
@@ -1060,6 +1073,7 @@ extern NodeRegion *extBasic();
extern NodeRegion *extFindNodes();
extern ExtTree *extHierNewOne();
extern int extNbrPushFunc();
+extern TileType extGetDevType();
/* --------------------- Miscellaneous globals ------------------------ */
diff --git a/lef/lefWrite.c b/lef/lefWrite.c
index 30859c1..8e2106c 100644
--- a/lef/lefWrite.c
+++ b/lef/lefWrite.c
@@ -83,6 +83,7 @@ lefFileOpen(def, file, suffix, mode, prealfile)
*/
{
char namebuf[512], *name, *endp, *ends;
+ char *locsuffix;
int len;
FILE *rfile;
@@ -115,14 +116,19 @@ lefFileOpen(def, file, suffix, mode, prealfile)
(void) strncpy(namebuf, name, len);
namebuf[len] = '\0';
name = namebuf;
+ locsuffix = suffix;
}
+ else
+ locsuffix = NULL;
}
+ else
+ locsuffix = suffix;
/* Try once as-is, and if this fails, try stripping any leading */
/* path information in case cell is in a read-only directory (mode */
/* "read" only, and if def is non-NULL). */
- if ((rfile = PaOpen(name, mode, suffix, Path, CellLibPath, prealfile)) != NULL)
+ if ((rfile = PaOpen(name, mode, locsuffix, Path, CellLibPath, prealfile)) != NULL)
return rfile;
if (def)
@@ -634,7 +640,7 @@ lefWriteMacro(def, f, scale, hide)
{
bool propfound;
char *propvalue, *class = NULL;
- Label *lab;
+ Label *lab, *tlab;
Rect boundary, labr;
SearchContext scx;
CellDef *lefFlatDef;
@@ -964,15 +970,21 @@ lefWriteMacro(def, f, scale, hide)
if (maxport >= 0)
{
- /* Sanity check to see if port number is a duplicate */
- for (lab = lab->lab_next; lab != NULL; lab = lab->lab_next)
+ /* Sanity check to see if port number is a duplicate. ONLY */
+ /* flag this if the other index has a different text, as it */
+ /* is perfectly legal to have multiple ports with the same */
+ /* name and index. */
+
+ for (tlab = lab->lab_next; tlab != NULL; tlab = tlab->lab_next)
{
- if (lab->lab_flags & PORT_DIR_MASK)
- if ((lab->lab_flags & PORT_NUM_MASK) == idx)
- {
- TxError("Port index %d is used more than once\n", idx);
- idx--;
- }
+ if (tlab->lab_flags & PORT_DIR_MASK)
+ if ((tlab->lab_flags & PORT_NUM_MASK) == idx)
+ if (strcmp(lab->lab_text, lab->lab_text))
+ {
+ TxError("Index %d is used for ports \"%s\" and \"%s\"\n",
+ idx, lab->lab_text, tlab->lab_text);
+ idx--;
+ }
}
}
else
diff --git a/resis/ResReadSim.c b/resis/ResReadSim.c
index 6d9dad1..4a447aa 100644
--- a/resis/ResReadSim.c
+++ b/resis/ResReadSim.c
@@ -79,7 +79,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
ResSimNode *ResInitializeNode();
ResSimNode *ResOriginalNodes; /*Linked List of Nodes */
-static float lambda=1.0; /* Scale factor */
+static float resscale=1.0; /* Scale factor */
char RDEV_NOATTR[1]={'0'};
ResFixPoint *ResFixList;
@@ -146,12 +146,8 @@ ResReadSim(simfile,fetproc,capproc,resproc,attrproc,mergeproc)
case '|':
if (strcmp(line[NODEUNITS],"units:") == 0)
{
- lambda = (float)atof(line[NODELAMBDA]);
- if (lambda == 0.0) lambda = 1.0;
- /* NOTE: units is derived from EFScale */
- /* which needs a factor of 100 conversion */
- /* to database units. */
- lambda *= 100.0;
+ resscale = (float)atof(line[NODELAMBDA]);
+ if (resscale == 0.0) resscale = 1.0;
}
result=0;
break;
@@ -231,6 +227,14 @@ ResReadNode(nodefile)
HashEntry *entry;
ResSimNode *node;
char *cp;
+ float lambda;
+
+ /* NOTE: Units from the .sim file or the .nodes file are in centimicrons
+ * when multiplied by resscale (units from the .sim file 1st line).
+ * multiply resscale by the extract scale (exts_unitsPerLambda) used to
+ * generate .ext dimensions originally, to get back to database units.
+ */
+ lambda = resscale * (float)ExtCurStyle->exts_unitsPerLambda;
fp = PaOpen(nodefile,"r",".nodes",".", (char *) NULL, (char **) NULL);
if (fp == NULL)
@@ -243,17 +247,13 @@ ResReadNode(nodefile)
entry = HashFind(&ResNodeTable,line[NODENODENAME]);
node = ResInitializeNode(entry);
- /* NOTE: Fixed 10/15/2019. No scalefactor is passed to EFNodeVisit()
- * so there is no scaling by lambda. Values are in centimicrons always,
- * and factor of 100 is required to get database units.
- */
- node->location.p_x = (int)((float)atof(line[NODENODEX]) / 100.0);
- node->location.p_y = (int)((float)atof(line[NODENODEY]) / 100.0);
+ node->location.p_x = (int)((float)atof(line[NODENODEX]) / lambda);
+ node->location.p_y = (int)((float)atof(line[NODENODEY]) / lambda);
#ifdef ARIEL
- node->rs_bbox.r_xbot = (int)((float)atof(line[NODE_BBOX_LL_X]) / 100.0);
- node->rs_bbox.r_ybot = (int)((float)atof(line[NODE_BBOX_LL_Y]) / 100.0);
- node->rs_bbox.r_xtop = (int)((float)atof(line[NODE_BBOX_UR_X]) / 100.0);
- node->rs_bbox.r_ytop = (int)((float)atof(line[NODE_BBOX_UR_Y]) / 100.0);
+ node->rs_bbox.r_xbot = (int)((float)atof(line[NODE_BBOX_LL_X]) / lambda);
+ node->rs_bbox.r_ybot = (int)((float)atof(line[NODE_BBOX_LL_Y]) / lambda);
+ node->rs_bbox.r_xtop = (int)((float)atof(line[NODE_BBOX_UR_X]) / lambda);
+ node->rs_bbox.r_ytop = (int)((float)atof(line[NODE_BBOX_UR_Y]) / lambda);
#endif
if (cp = strchr(line[NODETYPE], ';')) *cp = '\0';
node->type = DBTechNameType(line[NODETYPE]);
@@ -340,6 +340,7 @@ ResSimDevice(line,rpersquare,ttype)
int rvalue,i,j,k;
char *newattr,tmpattr[MAXTOKEN];
static int nowarning = TRUE;
+ float lambda;
device = (RDev *) mallocMagic((unsigned) (sizeof(RDev)));
if ((line[RDEV_WIDTH][0] == '\0') || (line[RDEV_LENGTH][0] == '\0'))
@@ -360,8 +361,11 @@ ResSimDevice(line,rpersquare,ttype)
device->tnumber = ++Maxtnumber;
device->status = FALSE;
device->nextDev = ResRDevList;
- device->location.p_x = atoi(line[RDEV_DEVX]);
- device->location.p_y = atoi(line[RDEV_DEVY]);
+
+ lambda = resscale * (float)ExtCurStyle->exts_unitsPerLambda;
+ device->location.p_x = (int)((float)atof(line[RDEV_DEVX]) / lambda);
+ device->location.p_y = (int)((float)atof(line[RDEV_DEVY]) / lambda);
+
device->rs_gattr=RDEV_NOATTR;
device->rs_sattr=RDEV_NOATTR;
device->rs_dattr=RDEV_NOATTR;