2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
#ifndef lint
|
2026-01-27 17:56:47 +01:00
|
|
|
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 $";
|
2017-04-25 14:41:48 +02:00
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* ResReadExt.c -- Routines to parse .ext files for information needed
|
|
|
|
|
* by extresist.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
|
|
#include "utils/magic.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"
|
2021-04-21 02:45:49 +02:00
|
|
|
#include "extflat/extflat.h"
|
2017-04-25 14:41:48 +02:00
|
|
|
#include "windows/windows.h"
|
|
|
|
|
#include "dbwind/dbwind.h"
|
|
|
|
|
#include "utils/utils.h"
|
|
|
|
|
#include "utils/tech.h"
|
|
|
|
|
#include "textio/txcommands.h"
|
2021-04-21 02:45:49 +02:00
|
|
|
#include "resis/resis.h"
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2026-01-27 17:56:47 +01:00
|
|
|
/* constants defining where various fields can be found in .ext files. */
|
|
|
|
|
/* (FIXME---Needs to be changed to positions in .ext files) */
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2019-10-17 22:21:56 +02:00
|
|
|
#define RDEV_LENGTH 4
|
|
|
|
|
#define RDEV_WIDTH 5
|
|
|
|
|
#define RDEV_DEVX 6
|
|
|
|
|
#define RDEV_DEVY 7
|
|
|
|
|
#define RDEV_ATTR 8
|
|
|
|
|
#define RDEV_NUM_ATTR 3
|
2017-04-25 14:41:48 +02:00
|
|
|
#define RESNODENAME 1
|
|
|
|
|
#define NODERESISTANCE 2
|
|
|
|
|
#define COUPLETERMINAL1 1
|
|
|
|
|
#define COUPLETERMINAL2 2
|
|
|
|
|
#define COUPLEVALUE 3
|
|
|
|
|
#define REALNAME 1
|
|
|
|
|
#define ALIASNAME 2
|
2021-04-21 19:03:26 +02:00
|
|
|
#define NODES_NODENAME 0
|
|
|
|
|
#define NODES_NODEX 1
|
|
|
|
|
#define NODES_NODEY 2
|
|
|
|
|
#define NODES_NODETYPE 3
|
2017-04-25 14:41:48 +02:00
|
|
|
#define NODE_BBOX_LL_X 5
|
|
|
|
|
#define NODE_BBOX_LL_Y 6
|
|
|
|
|
#define NODE_BBOX_UR_X 7
|
|
|
|
|
#define NODE_BBOX_UR_Y 8
|
|
|
|
|
#define NODELAMBDA 2
|
|
|
|
|
#define NODEUNITS 1
|
|
|
|
|
#define ATTRIBUTENODENAME 1
|
|
|
|
|
#define ATTRIBUTEVALUE 2
|
|
|
|
|
|
|
|
|
|
#define RES_EXT_ATTR 0
|
|
|
|
|
#define RES_EXT_ATTR_NAME 1
|
|
|
|
|
#define RES_EXT_ATTR_X 2
|
|
|
|
|
#define RES_EXT_ATTR_Y 3
|
|
|
|
|
#define RES_EXT_ATTR_TILE 6
|
|
|
|
|
#define RES_EXT_ATTR_TEXT 7
|
|
|
|
|
|
2023-03-25 21:11:46 +01:00
|
|
|
#define MAXTOKEN 1024
|
2017-04-25 14:41:48 +02:00
|
|
|
#define MAXLINE 40
|
|
|
|
|
#define MAXDIGIT 20
|
|
|
|
|
|
2026-01-27 17:56:47 +01:00
|
|
|
ResExtNode *ResInitializeNode();
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2026-01-27 17:56:47 +01:00
|
|
|
ResExtNode *ResOriginalNodes; /*Linked List of Nodes */
|
|
|
|
|
static float resscale = 1.0; /* Scale factor */
|
|
|
|
|
char RDEV_NOATTR[1] = {'0'};
|
|
|
|
|
ResFixPoint *ResFixList;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* ResReadExt--
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* Results: returns 0 if ext file is correct, 1 if not.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* Side Effects:Reads in ExtTable and makes a hash table of nodes.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
2026-01-27 17:56:47 +01:00
|
|
|
ResReadExt(char *extfile);
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2026-01-27 17:56:47 +01:00
|
|
|
char *line = NULL, *argv[128];
|
|
|
|
|
int result, fettype, readdrivepoints;
|
|
|
|
|
int size = 0;
|
|
|
|
|
FILE *fp;
|
2021-05-26 04:41:52 +02:00
|
|
|
|
2026-01-27 17:56:47 +01:00
|
|
|
fp = PaOpen(extfile, "r", ".ext", EFSearchPath, EFLibPath, (char **)NULL);
|
2021-05-26 04:41:52 +02:00
|
|
|
if (fp == NULL)
|
|
|
|
|
{
|
2026-01-27 17:56:47 +01:00
|
|
|
TxError("Cannot open file %s%s\n", extfile, ".ext");
|
2021-05-26 04:41:52 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
2026-01-27 17:56:47 +01:00
|
|
|
readdrivepoints = FALSE;
|
2021-05-26 04:41:52 +02:00
|
|
|
|
2026-01-27 17:56:47 +01:00
|
|
|
/* Read in the file. Makes use of various functions
|
|
|
|
|
* from extflat, mostly in EFread.c.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
EFSaveLocs = False;
|
|
|
|
|
efReadLineNum = 0;
|
|
|
|
|
|
|
|
|
|
while ((argc = efReadLine(&line, &size, fp, argv)) >= 0)
|
2021-05-26 04:41:52 +02:00
|
|
|
{
|
2026-01-27 17:56:47 +01:00
|
|
|
n = LookupStruct(argv[0], (const LookupTable *)keyTable, sizeof keyTable[0]);
|
|
|
|
|
if (n < 0)
|
2021-05-26 04:41:52 +02:00
|
|
|
{
|
2026-01-27 17:56:47 +01:00
|
|
|
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 MERGE is used to locate drive points.
|
|
|
|
|
*/
|
|
|
|
|
switch (keyTable[n].k_key)
|
|
|
|
|
{
|
|
|
|
|
case SCALE:
|
|
|
|
|
resscale = (float)atof(argv[1]);
|
|
|
|
|
if (resscale == 0.0) resscale = 1.0;
|
2021-05-26 04:41:52 +02:00
|
|
|
break;
|
2026-01-27 17:56:47 +01:00
|
|
|
case DEVICE:
|
|
|
|
|
ResReadSubckt(argc, argv);
|
2021-05-26 04:41:52 +02:00
|
|
|
break;
|
2026-01-27 17:56:47 +01:00
|
|
|
case FET:
|
|
|
|
|
ResReadDevice(argc, argv);
|
2021-05-26 04:41:52 +02:00
|
|
|
break;
|
2026-01-27 17:56:47 +01:00
|
|
|
case MERGE:
|
|
|
|
|
ResReadDrivePoint(argc, argv);
|
2021-05-26 04:41:52 +02:00
|
|
|
break;
|
2026-01-27 17:56:47 +01:00
|
|
|
case NODE:
|
|
|
|
|
case SUBSTRATE:
|
|
|
|
|
ResReadNode(argc, argv);
|
2024-10-04 18:04:43 +02:00
|
|
|
break;
|
2026-01-27 17:56:47 +01:00
|
|
|
case PORT:
|
|
|
|
|
ResReadPort(argc, argv);
|
2021-05-26 04:41:52 +02:00
|
|
|
break;
|
2026-01-27 17:56:47 +01:00
|
|
|
case ATTR:
|
|
|
|
|
result = ResExtAttribute(curnodename,
|
|
|
|
|
argv[1], &readdrivepoints);
|
2021-05-26 04:41:52 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2026-01-27 17:56:47 +01:00
|
|
|
|
|
|
|
|
/* to do: Handle CAP, RESISTOR, maybe others? */
|
2021-05-26 04:41:52 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fclose(fp);
|
|
|
|
|
return(result);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* ResReadNode-- Reads in a node file, puts location of nodes into node
|
|
|
|
|
* structures.
|
|
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* Results: 0 if the node was read correctly, 1 otherwise.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* Side Effects: see above
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
2026-01-27 17:56:47 +01:00
|
|
|
ResReadNode(int argc, char *argv[])
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
HashEntry *entry;
|
2026-01-27 17:56:47 +01:00
|
|
|
ResExtNode *node;
|
2017-04-25 14:41:48 +02:00
|
|
|
char *cp;
|
2019-10-28 18:10:16 +01:00
|
|
|
float lambda;
|
|
|
|
|
|
2026-01-27 17:56:47 +01:00
|
|
|
entry = HashFind(&ResNodeTable, line[NODES_NODENAME]);
|
|
|
|
|
node = ResInitializeNode(entry);
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2026-01-27 17:56:47 +01:00
|
|
|
node->location.p_x = atoi(line[NODES_NODEX]);
|
|
|
|
|
node->location.p_y = atoi(line[NODES_NODEY]);
|
|
|
|
|
if ((cp = strchr(line[NODES_NODETYPE], ';'))) *cp = '\0';
|
|
|
|
|
node->type = DBTechNameType(line[NODES_NODETYPE]);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2026-01-27 17:56:47 +01:00
|
|
|
if (node->type == -1)
|
2021-05-26 04:41:52 +02:00
|
|
|
{
|
2026-01-27 17:56:47 +01:00
|
|
|
TxError("Bad tile type name in .ext file for node %s\n",
|
|
|
|
|
node->name);
|
|
|
|
|
return 1;
|
2021-05-26 04:41:52 +02:00
|
|
|
}
|
2026-01-27 17:56:47 +01:00
|
|
|
return 0;
|
2021-05-26 04:41:52 +02:00
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2021-04-21 02:45:49 +02:00
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* ResReadSubckt-- Processes a subcircuit line from a ext file.
|
2021-04-21 02:45:49 +02:00
|
|
|
* This uses the "user subcircuit" extension defined in
|
|
|
|
|
* IRSIM, although it is mostly intended as a way to work
|
2026-01-27 17:56:47 +01:00
|
|
|
* around the device type limitations of the .ext format
|
2021-04-21 02:45:49 +02:00
|
|
|
* when using extresist.
|
|
|
|
|
*
|
|
|
|
|
* Results: returns 0 if line was added correctly.
|
|
|
|
|
*
|
|
|
|
|
* Side Effects: Allocates devices and adds nodes to the node hash table.
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
2026-01-27 17:56:47 +01:00
|
|
|
ResReadSubckt(line)
|
2021-04-21 02:45:49 +02:00
|
|
|
char line[][MAXTOKEN];
|
|
|
|
|
{
|
|
|
|
|
RDev *device;
|
|
|
|
|
int rvalue, i, j, k;
|
|
|
|
|
static int nowarning = TRUE;
|
|
|
|
|
float lambda;
|
|
|
|
|
TileType ttype = TT_SPACE;
|
|
|
|
|
char *lptr = NULL, *wptr = NULL;
|
2021-05-22 04:41:51 +02:00
|
|
|
ExtDevice *devptr;
|
2021-04-21 02:45:49 +02:00
|
|
|
|
|
|
|
|
device = (RDev *) mallocMagic((unsigned) (sizeof(RDev)));
|
|
|
|
|
|
|
|
|
|
device->status = FALSE;
|
|
|
|
|
device->nextDev = ResRDevList;
|
|
|
|
|
|
|
|
|
|
lambda = (float)ExtCurStyle->exts_unitsPerLambda / resscale;
|
|
|
|
|
device->location.p_x = 0;
|
|
|
|
|
device->location.p_y = 0;
|
|
|
|
|
|
|
|
|
|
device->rs_gattr=RDEV_NOATTR;
|
|
|
|
|
device->rs_sattr=RDEV_NOATTR;
|
|
|
|
|
device->rs_dattr=RDEV_NOATTR;
|
|
|
|
|
|
|
|
|
|
ResRDevList = device;
|
|
|
|
|
device->layout = NULL;
|
2021-05-26 04:41:52 +02:00
|
|
|
device->source = device->drain = device->gate = device->subs = NULL;
|
2021-04-21 02:45:49 +02:00
|
|
|
|
|
|
|
|
/* The last argument is the name of the device */
|
|
|
|
|
for (i = 1; line[i][0] != '\0'; i++);
|
|
|
|
|
i--;
|
|
|
|
|
|
2021-06-07 03:44:52 +02:00
|
|
|
/* To do: Replace this search with a pre-prepared hash */
|
|
|
|
|
/* table to key off of the device name. */
|
2021-04-21 02:45:49 +02:00
|
|
|
for (j = 0; j < EFDevNumTypes; j++)
|
|
|
|
|
if (!strcmp(EFDevTypes[j], line[i]))
|
|
|
|
|
break;
|
|
|
|
|
|
2023-02-16 17:59:13 +01:00
|
|
|
/* Read attributes, especially to pick up values for L, W, X, and Y;
|
|
|
|
|
* and source and drain area and perimeter, that are critical for use
|
|
|
|
|
* by extresist.
|
2021-04-21 02:45:49 +02:00
|
|
|
*/
|
|
|
|
|
for (k = 1; line[k][0] != '\0'; k++)
|
|
|
|
|
{
|
|
|
|
|
char *eqptr;
|
|
|
|
|
eqptr = strchr(line[k], '=');
|
|
|
|
|
if (eqptr != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (k < i) i = k;
|
|
|
|
|
eqptr++;
|
|
|
|
|
switch (line[k][0]) {
|
|
|
|
|
case 'l':
|
|
|
|
|
lptr = eqptr;
|
|
|
|
|
break;
|
|
|
|
|
case 'w':
|
|
|
|
|
wptr = eqptr;
|
|
|
|
|
break;
|
|
|
|
|
case 'x':
|
|
|
|
|
device->location.p_x = (int)((float)atof(eqptr) / lambda);
|
|
|
|
|
break;
|
|
|
|
|
case 'y':
|
|
|
|
|
device->location.p_y = (int)((float)atof(eqptr) / lambda);
|
|
|
|
|
break;
|
2023-02-16 17:59:13 +01:00
|
|
|
case 's':
|
|
|
|
|
device->rs_sattr = StrDup((char **)NULL, eqptr);
|
|
|
|
|
break;
|
|
|
|
|
case 'd':
|
|
|
|
|
device->rs_dattr = StrDup((char **)NULL, eqptr);
|
|
|
|
|
break;
|
2021-04-21 02:45:49 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-07 03:44:52 +02:00
|
|
|
if (j == EFDevNumTypes)
|
2021-04-21 02:45:49 +02:00
|
|
|
{
|
2021-06-07 03:44:52 +02:00
|
|
|
TxError("Failure to find device type %s\n", line[i]);
|
|
|
|
|
return 1;
|
2021-04-21 02:45:49 +02:00
|
|
|
}
|
2021-06-07 03:44:52 +02:00
|
|
|
ttype = extGetDevType(EFDevTypes[j]);
|
2025-02-13 09:22:28 +01:00
|
|
|
ASSERT(ttype >= 0, "ttype<0");
|
2021-04-21 02:45:49 +02:00
|
|
|
|
2021-06-07 03:44:52 +02:00
|
|
|
/* Find the device record that corresponds to the device name */
|
|
|
|
|
for (devptr = ExtCurStyle->exts_device[ttype]; devptr; devptr = devptr->exts_next)
|
|
|
|
|
if (!strcmp(devptr->exts_deviceName, EFDevTypes[j]))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
device->rs_devptr = devptr;
|
2021-04-21 02:45:49 +02:00
|
|
|
device->rs_ttype = ttype;
|
|
|
|
|
|
|
|
|
|
if (lptr != NULL && wptr != NULL)
|
|
|
|
|
{
|
A number of changes:
1) Corrected spurious error messages about cells already existing
in GDS when using "flatten" or "flatglob".
2) Fixed handling of resistance as a subcircuit parameter
3) Added area and perimeter resistance for a device; this is done
through the "devresist" statement in the tech file, which is an
extension of the original "fetresist" statement. Where "fetresist"
only supported type "linear", "devresist" supports types "area"
and "perimeter".
4) Support for CDL syntax, including generating subcircuit-like
parameters for components starting with SPICE-standard prefixes
like M, R, C, etc., adding "/" between pins and subcircuit name,
and saving the file as ".cdl" instead of ".spice".
5) Estimated L and W for devices whose geometry is complex and do not
reduce to a simple rectangle. L and W are estimated as the square
root of the area.
6) Changed the method of extracting L and W for diodes to use the same
method as capacitors. Note that diodes are not usually specified
by L and W, but if they are, this will produce the right result.
7) Corrected the reported filename and line number when printing error
messages related to errors inside a technology file, when the
technology file uses "include" to combine multiple files.
2025-10-01 21:17:49 +02:00
|
|
|
HashEntry *he;
|
2021-04-21 02:45:49 +02:00
|
|
|
float rpersquare;
|
|
|
|
|
|
A number of changes:
1) Corrected spurious error messages about cells already existing
in GDS when using "flatten" or "flatglob".
2) Fixed handling of resistance as a subcircuit parameter
3) Added area and perimeter resistance for a device; this is done
through the "devresist" statement in the tech file, which is an
extension of the original "fetresist" statement. Where "fetresist"
only supported type "linear", "devresist" supports types "area"
and "perimeter".
4) Support for CDL syntax, including generating subcircuit-like
parameters for components starting with SPICE-standard prefixes
like M, R, C, etc., adding "/" between pins and subcircuit name,
and saving the file as ".cdl" instead of ".spice".
5) Estimated L and W for devices whose geometry is complex and do not
reduce to a simple rectangle. L and W are estimated as the square
root of the area.
6) Changed the method of extracting L and W for diodes to use the same
method as capacitors. Note that diodes are not usually specified
by L and W, but if they are, this will produce the right result.
7) Corrected the reported filename and line number when printing error
messages related to errors inside a technology file, when the
technology file uses "include" to combine multiple files.
2025-10-01 21:17:49 +02:00
|
|
|
he = HashLookOnly(&devptr->exts_deviceResist, "linear");
|
|
|
|
|
if (he != NULL)
|
|
|
|
|
rpersquare = (ResValue)(spointertype)HashGetValue(he);
|
|
|
|
|
else
|
|
|
|
|
rpersquare = (ResValue)0.0;
|
2021-05-21 22:33:20 +02:00
|
|
|
/* Subcircuit types may not have a length or width value, in which */
|
|
|
|
|
/* case it is zero. Don't induce a divide-by-zero error. */
|
|
|
|
|
if (MagAtof(wptr) == 0)
|
|
|
|
|
device->resistance = 0;
|
|
|
|
|
else
|
|
|
|
|
device->resistance = MagAtof(lptr) * rpersquare/MagAtof(wptr);
|
2021-04-21 02:45:49 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
device->resistance = 0;
|
|
|
|
|
|
|
|
|
|
rvalue = 0;
|
|
|
|
|
for (k = 1; k < i; k++)
|
|
|
|
|
{
|
|
|
|
|
if (k > SUBS)
|
|
|
|
|
{
|
|
|
|
|
TxError("Device %s has more than 4 ports (not handled).\n", line[i]);
|
|
|
|
|
break; /* No method to handle more ports than this */
|
|
|
|
|
}
|
2026-01-27 17:56:47 +01:00
|
|
|
rvalue += ResExtNewNode(line[k], k, device);
|
2021-04-21 02:45:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rvalue;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* ResReadDevice-- Processes a device line from a ext file.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* Results: returns 0 if line was added correctly.
|
|
|
|
|
*
|
2019-10-17 22:21:56 +02:00
|
|
|
* Side Effects: Allocates devices and adds nodes to the node hash table.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
2026-01-27 17:56:47 +01:00
|
|
|
ResReadDevice(line, rpersquare, devptr)
|
2021-05-26 04:41:52 +02:00
|
|
|
char line[][MAXTOKEN];
|
|
|
|
|
float rpersquare;
|
2021-06-07 03:44:52 +02:00
|
|
|
ExtDevice *devptr;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
{
|
2021-05-26 04:41:52 +02:00
|
|
|
RDev *device;
|
|
|
|
|
int rvalue, i, j, k;
|
|
|
|
|
char *newattr, tmpattr[MAXTOKEN];
|
|
|
|
|
static int nowarning = TRUE;
|
|
|
|
|
float lambda;
|
2023-02-13 19:41:58 +01:00
|
|
|
ExtDevice *devtest;
|
2021-05-26 04:41:52 +02:00
|
|
|
|
|
|
|
|
if ((line[RDEV_WIDTH][0] == '\0') || (line[RDEV_LENGTH][0] == '\0'))
|
|
|
|
|
{
|
2017-04-25 14:41:48 +02:00
|
|
|
TxError("error in input file:\n");
|
2021-05-26 04:41:52 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
device = (RDev *)mallocMagic((unsigned)(sizeof(RDev)));
|
|
|
|
|
if (nowarning && rpersquare == 0)
|
|
|
|
|
{
|
|
|
|
|
TxError("Warning: FET resistance not included or "
|
|
|
|
|
"set to zero in technology file-\n");
|
|
|
|
|
TxError("All driven nodes will be extracted\n");
|
|
|
|
|
nowarning = FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (MagAtof(line[RDEV_WIDTH]) != 0)
|
|
|
|
|
device->resistance = MagAtof(line[RDEV_LENGTH]) * rpersquare /
|
|
|
|
|
MagAtof(line[RDEV_WIDTH]);
|
|
|
|
|
else
|
|
|
|
|
device->resistance = 0;
|
|
|
|
|
|
|
|
|
|
device->status = FALSE;
|
|
|
|
|
device->nextDev = ResRDevList;
|
|
|
|
|
|
2023-02-13 19:41:58 +01:00
|
|
|
/* Check that devptr matches the device name and number of terminals */
|
|
|
|
|
/* Note that this routine is only called for the original "fet" */
|
|
|
|
|
/* types with fixed names, so the names must match and there must */
|
|
|
|
|
/* always be three terminals (two source/drain terminals). */
|
|
|
|
|
|
|
|
|
|
if (devptr->exts_deviceSDCount != 2)
|
|
|
|
|
for (devtest = devptr->exts_next; devtest; devtest = devtest->exts_next)
|
|
|
|
|
if (devtest->exts_deviceSDCount == 2)
|
|
|
|
|
{
|
|
|
|
|
devptr = devtest;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 04:41:52 +02:00
|
|
|
lambda = (float)ExtCurStyle->exts_unitsPerLambda / resscale;
|
|
|
|
|
device->location.p_x = (int)((float)atof(line[RDEV_DEVX]) / lambda);
|
|
|
|
|
device->location.p_y = (int)((float)atof(line[RDEV_DEVY]) / lambda);
|
|
|
|
|
|
|
|
|
|
device->rs_gattr=RDEV_NOATTR;
|
|
|
|
|
device->rs_sattr=RDEV_NOATTR;
|
|
|
|
|
device->rs_dattr=RDEV_NOATTR;
|
2021-06-07 03:44:52 +02:00
|
|
|
device->rs_devptr = devptr;
|
2021-05-26 04:41:52 +02:00
|
|
|
|
|
|
|
|
device->gate = device->source = device->drain = device->subs = NULL;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2021-09-08 22:41:36 +02:00
|
|
|
device->rs_ttype = extGetDevType(devptr->exts_deviceName);
|
|
|
|
|
|
2026-01-27 17:56:47 +01:00
|
|
|
/* ext attributes look like g=a1,a2 */
|
2021-05-26 04:41:52 +02:00
|
|
|
/* ext attributes are "a1","a2" */
|
2023-02-16 17:59:13 +01:00
|
|
|
/* Do conversion from one to the other here */
|
|
|
|
|
/* NOTE: As of version 8.3.366, .ext attributes will end in two */
|
|
|
|
|
/* integer values, not quoted, for device area and perimeter. Do */
|
|
|
|
|
/* not quote them. */
|
2021-05-26 04:41:52 +02:00
|
|
|
|
|
|
|
|
for (i = RDEV_ATTR; i < RDEV_ATTR + RDEV_NUM_ATTR; i++)
|
|
|
|
|
{
|
2023-02-16 17:59:13 +01:00
|
|
|
char *cptr, *sptr;
|
|
|
|
|
int d1, d2;
|
|
|
|
|
|
2021-05-26 04:41:52 +02:00
|
|
|
if (line[i][0] == '\0') break;
|
2023-02-16 17:59:13 +01:00
|
|
|
|
|
|
|
|
sptr = &line[i][2]; /* Start after "s=" or "d=" */
|
|
|
|
|
tmpattr[0] = '\0';
|
|
|
|
|
while ((cptr = strchr(sptr, ',')) != NULL)
|
2021-05-26 04:41:52 +02:00
|
|
|
{
|
2023-02-16 17:59:13 +01:00
|
|
|
if (sscanf(sptr, "%d,%d", &d1, &d2) == 2)
|
2021-05-26 04:41:52 +02:00
|
|
|
{
|
2023-02-16 17:59:13 +01:00
|
|
|
strcat(tmpattr, sptr);
|
|
|
|
|
sptr = NULL;
|
|
|
|
|
break;
|
2021-05-26 04:41:52 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-02-16 17:59:13 +01:00
|
|
|
*cptr = '\0';
|
|
|
|
|
strcat(tmpattr, "\"");
|
|
|
|
|
strcat(tmpattr, sptr);
|
|
|
|
|
strcat(tmpattr, "\",");
|
|
|
|
|
sptr = cptr + 1;
|
|
|
|
|
*cptr = ',';
|
2021-05-26 04:41:52 +02:00
|
|
|
}
|
|
|
|
|
}
|
2023-02-16 17:59:13 +01:00
|
|
|
if (sptr && (strlen(sptr) != 0))
|
|
|
|
|
{
|
|
|
|
|
strcat(tmpattr, "\"");
|
|
|
|
|
strcat(tmpattr, sptr);
|
|
|
|
|
strcat(tmpattr, "\"");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newattr = (char *)mallocMagic(strlen(tmpattr) + 1);
|
|
|
|
|
strcpy(newattr, tmpattr);
|
2021-05-26 04:41:52 +02:00
|
|
|
switch (line[i][0])
|
|
|
|
|
{
|
|
|
|
|
case 'g':
|
|
|
|
|
device->rs_gattr = newattr;
|
|
|
|
|
break;
|
|
|
|
|
case 's':
|
|
|
|
|
device->rs_sattr = newattr;
|
|
|
|
|
break;
|
|
|
|
|
case 'd':
|
|
|
|
|
device->rs_dattr = newattr;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
TxError("Bad fet attribute\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ResRDevList = device;
|
|
|
|
|
device->layout = NULL;
|
2026-01-27 17:56:47 +01:00
|
|
|
rvalue = ResExtNewNode(line[GATE], GATE, device) +
|
|
|
|
|
ResExtNewNode(line[SOURCE], SOURCE, device) +
|
|
|
|
|
ResExtNewNode(line[DRAIN], DRAIN, device);
|
2021-05-26 04:41:52 +02:00
|
|
|
|
|
|
|
|
return rvalue;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* ResExtNewNode-- Adds a new node to the Node Hash Table.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* Results: returns zero if node is added correctly, one otherwise.
|
|
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* Side Effects: Allocates a new ResExtNode
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
2026-01-27 17:56:47 +01:00
|
|
|
ResExtNewNode(line, type, device)
|
2021-05-26 04:41:52 +02:00
|
|
|
char line[];
|
|
|
|
|
int type;
|
|
|
|
|
RDev *device;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
{
|
2021-05-26 04:41:52 +02:00
|
|
|
HashEntry *entry;
|
2026-01-27 17:56:47 +01:00
|
|
|
ResExtNode *node;
|
2021-05-26 04:41:52 +02:00
|
|
|
devPtr *tptr;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2021-05-26 04:41:52 +02:00
|
|
|
if (line[0] == '\0')
|
|
|
|
|
{
|
|
|
|
|
TxError("Missing device connection\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
entry = HashFind(&ResNodeTable, line);
|
|
|
|
|
node = ResInitializeNode(entry);
|
|
|
|
|
tptr = (devPtr *)mallocMagic((unsigned)(sizeof(devPtr)));
|
|
|
|
|
tptr->thisDev = device;
|
|
|
|
|
tptr->nextDev = node->firstDev;
|
|
|
|
|
node->firstDev = tptr;
|
|
|
|
|
tptr->terminal = type;
|
|
|
|
|
switch(type)
|
|
|
|
|
{
|
|
|
|
|
case GATE:
|
|
|
|
|
device->gate = node;
|
|
|
|
|
break;
|
|
|
|
|
case SOURCE:
|
|
|
|
|
device->source = node;
|
|
|
|
|
break;
|
|
|
|
|
case DRAIN:
|
|
|
|
|
device->drain = node;
|
|
|
|
|
break;
|
|
|
|
|
case SUBS:
|
|
|
|
|
device->subs = node;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
TxError("Bad Terminal Specifier\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* ResReadCapacitor-- Adds the capacitance from a C line to the appropriate
|
2020-05-23 23:13:14 +02:00
|
|
|
* node. Coupling capacitors are added twice, moving the capacitance
|
2017-04-25 14:41:48 +02:00
|
|
|
* to the substrate.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always return 0
|
|
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* Side Effects: modifies capacitance field of ResExtNode.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
2026-01-27 17:56:47 +01:00
|
|
|
ResReadCapacitor(line)
|
2021-05-26 04:41:52 +02:00
|
|
|
char line[][MAXTOKEN];
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
{
|
2021-05-26 04:41:52 +02:00
|
|
|
HashEntry *entry1, *entry2;
|
2026-01-27 17:56:47 +01:00
|
|
|
ResExtNode *node1, *node2;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2021-05-26 04:41:52 +02:00
|
|
|
if (line[COUPLETERMINAL1][0] == 0 || line[COUPLETERMINAL2][0] == 0)
|
|
|
|
|
{
|
|
|
|
|
TxError("Bad Capacitor\n");
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
entry1 = HashFind(&ResNodeTable, line[COUPLETERMINAL1]);
|
|
|
|
|
node1 = ResInitializeNode(entry1);
|
|
|
|
|
if (ResOptionsFlags & ResOpt_Signal)
|
|
|
|
|
{
|
|
|
|
|
node1->capacitance += MagAtof(line[COUPLEVALUE]);
|
|
|
|
|
if (strcmp(line[COUPLETERMINAL2], "GND") == 0 ||
|
|
|
|
|
strcmp(line[COUPLETERMINAL2], "Vdd") == 0)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
entry2 = HashFind(&ResNodeTable, line[COUPLETERMINAL2]);
|
|
|
|
|
node2 = ResInitializeNode(entry2);
|
|
|
|
|
node2->capacitance += MagAtof(line[COUPLEVALUE]);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(line[COUPLETERMINAL2], "GND") == 0)
|
|
|
|
|
{
|
|
|
|
|
node1->capacitance += MagAtof(line[COUPLEVALUE]);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(line[COUPLETERMINAL2], "Vdd") == 0)
|
|
|
|
|
{
|
|
|
|
|
node1->cap_vdd += MagAtof(line[COUPLEVALUE]);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
entry2 = HashFind(&ResNodeTable, line[COUPLETERMINAL2]);
|
|
|
|
|
node2 = ResInitializeNode(entry2);
|
|
|
|
|
if (strcmp(line[COUPLETERMINAL1], "GND") == 0)
|
|
|
|
|
{
|
|
|
|
|
node2->capacitance += MagAtof(line[COUPLEVALUE]);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(line[COUPLETERMINAL1], "Vdd") == 0)
|
|
|
|
|
{
|
|
|
|
|
node2->cap_vdd += MagAtof(line[COUPLEVALUE]);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
node1->cap_couple += MagAtof(line[COUPLEVALUE]);
|
|
|
|
|
node2->cap_couple += MagAtof(line[COUPLEVALUE]);
|
|
|
|
|
return 0;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* ResReadResistor-- Adds the capacitance from a R line to the appropriate
|
2020-05-23 23:13:14 +02:00
|
|
|
* node.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* Results
|
|
|
|
|
* Return 0 to keep search going, 1 to abort
|
|
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* Side Effects: modifies resistance field of ResExtNode
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
2026-01-27 17:56:47 +01:00
|
|
|
ResReadResistor(line)
|
2021-05-26 04:41:52 +02:00
|
|
|
char line[][MAXTOKEN];
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2021-05-26 04:41:52 +02:00
|
|
|
HashEntry *entry;
|
2026-01-27 17:56:47 +01:00
|
|
|
ResExtNode *node;
|
2021-05-26 04:41:52 +02:00
|
|
|
|
|
|
|
|
if (line[RESNODENAME][0] == 0)
|
|
|
|
|
{
|
|
|
|
|
TxError("Bad Resistor\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
entry = HashFind(&ResNodeTable, line[RESNODENAME]);
|
|
|
|
|
node = ResInitializeNode(entry);
|
|
|
|
|
if (node->resistance != 0)
|
|
|
|
|
{
|
2017-04-25 14:41:48 +02:00
|
|
|
TxError("Duplicate Resistance Entries\n");
|
2021-05-26 04:41:52 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
node->resistance = MagAtof(line[NODERESISTANCE]);
|
|
|
|
|
return(0);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* ResExtAttribute--checks to see if a node attribute is a resistance
|
2017-04-25 14:41:48 +02:00
|
|
|
* 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
|
|
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* Side Effects: modifies resistance field of ResExtNode
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
2026-01-27 17:56:47 +01:00
|
|
|
ResReadAttribute(aname, avalue, readdrivepoints)
|
|
|
|
|
char *aname;
|
|
|
|
|
char *avalue;
|
|
|
|
|
bool *readdrivepoints;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
{
|
2021-05-26 04:41:52 +02:00
|
|
|
HashEntry *entry;
|
2026-01-27 17:56:47 +01:00
|
|
|
ResExtNode *node;
|
2021-05-26 04:41:52 +02:00
|
|
|
char digit[MAXDIGIT];
|
|
|
|
|
int i;
|
2026-01-27 17:56:47 +01:00
|
|
|
static int notwarned = TRUE;
|
2021-05-26 04:41:52 +02:00
|
|
|
|
|
|
|
|
if (aname[0] == 0)
|
|
|
|
|
{
|
|
|
|
|
TxError("Bad Resistor\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
entry = HashFind(&ResNodeTable, aname);
|
|
|
|
|
node = ResInitializeNode(entry);
|
|
|
|
|
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;
|
2026-01-27 17:56:47 +01:00
|
|
|
for (i = 0, avalue += 8; *avalue != '\0'; avalue++)
|
2021-05-26 04:41:52 +02:00
|
|
|
{
|
|
|
|
|
digit[i++] = *avalue;
|
|
|
|
|
}
|
|
|
|
|
digit[i++] = '\0';
|
|
|
|
|
node->minsizeres = MagAtof(digit);
|
|
|
|
|
}
|
|
|
|
|
else if (strncmp(avalue, "res:drive", 9) == 0 &&
|
2017-04-25 14:41:48 +02:00
|
|
|
(ResOptionsFlags & ResOpt_Signal))
|
2021-05-26 04:41:52 +02:00
|
|
|
{
|
2026-01-27 17:56:47 +01:00
|
|
|
if (*readdrivepoints == FALSE)
|
2021-05-26 04:41:52 +02:00
|
|
|
{
|
2026-01-27 17:56:47 +01:00
|
|
|
ResExtProcessDrivePoints(rootname);
|
|
|
|
|
*readddrivepoints = TRUE;
|
2021-05-26 04:41:52 +02:00
|
|
|
}
|
|
|
|
|
/* is the attribute in root.ext? */
|
|
|
|
|
if (node->drivepoint.p_x != INFINITY)
|
|
|
|
|
node->status |= DRIVELOC;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (notwarned)
|
|
|
|
|
TxError("Drivepoint for %s not defined in %s.ext; is it "
|
|
|
|
|
"defined in a child cell?\n", node->name, rootname);
|
|
|
|
|
notwarned = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* ResExtProcessDrivePoints -- if the ext file contains a res:drive attribute,
|
2017-04-25 14:41:48 +02:00
|
|
|
* and we are doing a signal extraction,
|
|
|
|
|
* we need to search through the .ext file looking for attr labels that
|
|
|
|
|
* contain this text. For efficiency, the .ext file is only parsed when
|
2020-05-23 23:13:14 +02:00
|
|
|
* the first res:drive is encountered. res:drive labels only work if
|
2017-04-25 14:41:48 +02:00
|
|
|
* they are in the root cell.
|
|
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* FIXME---The .ext file is being read and this routine should only
|
|
|
|
|
* read in additional lines as necessary.
|
|
|
|
|
*
|
2017-04-25 14:41:48 +02:00
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side Effects:
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
2026-01-27 17:56:47 +01:00
|
|
|
ResExtProcessDrivePoints(FILE *fp)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2021-05-26 04:41:52 +02:00
|
|
|
char line[MAXLINE][MAXTOKEN];
|
|
|
|
|
FILE *fp;
|
|
|
|
|
HashEntry *entry;
|
2026-01-27 17:56:47 +01:00
|
|
|
ResExtNode *node;
|
2021-05-26 04:41:52 +02:00
|
|
|
|
2026-01-27 17:56:47 +01:00
|
|
|
while (gettokens(line, fp) != 0)
|
2021-05-26 04:41:52 +02:00
|
|
|
{
|
|
|
|
|
if (strncmp(line[RES_EXT_ATTR], "attr", 4) != 0 ||
|
|
|
|
|
strncmp(line[RES_EXT_ATTR_TEXT], "\"res:drive\"", 11) != 0)
|
|
|
|
|
continue;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2021-05-26 04:41:52 +02:00
|
|
|
entry = HashFind(&ResNodeTable, line[RES_EXT_ATTR_NAME]);
|
|
|
|
|
node = ResInitializeNode(entry);
|
|
|
|
|
node->drivepoint.p_x = atoi(line[RES_EXT_ATTR_X]);
|
|
|
|
|
node->drivepoint.p_y = atoi(line[RES_EXT_ATTR_Y]);
|
|
|
|
|
node->rs_ttype = DBTechNoisyNameType(line[RES_EXT_ATTR_TILE]);
|
|
|
|
|
}
|
2025-02-13 09:22:28 +01:00
|
|
|
fclose(fp);
|
2021-05-26 04:41:52 +02:00
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* ResExtProcessFixPoints -- if the ext file contains a "res:fix:name" label
|
2020-05-23 23:13:14 +02:00
|
|
|
* and we are checking for power supply noise, then we have to
|
2017-04-25 14:41:48 +02:00
|
|
|
* parse the .ext file looking for the fix label locations. This
|
|
|
|
|
* is only done after the first res:fix label is encountered.
|
|
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* (FIXME---This is now all in the .ext file so the information does
|
|
|
|
|
* not need to be read twice.)
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side Effects:
|
|
|
|
|
* For each new name, allocate memory
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
2026-01-27 17:56:47 +01:00
|
|
|
ResExtProcessFixPoints(filename)
|
2021-05-26 04:41:52 +02:00
|
|
|
char *filename;
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2021-05-26 04:41:52 +02:00
|
|
|
char line[MAXLINE][MAXTOKEN], *label, *c;
|
|
|
|
|
FILE *fp;
|
|
|
|
|
ResFixPoint *thisfix;
|
|
|
|
|
|
2023-08-07 21:37:04 +02:00
|
|
|
fp = PaOpen(filename, "r", ".ext", (ExtLocalPath == NULL) ? "." : ExtLocalPath,
|
|
|
|
|
(char *)NULL, (char **)NULL);
|
2021-05-26 04:41:52 +02:00
|
|
|
if (fp == NULL)
|
|
|
|
|
{
|
|
|
|
|
TxError("Cannot open file %s%s\n", filename, ".ext");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
while (gettokens(line, fp) != 0)
|
|
|
|
|
{
|
|
|
|
|
if (strncmp(line[RES_EXT_ATTR], "attr", 4) != 0 ||
|
|
|
|
|
strncmp(line[RES_EXT_ATTR_TEXT], "\"res:fix", 8) != 0)
|
|
|
|
|
continue;
|
|
|
|
|
label = line[RES_EXT_ATTR_TEXT];
|
|
|
|
|
label += 8;
|
|
|
|
|
if (*label == ':') label++;
|
|
|
|
|
if ((c=strrchr(label, '"')) != NULL) *c = '\0';
|
|
|
|
|
else if (*label != '\0')
|
|
|
|
|
{
|
|
|
|
|
TxError("Bad res:fix attribute label %s\n",
|
2017-04-25 14:41:48 +02:00
|
|
|
line[RES_EXT_ATTR_TEXT]);
|
2021-05-26 04:41:52 +02:00
|
|
|
*label ='\0';
|
|
|
|
|
}
|
|
|
|
|
thisfix = (ResFixPoint *)mallocMagic((unsigned)(sizeof(ResFixPoint)
|
|
|
|
|
+ strlen(label)));
|
|
|
|
|
thisfix->fp_next = ResFixList;
|
|
|
|
|
ResFixList = thisfix;
|
|
|
|
|
thisfix->fp_loc.p_x = atoi(line[RES_EXT_ATTR_X]);
|
|
|
|
|
thisfix->fp_loc.p_y = atoi(line[RES_EXT_ATTR_Y]);
|
|
|
|
|
thisfix->fp_ttype = DBTechNoisyNameType(line[RES_EXT_ATTR_TILE]);
|
|
|
|
|
thisfix->fp_tile = NULL;
|
|
|
|
|
strcpy(thisfix->fp_name, label);
|
|
|
|
|
}
|
2025-02-13 09:22:28 +01:00
|
|
|
fclose(fp);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2021-05-26 04:41:52 +02:00
|
|
|
/*
|
2017-04-25 14:41:48 +02:00
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* ResInitializeNode --
|
|
|
|
|
* Gets the node corresponding to a given hash table entry. If no
|
|
|
|
|
* such node exists, one is created.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* Results: Returns ResExtNode corresponding to entry.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
2026-01-27 17:56:47 +01:00
|
|
|
* Side Effects: May allocate a new ResExtNode.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
2026-01-27 17:56:47 +01:00
|
|
|
ResExtNode *
|
2017-04-25 14:41:48 +02:00
|
|
|
ResInitializeNode(entry)
|
2021-05-26 04:41:52 +02:00
|
|
|
HashEntry *entry;
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2026-01-27 17:56:47 +01:00
|
|
|
ResExtNode *node;
|
2021-05-26 04:41:52 +02:00
|
|
|
|
2026-01-27 17:56:47 +01:00
|
|
|
if ((node = (ResExtNode *) HashGetValue(entry)) == NULL)
|
2021-05-26 04:41:52 +02:00
|
|
|
{
|
2026-01-27 17:56:47 +01:00
|
|
|
node = (ResExtNode *)mallocMagic((unsigned)(sizeof(ResExtNode)));
|
2021-05-26 04:41:52 +02:00
|
|
|
HashSetValue(entry, (char *) node);
|
|
|
|
|
node->nextnode = ResOriginalNodes;
|
|
|
|
|
ResOriginalNodes = node;
|
|
|
|
|
node->status = FALSE;
|
2026-01-27 17:56:47 +01:00
|
|
|
node->forward = (ResExtNode *) NULL;
|
2021-05-26 04:41:52 +02:00
|
|
|
node->capacitance = 0;
|
|
|
|
|
node->cap_vdd = 0;
|
|
|
|
|
node->cap_couple = 0;
|
|
|
|
|
node->resistance = 0;
|
|
|
|
|
node->type = 0;
|
|
|
|
|
node->firstDev = NULL;
|
|
|
|
|
node->name = entry->h_key.h_name;
|
|
|
|
|
node->oldname = NULL;
|
|
|
|
|
node->drivepoint.p_x = INFINITY;
|
|
|
|
|
node->drivepoint.p_y = INFINITY;
|
|
|
|
|
node->location.p_x = INFINITY;
|
|
|
|
|
node->location.p_y = INFINITY;
|
|
|
|
|
node->rs_sublist[0] = NULL;
|
|
|
|
|
node->rs_sublist[1] = NULL;
|
|
|
|
|
}
|
|
|
|
|
while (node->status & FORWARD)
|
|
|
|
|
{
|
|
|
|
|
node = node->forward;
|
|
|
|
|
}
|
|
|
|
|
return node;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|