2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResReadSim.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* ResReadSim.c -- Routines to parse .sim files
|
|
|
|
|
|
*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#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"
|
|
|
|
|
|
#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 .sim files. */
|
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
|
|
|
|
|
|
#define NODECIFCOMMAND 0
|
|
|
|
|
|
#define NODENODENAME 1
|
|
|
|
|
|
#define NODENODEX 2
|
|
|
|
|
|
#define NODENODEY 3
|
|
|
|
|
|
#define NODETYPE 4
|
|
|
|
|
|
#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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define MAXTOKEN 256
|
|
|
|
|
|
#define MAXLINE 40
|
|
|
|
|
|
#define MAXDIGIT 20
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ResSimNode *ResInitializeNode();
|
|
|
|
|
|
|
|
|
|
|
|
ResSimNode *ResOriginalNodes; /*Linked List of Nodes */
|
2019-10-28 18:10:16 +01:00
|
|
|
|
static float resscale=1.0; /* Scale factor */
|
2019-10-17 22:21:56 +02:00
|
|
|
|
char RDEV_NOATTR[1]={'0'};
|
2017-04-25 14:41:48 +02:00
|
|
|
|
ResFixPoint *ResFixList;
|
|
|
|
|
|
|
|
|
|
|
|
#define nodeinit(n)\
|
|
|
|
|
|
{\
|
|
|
|
|
|
(n)->rn_more = ResNodeList;\
|
|
|
|
|
|
(n)->rn_less = NULL;\
|
|
|
|
|
|
if (ResNodeList)\
|
|
|
|
|
|
ResNodeList->rn_less = n;\
|
|
|
|
|
|
ResNodeList = n;\
|
|
|
|
|
|
(n)->rn_te = NULL;\
|
|
|
|
|
|
(n)->rn_re = NULL;\
|
|
|
|
|
|
(n)->rn_je=NULL;\
|
|
|
|
|
|
(n)->rn_ce=NULL;\
|
|
|
|
|
|
(n)->rn_noderes=RES_INFINITY;\
|
|
|
|
|
|
(n)->location.p_x=MINFINITY;\
|
|
|
|
|
|
(n)->location.p_y=MINFINITY;\
|
|
|
|
|
|
(n)->rn_why=0;\
|
|
|
|
|
|
(n)->rn_status = TRUE;\
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Forward declarations */
|
|
|
|
|
|
|
|
|
|
|
|
extern void ResSimProcessDrivePoints();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* ResReadSim--
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results: returns 0 if sim file is correct, 1 if not.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side Effects:Reads in SimTable and makes a hash table of nodes.
|
|
|
|
|
|
*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
ResReadSim(simfile,fetproc,capproc,resproc,attrproc,mergeproc)
|
|
|
|
|
|
char *simfile;
|
|
|
|
|
|
int (*fetproc)(),(*capproc)(),(*resproc)();
|
|
|
|
|
|
int (*attrproc)(),(*mergeproc)();
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
char line[MAXLINE][MAXTOKEN];
|
|
|
|
|
|
int result,fettype,extfile;
|
|
|
|
|
|
FILE *fp, *fopen();
|
|
|
|
|
|
|
|
|
|
|
|
fp = PaOpen(simfile,"r",".sim",".",(char *) NULL, (char **) NULL);
|
|
|
|
|
|
if (fp == NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
TxError("Cannot open file %s%s\n",simfile,".sim");
|
|
|
|
|
|
return(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
extfile = 0;
|
|
|
|
|
|
|
|
|
|
|
|
/*read in file */
|
|
|
|
|
|
while (gettokens(line,fp) != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
fettype = MINFINITY;
|
|
|
|
|
|
switch(line[0][0])
|
|
|
|
|
|
{
|
|
|
|
|
|
case '|':
|
|
|
|
|
|
if (strcmp(line[NODEUNITS],"units:") == 0)
|
|
|
|
|
|
{
|
2019-10-28 18:10:16 +01:00
|
|
|
|
resscale = (float)atof(line[NODELAMBDA]);
|
|
|
|
|
|
if (resscale == 0.0) resscale = 1.0;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
result=0;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'e': fettype = DBTechNameType("efet");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'd': fettype = DBTechNameType("dfet");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'n': fettype = DBTechNameType("nfet");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'p': fettype = DBTechNameType("pfet");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'b': fettype = DBTechNameType("bnpn");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'C': if (capproc) result = (*capproc)(line);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'R': if (resproc)result = (*resproc)(line);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case '=': if (mergeproc)result = (*mergeproc)(line);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'A': if (attrproc) result =
|
|
|
|
|
|
(*attrproc)(line[ATTRIBUTENODENAME],
|
|
|
|
|
|
line[ATTRIBUTEVALUE],
|
|
|
|
|
|
simfile, &extfile);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'D':
|
|
|
|
|
|
case 'c':
|
|
|
|
|
|
case 'r': break;
|
|
|
|
|
|
default: result = 1;
|
|
|
|
|
|
(void)fclose(fp);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (fettype == -1)
|
|
|
|
|
|
{
|
2019-10-17 22:21:56 +02:00
|
|
|
|
TxError("Error in Reading device line of sim file.\n");
|
2017-04-25 14:41:48 +02:00
|
|
|
|
result = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (fettype != MINFINITY)
|
|
|
|
|
|
{
|
|
|
|
|
|
float sheetr;
|
2019-08-19 20:11:02 +02:00
|
|
|
|
ExtDevice *devptr;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
2019-08-19 20:11:02 +02:00
|
|
|
|
devptr = ExtCurStyle->exts_device[fettype];
|
|
|
|
|
|
sheetr=(float)devptr->exts_linearResist;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
result = (*fetproc)(line,sheetr,fettype);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (result != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
TxError("Error in sim file %s\n",line[0]);
|
|
|
|
|
|
return(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
(void)fclose(fp);
|
|
|
|
|
|
return(result);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* ResReadNode-- Reads in a node file, puts location of nodes into node
|
|
|
|
|
|
* structures.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results: returns 0 if nodes file is correct, 1 if not.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side Effects:see above
|
|
|
|
|
|
*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
ResReadNode(nodefile)
|
|
|
|
|
|
char *nodefile;
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
char line[MAXLINE][MAXTOKEN];
|
|
|
|
|
|
FILE *fp, *fopen();
|
|
|
|
|
|
HashEntry *entry;
|
|
|
|
|
|
ResSimNode *node;
|
|
|
|
|
|
char *cp;
|
2019-10-28 18:10:16 +01:00
|
|
|
|
float lambda;
|
|
|
|
|
|
|
2019-12-08 23:37:48 +01:00
|
|
|
|
/* NOTE: Units from the .nodes file are in centimicrons.
|
|
|
|
|
|
* Divide by the extract scale (exts_unitsPerLambda) to get back
|
|
|
|
|
|
* to database units. This assumes that exts_unitsPerLambda doesn't
|
|
|
|
|
|
* change between output and readback.
|
2019-10-28 18:10:16 +01:00
|
|
|
|
*/
|
2019-12-08 23:37:48 +01:00
|
|
|
|
lambda = (float)ExtCurStyle->exts_unitsPerLambda;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
|
|
fp = PaOpen(nodefile,"r",".nodes",".", (char *) NULL, (char **) NULL);
|
|
|
|
|
|
if (fp == NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
TxError("Cannot open file %s%s\n",nodefile,".nodes");
|
|
|
|
|
|
return(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
while (gettokens(line,fp) != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
entry = HashFind(&ResNodeTable,line[NODENODENAME]);
|
|
|
|
|
|
node = ResInitializeNode(entry);
|
|
|
|
|
|
|
2019-10-28 18:10:16 +01:00
|
|
|
|
node->location.p_x = (int)((float)atof(line[NODENODEX]) / lambda);
|
|
|
|
|
|
node->location.p_y = (int)((float)atof(line[NODENODEY]) / lambda);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
#ifdef ARIEL
|
2019-10-28 18:10:16 +01:00
|
|
|
|
node->rs_bbox.r_xbot = (int)((float)atof(line[NODE_BBOX_LL_X]) / lambda);
|
|
|
|
|
|
node->rs_bbox.r_ybot = (int)((float)atof(line[NODE_BBOX_LL_Y]) / lambda);
|
|
|
|
|
|
node->rs_bbox.r_xtop = (int)((float)atof(line[NODE_BBOX_UR_X]) / lambda);
|
|
|
|
|
|
node->rs_bbox.r_ytop = (int)((float)atof(line[NODE_BBOX_UR_Y]) / lambda);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
#endif
|
|
|
|
|
|
if (cp = strchr(line[NODETYPE], ';')) *cp = '\0';
|
|
|
|
|
|
node->type = DBTechNameType(line[NODETYPE]);
|
|
|
|
|
|
|
|
|
|
|
|
if (node->type == -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
TxError("Bad tile type name in %s.nodes file for node %s\n",nodefile,node->name);
|
|
|
|
|
|
TxError("Did you use the newest version of ext2sim?\n");
|
|
|
|
|
|
(void)fclose(fp);
|
|
|
|
|
|
return(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
(void)fclose(fp);
|
|
|
|
|
|
return(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* getline-- Gets a line from the current input file and breaks it into
|
|
|
|
|
|
* tokens.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:returns the number of tokens in the current line
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side Effects: loads up its input line with the tokens.
|
|
|
|
|
|
*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
gettokens(line,fp)
|
|
|
|
|
|
char line[][MAXTOKEN];
|
|
|
|
|
|
FILE *fp;
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
int i=0,j=0;
|
|
|
|
|
|
int c;
|
|
|
|
|
|
|
|
|
|
|
|
while ((c = getc(fp)) != EOF && c != '\n')
|
|
|
|
|
|
{
|
|
|
|
|
|
switch(c)
|
|
|
|
|
|
{
|
|
|
|
|
|
case ' ':
|
|
|
|
|
|
case ' ' : line[i++][j] = '\0';
|
|
|
|
|
|
j=0;
|
|
|
|
|
|
break;
|
|
|
|
|
|
default: line[i][j++] = c;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (c == '\n')
|
|
|
|
|
|
{
|
|
|
|
|
|
line[i++][j] = '\0';
|
|
|
|
|
|
j=0;
|
|
|
|
|
|
}
|
|
|
|
|
|
for(j=i;j < MAXLINE;j++)
|
|
|
|
|
|
{
|
|
|
|
|
|
line[j][0] = '\0';
|
|
|
|
|
|
}
|
|
|
|
|
|
return(i);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*
|
2019-10-17 22:21:56 +02:00
|
|
|
|
* ResSimDevice-- Processes a device line from a sim 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
|
2019-10-17 22:21:56 +02:00
|
|
|
|
ResSimDevice(line,rpersquare,ttype)
|
2017-04-25 14:41:48 +02:00
|
|
|
|
char line[][MAXTOKEN];
|
|
|
|
|
|
float rpersquare;
|
|
|
|
|
|
TileType ttype;
|
|
|
|
|
|
|
|
|
|
|
|
{
|
2019-10-17 22:21:56 +02:00
|
|
|
|
RDev *device;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
int rvalue,i,j,k;
|
|
|
|
|
|
char *newattr,tmpattr[MAXTOKEN];
|
|
|
|
|
|
static int nowarning = TRUE;
|
2019-10-28 18:10:16 +01:00
|
|
|
|
float lambda;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
2019-10-17 22:21:56 +02:00
|
|
|
|
device = (RDev *) mallocMagic((unsigned) (sizeof(RDev)));
|
|
|
|
|
|
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");
|
|
|
|
|
|
return(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
2019-10-17 22:21:56 +02:00
|
|
|
|
device->resistance = MagAtof(line[RDEV_LENGTH]) * rpersquare/MagAtof(line[RDEV_WIDTH]);
|
|
|
|
|
|
}
|
|
|
|
|
|
device->status = FALSE;
|
|
|
|
|
|
device->nextDev = ResRDevList;
|
2019-10-28 18:10:16 +01:00
|
|
|
|
|
2019-12-08 23:37:48 +01:00
|
|
|
|
lambda = (float)ExtCurStyle->exts_unitsPerLambda / resscale;
|
2019-10-28 18:10:16 +01:00
|
|
|
|
device->location.p_x = (int)((float)atof(line[RDEV_DEVX]) / lambda);
|
|
|
|
|
|
device->location.p_y = (int)((float)atof(line[RDEV_DEVY]) / lambda);
|
|
|
|
|
|
|
2019-10-17 22:21:56 +02:00
|
|
|
|
device->rs_gattr=RDEV_NOATTR;
|
|
|
|
|
|
device->rs_sattr=RDEV_NOATTR;
|
|
|
|
|
|
device->rs_dattr=RDEV_NOATTR;
|
|
|
|
|
|
device->rs_ttype = ttype;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
|
|
/* sim attributes look like g=a1,a2 */
|
|
|
|
|
|
/* ext attributes are "a1","a2" */
|
|
|
|
|
|
/* do conversion from one to the other here */
|
|
|
|
|
|
|
2019-10-17 22:21:56 +02:00
|
|
|
|
for (i=RDEV_ATTR;i < RDEV_ATTR+RDEV_NUM_ATTR;i++)
|
2017-04-25 14:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
|
if (line[i][0] == '\0') break;
|
|
|
|
|
|
k=0;
|
|
|
|
|
|
tmpattr[k++]='"';
|
|
|
|
|
|
for (j=2;line[i][j] != '\0';j++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (line[i][j] == ',')
|
|
|
|
|
|
{
|
|
|
|
|
|
tmpattr[k++] = '"';
|
|
|
|
|
|
tmpattr[k++] = ',';
|
|
|
|
|
|
tmpattr[k++] = '"';
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
tmpattr[k++] = line[i][j];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
tmpattr[k++]='"';
|
|
|
|
|
|
tmpattr[k++]='\0';
|
|
|
|
|
|
newattr = (char *) mallocMagic((unsigned) k);
|
|
|
|
|
|
strncpy(newattr,tmpattr,k);
|
|
|
|
|
|
switch (line[i][0])
|
|
|
|
|
|
{
|
2019-10-17 22:21:56 +02:00
|
|
|
|
case 'g': device->rs_gattr = newattr; break;
|
|
|
|
|
|
case 's': device->rs_sattr = newattr; break;
|
|
|
|
|
|
case 'd': device->rs_dattr = newattr; break;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
default: TxError("Bad fet attribute\n");
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2019-10-17 22:21:56 +02:00
|
|
|
|
ResRDevList = device;
|
|
|
|
|
|
device->layout = NULL;
|
|
|
|
|
|
rvalue = ResSimNewNode(line[GATE],GATE,device) +
|
|
|
|
|
|
ResSimNewNode(line[SOURCE],SOURCE,device) +
|
|
|
|
|
|
ResSimNewNode(line[DRAIN],DRAIN,device);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
|
|
return(rvalue);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* ResSimNewNode-- Adds a new node to the Node Hash Table.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results: returns zero if node is added correctly, one otherwise.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side Effects: Allocates a new ResSimNode
|
|
|
|
|
|
*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-17 22:21:56 +02:00
|
|
|
|
ResSimNewNode(line,type,device)
|
2017-04-25 14:41:48 +02:00
|
|
|
|
char line[];
|
|
|
|
|
|
int type;
|
2019-10-17 22:21:56 +02:00
|
|
|
|
RDev *device;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
HashEntry *entry;
|
|
|
|
|
|
ResSimNode *node;
|
2019-10-17 22:21:56 +02:00
|
|
|
|
devPtr *tptr;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
|
|
if (line[0] == '\0')
|
|
|
|
|
|
{
|
2019-10-17 22:21:56 +02:00
|
|
|
|
TxError("Missing device connection\n");
|
2017-04-25 14:41:48 +02:00
|
|
|
|
return(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
entry = HashFind(&ResNodeTable,line);
|
|
|
|
|
|
node = ResInitializeNode(entry);
|
2019-10-17 22:21:56 +02:00
|
|
|
|
tptr = (devPtr *) mallocMagic((unsigned) (sizeof(devPtr)));
|
|
|
|
|
|
tptr->thisDev = device;
|
|
|
|
|
|
tptr->nextDev = node->firstDev;
|
|
|
|
|
|
node->firstDev = tptr;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
tptr->terminal = type;
|
|
|
|
|
|
switch(type)
|
|
|
|
|
|
{
|
2019-10-17 22:21:56 +02:00
|
|
|
|
case GATE: device->gate = node;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
break;
|
2019-10-17 22:21:56 +02:00
|
|
|
|
case SOURCE: device->source = node;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
break;
|
2019-10-17 22:21:56 +02:00
|
|
|
|
case DRAIN: device->drain = node;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
break;
|
|
|
|
|
|
default: TxError("Bad Terminal Specifier\n");
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
return(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* ResSimCapacitor-- 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 ResSimNode.
|
|
|
|
|
|
*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
ResSimCapacitor(line)
|
|
|
|
|
|
char line[][MAXTOKEN];
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
HashEntry *entry1,*entry2;
|
|
|
|
|
|
ResSimNode *node1,*node2;
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* ResSimResistor-- Adds the capacitance from a R line to the appropriate
|
|
|
|
|
|
* node.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results
|
|
|
|
|
|
* Return 0 to keep search going, 1 to abort
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side Effects: modifies resistance field of ResSimNode
|
|
|
|
|
|
*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
ResSimResistor(line)
|
|
|
|
|
|
char line[][MAXTOKEN];
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
HashEntry *entry;
|
|
|
|
|
|
ResSimNode *node;
|
|
|
|
|
|
|
|
|
|
|
|
if (line[RESNODENAME][0] == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
TxError("Bad Resistor\n");
|
|
|
|
|
|
return(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
entry = HashFind(&ResNodeTable,line[RESNODENAME]);
|
|
|
|
|
|
node = ResInitializeNode(entry);
|
|
|
|
|
|
if (node->resistance != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
TxError("Duplicate Resistance Entries\n");
|
|
|
|
|
|
return(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
node->resistance = MagAtof(line[NODERESISTANCE]);
|
|
|
|
|
|
return(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* ResSimAttribute--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 ResSimNode
|
|
|
|
|
|
*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
ResSimAttribute(aname,avalue,rootname,readextfile)
|
|
|
|
|
|
char *aname,*avalue,*rootname;
|
|
|
|
|
|
int *readextfile;
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
HashEntry *entry;
|
|
|
|
|
|
ResSimNode *node;
|
|
|
|
|
|
char digit[MAXDIGIT];
|
|
|
|
|
|
int i;
|
|
|
|
|
|
static int notwarned=TRUE;
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
for(i=0,avalue += 8; *avalue != '\0' && *avalue != ','; avalue++)
|
|
|
|
|
|
{
|
|
|
|
|
|
digit[i++] = *avalue;
|
|
|
|
|
|
}
|
|
|
|
|
|
digit[i++]='\0';
|
|
|
|
|
|
node->minsizeres=MagAtof(digit);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (strncmp(avalue,"res:drive",9) == 0 &&
|
|
|
|
|
|
(ResOptionsFlags & ResOpt_Signal))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (*readextfile == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
ResSimProcessDrivePoints(rootname);
|
|
|
|
|
|
*readextfile = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#ifdef ARIEL
|
|
|
|
|
|
else if (strncmp(avalue,"res:fix",7) == 0 &&
|
|
|
|
|
|
(ResOptionsFlags & ResOpt_Power))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (*readextfile == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
ResSimProcessFixPoints(rootname);
|
|
|
|
|
|
*readextfile = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
if (avalue = strchr(avalue,','))
|
|
|
|
|
|
{
|
|
|
|
|
|
(void) ResSimAttribute(aname,avalue+1,rootname,readextfile);
|
|
|
|
|
|
}
|
|
|
|
|
|
return(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* ResSimProcessDrivePoints -- if the sim file contains a res:drive attribute,
|
|
|
|
|
|
* 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
|
|
|
|
|
|
* the first res:drive is encountered. res:drive labels only work if
|
|
|
|
|
|
* they are in the root cell.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* None.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side Effects:
|
|
|
|
|
|
*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
ResSimProcessDrivePoints(filename)
|
|
|
|
|
|
char *filename;
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
char line[MAXLINE][MAXTOKEN];
|
|
|
|
|
|
FILE *fp;
|
|
|
|
|
|
HashEntry *entry;
|
|
|
|
|
|
ResSimNode *node;
|
|
|
|
|
|
|
|
|
|
|
|
fp = PaOpen(filename,"r",".ext",".",(char *) NULL,(char **) NULL);
|
|
|
|
|
|
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:drive\"",11) != 0) continue;
|
|
|
|
|
|
|
|
|
|
|
|
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]);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* ResSimProcessFixPoints -- if the sim file contains a "res:fix:name" label
|
|
|
|
|
|
* and we are checking for power supply noise, then we have to
|
|
|
|
|
|
* parse the .ext file looking for the fix label locations. This
|
|
|
|
|
|
* is only done after the first res:fix label is encountered.
|
|
|
|
|
|
*
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* None.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side Effects:
|
|
|
|
|
|
* For each new name, allocate memory
|
|
|
|
|
|
*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
ResSimProcessFixPoints(filename)
|
|
|
|
|
|
char *filename;
|
|
|
|
|
|
{
|
|
|
|
|
|
char line[MAXLINE][MAXTOKEN],*label,*c;
|
|
|
|
|
|
FILE *fp;
|
|
|
|
|
|
ResFixPoint *thisfix;
|
|
|
|
|
|
|
|
|
|
|
|
fp = PaOpen(filename,"r",".ext",".",(char *) NULL,(char **) NULL);
|
|
|
|
|
|
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');
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
TxError("Bad res:fix attribute label %s\n",
|
|
|
|
|
|
line[RES_EXT_ATTR_TEXT]);
|
|
|
|
|
|
*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);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* ResSimMerge-- Processes = line in sim file
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results: Success/Failure
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side Effects: The forward field of one node is set to point to the
|
|
|
|
|
|
* other node. All of the junkt from the first node is moved to
|
|
|
|
|
|
* the second node.
|
|
|
|
|
|
*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
ResSimMerge(line)
|
|
|
|
|
|
char line[][MAXTOKEN];
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
ResSimNode *node;
|
2019-10-17 22:21:56 +02:00
|
|
|
|
devPtr *ptr;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
|
|
if ((line[ALIASNAME][0] == '\0') || (line[REALNAME][0] == '\0'))
|
|
|
|
|
|
{
|
|
|
|
|
|
TxError("Bad node alias line\n");
|
|
|
|
|
|
return(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
node = ResInitializeNode(HashFind(&ResNodeTable,line[ALIASNAME]));
|
|
|
|
|
|
node->status |= FORWARD;
|
|
|
|
|
|
node->forward = ResInitializeNode(HashFind(&ResNodeTable,line[REALNAME]));
|
|
|
|
|
|
node->forward->resistance += node->resistance;
|
|
|
|
|
|
node->forward->capacitance += node->capacitance;
|
2019-10-17 22:21:56 +02:00
|
|
|
|
while (node->firstDev != NULL)
|
2017-04-25 14:41:48 +02:00
|
|
|
|
{
|
2019-10-17 22:21:56 +02:00
|
|
|
|
ptr=node->firstDev;
|
|
|
|
|
|
node->firstDev = node->firstDev->nextDev;
|
|
|
|
|
|
ptr->nextDev = node->forward->firstDev;
|
|
|
|
|
|
node->forward->firstDev = ptr;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
return(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* ResInitializeNode-- Gets the node corresponding to a given hash table
|
|
|
|
|
|
* entry. If no such node exists, one is created.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:Returns ResSimNode corresponding to entry.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side Effects: May allocate a new ResSimNode.
|
|
|
|
|
|
*
|
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
ResSimNode *
|
|
|
|
|
|
ResInitializeNode(entry)
|
|
|
|
|
|
HashEntry *entry;
|
|
|
|
|
|
{
|
|
|
|
|
|
ResSimNode *node;
|
|
|
|
|
|
|
|
|
|
|
|
if ((node = (ResSimNode *) HashGetValue(entry)) == NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
node = (ResSimNode *) mallocMagic((unsigned)(sizeof(ResSimNode)));
|
|
|
|
|
|
HashSetValue(entry,(char *) node);
|
|
|
|
|
|
node->nextnode = ResOriginalNodes;
|
|
|
|
|
|
ResOriginalNodes = node;
|
|
|
|
|
|
node->status = FALSE;
|
|
|
|
|
|
node->forward = (ResSimNode *) NULL;
|
|
|
|
|
|
node->capacitance = 0;
|
|
|
|
|
|
node->cap_vdd = 0;
|
|
|
|
|
|
node->cap_couple = 0;
|
|
|
|
|
|
node->resistance = 0;
|
|
|
|
|
|
node->type = 0;
|
2019-10-17 22:21:56 +02:00
|
|
|
|
node->firstDev = NULL;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
node->name = entry->h_key.h_name;
|
|
|
|
|
|
node->oldname = NULL;
|
|
|
|
|
|
node->drivepoint.p_x = INFINITY;
|
|
|
|
|
|
node->drivepoint.p_y = INFINITY;
|
2018-01-02 15:46:04 +01:00
|
|
|
|
node->location.p_x = INFINITY;
|
|
|
|
|
|
node->location.p_y = INFINITY;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
node->rs_sublist[0]=NULL;
|
|
|
|
|
|
node->rs_sublist[1]=NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
while (node->status & FORWARD)
|
|
|
|
|
|
{
|
|
|
|
|
|
node = node->forward;
|
|
|
|
|
|
}
|
|
|
|
|
|
return(node);
|
|
|
|
|
|
}
|