diff --git a/VERSION b/VERSION index d7e92369..ad509384 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.646 +8.3.658 diff --git a/cif/CIFgen.c b/cif/CIFgen.c index 0536078d..57014937 100644 --- a/cif/CIFgen.c +++ b/cif/CIFgen.c @@ -4171,12 +4171,21 @@ cifSrTiles2( } cifScale = 1; - for (t = 0; t < TT_MAXTYPES; t++, temps++) - if (TTMaskHasType(&cifOp->co_cifMask, t)) - if (DBSrPaintArea((Tile *)NULL, *temps, area, + if (TTMaskIsZero(&cifOp->co_cifMask) && TTMaskIsZero(&cifOp->co_paintMask)) + { + /* Current CIF plane is in *temps */ + if (DBSrPaintArea((Tile *)NULL, *temps, area, &CIFSolidBits, func, (ClientData)cdArg)) - return 1; - + return 1; + } + else + { + for (t = 0; t < TT_MAXTYPES; t++, temps++) + if (TTMaskHasType(&cifOp->co_cifMask, t)) + if (DBSrPaintArea((Tile *)NULL, *temps, area, + &CIFSolidBits, func, (ClientData)cdArg)) + return 1; + } return 0; } @@ -5454,7 +5463,6 @@ CIFGenLayer( if (bloats->bl_plane < 0) /* Bloat types are CIF types */ { - bls.temps = temps; for (ttype = 0; ttype < TT_MAXTYPES; ttype++, bls.temps++) if (bloats->bl_distance[ttype] > 0) (void) DBSrPaintArea((Tile *)NULL, *bls.temps, &TiPlaneRect, @@ -5660,6 +5668,20 @@ CIFGenLayer( bloats->bl_distance[ttype] = 0; } } + else + { + /* Operate on the existing plane. */ + + bloats->bl_distance[0] = 1; + for (ttype = 1; ttype < TT_MAXTYPES; ttype++) + bloats->bl_distance[ttype] = 0; + + bloats->bl_plane = -1; + bls.temps = &curPlane; + + DBClearPaintPlane(nextPlane); + cifPlane = nextPlane; + } /* Replace the client data with the bloat record */ op->co_client = (ClientData)bloats; @@ -5680,15 +5702,33 @@ CIFGenLayer( } for (label = cellDef->cd_labels; label; label = label->lab_next) + { if (!strcmp(label->lab_text, text)) - cifSrTiles2(op, &label->lab_rect, cellDef, temps, + { + Rect labr = label->lab_rect; + + /* Since cifSrTiles2() searches over an area, the + * area must not be degenerate. + */ + if (labr.r_xbot == labr.r_xtop) + { + labr.r_xbot--; + labr.r_xtop++; + } + if (labr.r_ybot == labr.r_ytop) + { + labr.r_ybot--; + labr.r_ytop++; + } + cifSrTiles2(op, &labr, cellDef, bls.temps, cifBloatAllFunc, (ClientData)&bls); + } + } /* Reset marked tiles */ if (bloats->bl_plane < 0) /* Bloat types are CIF types */ { - bls.temps = temps; for (ttype = 0; ttype < TT_MAXTYPES; ttype++, bls.temps++) if (bloats->bl_distance[ttype] > 0) (void) DBSrPaintArea((Tile *)NULL, *bls.temps, &TiPlaneRect, @@ -5706,6 +5746,15 @@ CIFGenLayer( /* Replace the client data */ op->co_client = (ClientData)text; + /* If operating on the current plane, swap the current + * and next planes. + */ + if (TTMaskIsZero(&op->co_cifMask) && TTMaskIsZero(&op->co_paintMask)) + { + temp = curPlane; + curPlane = nextPlane; + nextPlane = temp; + } break; case CIFOP_BOUNDARY: diff --git a/cif/CIFrdtech.c b/cif/CIFrdtech.c index 6157e480..efe5ee5e 100644 --- a/cif/CIFrdtech.c +++ b/cif/CIFrdtech.c @@ -1032,9 +1032,10 @@ CIFReadTechLine( newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]); break; case CIFOP_TAGGED: - if (argc != 3) goto wrongNumArgs; + if ((argc != 2) && (argc != 3)) goto wrongNumArgs; newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]); - CIFParseReadLayers(argv[2], &newOp->co_cifMask, TRUE); + if (argc == 3) + CIFParseReadLayers(argv[2], &newOp->co_cifMask, TRUE); break; } diff --git a/cif/CIFtech.c b/cif/CIFtech.c index 9d01468b..f9f983a7 100644 --- a/cif/CIFtech.c +++ b/cif/CIFtech.c @@ -1360,10 +1360,11 @@ bloatCheck: case CIFOP_NET: case CIFOP_TAGGED: - if (argc != 3) goto wrongNumArgs; + if ((argc != 2) && (argc != 3)) goto wrongNumArgs; newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]); - cifParseLayers(argv[2], CIFCurStyle, &newOp->co_paintMask, - &newOp->co_cifMask, FALSE); + if (argc == 3) + cifParseLayers(argv[2], CIFCurStyle, &newOp->co_paintMask, + &newOp->co_cifMask, FALSE); break; case CIFOP_MASKHINTS: diff --git a/commands/CmdE.c b/commands/CmdE.c index df4bc2f1..f3b0a148 100644 --- a/commands/CmdE.c +++ b/commands/CmdE.c @@ -1096,7 +1096,7 @@ CmdExtract( "lumped estimate lumped resistance", "labelcheck check for connections through sticky labels", "aliases output all net name aliases", - "unique ensure unique node names during extraction", + "unique [notopports] ensure unique node names during extraction", "resistance extract resistance (same as \"do extresist\")", NULL }; @@ -1403,6 +1403,7 @@ CmdExtract( TxPrintf("%s label check\n", OPTSET(EXT_DOLABELCHECK)); TxPrintf("%s aliases\n", OPTSET(EXT_DOALIASES)); TxPrintf("%s unique\n", OPTSET(EXT_DOUNIQUE)); + TxPrintf("%s unique notopports\n", OPTSET(EXT_DOUNIQNOTOPPORTS)); TxPrintf("%s resistance (extresist)\n", OPTSET(EXT_DOEXTRESIST)); return; #undef OPTSET @@ -1433,9 +1434,19 @@ CmdExtract( case DORESISTANCE: option = EXT_DORESISTANCE; break; case DOLABELCHECK: option = EXT_DOLABELCHECK; break; case DOALIASES: option = EXT_DOALIASES; break; - case DOUNIQUE: option = EXT_DOUNIQUE; break; case DOEXTRESIST: case DOEXTRESIST2: option = EXT_DOEXTRESIST; break; + case DOUNIQUE: + if (argc == 4) + { + if (!strncmp(argv[3], "notop", 5)) + option = EXT_DOUNIQNOTOPPORTS | EXT_DOUNIQUE; + else + TxError("Usage: extract do unique [notopports]\n"); + } + else + option = EXT_DOUNIQUE; + break; case DOLOCAL: /* "extract do local" and "extract no local" are kept for * backwards compatibility, but now effectively implement diff --git a/commands/CmdLQ.c b/commands/CmdLQ.c index 2c9006d2..6b3245b3 100644 --- a/commands/CmdLQ.c +++ b/commands/CmdLQ.c @@ -2324,7 +2324,7 @@ CmdDoProperty( TxCommand *cmd, int argstart) { - PropertyRecord *proprec; + PropertyRecord *proprec = NULL; char *value; bool propfound, dolist; int proptype, proplen, propvalue, i; @@ -2662,31 +2662,31 @@ CmdDoProperty( * the valid number of arguments, then again to parse the * values, once the property record has been allocated */ - if (proptype == PROPERTY_TYPE_PLANE) + value = cmd->tx_argv[argstart + 1]; + for (proplen = 0; *value != '\0'; ) { - proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord)); - plane = DBNewPlane((ClientData)TT_SPACE); - proprec->prop_value.prop_plane = plane; - } - else - { - value = cmd->tx_argv[argstart + 1]; - for (proplen = 0; *value != '\0'; ) + if (isspace(*value) && (*value != '\0')) value++; + if (!isspace(*value)) { - if (isspace(*value) && (*value != '\0')) value++; - if (!isspace(*value)) - { - proplen++; - while (!isspace(*value) && (*value != '\0')) value++; - } + proplen++; + while (!isspace(*value) && (*value != '\0')) value++; } - if (proplen > 0) + } + if (proplen > 0) + { + if (proptype == PROPERTY_TYPE_PLANE) + { + proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord)); + plane = DBNewPlane((ClientData)TT_SPACE); + proprec->prop_value.prop_plane = plane; + } else { proprec = (PropertyRecord *)mallocMagic( sizeof(PropertyRecord) + (proplen - 2) * sizeof(int)); + } + proprec->prop_type = proptype; + proprec->prop_len = proplen; } - proprec->prop_type = proptype; - proprec->prop_len = proplen; /* Second pass */ value = cmd->tx_argv[argstart + 1]; diff --git a/commands/CmdRS.c b/commands/CmdRS.c index 4ed1f16b..89f30ace 100644 --- a/commands/CmdRS.c +++ b/commands/CmdRS.c @@ -647,6 +647,9 @@ cmdSelectArea( if (!(crec->dbw_flags & DBW_SEELABELS)) TTMaskClearType(&mask, L_LABEL); if (!(crec->dbw_flags & DBW_SEECELLS)) TTMaskClearType(&mask, L_CELL); } + else if (option == SEL_AREA) + TTMaskSetType(&mask, L_LABEL); + SelectArea(&scx, &mask, crec->dbw_bitmask, globmatch); } diff --git a/database/DBconnect.c b/database/DBconnect.c index c8c767ed..a9c7bfdb 100644 --- a/database/DBconnect.c +++ b/database/DBconnect.c @@ -1037,7 +1037,13 @@ dbcConnectFunc(tile, dinfo, cx) if (++csa2->csa2_top == CSA2_LIST_SIZE) { /* Reached list size limit---need to push the list and */ - /* start a new one. */ + /* start a new one. NOTE: Setting lasttop to -1 means */ + /* that some entries may be duplicated between the */ + /* stacks, which is a small inefficiency. In theory, */ + /* lasttop could be left as is, then if lasttop > top */ + /* when searching the last 5 entries, pop the stack, do */ + /* the search, and then push the stack again. But it's */ + /* a lot easier just to be slightly inefficient. */ conSrArea *newlist; @@ -1045,6 +1051,7 @@ dbcConnectFunc(tile, dinfo, cx) StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack); csa2->csa2_list = newlist; csa2->csa2_top = 0; + csa2->csa2_lasttop = -1; } csa2->csa2_list[csa2->csa2_top].area = newarea; diff --git a/database/DBlabel.c b/database/DBlabel.c index a77bdf18..f8e0f58a 100644 --- a/database/DBlabel.c +++ b/database/DBlabel.c @@ -574,7 +574,8 @@ DBReOrientLabel(cellDef, area, newPos) * dbGetLabelArea --- * * Callback function used by DBAdjustLabels. Find all material under a label - * that is *not* the label type, and return the + * that is *not* the label type, and return the label area adjusted to leave + * out that amount. * * Note: This clips in a regular order, and does not consider what is the * largest rectangular area outside the area that has been clipped out. @@ -604,6 +605,26 @@ dbGetLabelArea(tile, dinfo, area) return 0; } +/* + * ---------------------------------------------------------------------------- + * + * dbLabelNotEmpty --- + * + * Callback function used by DBAdjustLabels. Finds any material under a + * label that is the label type, and returns 1 to stop the search. + * + * ---------------------------------------------------------------------------- + */ + +int +dbLabelNotEmpty(tile, dinfo, clientData) + Tile *tile; /* Tile found. */ + TileType dinfo; /* Split tile information (unused) */ + ClientData clientData; /* (unused) */ +{ + return 1; +} + /* * ---------------------------------------------------------------------------- * @@ -661,28 +682,37 @@ DBAdjustLabels(def, area) TTMaskSetOnlyType(&lmask, lab->lab_type); /* To do: Add compatible types (contact, residue) */ - TTMaskCom(&lmask); - r = lab->lab_rect; - DBSrPaintArea((Tile *) NULL, def->cd_planes[DBPlane(lab->lab_type)], - &lab->lab_rect, &lmask, dbGetLabelArea, (ClientData) &r); - - if (!GEO_RECTNULL(&r)) + /* If there is no material left inside the label area, then + * the label gets reassigned to space. + */ + if (DBSrPaintArea((Tile *) NULL, def->cd_planes[DBPlane(lab->lab_type)], + &lab->lab_rect, &lmask, dbLabelNotEmpty, (ClientData)NULL) == 1) { - if ((DBVerbose >= DB_VERBOSE_ALL) && ((def->cd_flags & CDINTERNAL) == 0)) - { - TxPrintf("Adjusting size of label \"%s\" in cell %s.\n", - lab->lab_text, def->cd_name); - } + TTMaskCom(&lmask); - DBUndoEraseLabel(def, lab); - DBWLabelChanged(def, lab, DBW_ALLWINDOWS); - lab->lab_rect = r; - DBFontLabelSetBBox(lab); - DBUndoPutLabel(def, lab); - DBWLabelChanged(def, lab, DBW_ALLWINDOWS); - modified = TRUE; - adjusted = TRUE; + r = lab->lab_rect; + DBSrPaintArea((Tile *) NULL, def->cd_planes[DBPlane(lab->lab_type)], + &lab->lab_rect, &lmask, dbGetLabelArea, (ClientData) &r); + + if (!GEO_RECTNULL(&r)) + { + if ((DBVerbose >= DB_VERBOSE_ALL) && + ((def->cd_flags & CDINTERNAL) == 0)) + { + TxPrintf("Adjusting size of label \"%s\" in cell %s.\n", + lab->lab_text, def->cd_name); + } + + DBUndoEraseLabel(def, lab); + DBWLabelChanged(def, lab, DBW_ALLWINDOWS); + lab->lab_rect = r; + DBFontLabelSetBBox(lab); + DBUndoPutLabel(def, lab); + DBWLabelChanged(def, lab, DBW_ALLWINDOWS); + modified = TRUE; + adjusted = TRUE; + } } } diff --git a/database/database.h.in b/database/database.h.in index d1e7385b..3f184c10 100644 --- a/database/database.h.in +++ b/database/database.h.in @@ -578,6 +578,20 @@ typedef struct extRectList struct extRectList *r_next; } ExtRectList; +/* Structure similar to the above, but adding a pointer to a cell use ID + * and a client data record which can be used to hold a region pointer. + */ + +typedef struct extConnList +{ + char *r_useid; /* Cell Use being connected to */ + TileType r_type; /* Connecting tile type in the parent */ + Rect r_r; /* Area of connection */ + ClientData r_upnode; /* Parent node making the connection */ + ClientData r_downnode; /* Child node making the connection */ + struct extConnList *r_next; /* Next item in the linked list */ +} ExtConnList; + /* -------------------- Search context information -------------------- */ /* Search contexts are used in hierarchical searches */ diff --git a/doc/html/extract.html b/doc/html/extract.html index 101ab739..b1926498 100644 --- a/doc/html/extract.html +++ b/doc/html/extract.html @@ -102,16 +102,17 @@ Circuit netlist extractor but will usually just slow down processing by commands like "ext2spice" that use the .ext file contents, so it is disabled by default. -
unique +
unique [notopports]
(Added in magic version 8.3.594) This setting replaces - the use of the command option "extract unique". Instead - of changing labels in the design, unique labels are - generated for the duration of the extraction, and then - reverted back to the original text. The "extract unique" - command option is maintained for backwards compatibility. - Note the difference: "extract unique" is a command that - runs immediately, and cannot be undone; - "extract do unique" is an option setting for "extract". + the use of the command option "extract unique" (and + "extract unique notopports"). Instead of changing labels + in the design, unique labels are generated for the duration + of the extraction, and then reverted back to the original + text. The "extract unique" command option is maintained + for backwards compatibility. Note the difference: + "extract unique" is a command that runs immediately, and + cannot be undone; "extract do unique" is an option setting + for "extract".
resistance
(Added in magic version 8.3.597) This setting replaces the use of the standalone command "extresist". The diff --git a/doc/html/extresist.html b/doc/html/extresist.html index 9b9d7b13..379260b0 100644 --- a/doc/html/extresist.html +++ b/doc/html/extresist.html @@ -30,11 +30,30 @@ information.
where option may be one of the following:
-
tolerance value -
Set the ratio between resistor and transistor tolerance - for determining when to insert resistance into a network route.
all
Extract all the nets. +
threshold [value] +
With no value given, returns the current lumped resistance + threshold used to determine if a network will or will not be + analyzed for resistance extraction, in milliohms. The default + threshold value is 10000 milliohms (10 ohms). If + value is given, then set the lumped resistance threshold + to value milliohms. +
mindelay [value] +
With no value given, returns the current delay time threshold + used to determine if a network will or will not be analyzed for + resistance extraction, in picoseconds. The default + mindelay value is 1ps. If value is given, + then set the delay threshold to value picoseconds. +
minres [value] +
With no value given, returns the current absolute resistance + threshold used to prune small resistances from a network when + simplifying, in milliohms. The default minres value + is 1000 milliohms (1 ohm). If value is given, then set + the absolute resistance threshold to value milliohms. + Note that resistances smaller than value may still + appear in the output netlist if the algorithm is unable to + simplify the network around the resistor.
simplify [on|off]
Turn on/off simplification of resistor nets.
extout [on|off] @@ -42,7 +61,9 @@ information.
lumped [on|off]
Turn on/off writing of updated lumped resistances.
silent [on|off] -
Turn off/on printing of net statistics. +
Turn off/on printing of nets being processed. +
debug [on|off] +
Turn off/on additional diagnostic information.
skip mask
Don't extract types indicated in the comma-separated list mask
ignore [netname|none] @@ -69,6 +90,8 @@ information. .fh file. If freq is specified, the file will be customized for fasthenry analysis at the indicated frequency (in Hz). +
tolerance value +
Deprecated! This option is no longer used by extresist.
help
Print help information
@@ -79,9 +102,9 @@ information.
The normal flow through layout extraction into a simulation file treats routes as nonphysical entities, that is, with infinitesimal - impedence through the wires. Extraction for digital simulation - using irsim generates "lumped resistances", a single - resistance per network node that, along with the node capacitance + impedence through the wires. Standard extraction generates "lumped + resistance" values, a single resistance per network node that, along + with the node capacitance to substrate, provides an RC time constant to approximately model the delay from point to point in the network node. The lumped resistance model is inappropriate for analog (i.e., SPICE) @@ -96,10 +119,9 @@ information. Using extresist as a standalone command is a multi-step process. It is first necessary to run extract to get - the initial netlist. - After a .ext file has been generated, the - extresist command may be run. The output is - a file .res.ext for each cell in the hierarchy. + the initial netlist. After a .ext file has been generated, + the extresist command may be run. The output is a file + .res.ext for each cell in the hierarchy. Finally, with the option extresist on set, ext2spice will generate the final, detailed simulation file.

@@ -110,7 +132,42 @@ information. magic version 8.3.597 an option extract do resistance that runs the resistance extraction in sequence with the regular extraction, producing both the .ext and .res.ext - files. + files. When extract do resistance is used, there is no need + to run extresist as a separate command. However, + extresist may be run prior to extract to set the + options that affect resistance network extraction, such as + extresist threshold, extresist minres, etc.

+ + As of magic version 8.3.653, the extresist tolerance option + is deprecated and has no effect on network resistance extraction. + Instead, extraction is controlled by three main options:

+ + extresist threshold (value in milliohms) sets a cutoff for + considering a network for detailed resistance extraction based on + the lumped resistance estimate (see above). For point-to-point + wires, the lumped resistance is approximately equal to the actual + wire resistance. For branching networks, it will generally be an + over-estimate. The default threshold value is set to + 10 ohms.

+ + extresist minres (value in milliohms) sets a cutoff for + individual resistors in the detailed resistor network. Resistors + below this threshold will get pruned out of the network if the + simplification algorithm is able to remove them. The default + minres value is set to 1 ohm.

+ + extresist mindelay (value in picoseconds) sets a cutoff for + considering a network for detailed resistance extraction based on + the end-to-end delay calculated from the lumped resistance + estimate. Once the network has been extracted, the mindelay + value is again evaluated against a revised calculation of the + delay to determine if the extracted detailed network should be + output. The default mindelay value is set to 0, indicating + that only the lumped resistance threshold should be used for + determining when to extract a detailed resistance network. + mindelay may be used in place of threshold, or both + may be used together, in which case a network is only extracted + if both threshold and mindelay are exceeded.

More details on using extresist can be found in magic Tutorial number 8. @@ -134,6 +191,6 @@ information. Return to command index -

Last updated: October 4, 2021 at 3:32pm

+

Last updated: May 29, 2026 at 11:33am

diff --git a/ext2spice/ext2hier.c b/ext2spice/ext2hier.c index cb7a94e5..a6bfa79a 100644 --- a/ext2spice/ext2hier.c +++ b/ext2spice/ext2hier.c @@ -757,7 +757,7 @@ spcdevHierVisit( case DEV_FET: if (source == drain) { - if (esFormat == NGSPICE) fprintf(esSpiceF, "$ "); + if (esFormat == NGSPICE) fprintf(esSpiceF, "; "); fprintf(esSpiceF, "** SOURCE/DRAIN TIED\n"); } break; @@ -765,7 +765,7 @@ spcdevHierVisit( default: if (gate == source) { - if (esFormat == NGSPICE) fprintf(esSpiceF, "$ "); + if (esFormat == NGSPICE) fprintf(esSpiceF, "; "); fprintf(esSpiceF, "** SHORTED DEVICE\n"); } break; @@ -1658,7 +1658,7 @@ spcnodeHierVisit( static char ntmp[MAX_STR_SIZE]; EFHNSprintf(ntmp, hierName); - if (esFormat == NGSPICE) fprintf(esSpiceF, " $ "); + if (esFormat == NGSPICE) fprintf(esSpiceF, " ; "); fprintf(esSpiceF, "** %s == %s\n", ntmp, nsn); } cap = cap / 1000; @@ -1668,14 +1668,14 @@ spcnodeHierVisit( esSIvalue(esSpiceF, 1.0E-15 * cap); if (!isConnected) { - if (esFormat == NGSPICE) fprintf(esSpiceF, " $"); + if (esFormat == NGSPICE) fprintf(esSpiceF, " ;"); fprintf(esSpiceF, " **FLOATING"); } fprintf(esSpiceF, "\n"); } if (node->efnode_attrs && !esNoAttrs) { - if (esFormat == NGSPICE) fprintf(esSpiceF, " $ "); + if (esFormat == NGSPICE) fprintf(esSpiceF, " ; "); fprintf(esSpiceF, "**nodeattr %s :",nsn ); for (fmt = " %s", ap = node->efnode_attrs; ap; ap = ap->efa_next) { diff --git a/ext2spice/ext2spice.c b/ext2spice/ext2spice.c index 45a6696c..0c3a0094 100644 --- a/ext2spice/ext2spice.c +++ b/ext2spice/ext2spice.c @@ -2817,7 +2817,7 @@ spcdevVisit( case DEV_FET: if (source == drain) { - if (esFormat == NGSPICE) fprintf(esSpiceF, "$ "); + if (esFormat == NGSPICE) fprintf(esSpiceF, "; "); fprintf(esSpiceF, "** SOURCE/DRAIN TIED\n"); } break; @@ -2825,7 +2825,7 @@ spcdevVisit( default: if (gate == source) { - if (esFormat == NGSPICE) fprintf(esSpiceF, "$ "); + if (esFormat == NGSPICE) fprintf(esSpiceF, "; "); fprintf(esSpiceF, "** SHORTED DEVICE\n"); } break; @@ -4111,7 +4111,7 @@ spcnodeVisit( static char ntmp[MAX_STR_SIZE]; EFHNSprintf(ntmp, hierName); - if (esFormat == NGSPICE) fprintf(esSpiceF, "$ "); + if (esFormat == NGSPICE) fprintf(esSpiceF, "; "); fprintf(esSpiceF, "** %s == %s\n", ntmp, nsn); } cap = cap / 1000; @@ -4121,14 +4121,14 @@ spcnodeVisit( esSIvalue(esSpiceF, 1.0E-15 * cap); if (!isConnected) { - if (esFormat == NGSPICE) fprintf(esSpiceF, " $"); + if (esFormat == NGSPICE) fprintf(esSpiceF, " ;"); fprintf(esSpiceF, " **FLOATING"); } fprintf(esSpiceF, "\n"); } if (node->efnode_attrs && !esNoAttrs) { - if (esFormat == NGSPICE) fprintf(esSpiceF, " $ "); + if (esFormat == NGSPICE) fprintf(esSpiceF, " ; "); fprintf(esSpiceF, "**nodeattr %s :",nsn ); for (fmt = " %s", ap = node->efnode_attrs; ap; ap = ap->efa_next) { diff --git a/extflat/EFbuild.c b/extflat/EFbuild.c index 65f485da..3f58267d 100644 --- a/extflat/EFbuild.c +++ b/extflat/EFbuild.c @@ -706,6 +706,11 @@ efBuildEquiv(def, nodeName1, nodeName2, resist, isspice) dev->dev_terms[n].dterm_node = (nn1->efnn_node == NULL) ? nn2->efnn_node : nn1->efnn_node; + + /* Also check the substrate terminal */ + if (dev->dev_subsnode == lostnode) + dev->dev_subsnode = (nn1->efnn_node == NULL) ? + nn2->efnn_node : nn1->efnn_node; } /* If a node has been merged away, make sure that its name */ @@ -1618,12 +1623,128 @@ efConnectionFreeLinkedList(Connection *conn) } } +/* + * ---------------------------------------------------------------------------- + * + * efConnPointFreeLinkedList -- + * + * Release memory for linked-list of ConnectionPoint* based on internal + * list at ConnectionPoint->conn_next. 'connpt' argument must be non-NULL. + * + * Results: + * Deallocates linked-list of ConnectionPoint* starting at 'connpt' + * + * Side effects: + * Deallocates one or more connection point record(s). + * + * ---------------------------------------------------------------------------- + */ + +void +efConnPointFreeLinkedList(ConnectionPoint *connpt) +{ + while (connpt) + { + ConnectionPoint *next = connpt->conn_next; + if (connpt->conn_name != NULL) + freeMagic(connpt->conn_name); + freeMagic(connpt); + connpt = next; + } +} + /* * ---------------------------------------------------------------------------- * * efBuildConnect -- * * Process a "connect" line from a .ext file. + * Creates a record of the area and type of the connection. Since the + * extraction at the point of finding connections no longer knows what + * net in the celldef (if any) is part of the connection, only the + * location and type is preserved, and the cell being connected has to + * be recovered by a search on the celldef's layout. These records are + * used only by "extresist". + * + * Results: + * None. + * + * Side effects: + * Allocates a new connection port record for extresist, and prepends + * it to the list for def. + * + * ---------------------------------------------------------------------------- + */ + +void +efBuildConnect(def, llx, lly, urx, ury, layerName, upnodeName, downnodeName) + Def *def; + int llx, lly, urx, ury; + char *layerName; + char *upnodeName; + char *downnodeName; +{ + int tnew; + ConnectionPoint *connpt; + HashEntry *he; + Use *subuse; + char *hierptr, *qptr, *useid; + + /* Can't do anything without a node name to connect to */ + if (!strcmp(downnodeName, "\"None\"")) return; + + /* "downnodeName" should be hierarchical; stop at the first hierarchical + * divider and use the prefix to find the use being connected to. + * NOTE: This will require dealing with connections that are more than + * one hierarchical level deep (to be done). + */ + useid = downnodeName; + if (*useid == '"') useid++; + hierptr = strchr(useid, '/'); + if (hierptr != NULL) *hierptr = '\0'; + qptr = strrchr(useid, '"'); + if (qptr != NULL) *qptr = '\0'; + + if (layerName) + tnew = efBuildAddStr(EFLayerNames, &EFLayerNumNames, MAXTYPES, layerName); + else + tnew = 0; + + connpt = (ConnectionPoint *)mallocMagic(sizeof(ConnectionPoint)); + + he = HashFind(&def->def_uses, useid); + subuse = (Use *)HashGetValue(he); + connpt->conn_use = subuse; + + connpt->conn_r.r_xbot = llx; + connpt->conn_r.r_ybot = lly; + connpt->conn_r.r_xtop = urx; + connpt->conn_r.r_ytop = ury; + connpt->conn_type = tnew; + if (!strcmp(upnodeName, "\"None\"")) + connpt->conn_name = (char *)NULL; + else + { + if (*upnodeName == '"') upnodeName++; + connpt->conn_name = StrDup((char **)NULL, upnodeName); + if ((qptr = strrchr(connpt->conn_name, '"')) != NULL) *qptr = '\0'; + } + + /* To do: Add "downnodeName" to the ConnectionPoint structure. This + * may not be necessary, as it is only being used by "extresist" which + * is not using the extflat parser. + */ + + connpt->conn_next = def->def_connpts; + def->def_connpts = connpt; +} + +/* + * ---------------------------------------------------------------------------- + * + * efBuildMerge -- + * + * Process a "merge" line from a .ext file. * Creates a connection record for the names 'nodeName1' and * 'nodeName2'. * @@ -1638,7 +1759,7 @@ efConnectionFreeLinkedList(Connection *conn) */ void -efBuildConnect(def, nodeName1, nodeName2, deltaC, av, ac) +efBuildMerge(def, nodeName1, nodeName2, deltaC, av, ac) Def *def; /* Def to which this connection is to be added */ char *nodeName1; /* Name of first node in connection */ char *nodeName2; /* Name of other node in connection */ diff --git a/extflat/EFdef.c b/extflat/EFdef.c index 291c8315..bc7b6089 100644 --- a/extflat/EFdef.c +++ b/extflat/EFdef.c @@ -122,6 +122,7 @@ EFDone(func) efConnectionFreeLinkedList(def->def_conns); efConnectionFreeLinkedList(def->def_caps); efConnectionFreeLinkedList(def->def_resistors); + efConnPointFreeLinkedList(def->def_connpts); free_magic1_t mm1 = freeMagic1_init(); for (kill = def->def_kills; kill; kill = kill->kill_next) @@ -248,6 +249,7 @@ efDefNew(name) newdef->def_conns = (Connection *) NULL; newdef->def_caps = (Connection *) NULL; newdef->def_resistors = (Connection *) NULL; + newdef->def_connpts = (ConnectionPoint *) NULL; newdef->def_kills = (Kill *) NULL; /* Initialize circular list of nodes */ diff --git a/extflat/EFhier.c b/extflat/EFhier.c index 594f95a8..e604823e 100644 --- a/extflat/EFhier.c +++ b/extflat/EFhier.c @@ -32,6 +32,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "utils/utils.h" #include "extflat/extflat.h" #include "extflat/EFint.h" +#include "textio/textio.h" /* * ---------------------------------------------------------------------------- @@ -491,7 +492,13 @@ efHierVisitDevs(hc, ca) { dev = (Dev *)HashGetValue(he); if (efHierDevKilled(hc, dev, hc->hc_hierName)) - continue; + { + TxError("Error: Device at (%d %d) is connected to one or more" + " eliminated nodes.\n", + dev->dev_rect.r_xbot, dev->dev_rect.r_ybot); + /* Output the device anyway, but something needs fixing */ + // continue; + } const cb_extflat_hiervisitdevs_t ca_hiervisitdevs_proc = (cb_extflat_hiervisitdevs_t) ca->ca_proc; /* FIXME temporary */ if ((*ca_hiervisitdevs_proc)(hc, dev, scale, ca->ca_cdata)) /* @invoke cb_extflat_hiervisitdevs_t */ diff --git a/extflat/EFint.h b/extflat/EFint.h index 92653734..9f223162 100644 --- a/extflat/EFint.h +++ b/extflat/EFint.h @@ -145,6 +145,8 @@ typedef struct conn #define conn_res conn_value.conn_val_res #define conn_cap conn_value.conn_val_cap +typedef struct connpoint ConnectionPoint; + /* -------------------------- Defs and uses --------------------------- */ /* A Def exists for each .ext file */ @@ -162,6 +164,7 @@ typedef struct def /* The following are all NULL-terminated lists */ Connection *def_conns; /* Hierarchical connections/adjustments */ + ConnectionPoint *def_connpts; /* Position of hierarchical connections */ Connection *def_caps; /* Two-terminal capacitors */ Connection *def_resistors; /* Two-terminal resistors */ Kill *def_kills; /* Used to modify hierarchical structure @@ -206,6 +209,17 @@ typedef struct use #define IsArray(u) ((u)->use_xlo!=(u)->use_xhi || (u)->use_ylo!=(u)->use_yhi) +/* Connection point structure (used by "extresist") */ + +typedef struct connpoint +{ + Use *conn_use; /* Use being connected to */ + Rect conn_r; /* Area, edge, or point of connection */ + int conn_type; /* A tile type at the connection */ + char *conn_name; /* Top level name of node, or NULL */ + struct connpoint *conn_next; /* Next connection point in list */ +} ConnectionPoint; + /* -------------------------------------------------------------------- */ /* Structure passed down during hierarchical searching */ @@ -307,7 +321,9 @@ extern void CapHashSetValue(); extern DevParam *efGetDeviceParams(); extern void efBuildNode(); extern void efConnectionFreeLinkedList(Connection *conn); +extern void efConnPointFreeLinkedList(ConnectionPoint *conn); extern void efBuildConnect(); +extern void efBuildMerge(); extern void efBuildResistor(); extern void efBuildCap(); extern HierContext *EFFlatBuildOneLevel(); diff --git a/extflat/EFread.c b/extflat/EFread.c index e4c2253e..9abc979c 100644 --- a/extflat/EFread.c +++ b/extflat/EFread.c @@ -275,15 +275,11 @@ readfile: efBuildCap(def, argv[1], argv[2], (double) cap); break; - /* subcap node capacitance */ - case SUBCAP: - cap = cscale*atoCap(argv[2]); - efAdjustSubCap(def, argv[1], cap); - break; - - /* equiv node1 node2 */ - case EQUIV: - efBuildEquiv(def, argv[1], argv[2], resist, isspice); + /* connect useid llx lly urx ury type "node" ... */ + case CONNECT: + efBuildConnect(def, atoi(argv[1]), atoi(argv[2]), + atoi(argv[3]), atoi(argv[4]), argv[5], + argv[6], argv[7]); break; /* replaces "fet" (below) */ @@ -337,6 +333,28 @@ readfile: r.r_xtop = (int)(0.5 + (float)atoi(argv[5]) * locScale); r.r_ytop = (int)(0.5 + (float)atoi(argv[6]) * locScale); + if (!strcmp(argv[2], "Short")) + { + /* Device name "Short" is a reserved name indicating + * that the device does not get output but acts as a + * short between the first two terminals. Consequently, + * it acts like an "equiv" statement. However, unlike + * regular "equiv" statements, it should always merge + * the nodes, so do not pass "resis" to efBuildEquiv(). + */ + int argstart = 7; + /* "Short" devices should not have parameters, but just in + * case, skip over any that are found. + */ + while (strchr(argv[argstart], '=') != NULL) argstart++; + if (argstart + 4 >= argc) + efReadError("Bad terminal description for Short device\n"); + else + efBuildEquiv(def, argv[argstart + 1], argv[argstart + 4], + FALSE, isspice); + break; + } + if (efBuildDevice(def, (char)n, argv[2], &r, argc - 7, &argv[7]) != 0) { efReadError("Incomplete terminal description for device\n"); @@ -344,6 +362,11 @@ readfile: } break; + /* equiv node1 node2 */ + case EQUIV: + efBuildEquiv(def, argv[1], argv[2], resist, isspice); + break; + /* for backwards compatibility */ /* fet type xlo ylo xhi yhi area perim substrate GATE T1 T2 ... */ case FET: @@ -373,7 +396,7 @@ readfile: */ cap = (argc > 3) ? atoCap(argv[3]) * cscale : 0; - efBuildConnect(def, argv[1], argv[2], (double)cap, &argv[4], argc - 4); + efBuildMerge(def, argv[1], argv[2], (double)cap, &argv[4], argc - 4); break; /* node name R C x y layer a1 p1 a2 p2 ... [ attrs ] */ @@ -449,6 +472,12 @@ resistChanged: } break; + /* subcap node capacitance */ + case SUBCAP: + cap = cscale*atoCap(argv[2]); + efAdjustSubCap(def, argv[1], cap); + break; + /* use def use-id T0 .. T5 */ case USE: efBuildUse(def, argv[1], argv[2], diff --git a/extflat/extparse.h b/extflat/extparse.h index a688bde7..bb39a897 100644 --- a/extflat/extparse.h +++ b/extflat/extparse.h @@ -25,9 +25,9 @@ */ typedef enum { - ABSTRACT, ADJUST, ATTR, CAP, DEVICE, DIST, EQUIV, FET, KILLNODE, MERGE, - NODE, PARAMETERS, PORT, PRIMITIVE, RESISTOR, RESISTCLASS, RNODE, SCALE, - SUBCAP, SUBSTRATE, TECH, TIMESTAMP, USE, VERSION, EXT_STYLE + ABSTRACT, ADJUST, ATTR, CAP, CONNECT, DEVICE, DIST, EQUIV, FET, KILLNODE, + MERGE, NODE, PARAMETERS, PORT, PRIMITIVE, RESISTOR, RESISTCLASS, RNODE, + SCALE, SUBCAP, SUBSTRATE, TECH, TIMESTAMP, USE, VERSION, EXT_STYLE } Key; static const struct @@ -42,6 +42,7 @@ keyTable[] = {"adjust", ADJUST, 4}, {"attr", ATTR, 8}, {"cap", CAP, 4}, + {"connect", CONNECT, 7}, {"device", DEVICE, 11}, /* effectively replaces "fet" */ {"distance", DIST, 4}, {"equiv", EQUIV, 3}, diff --git a/extract/ExtBasic.c b/extract/ExtBasic.c index 2606af05..d6e14fff 100644 --- a/extract/ExtBasic.c +++ b/extract/ExtBasic.c @@ -629,6 +629,8 @@ extSetResist(reg) for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++) { + ResValue resnew, restot; + reg->nreg_pa[n].pa_area = area = extResistArea[n]; reg->nreg_pa[n].pa_perim = perim = extResistPerim[n]; if (area > 0 && perim > 0) @@ -639,8 +641,15 @@ extSetResist(reg) if (v < 0) s = 0; else s = sqrt(v); fperim = (float) perim; - reg->nreg_resist += (fperim + s) / (fperim - s) - * ExtCurStyle->exts_resistByResistClass[n]; + resnew = (fperim + s) / (fperim - s) * + ExtCurStyle->exts_resistByResistClass[n]; + restot = reg->nreg_resist + resnew; + + /* Check for integer overflow. There is no point in trying + * to accommodate huge resistance values for an estimate. + * The value just saturates at the maximum integer value. + */ + if (restot > 0) reg->nreg_resist = restot; } /* Reset for the next pass */ @@ -722,7 +731,8 @@ extOutputNodes(nodeList, outFile) /* Check if this node is the substrate */ if (reg == glob_subsnode) { - fprintf(outFile, "substrate \"%s\" 0 0", text); + intR = (reg->nreg_resist + rround) / ExtCurStyle->exts_resistScale; + fprintf(outFile, "substrate \"%s\" %d 0", text, intR); } else { @@ -1110,7 +1120,7 @@ ExtSortTerminals(tran, ll) do { changed = 0; - for( nsd = 0; nsd < tran->tr_nterm-1; nsd++ ) + for (nsd = 0; nsd < tran->tr_nterm-1; nsd++) { p1 = &(tran->tr_termpos[nsd]); p2 = &(tran->tr_termpos[nsd+1]); @@ -1155,14 +1165,17 @@ ExtSortTerminals(tran, ll) * 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 ; - for ( lp = ll ; lp ; lp = lp->ll_next ) - if ( lp->ll_attr == LL_SORTATTR ) lp->ll_attr = nsd+1; + 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; + for (lp = ll; lp; lp = lp->ll_next) + if (lp->ll_attr == LL_SORTATTR) + lp->ll_attr = nsd + 1; } } - while( changed ); + while (changed); } /* @@ -2652,30 +2665,6 @@ extOutputDevices(def, transList, outFile) if (!strcmp(devptr->exts_deviceName, "Ignore")) continue; - /* Model type "Short" in the techfile indicates a device */ - /* to short across the first two nodes (the gate and the */ - /* source). This solves the specific issue of a transistor */ - /* extended drain where the drain is a resistor but the */ - /* resistor is part of the model and should not be output. */ - - if (!strcmp(devptr->exts_deviceName, "Short")) - { - fprintf(outFile, "equiv "); - - /* To do: Use parameters to specify which terminals */ - /* are shorted. */ - - /* gate */ - node = (NodeRegion *)ExtGetRegion(reg->treg_tile, reg->treg_dinfo); - fprintf(outFile, "\"%s\" ", extNodeName((LabRegion *)node)); - - /* First non-gate terminal */ - node = (NodeRegion *)extTransRec.tr_termnode[0]; - fprintf(outFile, "\"%s\"\n", extNodeName((LabRegion *)node)); - - continue; - } - /* Original-style FET record backward compatibility */ if (devptr->exts_deviceClass != DEV_FET) fprintf(outFile, "device "); diff --git a/extract/ExtCell.c b/extract/ExtCell.c index c6def9fe..46be433e 100644 --- a/extract/ExtCell.c +++ b/extract/ExtCell.c @@ -76,18 +76,19 @@ void extHeader(); */ Plane * -ExtCell(def, outName, doLength) +ExtCell(def, outName, isTop) CellDef *def; /* Cell being extracted */ char *outName; /* Name of output file; if NULL, derive from def name */ - bool doLength; /* If TRUE, extract pathlengths from drivers to - * receivers (the names are stored in ExtLength.c). - * Should only be TRUE for the root cell in a - * hierarchy. - */ + bool isTop; /* If TRUE, cell is the top level cell */ { char *filename; FILE *f = NULL; Plane *savePlane; + bool noextract; + + /* If marked abstract, then don't extract the cell */ + DBPropGet(def, "noextract", &noextract); + if (noextract) return extPrepSubstrate(def); /* Incremental extraction: If the cell is marked for no extraction, * then just prepare the substrate plane and return it to the caller. @@ -111,7 +112,7 @@ ExtCell(def, outName, doLength) } extNumErrors = extNumWarnings = 0; - savePlane = extCellFile(def, f, doLength); + savePlane = extCellFile(def, f, isTop); if (f != NULL) fclose(f); if (extNumErrors > 0 || extNumWarnings > 0) @@ -471,13 +472,10 @@ ExtRevertSubstrate(def, savePlane) */ Plane * -extCellFile(def, f, doLength) +extCellFile(def, f, isTop) CellDef *def; /* Def to be extracted */ FILE *f; /* Output to this file */ - bool doLength; /* TRUE if we should extract driver-receiver path - * length information for this cell (see ExtCell - * for more details). - */ + bool isTop; /* TRUE if the cell is the top level cell */ { NodeRegion *reg; Plane *saveSub; @@ -488,8 +486,19 @@ extCellFile(def, f, doLength) /* If "extract do unique" was specified, then make labels in the * cell unique. */ + if (ExtOptions & EXT_DOUNIQUE) - extUniqueCell(def, EXT_UNIQ_TEMP); + { + if (ExtOptions & EXT_DOUNIQNOTOPPORTS) + { + if (isTop) + extUniqueCell(def, EXT_UNIQ_TEMP_NOPORTS); + else + extUniqueCell(def, EXT_UNIQ_TEMP); + } + else + extUniqueCell(def, EXT_UNIQ_TEMP); + } /* Prep any isolated substrate areas */ if (ExtOptions & EXT_DOEXTRESIST) @@ -519,7 +528,7 @@ extCellFile(def, f, doLength) ExtResetTiles(def, CLIENTDEFAULT); /* Final pass: extract length information if desired */ - if (!SigInterruptPending && doLength && (ExtOptions & EXT_DOLENGTH)) + if (!SigInterruptPending && isTop && (ExtOptions & EXT_DOLENGTH)) extLength(extParentUse, f); UndoEnable(); diff --git a/extract/ExtHier.c b/extract/ExtHier.c index 5429ebf0..09df8ae5 100644 --- a/extract/ExtHier.c +++ b/extract/ExtHier.c @@ -281,6 +281,13 @@ extHierSubstrate(ha, use, x, y) nn->nn_next = node2->node_names->nn_next; node2->node_names->nn_next = node1->node_names; node2->node_len += node1->node_len; + if (node2->node_ports) + { + ExtConnList *nport; + for (nport = node2->node_ports; nport && nport->r_next; + nport = nport->r_next); + if (nport) nport->r_next = node1->node_ports; + } freeMagic((char *)node1); } else @@ -294,6 +301,13 @@ extHierSubstrate(ha, use, x, y) nn->nn_next = node1->node_names; node1->node_names = node2->node_names; node1->node_len += node2->node_len; + if (node1->node_ports) + { + ExtConnList *nport; + for (nport = node1->node_ports; nport && nport->r_next; + nport = nport->r_next); + if (nport) nport->r_next = node2->node_ports; + } freeMagic((char *)node2); } } @@ -499,6 +513,13 @@ extHierConnectFunc1(oneTile, dinfo, ha) nn->nn_next = node2->node_names->nn_next; node2->node_names->nn_next = node1->node_names; node2->node_len += node1->node_len; + if (node2->node_ports) + { + ExtConnList *nport; + for (nport = node2->node_ports; nport && nport->r_next; + nport = nport->r_next); + if (nport) nport->r_next = node1->node_ports; + } freeMagic((char *) node1); } else @@ -514,6 +535,13 @@ extHierConnectFunc1(oneTile, dinfo, ha) nn->nn_next = node1->node_names; node1->node_names = node2->node_names; node1->node_len += node2->node_len; + if (node1->node_ports) + { + ExtConnList *nport; + for (nport = node1->node_ports; nport && nport->r_next; + nport = nport->r_next); + if (nport) nport->r_next = node2->node_ports; + } freeMagic((char *) node2); } } @@ -523,6 +551,48 @@ extHierConnectFunc1(oneTile, dinfo, ha) } /* + *------------------------------------------------------------------------ + * + * extHierFindTopNode -- + * + * Simple callback function used in extHierConnectFunc2() to retrieve + * the node name of a node in the CellDef being extracted at a specific + * point. If there is no node at that point (indicating that there is + * paint in a subcell at that location but no paint in the top level + * cell) then return NULL. + * + * Returns: + * 1 if a node is found, otherwise 0 to keep the search going. + * + * Side effects: + * A pointer to the node is returned in the clientData field. + * + *------------------------------------------------------------------------ + */ + +int +extHierFindTopNode(Tile *tile, + TileType dinfo, + ExtRegion **nreg) +{ + ExtRegion *tireg; + + tireg = (ExtRegion *)ExtGetRegion(tile, dinfo); + if ((ClientData)tireg == CLIENTDEFAULT) + { + *nreg = (ExtRegion *)0; + return 0; + } + else + { + *nreg = tireg; + return 1; + } +} + +/* + *------------------------------------------------------------------------ + * * extHierConnectFunc2 -- * * Called once for each tile 'cum' in extHierCumFlat->et_use->cu_def @@ -538,6 +608,8 @@ extHierConnectFunc1(oneTile, dinfo, ha) * if the types of ha->hierOneTile and 'cum' connect. * Otherwise, if the tiles actually overlap (as opposed * to merely abut), mark it with feedback as an error. + * + *------------------------------------------------------------------------ */ int @@ -608,6 +680,53 @@ extHierConnectFunc2(cum, dinfo, ha) if (node1 != node2) { + ExtConnList *newport; + int pNum; + + if (ExtOptions & EXT_DOEXTRESIST) + { + NodeRegion *topnode = NULL; + + /* Record the area of connection for both nodes in their + * respective coordinate systems, and the name of the + * cell use to which the connection is made. + */ + newport = (ExtConnList *)mallocMagic(sizeof(ExtConnList)); + newport->r_r = r; + newport->r_type = ttype; + newport->r_useid = ha->ha_subUse->cu_id; + + /* Find a node at the given location in et_lookNames (the + * original CellDef being extracted). If there is no node + * in the def itself then the entry is NULL. + */ + for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) + { + if (TTMaskHasType(&DBPlaneTypes[pNum], ttype)) + { + /* Make sure that the rect is not zero area */ + if (r.r_xtop == r.r_xbot) + { + r.r_xtop++; + r.r_xbot--; + } + if (r.r_ytop == r.r_ybot) + { + r.r_ytop++; + r.r_ybot--; + } + + DBSrPaintArea((Tile *)NULL, + ha->ha_cumFlat.et_lookNames->cd_planes[pNum], + &r, &DBConnectTbl[ttype], extHierFindTopNode, + (ClientData)PTR2CD(&topnode)); + newport->r_upnode = PTR2CD(topnode); + + newport->r_downnode = PTR2CD(node2->node_names); + } + } + } + if (node1->node_len < node2->node_len) { /* @@ -622,6 +741,12 @@ extHierConnectFunc2(cum, dinfo, ha) node2->node_names->nn_next = node1->node_names; node2->node_len += node1->node_len; freeMagic((char *) node1); + + if (ExtOptions & EXT_DOEXTRESIST) + { + newport->r_next = node2->node_ports; + node2->node_ports = newport; + } } else { @@ -637,6 +762,12 @@ extHierConnectFunc2(cum, dinfo, ha) node1->node_names = node2->node_names; node1->node_len += node2->node_len; freeMagic((char *) node2); + + if (ExtOptions & EXT_DOEXTRESIST) + { + newport->r_next = node1->node_ports; + node1->node_ports = newport; + } } } } @@ -733,6 +864,13 @@ extHierConnectFunc3(cum, dinfo, ha) nn->nn_next = node2->node_names->nn_next; node2->node_names->nn_next = node1->node_names; node2->node_len += node1->node_len; + if (node2->node_ports) + { + ExtConnList *nport; + for (nport = node2->node_ports; nport && nport->r_next; + nport = nport->r_next); + if (nport) nport->r_next = node1->node_ports; + } freeMagic((char *) node1); } else @@ -748,6 +886,13 @@ extHierConnectFunc3(cum, dinfo, ha) nn->nn_next = node1->node_names; node1->node_names = node2->node_names; node1->node_len += node2->node_len; + if (node1->node_ports) + { + ExtConnList *nport; + for (nport = node1->node_ports; nport && nport->r_next; + nport = nport->r_next); + if (nport) nport->r_next = node2->node_ports; + } freeMagic((char *) node2); } } @@ -916,6 +1061,7 @@ extOutputConns(table, outf) NodeName *nfirst; HashSearch hs; HashEntry *he; + ExtConnList *nport, *npnext; HashStartSearch(&hs); while ((he = HashNext(table, &hs))) @@ -948,7 +1094,6 @@ extOutputConns(table, outf) node->node_pa[n].pa_area, node->node_pa[n].pa_perim); fprintf(outf, "\n"); - nn->nn_node = (Node *) NULL; /* Processed */ /* Subsequent merges */ @@ -960,6 +1105,23 @@ extOutputConns(table, outf) } } nn->nn_node = (Node *) NULL; + for (nport = node->node_ports; nport;) + { + LabRegion *lreg = (LabRegion *)CD2PTR(nport->r_upnode); + NodeName *nn2 = (NodeName *)CD2PTR(nport->r_downnode); + + npnext = nport->r_next; + /* Output port positions */ + fprintf(outf, "connect %d %d %d %d %s \"%s\" \"%s\"\n", + nport->r_r.r_xbot, nport->r_r.r_ybot, + nport->r_r.r_xtop, nport->r_r.r_ytop, + DBTypeShortName(nport->r_type), + (lreg == (LabRegion *)NULL) ? "None" : + extNodeName(lreg), + (nn2) ? nn2->nn_name : "None"); + freeMagic((char *)nport); + nport = npnext; + } freeMagic((char *) node); } freeMagic((char *) nfirst); @@ -1005,6 +1167,7 @@ extHierNewNode(he) node->node_names = nn; node->node_cap = (CapValue) 0; node->node_len = 1; + node->node_ports = (ExtConnList *)NULL; for (n = 0; n < nclasses; n++) node->node_pa[n].pa_perim = node->node_pa[n].pa_area = 0; HashSetValue(he, (char *) nn); diff --git a/extract/ExtInter.c b/extract/ExtInter.c index 080f241c..5148571d 100644 --- a/extract/ExtInter.c +++ b/extract/ExtInter.c @@ -272,7 +272,7 @@ extInterSubtreeElement(use, trans, x, y, r) int extInterSubtreeTile(tile, dinfo, cxp) Tile *tile; - TileType dinfo; + TileType dinfo; /* (unused) */ TreeContext *cxp; { SearchContext newscx; @@ -343,8 +343,9 @@ extInterOverlapSubtree(scx) */ int -extInterOverlapTile(tile, cxp) +extInterOverlapTile(tile, dinfo, cxp) Tile *tile; + TileType dinfo; /* (unused) */ TreeContext *cxp; { SearchContext *scx = cxp->tc_scx; diff --git a/extract/ExtMain.c b/extract/ExtMain.c index bdc594af..ec1f475d 100644 --- a/extract/ExtMain.c +++ b/extract/ExtMain.c @@ -473,6 +473,19 @@ ExtUnique(rootUse, option) /* Fix up bounding boxes if they've changed */ DBFixMismatch(); + /* Because the "extract unique" does the same thing as "extract do unique" + * but the options may be different, disable "extract do unique" when + * "extract unique" is run, on the assumption that no user would + * intentionally use both methods. If "do unique" was set and got + * disabled, then flag a warning. + */ + if (ExtOptions & EXT_DOUNIQUE) + { + ExtOptions &= ~EXT_DOUNIQUE; + TxPrintf("Warning: Extract option \"do unique\" disabled because " + "\"extract unique\" was run.\n"); + } + /* Mark all defs as being unvisited */ (void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0); diff --git a/extract/ExtSubtree.c b/extract/ExtSubtree.c index 733baddf..5a4bae1c 100644 --- a/extract/ExtSubtree.c +++ b/extract/ExtSubtree.c @@ -54,12 +54,14 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ /* C99 compat */ #include "drc/drc.h" -#ifdef exactinteractions /* - * If "exactinteractions" is defined, we use an experimental algorithm - * for finding exact interaction areas. Currently it doesn't work too - * well, so we leave it turned off. + * If "exactinteractions" is defined, use an experimental algorithm + * for finding exact interaction areas. Currently it doesn't work + * too well, so it is disabled. */ +/* #define exactinteractions */ + +#ifdef exactinteractions int ExtInterBloat = 10; #endif /* exactinteractions */ diff --git a/extract/ExtUnique.c b/extract/ExtUnique.c index 93726a13..82f4772d 100644 --- a/extract/ExtUnique.c +++ b/extract/ExtUnique.c @@ -66,6 +66,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ * label. This way, the unique label form can be used by the * extraction code but labels (and port indexes) can be reverted * afterward, and no permanent change is made to the circuit. + * Option EXT_UNIQ_TEMP_NOPORTS is a combination of EXT_UNIQ_TEMP and + * EXT_UNIQ_NOPORTS. * * Results: * Returns the number of warnings generated. @@ -226,8 +228,9 @@ extMakeUnique(def, ll, lreg, lregList, labelHash, option) text = ll->ll_label->lab_text; if (option == EXT_UNIQ_ALL || option == EXT_UNIQ_TEMP) goto makeUnique; - else if ((option == EXT_UNIQ_NOPORTS || option == EXT_UNIQ_NOTOPPORTS) - && !(ll->ll_label->lab_flags & PORT_DIR_MASK)) + else if ((option == EXT_UNIQ_NOPORTS || option == EXT_UNIQ_NOTOPPORTS || + option == EXT_UNIQ_TEMP_NOPORTS) && + !(ll->ll_label->lab_flags & PORT_DIR_MASK)) goto makeUnique; cpend = strchr(text, '\0'); @@ -326,7 +329,8 @@ makeUnique: saveLab = *lab; /* Flag this label as having been modified */ - if (option == EXT_UNIQ_TEMP) flags |= LABEL_UNIQUE; + if ((option == EXT_UNIQ_TEMP) || (option == EXT_UNIQ_TEMP_NOPORTS)) + flags |= LABEL_UNIQUE; DBRemoveLabel(def, lab); DBPutFontLabel(def, &saveLab.lab_rect, diff --git a/extract/extract.h b/extract/extract.h index 19242f65..43cd687b 100644 --- a/extract/extract.h +++ b/extract/extract.h @@ -76,6 +76,7 @@ extern const char * const extDevTable[]; #define EXT_DOLABELCHECK 0x040 /* Check for connections by label */ #define EXT_DOALIASES 0x080 /* Output all node aliases */ #define EXT_DOEXTRESIST 0x200 /* Do full R-C extraction */ +#define EXT_DOUNIQNOTOPPORTS 0x400 /* Ignore top cell ports w/EXT_DOUNIQUE */ extern int ExtOptions; /* Bitmask of above */ extern char *ExtLocalPath; /* If non-NULL, location to write .ext files */ @@ -86,6 +87,7 @@ extern char *ExtLocalPath; /* If non-NULL, location to write .ext files */ #define EXT_UNIQ_NOPORTS 2 #define EXT_UNIQ_NOTOPPORTS 3 #define EXT_UNIQ_TEMP 4 /* Used only with "EXT_DOUNIQUE" */ +#define EXT_UNIQ_TEMP_NOPORTS 5 /* Used only with "EXT_DOUNIQUE" */ extern bool ExtTechLine(); extern void ExtTechInit(); diff --git a/extract/extractInt.h b/extract/extractInt.h index ebbb671d..97cdcf05 100644 --- a/extract/extractInt.h +++ b/extract/extractInt.h @@ -981,6 +981,7 @@ typedef struct node * in the list is the "official" node name. */ int node_len; /* Number of entries in node_names */ + ExtConnList *node_ports; /* List of areas that connect to other cells */ CapValue node_cap; /* Capacitance to substrate */ PerimArea node_pa[1]; /* Dummy; each node actually has * ExtCurStyle->exts_numResistClasses diff --git a/resis/ResBasic.c b/resis/ResBasic.c index d49ae8b8..73b8856e 100644 --- a/resis/ResBasic.c +++ b/resis/ResBasic.c @@ -27,64 +27,24 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ /* *-------------------------------------------------------------------------- * - * resNodeIsPort -- - * - * If the given position is inside any port declared on the tile, - * change the node name to the port name. Remove the port - * declaration if it was used. - * - *-------------------------------------------------------------------------- - */ - -void -resNodeIsPort(node, x, y, tile) - resNode *node; - int x; - int y; - Tile *tile; -{ - Rect *rect; - Point p; - resPort *pl, *lp; - resInfo *info = (resInfo *)TiGetClientPTR(tile); - - p.p_x = x; - p.p_y = y; - - for (pl = info->portList; pl; pl = pl->rp_nextPort) - { - rect = &(pl->rp_bbox); - if (GEO_ENCLOSE(&p, rect)) - { - node->rn_name = pl->rp_nodename; - if (info->portList == pl) - info->portList = pl->rp_nextPort; - else - { - for (lp = info->portList; lp && (lp->rp_nextPort != pl); - lp = lp->rp_nextPort); - lp->rp_nextPort = pl->rp_nextPort; - } - freeMagic(pl); - break; - } - } -} - -/* - *-------------------------------------------------------------------------- - * - * resAllPortNodes -- + * resMakePortBreakpoints -- * * Generate new nodes and breakpoints for every unused port declared * on a tile. However, if "startpoint" is inside the port position, * then it has already been processed, so ignore it. * + * Results: + * None. + * + * Side effects: + * Adds breakpoints where ports (drivers, sinks, or labels) have been + * defined as connected to the tile. + * *-------------------------------------------------------------------------- */ void -resAllPortNodes(tile, list) +resMakePortBreakpoints(tile, list) Tile *tile; resNode **list; { @@ -92,6 +52,7 @@ resAllPortNodes(tile, list) resNode *resptr; resPort *pl; resInfo *info = (resInfo *)TiGetClientPTR(tile); + ResConnect *connect; free_magic1_t mm1 = freeMagic1_init(); for (pl = info->portList; pl; pl = pl->rp_nextPort) @@ -103,13 +64,30 @@ resAllPortNodes(tile, list) resptr->rn_status = TRUE; resptr->rn_noderes = 0; resptr->rn_name = pl->rp_nodename; + + /* Link back to the resnode from the ResConnect record */ + connect = pl->rp_connect; + connect->rc_node = resptr; + ResAddToQueue(resptr, list); - NEWBREAK(resptr, tile, x, y, NULL); + ResNewBreak(resptr, tile, x, y, NULL); freeMagic1(&mm1, pl); } freeMagic1_end(&mm1); } +/* + * Structure used by ResEachTile for the callback to ResMultiPlaneFunc() + * to pass a pointer to the tile being processed, and the terminal being + * searched. + */ + +typedef struct tile_and_term +{ + Tile *tat_tile; + int tat_term; +} TileAndTerm; + /* *-------------------------------------------------------------------------- * @@ -128,12 +106,13 @@ resAllPortNodes(tile, list) */ int -ResMultiPlaneFunc(tile, dinfo, tpptr) +ResMultiPlaneFunc(tile, dinfo, tat) Tile *tile; TileType dinfo; /* Not used, but needs to be handled */ - Tile **tpptr; + TileAndTerm *tat; { - Tile *tp = *tpptr; + Tile *tp = tat->tat_tile; + int term = tat->tat_term; int xj, yj; /* Simplified split tile handling---Ignore the right side of @@ -146,7 +125,7 @@ ResMultiPlaneFunc(tile, dinfo, tpptr) xj = (LEFT(tile) + RIGHT(tile)) / 2; yj = (TOP(tile) + BOTTOM(tile)) / 2; - ResNewSDDevice(tp, tile, xj, yj, OTHERPLANE, &ResNodeQueue); + ResNewTermDevice(tp, tile, term, xj, yj, OTHERPLANE, &ResNodeQueue); return 0; } @@ -195,7 +174,44 @@ ResSubstrateFunc(tile, dinfo, tpptr) /* *-------------------------------------------------------------------------- * - * ResEachTile--for each tile, make a list of all possible current sources/ + * ResStartTile -- + * + * For the tile at the starting point of the net, create an initial + * resNode entry. + * + * Results: + * None. + * + * Side Effects: + * creates a node. + * + * + *-------------------------------------------------------------------------- + */ + +void +ResStartTile(tile, x, y) + Tile *tile; + int x, y; + +{ + resNode *resptr; + + resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode))); + InitializeResNode(resptr, x, y, RES_NODE_ORIGIN); + resptr->rn_status = TRUE; + resptr->rn_noderes = 0; + ResAddToQueue(resptr, &ResNodeQueue); + ResNewBreak(resptr, tile, x, y, NULL); + if (resCurrentNode == NULL) resCurrentNode = resptr; +} + +/* + *-------------------------------------------------------------------------- + * + * ResEachTile -- + * + * For each tile, make a list of all possible current sources/ * sinks including contacts, devices, and junctions. Once this * list is made, calculate the resistor network for the tile. * @@ -214,10 +230,9 @@ ResSubstrateFunc(tile, dinfo, tpptr) #define IGNORE_BOTTOM 8 bool -ResEachTile(tile, startpoint) - Tile *tile; - Point *startpoint; - +ResEachTile(tile, devTiles) + Tile *tile; /* Tile being processed */ + ResDevTile *devTiles; /* List of device tiles for reference */ { Tile *tp; resNode *resptr; @@ -226,14 +241,12 @@ ResEachTile(tile, startpoint) int xj, yj, i; bool merged; tElement *tcell; - resInfo *tstructs= (resInfo *)TiGetClientPTR(tile); + resInfo *tstructs = (resInfo *)TiGetClientPTR(tile); ExtDevice *devptr; int sides; ResTileCount++; - /* Process startpoint, if any. */ - /* Simplification: Split tiles handle either the non-space side, * or if neither side is space, then handle the left side. */ @@ -258,21 +271,7 @@ ResEachTile(tile, startpoint) t1 = TiGetTypeExact(tile); } - if (startpoint != (Point *) NULL) - { - int x = startpoint->p_x; - int y = startpoint->p_y; - resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode))); - InitializeResNode(resptr, x, y, RES_NODE_ORIGIN); - resptr->rn_status = TRUE; - resptr->rn_noderes = 0; - ResAddToQueue(resptr, &ResNodeQueue); - NEWBREAK(resptr, tile, x, y, NULL); - if (resCurrentNode == NULL) resCurrentNode = resptr; - resNodeIsPort(resptr, x, y, tile); - } - - if TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t1) + if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t1)) { /* * The device is put in the center of the tile. This is fine @@ -295,9 +294,7 @@ ResEachTile(tile, startpoint) InitializeResNode(resptr, x, y, RES_NODE_JUNCTION); resptr->rn_te = tcell; ResAddToQueue(resptr, &ResNodeQueue); - resNodeIsPort(resptr, x, y, tile); - - NEWBREAK(resptr, tile, resptr->rn_loc.p_x, + ResNewBreak(resptr, tile, resptr->rn_loc.p_x, resptr->rn_loc.p_y, NULL); } } @@ -326,7 +323,7 @@ ResEachTile(tile, startpoint) /* left */ if (!(sides & IGNORE_LEFT)) - for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp)) + for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp)) { t2 = TiGetRightType(tp); if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2)) @@ -341,14 +338,14 @@ ResEachTile(tile, startpoint) /* found device */ xj = LEFT(tile); yj = (TOP(tp) + BOTTOM(tp)) >> 1; - ResNewSDDevice(tile, tp, xj, yj, RIGHTEDGE, &ResNodeQueue); + ResNewTermDevice(tile, tp, i, xj, yj, RIGHTEDGE, &ResNodeQueue); break; } } if (i < devptr->exts_deviceSDCount) break; } } - if TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2) + if (TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2)) { /* tile is junction */ xj = LEFT(tile); @@ -359,7 +356,7 @@ ResEachTile(tile, startpoint) /* right */ if (!(sides & IGNORE_RIGHT)) - for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp=LB(tp)) + for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp)) { t2 = TiGetLeftType(tp); if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2)) @@ -374,18 +371,18 @@ ResEachTile(tile, startpoint) /* found device */ xj = RIGHT(tile); yj = (TOP(tp) + BOTTOM(tp)) >> 1; - ResNewSDDevice(tile, tp, xj, yj, LEFTEDGE, &ResNodeQueue); + ResNewTermDevice(tile, tp, i, xj, yj, LEFTEDGE, &ResNodeQueue); break; } } if (i < devptr->exts_deviceSDCount) break; } } - if TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1], t2) + if (TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1], t2)) { /* tile is junction */ xj = RIGHT(tile); - yj = (MAX(BOTTOM(tile),BOTTOM(tp)) + MIN(TOP(tile), TOP(tp))) >> 1; + yj = (MAX(BOTTOM(tile), BOTTOM(tp)) + MIN(TOP(tile), TOP(tp))) >> 1; (void)ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue); } } @@ -407,25 +404,25 @@ ResEachTile(tile, startpoint) /* found device */ yj = TOP(tile); xj = (LEFT(tp) + RIGHT(tp)) >> 1; - ResNewSDDevice(tile, tp, xj, yj, BOTTOMEDGE, &ResNodeQueue); + ResNewTermDevice(tile, tp, i, xj, yj, BOTTOMEDGE, &ResNodeQueue); break; } } if (i < devptr->exts_deviceSDCount) break; } } - if TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1], t2) + if (TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1], t2)) { /* tile is junction */ yj = TOP(tile); - xj = (MAX(LEFT(tile),LEFT(tp)) + MIN(RIGHT(tile),RIGHT(tp))) >> 1; + xj = (MAX(LEFT(tile), LEFT(tp)) + MIN(RIGHT(tile), RIGHT(tp))) >> 1; ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue); } } /* bottom */ if (!(sides & IGNORE_BOTTOM)) - for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp)) + for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp)) { t2 = TiGetTopType(tp); if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2)) @@ -440,50 +437,59 @@ ResEachTile(tile, startpoint) /* found device */ yj = BOTTOM(tile); xj = (LEFT(tp) + RIGHT(tp)) >> 1; - ResNewSDDevice(tile, tp, xj, yj, TOPEDGE, &ResNodeQueue); + ResNewTermDevice(tile, tp, i, xj, yj, TOPEDGE, &ResNodeQueue); break; } } if (i < devptr->exts_deviceSDCount) break; } } - if TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2) + if (TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2)) { /* tile is junction */ yj = BOTTOM(tile); - xj = (MAX(LEFT(tile),LEFT(tp)) + MIN(RIGHT(tile),RIGHT(tp))) >> 1; + xj = (MAX(LEFT(tile), LEFT(tp)) + MIN(RIGHT(tile), RIGHT(tp))) >> 1; ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue); } } - /* Check for source/drain on other planes (e.g., capacitors, bipolars, ...) */ + /* Check for terminals on other planes (e.g., capacitors, bipolars, ...) */ + /* Note: Need to tag these tiles per device to avoid checking through */ + /* the device list for each tile. (To be done) */ - if (TTMaskHasType(&ResSDTypesBitMask, t1)) + if (TTMaskHasType(&ResTermTypesBitMask, t1)) { Rect r; int pNum; TileTypeBitMask devMask; + TileAndTerm tat; + ResDevTile *devtile; + ExtDevice *devptr; TiToRect(tile, &r); - for (pNum = 0; pNum < DBNumPlanes; pNum++) + for (devtile = devTiles; devtile; devtile = devtile->nextDev) { - if (DBTypeOnPlane(t1, pNum)) continue; + Tile *tp; + TileType devtype = devtile->type; - /* NOTE: This is ridiculously inefficient and should be done - * in a different way. - */ - - TTMaskZero(&devMask); - for (t2 = TT_TECHDEPBASE; t2 < DBNumUserLayers; t2++) - for (devptr = ExtCurStyle->exts_device[t2]; devptr; - devptr = devptr->exts_next) - for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++) - if (TTMaskHasType(&devptr->exts_deviceSDTypes[i], t1)) - TTMaskSetType(&devMask, t2); - - DBSrPaintArea((Tile *)NULL, ResUse->cu_def->cd_planes[pNum], - &r, &devMask, ResMultiPlaneFunc, (ClientData)&tile); + devptr = devtile->devptr; + for (i = 0; i < devptr->exts_deviceSDCount; i++) + { + if (TTMaskHasType(&devptr->exts_deviceSDTypes[i], t1)) + { + if (GEO_OVERLAP(&devtile->area, &r)) + { + Plane *plane = ResUse->cu_def->cd_planes[DBPlane(devtype)]; + xj = (r.r_xtop + r.r_xbot) / 2; + yj = (r.r_ytop + r.r_ybot) / 2; + tp = PlaneGetHint(plane); + GOTOPOINT(tp, &devtile->area.r_ll); + PlaneSetHint(plane, tp); + ResNewTermDevice(tile, tp, i, xj, yj, OTHERPLANE, &ResNodeQueue); + } + } + } } } @@ -494,32 +500,37 @@ ResEachTile(tile, startpoint) Rect r; int pNum; TileTypeBitMask devMask; + ResDevTile *devtile; + ExtDevice *devptr; TiToRect(tile, &r); - for (pNum = 0; pNum < DBNumPlanes; pNum++) + for (devtile = devTiles; devtile; devtile = devtile->nextDev) { - if (DBTypeOnPlane(t1, pNum)) continue; + Tile *tp; + TileType devtype = devtile->type; - /* NOTE: This is ridiculously inefficient and should be done - * in a different way. - */ + devptr = devtile->devptr; - TTMaskZero(&devMask); - for (t2 = TT_TECHDEPBASE; t2 < DBNumUserLayers; t2++) - for (devptr = ExtCurStyle->exts_device[t2]; devptr; - devptr = devptr->exts_next) - if (TTMaskHasType(&devptr->exts_deviceSubstrateTypes, t1)) - TTMaskSetType(&devMask, t2); - - DBSrPaintArea((Tile *)NULL, ResUse->cu_def->cd_planes[pNum], - &r, &devMask, ResSubstrateFunc, (ClientData)&tile); + if (TTMaskHasType(&devptr->exts_deviceSubstrateTypes, t1)) + { + if (GEO_OVERLAP(&devtile->area, &r)) + { + Plane *plane = ResUse->cu_def->cd_planes[DBPlane(devtype)]; + xj = (r.r_xtop + r.r_xbot) / 2; + yj = (r.r_ytop + r.r_ybot) / 2; + tp = PlaneGetHint(plane); + GOTOPOINT(tp, &devtile->area.r_ll); + PlaneSetHint(plane, tp); + ResNewSubDevice(tile, tp, xj, yj, OTHERPLANE, &ResNodeQueue); + } + } } } tstructs->ri_status |= RES_TILE_DONE; - resAllPortNodes(tile, &ResNodeQueue); + resMakePortBreakpoints(tile, &ResNodeQueue); merged = ResCalcTileResistance(tile, tstructs, &ResNodeQueue, &ResNodeList); diff --git a/resis/ResChecks.c b/resis/ResChecks.c index 2fc75d97..3007a455 100644 --- a/resis/ResChecks.c +++ b/resis/ResChecks.c @@ -61,7 +61,7 @@ ResSanityChecks(nodename, resistorList, nodeList, devlist) { resSanityStack = StackNew(64); } - for (node = nodeList; node != NULL; node=node->rn_more) + for (node = nodeList; node != NULL; node = node->rn_more) { node->rn_status &= ~RES_REACHED_NODE; if (node->rn_why & RES_NODE_ORIGIN) @@ -133,7 +133,7 @@ ResSanityChecks(nodename, resistorList, nodeList, devlist) } } foundorigin = 0; - for (node = nodeList; node != NULL; node=node->rn_more) + for (node = nodeList; node != NULL; node = node->rn_more) { if ((node->rn_status & RES_REACHED_NODE) == 0) { diff --git a/resis/ResDebug.c b/resis/ResDebug.c index 44f750e4..be5cdc06 100644 --- a/resis/ResDebug.c +++ b/resis/ResDebug.c @@ -128,11 +128,11 @@ ResPrintDeviceList(fp, list) { if (list->rd_terminals[i] == NULL) continue; if (fp == stdout) - TxPrintf("%c (%d,%d) ",termtype[i], + TxPrintf("%c (%d,%d) ", termtype[i], list->rd_terminals[i]->rn_loc.p_x, list->rd_terminals[i]->rn_loc.p_y); else - fprintf(fp, "%c (%d,%d) ",termtype[i], + fprintf(fp, "%c (%d,%d) ", termtype[i], list->rd_terminals[i]->rn_loc.p_x, list->rd_terminals[i]->rn_loc.p_y); diff --git a/resis/ResFract.c b/resis/ResFract.c index ddd881ea..0dc498b2 100644 --- a/resis/ResFract.c +++ b/resis/ResFract.c @@ -106,7 +106,7 @@ enumerate: } else { - resTopTile=BL(resTopTile); + resTopTile = BL(resTopTile); } } } @@ -205,7 +205,7 @@ ResCheckConcavity(bot, top, tt) ylen = ypos - resWalkdown(bot, tt, xpos, ypos, NULL); if (xlen > ylen) { - (void) resWalkdown(bot,tt,xpos,ypos,ResSplitX); + (void) resWalkdown(bot, tt, xpos, ypos, ResSplitX); } } } @@ -274,7 +274,7 @@ int resWalkup(tile, tt, xpos, ypos, func) Tile *tile; TileType tt; - int xpos,ypos; + int xpos, ypos; Tile * (*func)(); { @@ -443,7 +443,7 @@ ResSplitX(tile, x) Tile *tp = TiSplitX(tile, x); Tile *tp2; - TiSetBody(tp,tt); + TiSetBody(tp, tt); /* check to see if we can combine with the tiles above or below us */ tp2 = RT(tile); if (TiGetType(tp2) == tt && LEFT(tp2) == LEFT(tile) && RIGHT(tp2) == RIGHT(tile)) diff --git a/resis/ResJunct.c b/resis/ResJunct.c index 7eb4556a..14df60a2 100644 --- a/resis/ResJunct.c +++ b/resis/ResJunct.c @@ -29,26 +29,31 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ /* *------------------------------------------------------------------------- * - * ResNewSDDevice -- called when a device is reached via a piece of - * diffusion. (Devices reached via poly, i.e. - * gates, are handled by ResEachTile.) + * ResNewTermDevice -- * - * Results:none + * Called when a device is reached via a type in the device's + * terminal type list (e.g., diffusion, for MOSFETs). Note that + * devices reached by the device type (e.g., poly, for MOSFETs) + * are handled by ResEachTile. * - * Side Effects: determines to which terminal (source or drain) node - * is connected. Makes new node if node hasn't already been created . - * Allocates breakpoint in current tile for device. + * Results: + * None + * + * Side Effects: + * Determines to which terminal (source or drain) node is connected. + * Makes new node if node hasn't already been created. Allocates + * breakpoint in current tile for device. * *------------------------------------------------------------------------- */ void -ResNewSDDevice(tile, tp, xj, yj, direction, PendingList) +ResNewTermDevice(tile, tp, n, xj, yj, direction, PendingList) Tile *tile, *tp; - int xj, yj, direction; + int n, xj, yj, direction; resNode **PendingList; { - resNode *resptr; + resNode *resptr = NULL; resDevice *resDev; tElement *tcell; int newnode; @@ -64,7 +69,9 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList) ri = (resInfo *) TiGetClientPTR(tp); resDev = ri->deviceList; - if ((ri->sourceEdge & direction) != 0) + if (resDev == NULL) return; /* Shouldn't happen? */ + if ((((ri->sourceEdge & direction) != 0) && (resDev->rd_nterms == 4)) + || (resDev->rd_nterms > 2)) { if (resDev->rd_fet_source == (resNode *) NULL) { @@ -73,11 +80,9 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList) resDev->rd_fet_source = resptr; } else - { resptr = resDev->rd_fet_source; - } } - else + else if (resDev->rd_nterms > 3) { if (resDev->rd_fet_drain == (resNode *) NULL) { @@ -86,9 +91,7 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList) resDev->rd_fet_drain = resptr; } else - { resptr = resDev->rd_fet_drain; - } } if (newnode) { @@ -99,7 +102,8 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList) resptr->rn_te = tcell; ResAddToQueue(resptr, PendingList); } - NEWBREAK(resptr, tile, xj, yj, NULL); + if (resptr != NULL) + ResNewBreak(resptr, tile, xj, yj, NULL); } /* @@ -131,20 +135,16 @@ ResNewSubDevice(tile, tp, xj, yj, direction, PendingList) ri = (resInfo *) TiGetClientPTR(tp); resDev = ri->deviceList; - /* Arrived at a device that has a terminal connected to substrate */ - /* that is not a FET bulk terminal (e.g., varactor, diode). */ - if (resDev->rd_nterms < 4) return; + if (resDev == NULL) return; /* Should not happen? */ - if (resDev->rd_fet_subs == (resNode *) NULL) + if (resDev->rd_fet_subs == (resNode *)NULL) { - resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode))); - newnode = TRUE; - resDev->rd_fet_subs = resptr; + resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode))); + newnode = TRUE; + resDev->rd_fet_subs = resptr; } else - { - resptr = resDev->rd_fet_subs; - } + resptr = resDev->rd_fet_subs; if (newnode) { @@ -155,7 +155,7 @@ ResNewSubDevice(tile, tp, xj, yj, direction, PendingList) resptr->rn_te = tcell; ResAddToQueue(resptr, PendingList); } - NEWBREAK(resptr, tile, xj, yj, NULL); + ResNewBreak(resptr, tile, xj, yj, NULL); } /* @@ -213,10 +213,10 @@ ResProcessJunction(tile, tp, xj, yj, NodeList) junction->rj_nextjunction[1] = ri2->junctionList; ri2->junctionList = junction; - NEWBREAK(junction->rj_jnode,tile, junction->rj_loc.p_x, + ResNewBreak(junction->rj_jnode, tile, junction->rj_loc.p_x, junction->rj_loc.p_y, NULL); - NEWBREAK(junction->rj_jnode,tp, junction->rj_loc.p_x, + ResNewBreak(junction->rj_jnode, tp, junction->rj_loc.p_x, junction->rj_loc.p_y, NULL); } diff --git a/resis/ResMain.c b/resis/ResMain.c index 988a67a9..fb4ce0b5 100644 --- a/resis/ResMain.c +++ b/resis/ResMain.c @@ -40,8 +40,7 @@ resNode *resCurrentNode; int ResTileCount = 0; /* Number of tiles rn_status */ extern ExtRegion *ResFirst(); extern Tile *FindStartTile(); -extern int ResEachTile(); -TileTypeBitMask ResSDTypesBitMask; +TileTypeBitMask ResTermTypesBitMask; TileTypeBitMask ResSubTypesBitMask; extern HashTable ResNodeTable; @@ -100,7 +99,7 @@ ResInitializeConn() * * ResGetReCell -- * - * This procedure makes sure that ResUse,ResDef + * This procedure makes sure that ResUse, ResDef * have been properly initialized to refer to a cell definition * named "__RESIS__". * @@ -148,54 +147,86 @@ void ResDissolveContacts(contacts) ResContactPoint *contacts; { - TileType t, oldtype, lasttype = TT_SPACE; + TileType t, conttype; Tile *tp; - TileTypeBitMask residues; + TileType residue[NP][NT]; + int pNum; + + bzero((char *)residue, NP * NT * sizeof(TileType)); for (; contacts != (ResContactPoint *)NULL; contacts = contacts->cp_nextcontact) { - oldtype = contacts->cp_type; + conttype = contacts->cp_type; #ifdef PARANOID - if (oldtype == TT_SPACE) - TxError("Error in Contact Dissolving for %s \n",ResCurrentNode); + if (conttype == TT_SPACE) + TxError("Error in Contact Dissolving for %s \n", ResCurrentNode); #endif - if (oldtype != lasttype) + + /* Fill in details of the residue types for each contact type. + * This is done only once per contact type. This could be refined + * further by temporarily changing the paint table directly or + * creating a separate paint table which erases contact cuts and + * replaces them with the residues. + */ + + if (residue[DBPlane(conttype)][conttype] == TT_SPACE) + for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) + residue[pNum][conttype] = DBPlaneToResidue(conttype, pNum); + + for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) { - lasttype = oldtype; - DBFullResidueMask(oldtype, &residues); + if (DBTypeOnPlane(conttype, pNum)) + { + DBPaintPlane(ResUse->cu_def->cd_planes[pNum], &(contacts->cp_rect), + DBStdEraseTbl(conttype, pNum), (PaintUndoInfo *)NULL); + DBPaintPlane(ResUse->cu_def->cd_planes[pNum], &(contacts->cp_rect), + DBStdPaintTbl(residue[pNum][conttype], pNum), + (PaintUndoInfo *)NULL); + } } - DBErase(ResUse->cu_def, &(contacts->cp_rect), oldtype); - for (t = TT_TECHDEPBASE; t < DBNumTypes; t++) - if (TTMaskHasType(&residues, t)) - DBPaint(ResUse->cu_def, &(contacts->cp_rect), t); - #ifdef PARANOID - tp = PlaneGetHint(ResDef->cd_planes[DBPlane(contacts->cp_type)]); + tp = PlaneGetHint(ResDef->cd_planes[DBPlane(conttype)]); GOTOPOINT(tp, &(contacts->cp_rect.r_ll)); - if (TiGetTypeExact(tp) == contacts->cp_type) + if (TiGetTypeExact(tp) == conttype) TxError("Error in Contact Preprocess Routines\n"); #endif } } +/* Structure used by ResMakeDriverSinkPorts() to pass information to + * ResAddPortFunc(). Contains a reference to a node, so that the + * link between the tile and the node can be maintained, and the + * driver or sink, which has the information about the position and + * tile type of the connection. + */ + +typedef struct driversinkdata { + ResExtNode *dsd_node; + ResConnect *dsd_connect; +} DriverSinkData; + /* *--------------------------------------------------------------------------- * - * ResMakePortBreakpoints -- + * ResMakeDriverSinkPorts -- * - * Search for nodes which are ports, and force them to be breakpoints - * in the "resInfo" field of their respective tiles in ResUse. This - * ensures that connected nodes that stretch between two ports will - * not be assumed to be "hanging" nodes. + * Search through the list of node drivers and sinks (connections up + * and down in the hierarchy), and make sure this information is + * copied to the resInfo record of the tile(s) found at the connection. * - * Do the same thing for labels. + * Results: + * None. + * + * Side effects: + * Adds information to the resInfo clientData of tiles in def. * *---------------------------------------------------------------------------- */ + void -ResMakePortBreakpoints(def) +ResMakeDriverSinkPorts(def) CellDef *def; { Plane *plane; @@ -204,21 +235,66 @@ ResMakePortBreakpoints(def) HashSearch hs; HashEntry *entry; ResExtNode *node; - int ResAddBreakpointFunc(); /* Forward Declaration */ + ResConnect *rdriver, *rsink; + DriverSinkData dsd; + int ResAddPortFunc(); /* Forward Declaration */ HashStartSearch(&hs); while((entry = HashNext(&ResNodeTable, &hs)) != NULL) { node = (ResExtNode *)HashGetValue(entry); - if (node->status & PORTNODE) + + for (rdriver = node->drivepoints; rdriver; rdriver = rdriver->rc_next) { - if (node->rs_ttype <= 0) + if (rdriver->rc_type <= 0) { TxError("Warning: Label \"%s\" is unconnected.\n", node->name); continue; } - rect = &(node->rs_bbox); + rect = &(rdriver->rc_rect); + + /* If label is on a contact, the contact has been dissolved. */ + /* Assume that the uppermost residue is the port. This may */ + /* not necessarily be the case. Could do a boundary scan on */ + /* each residue plane to see which side of the contact is */ + /* the internal connection in the def. . . */ + + if (DBIsContact(rdriver->rc_type)) + { + TileType type; + + DBFullResidueMask(rdriver->rc_type, &mask); + for (type = DBNumUserLayers - 1; type >= TT_TECHDEPBASE; type--) + if (TTMaskHasType(&mask, type)) + { + plane = def->cd_planes[DBPlane(type)]; + break; + } + } + else + { + TTMaskSetOnlyType(&mask, rdriver->rc_type); + plane = def->cd_planes[DBPlane(rdriver->rc_type)]; + } + + dsd.dsd_connect = rdriver; + dsd.dsd_node = node; + (void) DBSrPaintArea((Tile *) NULL, plane, rect, &mask, + ResAddPortFunc, (ClientData)&dsd); + } + + /* Process sink points in the same way */ + + for (rsink = node->sinkpoints; rsink; rsink = rsink->rc_next) + { + if (rsink->rc_type <= 0) + { + TxError("Warning: Label \"%s\" is unconnected.\n", node->name); + continue; + } + + rect = &(rsink->rc_rect); /* Beware of zero-area ports */ if (rect->r_xbot == rect->r_xtop) @@ -238,11 +314,11 @@ ResMakePortBreakpoints(def) /* each residue plane to see which side of the contact is */ /* the internal connection in the def. . . */ - if (DBIsContact(node->rs_ttype)) + if (DBIsContact(rsink->rc_type)) { TileType type; - DBFullResidueMask(node->rs_ttype, &mask); + DBFullResidueMask(rsink->rc_type, &mask); for (type = DBNumUserLayers - 1; type >= TT_TECHDEPBASE; type--) if (TTMaskHasType(&mask, type)) { @@ -252,40 +328,122 @@ ResMakePortBreakpoints(def) } else { - TTMaskSetOnlyType(&mask, node->rs_ttype); - plane = def->cd_planes[DBPlane(node->rs_ttype)]; + TTMaskSetOnlyType(&mask, rsink->rc_type); + plane = def->cd_planes[DBPlane(rsink->rc_type)]; } + dsd.dsd_connect = rsink; + dsd.dsd_node = node; (void) DBSrPaintArea((Tile *) NULL, plane, rect, &mask, - ResAddBreakpointFunc, (ClientData)node); + ResAddPortFunc, (ClientData)&dsd); } } } /* - *--------------------------------------------------------------------------- + *---------------------------------------------------------------------------- * - * ResMakeLabelBreakpoints -- + * ResAddPortFunc -- * - * Search for labels that are part of a node, and force them to be - * breakpoints in the "resInfo" field of their respective tiles in - * ResUse. This ensures (among other things) that pins of a top level - * cell will be retained and become the endpoint of a net. + * Add a portList entry to the "resInfo" structure of the tile. The + * portList entry keeps a record of the area of overlap or abutment + * of the port, as well as a pointer to the resNode. + * + * Results: + * Always returns 0; + * + * Side effects: + * Adds information to a tile's "resInfo" clientData. * *---------------------------------------------------------------------------- */ + +int +ResAddPortFunc(tile, dinfo, dsd) + Tile *tile; + TileType dinfo; /* (unused) */ + DriverSinkData *dsd; /* Data for driver or sink */ +{ + resPort *rp; + resInfo *pX; + Rect rect; + ResConnect *connect; + ResExtNode *node; + + if (TiGetClient(tile) == CLIENTDEFAULT) + return 0; + + /* To simplify processing, if a split tile does not have TT_SPACE + * on either side, then only the left side is processed. + */ + if (IsSplit(tile)) + if (TiGetLeftType(tile) != TT_SPACE && TiGetRightType(tile) != TT_SPACE) + if (dinfo & TT_SIDE) + return 0; + + node = dsd->dsd_node; + connect = dsd->dsd_connect; + + TiToRect(tile, &rect); + + pX = (resInfo *)TiGetClient(tile); + + rp = (resPort *) mallocMagic((unsigned)(sizeof(resPort))); + rp->rp_nextPort = pX->portList; + rp->rp_bbox = connect->rc_rect; + rp->rp_loc = connect->rc_rect.r_ll; + rp->rp_connect = connect; + rp->rp_nodename = node->name; + pX->portList = rp; + + return 0; +} + +/* Structure used by ResMakeLabelPorts() to pass information to + * ResAddPortFunc(). Contains a reference to a node, so that the + * link between the tile and the node can be maintained, and the + * label, which has the information about the position and tile + * type of the label. + */ + +typedef struct reslabeldata { + ResExtNode *rld_node; + Label *rld_label; + ResConnect *rld_connect; +} ResLabelData; + +/* + *--------------------------------------------------------------------------- + * + * ResMakeLabelPorts -- + * + * Search for labels that are part of a node, and add them to the + * portList linked list in the "resInfo" field of their respective tiles + * in ResUse. This ensures (among other things) that pins of a top level + * cell will be retained and become the endpoint of a net. + * + * Results: + * None. + * + * Side effects: + * Adds information to the resInfo clientData of tiles in def. + * + *---------------------------------------------------------------------------- + */ + void -ResMakeLabelBreakpoints(def, resisdata) +ResMakeLabelPorts(def, resisdata) CellDef *def; ResisData *resisdata; { Plane *plane; - Rect *rect; TileTypeBitMask mask; HashEntry *entry; ResExtNode *node; + ResConnect *rdriver, *newsink; Label *slab; - int ResAddBreakpointFunc(); /* Forward Declaration */ + ResLabelData rld; + int ResAddLabelFunc(); /* Forward Declaration */ for (slab = def->cd_labels; slab != NULL; slab = slab->lab_next) { @@ -296,20 +454,26 @@ ResMakeLabelBreakpoints(def, resisdata) entry = HashFind(&ResNodeTable, slab->lab_text); node = ResExtInitNode(entry); - /* If the drivepoint position changes and the drivepoint is */ - /* in the "resisdata" record, then make sure the tile type */ - /* in "resisdata" gets changed to match. */ + /* If there is an existing drivepoint at this location, */ + /* then ignore it. */ - if (resisdata->rg_devloc == &node->drivepoint) + for (rdriver = node->drivepoints; rdriver; rdriver = rdriver->rc_next) + { + if (GEO_TOUCH(&slab->lab_rect, &rdriver->rc_rect)) + break; + } + if (rdriver != NULL) break; + + /* Add a new sinkpoint to the node where the label is */ + newsink = (ResConnect *)mallocMagic(sizeof(ResConnect)); + newsink->rc_next = node->sinkpoints; + node->sinkpoints = newsink; + + if (GEO_ENCLOSE(resisdata->rg_devloc, &slab->lab_rect)) resisdata->rg_ttype = slab->lab_type; - node->drivepoint = slab->lab_rect.r_ll; - node->rs_bbox = slab->lab_rect; - node->location = slab->lab_rect.r_ll; - node->rs_ttype = slab->lab_type; - node->type = slab->lab_type; - - rect = &(node->rs_bbox); + newsink->rc_rect = slab->lab_rect; + newsink->rc_type = slab->lab_type; /* If label is on a contact, the contact has been dissolved. */ /* Assume that the uppermost residue is the port. This may */ @@ -335,29 +499,44 @@ ResMakeLabelBreakpoints(def, resisdata) plane = def->cd_planes[DBPlane(slab->lab_type)]; } - (void) DBSrPaintArea((Tile *) NULL, plane, rect, &mask, - ResAddBreakpointFunc, (ClientData)node); - + rld.rld_node = node; + rld.rld_label = slab; + rld.rld_connect = newsink; + (void) DBSrPaintArea((Tile *) NULL, plane, &newsink->rc_rect, &mask, + ResAddLabelFunc, (ClientData)&rld); } } /* *---------------------------------------------------------------------------- * - * ResAddBreakpointFunc -- + * ResAddLabelFunc -- * - * Add a breakpoint to the "resInfo" structure of the tile + * Add a portList entry to the "resInfo" structure of the tile. The + * portList entry keeps a record of the area of overlap or abutment + * of the port, as well as a pointer to the resNode. + * + * Results: + * Always returns 0; + * + * Side effects: + * Adds information to a tile's "resInfo" clientData. * *---------------------------------------------------------------------------- */ int -ResAddBreakpointFunc(tile, dinfo, node) - Tile *tile; - TileType dinfo; /* (unused) */ - ResExtNode *node; +ResAddLabelFunc(tile, dinfo, rld) + Tile *tile; + TileType dinfo; /* (unused) */ + ResLabelData *rld; /* Label and node data */ { - resInfo *info; + resPort *rp; + resInfo *pX; + Rect rect; + Label *label; + ResExtNode *node; + ResConnect *connect; if (TiGetClient(tile) == CLIENTDEFAULT) return 0; @@ -370,12 +549,25 @@ ResAddBreakpointFunc(tile, dinfo, node) if (dinfo & TT_SIDE) return 0; - NEWPORT(node, tile); + node = rld->rld_node; + label = rld->rld_label; + connect = rld->rld_connect; + + TiToRect(tile, &rect); + + pX = (resInfo *)TiGetClient(tile); + + rp = (resPort *) mallocMagic((unsigned)(sizeof(resPort))); + rp->rp_nextPort = pX->portList; + rp->rp_bbox = label->lab_rect; + rp->rp_loc = label->lab_rect.r_ll; + rp->rp_connect = connect; + rp->rp_nodename = node->name; + pX->portList = rp; return 0; } - /* *--------------------------------------------------------------------------- * @@ -433,6 +625,7 @@ ResFindNewContactTiles(contacts) tile = PlaneGetHint(ResDef->cd_planes[pNum]); GOTOPOINT(tile, &(contacts->cp_center)); + PlaneSetHint(ResDef->cd_planes[pNum], tile); #ifdef PARANOID if (tile == (Tile *) NULL) { @@ -504,10 +697,10 @@ ResFindNewContactTiles(contacts) */ int -ResProcessTiles(resisdata, origin) - Point *origin; +ResProcessTiles(resisdata, origin, devices) ResisData *resisdata; - + Point *origin; + ResDevTile *devices; { Tile *startTile; int tilenum, merged; @@ -524,7 +717,8 @@ ResProcessTiles(resisdata, origin) if (startTile == NULL) return 1; resCurrentNode = NULL; - (void) ResEachTile(startTile, origin); + ResStartTile(startTile, origin->p_x, origin->p_y); + (void) ResEachTile(startTile, devices); } #ifdef PARANOID else @@ -561,7 +755,7 @@ ResProcessTiles(resisdata, origin) if ((ri->ri_status & RES_TILE_DONE) == 0) { resCurrentNode = resptr2; - merged |= ResEachTile(tile, (Point *)NULL); + merged |= ResEachTile(tile, devices); } } rj->rj_status = TRUE; @@ -587,7 +781,7 @@ ResProcessTiles(resisdata, origin) if (cp->cp_cnode[tilenum] == resptr2) { resCurrentNode = resptr2; - merged |= ResEachTile(tile, (Point *)NULL); + merged |= ResEachTile(tile, devices); } else { @@ -670,7 +864,7 @@ ResCalcPerimOverlap(tile, dev) } /* right */ - for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp=LB(tp)) + for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp)) { if TTMaskHasType(omask, TiGetLeftType(tp)) overlap += MIN(TOP(tile), TOP(tp)) - MAX(BOTTOM(tile), BOTTOM(tp)); @@ -684,7 +878,7 @@ ResCalcPerimOverlap(tile, dev) } /* bottom */ - for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp)) + for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp)) { if TTMaskHasType(omask, TiGetTopType(tp)) overlap += MIN(RIGHT(tile), RIGHT(tp)) - MAX(LEFT(tile), LEFT(tp)); @@ -1015,6 +1209,7 @@ ResExtractNet(node, resisdata, cellname) int pNum; int resMakeDevFunc(); int resExpandDevFunc(); + int result; /* Make sure all global network variables are reset */ @@ -1069,15 +1264,22 @@ ResExtractNet(node, resisdata, cellname) /* Copy Paint */ - /* If the node location is INFINITY, then use the rs_bbox */ + /* If the node location is INFINITY, then use the first drivepoint */ if ((node->location.p_x == INFINITY) || (node->location.p_y == INFINITY)) { - scx.scx_area.r_ll.p_x = node->rs_bbox.r_xbot; - scx.scx_area.r_ll.p_y = node->rs_bbox.r_ybot; - scx.scx_area.r_ur.p_x = node->rs_bbox.r_xtop; - scx.scx_area.r_ur.p_y = node->rs_bbox.r_ytop; - startpoint = node->drivepoint; + ResConnect *rdriver = node->drivepoints; + if (rdriver) + { + scx.scx_area.r_ll.p_x = rdriver->rc_rect.r_xbot - 2; + scx.scx_area.r_ll.p_y = rdriver->rc_rect.r_ybot - 2; + scx.scx_area.r_ur.p_x = rdriver->rc_rect.r_xtop + 2; + scx.scx_area.r_ur.p_y = rdriver->rc_rect.r_ytop + 2; + startpoint.p_x = (rdriver->rc_rect.r_xtop + rdriver->rc_rect.r_xbot) / 2; + startpoint.p_y = (rdriver->rc_rect.r_ytop + rdriver->rc_rect.r_ybot) / 2; + } + else + TxError("Internal error: Node location is set to infinity.\n"); } else { @@ -1100,15 +1302,41 @@ ResExtractNet(node, resisdata, cellname) DBTreeCopyConnect(&scx, &FirstTileMask, 0, ResCopyMask, &TiPlaneRect, SEL_DO_LABELS, ResUse); } + else if (node->drivepoints) + { + /* Use the first valid drivepoint */ + ResConnect *drivepoint = node->drivepoints; + while (drivepoint && (drivepoint->rc_type == TT_SPACE)) + drivepoint = drivepoint->rc_next; + if (drivepoint) + { + TTMaskZero(&FirstTileMask); + TTMaskSetMask(&FirstTileMask, &DBConnectTbl[drivepoint->rc_type]); - TTMaskZero(&ResSDTypesBitMask); + DBTreeCopyConnect(&scx, &FirstTileMask, 0, ResCopyMask, &TiPlaneRect, + SEL_DO_LABELS, ResUse); + } + else + { + TxError("Node %s: Did not find the net layout at any drivepoint.\n", + node->name); + return TRUE; + } + } + else + { + TxError("Node %s: Did not find the net layout at node location (%d %d).\n", + node->name, node->location.p_x, node->location.p_y); + return TRUE; + } + + TTMaskZero(&ResTermTypesBitMask); TTMaskZero(&ResSubTypesBitMask); /* Add devices to ResUse from list in node */ DevTiles = NULL; - for (tptr = node->firstDev; tptr; tptr = tptr->nextDev) + for (tptr = node->devices; tptr; tptr = tptr->nextDev) { - int result; int i; ExtDevice *devptr; @@ -1138,13 +1366,13 @@ ResExtractNet(node, resisdata, cellname) TTMaskSetOnlyType(&tMask, thisDev->type); DBTreeSrTiles(&scx, &tMask, 0, resExpandDevFunc, (ClientData)thisDev); - /* If the device has source/drain types in a different plane than */ - /* the device identifier type, then add the source/drain types to */ - /* the mask ResSDTypesBitMask. */ + /* If the device has terminal types in a different plane than */ + /* the device identifier type, then add the terminal types to */ + /* the mask ResTermTypesBitMask. */ devptr = tptr->thisDev->rs_devptr; for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++) - TTMaskSetMask(&ResSDTypesBitMask, &devptr->exts_deviceSDTypes[i]); + TTMaskSetMask(&ResTermTypesBitMask, &devptr->exts_deviceSDTypes[i]); /* Add the substrate types to the mask ResSubTypesBitMask */ TTMaskSetMask(&ResSubTypesBitMask, &devptr->exts_deviceSubstrateTypes); @@ -1154,8 +1382,6 @@ ResExtractNet(node, resisdata, cellname) } DBReComputeBbox(ResUse->cu_def); - ExtResetTiles(scx.scx_use->cu_def, CLIENTDEFAULT); - /* To avoid issues with overlapping stacked contact types and */ /* double-counting contacts on multiple planes, erase the top */ /* contact layers of all contacts. ExtFindRegions() will still */ @@ -1191,27 +1417,38 @@ ResExtractNet(node, resisdata, cellname) ResDissolveContacts(ResContactList); - /* Add "resInfo" fields to tiles */ + /* Fracture the plane to change maximum horizontal stripes to a + * format better suited to tracking the path of current through + * the wiring. + */ for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) { Plane *plane = ResUse->cu_def->cd_planes[pNum]; Rect *rect = &ResUse->cu_def->cd_bbox; ResFracture(plane, rect); - (void) DBSrPaintClient((Tile *) NULL, plane, rect, - &DBAllButSpaceAndDRCBits, - (ClientData) CLIENTDEFAULT, ResAddPlumbing, - (ClientData) &ResDevList); } + /* Add "resInfo" fields to device tiles. */ + for (thisDev = DevTiles; thisDev; thisDev = thisDev->nextDev) + ResAddDevPlumbing(thisDev, &ResDevList); + + /* Add "resInfo" fields to any untouched tiles. */ + for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) + DBSrPaintClient((Tile *)NULL, + ResUse->cu_def->cd_planes[pNum], + &TiPlaneRect, &DBAllButSpaceAndDRCBits, + (ClientData)CLIENTDEFAULT, ResAddPlumbing, + (ClientData)NULL); + /* If this is a top-level cell, then determine where connections * are made into the cell from ports. Otherwise, determine points * of entry by looking at how all parent cells connect to this * cell. */ - ResMakePortBreakpoints(ResUse->cu_def); - ResMakeLabelBreakpoints(ResUse->cu_def, resisdata); + ResMakeDriverSinkPorts(ResUse->cu_def); + ResMakeLabelPorts(ResUse->cu_def, resisdata); /* Finish preprocessing. */ @@ -1219,7 +1456,9 @@ ResExtractNet(node, resisdata, cellname) ResPreProcessDevices(DevTiles, ResDevList, ResUse->cu_def); /* do extraction */ - if (ResProcessTiles(resisdata, &startpoint) != 0) return TRUE; + result = ResProcessTiles(resisdata, &startpoint, DevTiles); + ResFreeDevTiles(DevTiles); + if (result != 0) return TRUE; return FALSE; } @@ -1396,6 +1635,7 @@ FindStartTile(resisdata, SourcePoint) { tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]); GOTOPOINT(tile, &workingPoint); + PlaneSetHint(ResUse->cu_def->cd_planes[pnum], tile); SourcePoint->p_x = workingPoint.p_x; SourcePoint->p_y = workingPoint.p_y; @@ -1410,13 +1650,13 @@ FindStartTile(resisdata, SourcePoint) if (workingPoint.p_x == LEFT(tile)) { - for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp)) + for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp)) if (TiGetRightType(tp) == resisdata->rg_ttype) return(tp); } else if (workingPoint.p_y == BOTTOM(tile)) { - for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp)) + for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp)) if (TiGetTopType(tp) == resisdata->rg_ttype) return(tp); } @@ -1429,6 +1669,7 @@ FindStartTile(resisdata, SourcePoint) tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]); GOTOPOINT(tile, &workingPoint); + PlaneSetHint(ResUse->cu_def->cd_planes[pnum], tile); if (IsSplit(tile)) { @@ -1472,7 +1713,7 @@ FindStartTile(resisdata, SourcePoint) TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2)) { SourcePoint->p_x = LEFT(tile); - SourcePoint->p_y = (MIN(TOP(tile),TOP(tp)) + + SourcePoint->p_y = (MIN(TOP(tile), TOP(tp)) + MAX(BOTTOM(tile), BOTTOM(tp))) >> 1; return(tp); } @@ -1515,7 +1756,7 @@ FindStartTile(resisdata, SourcePoint) TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2)) { SourcePoint->p_y = TOP(tile); - SourcePoint->p_x = (MIN(RIGHT(tile),RIGHT(tp)) + + SourcePoint->p_x = (MIN(RIGHT(tile), RIGHT(tp)) + MAX(LEFT(tile), LEFT(tp))) >> 1; return(tp); } @@ -1571,7 +1812,7 @@ FindStartTile(resisdata, SourcePoint) TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2)) { SourcePoint->p_x = LEFT(tile); - SourcePoint->p_y = (MIN(TOP(tile),TOP(tp)) + + SourcePoint->p_y = (MIN(TOP(tile), TOP(tp)) + MAX(BOTTOM(tile), BOTTOM(tp))) >> 1; while (!StackEmpty(devStack)) { @@ -1639,7 +1880,7 @@ FindStartTile(resisdata, SourcePoint) TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2)) { SourcePoint->p_y = TOP(tile); - SourcePoint->p_x = (MIN(RIGHT(tile),RIGHT(tp)) + + SourcePoint->p_x = (MIN(RIGHT(tile), RIGHT(tp)) + MAX(LEFT(tile), LEFT(tp))) >> 1; while (!StackEmpty(devStack)) { @@ -1780,6 +2021,7 @@ ResGetDevice(pt, type) tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]); GOTOPOINT(tile, &workingPoint); + PlaneSetHint(ResUse->cu_def->cd_planes[pnum], tile); const ClientData ticlient = TiGetClient(tile); if (IsSplit(tile)) diff --git a/resis/ResMakeRes.c b/resis/ResMakeRes.c index 73fe0b99..d9ea3222 100644 --- a/resis/ResMakeRes.c +++ b/resis/ResMakeRes.c @@ -76,10 +76,9 @@ ResCalcTileResistance(tile, info, pendingList, doneList) if (x < MinX) MinX = x; if (y > MaxY) MaxY = y; if (y < MinY) MinY = y; + if (p1->br_this->rn_why == RES_NODE_DEVICE) - { device = TRUE; - } } /* Finally, produce resistors for partition. Keep track of */ @@ -125,7 +124,7 @@ ResCalcEastWest(tile, pendingList, doneList, resList) resNode **pendingList, **doneList; resResistor **resList; { - int height; + int count, height; bool merged; TileType ttype; Breakpoint *p1, *p2, *p3; @@ -134,6 +133,8 @@ ResCalcEastWest(tile, pendingList, doneList, resList) resNode *currNode; float rArea; resInfo *info = (resInfo *)TiGetClientPTR(tile); + HashTable BreakTable; + HashEntry *he; merged = FALSE; height = TOP(tile) - BOTTOM(tile); @@ -163,21 +164,38 @@ ResCalcEastWest(tile, pendingList, doneList, resList) ttype = TiGetTypeExact(tile); /* Re-sort nodes left to right. */ + count = ResSortBreaks(&info->breakList, TRUE); - ResSortBreaks(&info->breakList, TRUE); + /* For long lists (defined as >= 16 entries), make a hash table of + * the node pointer conversions so that each node can be updated + * as we walk the list, instead of walking the rest of the list in + * a nested loop for each entry. + */ + if (count >= 16) + HashInit(&BreakTable, HT_DEFAULTSIZE, HT_CLIENTKEYS); /* * Eliminate breakpoints with the same X coordinate and merge * their nodes. */ - p2= info->breakList; + p2 = info->breakList; /* Add extra left area to leftmost node */ p2->br_this->rn_float.rn_area += height * (p2->br_loc.p_x - LEFT(tile)); while (p2->br_next != NULL) { + /* Has the node been recorded as needing to be replaced? */ + if (count >= 16) + { + while (TRUE) + { + he = HashLookOnly(&BreakTable, (char *)p2->br_this); + if (!he) break; + p2->br_this = (resNode *)HashGetValue(he); + } + } p1 = p2; p2 = p2->br_next; if (p2->br_loc.p_x == p1->br_loc.p_x) @@ -215,25 +233,38 @@ ResCalcEastWest(tile, pendingList, doneList, resList) /* * Was the node used in another info or breakpoint? * If so, replace the old node with the new one. + * + * Short lists: Walk the list to the end and change + * nodes on the fly. + * Long lists: Record the change to be made in the + * hash table so that it can be executed as each list + * entry is encountered. */ - - p3 = p2->br_next; - while (p3 != NULL) + if (count >= 16) { - if (p3->br_this == currNode) - p3->br_this = p2->br_this; - - p3 = p3->br_next; + he = HashFind(&BreakTable, (char *)currNode); + HashSetValue(he, (char *)p2->br_this); } - } + else + { + p3 = p2->br_next; + while (p3 != NULL) + { + if (p3->br_this == currNode) + p3->br_this = p2->br_this; - /* - * If the X coordinates don't match, make a resistor between - * the breakpoints. - */ + p3 = p3->br_next; + } + } + } - else - { + /* + * If the X coordinates don't match, make a resistor between + * the breakpoints. + */ + + else + { resistor = (resResistor *)mallocMagic((unsigned)sizeof(resResistor)); resistor->rr_nextResistor = (*resList); resistor->rr_lastResistor = NULL; @@ -276,6 +307,8 @@ ResCalcEastWest(tile, pendingList, doneList, resList) } } + if (count >= 16) HashKill(&BreakTable); + p2->br_this->rn_float.rn_area += height * (RIGHT(tile) - p2->br_loc.p_x); freeMagic((char *)p2); info->breakList = NULL; @@ -301,7 +334,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList) resNode **pendingList, **doneList; resResistor **resList; { - int width; + int count, width; bool merged; TileType ttype; Breakpoint *p1, *p2, *p3; @@ -310,6 +343,8 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList) resNode *currNode; float rArea; resInfo *info = (resInfo *)TiGetClientPTR(tile); + HashTable BreakTable; + HashEntry *he; merged = FALSE; width = RIGHT(tile) - LEFT(tile); @@ -329,7 +364,15 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList) } /* Re-sort nodes south to north. */ - ResSortBreaks(&info->breakList, FALSE); + count = ResSortBreaks(&info->breakList, FALSE); + + /* For long lists (defined as >= 16 entries), make a hash table of + * the node pointer conversions so that each node can be updated + * as we walk the list, instead of walking the rest of the list in + * a nested loop for each entry. + */ + if (count >= 16) + HashInit(&BreakTable, HT_DEFAULTSIZE, HT_CLIENTKEYS); /* Simplified split tile handling */ if (IsSplit(tile)) @@ -353,51 +396,75 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList) p2->br_this->rn_float.rn_area += width * (p2->br_loc.p_y - BOTTOM(tile)); while (p2->br_next != NULL) { + /* Has the node been recorded as needing to be replaced? */ + if (count >= 16) + { + while (TRUE) + { + he = HashLookOnly(&BreakTable, (char *)p2->br_this); + if (!he) break; + p2->br_this = (resNode *)HashGetValue(he); + } + } p1 = p2; p2 = p2->br_next; if (p1->br_loc.p_y == p2->br_loc.p_y) { if (p2->br_this == p1->br_this) { - currNode = NULL; - p1->br_next = p2->br_next; - freeMagic((char *)p2); - p2 = p1; + currNode = NULL; + p1->br_next = p2->br_next; + freeMagic((char *)p2); + p2 = p1; } else if (p2->br_this == resCurrentNode) { - currNode = p1->br_this; - ResMergeNodes(p2->br_this, p1->br_this, pendingList, doneList); - freeMagic((char *)p1); - merged = TRUE; + currNode = p1->br_this; + ResMergeNodes(p2->br_this, p1->br_this, pendingList, doneList); + freeMagic((char *)p1); + merged = TRUE; } else if (p1->br_this == resCurrentNode) { - currNode = p2->br_this; - p1->br_next = p2->br_next; - ResMergeNodes(p1->br_this, p2->br_this, pendingList, doneList); - merged = TRUE; - freeMagic((char *)p2); - p2 = p1; + currNode = p2->br_this; + p1->br_next = p2->br_next; + ResMergeNodes(p1->br_this, p2->br_this, pendingList, doneList); + merged = TRUE; + freeMagic((char *)p2); + p2 = p1; } else { - currNode = p1->br_this; - ResMergeNodes(p2->br_this, p1->br_this, pendingList, doneList); - freeMagic((char *)p1); + currNode = p1->br_this; + ResMergeNodes(p2->br_this, p1->br_this, pendingList, doneList); + freeMagic((char *)p1); } /* * Was the node used in another info or breakpoint? * If so, replace the old node with the new one. + * + * Short lists: Walk the list to the end and change + * nodes on the fly. + * Long lists: Record the change to be made in the + * hash table so that it can be executed as each list + * entry is encountered. */ - p3 = p2->br_next; - while (p3 != NULL) + if (count >= 16) { - if (p3->br_this == currNode) - p3->br_this = p2->br_this; + he = HashFind(&BreakTable, (char *)currNode); + HashSetValue(he, (char *)p2->br_this); + } + else + { + p3 = p2->br_next; + while (p3 != NULL) + { + if (p3->br_this == currNode) + p3->br_this = p2->br_this; - p3 = p3->br_next; + p3 = p3->br_next; + } } } @@ -491,7 +558,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList) * breakpoint, then return. */ - if (info->breakList->br_next == NULL) + if (info->breakList->br_next == NULL) { freeMagic((char *)info->breakList); info->breakList = NULL; @@ -620,7 +687,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList) } else { - deltay=0; + deltay = 0; } } else @@ -634,15 +701,15 @@ ResCalcNearDevice(tile, pendingList, doneList, resList) { if (p2->br_crect->r_ll.p_y > p1->br_loc.p_y) { - deltay = MIN(deltay,p2->br_crect->r_ll.p_y - p1->br_loc.p_y); + deltay = MIN(deltay, p2->br_crect->r_ll.p_y - p1->br_loc.p_y); } else if (p2->br_crect->r_ur.p_y < p1->br_loc.p_y) { - deltay = MIN(deltay,p1->br_loc.p_y - p2->br_crect->r_ur.p_y); + deltay = MIN(deltay, p1->br_loc.p_y - p2->br_crect->r_ur.p_y); } else { - deltay=0; + deltay = 0; } } else @@ -820,7 +887,7 @@ ResDoContacts(contact, nodes, resList) Tile *tile = contact->cp_tile[tilenum]; contact->cp_cnode[tilenum] = resptr; - NEWBREAK(resptr, tile, contact->cp_center.p_x, + ResNewBreak(resptr, tile, contact->cp_center.p_x, contact->cp_center.p_y, &contact->cp_rect); } } @@ -869,7 +936,7 @@ ResDoContacts(contact, nodes, resList) ccell->ce_thisc = contact; contact->cp_cnode[tilenum] = resptr; - NEWBREAK(resptr, tile, contact->cp_center.p_x, + ResNewBreak(resptr, tile, contact->cp_center.p_x, contact->cp_center.p_y, &contact->cp_rect); /* Add resistors here */ @@ -1093,12 +1160,14 @@ MergeSortBreaks(Breakpoint *list, int xsort) * bottleneck. * * Results: - * None + * Return the length of the list (maximum truncated at 16) so that + * the calling routine can determine if this is a long or a short + * linked list and treat it accordingly. * *------------------------------------------------------------------------- */ -void +int ResSortBreaks(masterlist, xsort) Breakpoint **masterlist; int xsort; @@ -1113,7 +1182,7 @@ ResSortBreaks(masterlist, xsort) if (count > 16) { *masterlist = MergeSortBreaks(*masterlist, xsort); - return; + return count; } } @@ -1154,5 +1223,6 @@ ResSortBreaks(masterlist, xsort) } } } + return count; } diff --git a/resis/ResMerge.c b/resis/ResMerge.c index aafdc992..3e4b4dec 100644 --- a/resis/ResMerge.c +++ b/resis/ResMerge.c @@ -210,7 +210,7 @@ ResFixParallel(elimResis, newResis) * ResSeriesCheck -- for nodes with no devices, sees if a series * or loop combination is possible. * - * Results: returns SINGLE,LOOP,or SERIES if succesful. + * Results: returns SINGLE, LOOP, or SERIES if succesful. * * Side Effects: may delete some nodes and resistors. * @@ -839,9 +839,9 @@ ResTriangleCheck(resptr) * * ResMergeNodes-- * - * results: none + * Results: none * - * side effects: appends all the cElement, jElement, tElement and + * Side Effects: appends all the cElement, jElement, tElement and * resElement structures from node 2 onto node 1. Node 2 is * then eliminated. * @@ -1010,7 +1010,7 @@ ResMergeNodes(node1, node2, pendingList, doneList) * ResDeleteResPointer-- Deletes the pointer from a node to a resistor. * Used when a resistor is deleted. * - * Results:none + * Results: none * * Side Effects: Modifies a node's resistor list. * @@ -1018,7 +1018,7 @@ ResMergeNodes(node1, node2, pendingList, doneList) */ void -ResDeleteResPointer(node,resistor) +ResDeleteResPointer(node, resistor) resNode *node; resResistor *resistor; @@ -1059,7 +1059,7 @@ ResDeleteResPointer(node,resistor) * * ResEliminateResistor-- * - * Results:none + * Results: none * * Side Effects: Deletes a resistor. Does not delete pointers from nodes to * resistor. @@ -1097,8 +1097,7 @@ ResEliminateResistor(resistor, homelist) * they are no longer needed. If the 'info' option is used, * the node is eradicated. * - * Results: - * None. + * Results: none. * * Side Effects: frees memory * diff --git a/resis/ResPrint.c b/resis/ResPrint.c index 4d0e68e6..91eeef41 100644 --- a/resis/ResPrint.c +++ b/resis/ResPrint.c @@ -52,7 +52,7 @@ ResPrintExtRes(outextfile, resistors, nodename) char *nodename; { - int nodenum=0; + int nodenum = 0; char newname[MAXNAME]; HashEntry *entry; ResExtNode *node; @@ -261,7 +261,7 @@ ResPrintExtNode(outextfile, nodelist, node) { if (snode->rn_name == NULL) { - (void)sprintf(tmpname,"%s",nodename); + (void)sprintf(tmpname, "%s", nodename); cp = tmpname + strlen(tmpname) - 1; if (*cp == '!' || *cp == '#') *cp = '\0'; @@ -342,13 +342,13 @@ ResPrintStats(resisdata, name) nodes = 0; resistors = 0; totalnets++; - for (node = ResNodeList; node != NULL; node=node->rn_more) + for (node = ResNodeList; node != NULL; node = node->rn_more) { nodes++; totalnodes++; } - for (res = ResResList; res != NULL; res=res->rr_nextResistor) + for (res = ResResList; res != NULL; res = res->rr_nextResistor) { resistors++; totalresistors++; diff --git a/resis/ResReadExt.c b/resis/ResReadExt.c index 7b880d96..7bd95c09 100644 --- a/resis/ResReadExt.c +++ b/resis/ResReadExt.c @@ -61,6 +61,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #define DEV_PARAM_START 7 #define NODES_NODENAME 1 +#define NODES_NODERES 2 #define NODES_NODEX 4 #define NODES_NODEY 5 #define NODES_NODETYPE 6 @@ -82,6 +83,24 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #define PORT_URY 6 #define PORT_TYPE 7 +#define USE_DEF_NAME 1 +#define USE_ID_NAME 2 +#define USE_TRANSFORM_A 3 +#define USE_TRANSFORM_B 4 +#define USE_TRANSFORM_C 5 +#define USE_TRANSFORM_D 6 +#define USE_TRANSFORM_E 7 +#define USE_TRANSFORM_F 8 + +/* Note that "connect" lines may repeat these six entries up to argc */ +#define CONNECT_LLX 1 +#define CONNECT_LLY 2 +#define CONNECT_URX 3 +#define CONNECT_URY 4 +#define CONNECT_TYPE 5 +#define CONNECT_UP_NAME 6 +#define CONNECT_DOWN_NAME 7 + #define MAXDIGIT 20 ResExtNode *ResOriginalNodes; /*Linked List of Nodes */ @@ -91,11 +110,18 @@ ResFixPoint *ResFixList; /* *------------------------------------------------------------------------- * - * ResReadExt-- + * ResReadExt -- * - * Results: returns 0 if ext file is correct, 1 if not. + * Read a .ext file for resistance extraction. Extresist does not use + * the .ext file reader in extflat/EFread.c because it takes only a + * small amount of information from the .ext file, mainly to keep a + * list of nets and net names, devices and their terminals and + * connections, and subcell connections. However, it does make use + * of the line parser and tokenizer in extflat. * - * Side Effects:Reads in ExtTable and makes a hash table of nodes. + * Results: Returns 0 if ext file is correct, 1 if not. + * + * Side Effects: Creates lists of nodes and devices for extresist. * *------------------------------------------------------------------------- */ @@ -107,8 +133,11 @@ ResReadExt(CellDef *def) int result, locresult; int argc, n, size = 0; FILE *fp; - CellDef *dbdef; + CellDef *dbdef, *parent; + CellUse *use; ResExtNode *curnode; + HashTable parentHash; + HashEntry *he; /* Search for the .ext file in the same way that efReadDef() does. */ @@ -142,7 +171,10 @@ ResReadExt(CellDef *def) } /* We don't care about most tokens, only DEVICE, NODE, PORT, - * and SUBSTRATE; and MERGE is used to locate drive points. + * and SUBSTRATE; and CONNECT is used to locate sink points. + * Note that MERGE is not useful here, as it may implicitly + * merge nets in the cell, which is useful for netlisting but + * not for annotating the extraction file. */ switch (keyTable[n].k_key) { @@ -161,17 +193,16 @@ ResReadExt(CellDef *def) case FET: locresult = ResReadFET(argc, argv); break; - case MERGE: - /* To be completed */ - /* ResReadDrivePoint(argc, argv); */ + case CONNECT: + locresult = ResReadConnectPoint(def, argc, argv); + break; + case PORT: + locresult = ResReadPort(argc, argv); break; case NODE: case SUBSTRATE: curnode = ResReadNode(argc, argv); break; - case PORT: - locresult = ResReadPort(argc, argv); - break; case ATTR: locresult = ResReadAttribute(curnode, argc, argv); break; @@ -184,9 +215,293 @@ ResReadExt(CellDef *def) if (locresult == 1) result = 1; } fclose(fp); + + /* Find all the parent CellDefs of "def" and read the .ext file of + * each one to find where connections are made to this cell from + * parent cells. Place drive points at each connection point. + */ + HashInit(&parentHash, 32, HT_STRINGKEYS); + + for (use = def->cd_parents; use; use = use->cu_nextuse) + { + if ((parent = use->cu_parent) == NULL) continue; + if (parent->cd_flags & CDINTERNAL) continue; + he = HashFind(&parentHash, parent->cd_name); + if ((CellDef *)HashGetValue(he) == NULL) + { + /* Mark parent def as being visited */ + HashSetValue(he, (char *)parent); + /* Read connection information from the parent's .ext file */ + ResReadParentExt(parent, def); + } + } + HashKill(&parentHash); + return(result); } +/* + *------------------------------------------------------------------------- + * + * ResReadUse -- + * + * Read a "use" statement from the .ext file of a parent CellDef of + * the current def being extracted. If the use is a use of the + * current def, then save the use name and its transform in the + * hash table so that later "connect" statements can be translated + * into the coordinate system of the current cell def. + * + * Results: + * 1 if something went wrong with the parsing, 0 otherwise. + * + * Side effects: + * May add to the hash table. + * + *------------------------------------------------------------------------- + */ + +int +ResReadUse(CellDef *def, + int argc, + char *argv[], + HashTable *useHash) +{ + char *defname, *useid; + Transform *tinv, t; + HashEntry *he; + + defname = argv[USE_DEF_NAME]; + + if (strcmp(defname, def->cd_name)) return 0; /* Not my use */ + + useid = argv[USE_ID_NAME]; + + he = HashFind(useHash, useid); + + t.t_a = atoi(argv[USE_TRANSFORM_A]); + t.t_b = atoi(argv[USE_TRANSFORM_B]); + t.t_c = atoi(argv[USE_TRANSFORM_C]); + t.t_d = atoi(argv[USE_TRANSFORM_D]); + t.t_e = atoi(argv[USE_TRANSFORM_E]); + t.t_f = atoi(argv[USE_TRANSFORM_F]); + + tinv = (Transform *)mallocMagic(sizeof(Transform)); + GeoInvertTrans(&t, tinv); + + HashSetValue(he, (char *)tinv); + return 0; +} + +/* + *------------------------------------------------------------------------- + * + * ResReadDrivePoint -- + * + * Read a "connect" statement from the .ext file of a parent CellDef + * of the current def being extracted. If the connection is made to + * a use of the current def, then translate the area of the connection + * into the current def, and mark the connection as a drive point of + * def. + * + * Results: + * 1 if something went wrong with the parsing, 0 otherwise. + * + * Side effects: + * May add information to the node list of def. + * + *------------------------------------------------------------------------- + */ + +int +ResReadDrivePoint(CellDef *def, + int argc, + char *argv[], + HashTable *useHash) +{ + HashEntry *entry; + ResExtNode *node; + ResConnect *newdriver; + int pNum; + TileType ttype; + Transform *t; + Rect r; + char *hierptr, *useid, *qptr, *downname; + + /* Only handle entries that are in the use ID hash table */ + + useid = argv[CONNECT_DOWN_NAME]; + if (*useid == '"') useid++; + hierptr = strchr(useid, '/'); + if (hierptr != NULL) *hierptr = '\0'; + qptr = strrchr(useid, '"'); + if (qptr != NULL) *qptr = '\0'; + if (hierptr != NULL) + downname = hierptr + 1; + else + downname = useid; /* This is probably invalid */ + + entry = HashFind(useHash, useid); + if ((t = (Transform *)HashGetValue(entry)) == NULL) return 0; + + /* Check for the given tile type */ + ttype = DBTechNoisyNameType(argv[CONNECT_TYPE]); + + if (ttype == -1) + { + TxError("Bad tile type name \"%s\" in .ext file for node %s\n", + argv[CONNECT_TYPE], argv[CONNECT_UP_NAME]); + return 1; + } + + /* Look up the node name */ + if (strcmp(downname, "None")) + { + entry = HashLookOnly(&ResNodeTable, downname); + if (entry != NULL) + node = (ResExtNode *)HashGetValue(entry); + else + { + TxError("Unknown node name \"%s\" in .ext file connect entry\n", + downname); + return 1; + } + + /* Generate new drivepoint entry */ + + newdriver = (ResConnect *)mallocMagic(sizeof(ResConnect)); + + r.r_xbot = atoi(argv[CONNECT_LLX]); + r.r_ybot = atoi(argv[CONNECT_LLY]); + r.r_xtop = atoi(argv[CONNECT_URX]); + r.r_ytop = atoi(argv[CONNECT_URY]); + + /* Translate the connection position from the parent to the + * current cell def. + */ + GeoTransRect(t, &r, &newdriver->rc_rect); + + newdriver->rc_type = ttype; + newdriver->rc_node = (resNode *)NULL; + + newdriver->rc_next = node->drivepoints; + node->drivepoints = newdriver; + node->status |= FORCE | DRIVELOC; + + if (ResOptionsFlags & ResOpt_Debug) + { + /* Diagnostic */ + TxPrintf("Added driver at %d %d %d %d\n", + newdriver->rc_rect.r_xbot, newdriver->rc_rect.r_ybot, + newdriver->rc_rect.r_xtop, newdriver->rc_rect.r_ytop); + } + } + + return 0; +} + +/* + *------------------------------------------------------------------------- + * + * ResReadParentExt -- + * + * Read a .ext file for a parent cell of the cell being extracted. + * Each .ext file contains a list of connection points into its + * subcells. However, no .ext file has information about how a + * parent cell connects to it; the exact connection may depend on + * the layout, and may or may not coincide with marked ports. + * Except for the top level cell, for which only marked ports can + * be used to guess at intended points of connection, every subcell + * can query its parents to find exact points of connection. + * + * Results: Returns 0 if ext file is correct, 1 if not. + * + * Side Effects: Creates lists of connection points for extresist. + * + *------------------------------------------------------------------------- + */ + +int +ResReadParentExt(CellDef *parent, + CellDef *def) +{ + char *line = NULL, *argv[128]; + int result, locresult; + int argc, n, size = 0; + FILE *fp; + CellDef *dbdef; + ResExtNode *curnode; + HashTable useHash; + HashEntry *he; + HashSearch hs; + + /* Search for the .ext file in the same way that efReadDef() does. */ + + fp = ExtFileOpen(parent, (char *)NULL, "r", (char **)NULL); + if (fp == NULL) + { + TxError("Cannot open file %s%s\n", parent->cd_name, ".ext"); + return 1; + } + + HashInit(&useHash, 32, HT_STRINGKEYS); + + /* Read in the file. Makes use of various functions + * from extflat, mostly in EFread.c. + */ + + EFSaveLocs = FALSE; + efReadLineNum = 0; + result = 0; + + while ((argc = efReadLine(&line, &size, fp, argv)) >= 0) + { + n = LookupStruct(argv[0], (const LookupTable *)keyTable, sizeof keyTable[0]); + if (n < 0) + { + efReadError("Unrecognized token \"%s\" (ignored)\n", argv[0]); + continue; + } + if (argc < keyTable[n].k_mintokens) + { + efReadError("Not enough tokens for %s line\n", argv[0]); + continue; + } + + /* When reading a parent .ext file to find connections to + * the cell being extracted by "extresist", we only care + * about CONNECT lines, and USE lines so that we can + * translate the connection points into the current cell def. + * + * Note: This method depends on the .ext file format having + * all "use" lines before "connect" lines. + */ + switch (keyTable[n].k_key) + { + case USE: + locresult = ResReadUse(def, argc, argv, &useHash); + break; + case CONNECT: + locresult = ResReadDrivePoint(def, argc, argv, &useHash); + break; + default: + break; + } + if (locresult == 1) result = 1; + } + fclose(fp); + + HashStartSearch(&hs); + while ((he = HashNext(&useHash, &hs))) + { + if (HashGetValue(he) != NULL) + { + freeMagic(HashGetValue(he)); /* Free the allocated tranform */ + HashSetValue(he, (ClientData)NULL); + } + } + HashKill(&useHash); + return(result); +} /* *------------------------------------------------------------------------- @@ -207,20 +522,18 @@ ResReadNode(int argc, char *argv[]) { HashEntry *entry; ResExtNode *node; + int noderesist; entry = HashFind(&ResNodeTable, argv[NODES_NODENAME]); node = ResExtInitNode(entry); node->location.p_x = atoi(argv[NODES_NODEX]); node->location.p_y = atoi(argv[NODES_NODEY]); - - /* If this node was previously read as a port, then don't change the - * node type, which is tracking the type at the drivepoint. - */ - if (!(node->status & PORTNODE)) - { - node->type = DBTechNameType(argv[NODES_NODETYPE]); - } + node->type = DBTechNameType(argv[NODES_NODETYPE]); + noderesist = atoi(argv[NODES_NODERES]); + if (noderesist < 0) noderesist = INFINITY; + /* Make sure node resistance is in units of milliohms */ + node->resistance = (float)noderesist * (float)ExtCurStyle->exts_resistScale; if (node->type == -1) { @@ -230,6 +543,85 @@ ResReadNode(int argc, char *argv[]) return node; } +/* + *------------------------------------------------------------------------- + * + * ResReadConnectPoint-- Reads in a "connect" statement from the .ext file + * and sets node records accordingly to mark the node as a connection + * point. There is a use (instance) name associated with each connection, + * which is unused for finding connection points to subcells; we + * don't care what the subcell is, only that there is a connection at + * a point on a net in this cell that should be recorded and never + * optimized out. + * + * Results: 0 if successful and 1 otherwise. + * + * Side Effects: see above + * + *------------------------------------------------------------------------- + */ + +int +ResReadConnectPoint(CellDef *def, + int argc, + char *argv[]) +{ + HashEntry *entry; + ResExtNode *node; + ResConnect *newsink; + int pNum; + TileType ttype; + + /* Check for the given tile type */ + ttype = DBTechNoisyNameType(argv[CONNECT_TYPE]); + + if (ttype == -1) + { + TxError("Bad tile type name \"%s\" in .ext file for node %s\n", + argv[CONNECT_TYPE], argv[CONNECT_UP_NAME]); + return 1; + } + + /* Look up the node name */ + if (strcmp(argv[CONNECT_UP_NAME], "None")) + { + entry = HashLookOnly(&ResNodeTable, argv[CONNECT_UP_NAME]); + if (entry != NULL) + node = (ResExtNode *)HashGetValue(entry); + else + { + TxError("Unknown node name \"%s\" in .ext file connect entry\n", + argv[CONNECT_UP_NAME]); + return 1; + } + + /* Generate new sinkpoint entry */ + + newsink = (ResConnect *)mallocMagic(sizeof(ResConnect)); + + newsink->rc_rect.r_xbot = atoi(argv[CONNECT_LLX]); + newsink->rc_rect.r_ybot = atoi(argv[CONNECT_LLY]); + newsink->rc_rect.r_xtop = atoi(argv[CONNECT_URX]); + newsink->rc_rect.r_ytop = atoi(argv[CONNECT_URY]); + newsink->rc_type = ttype; + newsink->rc_node = (resNode *)NULL; + + newsink->rc_next = node->sinkpoints; + node->sinkpoints = newsink; + node->status |= FORCE | DRIVELOC; + + if (ResOptionsFlags & ResOpt_Debug) + { + /* Diagnostic */ + TxPrintf("Added sink at %d %d %d %d\n", newsink->rc_rect.r_xbot, + newsink->rc_rect.r_ybot, newsink->rc_rect.r_xtop, + newsink->rc_rect.r_ytop); + } + } + + return 0; +} + /* *------------------------------------------------------------------------- * @@ -240,6 +632,13 @@ ResReadNode(int argc, char *argv[]) * * Side Effects: see above * + * NOTE: The use of "port" to mark drive points is restricted to top + * level cells, because no other information is available about how the + * cell connects to a parent cell. For every cell other than the top + * level, the "connect" statements are used to find the actual locations + * where signals connect between cells through abutting or overlapping + * material. + * *------------------------------------------------------------------------- */ @@ -249,22 +648,33 @@ ResReadPort(int argc, { HashEntry *entry; ResExtNode *node; + ResConnect *newdriver; entry = HashFind(&ResNodeTable, argv[PORT_NAME]); node = ResExtInitNode(entry); - node->drivepoint.p_x = atoi(argv[PORT_LLX]); - node->drivepoint.p_y = atoi(argv[PORT_LLY]); - node->status |= FORCE; - /* To do: Check for multiple ports on a net; each port needs its - * own drivepoint. - */ - node->status |= DRIVELOC | PORTNODE; - node->rs_bbox.r_ll = node->drivepoint; - node->rs_bbox.r_ur.p_x = atoi(argv[PORT_URX]); - node->rs_bbox.r_ur.p_y = atoi(argv[PORT_URY]); - node->rs_ttype = DBTechNoisyNameType(argv[PORT_TYPE]); - node->type = node->rs_ttype; + /* Generate new drivepoint entry */ + + newdriver = (ResConnect *)mallocMagic(sizeof(ResConnect)); + + newdriver->rc_rect.r_xbot = atoi(argv[PORT_LLX]); + newdriver->rc_rect.r_ybot = atoi(argv[PORT_LLY]); + newdriver->rc_rect.r_xtop = atoi(argv[PORT_URX]); + newdriver->rc_rect.r_ytop = atoi(argv[PORT_URY]); + newdriver->rc_type = DBTechNoisyNameType(argv[PORT_TYPE]); + newdriver->rc_node = (resNode *)NULL; + + newdriver->rc_next = node->drivepoints; + node->drivepoints = newdriver; + node->status |= FORCE | DRIVELOC | PORTNODE; + + if (ResOptionsFlags & ResOpt_Debug) + { + /* Diagnostic */ + TxPrintf("Added port at %d %d %d %d\n", + newdriver->rc_rect.r_xbot, newdriver->rc_rect.r_ybot, + newdriver->rc_rect.r_xtop, newdriver->rc_rect.r_ytop); + } if (node->type == -1) { @@ -273,6 +683,7 @@ ResReadPort(int argc, } return 0; } + /* *------------------------------------------------------------------------- * @@ -287,7 +698,7 @@ ResReadPort(int argc, * None. * * Side effects: - * Allocates memory for a devPtr, adds to the node's firstDev linked + * Allocates memory for a devPtr, adds to the node's "devices" linked * list. * *------------------------------------------------------------------------- @@ -302,8 +713,8 @@ ResNodeAddDevice(ResExtNode *node, tptr = (devPtr *)mallocMagic((unsigned)(sizeof(devPtr))); tptr->thisDev = device; - tptr->nextDev = node->firstDev; - node->firstDev = tptr; + tptr->nextDev = node->devices; + node->devices = tptr; tptr->terminal = termtype; } @@ -326,13 +737,11 @@ ResReadDevice(int argc, char *argv[]) { RDev *device; - int rvalue, i, j, k; + int rvalue, i, j, k, w, l; ExtDevice *devptr; TileType ttype; HashEntry *entry; ResExtNode *node; - ResValue rpersquare; - float wval; device = (RDev *)mallocMagic((unsigned)(sizeof(RDev))); @@ -361,34 +770,20 @@ ResReadDevice(int argc, device->drain = (ResExtNode *)NULL; device->subs = (ResExtNode *)NULL; - entry = HashLookOnly(&devptr->exts_deviceResist, "linear"); - if (entry != NULL) - rpersquare = (ResValue)(spointertype)HashGetValue(entry); - else - rpersquare = (ResValue)10000.0; /* Default to a sane value */ - - /* For devices, the device width is in the parameter list */ - wval = 0.0; + /* Find the end of parameter arguments */ for (i = DEV_Y; i < argc; i++) { char *eptr; - if ((eptr = strchr(argv[i], '=')) != NULL) - { - if (*argv[i] == 'w') - sscanf(eptr + 1, "%f", &wval); - } - else if (!StrIsInt(argv[i])) - break; + if ((eptr = strchr(argv[i], '=')) == NULL) + if (!StrIsInt(argv[i])) + break; } - if (i == argc) { TxError("Bad device %s: Too few arguments in .ext file\n", argv[DEV_NAME]); return 1; } - else - device->resistance = wval * rpersquare; /* Channel resistance */ /* Find and record the device terminal nodes */ /* Note that this only records up to two terminals matching FET @@ -406,6 +801,8 @@ ResReadDevice(int argc, entry = HashFind(&ResNodeTable, argv[i]); device->gate = (ResExtNode *)HashGetValue(entry); device->rs_gattr = StrDup((char **)NULL, argv[i + 2]); + l = atoi(argv[i + 1]); + w = 0; ResNodeAddDevice(device->gate, device, GATE); i += 3; @@ -414,6 +811,7 @@ ResReadDevice(int argc, entry = HashFind(&ResNodeTable, argv[i]); device->source = (ResExtNode *)HashGetValue(entry); device->rs_sattr = StrDup((char **)NULL, argv[i + 2]); + w = atoi(argv[i + 1]); ResNodeAddDevice(device->source, device, SOURCE); i += 3; } @@ -423,6 +821,7 @@ ResReadDevice(int argc, entry = HashFind(&ResNodeTable, argv[i]); device->drain = (ResExtNode *)HashGetValue(entry); device->rs_dattr = StrDup((char **)NULL, argv[i + 2]); + w = MAX(w, atoi(argv[i + 1])); ResNodeAddDevice(device->drain, device, DRAIN); i += 3; } @@ -433,6 +832,7 @@ ResReadDevice(int argc, } device->rs_ttype = extGetDevType(devptr->exts_deviceName); + device->rs_wl = (l == 0) ? 0.0 : (float)w / (float)l; ResRDevList = device; device->layout = NULL; @@ -456,13 +856,11 @@ ResReadFET(int argc, char *argv[]) { RDev *device; - int rvalue, i, j, k; + int rvalue, i, j, k, w, l; ExtDevice *devptr; TileType ttype; HashEntry *entry; ResExtNode *node; - ResValue rpersquare; - float area, perim, wval, lval; device = (RDev *)mallocMagic((unsigned)(sizeof(RDev))); @@ -487,20 +885,6 @@ ResReadFET(int argc, device->rs_dattr = RDEV_NOATTR; device->rs_devptr = devptr; - entry = HashLookOnly(&devptr->exts_deviceResist, "linear"); - if (entry != NULL) - rpersquare = (ResValue)(spointertype)HashGetValue(entry); - else - rpersquare = (ResValue)10000.0; /* Default to a sane value */ - - /* For old-style FETs, the width is determined from area and perimeter */ - area = MagAtof(argv[FET_AREA]); - perim = MagAtof(argv[FET_PERIM]); - lval = 0.5 * (perim + sqrt(perim * perim - 4 * area)); - wval = area / lval; - - device->resistance = wval * rpersquare; /* Channel resistance */ - /* Find and record the FET terminal nodes */ entry = HashFind(&ResNodeTable, argv[FET_GATE]); @@ -522,6 +906,11 @@ ResReadFET(int argc, device->rs_sattr = StrDup((char **)NULL, argv[FET_SOURCE_ATTR]); device->rs_dattr = StrDup((char **)NULL, argv[FET_DRAIN_ATTR]); + l = atoi(argv[FET_GATE_ATTR - 1]); + w = atoi(argv[FET_SOURCE_ATTR - 1]); + w = MAX(w, atoi(argv[FET_DRAIN_ATTR - 1])); + device->rs_wl = (l == 0) ? 0.0 : (float)w / (float)l; + ResRDevList = device; device->layout = NULL; return 0; @@ -628,10 +1017,22 @@ ResReadAttribute(ResExtNode *node, else if (strncmp(avalue, "res:drive", 9) == 0 && (ResOptionsFlags & ResOpt_Signal)) { - node->drivepoint.p_x = atoi(argv[RES_EXT_ATTR_X]); - node->drivepoint.p_y = atoi(argv[RES_EXT_ATTR_Y]); - node->rs_ttype = DBTechNoisyNameType(argv[RES_EXT_ATTR_TYPE]); + ResConnect *newdriver; + + /* Generate new drivepoint entry */ + + newdriver = (ResConnect *)mallocMagic(sizeof(ResConnect)); + node->status |= DRIVELOC; + newdriver->rc_rect.r_xbot = atoi(argv[RES_EXT_ATTR_X]); + newdriver->rc_rect.r_ybot = atoi(argv[RES_EXT_ATTR_Y]); + newdriver->rc_rect.r_xtop = atoi(argv[RES_EXT_ATTR_X]); + newdriver->rc_rect.r_ytop = atoi(argv[RES_EXT_ATTR_Y]); + newdriver->rc_type = DBTechNoisyNameType(argv[RES_EXT_ATTR_TYPE]); + newdriver->rc_node = (resNode *)NULL; + + newdriver->rc_next = node->drivepoints; + node->drivepoints = newdriver; } return 0; } @@ -668,11 +1069,11 @@ ResExtInitNode(entry) node->cap_couple = 0; node->resistance = 0; node->type = 0; - node->firstDev = NULL; + node->devices = NULL; node->name = entry->h_key.h_name; node->oldname = NULL; - node->drivepoint.p_x = INFINITY; - node->drivepoint.p_y = INFINITY; + node->drivepoints = NULL; + node->sinkpoints = NULL; node->location.p_x = INFINITY; node->location.p_y = INFINITY; } diff --git a/resis/ResRex.c b/resis/ResRex.c index 98bcfd30..168b5f1b 100644 --- a/resis/ResRex.c +++ b/resis/ResRex.c @@ -40,18 +40,19 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ /* giving zeptoseconds (yes, really. Look it up). This constant */ /* converts zeptoseconds to picoseconds. */ -#define Z_TO_P 1e9 +#define Z_TO_P 1e-9 +#define P_TO_Z 1e9 /* Table of nodes to ignore (manually specified) */ - HashTable ResIgnoreTable; /* Hash table of nodes to ignore */ /* Table of nodes to include (manually specified) */ - HashTable ResIncludeTable; /* Hash table of nodes to include */ -/* Table of cells that have been processed */ +/* Table of nodes to force extraction of (manually specified) */ +HashTable ResForceTable; /* Hash table of nodes to include */ +/* Table of cells that have been processed */ HashTable ResProcessedTable; /* ResExtNode is a node read in from a .ext file */ @@ -62,7 +63,7 @@ int resNodeNum; extern ResExtNode *ResOriginalNodes; /*Linked List of Nodes */ -int ResOptionsFlags = ResOpt_Simplify | ResOpt_Tdi | ResOpt_DoExtFile; +int ResOptionsFlags = ResOpt_Simplify | ResOpt_DoExtFile; char *ResCurrentNode; FILE *ResExtFile; @@ -90,6 +91,7 @@ ExtResisForDef(celldef, resisdata) HashSearch hs; HashEntry *entry; devPtr *tptr, *oldtptr; + ResConnect *sptr, *snext; ResExtNode *node; int result, idx; char *devname; @@ -137,8 +139,8 @@ ExtResisForDef(celldef, resisdata) HashStartSearch(&hs); while((entry = HashNext(&ResNodeTable, &hs)) != NULL) { - node=(ResExtNode *) HashGetValue(entry); - tptr = node->firstDev; + node = (ResExtNode *) HashGetValue(entry); + tptr = node->devices; if (node == NULL) { TxError("Error: NULL Hash entry!\n"); @@ -150,6 +152,18 @@ ExtResisForDef(celldef, resisdata) tptr = tptr->nextDev; freeMagic((char *)oldtptr); } + for (sptr = node->drivepoints; sptr; ) + { + snext = sptr->rc_next; + freeMagic((char *)sptr); + sptr = snext; + } + for (sptr = node->sinkpoints; sptr; ) + { + snext = sptr->rc_next; + freeMagic((char *)sptr); + sptr = snext; + } freeMagic((char *) node); } HashKill(&ResNodeTable); @@ -200,11 +214,19 @@ ResInit() TTMaskZero(&(ResCopyMask[i])); TTMaskSetMask(&ResCopyMask[i], &DBConnectTbl[i]); } - resisdata->rthresh = 0; - resisdata->tdiTolerance = 1; + + /* Defaults: + * (1) rthresh: Only extract networks with a lumped resistance > 10 ohms + * (2) minres: Prune resistors < 1 ohm when possible + * (3) mindelay: Only extract networks with a calculated delay > 1 ps + */ + resisdata->rthresh = 10000.0; + resisdata->minres = 1000.0; + resisdata->mindelay = 1.0e9; /* 1ps = 1.0e9zs resisdata->frequency = 10e6; /* 10 MHz default */ HashInit(&ResIgnoreTable, INITFLATSIZE, HT_STRINGKEYS); + HashInit(&ResForceTable, INITFLATSIZE, HT_STRINGKEYS); HashInit(&ResIncludeTable, INITFLATSIZE, HT_STRINGKEYS); init = 0; } @@ -214,7 +236,6 @@ ResInit() resisdata->rg_Tdi = 0.0; resisdata->rg_nodecap = 0.0; resisdata->rg_maxres = 0.0; - resisdata->rg_bigdevres = 0; resisdata->rg_tilecount = 0; resisdata->rg_status = 0; resisdata->rg_devloc = NULL; @@ -267,17 +288,21 @@ CmdExtResis(win, cmd) static const char * const cmdExtresisCmd[] = { "all extract all the nets", - "threshold [value] set minimum resistor extraction threshold", - "tolerance [value] set ratio between resistor and device tol.", + "threshold [value] set minimum network resistance threshold (milliohms)", + "minresist [value] set minimum individual resistance threshold (milliohms)", + "mindelay [value] set minimum network delay threshold (picoseconds)", + "tolerance [value] set ratio between resistor and device resistance (deprecated)", "simplify [on/off] turn on/off simplification of resistor nets", "extout [on/off] turn on/off writing of .res.ext file", "lumped [on/off] turn on/off writing of updated lumped resistances", "silent [on/off] turn on/off printing of net statistics", + "debug [on/off] turn on/off printing of detailed information", "skip mask don't extract these types", + "force names force these nets to be extracted", "ignore names don't extract these nets", "include names extract only these nets", "box type extract the signal under the box on layer type", - "cell cellname extract the network for the cell named cellname", + "cell cellname extract the network for the cell named cellname", "blackbox [on/off] treat subcircuits with ports as black boxes", "fasthenry [freq] extract subcircuit network geometry into .fh file", "geometry extract network centerline geometry (experimental)", @@ -288,11 +313,11 @@ CmdExtResis(win, cmd) typedef enum { RES_BAD=-2, RES_AMBIG, RES_ALL, - RES_THRESH, RES_TOL, - RES_SIMP, RES_EXTOUT, RES_LUMPED, RES_SILENT, - RES_SKIP, RES_IGNORE, RES_INCLUDE, RES_BOX, RES_CELL, - RES_BLACKBOX, RES_FASTHENRY, RES_GEOMETRY, RES_STATS, - RES_HELP, RES_RUN + RES_THRESH, RES_MINRES, RES_MINDELAY, RES_TOL, + RES_SIMP, RES_EXTOUT, RES_LUMPED, RES_SILENT, RES_DEBUG, + RES_SKIP, RES_FORCE, RES_IGNORE, RES_INCLUDE, RES_BOX, + RES_CELL, RES_BLACKBOX, RES_FASTHENRY, RES_GEOMETRY, + RES_STATS, RES_HELP, RES_RUN } ResOptions; resisdata = ResInit(); @@ -321,13 +346,13 @@ typedef enum { switch (option) { - case RES_TOL: + case RES_MINRES: if (cmd->tx_argc > 2) { - resisdata->tdiTolerance = MagAtof(cmd->tx_argv[2]); - if (resisdata->tdiTolerance <= 0) + resisdata->minres = MagAtof(cmd->tx_argv[2]); + if (resisdata->minres <= 0) { - TxError("Usage: %s tolerance [value]\n", cmd->tx_argv[0]); + TxError("Usage: %s minres [value]\n", cmd->tx_argv[0]); return; } } @@ -335,14 +360,41 @@ typedef enum { { #ifdef MAGIC_WRAPPER Tcl_SetObjResult(magicinterp, - Tcl_NewDoubleObj((double)resisdata->tdiTolerance)); + Tcl_NewDoubleObj((double)resisdata->minres)); #else - TxPrintf("Tolerance ratio is %g.\n", resisdata->tdiTolerance); + TxPrintf("Minimum network resistance is %g milliohms.\n", + resisdata->minres); #endif } return; - case RES_THRESH: + case RES_MINDELAY: + if (cmd->tx_argc > 2) + { + resisdata->mindelay = MagAtof(cmd->tx_argv[2]) * P_TO_Z; + if (resisdata->mindelay < 0) + { + TxError("Usage: %s mindelay [value]\n", cmd->tx_argv[0]); + return; + } + } + else + { +#ifdef MAGIC_WRAPPER + Tcl_SetObjResult(magicinterp, + Tcl_NewDoubleObj((double)resisdata->mindelay * Z_TO_P)); +#else + TxPrintf("Minimum network delay is %g picoseconds.\n", + resisdata->mindelay); +#endif + } + return; + + case RES_TOL: + TxError("Note: This option has been deprecated and is unused.\n"); + return; + + case RES_THRESH: if (cmd->tx_argc > 2) { resisdata->rthresh = MagAtof(cmd->tx_argv[2]); @@ -358,23 +410,24 @@ typedef enum { Tcl_SetObjResult(magicinterp, Tcl_NewDoubleObj((double)resisdata->rthresh)); #else - TxPrintf("Resistance threshold is %g.\n", resisdata->rthresh); + TxPrintf("Minimum resistor threshold is %g mohms.\n", + resisdata->rthresh); #endif } return; - case RES_ALL: + case RES_ALL: ResOptionsFlags |= ResOpt_ExtractAll; break; - case RES_GEOMETRY: + case RES_GEOMETRY: saveFlags = ResOptionsFlags; ResOptionsFlags |= ResOpt_Geometry | ResOpt_ExtractAll; ResOptionsFlags &= ~(ResOpt_DoExtFile | ResOpt_DoLumpFile - | ResOpt_Simplify | ResOpt_Tdi); + | ResOpt_Simplify); break; - case RES_FASTHENRY: + case RES_FASTHENRY: if (cmd->tx_argc == 3) { double tmpf = strtod(cmd->tx_argv[2], &endptr); @@ -389,7 +442,7 @@ typedef enum { saveFlags = ResOptionsFlags; ResOptionsFlags |= ResOpt_FastHenry | ResOpt_ExtractAll; ResOptionsFlags &= ~(ResOpt_DoExtFile | ResOpt_DoLumpFile - | ResOpt_Simplify | ResOpt_Tdi); + | ResOpt_Simplify); break; case RES_BLACKBOX: @@ -426,10 +479,14 @@ typedef enum { ResOptionsFlags &= ~ResOpt_Stats; } return; + case RES_SIMP: + /* Enable or disable resistor network simplification. Usually + * enabled in conjunction with TDi calculations (see below). + */ if (cmd->tx_argc == 2) { - value = (ResOptionsFlags & (ResOpt_Simplify | ResOpt_Tdi)) ? + value = (ResOptionsFlags & ResOpt_Simplify) ? TRUE : FALSE; TxPrintf("%s\n", onOff[value]); } @@ -438,11 +495,12 @@ typedef enum { value = Lookup(cmd->tx_argv[2], onOff); if (value) - ResOptionsFlags |= ResOpt_Simplify | ResOpt_Tdi; + ResOptionsFlags |= ResOpt_Simplify; else - ResOptionsFlags &= ~(ResOpt_Simplify | ResOpt_Tdi); + ResOptionsFlags &= ~ResOpt_Simplify; } return; + case RES_EXTOUT: if (cmd->tx_argc == 2) { @@ -459,6 +517,7 @@ typedef enum { ResOptionsFlags &= ~ResOpt_DoExtFile; } return; + case RES_LUMPED: if (cmd->tx_argc == 2) { @@ -475,6 +534,7 @@ typedef enum { ResOptionsFlags &= ~ResOpt_DoLumpFile; } return; + case RES_SILENT: if (cmd->tx_argc == 2) { @@ -492,6 +552,23 @@ typedef enum { } return; + case RES_DEBUG: + if (cmd->tx_argc == 2) + { + value = (ResOptionsFlags & ResOpt_Debug) ? + TRUE : FALSE; + TxPrintf("%s\n", onOff[value]); + } + else + { + value = Lookup(cmd->tx_argv[2], onOff); + if (value) + ResOptionsFlags |= ResOpt_Debug; + else + ResOptionsFlags &= ~ResOpt_Debug; + } + return; + case RES_SKIP: if (cmd->tx_argc > 2) { @@ -511,6 +588,31 @@ typedef enum { } return; + case RES_FORCE: + if (cmd->tx_argc > 2) + { + if (!strcasecmp(cmd->tx_argv[2], "none")) + { + /* Kill and reinitialize the table of forced nets */ + HashKill(&ResForceTable); + HashInit(&ResForceTable, INITFLATSIZE, HT_STRINGKEYS); + } + else + HashFind(&ResForceTable, cmd->tx_argv[2]); + } + else + { + HashSearch hs; + HashEntry *entry; + + /* List all net names that are being ignored */ + HashStartSearch(&hs); + while((entry = HashNext(&ResForceTable, &hs)) != NULL) + TxPrintf("%s ", (char *)entry->h_key.h_name); + TxPrintf("\n"); + } + return; + case RES_IGNORE: if (cmd->tx_argc > 2) { @@ -610,14 +712,17 @@ typedef enum { case RES_RUN: ResOptionsFlags &= ~ResOpt_ExtractAll; break; + case RES_AMBIG: TxPrintf("Ambiguous option: %s\n", cmd->tx_argv[1]); TxFlushOut(); return; + case RES_BAD: TxPrintf("Unknown option: %s\n", cmd->tx_argv[1]); TxFlushOut(); return; + default: return; } @@ -749,6 +854,7 @@ resPortFunc(scx, lab, tpath, result) Point portloc; HashEntry *entry; ResExtNode *node; + ResConnect *newdriver; // Ignore the top level cell if (scx->scx_use->cu_id == NULL) return 0; @@ -803,12 +909,15 @@ resPortFunc(scx, lab, tpath, result) /* Digital outputs are drivers */ if (pclass == PORT_CLASS_OUTPUT) node->status |= FORCE; - node->drivepoint = portloc; + /* Create new node drivepoint */ + newdriver = (ResConnect *)mallocMagic(sizeof(ResConnect)); + + newdriver->rc_type = lab->lab_type; + newdriver->rc_rect = r; + newdriver->rc_next = node->drivepoints; + node->drivepoints = newdriver; + node->status |= DRIVELOC | PORTNODE; - node->rs_bbox = r; - node->location = portloc; - node->rs_ttype = lab->lab_type; - node->type = lab->lab_type; *result = 0; freeMagic(nodename); @@ -884,33 +993,16 @@ int ResCheckPorts(cellDef) CellDef *cellDef; { - Point portloc; Label *lab; HashEntry *entry; ResExtNode *node; + ResConnect *newdriver; int result = 1; for (lab = cellDef->cd_labels; lab; lab = lab->lab_next) { if (lab->lab_flags & PORT_DIR_MASK) { - /* Get drivepoint from the port connection direction(s) */ - /* NOTE: This is not rigorous! */ - - if (lab->lab_flags & (PORT_DIR_NORTH | PORT_DIR_SOUTH)) - portloc.p_x = (lab->lab_rect.r_xbot + lab->lab_rect.r_xtop) >> 1; - else if (lab->lab_flags & (PORT_DIR_EAST | PORT_DIR_WEST)) - portloc.p_y = (lab->lab_rect.r_ybot + lab->lab_rect.r_ytop) >> 1; - - if (lab->lab_flags & PORT_DIR_NORTH) - portloc.p_y = lab->lab_rect.r_ytop; - if (lab->lab_flags & PORT_DIR_SOUTH) - portloc.p_y = lab->lab_rect.r_ybot; - if (lab->lab_flags & PORT_DIR_EAST) - portloc.p_x = lab->lab_rect.r_xtop; - if (lab->lab_flags & PORT_DIR_WEST) - portloc.p_x = lab->lab_rect.r_xbot; - entry = HashFind(&ResNodeTable, lab->lab_text); result = 0; if ((node = (ResExtNode *) HashGetValue(entry)) != NULL) @@ -919,9 +1011,9 @@ ResCheckPorts(cellDef) lab->lab_text); TxPrintf("Location is (%d, %d); drivepoint (%d, %d)\n", node->location.p_x, node->location.p_y, - portloc.p_x, portloc.p_y); + lab->lab_rect.r_xbot, lab->lab_rect.r_ybot); TxFlush(); - node->drivepoint = portloc; + node->status |= FORCE; } else @@ -934,16 +1026,20 @@ ResCheckPorts(cellDef) TxPrintf("Port: name = %s is new node %p\n", lab->lab_text, (void *)node); TxPrintf("Location is (%d, %d); drivepoint (%d, %d)\n", - portloc.p_x, portloc.p_y, - portloc.p_x, portloc.p_y); - node->location = portloc; - node->drivepoint = node->location; + lab->lab_rect.r_xbot, lab->lab_rect.r_ybot, + lab->lab_rect.r_xtop, lab->lab_rect.r_ytop); + TxFlush(); + node->status |= REDUNDANT; } + + newdriver = (ResConnect *)mallocMagic(sizeof(ResConnect)); + newdriver->rc_rect = lab->lab_rect; + newdriver->rc_type = lab->lab_type; + newdriver->rc_next = node->drivepoints; + node->drivepoints = newdriver; + node->status |= DRIVELOC | PORTNODE; - node->rs_bbox = lab->lab_rect; - node->rs_ttype = lab->lab_type; - node->type = lab->lab_type; } } return result; @@ -977,9 +1073,9 @@ ResProcessNode( { HashEntry *he; devPtr *ptr; - float ftolerance, minRes, cumRes; - float rthresh = resisdata->rthresh; + int totWL, maxWL = 0; int nidx = 1, eidx = 1; /* node & segment counters for geom. */ + bool processThis; /* Ignore or include specified nodes */ @@ -1003,11 +1099,8 @@ ResProcessNode( return 0; ResCurrentNode = node->name; - ResSortByGate(&node->firstDev); + ResSortByGate(&node->devices); - /* Find largest SD device connected to node. */ - - minRes = FLT_MAX; resisdata->rg_devloc = (Point *) NULL; resisdata->rg_status = FALSE; resisdata->rg_nodecap = node->capacitance; @@ -1015,94 +1108,166 @@ ResProcessNode( /* The following is only used if there is a drivepoint */ /* to identify which tile the drivepoint is on. */ - resisdata->rg_ttype = node->rs_ttype; + resisdata->rg_ttype = node->type; - for (ptr = node->firstDev; ptr != NULL; ptr = ptr->nextDev) + /* Find the device with largest drive on the net; this will be + * assumed to be the primary net driver. Make sure that devices + * in parallel have been combined to determine which device is the + * largest. If there are no drivers on the net, then choose a + * source or sink point as the driver. The driver will be used as + * the starting point to determine the longest driver-to-terminal + * resistance or delay. + */ + + for (ptr = node->devices; ptr != NULL; ptr = ptr->nextDev) { - RDev *t1; - RDev *t2; + RDev *t1, *t2; - if (ptr->terminal == GATE) + /* Ignore devices unless they are FETs or BJTs */ + switch (ptr->thisDev->rs_devptr->exts_deviceClass) { - break; + case DEV_FET: + case DEV_MOSFET: + case DEV_ASYMMETRIC: + case DEV_MSUBCKT: + case DEV_BJT: + break; + default: + continue; } + + /* Devices have been sorted with those being gate terminals + * at the end, so once the first gate terminal is reached, + * there are no more drivers to be found. + */ + if (ptr->terminal == GATE) + break; else { - /* Get cumulative resistance of all devices */ - /* with same connections. */ - - cumRes = ptr->thisDev->resistance; + /* Sorting has put all parallel devices together, so + * combine their total W/L + */ + totWL = ptr->thisDev->rs_wl; t1 = ptr->thisDev; for (; ptr->nextDev != NULL; ptr = ptr->nextDev) { t1 = ptr->thisDev; t2 = ptr->nextDev->thisDev; if (t1->gate != t2->gate) break; - if ((t1->source != t2->source || t1->drain != t2->drain) && - (t1->source != t2->drain || t1->drain != t2->source)) + if ((t1->source != t2->source || t1->drain != t2->drain) && + (t1->source != t2->drain || t2->drain != t2->source)) break; - /* Do parallel combination */ - if ((cumRes != 0.0) && (t2->resistance != 0.0)) - cumRes = (cumRes * t2->resistance) / (cumRes + t2->resistance); - else - cumRes = 0; + /* Sum the W/L value of devices in parallel */ + totWL += t2->rs_wl; } - if (minRes > cumRes) + if (totWL > maxWL) { - minRes = cumRes; + maxWL = totWL; resisdata->rg_devloc = &t1->location; resisdata->rg_ttype = t1->rs_ttype; } } } - /* Special handling for FORCE and DRIVELOC labels: */ - /* Set minRes = node->minsizeres if it exists, 0 otherwise. */ + /* Special handling for DRIVELOC labels: */ - if (node->status & (FORCE|DRIVELOC)) + if (node->status & DRIVELOC) { - if (node->status & MINSIZE) - minRes = node->minsizeres; - else - minRes = 0; - - if (node->status & DRIVELOC) + if ((node->status & DRIVELOC) && (node->drivepoints != NULL)) { - resisdata->rg_devloc = &node->drivepoint; + resisdata->rg_devloc = &node->drivepoints->rc_rect.r_ll; + resisdata->rg_ttype = node->drivepoints->rc_type; resisdata->rg_status |= DRIVEONLY; } - if (node->status & PORTNODE) + + /* If there is no drivepoint but there is a sinkpoint, use that. + * The "drivers" and "sinks" are arbitrary, anyway, and any of + * them can be considered a node driver. + */ + else if ((node->status & DRIVELOC) && (node->sinkpoints != NULL)) { - /* The node is a port, not a device, so make */ - /* sure rg_ttype is set accordingly. */ - resisdata->rg_ttype = node->rs_ttype; + resisdata->rg_devloc = &node->sinkpoints->rc_rect.r_ll; + resisdata->rg_ttype = node->sinkpoints->rc_type; + resisdata->rg_status |= DRIVEONLY; } } + + /* If no driving device was found and node was not marked with a + * DRIVELOC label, then use the first drivepoint as the driver. + * If there are no drivepoints, then use a sinkpoint. Using sinkpoints + * (design is hierarchical) is problematic because there is no information + * on whether the sinkpoint leads to a driver in the child cell, which + * needs to be addressed to correctly handle hierarchical R-C extraction. + */ + + if (resisdata->rg_devloc == NULL) + { + if (node->drivepoints != NULL) + { + resisdata->rg_devloc = &node->drivepoints->rc_rect.r_ll; + resisdata->rg_ttype = node->drivepoints->rc_type; + resisdata->rg_status |= DRIVEONLY; + } + else if (node->sinkpoints != NULL) + { + resisdata->rg_devloc = &node->sinkpoints->rc_rect.r_ll; + resisdata->rg_ttype = node->sinkpoints->rc_type; + resisdata->rg_status |= DRIVEONLY; + } + } + if ((resisdata->rg_devloc == NULL) && (node->status & FORCE)) { TxError("Node %s has force label but no drive point or " "driving device\n", node->name); } - if ((minRes == FLT_MAX) || (resisdata->rg_devloc == NULL)) + if (resisdata->rg_devloc == NULL) return 1; - resisdata->rg_bigdevres = (int)minRes * OHMSTOMILLIOHMS; - if (minRes > resisdata->rthresh) - ftolerance = minRes; - else - ftolerance = resisdata->rthresh; - /* - * Is the device resistance greater than the lumped node - * resistance? If so, extract net. + * Extract the net if: + * 1. The lumped node resistance is greater than the minimum specified AND + * 2. The maximum net delay is greater than the minimum delay specified OR + * 3. "extresist all" has been invoked. + * + * The purpose of (1 AND 2) is to allow the cutoff to be specified either + * by absolute resistance ("extresist threshold") or by effective signal + * propagation delay ("extresist mindelay"). If either one is set to zero, + * it will be ignored, although they can also be used in combination. + * + * Note that the substrate net has a capacitance to substrate of zero by + * definition, and should be the only net with a zero capacitance. + * Therefore, for any node with zero capacitance, use only the lumped + * resistance to determine whether or not to process the node. */ - if ((node->resistance > ftolerance) || (node->status & FORCE) || - (ResOpt_ExtractAll & ResOptionsFlags)) + processThis = FALSE; + if (ResOpt_ExtractAll & ResOptionsFlags) + processThis = TRUE; + else if ((node->capacitance > 0) && (node->resistance > resisdata->rthresh) && + (node->resistance * node->capacitance > resisdata->mindelay)) + processThis = TRUE; + else if ((node->capacitance == 0) && (node->resistance > resisdata->rthresh)) + processThis = TRUE; + else if (HashLookOnly(&ResForceTable, node->name) != NULL) + processThis = TRUE; + + if (processThis) { ResFixPoint fp; + /* Diagnostic */ + if (!(ResOptionsFlags & ResOpt_RunSilent)) + { + TxPrintf("Extracting %s", node->name); + if (ResOptionsFlags & ResOpt_Debug) + TxPrintf(" (Rnode = %.2fohm ; Rthresh = %.2fohm)", + node->resistance * MILLIOHMSTOOHMS, + resisdata->rthresh * MILLIOHMSTOOHMS); + TxPrintf("\n"); + } + (*num_extracted)++; if (ResExtractNet(node, resisdata, outfile) != 0) { @@ -1115,17 +1280,13 @@ ResProcessNode( } else { - ResDoSimplify(ftolerance, resisdata); + ResDoSimplify(resisdata); if (ResOptionsFlags & ResOpt_DoLumpFile) ResWriteLumpFile(node, resisdata); - if (resisdata->rg_maxres >= ftolerance || - (ResOptionsFlags & ResOpt_ExtractAll)) - { - resNodeNum = 0; - (*num_output) += ResWriteExtFile(celldef, node, resisdata, + resNodeNum = 0; + (*num_output) += ResWriteExtFile(celldef, node, resisdata, &nidx, &eidx); - } } #ifdef PARANOID ResSanityChecks(node->name, ResResList, ResNodeList, ResDevList); @@ -1222,7 +1383,7 @@ ResCheckExtNodes(celldef, resisdata) if (ResOptionsFlags & ResOpt_FastHenry) ResPrintReference(ResFHFile, ResRDevList, celldef); - for (node = ResOriginalNodes; node != NULL; node=node->nextnode) + for (node = ResOriginalNodes; node != NULL; node = node->nextnode) { if (SigInterruptPending) break; total += ResProcessNode(node, celldef, resisdata, outfile, @@ -1285,7 +1446,51 @@ ResCheckExtNodes(celldef, resisdata) /* *------------------------------------------------------------------------- * - * ResFixUpConnections-- + * ResFixUpDrivepoints -- + * + * Change the name of a connection to a drivepoint (upward + * connection in the hierarchy). If there is an existing + * drivepoint that has the name of the node, then keep it + * as-is. If not, then assign the original name of the node + * to the drivepoint. All other drivepoints get a ".uX" + * suffix added to the node name ("u" for "upward"). + * + *------------------------------------------------------------------------- + */ + +void +ResFixUpDrivepoints(ResConnect *driver, + ResExtNode *node, + char *nodename) +{ + /* To be completed */ +} + +/* + *------------------------------------------------------------------------- + * + * ResFixUpSinkpoints -- + * + * Change the name of a connection to a sinkpoint (downward + * connection in the hierarchy). All sinkpoints get a ".dX" + * suffix added to the node name ("d" for "downward"). + * + *------------------------------------------------------------------------- + */ + +void +ResFixUpSinkpoints(ResConnect *sink, + ResExtNode *node, + char *nodename) +{ + /* To be completed */ +} + +/* + *------------------------------------------------------------------------- + * + * ResFixUpConnections -- + * * Changes the connection to a terminal of a device. * The new name is formed by appending .t# to the old name. * The new name is added to the hash table of node names. @@ -1309,7 +1514,9 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename) { static char newname[MAXNAME], oldnodename[MAXNAME]; int notdecremented; + ExtDevice *devptr; resNode *gate, *source, *drain, *subs; + bool doPermute = FALSE; /* If we aren't doing output (i.e. this is just a statistical run) */ /* don't patch up networks. This cuts down on memory use. */ @@ -1317,6 +1524,16 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename) if ((ResOptionsFlags & ResOpt_DoExtFile) == 0) return; + /* Check if device has symmetric source and drain, which will + * force a check for permutations of source and drain. + */ + devptr = extDev->rs_devptr; + if (devptr->exts_deviceSDCount > 1) + if (TTMaskIsZero(&devptr->exts_deviceSDTypes[1]) || + TTMaskEqual(&devptr->exts_deviceSDTypes[0], + &devptr->exts_deviceSDTypes[1])) + doPermute = TRUE; + if (extDev->layout == NULL) { layoutDev->rd_status |= RES_DEV_SAVE; @@ -1356,7 +1573,7 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename) } if (extDev->subs == extNode) { - if ((layoutDev->rd_nterms >= 4) && ((subs = layoutDev->rd_fet_subs) != NULL)) + if ((subs = layoutDev->rd_fet_subs) != NULL) { if (subs->rn_name != NULL && notdecremented) { @@ -1376,13 +1593,13 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename) } } - if (extDev->source == extNode) + if ((extDev->source == extNode) && doPermute) { /* Check for devices with only one terminal. If it was cast as drain, */ /* then swap it with the source so that the code below handles it */ /* correctly. */ - if (layoutDev->rd_fet_source == NULL && layoutDev->rd_fet_drain != NULL) + if ((layoutDev->rd_fet_source == NULL) && (layoutDev->rd_fet_drain != NULL)) { layoutDev->rd_fet_source = layoutDev->rd_fet_drain; layoutDev->rd_fet_drain = (struct resnode *)NULL; @@ -1401,7 +1618,7 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename) if (((source = layoutDev->rd_fet_source) != NULL) && ((drain = layoutDev->rd_fet_drain) != NULL)) { - if (source->rn_name != NULL && notdecremented) + if ((source->rn_name != NULL) && notdecremented) { resNodeNum--; notdecremented = FALSE; @@ -1469,7 +1686,31 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename) } } } - else if (extDev->drain == extNode) + else if (extDev->source == extNode) + { + /* Device only has 3 terminals, don't need to check for permutations */ + + if ((source = layoutDev->rd_fet_source) != NULL) + { + if (source->rn_name != NULL && notdecremented) + { + resNodeNum--; + notdecremented = FALSE; + } + + ResFixDevName(newname, SOURCE, extDev, source); + source->rn_name = extDev->source->name; + sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++); + } + else + { + TxError("Missing source connection of device at (%d %d) on net %s\n", + layoutDev->rd_inside.r_xbot, layoutDev->rd_inside.r_ybot, + nodename); + extNode->status |= DONTKILL; + } + } + else if ((extDev->drain == extNode) && doPermute) { /* Check for devices with only one terminal. If it was cast as source, */ /* then swap it with the drain so that the code below handles it */ @@ -1528,6 +1769,28 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename) extNode->status |= DONTKILL; } } + else if (extDev->drain == extNode) + { + if ((drain = layoutDev->rd_fet_drain) != NULL) + { + if (drain->rn_name != NULL && notdecremented) + { + resNodeNum--; + notdecremented = FALSE; + } + + ResFixDevName(newname, DRAIN, extDev, drain); + drain->rn_name = extDev->drain->name; + sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++); + } + else + { + TxError("Missing drain connection of device at (%d %d) on net %s\n", + layoutDev->rd_inside.r_xbot, layoutDev->rd_inside.r_ybot, + nodename); + extNode->status |= DONTKILL; + } + } else resNodeNum--; } @@ -1571,8 +1834,8 @@ ResFixDevName(line, type, device, layoutnode) } tptr = (devPtr *) mallocMagic((unsigned) (sizeof(devPtr))); tptr->thisDev = device; - tptr->nextDev = node->firstDev; - node->firstDev = tptr; + tptr->nextDev = node->devices; + node->devices = tptr; tptr->terminal = type; switch(type) { @@ -1716,19 +1979,19 @@ ResWriteLumpFile(node, resisdata) { int lumpedres; - if (ResOptionsFlags & ResOpt_Tdi) + if (resisdata->mindelay > 0) { if (resisdata->rg_nodecap != 0) { - lumpedres = (int)((resisdata->rg_Tdi / resisdata->rg_nodecap - - (float)(resisdata->rg_bigdevres)) / OHMSTOMILLIOHMS); + lumpedres = (int)((resisdata->rg_Tdi / resisdata->rg_nodecap) / + OHMSTOMILLIOHMS); } else lumpedres = 0; } else { - lumpedres = resisdata->rg_maxres; + lumpedres = resisdata->rg_maxres * MILLIOHMSTOOHMS; } fprintf(ResLumpFile, "R %s %d\n", node->name, lumpedres); } @@ -1811,64 +2074,238 @@ ResWriteExtFile(celldef, node, resisdata, nidx, eidx) ResisData *resisdata; int *nidx, *eidx; { - float RCdev; char *cp, newname[MAXNAME]; devPtr *ptr; resDevice *layoutDev, *ResGetDevice(); - float rctol; + ResConnect *driver, *sink; - rctol = resisdata->tdiTolerance; - RCdev = resisdata->rg_bigdevres * resisdata->rg_nodecap; + ASSERT(resisdata->rg_Tdi != -1, "ResWriteExtFile"); - if ((node->status & FORCE) || - (ResOptionsFlags & ResOpt_ExtractAll) || - (ResOptionsFlags & ResOpt_Simplify) == 0 || - (rctol + 1) * RCdev < rctol * resisdata->rg_Tdi) + sprintf(newname, "%s", node->name); + cp = newname + strlen(newname) - 1; + if (*cp == '!' || *cp == '#') *cp = '\0'; + + /* Second cutoff (if mindelay is specified): The original cutoff + * was based on the original lumped resistance estimate from basic + * extraction. Having done full network extraction, there is now + * a refined delay estimate rg_Tdi which may be much lower than + * the original estimate. If the new estimate falls below the + * threshold, then return without outputting the node's network. + */ + if (resisdata->rg_Tdi == 0) { - ASSERT(resisdata->rg_Tdi != -1, "ResWriteExtFile"); - (void)sprintf(newname,"%s", node->name); - cp = newname + strlen(newname)-1; - if (*cp == '!' || *cp == '#') *cp = '\0'; - if ((rctol + 1) * RCdev < rctol * resisdata->rg_Tdi || - (ResOptionsFlags & ResOpt_Tdi) == 0) - { - if ((ResOptionsFlags & (ResOpt_RunSilent | ResOpt_Tdi)) == ResOpt_Tdi) + /* The substrate net has zero capacitance by definition and + * so it also has zero delay by definition. In that case, + * check if the updated lumped resistance exceeds the + * threshold or not. + */ + if (resisdata->rg_maxres < resisdata->rthresh) + if (HashLookOnly(&ResForceTable, node->name) == NULL) { - TxPrintf("Adding %s; Tnew = %.2fns, Told = %.2fns\n", - node->name, resisdata->rg_Tdi / Z_TO_P, RCdev / Z_TO_P); - } - } - else - TxPrintf("Adding %s\n", node->name); - - for (ptr = node->firstDev; ptr != NULL; ptr=ptr->nextDev) - { - if ((layoutDev = ResGetDevice(&ptr->thisDev->location, ptr->thisDev->rs_ttype))) - { - ResFixUpConnections(ptr->thisDev, layoutDev, node, newname); - } - } - if (ResOptionsFlags & ResOpt_DoExtFile) - { - ResPrintExtNode(ResExtFile, ResNodeList, node); - ResPrintExtRes(ResExtFile, ResResList, newname); - } - if (ResOptionsFlags & ResOpt_FastHenry) - { - if (ResResList) - ResAlignNodes(ResNodeList, ResResList); - ResPrintFHNodes(ResFHFile, ResNodeList, node->name, nidx, celldef); - ResPrintFHRects(ResFHFile, ResResList, newname, eidx); - } - if (ResOptionsFlags & ResOpt_Geometry) - { - if (ResResList) - ResAlignNodes(ResNodeList, ResResList); - if (ResCreateCenterlines(ResResList, nidx, celldef) < 0) + if (ResOptionsFlags & ResOpt_Debug) + TxPrintf("Not adding %s (maxres = %.2fohm)\n", node->name, + resisdata->rg_maxres * MILLIOHMSTOOHMS); return 0; - } - return 1; + } } - else return 0; + else if ((resisdata->rg_Tdi != -1) && (resisdata->rg_Tdi < resisdata->mindelay)) + { + if (HashLookOnly(&ResForceTable, node->name) == NULL) + { + if (ResOptionsFlags & ResOpt_Debug) + { + /* Diagnostic */ + float ftdi, fdmin; + + ftdi = resisdata->rg_Tdi * Z_TO_P; + fdmin = resisdata->mindelay * Z_TO_P; + + if ((ftdi < 0.01) || ((fdmin < 0.01) && (resisdata->mindelay > 0))) + TxPrintf("Not adding %s; (Tnew = %.2ffs ; Tmin = %.2ffs)\n", + node->name, ftdi * 1000, fdmin * 1000); + else + TxPrintf("Not adding %s; (Tnew = %.2fps ; Tmin = %.2fps)\n", + node->name, ftdi, fdmin); + } + return 0; + } + } + + if (ResOptionsFlags & ResOpt_Debug) + { + if (resisdata->mindelay == 0) + { + TxPrintf("Adding %s (maxres = %.2fohm)\n", node->name, + resisdata->rg_maxres * MILLIOHMSTOOHMS); + } + else + { + float ftdi, fdmin; + fdmin = resisdata->mindelay * Z_TO_P; + + if (resisdata->rg_Tdi == -1) + ftdi = resisdata->rg_maxres * resisdata->rg_nodecap * Z_TO_P; + else + ftdi = resisdata->rg_Tdi * Z_TO_P; + + if ((ftdi < 0.01) || ((fdmin < 0.01) && (resisdata->mindelay > 0))) + TxPrintf("Adding %s; (Tnew = %.2ffs ; Tmin = %.2ffs)\n", + node->name, ftdi * 1000, fdmin * 1000); + else + TxPrintf("Adding %s; (Tnew = %.2fps ; Tmin = %.2fps)\n", + node->name, ftdi, fdmin); + } + } + + for (ptr = node->devices; ptr != NULL; ptr = ptr->nextDev) + if ((layoutDev = ResGetDevice(&ptr->thisDev->location, + ptr->thisDev->rs_ttype))) + ResFixUpConnections(ptr->thisDev, layoutDev, node, newname); + + /* Copy the node name into a driver connection if no driver connection + * has the original node name (e.g., was a port). All other drivers + * get ".uX" suffixes to distinguish them from internal network nodes + * (".nX"). + */ + for (driver = node->drivepoints; driver != NULL; driver = driver->rc_next) + ResFixUpDrivepoints(driver, node, newname); + + /* Replace downward connections (sinks) with new node names. Node + * names of sinks are given the suffix ".dX" to distinguish them + * from terminals, drivers, and nodes. + */ + for (sink = node->sinkpoints; sink != NULL; sink = sink->rc_next) + ResFixUpSinkpoints(driver, node, newname); + + if (ResOptionsFlags & ResOpt_DoExtFile) + { + ResPrintExtNode(ResExtFile, ResNodeList, node); + ResPrintExtRes(ResExtFile, ResResList, newname); + } + if (ResOptionsFlags & ResOpt_FastHenry) + { + if (ResResList) + ResAlignNodes(ResNodeList, ResResList); + ResPrintFHNodes(ResFHFile, ResNodeList, node->name, nidx, celldef); + ResPrintFHRects(ResFHFile, ResResList, newname, eidx); + } + if (ResOptionsFlags & ResOpt_Geometry) + { + if (ResResList) + ResAlignNodes(ResNodeList, ResResList); + if (ResCreateCenterlines(ResResList, nidx, celldef) < 0) + return 0; + } + return 1; +} + +/* + *------------------------------------------------------------------------- + * + * InitializeResNode -- + * + * Initialize a ResNode structure. + * + * Results: + * None. + * + * Side effects: + * Values are filled in the ResNode structure pointed to by "node". + * + * Notes: + * This routine was previously defined as a macro. + * + *------------------------------------------------------------------------- + */ + +void InitializeResNode(resNode *node, + int x, + int y, + int why) +{ + node->rn_te = NULL; + node->rn_id = 0; + node->rn_float.rn_area = 0.0; + node->rn_name = NULL; + node->rn_client = (ClientData)NULL; + node->rn_noderes = RES_INFINITY; + node->rn_je = NULL; + node->rn_status = FALSE; + node->rn_loc.p_x = x; + node->rn_loc.p_y = y; + node->rn_why = why; + node->rn_ce = (cElement *)NULL; + node->rn_re = (resElement *)NULL; +} + +/* + *------------------------------------------------------------------------- + * + * ResInfoInit-- + * + * Initialize a resInfo structure. + * + * Results: + * None. + * + * Side effects: + * Values are filled in the resInfo structure pointed to by "Info". + * + * Notes: + * This routine was previously defined as a macro. + * + *------------------------------------------------------------------------- + */ + +void ResInfoInit(resInfo *Info) +{ + Info->contactList = (cElement *)NULL; + Info->deviceList = (resDevice *)NULL; + Info->junctionList = (ResJunction *)NULL; + Info->breakList = (Breakpoint *)NULL; + Info->portList = (resPort *)NULL; + Info->ri_status = FALSE; + Info->sourceEdge = 0; +} + +/* + *------------------------------------------------------------------------- + * + * ResNewBreak -- + * + * Create and initialize a new breakpoint structure. + * + * Results: + * None. + * + * Side effects: + * Memory is allocated for the breakpoint, values are filled in, + * and the breakpoint is added to the resNode structure pointed + * to by "node". + * + * Notes: + * This routine was previously defined as a macro. + * + *------------------------------------------------------------------------- + */ + +void +ResNewBreak(resNode *node, + Tile *tile, + int px, + int py, + Rect *crect) +{ + Breakpoint *bp; + resInfo *rX; + + rX = (resInfo *)((tile)->ti_client); + bp = (Breakpoint *)mallocMagic((unsigned)(sizeof(Breakpoint))); + bp->br_next= rX->breakList; + bp->br_this = node; + bp->br_loc.p_x = px; + bp->br_loc.p_y = py; + bp->br_crect = crect; + rX->breakList = bp; } diff --git a/resis/ResSimple.c b/resis/ResSimple.c index 1dea7b95..0ff28105 100644 --- a/resis/ResSimple.c +++ b/resis/ResSimple.c @@ -178,7 +178,7 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance) /* other recievers at far end? If so, reschedule other node; * deadlock will be settled from that node. */ - if ((MarkedReceivers+UnMarkedReceivers+NumberOfDrivers == 2) || + if ((MarkedReceivers + UnMarkedReceivers + NumberOfDrivers == 2) || (UnMarkedReceivers == 0 && MarkedReceivers > 1 && resistor2 == resistor1 && PendingReceivers == 0)) { @@ -229,7 +229,7 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance) * Two resistors in series? Combine them and move devices to * appropriate end. */ - else if (numdrive+numreceive == 2 && (resistor1->rr_value < tolerance && + else if (numdrive + numreceive == 2 && (resistor1->rr_value < tolerance && resistor2->rr_value < tolerance)) { if ((resistor1->rr_status & RES_MARKED) == 0 && @@ -362,7 +362,7 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance) /* *------------------------------------------------------------------------- * - * ResMoveDevices-- move devices from one node1 to node2 + * ResMoveDevices-- move devices from one node (node1) to anther (node2) * * Results: none * @@ -387,11 +387,11 @@ ResMoveDevices(node1, node2) devptr = devptr->te_nextt; if (device->rd_fet_gate == node1) device->rd_fet_gate = node2; - else if ((device->rd_nterms >= 4) && (device->rd_fet_subs == node1)) + else if (device->rd_fet_subs == node1) device->rd_fet_subs = node2; - else if (device->rd_fet_source == node1) + else if ((device->rd_nterms > 2) && (device->rd_fet_source == node1)) device->rd_fet_source = node2; - else if (device->rd_fet_drain == node1) + else if ((device->rd_nterms > 3) && (device->rd_fet_drain == node1)) device->rd_fet_drain = node2; else TxError("Missing Device connection in squish routines" @@ -707,7 +707,7 @@ ResDistributeCapacitance(nodelist, totalcap) for (workingNode = nodelist; workingNode != NULL; workingNode = workingNode->rn_more) { - for (rptr = workingNode->rn_re; rptr != NULL; rptr=rptr->re_nextEl) + for (rptr = workingNode->rn_re; rptr != NULL; rptr = rptr->re_nextEl) if (rptr->re_thisEl->rr_float.rr_area != 0.0) TxError("Nonnull resistor area\n"); @@ -829,11 +829,11 @@ ResCalculateTDi(node, resistor, resistorvalue) ASSERT(rcd != NULL, "ResCalculateTdi"); if (resistor == NULL) - rcd->rc_Tdi = rcd->rc_Cdownstream*(float)resistorvalue; + rcd->rc_Tdi = rcd->rc_Cdownstream * (float)resistorvalue; else { rcd2 = (RCDelayStuff *)resistor->rr_connection1->rn_client; - ASSERT(rcd2 != NULL,"ResCalculateTdi"); + ASSERT(rcd2 != NULL, "ResCalculateTdi"); rcd->rc_Tdi = rcd->rc_Cdownstream * (float)resistor->rr_value + rcd2->rc_Tdi; } @@ -920,25 +920,20 @@ ResPruneTree(node, minTdi, nodelist1, nodelist2, resistorlist) */ int -ResDoSimplify(tolerance,resisdata) - float tolerance; +ResDoSimplify(resisdata) ResisData *resisdata; { resNode *node, *slownode; - float bigres = 0; - float millitolerance; + float bigres = 0.0; float totalcap; - float rctol; resResistor *res; - rctol = resisdata->tdiTolerance; ResSetPathRes(resisdata); for (node = ResNodeList; node != NULL; node = node->rn_more) - bigres = MAX(bigres, node->rn_noderes); + bigres = MAX(bigres, node->rn_noderes); - bigres /= OHMSTOMILLIOHMS; /* convert from milliohms to ohms */ resisdata->rg_maxres = bigres; #ifdef PARANOID @@ -952,8 +947,8 @@ ResDoSimplify(tolerance,resisdata) (void) ResDistributeCapacitance(ResNodeList, resisdata->rg_nodecap); - if (((tolerance > bigres) || ((ResOptionsFlags & ResOpt_Simplify) == 0)) && - ((ResOptionsFlags & ResOpt_DoLumpFile) == 0)) + if (((ResOptionsFlags & ResOpt_Simplify) == 0) && + ((ResOptionsFlags & ResOpt_DoLumpFile) == 0)) return 0; res = ResResList; @@ -963,16 +958,6 @@ ResDoSimplify(tolerance,resisdata) res = res->rr_nextResistor; oldres->rr_status &= ~RES_HEAP; - - /*------ NOTE: resistors marked with RES_TDI_IGNORE are - * part of loops but should NOT be removed. - if (oldres->rr_status & RES_TDI_IGNORE) - { - ResDeleteResPointer(oldres->rr_node[0], oldres); - ResDeleteResPointer(oldres->rr_node[1], oldres); - ResEliminateResistor(oldres, &ResResList); - } - ------*/ } if (ResNodeAtOrigin == NULL) @@ -980,7 +965,7 @@ ResDoSimplify(tolerance,resisdata) TxError("Error: Network simplification: Failed to to get origin node.\n"); resisdata->rg_Tdi = 0; } - else if (ResOptionsFlags & ResOpt_Tdi) + else if (resisdata->mindelay > 0) { if ((resisdata->rg_nodecap != -1) && (totalcap = ResCalculateChildCapacitance(ResNodeAtOrigin)) != -1) @@ -988,8 +973,7 @@ ResDoSimplify(tolerance,resisdata) RCDelayStuff *rc = (RCDelayStuff *) ResNodeList->rn_client; resisdata->rg_nodecap = totalcap; - ResCalculateTDi(ResNodeAtOrigin, (resResistor *)NULL, - resisdata->rg_bigdevres); + ResCalculateTDi(ResNodeAtOrigin, (resResistor *)NULL, 0); if (rc != (RCDelayStuff *)NULL) resisdata->rg_Tdi = rc->rc_Tdi; else @@ -1013,20 +997,10 @@ ResDoSimplify(tolerance,resisdata) else resisdata->rg_Tdi = 0; - if ((rctol+1) * resisdata->rg_bigdevres * resisdata->rg_nodecap > - rctol * resisdata->rg_Tdi && - (ResOptionsFlags & ResOpt_Tdi) && - resisdata->rg_Tdi != -1) - return 0; - - /* Simplify network; resistors are still in milliohms, so use - * millitolerance. - */ + /* Simplify network */ if (ResOptionsFlags & ResOpt_Simplify) { - millitolerance = tolerance * MILLIOHMSPEROHM; - /* * Start simplification at driver (R=0). Remove it from the done list * and add it to the pending list. Call ResSimplifyNet as long as @@ -1044,16 +1018,18 @@ ResDoSimplify(tolerance,resisdata) /* if Tdi is enabled, prune all branches whose end nodes */ /* have time constants less than the tolerance. */ - if ((ResOptionsFlags & ResOpt_Tdi) && - resisdata->rg_Tdi != -1 && - rctol != 0) - { - ResPruneTree(ResNodeAtOrigin, (rctol + 1) * - resisdata->rg_bigdevres * resisdata->rg_nodecap / rctol, + if ((resisdata->rg_Tdi != -1) && (resisdata->mindelay > 0)) + ResPruneTree(ResNodeAtOrigin, resisdata->mindelay, &ResNodeList, &ResNodeQueue, &ResResList); - } + ResNodeAtOrigin->rn_status &= ~RES_MARKED; - if (ResNodeAtOrigin->rn_less == NULL) + if (ResNodeAtOrigin->rn_less == CLIENTDEFAULT) + { + TxError("ResSimplify: Bad resptr at node %s origin.\n", + ResNodeAtOrigin->rn_name); + return 0; + } + else if (ResNodeAtOrigin->rn_less == NULL) ResNodeList = ResNodeAtOrigin->rn_more; else ResNodeAtOrigin->rn_less->rn_more = ResNodeAtOrigin->rn_more; @@ -1065,13 +1041,14 @@ ResDoSimplify(tolerance,resisdata) ResNodeAtOrigin->rn_less = NULL; ResNodeQueue = ResNodeAtOrigin; while (ResNodeQueue != NULL) - ResSimplifyNet(&ResNodeQueue, &ResNodeList, &ResResList, millitolerance); + ResSimplifyNet(&ResNodeQueue, &ResNodeList, &ResResList, + resisdata->minres); /* - * Call ResScrunchNet to eliminate any remaining under tolerance + * Call ResScrunchNet to eliminate any remaining under-tolerance * resistors. */ - ResScrunchNet(&ResResList, &ResNodeQueue, &ResNodeList, millitolerance); + ResScrunchNet(&ResResList, &ResNodeQueue, &ResNodeList, resisdata->minres); } } return 0; diff --git a/resis/ResUtils.c b/resis/ResUtils.c index 3a8cd8bb..8dcd21d2 100644 --- a/resis/ResUtils.c +++ b/resis/ResUtils.c @@ -168,483 +168,635 @@ ResEach(tile, dinfo, pNum, arg) /* *------------------------------------------------------------------------- * - * ResAddPlumbing-- Each tile has a resInfo structure associated with it - * to keep track of various things used by the extractor. ResAddPlumbing - * adds this structure and sets the tile's ClientData field to point to it. - * If the tile is a device, then a device structure is also added; - * all connected device tiles are enumerated and their deviceList - * fields set to the new structure. + * ResAddTerminalPlumbing -- * - * Results: always returns 0 + * Called from ResAddDevPlumbing(). When a tile has been found adjacent to + * a device tile that is a terminal type, walk through all of the tiles + * belonging to the terminal and mark them all with resInfo structures + * and set a status of RES_TILE_SD. * - * Side Effects:see above + * Results: None. + * + * Side effects: See above. + * + *------------------------------------------------------------------------- + */ + +void +ResAddTerminalPlumbing( + Tile *tile, + ExtDevice *devptr, + int sourceTerm) +{ + static Stack *resSDStack = NULL; + Tile *tp1, *tp2; + TileType t1; + + if (resSDStack == NULL) + resSDStack = StackNew(64); + + STACKPUSH(PTR2CD(tile), resSDStack); + + while (!StackEmpty(resSDStack)) + { + /* Find and mark all tiles belonging to the same source */ + + tp1 = (Tile *) STACKPOP(resSDStack); + if (IsSplit(tp1)) + { + if (TTMaskHasType(&(devptr->exts_deviceSDTypes[sourceTerm]), + TiGetRightType(tp1))) + t1 = SplitRightType(tp1); + else + t1 = SplitLeftType(tp1); + } + else + t1 = TiGetTypeExact(tp1); + + /* Top */ + for (tp2 = RT(tp1); RIGHT(tp2) > LEFT(tp1); tp2 = BL(tp2)) + { + if (TTMaskHasType(&(devptr->exts_deviceSDTypes[sourceTerm]), + TiGetBottomType(tp2))) + { + resInfo *re = resAddField(tp2); + if ((re->ri_status & RES_TILE_SD) == 0) + { + re->ri_status |= RES_TILE_SD; + STACKPUSH(PTR2CD(tp2), resSDStack); + } + } + } + + /* Bottom */ + for (tp2 = LB(tp1); LEFT(tp2) < RIGHT(tp1); tp2 = TR(tp2)) + { + if (TTMaskHasType(&(devptr->exts_deviceSDTypes[sourceTerm]), + TiGetTopType(tp2))) + { + resInfo *re = resAddField(tp2); + if ((re->ri_status & RES_TILE_SD) == 0) + { + re->ri_status |= RES_TILE_SD; + STACKPUSH(PTR2CD(tp2), resSDStack); + } + } + } + + /* Right */ + for (tp2 = TR(tp1); TOP(tp2) > BOTTOM(tp1); tp2 = LB(tp2)) + { + if (TTMaskHasType(&(devptr->exts_deviceSDTypes[sourceTerm]), + TiGetLeftType(tp2))) + { + resInfo *re = resAddField(tp2); + if ((re->ri_status & RES_TILE_SD) == 0) + { + re->ri_status |= RES_TILE_SD; + STACKPUSH(PTR2CD(tp2), resSDStack); + } + } + } + + /* Left */ + for (tp2 = BL(tp1); BOTTOM(tp2) < TOP(tp1); tp2 = RT(tp2)) + { + if (TTMaskHasType(&(devptr->exts_deviceSDTypes[sourceTerm]), + TiGetRightType(tp2))) + { + resInfo *re = resAddField(tp2); + if ((re->ri_status & RES_TILE_SD) == 0) + { + re->ri_status |= RES_TILE_SD; + STACKPUSH(PTR2CD(tp2), resSDStack); + } + } + } + } +} + +/* + *------------------------------------------------------------------------- + * + * ResUnmarkTerminal -- + * + * After adding structures to all tiles of a device, remove the RES_TILE_SD + * status from all tiles. + * + * Results: None + * + * Side effects: Tile status changes + * + *------------------------------------------------------------------------- + */ + +void +ResUnmarkTerminal( + Tile *tile, + ExtDevice *devptr, + int sourceTerm) +{ + static Stack *resSDStack = NULL; + resInfo *re, *re2; + Tile *tp1, *tp2; + TileType t1; + + if (resSDStack == NULL) + resSDStack = StackNew(64); + + re = (resInfo *)TiGetClientPTR(tile); + + STACKPUSH(PTR2CD(tile), resSDStack); + re->ri_status &= ~RES_TILE_SD; + + while (!StackEmpty(resSDStack)) + { + tp1 = (Tile *) STACKPOP(resSDStack); + if (IsSplit(tp1)) + { + if (TTMaskHasType(&(devptr->exts_deviceSDTypes[sourceTerm]), + TiGetRightType(tp1))) + t1 = SplitRightType(tp1); + else + t1 = SplitLeftType(tp1); + } + else + t1 = TiGetTypeExact(tp1); + + /* Top */ + for (tp2 = RT(tp1); RIGHT(tp2) > LEFT(tp1); tp2 = BL(tp2)) + { + re2 = (resInfo *) TiGetClientPTR(tp2); + if ((re2 != (resInfo *)CLIENTDEFAULT) && (re2->ri_status & RES_TILE_SD)) + { + if (TTMaskHasType(&(devptr->exts_deviceSDTypes[sourceTerm]), + TiGetBottomType(tp2))) + { + re2->ri_status &= ~RES_TILE_SD; + STACKPUSH(PTR2CD(tp2), resSDStack); + } + } + } + + /* Bottom */ + for (tp2 = LB(tp1); LEFT(tp2) < RIGHT(tp1); tp2 = TR(tp2)) + { + re2 = (resInfo *) TiGetClientPTR(tp2); + if ((re2 != (resInfo *)CLIENTDEFAULT) && (re2->ri_status & RES_TILE_SD)) + { + if (TTMaskHasType(&(devptr->exts_deviceSDTypes[sourceTerm]), + TiGetTopType(tp2))) + { + re2->ri_status &= ~RES_TILE_SD; + STACKPUSH(PTR2CD(tp2), resSDStack); + } + } + } + + /* Right */ + for (tp2 = TR(tp1); TOP(tp2) > BOTTOM(tp1); tp2 = LB(tp2)) + { + re2 = (resInfo *) TiGetClientPTR(tp2); + if ((re2 != (resInfo *)CLIENTDEFAULT) && (re2->ri_status & RES_TILE_SD)) + { + if (TTMaskHasType(&(devptr->exts_deviceSDTypes[sourceTerm]), + TiGetLeftType(tp2))) + { + re2->ri_status &= ~RES_TILE_SD; + STACKPUSH(PTR2CD(tp2), resSDStack); + } + } + } + + /* Left */ + for (tp2 = BL(tp1); BOTTOM(tp2) < TOP(tp1); tp2 = RT(tp2)) + { + re2 = (resInfo *) TiGetClientPTR(tp2); + if ((re2 != (resInfo *)CLIENTDEFAULT) && (re2->ri_status & RES_TILE_SD)) + { + if (TTMaskHasType(&(devptr->exts_deviceSDTypes[sourceTerm]), + TiGetRightType(tp2))) + { + re2->ri_status &= ~RES_TILE_SD; + STACKPUSH(PTR2CD(tp2), resSDStack); + } + } + } + } +} + +/* + *------------------------------------------------------------------------- + * + * ResAddPlumbing -- + * + * Each tile has a resInfo structure associated with it to keep track of + * various things used by the extractor. ResAddPlumbing adds this structure + * and sets the tile's ClientData field to point to it. + * + * Results: Always return 0 to keep the search going. + * + * Side Effects: See above * *------------------------------------------------------------------------- */ int -ResAddPlumbing(tile, dinfo, arg) - Tile *tile; - TileType dinfo; - ClientData *arg; +ResAddPlumbing( + Tile *tile, + TileType dinfo, /* (unused) */ + ClientData clientdata) /* (unused) */ +{ + if (TiGetClient(tile) == CLIENTDEFAULT) + resAddField(tile); + return 0; +} + +/* + *------------------------------------------------------------------------- + * + * ResAddDevPlumbing -- + * + * Each tile has a resInfo structure associated with it to keep track of + * various things used by the extractor. ResAddDevPlumbing adds this structure + * to tiles associated with devices and sets the tile's ClientData field to + * point to it. A device structure is also added; all connected device + * tiles are enumerated and their deviceList fields set to the new structure. + * + * Results: None. + * + * Side Effects: See above + * + *------------------------------------------------------------------------- + */ + +void +ResAddDevPlumbing( + ResDevTile *thisDev, /* Pointer to device from .ext file */ + resDevice **resDevListPtr) /* Add to this list */ { resInfo *Info, *rinfo2; static Stack *resDevStack = NULL; - TileType loctype, t1; - Tile *tp1, *tp2, *source; + Tile *tile, *tp1, *tp2, *sourceTile = NULL; + TileType ttype, loctype, t1; + TileTypeBitMask locDevSubsMask; + int i, pNum, nterms; + Plane *plane; + Rect r; resDevice *resDev; ExtDevice *devptr; - TileTypeBitMask locDevSubsMask; + int srcidx, sourceTerm = -1; if (resDevStack == NULL) resDevStack = StackNew(64); - if (TiGetClient(tile) == CLIENTDEFAULT) + ttype = thisDev->type; + pNum = DBPlane(ttype); + plane = ResDef->cd_planes[pNum]; + devptr = thisDev->devptr; + /* Add 2 to # terminals to include the device node and the substrate */ + nterms = devptr->exts_deviceSDCount + 2; + + /* Find the tile in the location of the device on the device's plane. + * Note that GOTOPOINT() is used because the actual tile will have + * changed after dissolving contacts and re-forming the entire database + * with ResFract(). + */ + + tile = PlaneGetHint(plane); + GOTOPOINT(tile, &(thisDev->area.r_ll)); + PlaneSetHint(plane, tile); + + if (IsSplit(tile)) { - if (IsSplit(tile)) - loctype = (dinfo & TT_SIDE) ? SplitRightType(tile) : - SplitLeftType(tile); - else - loctype = TiGetTypeExact(tile); + loctype = SplitRightType(tile); + if (!TTMaskHasType(&ExtCurStyle->exts_deviceConn[ttype], loctype)) + loctype = SplitLeftType(tile); + } + else + loctype = TiGetTypeExact(tile); - devptr = ExtCurStyle->exts_device[loctype]; - rinfo2 = resAddField(tile); - if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), loctype)) + /* Create a record for the device type and add it to tile */ + + resDev = (resDevice *)mallocMagic((unsigned)(sizeof(resDevice))); + resDev->rd_nterms = nterms; + + resDev->rd_terminals = (resNode **)mallocMagic(nterms * sizeof(resNode *)); + for (i = 0; i != nterms; i++) resDev->rd_terminals[i] = (resNode *) NULL; + + resDev->rd_tile = tile; + resDev->rd_inside.r_ll.p_x = LEFT(tile); + resDev->rd_inside.r_ll.p_y = BOTTOM(tile); + resDev->rd_inside.r_ur.p_x = RIGHT(tile); + resDev->rd_inside.r_ur.p_y = TOP(tile); + resDev->rd_devtype = loctype; + resDev->rd_tiles = 0; + resDev->rd_length = 0; + resDev->rd_width = 0; + resDev->rd_perim = 0; + resDev->rd_area = 0; + resDev->rd_status = 0; + resDev->rd_nextDev = (resDevice *)*resDevListPtr; + *resDevListPtr = (ClientData)resDev; + + /* Add a record to the initial tile */ + rinfo2 = resAddField(tile); + rinfo2->deviceList = resDev; + rinfo2->ri_status |= RES_TILE_DEV; + + /* Walk the area of the device, adding records to the tiles and + * looking for terminals. When a terminal is found, walk the + * area of the terminal, adding records to the tiles. Mark + * terminal tiles adjacent to the device with the relative + * position. + */ + + STACKPUSH(PTR2CD(tile), resDevStack); + while (!StackEmpty(resDevStack)) + { + resInfo *re0; + + tp1 = (Tile *)STACKPOP(resDevStack); + if (IsSplit(tp1)) { - int i, nterms, pNum; - Rect r; + t1 = SplitRightType(tp1); + if (!TTMaskHasType(&ExtCurStyle->exts_deviceConn[ttype], t1)) + t1 = SplitLeftType(tp1); + } + else + t1 = TiGetTypeExact(tp1); - /* Count SD terminals of the device */ - nterms = 0; - for (i = 0;; i++) + re0 = (resInfo *) TiGetClientPTR(tp1); + + /* Top */ + for (tp2 = RT(tp1); RIGHT(tp2) > LEFT(tp1); tp2 = BL(tp2)) + { + if (TTMaskHasType(&ExtCurStyle->exts_deviceConn[t1], TiGetBottomType(tp2)) + && (TiGetClient(tp2) == CLIENTDEFAULT)) { - if (TTMaskIsZero(&(devptr->exts_deviceSDTypes[i]))) break; - nterms++; - } - if (nterms < devptr->exts_deviceSDCount) - nterms = devptr->exts_deviceSDCount; + STACKPUSH(PTR2CD(tp2), resDevStack); + Info = resAddField(tp2); + Info->deviceList = resDev; + Info->ri_status |= RES_TILE_DEV; - /* resDev terminals includes device identifier (e.g., gate) and - * substrate, so add two to nterms. - */ - nterms += 2; - - resDev = (resDevice *)mallocMagic((unsigned)(sizeof(resDevice))); - resDev->rd_nterms = nterms; - resDev->rd_terminals = (resNode **) mallocMagic(nterms * sizeof(resNode *)); - for (i = 0; i != nterms; i++) - resDev->rd_terminals[i] = (resNode *) NULL; - - resDev->rd_tile = tile; - resDev->rd_inside.r_ll.p_x = LEFT(tile); - resDev->rd_inside.r_ll.p_y = BOTTOM(tile); - resDev->rd_inside.r_ur.p_x = RIGHT(tile); - resDev->rd_inside.r_ur.p_y = TOP(tile); - resDev->rd_devtype = loctype; - resDev->rd_tiles = 0; - resDev->rd_length = 0; - resDev->rd_width = 0; - resDev->rd_perim = 0; - resDev->rd_area = 0; - resDev->rd_status = 0; - resDev->rd_nextDev = (resDevice *)*arg; - *arg = (ClientData)resDev; - rinfo2->deviceList = resDev; - rinfo2->ri_status |= RES_TILE_DEV; - - for (i = 0; i < nterms - 2; i++) - { - source = NULL; - /* find diffusion (if present) to be source contact */ - - /* top */ - for (tp2 = RT(tile); RIGHT(tp2) > LEFT(tile); tp2 = BL(tp2)) + /* Update device position to point to the lower-leftmost tile */ + if ((tp2->ti_ll.p_x < resDev->rd_inside.r_ll.p_x) || + ((tp2->ti_ll.p_x == resDev->rd_inside.r_ll.p_x) && + (tp2->ti_ll.p_y < resDev->rd_inside.r_ll.p_y))) { - if TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), - TiGetBottomType(tp2)) - { - rinfo2->sourceEdge |= TOPEDGE; - source = tp2; - Info = resAddField(source); - Info->ri_status |= RES_TILE_SD; - break; - } - } - - /* bottom */ - if (source == NULL) - for (tp2 = LB(tile); LEFT(tp2) < RIGHT(tile); tp2 = TR(tp2)) - { - if TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), - TiGetTopType(tp2)) - { - rinfo2->sourceEdge |= BOTTOMEDGE; - source = tp2; - Info = resAddField(source); - Info->ri_status |= RES_TILE_SD; - break; - } - } - - /* right */ - if (source == NULL) - for (tp2 = TR(tile); TOP(tp2) > BOTTOM(tile); tp2 = LB(tp2)) - { - if TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), - TiGetLeftType(tp2)) - { - rinfo2->sourceEdge |= RIGHTEDGE; - source = tp2; - Info = resAddField(source); - Info->ri_status |= RES_TILE_SD; - break; - } - } - - /* left */ - if (source == NULL) - for (tp2 = BL(tile); BOTTOM(tp2) < TOP(tile); tp2 = RT(tp2)) - { - if TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), - TiGetRightType(tp2)) - { - source = tp2; - Info = resAddField(source); - Info->ri_status |= RES_TILE_SD; - rinfo2->sourceEdge |= LEFTEDGE; - break; - } - } - - /* other plane (in ResUse) */ - if (source == NULL) - { - TiToRect(tile, &r); - for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) - { - if (TTMaskIntersect(&DBPlaneTypes[pNum], - &(devptr->exts_deviceSDTypes[i]))) - DBSrPaintArea((Tile *)NULL, - ResUse->cu_def->cd_planes[pNum], - &r, &(devptr->exts_deviceSDTypes[i]), - resMultiPlaneTerm, (ClientData)rinfo2); - } - } - - /* We need to know whether a given diffusion tile connects to - * the source or to the drain of a device. A single - * diffusion tile is marked, and all connecting diffusion tiles - * are enumerated and called the source. Any other SD tiles - * are assumed to be the drain. BUG: this does not work - * correctly with multi SD structures. - */ - - if (source != (Tile *) NULL) - { - STACKPUSH((ClientData)source, resDevStack); + resDev->rd_inside.r_ll.p_x = LEFT(tp2); + resDev->rd_inside.r_ll.p_y = BOTTOM(tp2); + resDev->rd_inside.r_ur.p_x = RIGHT(tp2); + resDev->rd_inside.r_ur.p_y = TOP(tp2); } } - while (!StackEmpty(resDevStack)) + else { - tp1 = (Tile *) STACKPOP(resDevStack); - if (IsSplit(tp1)) + if (sourceTerm < 0) { - t1 = (dinfo & TT_SIDE) ? SplitRightType(tp1) : - SplitLeftType(tp1); - } - else - t1 = TiGetTypeExact(tp1); - - /* top */ - for (tp2 = RT(tp1); RIGHT(tp2) > LEFT(tp1); tp2 = BL(tp2)) - { - if (TiGetBottomType(tp2) == t1) + for (srcidx = 0; srcidx < (nterms - 2); srcidx++) { - resInfo *re = resAddField(tp2); - if ((re->ri_status & RES_TILE_SD) == 0) + if (TTMaskHasType(&(devptr->exts_deviceSDTypes[srcidx]), + TiGetBottomType(tp2))) { - re->ri_status |= RES_TILE_SD; - STACKPUSH((ClientData)tp2, resDevStack); + sourceTile = tp2; + sourceTerm = srcidx; + ResAddTerminalPlumbing(tp2, devptr, srcidx); + break; } } } - /* bottom */ - for (tp2 = LB(tp1); LEFT(tp2) < RIGHT(tp1); tp2 = TR(tp2)) + if (sourceTerm >= 0) { - if (TiGetTopType(tp2) == t1) + if (TTMaskHasType(&(devptr->exts_deviceSDTypes[sourceTerm]), + TiGetBottomType(tp2))) { - resInfo *re = resAddField(tp2); - if ((re->ri_status & RES_TILE_SD) == 0) - { - re->ri_status |= RES_TILE_SD; - STACKPUSH((ClientData)tp2, resDevStack); - } - } - } - /* right */ - for (tp2 = TR(tp1); TOP(tp2) > BOTTOM(tp1); tp2 = LB(tp2)) - { - if (TiGetLeftType(tp2) == t1) - { - resInfo *re = resAddField(tp2); - if ((re->ri_status & RES_TILE_SD) == 0) - { - re->ri_status |= RES_TILE_SD; - STACKPUSH((ClientData)tp2, resDevStack); - } - } - } - /* left */ - for (tp2 = BL(tp1); BOTTOM(tp2) < TOP(tp1); tp2 = RT(tp2)) - { - if (TiGetRightType(tp2) == t1) - { - resInfo *re = resAddField(tp2); - if ((re->ri_status & RES_TILE_SD) == 0) - { - re->ri_status |= RES_TILE_SD; - STACKPUSH((ClientData)tp2, resDevStack); - } - } - } - } + /* If # terminals found > nterms then assume that they + * are connected, for example through a well or substrate. + */ + if ((TiGetClient(tp2) == CLIENTDEFAULT) && + (sourceTerm == nterms - 3)) + ResAddTerminalPlumbing(tp2, devptr, sourceTerm); - /* Find device substrate */ - - TTMaskZero(&locDevSubsMask); - TTMaskSetMask(&locDevSubsMask, &(devptr->exts_deviceSubstrateTypes)); - TTMaskClearType(&locDevSubsMask, TT_SPACE); - - TiToRect(tile, &r); - for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) - { - if (TTMaskIntersect(&DBPlaneTypes[pNum], &locDevSubsMask)) - DBSrPaintArea((Tile *)NULL, - ResUse->cu_def->cd_planes[pNum], - &r, &locDevSubsMask, - resSubstrateTerm, (ClientData)NULL); - } - - /* find rest of device; search for source edges */ - - STACKPUSH((ClientData)tile, resDevStack); - while (!StackEmpty(resDevStack)) - { - resInfo *re0; - - tp1 = (Tile *) STACKPOP(resDevStack); - if (IsSplit(tp1)) - { - t1 = (dinfo & TT_SIDE) ? SplitRightType(tp1) : - SplitLeftType(tp1); - /* Check in case this is the wrong side */ - if (ExtCurStyle->exts_device[t1] == NULL) - t1 = (dinfo & TT_SIDE) ? SplitLeftType(tp1) : - SplitRightType(tp1); - } - else - t1 = TiGetTypeExact(tp1); - - devptr = ExtCurStyle->exts_device[t1]; - re0 = (resInfo *) TiGetClientPTR(tp1); - /* top */ - for (tp2 = RT(tp1); RIGHT(tp2) > LEFT(tp1); tp2 = BL(tp2)) - { - if ((TiGetBottomType(tp2) == t1) && - (TiGetClient(tp2) == CLIENTDEFAULT)) - { - Info = resAddField(tp2); - STACKPUSH((ClientData)tp2, resDevStack); - Info->deviceList = resDev; - Info->ri_status |= RES_TILE_DEV; - - /* Update device position to point to the lower-leftmost tile */ - if ((tp2->ti_ll.p_x < resDev->rd_inside.r_ll.p_x) || - ((tp2->ti_ll.p_x == resDev->rd_inside.r_ll.p_x) && - (tp2->ti_ll.p_y < resDev->rd_inside.r_ll.p_y))) - { - resDev->rd_inside.r_ll.p_x = LEFT(tp2); - resDev->rd_inside.r_ll.p_y = BOTTOM(tp2); - resDev->rd_inside.r_ur.p_x = RIGHT(tp2); - resDev->rd_inside.r_ur.p_y = TOP(tp2); - } - } - else if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), - TiGetBottomType(tp2)) - { Info = resAddField(tp2); if (Info->ri_status & RES_TILE_SD) - re0->sourceEdge |= TOPEDGE; + re0->sourceEdge |= TOPEDGE; } } - /* bottom */ - for (tp2 = LB(tp1); LEFT(tp2) < RIGHT(tp1); tp2 = TR(tp2)) - { - if ((TiGetTopType(tp2) == t1) && - (TiGetClient(tp2) == CLIENTDEFAULT)) - { - Info = resAddField(tp2); - STACKPUSH((ClientData)tp2, resDevStack); - Info->deviceList = resDev; - Info->ri_status |= RES_TILE_DEV; + } + } - /* Update device position to point to the lower-leftmost tile */ - if ((tp2->ti_ll.p_x < resDev->rd_inside.r_ll.p_x) || - ((tp2->ti_ll.p_x == resDev->rd_inside.r_ll.p_x) && - (tp2->ti_ll.p_y < resDev->rd_inside.r_ll.p_y))) + /* Bottom */ + for (tp2 = LB(tp1); LEFT(tp2) < RIGHT(tp1); tp2 = TR(tp2)) + { + if (TTMaskHasType(&ExtCurStyle->exts_deviceConn[t1], TiGetTopType(tp2)) + && (TiGetClient(tp2) == CLIENTDEFAULT)) + { + STACKPUSH(PTR2CD(tp2), resDevStack); + Info = resAddField(tp2); + Info->deviceList = resDev; + Info->ri_status |= RES_TILE_DEV; + + /* Update device position to point to the lower-leftmost tile */ + if ((tp2->ti_ll.p_x < resDev->rd_inside.r_ll.p_x) || + ((tp2->ti_ll.p_x == resDev->rd_inside.r_ll.p_x) && + (tp2->ti_ll.p_y < resDev->rd_inside.r_ll.p_y))) + { + resDev->rd_inside.r_ll.p_x = LEFT(tp2); + resDev->rd_inside.r_ll.p_y = BOTTOM(tp2); + resDev->rd_inside.r_ur.p_x = RIGHT(tp2); + resDev->rd_inside.r_ur.p_y = TOP(tp2); + } + } + else + { + if (sourceTerm < 0) + { + for (srcidx = 0; srcidx < (nterms - 2); srcidx++) + { + if (TTMaskHasType(&(devptr->exts_deviceSDTypes[srcidx]), + TiGetBottomType(tp2))) { - resDev->rd_inside.r_ll.p_x = LEFT(tp2); - resDev->rd_inside.r_ll.p_y = BOTTOM(tp2); - resDev->rd_inside.r_ur.p_x = RIGHT(tp2); - resDev->rd_inside.r_ur.p_y = TOP(tp2); + sourceTile = tp2; + sourceTerm = srcidx; + ResAddTerminalPlumbing(tp2, devptr, srcidx); + break; } } - else if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), - TiGetTopType(tp2)) + } + if (sourceTerm >= 0) + { + if (TTMaskHasType(&(devptr->exts_deviceSDTypes[sourceTerm]), + TiGetBottomType(tp2))) { + /* If # terminals found > nterms then assume that they + * are connected, for example through a well or substrate. + */ + if ((TiGetClient(tp2) == CLIENTDEFAULT) && + (sourceTerm == nterms - 3)) + ResAddTerminalPlumbing(tp2, devptr, sourceTerm); + Info = resAddField(tp2); if (Info->ri_status & RES_TILE_SD) re0->sourceEdge |= BOTTOMEDGE; } } - /* right */ - for (tp2 = TR(tp1); TOP(tp2) > BOTTOM(tp1); tp2 = LB(tp2)) - { - if ((TiGetLeftType(tp2) == t1) && - (TiGetClient(tp2) == CLIENTDEFAULT)) - { - Info = resAddField(tp2); - STACKPUSH((ClientData)tp2, resDevStack); - Info->deviceList = resDev; - Info->ri_status |= RES_TILE_DEV; + } + } - /* Update device position to point to the lower-leftmost tile */ - if ((tp2->ti_ll.p_x < resDev->rd_inside.r_ll.p_x) || - ((tp2->ti_ll.p_x == resDev->rd_inside.r_ll.p_x) && - (tp2->ti_ll.p_y < resDev->rd_inside.r_ll.p_y))) + /* Right */ + for (tp2 = TR(tp1); TOP(tp2) > BOTTOM(tp1); tp2 = LB(tp2)) + { + if (TTMaskHasType(&ExtCurStyle->exts_deviceConn[t1], TiGetLeftType(tp2)) + && (TiGetClient(tp2) == CLIENTDEFAULT)) + { + STACKPUSH(PTR2CD(tp2), resDevStack); + Info = resAddField(tp2); + Info->deviceList = resDev; + Info->ri_status |= RES_TILE_DEV; + + /* Update device position to point to the lower-leftmost tile */ + if ((tp2->ti_ll.p_x < resDev->rd_inside.r_ll.p_x) || + ((tp2->ti_ll.p_x == resDev->rd_inside.r_ll.p_x) && + (tp2->ti_ll.p_y < resDev->rd_inside.r_ll.p_y))) + { + resDev->rd_inside.r_ll.p_x = LEFT(tp2); + resDev->rd_inside.r_ll.p_y = BOTTOM(tp2); + resDev->rd_inside.r_ur.p_x = RIGHT(tp2); + resDev->rd_inside.r_ur.p_y = TOP(tp2); + } + } + else + { + if (sourceTerm < 0) + { + for (srcidx = 0; srcidx < (nterms - 2); srcidx++) + { + if (TTMaskHasType(&(devptr->exts_deviceSDTypes[srcidx]), + TiGetBottomType(tp2))) { - resDev->rd_inside.r_ll.p_x = LEFT(tp2); - resDev->rd_inside.r_ll.p_y = BOTTOM(tp2); - resDev->rd_inside.r_ur.p_x = RIGHT(tp2); - resDev->rd_inside.r_ur.p_y = TOP(tp2); + sourceTile = tp2; + sourceTerm = srcidx; + ResAddTerminalPlumbing(tp2, devptr, srcidx); + break; } } - else if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), - TiGetLeftType(tp2)) + } + if (sourceTerm >= 0) + { + if (TTMaskHasType(&(devptr->exts_deviceSDTypes[sourceTerm]), + TiGetBottomType(tp2))) { - Info = resAddField(tp2); + /* If # terminals found > nterms then assume that they + * are connected, for example through a well or substrate. + */ + if ((TiGetClient(tp2) == CLIENTDEFAULT) && + (sourceTerm == nterms - 3)) + ResAddTerminalPlumbing(tp2, devptr, sourceTerm); + + Info = resAddField(tp2); if (Info->ri_status & RES_TILE_SD) re0->sourceEdge |= RIGHTEDGE; } } - /* left */ - for (tp2 = BL(tp1); BOTTOM(tp2) < TOP(tp1); tp2 = RT(tp2)) - { - if ((TiGetRightType(tp2) == t1) && - (TiGetClient(tp2) == CLIENTDEFAULT)) - { - Info = resAddField(tp2); - STACKPUSH((ClientData)tp2, resDevStack); - Info->deviceList = resDev; - Info->ri_status |= RES_TILE_DEV; + } + } - /* Update device position to point to the lower-leftmost tile */ - if ((tp2->ti_ll.p_x < resDev->rd_inside.r_ll.p_x) || - ((tp2->ti_ll.p_x == resDev->rd_inside.r_ll.p_x) && - (tp2->ti_ll.p_y < resDev->rd_inside.r_ll.p_y))) + /* Left */ + for (tp2 = BL(tp1); BOTTOM(tp2) < TOP(tp1); tp2 = RT(tp2)) + { + if (TTMaskHasType(&ExtCurStyle->exts_deviceConn[t1], TiGetRightType(tp2)) + && (TiGetClient(tp2) == CLIENTDEFAULT)) + { + STACKPUSH(PTR2CD(tp2), resDevStack); + Info = resAddField(tp2); + Info->deviceList = resDev; + Info->ri_status |= RES_TILE_DEV; + + /* Update device position to point to the lower-leftmost tile */ + if ((tp2->ti_ll.p_x < resDev->rd_inside.r_ll.p_x) || + ((tp2->ti_ll.p_x == resDev->rd_inside.r_ll.p_x) && + (tp2->ti_ll.p_y < resDev->rd_inside.r_ll.p_y))) + { + resDev->rd_inside.r_ll.p_x = LEFT(tp2); + resDev->rd_inside.r_ll.p_y = BOTTOM(tp2); + resDev->rd_inside.r_ur.p_x = RIGHT(tp2); + resDev->rd_inside.r_ur.p_y = TOP(tp2); + } + } + else + { + if (sourceTerm < 0) + { + for (srcidx = 0; srcidx < (nterms - 2); srcidx++) + { + if (TTMaskHasType(&(devptr->exts_deviceSDTypes[srcidx]), + TiGetBottomType(tp2))) { - resDev->rd_inside.r_ll.p_x = LEFT(tp2); - resDev->rd_inside.r_ll.p_y = BOTTOM(tp2); - resDev->rd_inside.r_ur.p_x = RIGHT(tp2); - resDev->rd_inside.r_ur.p_y = TOP(tp2); + sourceTile = tp2; + sourceTerm = srcidx; + ResAddTerminalPlumbing(tp2, devptr, srcidx); + break; } } - else if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), - TiGetRightType(tp2)) + } + if (sourceTerm >= 0) + { + if (TTMaskHasType(&(devptr->exts_deviceSDTypes[sourceTerm]), + TiGetBottomType(tp2))) { - Info = resAddField(tp2); + /* If # terminals found > nterms then assume that they + * are connected, for example through a well or substrate. + */ + if ((TiGetClient(tp2) == CLIENTDEFAULT) && + (sourceTerm == nterms - 3)) + ResAddTerminalPlumbing(tp2, devptr, sourceTerm); + + Info = resAddField(tp2); if (Info->ri_status & RES_TILE_SD) re0->sourceEdge |= LEFTEDGE; } } } + } + } - /* unmark all tiles marked as being part of source */ + TiToRect(tile, &r); - if (source != (Tile *) NULL) + /* Check other planes for terminals */ + if (sourceTile == NULL) + { + for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) + { + for (srcidx = 0; srcidx < (nterms - 2); srcidx++) { - resInfo *re = (resInfo *) TiGetClientPTR(source); - - STACKPUSH((ClientData)source, resDevStack); - re->ri_status &= ~RES_TILE_SD; - } - while (!StackEmpty(resDevStack)) - { - tp1 = (Tile *) STACKPOP(resDevStack); - if (IsSplit(tp1)) - { - t1 = (dinfo & TT_SIDE) ? SplitRightType(tp1) : - SplitLeftType(tp1); - } - else - t1 = TiGetTypeExact(tp1); - - /* top */ - for (tp2 = RT(tp1); RIGHT(tp2) > LEFT(tp1); tp2 = BL(tp2)) - { - resInfo *re2 = (resInfo *) TiGetClientPTR(tp2); - if (TiGetBottomType(tp2) == t1) - { - if (re2->ri_status & RES_TILE_SD) - { - re2->ri_status &= ~RES_TILE_SD; - STACKPUSH((ClientData)tp2, resDevStack); - } - } - } - /* bottom */ - for(tp2 = LB(tp1); LEFT(tp2) < RIGHT(tp1); tp2 = TR(tp2)) - { - resInfo *re2 = (resInfo *) TiGetClientPTR(tp2); - if (TiGetTopType(tp2) == t1) - { - if (re2->ri_status & RES_TILE_SD) - { - re2->ri_status &= ~RES_TILE_SD; - STACKPUSH((ClientData)tp2, resDevStack); - } - } - } - /* right */ - for (tp2 = TR(tp1); TOP(tp2) > BOTTOM(tp1); tp2 = LB(tp2)) - { - resInfo *re2 = (resInfo *) TiGetClientPTR(tp2); - if (TiGetLeftType(tp2) == t1) - { - if (re2->ri_status & RES_TILE_SD) - { - re2->ri_status &= ~RES_TILE_SD; - STACKPUSH((ClientData)tp2, resDevStack); - } - } - } - /* left */ - for (tp2 = BL(tp1); BOTTOM(tp2) < TOP(tp1); tp2 = RT(tp2)) - { - resInfo *re2 = (resInfo *) TiGetClientPTR(tp2); - if (TiGetRightType(tp2) == t1) - { - if (re2->ri_status & RES_TILE_SD) - { - re2->ri_status &= ~RES_TILE_SD; - STACKPUSH((ClientData)tp2, resDevStack); - } - } - } + if (TTMaskIntersect(&DBPlaneTypes[pNum], + &(devptr->exts_deviceSDTypes[srcidx]))) + DBSrPaintArea((Tile *)NULL, + ResUse->cu_def->cd_planes[pNum], + &r, &(devptr->exts_deviceSDTypes[srcidx]), + resMultiPlaneTerm, (ClientData)rinfo2); } } } - return(0); + + /* Find device substrate */ + + TTMaskZero(&locDevSubsMask); + TTMaskSetMask(&locDevSubsMask, &(devptr->exts_deviceSubstrateTypes)); + TTMaskClearType(&locDevSubsMask, TT_SPACE); + + for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) + { + if (TTMaskIntersect(&DBPlaneTypes[pNum], &locDevSubsMask)) + DBSrPaintArea((Tile *)NULL, + ResUse->cu_def->cd_planes[pNum], + &r, &locDevSubsMask, + resSubstrateTerm, (ClientData)NULL); + } + + if (sourceTile) + ResUnmarkTerminal(sourceTile, devptr, srcidx); } /* @@ -675,6 +827,33 @@ ResRemovePlumbing(tile, dinfo, arg) return(0); } +/* + *------------------------------------------------------------------------- + * + * ResFreeDevTiles -- + * + * Free memory allocated to the DevTiles list. + * + * Results: None. + * + * Side effects: Frees memory. + * + *------------------------------------------------------------------------- + */ + +void +ResFreeDevTiles(TileList) + ResDevTile *TileList; +{ + ResDevTile *oldTile; + + while (TileList != (ResDevTile *) NULL) + { + oldTile = TileList; + TileList = TileList->nextDev; + freeMagic((char *)oldTile); + } +} /* *------------------------------------------------------------------------- @@ -688,8 +867,7 @@ ResRemovePlumbing(tile, dinfo, arg) * * Results: none * - * Side Effects: sets length and width of devices. "ResDevTile" - * structures are freed. + * Side Effects: sets length and width of devices. * *------------------------------------------------------------------------- */ @@ -701,14 +879,14 @@ ResPreProcessDevices(TileList, DeviceList, Def) CellDef *Def; { Tile *tile; - ResDevTile *oldTile; + ResDevTile *devTile; resInfo *tstruct; TileType tt, residue; int pNum; - while (TileList != (ResDevTile *) NULL) + for (devTile = TileList; devTile; devTile = devTile->nextDev) { - tt = TileList->type; + tt = devTile->type; if (DBIsContact(tt)) { /* Find which residue of the contact is a device. */ @@ -732,7 +910,8 @@ ResPreProcessDevices(TileList, DeviceList, Def) pNum = DBPlane(tt); /* always correct for non-contact types */ tile = PlaneGetHint(Def->cd_planes[pNum]); - GOTOPOINT(tile, &(TileList->area.r_ll)); + GOTOPOINT(tile, &(devTile->area.r_ll)); + PlaneSetHint(Def->cd_planes[pNum], tile); tt = TiGetType(tile); tstruct = (resInfo *) TiGetClientPTR(tile); @@ -742,23 +921,20 @@ ResPreProcessDevices(TileList, DeviceList, Def) !TTMaskHasType(&ExtCurStyle->exts_deviceMask, tt)) { TxError("Bad Device Location at %d,%d\n", - TileList->area.r_ll.p_x, - TileList->area.r_ll.p_y); + devTile->area.r_ll.p_x, + devTile->area.r_ll.p_y); } else if ((tstruct->ri_status & RES_TILE_MARK) == 0) { resDevice *rd = tstruct->deviceList; tstruct->ri_status |= RES_TILE_MARK; - rd->rd_perim += TileList->perim; - rd->rd_length += TileList->overlap; - rd->rd_area += (TileList->area.r_xtop - TileList->area.r_xbot) - * (TileList->area.r_ytop - TileList->area.r_ybot); + rd->rd_perim += devTile->perim; + rd->rd_length += devTile->overlap; + rd->rd_area += (devTile->area.r_xtop - devTile->area.r_xbot) + * (devTile->area.r_ytop - devTile->area.r_ybot); rd->rd_tiles++; } - oldTile = TileList; - TileList = TileList->nextDev; - freeMagic((char *)oldTile); } for (; DeviceList != NULL; DeviceList = DeviceList->rd_nextDev) diff --git a/resis/ResWrite.c b/resis/ResWrite.c index 8458282a..9a6e85ef 100644 --- a/resis/ResWrite.c +++ b/resis/ResWrite.c @@ -160,7 +160,7 @@ resCurrentPrintFunc(node, resistor, filename) void ResDeviceCounts() { - int i,j,k; + int i, j, k; resNode *n; resDevice *t; resResistor *r; diff --git a/resis/resis.h b/resis/resis.h index 85af3961..c2a2ce0b 100644 --- a/resis/resis.h +++ b/resis/resis.h @@ -51,16 +51,24 @@ typedef struct resistor #define rr_connection1 rr_node[0] #define rr_connection2 rr_node[1] -/* Definitions for old FET-style MOSFET devices */ +/* Definitions for old FET-style MOSFET devices. Actual devices may have + * any number of terminals. "GATE" is the identifying type; "SUBS" is + * the substrate/well connection (if it exists), and the other terminals + * make up the remaining entries. Memory will be allocated for the + * substrate whether or not one is defined for the device. If the device + * does not define a substrate connection, then this entry will remain + * NULL. + */ + #define RT_GATE 0 -#define RT_SOURCE 1 -#define RT_DRAIN 2 -#define RT_SUBS 3 +#define RT_SUBS 1 +#define RT_SOURCE 2 +#define RT_DRAIN 3 #define rd_fet_gate rd_terminals[RT_GATE] +#define rd_fet_subs rd_terminals[RT_SUBS] #define rd_fet_source rd_terminals[RT_SOURCE] #define rd_fet_drain rd_terminals[RT_DRAIN] -#define rd_fet_subs rd_terminals[RT_SUBS] typedef struct device { @@ -79,6 +87,19 @@ typedef struct device Tile *rd_tile; /* pointer to a tile in device */ } resDevice; +/* + * A resConnect maintains a location and tile type of a connections up + * (driver) or down (sink), a tile type that makes the connection, and + * a link to the resNode that must exist at the point of connection. + */ +typedef struct resconnect +{ + TileType rc_type; + Rect rc_rect; + struct resnode *rc_node; + struct resconnect *rc_next; +} ResConnect; + /* * A junction is formed when two tiles that connect are next to one another. */ @@ -100,9 +121,10 @@ typedef struct junction typedef struct resport { struct resport *rp_nextPort; - Rect rp_bbox; - Point rp_loc; char *rp_nodename; + ResConnect *rp_connect; + Rect rp_bbox; + Point rp_loc; } resPort; /* @@ -252,9 +274,10 @@ typedef struct resoptions { /* Global options for extresist */ - float tdiTolerance; - float frequency; - float rthresh; + float minres; /* Minimum network resistance to output */ + float mindelay; /* Minimum network delay to output */ + float rthresh; /* Minimum individual resistance */ + float frequency; /* For FastHenry geometry extraction */ struct saveList *savePlanes; CellDef *mainDef; @@ -266,9 +289,8 @@ typedef struct resoptions TileType rg_ttype; float rg_maxres; - float rg_nodecap; - float rg_Tdi; - int rg_bigdevres; + float rg_nodecap; /* Node capacitance */ + float rg_Tdi; /* Node delay */ int rg_tilecount; int rg_status; Point *rg_devloc; @@ -289,21 +311,19 @@ typedef struct rcdelaystuff typedef struct rdev { struct rdev *nextDev; /* Next device in linked list */ - struct rdev *realDev; /* Single Lumped Device for */ - /* devices connected in parallel */ resDevice *layout; /* pointer to resDevice that */ /* corresponds to RDev */ int status; struct resextnode *gate; /* Terminals of transistor. */ struct resextnode *source; struct resextnode *drain; - struct resextnode *subs; /* Used with subcircuit type only */ - Point location; /* Location of lower left point of */ - /* device. */ - float resistance; /* "Resistance" of device. */ - TileType rs_ttype; /* tile type for device */ - ExtDevice *rs_devptr; /* device extraction record */ - char *rs_gattr; /* Gate attributes, if any */ + struct resextnode *subs; /* Used with subcircuit type only */ + Point location; /* Location of lower left point */ + /* of the device. */ + TileType rs_ttype; /* tile type for device */ + float rs_wl; /* device W/L, if relevant */ + ExtDevice *rs_devptr; /* device extraction record */ + char *rs_gattr; /* Gate attributes, if any */ char *rs_sattr; char *rs_dattr; } RDev; @@ -320,17 +340,13 @@ typedef struct resextnode float cap_couple; /* Coupling capacitance */ float resistance; /* Lumped resistance */ float minsizeres; /* Minimum size resistor allowed */ - Point drivepoint; /* optional, user specified drive */ - /* point for network. */ - TileType rs_ttype; /* Tiletype of drivepoint */ + ResConnect *drivepoints; /* Upward connections */ + ResConnect *sinkpoints; /* Downward connections */ Point location; /* Location of bottom of leftmost */ /* tile in the lowest numbered */ /* plane contained in the node. */ - Rect rs_bbox; /* Location of bottom of leftmost */ - /* tile in the lowest numbered */ - /* plane contained in the node. */ TileType type; /* Tile type of tile at location */ - struct devptr *firstDev; /* Linked list of devices */ + struct devptr *devices; /* Linked list of devices */ /* connected to node. */ char *name; /* Pointer to name of node stored */ /* in hash table. */ @@ -443,6 +459,7 @@ typedef struct capval /* Capacitance table constants */ #define OHMSTOMILLIOHMS 1000 +#define MILLIOHMSTOOHMS 0.001 #define UNTOUCHED 0 #define SERIES 1 @@ -477,12 +494,12 @@ typedef struct capval #define ResOpt_DoExtFile 0x0004 #define ResOpt_DoLumpFile 0x0008 #define ResOpt_RunSilent 0x0010 -#define ResOpt_Stats 0x0020 -#define ResOpt_Tdi 0x0040 +#define ResOpt_Debug 0x0020 +#define ResOpt_Stats 0x0040 #define ResOpt_Signal 0x0080 #define ResOpt_Geometry 0x0100 #define ResOpt_FastHenry 0x0200 -#define ResOpt_Blackbox 0x0300 +#define ResOpt_Blackbox 0x0400 #define ResOpt_DoSubstrate 0x0800 #define ResOpt_Box 0x1000 @@ -510,7 +527,7 @@ extern ResFixPoint *ResFixList; extern int ResTileCount; extern ResExtNode **ResNodeArray; extern CellDef *mainDef; -extern TileTypeBitMask ResSDTypesBitMask; +extern TileTypeBitMask ResTermTypesBitMask; extern TileTypeBitMask ResSubTypesBitMask; extern HashTable ResDevTable; extern TileTypeBitMask ResNoMergeMask[NT]; @@ -525,12 +542,14 @@ extern int ResReadResistor(); extern int ResReadAttribute(); extern int ResReadMerge(); extern int ResReadSubckt(); +extern int ResReadParentExt(); extern int ResProcessNode(); extern int ResExtCombineParallel(); extern int dbSrConnectStartFunc(); extern int ResEach(); extern int ResAddPlumbing(); +extern void ResAddDevPlumbing(); extern int ResRemovePlumbing(); extern float ResCalculateChildCapacitance(); extern ResDevTile *DBTreeCopyConnectDCS(); @@ -543,14 +562,18 @@ extern void ResCheckExtNodes(); extern void ResSortByGate(); extern void ResFixDevName(); extern void ResWriteLumpFile(); -extern void ResSortBreaks(); +extern int ResSortBreaks(); extern Plane *extResPrepSubstrate(); +extern bool ResEachTile(); +extern void ResStartTile(); + /* C99 compat */ extern void ExtResisForDef(CellDef *celldef, ResisData *resisdata); extern char *ResExtGetAttribute(char *sptr); extern int ResReadFET(int argc, char *argv[]); +extern int ResReadConnectPoint(CellDef *def, int argc, char *argv[]); extern int ResReadPort(int argc, char *argv[]); extern char *ResExtGetAttribute(char *sptr); @@ -567,9 +590,10 @@ extern void ResEliminateResistor(); extern bool ResExtractNet(); extern int ResFracture(); extern void ResMergeNodes(); -extern void ResNewSDDevice(); +extern void ResNewTermDevice(); extern void ResNewSubDevice(); extern void ResPreProcessDevices(); +extern void ResFreeDevTiles(); extern void ResPrintDeviceList(); extern void ResPrintExtDev(); extern void ResPrintReference(); @@ -596,59 +620,8 @@ extern int resWalkleft(); extern int resWalkright(); extern int resWalkup(); -/* Macros */ - -#define InitializeResNode(node,x,y,why) \ -{\ - (node)->rn_te = NULL;\ - (node)->rn_id=0;\ - (node)->rn_float.rn_area = 0.0;\ - (node)->rn_name = NULL;\ - (node)->rn_client = (ClientData)NULL;\ - (node)->rn_noderes = RES_INFINITY;\ - (node)->rn_je = NULL;\ - (node)->rn_status = FALSE;\ - (node)->rn_loc.p_x = (x);\ - (node)->rn_loc.p_y = (y);\ - (node)->rn_why = (why);\ - (node)->rn_ce = (cElement *) NULL;\ - (node)->rn_re = (resElement *) NULL;\ -} - -#define ResInfoInit(Info) \ -{ \ - Info->contactList = (cElement *) NULL; \ - Info->deviceList = (resDevice *) NULL; \ - Info->junctionList = (ResJunction *) NULL; \ - Info->breakList = (Breakpoint *) NULL; \ - Info->portList = (resPort *) NULL; \ - Info->ri_status = FALSE; \ - Info->sourceEdge = 0 ; \ -} - -#define NEWBREAK(node,tile,px,py,crect)\ -{\ - Breakpoint *bp;\ - resInfo *jX_ = (resInfo *)((tile)->ti_client); \ - bp = (Breakpoint *) mallocMagic((unsigned)(sizeof(Breakpoint))); \ - bp->br_next= jX_->breakList; \ - bp->br_this = (node); \ - bp->br_loc.p_x = px; \ - bp->br_loc.p_y = py; \ - bp->br_crect = (Rect *) (crect); \ - jX_->breakList = bp; \ -} - -#define NEWPORT(node,tile)\ -{\ - resPort *rp;\ - resInfo *pX_ = (resInfo *)((tile)->ti_client); \ - rp = (resPort *) mallocMagic((unsigned)(sizeof(resPort))); \ - rp->rp_nextPort = pX_->portList; \ - rp->rp_bbox = node->rs_bbox; \ - rp->rp_loc = node->drivepoint; \ - rp->rp_nodename = node->name; \ - pX_->portList = rp; \ -} +extern void InitializeResNode(); +extern void ResInfoInit(); +extern void ResNewBreak(); #endif /* _MAGIC__RESIS__RESIS_H */ diff --git a/select/selCreate.c b/select/selCreate.c index 571714af..d7f40ba3 100644 --- a/select/selCreate.c +++ b/select/selCreate.c @@ -470,6 +470,9 @@ SelectArea(scx, types, xMask, globmatch) if (TTMaskHasType(types, L_LABEL)) { + TTMaskClearType(types, L_LABEL); + if (TTMaskIsZero(types)) types = &DBAllButSpaceAndDRCBits; + if (globmatch != NULL) DBCellCopyGlobLabels(scx, types, xMask, SelectUse, &labelArea, globmatch); @@ -834,6 +837,8 @@ chunkdone: if (DBIsContact(type)) TTMaskSetOnlyType(&typeMask, type); + /* Allow labels to be selected as part of the chunk */ + TTMaskSetType(&typeMask, L_LABEL); SelectArea(&newscx, &typeMask, xMask, NULL); } diff --git a/sim/SimDBstuff.c b/sim/SimDBstuff.c index bc294f6d..8ae21aa4 100644 --- a/sim/SimDBstuff.c +++ b/sim/SimDBstuff.c @@ -93,7 +93,7 @@ SimConnectFunc( TileType loctype, ctype; TileType newdinfo = 0; int i, pNum; - static char nodeName[256]; + static char nodeName[MAXPATHNAME]; CellDef *def; TerminalPath *tpath = cx->tc_filter->tf_tpath; @@ -133,7 +133,8 @@ SimConnectFunc( char c = *n; SigDisableInterrupts(); - strcpy(nodeName, SimGetNodeName(cx->tc_scx, tile, dinfo, tpath->tp_first)); + strncpy(nodeName, SimGetNodeName(cx->tc_scx, tile, dinfo, tpath->tp_first), + MAXPATHNAME); SigEnableInterrupts(); *n = c; diff --git a/tcltk/libmgr.tcl b/tcltk/libmgr.tcl index 71888059..44f164f8 100644 --- a/tcltk/libmgr.tcl +++ b/tcltk/libmgr.tcl @@ -35,10 +35,10 @@ proc magic::libcallback {command} { switch $command { load {$winname load $celldef} - place {$winname getcell $celldef} + place {$winname getcell $celldef child 0 0} pick { magic::tool pick - $winname getcell $celldef + $winname getcell $celldef child 0 0 magic::startselect $winname pick } } diff --git a/tcltk/tools.tcl b/tcltk/tools.tcl index b3ac5d7e..27921bad 100644 --- a/tcltk/tools.tcl +++ b/tcltk/tools.tcl @@ -651,9 +651,9 @@ proc magic::startselect {window {option {}}} { select nocycle } } - set Opts(origin) [cursor] + set Opts(origin) [cursor internal] set Opts(motion) [bind ${window} ] - bind ${window} [subst {$Opts(motion); set p \[cursor\]; \ + bind ${window} [subst {$Opts(motion); set p \[cursor internal\]; \ set x \[expr {\[lindex \$p 0\] - [lindex $Opts(origin) 0]}\]i; \ set y \[expr {\[lindex \$p 1\] - [lindex $Opts(origin) 1]}\]i; \ *bypass select move \${x} \${y}}]