Files
magic/resis/ResReadSim.c
T
Tim Edwards fd737dbf80 Overhauled the extresist code (again), this time to (1) correct for
a long-standing error (introduced with the "extresist geometry"
option) that can cause nets not to be extracted (due to the first
record not having extraction data, which was itself a long-standing
error in the code but which was not fixed correctly);  (2) handle
"device mosfet" type transistors (previously only handled the old
"fet" type extraction devices);  and (3) correct for the res.ext
file having a different scalefactor relative to the .ext file.  The
latter item was solved by forcing all input to scale like
ExtCurStyle->exts_unitsPerLambda, locally correcting all input as
needed.  Note that extresist still needs to handle other extraction
devices (e.g., resistors and capacitors) but those will require
additional handling in the routines which analyze the current path
to determine how to break up wires into paths.
2019-12-08 17:37:48 -05:00

882 lines
22 KiB
C

#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. */
#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
#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 */
static float resscale=1.0; /* Scale factor */
char RDEV_NOATTR[1]={'0'};
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)
{
resscale = (float)atof(line[NODELAMBDA]);
if (resscale == 0.0) resscale = 1.0;
}
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)
{
TxError("Error in Reading device line of sim file.\n");
result = 1;
}
else if (fettype != MINFINITY)
{
float sheetr;
ExtDevice *devptr;
devptr = ExtCurStyle->exts_device[fettype];
sheetr=(float)devptr->exts_linearResist;
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;
float lambda;
/* 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.
*/
lambda = (float)ExtCurStyle->exts_unitsPerLambda;
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);
node->location.p_x = (int)((float)atof(line[NODENODEX]) / lambda);
node->location.p_y = (int)((float)atof(line[NODENODEY]) / lambda);
#ifdef ARIEL
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);
#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);
}
/*
*-------------------------------------------------------------------------
*
* ResSimDevice-- Processes a device line from a sim file.
*
* Results: returns 0 if line was added correctly.
*
* Side Effects: Allocates devices and adds nodes to the node hash table.
*
*-------------------------------------------------------------------------
*/
int
ResSimDevice(line,rpersquare,ttype)
char line[][MAXTOKEN];
float rpersquare;
TileType ttype;
{
RDev *device;
int rvalue,i,j,k;
char *newattr,tmpattr[MAXTOKEN];
static int nowarning = TRUE;
float lambda;
device = (RDev *) mallocMagic((unsigned) (sizeof(RDev)));
if ((line[RDEV_WIDTH][0] == '\0') || (line[RDEV_LENGTH][0] == '\0'))
{
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;
}
device->resistance = MagAtof(line[RDEV_LENGTH]) * rpersquare/MagAtof(line[RDEV_WIDTH]);
}
device->status = FALSE;
device->nextDev = ResRDevList;
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;
device->rs_ttype = ttype;
/* sim attributes look like g=a1,a2 */
/* ext attributes are "a1","a2" */
/* do conversion from one to the other here */
for (i=RDEV_ATTR;i < RDEV_ATTR+RDEV_NUM_ATTR;i++)
{
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])
{
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;
rvalue = ResSimNewNode(line[GATE],GATE,device) +
ResSimNewNode(line[SOURCE],SOURCE,device) +
ResSimNewNode(line[DRAIN],DRAIN,device);
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
ResSimNewNode(line,type,device)
char line[];
int type;
RDev *device;
{
HashEntry *entry;
ResSimNode *node;
devPtr *tptr;
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;
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;
devPtr *ptr;
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;
while (node->firstDev != NULL)
{
ptr=node->firstDev;
node->firstDev = node->firstDev->nextDev;
ptr->nextDev = node->forward->firstDev;
node->forward->firstDev = ptr;
}
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;
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);
}