diff --git a/VERSION b/VERSION index 8e5ca847..21d6308a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.366 +8.3.367 diff --git a/database/DBconnect.c b/database/DBconnect.c index c57ab7b7..aa085d53 100644 --- a/database/DBconnect.c +++ b/database/DBconnect.c @@ -129,6 +129,85 @@ DBInvTransformDiagonal(oldtype, trans) } +/* + * ---------------------------------------------------------------------------- + * + * DBSrConnectOnePlane -- + * + * Search from a starting tile to find all paint that is electrically + * connected to that tile in the same plane. + * + * Results: + * 0 is returned if the search finished normally. 1 is returned + * if the search was aborted. + * + * Side effects: + * For every paint tile that is electrically connected to the initial + * tile, func is called. Func should have the following form: + * + * int + * func(tile, clientData) + * Tile *tile; + * ClientData clientData; + * { + * } + * + * The clientData passed to func is the same one that was passed + * to us. Func returns 0 under normal conditions; if it returns + * 1 then the search is aborted. + * + * *** WARNING *** + * + * Func should not modify any paint during the search, since this + * will mess up pointers kept by these procedures and likely cause + * a core-dump. + * + * ---------------------------------------------------------------------------- + */ + +int +DBSrConnectOnePlane(startTile, connect, func, clientData) + Tile *startTile; /* Starting tile for search */ + TileTypeBitMask *connect; /* Pointer to a table indicating what tile + * types connect to what other tile types. + * Each entry gives a mask of types that + * connect to tiles of a given type. + */ + int (*func)(); /* Function to apply at each connected tile. */ + ClientData clientData; /* Client data for above function. */ + +{ + struct conSrArg csa; + int result; + extern int dbSrConnectFunc(); /* Forward declaration. */ + + result = 0; + csa.csa_def = (CellDef *)NULL; + csa.csa_bounds = TiPlaneRect; + + /* Pass 1. During this pass the client function gets called. */ + + csa.csa_clientFunc = func; + csa.csa_clientData = clientData; + csa.csa_clientDefault = startTile->ti_client; + csa.csa_clear = FALSE; + csa.csa_connect = connect; + csa.csa_pNum = -1; + if (dbSrConnectFunc(startTile, &csa) != 0) result = 1; + + /* Pass 2. Don't call any client function, just clear the marks. + * Don't allow any interruptions. + */ + + SigDisableInterrupts(); + csa.csa_clientFunc = NULL; + csa.csa_clear = TRUE; + (void) dbSrConnectFunc(startTile, &csa); + SigEnableInterrupts(); + + return result; +} + /* * ---------------------------------------------------------------------------- * @@ -227,6 +306,7 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData) csa.csa_clientFunc = func; csa.csa_clientData = clientData; + csa.csa_clientDefault = CLIENTDEFAULT; csa.csa_clear = FALSE; csa.csa_connect = connect; if (dbSrConnectFunc(startTile, &csa) != 0) result = 1; @@ -316,6 +396,7 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData) csa.csa_clientFunc = func; csa.csa_clientData = clientData; + csa.csa_clientDefault = CLIENTDEFAULT; csa.csa_clear = FALSE; csa.csa_connect = connect; if (dbSrConnectFunc(startTile, &csa) != 0) result = 1; @@ -424,15 +505,15 @@ dbSrConnectFunc(tile, csa) callClient = TRUE; if (csa->csa_clear) { - if (tile->ti_client == (ClientData) CLIENTDEFAULT) continue; - tile->ti_client = (ClientData) CLIENTDEFAULT; + if (tile->ti_client == csa->csa_clientDefault) continue; + tile->ti_client = csa->csa_clientDefault; } else { if (tile->ti_client == (ClientData) 1) continue; /* Allow a process to mark tiles for skipping the client function */ - if (tile->ti_client != (ClientData) CLIENTDEFAULT) + if (tile->ti_client != csa->csa_clientDefault) callClient = FALSE; tile->ti_client = (ClientData) 1; } @@ -480,7 +561,7 @@ dbSrConnectFunc(tile, csa) { if (csa->csa_clear) { - if (t2->ti_client == (ClientData) CLIENTDEFAULT) continue; + if (t2->ti_client == csa->csa_clientDefault) continue; } else if (t2->ti_client == (ClientData) 1) continue; if (IsSplit(t2)) @@ -508,7 +589,7 @@ bottomside: { if (csa->csa_clear) { - if (t2->ti_client == (ClientData) CLIENTDEFAULT) continue; + if (t2->ti_client == csa->csa_clientDefault) continue; } else if (t2->ti_client == (ClientData) 1) continue; if (IsSplit(t2)) @@ -542,7 +623,7 @@ rightside: { if (csa->csa_clear) { - if (t2->ti_client == (ClientData) CLIENTDEFAULT) goto nextRight; + if (t2->ti_client == csa->csa_clientDefault) goto nextRight; } else if (t2->ti_client == (ClientData) 1) goto nextRight; if (IsSplit(t2)) @@ -570,7 +651,7 @@ topside: { if (csa->csa_clear) { - if (t2->ti_client == (ClientData) CLIENTDEFAULT) goto nextTop; + if (t2->ti_client == csa->csa_clientDefault) goto nextTop; } else if (t2->ti_client == (ClientData) 1) goto nextTop; if (IsSplit(t2)) @@ -589,6 +670,7 @@ topside: } donesides: + if (pNum < 0) continue; /* Used for single-plane search */ /* Lastly, check to see if this tile connects to anything on * other planes. If so, search those planes. diff --git a/database/database.h.in b/database/database.h.in index ef8ff802..808ea983 100644 --- a/database/database.h.in +++ b/database/database.h.in @@ -691,6 +691,7 @@ struct conSrArg */ int (*csa_clientFunc)(); /* Client function to call. */ ClientData csa_clientData; /* Argument for clientFunc. */ + ClientData csa_clientDefault; /* Value to reset tiles' ClientData to. */ bool csa_clear; /* FALSE means pass 1, TRUE * means pass 2. */ @@ -1001,6 +1002,7 @@ extern void DBResetTilePlane(); extern void DBNewYank(); extern int DBSrPaintClient(); extern int DBSrConnect(); +extern int DBSrConnectOnePlane(); extern char *dbFgets(); extern void DBAdjustLabelsNew(); extern bool DBScaleValue(); diff --git a/ext2sim/ext2sim.c b/ext2sim/ext2sim.c index 8f00ea58..40c5ad35 100644 --- a/ext2sim/ext2sim.c +++ b/ext2sim/ext2sim.c @@ -1225,6 +1225,12 @@ simdevVisit(dev, hc, scale, trans) } else if (is_subckt) { + /* Output source and drain attributes */ + if (source->dterm_attrs) + fprintf(esSimF, " s=%s", source->dterm_attrs); + if (drain->dterm_attrs) + fprintf(esSimF, " d=%s", drain->dterm_attrs); + /* Output length, width, and position as attributes */ fprintf(esSimF, " l=%g w=%g x=%g y=%g", l * scale, w * scale, r.r_xbot * scale, r.r_ybot * scale); diff --git a/ext2spice/ext2hier.c b/ext2spice/ext2hier.c index e52a68a5..8a47fbb7 100644 --- a/ext2spice/ext2hier.c +++ b/ext2spice/ext2hier.c @@ -173,7 +173,7 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM) * esScale * esScale * plist->parm_scale * 1E-12); else - fprintf(esSpiceF, "%gp", parmval * scale * scale + esSIvalue(esSpiceF, 1.0E-12 * parmval * scale * scale * esScale * esScale); } else @@ -194,15 +194,15 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM) 'p' && plist->parm_next->parm_type[1] == plist->parm_type[1]) { - spcnAP(dnode, resclass, scale, plist->parm_name, - plist->parm_next->parm_name, sdM, - esSpiceF, w); + spcnAP(&dev->dev_terms[pn], dnode, resclass, scale, + plist->parm_name, plist->parm_next->parm_name, + sdM, esSpiceF, w); plist = plist->parm_next; } else { - spcnAP(dnode, resclass, scale, plist->parm_name, NULL, sdM, - esSpiceF, w); + spcnAP(&dev->dev_terms[pn], dnode, resclass, scale, + plist->parm_name, NULL, sdM, esSpiceF, w); } } @@ -220,7 +220,7 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM) fprintf(esSpiceF, "%g", parmval * scale * esScale * plist->parm_scale * 1E-6); else - fprintf(esSpiceF, "%gu", parmval * scale * esScale); + esSIvalue(esSpiceF, 1.0E-6 * parmval * scale * esScale); } else { @@ -240,14 +240,15 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM) 'a' && plist->parm_next->parm_type[1] == plist->parm_type[1]) { - spcnAP(dnode, resclass, scale, plist->parm_next->parm_name, + spcnAP(&dev->dev_terms[pn], dnode, resclass, scale, + plist->parm_next->parm_name, plist->parm_name, sdM, esSpiceF, w); plist = plist->parm_next; } else { - spcnAP(dnode, resclass, scale, NULL, plist->parm_name, sdM, - esSpiceF, w); + spcnAP(&dev->dev_terms[pn], dnode, resclass, scale, NULL, + plist->parm_name, sdM, esSpiceF, w); } } @@ -263,7 +264,7 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM) fprintf(esSpiceF, "%g", l * scale * esScale * plist->parm_scale * 1E-6); else - fprintf(esSpiceF, "%gu", l * scale * esScale); + esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale); } else { @@ -286,7 +287,7 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM) fprintf(esSpiceF, "%g", dval * scale * esScale * plist->parm_scale * 1E-6); else - fprintf(esSpiceF, "%gu", dval * scale * esScale); + esSIvalue(esSpiceF, 1.0E-6 * dval * scale * esScale); dparam->parm_name[0] = '\0'; break; } @@ -303,7 +304,7 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM) fprintf(esSpiceF, "%g", w * scale * esScale * plist->parm_scale * 1E-6); else - fprintf(esSpiceF, "%gu", w * scale * esScale); + esSIvalue(esSpiceF, 1.0E-6 * w * scale * esScale); break; case 's': fprintf(esSpiceF, " %s=", plist->parm_name); @@ -319,8 +320,7 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM) fprintf(esSpiceF, "%g", dev->dev_rect.r_xbot * scale * esScale * plist->parm_scale * 1E-6); else - fprintf(esSpiceF, "%gu", dev->dev_rect.r_xbot * scale - * esScale); + esSIvalue(esSpiceF, 1.0E-6 * dev->dev_rect.r_xbot * scale * esScale); break; case 'y': fprintf(esSpiceF, " %s=", plist->parm_name); @@ -330,8 +330,7 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM) fprintf(esSpiceF, "%g", dev->dev_rect.r_ybot * scale * esScale * plist->parm_scale * 1E-6); else - fprintf(esSpiceF, "%gu", dev->dev_rect.r_ybot * scale - * esScale); + esSIvalue(esSpiceF, 1.0E-6 * dev->dev_rect.r_ybot * scale * esScale); break; case 'r': fprintf(esSpiceF, " %s=", plist->parm_name); @@ -426,9 +425,10 @@ esOutputHierResistor(hc, dev, scale, term1, term2, has_model, l, w, dscale) } else { - fprintf(esSpiceF, " w=%gu l=%gu", - (float)w * scale * esScale, - (float)((l * scale * esScale) / dscale)); + fprintf(esSpiceF, " w="); + esSIvalue(esSpiceF, 1.0E-6 * (float)w * scale * esScale); + fprintf(esSpiceF, " w="); + esSIvalue(esSpiceF, 1.0E-6 * (float)((l * scale * esScale) / dscale)); } spcHierWriteParams(hc, dev, scale, l, w, sdM); if (sdM != 1.0) @@ -934,9 +934,10 @@ spcdevHierVisit(hc, dev, scale) } else { - fprintf(esSpiceF, " w=%gu l=%gu", - w * scale * esScale, - l * scale * esScale); + fprintf(esSpiceF, " w="); + esSIvalue(esSpiceF, 1.0E-6 * w * scale * esScale); + fprintf(esSpiceF, " l="); + esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale); } spcHierWriteParams(hc, dev, scale, l, w, sdM); if (sdM != 1.0) @@ -981,9 +982,10 @@ spcdevHierVisit(hc, dev, scale) } else { - fprintf(esSpiceF, " w=%gu l=%gu", - w * scale * esScale, - l * scale * esScale); + fprintf(esSpiceF, " w="); + esSIvalue(esSpiceF, 1.0E-6 * w * scale * esScale); + fprintf(esSpiceF, " l="); + esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale); } spcHierWriteParams(hc, dev, scale, l, w, sdM); if (sdM != 1.0) @@ -1024,9 +1026,10 @@ spcdevHierVisit(hc, dev, scale) } else { - fprintf(esSpiceF, " w=%gu l=%gu", - w * scale * esScale, - l * scale * esScale); + fprintf(esSpiceF, " w="); + esSIvalue(esSpiceF, 1.0E-6 * w * scale * esScale); + fprintf(esSpiceF, " l="); + esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale); } spcHierWriteParams(hc, dev, scale, l, w, sdM); if (sdM != 1.0) @@ -1042,10 +1045,10 @@ spcdevHierVisit(hc, dev, scale) fprintf(esSpiceF, "\n+ "); dnode = GetHierNode(hc, drain->dterm_node->efnode_name->efnn_hier); - spcnAP(dnode, esFetInfo[dev->dev_type].resClassDrain, scale, + spcnAP(drain, 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].resClassSource, scale, + spcnAP(source, snode, esFetInfo[dev->dev_type].resClassSource, scale, "as", "ps", sdM, esSpiceF, w); if (subAP) { @@ -1057,8 +1060,8 @@ spcdevHierVisit(hc, dev, scale) fprintf(esSpiceF, "asub=0 psub=0"); } else if (subnodeFlat) - spcnAP(subnodeFlat, esFetInfo[dev->dev_type].resClassSub, scale, - "asub", "psub", sdM, esSpiceF, -1); + spcnAP(NULL, subnodeFlat, esFetInfo[dev->dev_type].resClassSub, + scale, "asub", "psub", sdM, esSpiceF, -1); else fprintf(esSpiceF, "asub=0 psub=0"); } @@ -1073,13 +1076,21 @@ spcdevHierVisit(hc, dev, scale) case DEV_MSUBCKT: if (!esNoAttrs) { - if (gate->dterm_attrs || source->dterm_attrs || drain->dterm_attrs) + bool haveSattr = FALSE; + bool haveDattr = FALSE; + + if (source->dterm_attrs && (*source->dterm_attrs)) + haveSattr = TRUE; + if (drain->dterm_attrs && (*drain->dterm_attrs)) + haveDattr = TRUE; + + if (gate->dterm_attrs || haveSattr || haveDattr) fprintf(esSpiceF,"\n**devattr"); if (gate->dterm_attrs) fprintf(esSpiceF, " g=%s", gate->dterm_attrs); - if (source->dterm_attrs) + if (haveSattr) fprintf(esSpiceF, " s=%s", source->dterm_attrs); - if (drain->dterm_attrs) + if (haveDattr) fprintf(esSpiceF, " d=%s", drain->dterm_attrs); } break; diff --git a/ext2spice/ext2spice.c b/ext2spice/ext2spice.c index 6d2e6033..735ffde4 100644 --- a/ext2spice/ext2spice.c +++ b/ext2spice/ext2spice.c @@ -20,6 +20,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include /* for atof() */ #include #include +#include /* for fabs() */ #include "tcltk/tclmagic.h" #include "utils/magic.h" @@ -1002,7 +1003,11 @@ runexttospice: fprintf(esSpiceF, "* %s file created from %s.ext - technology: %s\n\n", spiceFormats[esFormat], inName, EFTech); if (esScale < 0) - fprintf(esSpiceF, ".option scale=%gu\n\n", EFScale / 100.0); + { + fprintf(esSpiceF, ".option scale="); + esSIvalue(esSpiceF, 1.0E-6 * EFScale / 100.0); + fprintf(esSpiceF, "\n\n"); + } else esScale = EFScale / 100.0; @@ -1237,7 +1242,11 @@ main(argc, argv) fprintf(esSpiceF, "* %s file created from %s.ext - technology: %s\n\n", spiceFormats[esFormat], inName, EFTech); if (esScale < 0) - fprintf(esSpiceF,".option scale=%gu\n\n", EFScale / 100.0); + { + fprintf(esSpiceF,".option scale="); + esSIvalue(esSpiceF, 1.0E-6 * EFScale / 100.0); + fprintf(esSpiceF, "\n\n"); + } else esScale = EFScale / 100.0; @@ -2005,7 +2014,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM) * esScale * esScale * plist->parm_scale * 1E-12); else - fprintf(esSpiceF, "%gp", parmval * scale * scale + esSIvalue(esSpiceF, 1.0E-12 * parmval * scale * scale * esScale * esScale); } else @@ -2036,8 +2045,8 @@ spcWriteParams(dev, hierName, scale, l, w, sdM) { dnode = SpiceGetNode(hierName, dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier); - spcnAP(dnode, resclass, scale, plist->parm_name, - plist->parm_next->parm_name, + spcnAP(&dev->dev_terms[pn], dnode, resclass, scale, + plist->parm_name, plist->parm_next->parm_name, sdM, esSpiceF, w); } plist = plist->parm_next; @@ -2052,8 +2061,8 @@ spcWriteParams(dev, hierName, scale, l, w, sdM) { dnode = SpiceGetNode(hierName, dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier); - spcnAP(dnode, resclass, scale, plist->parm_name, NULL, - sdM, esSpiceF, w); + spcnAP(&dev->dev_terms[pn], dnode, resclass, scale, + plist->parm_name, NULL, sdM, esSpiceF, w); } } } @@ -2071,7 +2080,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM) fprintf(esSpiceF, "%g", parmval * scale * esScale * plist->parm_scale * 1E-6); else - fprintf(esSpiceF, "%gu", parmval * scale * esScale); + esSIvalue(esSpiceF, 1.0E-12 * parmval * scale * esScale); } else { @@ -2100,7 +2109,8 @@ spcWriteParams(dev, hierName, scale, l, w, sdM) { dnode = SpiceGetNode(hierName, dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier); - spcnAP(dnode, resclass, scale, plist->parm_next->parm_name, + spcnAP(&dev->dev_terms[pn], dnode, resclass, scale, + plist->parm_next->parm_name, plist->parm_name, sdM, esSpiceF, w); } plist = plist->parm_next; @@ -2115,8 +2125,8 @@ spcWriteParams(dev, hierName, scale, l, w, sdM) { dnode = SpiceGetNode(hierName, dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier); - spcnAP(dnode, resclass, scale, NULL, plist->parm_name, - sdM, esSpiceF, w); + spcnAP(&dev->dev_terms[pn], dnode, resclass, scale, + NULL, plist->parm_name, sdM, esSpiceF, w); } } } @@ -2133,7 +2143,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM) fprintf(esSpiceF, "%g", l * scale * esScale * plist->parm_scale * 1E-6); else - fprintf(esSpiceF, "%gu", l * scale * esScale); + esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale); } else { @@ -2156,7 +2166,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM) fprintf(esSpiceF, "%g", dval * scale * esScale * plist->parm_scale * 1E-6); else - fprintf(esSpiceF, "%gu", dval * scale * esScale); + esSIvalue(esSpiceF, 1.0E-6 * dval * scale * esScale); dparam->parm_name[0] = '\0'; break; } @@ -2173,7 +2183,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM) fprintf(esSpiceF, "%g", w * scale * esScale * plist->parm_scale * 1E-6); else - fprintf(esSpiceF, "%gu", w * scale * esScale); + esSIvalue(esSpiceF, 1.0E-6 * w * scale * esScale); break; case 's': fprintf(esSpiceF, " %s=", plist->parm_name); @@ -2189,8 +2199,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM) fprintf(esSpiceF, "%g", dev->dev_rect.r_xbot * scale * esScale * plist->parm_scale * 1E-6); else - fprintf(esSpiceF, "%gu", dev->dev_rect.r_xbot * scale - * esScale); + esSIvalue(esSpiceF, 1.0E-6 * dev->dev_rect.r_xbot * scale * esScale); break; case 'y': fprintf(esSpiceF, " %s=", plist->parm_name); @@ -2200,8 +2209,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM) fprintf(esSpiceF, "%g", dev->dev_rect.r_ybot * scale * esScale * plist->parm_scale * 1E-6); else - fprintf(esSpiceF, "%gu", dev->dev_rect.r_ybot * scale - * esScale); + esSIvalue(esSpiceF, 1.0E-6 * dev->dev_rect.r_ybot * scale * esScale); break; case 'r': fprintf(esSpiceF, " %s=", plist->parm_name); @@ -2283,9 +2291,12 @@ esOutputResistor(dev, hierName, scale, term1, term2, has_model, l, w, dscale) if (esScale < 0) fprintf(esSpiceF, " w=%g l=%g", w * scale, (l * scale) / dscale); else - fprintf(esSpiceF, " w=%gu l=%gu", - w * scale * esScale, - ((l * scale * esScale) / dscale)); + { + fprintf(esSpiceF, " w="); + esSIvalue(esSpiceF, 1.0E-6 * w * scale * esScale); + fprintf(esSpiceF, " l="); + esSIvalue(esSpiceF, 1.0E-6 * (l * scale * esScale) / dscale); + } spcWriteParams(dev, hierName, scale, l, w, sdM); if (sdM != 1.0) @@ -2838,9 +2849,12 @@ spcdevVisit(dev, hc, scale, trans) if (esScale < 0) fprintf(esSpiceF, " w=%g l=%g", w*scale, l*scale); else - fprintf(esSpiceF, " w=%gu l=%gu", - w * scale * esScale, - l * scale * esScale); + { + fprintf(esSpiceF, " w="); + esSIvalue(esSpiceF, 1.0E-6 * w * scale * esScale); + fprintf(esSpiceF, " l="); + esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale); + } spcWriteParams(dev, hierName, scale, l, w, sdM); if (sdM != 1.0) @@ -2879,9 +2893,12 @@ spcdevVisit(dev, hc, scale, trans) if (esScale < 0) fprintf(esSpiceF, " w=%g l=%g", w*scale, l*scale); else - fprintf(esSpiceF, " w=%gu l=%gu", - w * scale * esScale, - l * scale * esScale); + { + fprintf(esSpiceF, " w="); + esSIvalue(esSpiceF, 1.0E-6 * w * scale * esScale); + fprintf(esSpiceF, " l="); + esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale); + } spcWriteParams(dev, hierName, scale, l, w, sdM); if (sdM != 1.0) @@ -2924,9 +2941,12 @@ spcdevVisit(dev, hc, scale, trans) if (esScale < 0) fprintf(esSpiceF, " w=%g l=%g", w*scale, l*scale); else - fprintf(esSpiceF, " w=%gu l=%gu", - w * scale * esScale, - l * scale * esScale); + { + fprintf(esSpiceF, " w="); + esSIvalue(esSpiceF, 1.0E-6 * w * scale * esScale); + fprintf(esSpiceF, " l="); + esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale); + } spcWriteParams(dev, hierName, scale, l, w, sdM); if (sdM != 1.0) @@ -2947,7 +2967,7 @@ spcdevVisit(dev, hc, scale, trans) else { dnode = SpiceGetNode(hierName, drain->dterm_node->efnode_name->efnn_hier); - spcnAP(dnode, esFetInfo[dev->dev_type].resClassDrain, scale, + spcnAP(drain, dnode, esFetInfo[dev->dev_type].resClassDrain, scale, "ad", "pd", sdM, esSpiceF, w); } if (hierS) @@ -2955,7 +2975,7 @@ spcdevVisit(dev, hc, scale, trans) scale, "as", "ps", sdM, esSpiceF); else { snode= SpiceGetNode(hierName, source->dterm_node->efnode_name->efnn_hier); - spcnAP(snode, esFetInfo[dev->dev_type].resClassSource, scale, + spcnAP(source, snode, esFetInfo[dev->dev_type].resClassSource, scale, "as", "ps", sdM, esSpiceF, w); } if (subAP) @@ -2968,8 +2988,8 @@ spcdevVisit(dev, hc, scale, trans) fprintf(esSpiceF, "asub=0 psub=0"); } else if (subnodeFlat) - spcnAP(subnodeFlat, esFetInfo[dev->dev_type].resClassSub, scale, - "asub", "psub", sdM, esSpiceF, -1); + spcnAP(NULL, subnodeFlat, esFetInfo[dev->dev_type].resClassSub, + scale, "asub", "psub", sdM, esSpiceF, -1); else fprintf(esSpiceF, "asub=0 psub=0"); } @@ -2977,13 +2997,21 @@ spcdevVisit(dev, hc, scale, trans) /* Now output attributes, if present */ if (!esNoAttrs) { - if (gate->dterm_attrs || source->dterm_attrs || drain->dterm_attrs) + bool haveSattr = FALSE; + bool haveDattr = FALSE; + + if (source->dterm_attrs && (*source->dterm_attrs)) + haveSattr = TRUE; + if (drain->dterm_attrs && (*drain->dterm_attrs)) + haveDattr = TRUE; + + if (gate->dterm_attrs || haveSattr || haveDattr) fprintf(esSpiceF,"\n**devattr"); if (gate->dterm_attrs) fprintf(esSpiceF, " g=%s", gate->dterm_attrs); - if (source->dterm_attrs) + if (haveSattr) fprintf(esSpiceF, " s=%s", source->dterm_attrs); - if (drain->dterm_attrs) + if (haveDattr) fprintf(esSpiceF, " d=%s", drain->dterm_attrs); } break; @@ -3054,6 +3082,83 @@ FILE *outf; } } +/* + * ---------------------------------------------------------------------------- + * + * esSIvalue -- + * + * Print an output in appropriate SI units used by SPICE. e.g., 1.0e-6 + * will be printed as "1.0u"; 1.0e-12 will be printed as "1.0p", etc. + * + * Return value: + * None. + * + * Side effects: + * Generates output to stream "file". + * + * ---------------------------------------------------------------------------- + */ + +void +esSIvalue(file, value) + FILE *file; + float value; +{ + char suffix = '\0'; + float avalue; + + avalue = fabsf(value); + + if (avalue < 1.0E-18) + { + /* Do nothing---value is probably zero */ + } + else if (avalue < 1.0E-15) + { + suffix = 'a'; + value *= 1.0E18; + } + else if (avalue < 1.0E-12) + { + suffix = 'f'; + value *= 1.0E15; + } + else if (avalue < 1.0E-9) + { + suffix = 'p'; + value *= 1.0E12; + } + else if (avalue < 1.0E-6) + { + suffix = 'n'; + value *= 1.0E9; + } + else if (avalue < 1.0E-3) + { + suffix = 'u'; + value *= 1.0E6; + } + else if (avalue <= 1.0E-3) + { + suffix = 'm'; + value *= 1.0E3; + } + else if (avalue >= 1.0E9) + { + suffix = 'G'; + value /= 1.0E9; + } + else if (avalue >= 1.0E3) + { + suffix = 'k'; + value /= 1.0E3; + } + + if (suffix == '\0') + fprintf(file, "%g", value); + else + fprintf(file, "%g%c", value, suffix); +} /* * ---------------------------------------------------------------------------- @@ -3074,7 +3179,8 @@ FILE *outf; * * ---------------------------------------------------------------------------- */ -int spcnAP(node, resClass, scale, asterm, psterm, m, outf, w) +int spcnAP(dterm, node, resClass, scale, asterm, psterm, m, outf, w) + DevTerm *dterm; EFNode *node; int resClass; float scale, m; @@ -3084,6 +3190,9 @@ int spcnAP(node, resClass, scale, asterm, psterm, m, outf, w) { char afmt[15], pfmt[15]; float dsc; + int area, perim; + char *cptr; + bool haveAttrs = FALSE; if ((node == NULL) || (node->efnode_client == (ClientData)NULL)) { @@ -3091,18 +3200,10 @@ int spcnAP(node, resClass, scale, asterm, psterm, m, outf, w) return 1; } - if (esScale < 0) - { - if (asterm) sprintf(afmt, " %s=%%g", asterm); - if (psterm) sprintf(pfmt, " %s=%%g", psterm); - } - else - { - if (asterm) sprintf(afmt, " %s=%%gp", asterm); - if (psterm) sprintf(pfmt, " %s=%%gu", psterm); - } + if (asterm) sprintf(afmt, " %s=", asterm); + if (psterm) sprintf(pfmt, " %s=", psterm); - if (!esDistrJunct || w == -1) goto oldFmt; + if (!esDistrJunct || w == -1) goto newFmt; if (((nodeClient*)node->efnode_client)->m_w.widths != NULL) dsc = w / ((nodeClient*)node->efnode_client)->m_w.widths[resClass]; @@ -3115,52 +3216,96 @@ int spcnAP(node, resClass, scale, asterm, psterm, m, outf, w) if (esScale < 0) { if (asterm) - fprintf(outf, afmt, - node->efnode_pa[resClass].pa_area * scale * scale * dsc); + { + fprintf(outf, afmt); + esSIvalue(outf, 1.0E-12 * node->efnode_pa[resClass].pa_area + * scale * scale * dsc); + } if (psterm) - fprintf(outf, pfmt, - node->efnode_pa[resClass].pa_perim * scale * dsc); + { + fprintf(outf, pfmt); + esSIvalue(outf, 1.0E-6 * node->efnode_pa[resClass].pa_perim * scale * dsc); + } } else { if (asterm) - fprintf(outf, afmt, - ((float)node->efnode_pa[resClass].pa_area * scale * scale) - * esScale * esScale * dsc); + { + fprintf(outf, afmt); + esSIvalue(outf, 1.0E-12 * ((float)node->efnode_pa[resClass].pa_area + * scale * scale) * esScale * esScale * dsc); + } if (psterm) - fprintf(outf, pfmt, - ((float)node->efnode_pa[resClass].pa_perim * scale) - * esScale * dsc); + { + fprintf(outf, pfmt); + esSIvalue(outf, 1.0E-6 * ((float)node->efnode_pa[resClass].pa_perim + * scale) * esScale * dsc); + } } return 0; -oldFmt: - if (resClass == NO_RESCLASS || - beenVisited((nodeClient *)node->efnode_client, resClass)) - scale = 0; - else - markVisited((nodeClient *)node->efnode_client, resClass); +newFmt: + /* New format introduced 2/15/2023: Area and perimeter of each terminal + * are maintained in the terminal attributes for "fet" or "device mosfet" + * type devices (otherwise, for subcircuit device types, this routine is + * not used and the same values are found in the device parameters). + * + * Values are the last two values in a comma-separated list in + * dterm_attrs. If not found, then default to the + */ + + cptr = (dterm) ? dterm->dterm_attrs : NULL; + while (cptr) + { + if (*cptr == ',') cptr++; + if (sscanf(cptr, "%d,%d", &area, &perim) != 2) + cptr = strchr(cptr, ','); + else + { + haveAttrs = TRUE; + *cptr = '\0'; + break; + } + } + + if (!haveAttrs) + { + area = node->efnode_pa[resClass].pa_area; + perim = node->efnode_pa[resClass].pa_perim; + + if (resClass == NO_RESCLASS || + beenVisited((nodeClient *)node->efnode_client, resClass)) + scale = 0; + else + markVisited((nodeClient *)node->efnode_client, resClass); + } if (esScale < 0) { if (asterm) - fprintf(outf, afmt, - node->efnode_pa[resClass].pa_area * scale * scale / m); + { + fprintf(outf, afmt); + esSIvalue(outf, 1.0E-12 * area * scale * scale / m); + } if (psterm) - fprintf(outf, pfmt, - node->efnode_pa[resClass].pa_perim * scale / m); + { + fprintf(outf, pfmt); + esSIvalue(outf, 1.0E-6 * perim * scale / m); + } } else { if (asterm) - fprintf(outf, afmt, - ((float)node->efnode_pa[resClass].pa_area * scale * scale) - * esScale * esScale); + { + fprintf(outf, afmt); + esSIvalue(outf, 1.0E-12 * ((float)area * scale * scale) * esScale * esScale); + } if (psterm) - fprintf(outf, pfmt, - ((float)node->efnode_pa[resClass].pa_perim * scale) - * esScale); + { + fprintf(outf, pfmt); + esSIvalue(outf, 1.0E-6 * ((float)perim * scale) * esScale); + } } return 0; } @@ -3176,17 +3321,13 @@ int spcnAPHier(dterm, hierName, resClass, scale, asterm, psterm, m, outf) EFNode *node = dterm->dterm_node; nodeClientHier *nc; char afmt[15], pfmt[15]; + int area, perim; + char *cptr; + bool haveAttrs = FALSE; + + sprintf(afmt," %s=", asterm); + sprintf(pfmt," %s=", psterm); - if (esScale < 0) - { - sprintf(afmt," %s=%%g", asterm); - sprintf(pfmt," %s=%%g", psterm); - } - else - { - sprintf(afmt," %s=%%gp", asterm); - sprintf(pfmt," %s=%%gu", psterm); - } if (node->efnode_client == (ClientData) NULL) initNodeClientHier(node); @@ -3196,27 +3337,48 @@ int spcnAPHier(dterm, hierName, resClass, scale, asterm, psterm, m, outf) clearVisited(nc); nc->lastPrefix = hierName; } - if (resClass == NO_RESCLASS || - beenVisited((nodeClientHier *)node->efnode_client, resClass) ) - scale = 0.0; - else - markVisited((nodeClientHier *)node->efnode_client, resClass); + + /* Check for area and perim values in dterm_attrs */ + + cptr = dterm->dterm_attrs; + while (cptr) + { + if (*cptr == ',') cptr++; + if (sscanf(cptr, "%d,%d", &area, &perim) != 2) + cptr = strchr(cptr, ','); + else + { + haveAttrs = TRUE; + *cptr = '\0'; + break; + } + } + + if (!haveAttrs) + { + area = node->efnode_pa[resClass].pa_area; + perim = node->efnode_pa[resClass].pa_perim; + + if (resClass == NO_RESCLASS || + beenVisited((nodeClient *)node->efnode_client, resClass)) + scale = 0; + else + markVisited((nodeClient *)node->efnode_client, resClass); + } if (esScale < 0) { - fprintf(outf, afmt, - node->efnode_pa[resClass].pa_area * scale * scale / m); - fprintf(outf, pfmt, - node->efnode_pa[resClass].pa_perim * scale / m); + fprintf(outf, afmt); + esSIvalue(outf, 1.0E-12 * area * scale * scale / m); + fprintf(outf, pfmt); + esSIvalue(outf, 1.0E-6 * perim * scale / m); } else { - fprintf(outf, afmt, - ((float)node->efnode_pa[resClass].pa_area * scale) - * esScale * esScale); - fprintf(outf, pfmt, - ((float)node->efnode_pa[resClass].pa_perim * scale) - * esScale); + fprintf(outf, afmt); + esSIvalue(outf, 1.0E-12 * ((float)area * scale) * esScale * esScale); + fprintf(outf, pfmt); + esSIvalue(outf, 1.0E-6 * ((float)perim * scale) * esScale); } return 0; } diff --git a/ext2spice/ext2spice.h b/ext2spice/ext2spice.h index 8d7dde38..4ba9da2c 100644 --- a/ext2spice/ext2spice.h +++ b/ext2spice/ext2spice.h @@ -52,6 +52,7 @@ extern int devDistJunctHierVisit(); extern int spcnAPHier(); extern void mergeAttr(); extern int update_w(); +extern void esSIvalue(); /* Options specific to ext2spice */ extern bool esDoExtResis; diff --git a/extflat/EFbuild.c b/extflat/EFbuild.c index a167878d..e1822a88 100644 --- a/extflat/EFbuild.c +++ b/extflat/EFbuild.c @@ -1083,8 +1083,6 @@ efBuildDevice(def, class, type, r, argc, argv) term = &newdev->dev_terms[n]; term->dterm_node = efBuildDevNode(def, av[TERM_NAME], FALSE); term->dterm_length = atoi(av[TERM_PERIM]); - term->dterm_area = 0; - term->dterm_perim = 0; /* If the attr list is '0', this signifies no attributes */ if (av[TERM_ATTRS][0] == '0' && av[TERM_ATTRS][1] == '\0') diff --git a/extflat/extflat.h b/extflat/extflat.h index ef475d3e..2275313b 100644 --- a/extflat/extflat.h +++ b/extflat/extflat.h @@ -255,8 +255,6 @@ typedef struct devterm EFNode *dterm_node; /* Node to which we're connected */ char *dterm_attrs; /* Attribute list */ int dterm_length; /* Length of terminal connection to gate */ - int dterm_perim; /* Terminal perimeter if passed as a param */ - int dterm_area; /* Terminal area if passed as a param */ } DevTerm; /* diff --git a/extract/ExtBasic.c b/extract/ExtBasic.c index 62244ad9..87e1656d 100644 --- a/extract/ExtBasic.c +++ b/extract/ExtBasic.c @@ -105,9 +105,9 @@ struct transRec int tr_termlen[MAXSD]; /* Length of each diff terminal edge, * used for computing L/W for the fet. */ - int tr_termdepth[MAXSD]; /* Length of the terminal perpendicular - * to the device edge. - */ + int tr_termarea[MAXSD]; /* Total area of the terminal */ + int tr_termperim[MAXSD]; /* Total perimeter of the terminal */ + int tr_termshared[MAXSD]; /* Number of devices sharing this terminal */ Point tr_termvector[MAXSD]; /* Perimeter traversal vector, used to * find and calculate correct parameters * for annular (ring) devices and other @@ -1061,7 +1061,7 @@ ExtSortTerminals(tran, ll) TermTilePos *p1, *p2; NodeRegion *tmp_node; TermTilePos tmp_pos; - int tmp_len, tmp_depth; + int tmp_len, tmp_area, tmp_perim, tmp_shared; LabelList *lp; do @@ -1089,21 +1089,29 @@ ExtSortTerminals(tran, ll) tmp_node = tran->tr_termnode[nsd]; tmp_pos = tran->tr_termpos[nsd]; tmp_len = tran->tr_termlen[nsd]; - tmp_depth = tran->tr_termdepth[nsd]; + tmp_area = tran->tr_termarea[nsd]; + tmp_perim = tran->tr_termperim[nsd]; + tmp_shared = tran->tr_termshared[nsd]; tran->tr_termnode[nsd] = tran->tr_termnode[nsd+1]; tran->tr_termpos[nsd] = tran->tr_termpos[nsd+1]; tran->tr_termlen[nsd] = tran->tr_termlen[nsd+1]; - tran->tr_termdepth[nsd] = tran->tr_termdepth[nsd+1]; + tran->tr_termperim[nsd] = tran->tr_termperim[nsd+1]; + tran->tr_termarea[nsd] = tran->tr_termarea[nsd+1]; + tran->tr_termshared[nsd] = tran->tr_termshared[nsd+1]; tran->tr_termnode[nsd+1] = tmp_node; tran->tr_termpos[nsd+1] = tmp_pos; tran->tr_termlen[nsd+1] = tmp_len; - tran->tr_termdepth[nsd+1] = tmp_depth; + tran->tr_termarea[nsd+1] = tmp_area; + tran->tr_termperim[nsd+1] = tmp_perim; + tran->tr_termshared[nsd+1] = tmp_shared; + /* Need to SWAP the indices in the labRegion too. * These for loops within the bubblesort in here are kinda slow * but S,D attributes are not that common so it should not matter * that much -- Stefanos 5/96 */ + for ( lp = ll ; lp ; lp = lp->ll_next ) if ( lp->ll_attr == nsd ) lp->ll_attr = LL_SORTATTR ; else if ( lp->ll_attr == nsd+1 ) lp->ll_attr = nsd ; @@ -1690,13 +1698,13 @@ extOutputParameters(def, transList, outFile) */ void -extOutputDevParams(reg, devptr, outFile, length, width, depthvec) +extOutputDevParams(reg, devptr, outFile, length, width, areavec) TransRegion *reg; ExtDevice *devptr; FILE *outFile; int length; int width; - int *depthvec; + int *areavec; { ParamList *chkParam; @@ -1710,12 +1718,14 @@ extOutputDevParams(reg, devptr, outFile, length, width, depthvec) chkParam->pl_param[1] == '0') fprintf(outFile, " %c=%d", chkParam->pl_param[0], reg->treg_area); + /* Note: a1, a2, etc., are standard output */ break; case 'p': if (chkParam->pl_param[1] == '\0' || chkParam->pl_param[1] == '0') fprintf(outFile, " %c=%d", chkParam->pl_param[0], extTransRec.tr_perim); + /* Note: p1, p2, etc., are standard output */ break; case 'l': if (chkParam->pl_param[1] == '\0' || @@ -1725,10 +1735,12 @@ extOutputDevParams(reg, devptr, outFile, length, width, depthvec) else if (chkParam->pl_param[1] > '0' && chkParam->pl_param[1] <= '9') { int tidx = chkParam->pl_param[1] - '1'; - /* output depth of terminal */ + /* output length of terminal, assuming a rectangular + * shape, as simplified terminal area / width + */ fprintf(outFile, " %c%c=%d", chkParam->pl_param[0], chkParam->pl_param[1], - depthvec[tidx]); + areavec[tidx] / width); } break; case 'w': @@ -1953,7 +1965,9 @@ extOutputDevices(def, transList, outFile) while (extTransRec.tr_nterm < nsd) { extTransRec.tr_termlen[extTransRec.tr_nterm] = 0; - extTransRec.tr_termdepth[extTransRec.tr_nterm] = 0; + extTransRec.tr_termarea[extTransRec.tr_nterm] = 0; + extTransRec.tr_termperim[extTransRec.tr_nterm] = 0; + extTransRec.tr_termshared[extTransRec.tr_nterm] = 0; extTransRec.tr_termnode[extTransRec.tr_nterm++] = node; } } @@ -2177,7 +2191,7 @@ extOutputDevices(def, transList, outFile) } extOutputDevParams(reg, devptr, outFile, length, width, - extTransRec.tr_termdepth); + extTransRec.tr_termarea); fprintf(outFile, " \"%s\"", (subsName == NULL) ? "None" : subsName); @@ -2187,7 +2201,7 @@ extOutputDevices(def, transList, outFile) case DEV_NDIODE: case DEV_PDIODE: extOutputDevParams(reg, devptr, outFile, length, width, - extTransRec.tr_termdepth); + extTransRec.tr_termarea); if (subsName != NULL) fprintf(outFile, " \"%s\"", subsName); break; @@ -2315,7 +2329,7 @@ extOutputDevices(def, transList, outFile) fprintf(outFile, " %g", dres / 1000.0); /* mOhms -> Ohms */ extOutputDevParams(reg, devptr, outFile, length, width, - extTransRec.tr_termdepth); + extTransRec.tr_termarea); if (devptr->exts_deviceClass == DEV_RSUBCKT) { @@ -2406,7 +2420,7 @@ extOutputDevices(def, transList, outFile) } extOutputDevParams(reg, devptr, outFile, length, width, - extTransRec.tr_termdepth); + extTransRec.tr_termarea); if (devptr->exts_deviceClass == DEV_CSUBCKT) { @@ -2428,7 +2442,7 @@ extOutputDevices(def, transList, outFile) node = (NodeRegion *) extGetRegion(reg->treg_tile); ll = node->nreg_labels; extTransOutTerminal((LabRegion *) node, ll, LL_GATEATTR, - extTransRec.tr_gatelen, outFile); + extTransRec.tr_gatelen, 0, 0, 0, outFile); /* Sort source and drain terminals by position, unless the */ /* device is asymmetric, in which case source and drain do not */ @@ -2440,7 +2454,10 @@ extOutputDevices(def, transList, outFile) /* each non-gate terminal */ for (nsd = 0; nsd < extTransRec.tr_nterm; nsd++) extTransOutTerminal((LabRegion *) extTransRec.tr_termnode[nsd], ll, - nsd, extTransRec.tr_termlen[nsd], outFile); + nsd, extTransRec.tr_termlen[nsd], + extTransRec.tr_termarea[nsd], + extTransRec.tr_termperim[nsd], + extTransRec.tr_termshared[nsd], outFile); (void) fputs("\n", outFile); } @@ -2867,6 +2884,171 @@ extTransTileFunc(tile, pNum, arg) return 0; } +/* Structures used by extTermAPFunc() for storing area and perimeter data */ + +typedef struct _nodelist { + struct _nodelist *nl_next; + NodeRegion *nl_node; +} ExtNodeList; + +typedef struct _extareaperimdata { + int eapd_area; + int eapd_perim; + TileTypeBitMask eapd_mask; + TileTypeBitMask *eapd_gatemask; + NodeRegion *eapd_gatenode; + ExtNodeList *eapd_shared; +} ExtAreaPerimData; + +/* + * ---------------------------------------------------------------------------- + * + * extAddSharedDevice -- + * + * Add a node region representing a device to the list of nodes + * kept in the structure passed to extTermAPFunc(), to keep track + * of how many devices share the same terminal area. + * + * ---------------------------------------------------------------------------- + */ + +void +extAddSharedDevice(eapd, node) + ExtAreaPerimData *eapd; + NodeRegion *node; +{ + ExtNodeList *nl, *newnl; + + for (nl = eapd->eapd_shared; nl; nl = nl->nl_next) + if (nl->nl_node == node) break; + + if (nl == NULL) + { + newnl = (ExtNodeList *)mallocMagic(sizeof(ExtNodeList)); + newnl->nl_node = node; + newnl->nl_next = eapd->eapd_shared; + eapd->eapd_shared = newnl; + } +} + +/* + * ---------------------------------------------------------------------------- + * + * extTermAPFunc -- + * + * Callback function used by extTransPerimFunc() to find the largest + * area encompassing a device terminal. This is the bounding box of + * the area containing terminal types connected to a device tile. + * + * This routine is redundant with the area and perimeter calculations + * in extFindNodes(), but that routine traverses an entire net. This + * routine finds the area and perimeter belonging to material on a + * single plane extending from a device (e.g., diffusion and contacts + * on a FET source or drain). + * + * Note that this definition is not necessarily accurate for defining + * terminal area and perimeter, as the area of terminal types may not + * be rectangular, making an approximation using length and width + * inappropriate. + * + * ---------------------------------------------------------------------------- + */ + +int +extTermAPFunc(tile, pNum, eapd) + Tile *tile; /* Tile extending a device terminal */ + int pNum; /* Plane of tile (unused, set to -1) */ + ExtAreaPerimData *eapd; /* Area and perimeter totals for terminal */ +{ + TileType type; + Tile *tp; + Rect r; + + TiToRect(tile, &r); + eapd->eapd_area += (r.r_xtop - r.r_xbot) * (r.r_ytop - r.r_ybot); + + /* Diagonal */ + if (IsSplit(tile)) + { + int w, h, l; + type = (SplitSide(tile)) ? SplitLeftType(tile): SplitRightType(tile); + w = RIGHT(tile) - LEFT(tile); + h = TOP(tile) - BOTTOM(tile); + l = w * w + h * h; + eapd->eapd_perim += (int)sqrt((double)l); + } + + /* Top */ + for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp)) + { + type = TiGetBottomType(tp); + if (TTMaskHasType(&eapd->eapd_mask, type)) + { + eapd->eapd_perim += MIN(RIGHT(tile), RIGHT(tp)) - + MAX(LEFT(tile), LEFT(tp)); + if (TTMaskHasType(eapd->eapd_gatemask, type)) + if (tp->ti_client != (ClientData)eapd->eapd_gatenode) + extAddSharedDevice(eapd, (NodeRegion *)tp->ti_client); + } + } + + /* Bottom */ + for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp)) + { + type = TiGetTopType(tp); + if (TTMaskHasType(&eapd->eapd_mask, type)) + { + eapd->eapd_perim += MIN(RIGHT(tile), RIGHT(tp)) - + MAX(LEFT(tile), LEFT(tp)); + if (TTMaskHasType(eapd->eapd_gatemask, type)) + if (tp->ti_client != (ClientData)eapd->eapd_gatenode) + extAddSharedDevice(eapd, (NodeRegion *)tp->ti_client); + } + } + + /* Left */ + for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp)) + { + type = TiGetRightType(tp); + if (TTMaskHasType(&eapd->eapd_mask, type)) + { + eapd->eapd_perim += MIN(TOP(tile), TOP(tp)) - + MAX(BOTTOM(tile), BOTTOM(tp)); + if (TTMaskHasType(eapd->eapd_gatemask, type)) + if (tp->ti_client != (ClientData)eapd->eapd_gatenode) + extAddSharedDevice(eapd, (NodeRegion *)tp->ti_client); + } + } + + /* Right */ + for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp)) + { + type = TiGetLeftType(tp); + if (TTMaskHasType(&eapd->eapd_mask, type)) + { + eapd->eapd_perim += MIN(TOP(tile), TOP(tp)) - + MAX(BOTTOM(tile), BOTTOM(tp)); + if (TTMaskHasType(eapd->eapd_gatemask, type)) + if (tp->ti_client != (ClientData)eapd->eapd_gatenode) + extAddSharedDevice(eapd, (NodeRegion *)tp->ti_client); + } + } + + return 0; +} + +/* + * ---------------------------------------------------------------------------- + * + * extTransPerimFunc -- + * + * Callback function for exploring the perimeter of a device to find + * areas connected to the device (e.g., gate) and areas adjacent but + * not connected (e.g., source and drain). + * + * ---------------------------------------------------------------------------- + */ + int extTransPerimFunc(bp) Boundary *bp; @@ -2875,11 +3057,10 @@ extTransPerimFunc(bp) Tile *tile; NodeRegion *diffNode = (NodeRegion *) extGetRegion(bp->b_outside); ExtDevice *devptr, *deventry; - int i, depth, len = BoundaryLength(bp); + int i, area, perim, len = BoundaryLength(bp); int thisterm; LabelList *ll; Label *lab; - Rect r; bool SDterm = FALSE; tile = bp->b_inside; @@ -2893,17 +3074,6 @@ extTransPerimFunc(bp) else toutside = TiGetTypeExact(bp->b_outside); - /* Experimental---find the depth of the area outside the boundary. - * This can be used in limited circumstances to extract the terminal - * length (here, called tr_depth). - */ - if (toutside == TT_SPACE) - depth = 0; - else if (bp->b_segment.r_xtop == bp->b_segment.r_xbot) - depth = RIGHT(bp->b_outside) - LEFT(bp->b_outside); - else - depth = TOP(bp->b_outside) - BOTTOM(bp->b_outside); - if (extTransRec.tr_devrec != NULL) devptr = extTransRec.tr_devrec; else @@ -2943,7 +3113,9 @@ extTransPerimFunc(bp) extTransRec.tr_nterm++; extTransRec.tr_termnode[thisterm] = diffNode; extTransRec.tr_termlen[thisterm] = 0; - extTransRec.tr_termdepth[thisterm] = 0; + extTransRec.tr_termarea[thisterm] = 0; + extTransRec.tr_termperim[thisterm] = 0; + extTransRec.tr_termshared[thisterm] = 0; extTransRec.tr_termvector[thisterm].p_x = 0; extTransRec.tr_termvector[thisterm].p_y = 0; extTransRec.tr_termpos[thisterm].pnum = DBPlane(toutside); @@ -2986,9 +3158,39 @@ extTransPerimFunc(bp) /* Add the length to this terminal's perimeter */ extTransRec.tr_termlen[thisterm] += len; - /* Update the terminal depth */ - if (depth > extTransRec.tr_termdepth[thisterm]) - extTransRec.tr_termdepth[thisterm] = depth; + if (extTransRec.tr_termarea[thisterm] == 0) + { + /* Find the area and perimeter of the terminal area (connected + * area outside the boundary on a single plane). Note that + * this does not consider terminal area outside of the cell + * or how area or perimeter may be shared or overlap between + * devices. + */ + + ExtAreaPerimData eapd; + int shared; + + eapd.eapd_area = eapd.eapd_perim = 0; + TTMaskCom2(&eapd.eapd_mask, &DBConnectTbl[toutside]); + eapd.eapd_gatemask = &ExtCurStyle->exts_deviceMask; + eapd.eapd_gatenode = (NodeRegion *)extGetRegion(bp->b_inside); + eapd.eapd_shared = NULL; + + DBSrConnectOnePlane(bp->b_outside, DBConnectTbl, + extTermAPFunc, (ClientData)&eapd); + + shared = 1; + while (eapd.eapd_shared) + { + shared++; + freeMagic(eapd.eapd_shared); + eapd.eapd_shared = eapd.eapd_shared->nl_next; + } + + extTransRec.tr_termarea[thisterm] = eapd.eapd_area; + extTransRec.tr_termperim[thisterm] = eapd.eapd_perim; + extTransRec.tr_termshared[thisterm] = shared; + } /* Update the boundary traversal vector */ switch(bp->b_direction) { @@ -3435,13 +3637,16 @@ extSpecialPerimFunc(bp, sense) */ void -extTransOutTerminal(lreg, ll, whichTerm, len, outFile) +extTransOutTerminal(lreg, ll, whichTerm, len, area, perim, shared, outFile) LabRegion *lreg; /* Node connected to terminal */ LabelList *ll; /* Gate's label list */ int whichTerm; /* Which terminal we are processing. The gate * is indicated by LL_GATEATTR. */ int len; /* Length of perimeter along terminal */ + int area; /* Total area of terminal */ + int perim; /* Total perimeter of terminal (includes len) */ + int shared; /* Number of devices sharing the terminal */ FILE *outFile; /* Output file */ { char *cp; @@ -3463,7 +3668,16 @@ extTransOutTerminal(lreg, ll, whichTerm, len, outFile) fmt = ','; } - if (fmt == ' ') + /* NOTE: The area and perimeter of a terminal are divided equally + * among devices that share the same terminal area. This may not + * necessarily be the best way to handle shared terminals; in + * particular, it is preferable to detect and output fingered + * devices separately. + */ + + if ((whichTerm != LL_GATEATTR) && (area != 0) && (perim != 0)) + fprintf(outFile, "%c%d,%d", fmt, (area / shared), (perim / shared)); + else if (fmt == ' ') fprintf(outFile, " 0"); } diff --git a/resis/ResBasic.c b/resis/ResBasic.c index b471954b..cd40077e 100644 --- a/resis/ResBasic.c +++ b/resis/ResBasic.c @@ -24,8 +24,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "textio/txcommands.h" #include "resis/resis.h" -int resSubDevFunc(); - /* *-------------------------------------------------------------------------- * @@ -440,45 +438,3 @@ ResEachTile(tile, startpoint) return(merged); } - -/* - *------------------------------------------------------------------------- - * - * resSubDevFunc -- called when DBSrPaintArea finds a device within - * a substrate area. - * - * Results: always returns 0 to keep search going. - * - * Side Effects: allocates substrate node. - * - *------------------------------------------------------------------------- - */ - -int -resSubDevFunc(tile, tp) - Tile *tile, *tp; -{ - tileJunk *junk = (tileJunk *)(tile->ti_client); - resNode *resptr; - tElement *tcell; - int x, y; - - if (junk->deviceList->rd_fet_subs == NULL) - { - resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode))); - junk->deviceList->rd_fet_subs = resptr; - junk->tj_status |= RES_TILE_DEV; - tcell = (tElement *) mallocMagic((unsigned)(sizeof(tElement))); - tcell->te_thist = junk->deviceList; - tcell->te_nextt = NULL; - x = (LEFT(tile) + RIGHT(tile)) >> 1; - y = (TOP(tile) + BOTTOM(tile)) >> 1; - - InitializeNode(resptr, x, y, RES_NODE_JUNCTION); - resptr->rn_te = tcell; - ResAddToQueue(resptr, &ResNodeQueue); - - NEWBREAK(resptr, tp, x, y, NULL); - } - return 0; -} diff --git a/resis/ResReadSim.c b/resis/ResReadSim.c index 61007f2a..85f35f6d 100644 --- a/resis/ResReadSim.c +++ b/resis/ResReadSim.c @@ -382,8 +382,9 @@ ResSimSubckt(line) if (!strcmp(EFDevTypes[j], line[i])) break; - /* Read attributes, especially to pick up values for L, W, X, and Y, - * that are critical for use by extresist. + /* Read attributes, especially to pick up values for L, W, X, and Y; + * and source and drain area and perimeter, that are critical for use + * by extresist. */ for (k = 1; line[k][0] != '\0'; k++) { @@ -406,6 +407,12 @@ ResSimSubckt(line) case 'y': device->location.p_y = (int)((float)atof(eqptr) / lambda); break; + case 's': + device->rs_sattr = StrDup((char **)NULL, eqptr); + break; + case 'd': + device->rs_dattr = StrDup((char **)NULL, eqptr); + break; } } } @@ -531,30 +538,47 @@ ResSimDevice(line, rpersquare, devptr) /* sim attributes look like g=a1,a2 */ /* ext attributes are "a1","a2" */ - /* do conversion from one to the other here */ + /* Do conversion from one to the other here */ + /* NOTE: As of version 8.3.366, .ext attributes will end in two */ + /* integer values, not quoted, for device area and perimeter. Do */ + /* not quote them. */ for (i = RDEV_ATTR; i < RDEV_ATTR + RDEV_NUM_ATTR; i++) { + char *cptr, *sptr; + int d1, d2; + if (line[i][0] == '\0') break; - k = 0; - tmpattr[k++] = '"'; - for (j = 2; line[i][j] != '\0'; j++) + + sptr = &line[i][2]; /* Start after "s=" or "d=" */ + tmpattr[0] = '\0'; + while ((cptr = strchr(sptr, ',')) != NULL) { - if (line[i][j] == ',') + if (sscanf(sptr, "%d,%d", &d1, &d2) == 2) { - tmpattr[k++] = '"'; - tmpattr[k++] = ','; - tmpattr[k++] = '"'; + strcat(tmpattr, sptr); + sptr = NULL; + break; } else { - tmpattr[k++] = line[i][j]; + *cptr = '\0'; + strcat(tmpattr, "\""); + strcat(tmpattr, sptr); + strcat(tmpattr, "\","); + sptr = cptr + 1; + *cptr = ','; } } - tmpattr[k++] = '"'; - tmpattr[k++] = '\0'; - newattr = (char *)mallocMagic((unsigned)k); - strncpy(newattr, tmpattr, k); + if (sptr && (strlen(sptr) != 0)) + { + strcat(tmpattr, "\""); + strcat(tmpattr, sptr); + strcat(tmpattr, "\""); + } + + newattr = (char *)mallocMagic(strlen(tmpattr) + 1); + strcpy(newattr, tmpattr); switch (line[i][0]) { case 'g':