#ifndef lint static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResReadExt.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $"; #endif /* not lint */ /* *------------------------------------------------------------------------- * * ResReadExt.c -- Routines to parse .ext files for information needed * by extresist. * *------------------------------------------------------------------------- */ #include #include #include #include #include #include "utils/magic.h" #include "utils/main.h" #include "utils/geometry.h" #include "utils/geofast.h" #include "tiles/tile.h" #include "utils/hash.h" #include "database/database.h" #include "utils/malloc.h" #include "textio/textio.h" #include "extract/extract.h" #include "extract/extractInt.h" #include "extflat/extflat.h" #include "extflat/extparse.h" #include "windows/windows.h" #include "dbwind/dbwind.h" #include "utils/utils.h" #include "utils/tech.h" #include "textio/txcommands.h" #include "resis/resis.h" /* constants defining where various fields can be found in .ext files. */ /* The value corresponds to the argument number on the list after */ /* parsing by efReadLine(). */ #define FET_NAME 1 #define FET_X 2 #define FET_Y 3 #define FET_AREA 4 #define FET_PERIM 5 #define FET_SUBS 6 #define FET_GATE 7 #define FET_GATE_ATTR 9 #define FET_SOURCE 10 #define FET_SOURCE_ATTR 12 #define FET_DRAIN 13 #define FET_DRAIN_ATTR 15 #define DEV_NAME 2 #define DEV_X 3 #define DEV_Y 4 #define DEV_PARAM_START 7 #define NODES_NODENAME 1 #define NODES_NODEX 4 #define NODES_NODEY 5 #define NODES_NODETYPE 6 #define COUPLETERMINAL1 1 #define COUPLETERMINAL2 2 #define COUPLEVALUE 3 #define RES_EXT_ATTR_NAME 1 #define RES_EXT_ATTR_X 2 #define RES_EXT_ATTR_Y 3 #define RES_EXT_ATTR_TYPE 6 #define RES_EXT_ATTR_TEXT 7 #define PORT_NAME 1 #define PORT_LLX 3 #define PORT_LLY 4 #define PORT_URX 5 #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 */ char RDEV_NOATTR[1] = {'0'}; ResFixPoint *ResFixList; /* *------------------------------------------------------------------------- * * ResReadExt -- * * 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. * * Results: Returns 0 if ext file is correct, 1 if not. * * Side Effects: Creates lists of nodes and devices for extresist. * *------------------------------------------------------------------------- */ int ResReadExt(CellDef *def) { char *line = NULL, *argv[128]; int result, locresult; int argc, n, size = 0; FILE *fp; CellDef *dbdef, *parent; CellUse *use; ResExtNode *curnode; HashTable parentHash; HashEntry *he; /* Search for the .ext file in the same way that efReadDef() does. */ fp = ExtFileOpen(def, (char *)NULL, "r", (char **)NULL); if (fp == NULL) { TxError("Cannot open file %s%s\n", def->cd_name, ".ext"); return 1; } /* 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; } /* We don't care about most tokens, only DEVICE, NODE, PORT, * 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) { case SCALE: /* NOTE: Currently the code assumes that the .ext * file is read back immediately and has the same * scale values currently in the extraction style. * However, this should be style-independent and * scale values should be read back and used. * (to be completed). */ break; case DEVICE: locresult = ResReadDevice(argc, argv); break; case FET: locresult = ResReadFET(argc, argv); break; 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 ATTR: locresult = ResReadAttribute(curnode, argc, argv); break; case CAP: locresult = ResReadCapacitor(argc, argv); break; default: break; } 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); } /* *------------------------------------------------------------------------- * * ResReadNode-- Reads in a node statement, puts location and type of * node into a node structure. * * Results: Pointer to the node record if the node was read correctly, * NULL otherwise. * * Side Effects: see above * *------------------------------------------------------------------------- */ ResExtNode * ResReadNode(int argc, char *argv[]) { HashEntry *entry; ResExtNode *node; entry = HashFind(&ResNodeTable, argv[NODES_NODENAME]); node = ResExtInitNode(entry); node->location.p_x = atoi(argv[NODES_NODEX]); node->location.p_y = atoi(argv[NODES_NODEY]); node->type = DBTechNameType(argv[NODES_NODETYPE]); if (node->type == -1) { TxError("Bad tile type name in .ext file for node %s\n", node->name); return NULL; } 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; } /* *------------------------------------------------------------------------- * * ResReadPort-- Reads in a port statement from the .ext file and sets * node records accordingly to mark the node as a drivepoint. * * Results: 0 if successful and 1 otherwise. * * 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. * *------------------------------------------------------------------------- */ int ResReadPort(int argc, char *argv[]) { HashEntry *entry; ResExtNode *node; ResConnect *newdriver; entry = HashFind(&ResNodeTable, argv[PORT_NAME]); node = ResExtInitNode(entry); /* 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) { TxError("Bad tile type name in .ext file for node %s\n", node->name); return 1; } return 0; } /* *------------------------------------------------------------------------- * * ResNodeAddDevice -- * * Given a device and a node which connects to one of its terminals, * add the device to the node's device list. Device type is one * of the indexes defined by GATE, SOURCE, or DRAIN (to do: generalize * this). * * Results: * None. * * Side effects: * Allocates memory for a devPtr, adds to the node's "devices" linked * list. * *------------------------------------------------------------------------- */ void ResNodeAddDevice(ResExtNode *node, RDev *device, int termtype) { devPtr *tptr; tptr = (devPtr *)mallocMagic((unsigned)(sizeof(devPtr))); tptr->thisDev = device; tptr->nextDev = node->devices; node->devices = tptr; tptr->terminal = termtype; } /* *------------------------------------------------------------------------- * * ResReadDevice-- * * Process a "device" line from a ext file. * * Results: returns 0 if line was added correctly. * * Side Effects: Allocates devicesl * *------------------------------------------------------------------------- */ int ResReadDevice(int argc, char *argv[]) { RDev *device; int rvalue, i, j, k; ExtDevice *devptr; TileType ttype; HashEntry *entry; ResExtNode *node; ResValue rpersquare; float wval; device = (RDev *)mallocMagic((unsigned)(sizeof(RDev))); device->status = FALSE; device->nextDev = ResRDevList; /* Find the device definition record corresponding to the device name */ devptr = (ExtDevice *)NULL; for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++) { for (devptr = ExtCurStyle->exts_device[ttype]; devptr; devptr = devptr->exts_next) if (!strcmp(devptr->exts_deviceName, argv[DEV_NAME])) break; if (devptr != NULL) break; } device->location.p_x = atoi(argv[DEV_X]); device->location.p_y = atoi(argv[DEV_Y]); device->rs_gattr = RDEV_NOATTR; device->rs_sattr = RDEV_NOATTR; device->rs_dattr = RDEV_NOATTR; device->rs_devptr = devptr; device->source = (ResExtNode *)NULL; device->drain = (ResExtNode *)NULL; device->subs = (ResExtNode *)NULL; entry = HashLookOnly(&devptr->exts_deviceResist, "linear"); if (entry != NULL) rpersquare = (ResValue)(spointertype)HashGetValue(entry); else rpersquare = (ResValue)10000.0; /* Default to a sane value */ /* For devices, the device width is in the parameter list */ wval = 0.0; for (i = DEV_Y; i < argc; i++) { char *eptr; if ((eptr = strchr(argv[i], '=')) != NULL) { if (*argv[i] == 'w') sscanf(eptr + 1, "%f", &wval); } else if (!StrIsInt(argv[i])) break; } if (i == argc) { TxError("Bad device %s: Too few arguments in .ext file\n", argv[DEV_NAME]); return 1; } else device->resistance = wval * rpersquare; /* Channel resistance */ /* Find and record the device terminal nodes */ /* Note that this only records up to two terminals matching FET * source and drain; it needs to be expanded to include an * arbitrary number of terminals. */ if (strcmp(argv[i], "None")) { entry = HashFind(&ResNodeTable, argv[i]); device->subs = (ResExtNode *)HashGetValue(entry); ResNodeAddDevice(device->subs, device, SUBS); } i++; entry = HashFind(&ResNodeTable, argv[i]); device->gate = (ResExtNode *)HashGetValue(entry); device->rs_gattr = StrDup((char **)NULL, argv[i + 2]); ResNodeAddDevice(device->gate, device, GATE); i += 3; if (i < argc - 2) { entry = HashFind(&ResNodeTable, argv[i]); device->source = (ResExtNode *)HashGetValue(entry); device->rs_sattr = StrDup((char **)NULL, argv[i + 2]); ResNodeAddDevice(device->source, device, SOURCE); i += 3; } if (i < argc - 2) { entry = HashFind(&ResNodeTable, argv[i]); device->drain = (ResExtNode *)HashGetValue(entry); device->rs_dattr = StrDup((char **)NULL, argv[i + 2]); ResNodeAddDevice(device->drain, device, DRAIN); i += 3; } if (i < argc - 2) { TxError("Warning: Device %s has more than 4 ports (not handled).\n", argv[DEV_NAME]); } device->rs_ttype = extGetDevType(devptr->exts_deviceName); ResRDevList = device; device->layout = NULL; return 0; } /* *------------------------------------------------------------------------- * * ResReadFET-- Processes a "fet" line from a ext file. * * Results: returns 0 if line was added correctly. * * Side Effects: Allocates devices. * *------------------------------------------------------------------------- */ int ResReadFET(int argc, char *argv[]) { RDev *device; int rvalue, i, j, k; ExtDevice *devptr; TileType ttype; HashEntry *entry; ResExtNode *node; ResValue rpersquare; float area, perim, wval, lval; device = (RDev *)mallocMagic((unsigned)(sizeof(RDev))); device->status = FALSE; device->nextDev = ResRDevList; /* Find the device definition record corresponding to the device name */ devptr = (ExtDevice *)NULL; for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++) { for (devptr = ExtCurStyle->exts_device[ttype]; devptr; devptr = devptr->exts_next) if (!strcmp(devptr->exts_deviceName, argv[FET_NAME])) break; if (devptr != NULL) break; } device->location.p_x = atoi(argv[FET_X]); device->location.p_y = atoi(argv[FET_Y]); device->rs_gattr = RDEV_NOATTR; device->rs_sattr = RDEV_NOATTR; device->rs_dattr = RDEV_NOATTR; device->rs_devptr = devptr; entry = HashLookOnly(&devptr->exts_deviceResist, "linear"); if (entry != NULL) rpersquare = (ResValue)(spointertype)HashGetValue(entry); else rpersquare = (ResValue)10000.0; /* Default to a sane value */ /* For old-style FETs, the width is determined from area and perimeter */ area = MagAtof(argv[FET_AREA]); perim = MagAtof(argv[FET_PERIM]); lval = 0.5 * (perim + sqrt(perim * perim - 4 * area)); wval = area / lval; device->resistance = wval * rpersquare; /* Channel resistance */ /* Find and record the FET terminal nodes */ entry = HashFind(&ResNodeTable, argv[FET_GATE]); device->gate = (ResExtNode *)HashGetValue(entry); entry = HashFind(&ResNodeTable, argv[FET_SOURCE]); device->source = (ResExtNode *)HashGetValue(entry); entry = HashFind(&ResNodeTable, argv[FET_DRAIN]); device->drain = (ResExtNode *)HashGetValue(entry); entry = HashFind(&ResNodeTable, argv[FET_SUBS]); device->subs = (ResExtNode *)HashGetValue(entry); device->rs_ttype = extGetDevType(devptr->exts_deviceName); /* Copy attributes verbatim */ device->rs_gattr = StrDup((char **)NULL, argv[FET_GATE_ATTR]); device->rs_sattr = StrDup((char **)NULL, argv[FET_SOURCE_ATTR]); device->rs_dattr = StrDup((char **)NULL, argv[FET_DRAIN_ATTR]); ResRDevList = device; device->layout = NULL; return 0; } /* *------------------------------------------------------------------------- * * ResReadCapacitor-- Adds the capacitance from a C line to the appropriate * node. Coupling capacitors are added twice, moving the capacitance * to the substrate. * * Results: * Always return 0 * * Side Effects: modifies capacitance field of ResExtNode. * *------------------------------------------------------------------------- */ int ResReadCapacitor(int argc, char *argv[]) { HashEntry *entry1, *entry2; ResExtNode *node1, *node2; entry1 = HashFind(&ResNodeTable, argv[COUPLETERMINAL1]); node1 = ResExtInitNode(entry1); if (ResOptionsFlags & ResOpt_Signal) { node1->capacitance += MagAtof(argv[COUPLEVALUE]); entry2 = HashFind(&ResNodeTable, argv[COUPLETERMINAL2]); node2 = ResExtInitNode(entry2); node2->capacitance += MagAtof(argv[COUPLEVALUE]); return 0; } entry2 = HashFind(&ResNodeTable, argv[COUPLETERMINAL2]); node2 = ResExtInitNode(entry2); node1->cap_couple += MagAtof(argv[COUPLEVALUE]); node2->cap_couple += MagAtof(argv[COUPLEVALUE]); return 0; } /* *------------------------------------------------------------------------- * * ResReadAttribute--checks to see if a node attribute is a resistance * attribute. If it is, add it to the correct node's status flag. * Only works with 5.0 1/line attributes * * Results: * Return 0 to keep search going, 1 to abort * * Side Effects: modifies resistance field of ResExtNode * *------------------------------------------------------------------------- */ int ResReadAttribute(ResExtNode *node, int argc, char *argv[]) { char *aname, *avalue; char digit[MAXDIGIT]; int i; static int notwarned = TRUE; aname = argv[RES_EXT_ATTR_NAME]; avalue = argv[RES_EXT_ATTR_TEXT]; if (strncmp(avalue, "res:skip", 8) == 0) { if (node->status & FORCE) { TxError("Warning: Node %s is both forced and skipped\n", aname); } else { node->status |= SKIP; } } else if (strncmp(avalue, "res:force", 9) == 0) { if (node->status & SKIP) TxError("Warning: Node %s is both skipped and forced \n", aname); else node->status |= FORCE; } else if (strncmp(avalue, "res:min=", 8) == 0) { node->status |= MINSIZE; for (i = 0, avalue += 8; *avalue != '\0'; avalue++) { digit[i++] = *avalue; } digit[i++] = '\0'; node->minsizeres = MagAtof(digit); } else if (strncmp(avalue, "res:drive", 9) == 0 && (ResOptionsFlags & ResOpt_Signal)) { 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; } /* *------------------------------------------------------------------------- * * ResExtInitNode -- * Gets the node corresponding to a given hash table entry. If no * such node exists, one is created. * * Results: Returns ResExtNode corresponding to entry. * * Side Effects: May allocate a new ResExtNode. * *------------------------------------------------------------------------- */ ResExtNode * ResExtInitNode(entry) HashEntry *entry; { ResExtNode *node; if ((node = (ResExtNode *) HashGetValue(entry)) == NULL) { node = (ResExtNode *)mallocMagic((unsigned)(sizeof(ResExtNode))); HashSetValue(entry, (char *) node); node->nextnode = ResOriginalNodes; ResOriginalNodes = node; node->status = FALSE; node->forward = (ResExtNode *) NULL; node->capacitance = 0; node->cap_couple = 0; node->resistance = 0; node->type = 0; node->devices = NULL; node->name = entry->h_key.h_name; node->oldname = NULL; node->drivepoints = NULL; node->sinkpoints = NULL; node->location.p_x = INFINITY; node->location.p_y = INFINITY; } while (node->status & FORWARD) { node = node->forward; } return node; }