diff --git a/VERSION b/VERSION index 0f9ce66b..ae074d55 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.652 +8.3.653 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/extflat/EFbuild.c b/extflat/EFbuild.c index 65f485da..beb2168a 100644 --- a/extflat/EFbuild.c +++ b/extflat/EFbuild.c @@ -1618,12 +1618,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 +1754,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/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..cc6b391d 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) */ @@ -344,6 +340,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 +374,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 +450,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..3885ac80 100644 --- a/extract/ExtBasic.c +++ b/extract/ExtBasic.c @@ -1110,7 +1110,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 +1155,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); } /* diff --git a/extract/ExtCell.c b/extract/ExtCell.c index c6def9fe..994b47cb 100644 --- a/extract/ExtCell.c +++ b/extract/ExtCell.c @@ -88,6 +88,11 @@ ExtCell(def, outName, doLength) 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. 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/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/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..bbaacde9 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,8 @@ ResSubstrateFunc(tile, dinfo, tpptr) #define IGNORE_BOTTOM 8 bool -ResEachTile(tile, startpoint) +ResEachTile(tile) Tile *tile; - Point *startpoint; - { Tile *tp; resNode *resptr; @@ -226,14 +240,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 +270,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 +293,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 +322,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 +337,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 +355,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 +370,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 +403,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,29 +436,30 @@ 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, ...) */ - if (TTMaskHasType(&ResSDTypesBitMask, t1)) + if (TTMaskHasType(&ResTermTypesBitMask, t1)) { Rect r; int pNum; TileTypeBitMask devMask; + TileAndTerm tat; TiToRect(tile, &r); @@ -470,20 +467,29 @@ ResEachTile(tile, startpoint) { if (DBTypeOnPlane(t1, pNum)) continue; - /* 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; + 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); + { + for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++) + { + /* Check if any type in the terminal type list exists on this + * plane before calling the search function. + */ + TileTypeBitMask termtypes; - DBSrPaintArea((Tile *)NULL, ResUse->cu_def->cd_planes[pNum], - &r, &devMask, ResMultiPlaneFunc, (ClientData)&tile); + TTMaskAndMask3(&termtypes, &devptr->exts_deviceSDTypes[i], + &DBPlaneTypes[pNum]); + + if (TTMaskIsZero(&termtypes)) + { + tat.tat_tile = tile; + tat.tat_term = i; + DBSrPaintArea((Tile *)NULL, ResUse->cu_def->cd_planes[pNum], + &r, &devptr->exts_deviceSDTypes[i], + ResMultiPlaneFunc, (ClientData)&tat); + } + } + } } } @@ -519,7 +525,7 @@ ResEachTile(tile, startpoint) 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 330b164e..6e1127a3 100644 --- a/resis/ResJunct.c +++ b/resis/ResJunct.c @@ -29,23 +29,28 @@ 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 = NULL; @@ -97,9 +102,7 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList) ResAddToQueue(resptr, PendingList); } if (resptr != NULL) - { - NEWBREAK(resptr, tile, xj, yj, NULL); - } + ResNewBreak(resptr, tile, xj, yj, NULL); } /* @@ -149,7 +152,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); } /* @@ -207,10 +210,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 af2d06dc..9c90ac53 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__". * @@ -161,7 +160,7 @@ ResDissolveContacts(contacts) #ifdef PARANOID if (conttype == TT_SPACE) - TxError("Error in Contact Dissolving for %s \n",ResCurrentNode); + TxError("Error in Contact Dissolving for %s \n", ResCurrentNode); #endif /* Fill in details of the residue types for each contact type. @@ -196,22 +195,38 @@ ResDissolveContacts(contacts) } } +/* 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; @@ -220,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) @@ -254,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)) { @@ -268,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) { @@ -312,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 */ @@ -351,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; @@ -386,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; } - /* *--------------------------------------------------------------------------- * @@ -522,8 +698,8 @@ ResFindNewContactTiles(contacts) int ResProcessTiles(resisdata, origin) - Point *origin; ResisData *resisdata; + Point *origin; { Tile *startTile; @@ -541,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); } #ifdef PARANOID else @@ -578,7 +755,7 @@ ResProcessTiles(resisdata, origin) if ((ri->ri_status & RES_TILE_DONE) == 0) { resCurrentNode = resptr2; - merged |= ResEachTile(tile, (Point *)NULL); + merged |= ResEachTile(tile); } } rj->rj_status = TRUE; @@ -604,7 +781,7 @@ ResProcessTiles(resisdata, origin) if (cp->cp_cnode[tilenum] == resptr2) { resCurrentNode = resptr2; - merged |= ResEachTile(tile, (Point *)NULL); + merged |= ResEachTile(tile); } else { @@ -687,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)); @@ -701,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)); @@ -1086,15 +1263,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 { @@ -1117,13 +1301,40 @@ 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; @@ -1155,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); @@ -1227,8 +1438,8 @@ ResExtractNet(node, resisdata, cellname) * cell. */ - ResMakePortBreakpoints(ResUse->cu_def); - ResMakeLabelBreakpoints(ResUse->cu_def, resisdata); + ResMakeDriverSinkPorts(ResUse->cu_def); + ResMakeLabelPorts(ResUse->cu_def, resisdata); /* Finish preprocessing. */ @@ -1428,13 +1639,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); } @@ -1491,7 +1702,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); } @@ -1534,7 +1745,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); } @@ -1590,7 +1801,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)) { @@ -1658,7 +1869,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)) { diff --git a/resis/ResMakeRes.c b/resis/ResMakeRes.c index b7ffd0ac..d9ea3222 100644 --- a/resis/ResMakeRes.c +++ b/resis/ResMakeRes.c @@ -687,7 +687,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList) } else { - deltay=0; + deltay = 0; } } else @@ -701,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 @@ -887,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); } } @@ -936,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 */ diff --git a/resis/ResMerge.c b/resis/ResMerge.c index 3cf2e79e..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. * 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..9ef92f06 100644 --- a/resis/ResReadExt.c +++ b/resis/ResReadExt.c @@ -82,6 +82,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 +109,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 +132,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 +170,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 +192,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 +214,290 @@ 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; + + /* XXX Diagnostic XXX */ + 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); +} /* *------------------------------------------------------------------------- @@ -213,14 +524,7 @@ ResReadNode(int argc, char *argv[]) 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]); if (node->type == -1) { @@ -230,6 +534,82 @@ 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; + + /* XXX Diagnostic XXX */ + 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 +620,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 +636,30 @@ 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; + + /* XXX Diagnostic XXX */ + 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 +668,7 @@ ResReadPort(int argc, } return 0; } + /* *------------------------------------------------------------------------- * @@ -287,7 +683,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 +698,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; } @@ -628,10 +1024,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 +1076,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 5f44b27c..b7e50edb 100644 --- a/resis/ResRex.c +++ b/resis/ResRex.c @@ -90,6 +90,7 @@ ExtResisForDef(celldef, resisdata) HashSearch hs; HashEntry *entry; devPtr *tptr, *oldtptr; + ResConnect *sptr, *snext; ResExtNode *node; int result, idx; char *devname; @@ -137,8 +138,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 +151,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); @@ -749,6 +762,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 +817,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 +901,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 +919,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 +934,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; @@ -1003,7 +1007,7 @@ ResProcessNode( return 0; ResCurrentNode = node->name; - ResSortByGate(&node->firstDev); + ResSortByGate(&node->devices); /* Find largest SD device connected to node. */ @@ -1015,9 +1019,9 @@ 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) + for (ptr = node->devices; ptr != NULL; ptr = ptr->nextDev) { RDev *t1; RDev *t2; @@ -1067,16 +1071,26 @@ ResProcessNode( else minRes = 0; - if (node->status & DRIVELOC) + /* NOTE: This needs to be fixed, as it is assuming that + * a node has exactly one drivepoint; this is (probably) + * valid for top level cells, but not in general. + */ + if ((node->status & (DRIVELOC | PORTNODE)) && (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 start point. + */ + else if ((node->status & (DRIVELOC | PORTNODE)) && (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 ((resisdata->rg_devloc == NULL) && (node->status & FORCE)) @@ -1222,7 +1236,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 +1299,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. @@ -1376,13 +1434,13 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename) } } - if (extDev->source == extNode) + if ((extDev->source == extNode) && (layoutDev->rd_nterms > 3)) { /* 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 +1459,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; @@ -1571,8 +1629,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) { @@ -1816,6 +1874,7 @@ ResWriteExtFile(celldef, node, resisdata, nidx, eidx) devPtr *ptr; resDevice *layoutDev, *ResGetDevice(); float rctol; + ResConnect *driver, *sink; rctol = resisdata->tdiTolerance; RCdev = resisdata->rg_bigdevres * resisdata->rg_nodecap; @@ -1826,8 +1885,9 @@ ResWriteExtFile(celldef, node, resisdata, nidx, eidx) (rctol + 1) * RCdev < rctol * resisdata->rg_Tdi) { ASSERT(resisdata->rg_Tdi != -1, "ResWriteExtFile"); - (void)sprintf(newname,"%s", node->name); - cp = newname + strlen(newname)-1; + + 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) @@ -1841,13 +1901,26 @@ ResWriteExtFile(celldef, node, resisdata, nidx, eidx) 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))) - { + 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); @@ -1872,3 +1945,113 @@ ResWriteExtFile(celldef, node, resisdata, nidx, eidx) else return 0; } +/* + *------------------------------------------------------------------------- + * + * 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 02c79e9a..62984247 100644 --- a/resis/ResSimple.c +++ b/resis/ResSimple.c @@ -389,9 +389,9 @@ ResMoveDevices(node1, node2) device->rd_fet_gate = node2; 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"); @@ -920,7 +920,7 @@ ResPruneTree(node, minTdi, nodelist1, nodelist2, resistorlist) */ int -ResDoSimplify(tolerance,resisdata) +ResDoSimplify(tolerance, resisdata) float tolerance; ResisData *resisdata; diff --git a/resis/ResUtils.c b/resis/ResUtils.c index bf497058..f0f421ff 100644 --- a/resis/ResUtils.c +++ b/resis/ResUtils.c @@ -604,7 +604,7 @@ ResAddPlumbing(tile, dinfo, arg) } } /* bottom */ - for(tp2 = LB(tp1); LEFT(tp2) < RIGHT(tp1); tp2 = TR(tp2)) + for (tp2 = LB(tp1); LEFT(tp2) < RIGHT(tp1); tp2 = TR(tp2)) { resInfo *re2 = (resInfo *) TiGetClientPTR(tp2); if (TiGetTopType(tp2) == t1) 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 ab501dee..aa187b0b 100644 --- a/resis/resis.h +++ b/resis/resis.h @@ -87,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. */ @@ -108,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; /* @@ -328,17 +342,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. */ @@ -518,7 +528,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]; @@ -533,6 +543,7 @@ extern int ResReadResistor(); extern int ResReadAttribute(); extern int ResReadMerge(); extern int ResReadSubckt(); +extern int ResReadParentExt(); extern int ResProcessNode(); extern int ResExtCombineParallel(); @@ -553,12 +564,16 @@ extern void ResFixDevName(); extern void ResWriteLumpFile(); 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); @@ -575,7 +590,7 @@ 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 ResPrintDeviceList(); @@ -604,59 +619,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 */