
#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 .sim file or the .nodes file are in centimicrons
     * when multiplied by resscale (units from the .sim file 1st line).
     * multiply resscale by the extract scale (exts_unitsPerLambda) used to
     * generate .ext dimensions originally, to get back to database units.
     */
    lambda = resscale * (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->tnumber = ++Maxtnumber;
     device->status = FALSE;
     device->nextDev = ResRDevList;

     lambda = resscale * (float)ExtCurStyle->exts_unitsPerLambda;
     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);
}
