#include MUT_H 
#include MLO_H 
#include MLU_H
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "max.h"
#include "extern.h"
#include "foncspi.h"
#define PARSE_TRACE NO

#define HASH_MAX 100
#define LINESIZE 120

chain_list *already_drived = NULL;
FILE *file_out;


spi_triplet_list *hashtable[HASH_MAX];

/* emulation de la fonction mathematique pow(x,y) */

double spi_modpow(x,y)
double x;
int y;
{
int i;
double val;
val = x;
if(y>0)
    {  
    for(i = 1;i<y;i++)
        {
        val *= x;
        }
        return(val);
    }
else
    {
    y = -y;
    for(i = 1;i<y;i++)
        {
        val *= x;
        }
        val  = 1.0/val;
        return(val);
    }
}


/*la declaration de la fonction de spi_givefloat_capa */

double spi_givefloat_capa(s)
	char *s;
	{
	double x=0.0;
	char ch[10];
	strcpy(ch,"?");
	if(s != (char *)NULL)
	{
	sscanf(s,"%lf %s",&x,ch);
	if(strncmp(ch,"m",1)==0 || strncmp(ch,"M",1)==0)
	return (spi_modpow(10.0,9)*x);
	else if(strncmp(ch,"u",1)==0 || strncmp(ch,"U",1)==0)
	return (spi_modpow(10.0,6)*x);
	else if(strncmp(ch,"n",1)==0 || strncmp(ch,"N",1)==0)
	return (spi_modpow(10.0,3)*x);
	else if(strncmp(ch,"p",1)==0 || strncmp(ch,"P",1)==0)
	return (x);
	else if(strncmp(ch,"f",1)==0 || strncmp(ch,"F",1)==0)
	return (spi_modpow(10.0,-3)*x);
	else if(strncmp(ch,"?",1)==0 )
        return (spi_modpow(10.0,12)*x);
	}
	}

/*la declaration de la fonction de spi_givelong */

long spi_givelong(s)
	char *s;
	{
	double x=0.0;
	char ch[10];
	strcpy(ch,"?");
	if(s != (char *)NULL)
	{
	sscanf(s,"%lf %s",&x,ch);
	if(strncmp(ch,"m",1)==0 || strncmp(ch,"M",1)==0)
	return ((long)(1000.0*x*SCALE_X));
	else if(strncmp(ch,"u",1)==0 || strncmp(ch,"U",1)==0)
	return ((long)(x*SCALE_X));
	else if(strncmp(ch,"n",1)==0 || strncmp(ch,"N",1)==0)
	return ((long)(0.0010*x*SCALE_X));
	else if(strncmp(ch,"p",1)==0 || strncmp(ch,"P",1)==0)
	return ((long)(0.0000010*x*SCALE_X));
	else if(strncmp(ch,"f",1)==0 || strncmp(ch,"F",1)==0)
	return ((long)(0.0000000010*x*SCALE_X));
	else if(strncmp(ch,"?",1)==0 )
        return ((long)(1000000.0*x*SCALE_X));
	}
	}

/*la declaration de la fonction de spi_givelarea */

long spi_givearea(s,wr)
	char *s;
	long wr;
	{
	double x=0.0;
	char ch[10];
	strcpy(ch,"?");
	if(s != (char *)NULL && wr!=0)
	{
	sscanf(s,"%lf %s",&x,ch);
	if(strncmp(ch,"m",1)==0 || strncmp(ch,"M",1)==0)
	return ((long)((x*SCALE_X*SCALE_X)*(1000000000.0/wr)));
	else if(strncmp(ch,"u",1)==0 || strncmp(ch,"U",1)==0)
	return ((long)((x*SCALE_X*SCALE_X)*(1000000.0/wr)));
	else if(strncmp(ch,"n",1)==0 || strncmp(ch,"N",1)==0)
	return ((long)((x*SCALE_X*SCALE_X)*(1000.0/wr)));
	else if(strncmp(ch,"p",1)==0 || strncmp(ch,"P",1)==0)
	return ((long)((x*SCALE_X*SCALE_X)/wr));
	else if(strncmp(ch,"f",1)==0 || strncmp(ch,"F",1)==0)
	return ((long)(0.0010*(x*SCALE_X*SCALE_X)/wr));
	else if(strncmp(ch,"?",1)==0 )
        return ((long)((x*SCALE_X*SCALE_X)*(spi_modpow(10.0,12)/wr)));
	}
	}

/*allocation */

spi_triplet_list *spi_create_triplet(name,index)
	char *name;
	int index;
	{
	spi_triplet_list *pt = (spi_triplet_list *) NULL;
	pt = (spi_triplet_list *)malloc(sizeof(spi_triplet_list));
	if(pt!=NULL){
		name = namealloc(name);
		pt -> next = NULL;
		pt -> name = name;
		pt -> index = index+MAXSIGINDEX;
		return(pt);
	       	}
	else return((spi_triplet_list *)NULL);
         }	         

/*la fonction de la gestion de la table de hachage */

	int spi_getcode(s)
	char *s;
	{
	 int code = 0;
	 while(*s)
	{
	 code = code << 1^ *s;
		s++;
	}
	if(code < 0) code = -code;
	   code = (code % HASH_MAX);
	return (code);
        }

spi_triplet_list *spi_append2(pt1,pt2)

spi_triplet_list *pt1,*pt2;
{
	if(pt2 == NULL) fprintf(stderr, " **********no memory space********** \n");
	if(pt1 == NULL) pt1 = pt2;
	else {
		pt2 ->next = pt1;
		pt1 = pt2;
	     }
return(pt1);
}               

/* initialisation de la table de hashage */

spi_init_hash()
	{
	 int i;
	    for(i=0; i < HASH_MAX; i++)
		 hashtable[i] = NULL;
	}

/* ajout d'un element dans la table */

spi_triplet_list *spi_addtriplet(s,i,n)
	char *s;   
	int i,n;
{
spi_triplet_list *pt_aux =(spi_triplet_list *) NULL;
pt_aux = spi_append2(hashtable[i],spi_create_triplet(s,n));
return(pt_aux);
} 

/* la fonction scan() */

spi_triplet_list *spi_scan_list2(s,i) 
char *s;
int i;
{
spi_triplet_list *pt_aux =(spi_triplet_list *) NULL;   /* pointeur signal */
for(pt_aux=hashtable[i];pt_aux!=NULL;pt_aux=pt_aux->next)
	{
	  downstr(s,s);
	  if(!strcmp(pt_aux ->name,s))
	  return(pt_aux);
	} 
	  return( (spi_triplet_list *) NULL);
}

/* fonction de (long)spi_giveindex */

int spi_giveindex(s)
char *s; 
{
int i=0;
spi_triplet_list *pt = (spi_triplet_list *) NULL;
i= spi_getcode(s);
if(hashtable[i] == NULL) 
	{
	hashtable[i] = spi_addtriplet(s,i,spi_index);
	
	if(hashtable[i]!=NULL) {spi_index++;return (hashtable[i]->index);} 
	else return(-1);
	}
	else  if((pt = spi_scan_list2(s,i)) != NULL) 
                 return (pt->index);
	else { 
	 hashtable[i] = spi_addtriplet(s,i,spi_index);
	
if(hashtable[i]!=NULL)  {spi_index++;return(hashtable[i]->index);} 
	else return(-1);
	     }
}

/* nettoyage de la table de hashage */

void spi_clear_hash()
{ 
  int i;
  spi_triplet_list *pt_aux=(spi_triplet_list *)NULL ,*pt_aux1=(spi_triplet_list *)NULL ;
  for (i=0; i<HASH_MAX; i++)
  { if(hashtable[i] != NULL)
	for(pt_aux = hashtable[i];pt_aux!=NULL;pt_aux=pt_aux->next)
		{
		pt_aux1 = pt_aux->next;
		hashtable[i] = pt_aux1;
		free(pt_aux);
		}
  }
}

lofig_list *spi_findlofig(name)
char    *name;
{
        lofig_list  *pt = (lofig_list *) NULL;

        /* scan figure list */
        for (pt = HEAD_LOFIG; pt; pt=pt->NEXT)
                if (!strcmp(pt->NAME, name)) return pt;
        return (lofig_list *)NULL;
}


/*******************************************************************************
* checkname : check for busses with single index for parsers
*
*******************************************************************************/
char *spi_checkname(name)
char *name;
{
char *s, *t;
 
   s = t = name;
   while (*t) {
      if (*t == '[')
         *t = ' ';
      else if (*t == ']')
         if (*(++t) == '\0') /* ok, it's finished */
            goto end;
         else if (*t == '[') /* multiple array */
            continue;
      *s++ = *t++;
   }
end:
   *s = '\0';
   return name;
}
 
/*******************************************************************************
* function busname for drivers
*
*******************************************************************************/
char *spi_busname(name)
char *name;
{
char buffer[255], *s, *t;
char one = 1;
   s = name;
   t = buffer;
   while (*s) {
      if (*s == ' ')
         if (one) {
            *t++ = '[';
            s++;
            one = 0;
         } else {
            *t++ = ']';
            *t++ = '[';
            s++;
         }
      *t++ = *s++;
   }
   if (!one)
      *t++ = ']';
   *t = '\0';
   return buffer;
}

 
int spi_lit_string(pfic,repere)
FILE *pfic;
char *repere;
{       
	char chaine[LINESIZE];       /* recherche d'un repere     */
        if (!feof(pfic))
                do {
		fscanf(pfic,"%s",&chaine[0]);
                   } while ((!feof(pfic)) && (strcmp(chaine, repere)));
        return(strcmp(chaine, repere) == 0);
}

int spi_lit_line(pfic,repere)
FILE *pfic;
char *repere;
{       
	char chaine[LINESIZE];       /* recherche d'un repere     */
        if (!feof(pfic))
                do {
	 	fgets(chaine, strlen(repere) + 1, pfic);
                   } while ((!feof(pfic)) && (strcmp(chaine, repere)));
        return(strcmp(chaine, repere) == 0);
}

char *cleaname(str)
char *str;
{
char *name;
int i;
name =namealloc(str);
	if (str[0]=='/')
		{
	for(i=1;i<=strlen(str)+1;i++)
	name[i-1] = str[i];
		}
	if (name[strlen(name)-1]=='!') name[strlen(name)-1]='\0';
return(name);
}

void spi_viewtrip(pt)
spi_triplet_list *pt;
{
spi_triplet_list *pt_aux = (spi_triplet_list *) NULL;
for(pt_aux = pt; pt_aux!=NULL;pt_aux = pt_aux->next)
fprintf(stdout, "* net %d = %s\n",pt_aux->index,pt_aux->name);
}

char *spi_getdicname(index,ptdic)
int index;
spi_triplet_list *ptdic;
{
spi_triplet_list *pt_aux = (spi_triplet_list *) NULL;

for(pt_aux=ptdic;pt_aux!=NULL;pt_aux=pt_aux->next)
	{
	if(pt_aux->index == index)
	return(pt_aux->name);
	}
return((char *) NULL);
}

int spi_getdicindex(str,ptdic)
char *str;
spi_triplet_list *ptdic;
{
spi_triplet_list *pt_aux = (spi_triplet_list *) NULL;

if(str)
	{
	for(pt_aux=ptdic;pt_aux!=NULL;pt_aux=pt_aux->next)
		{
	if(!strcmp(pt_aux->name , str))
	return(pt_aux->index);
		}
	}
return(0);
}


losig_list *spi_addsigname(signame)
char *signame;
{
losig_list *ptsig;
char *str;


	if(isalpha(signame[0]))
	{
		ptsig = givelosig(spi_ptfig, (long)spi_giveindex(signame));
		ptsig->NAMECHAIN = addchain(ptsig->NAMECHAIN,
                                            namealloc(signame));
	}
	else
	{
		if (atoi(signame) > MAXSIGINDEX)
		{
			fprintf(stderr, "*** parser spice error *****\n");
			fprintf(stderr, "line %d : index too big, you must change MAXSIGINDEX\n");
			exit(-1);
		}
		ptsig=givelosig(spi_ptfig, atoi(signame));
                /* si aucun nom n'est donne on n'en donne pas */
	}
return(ptsig);
}


losig_list *spi_givelosig(ptfig,index)
lofig_list *ptfig;
long index;
{
losig_list *ptsig = (losig_list *) NULL;

for(ptsig = ptfig->LOSIG; ptsig != NULL; ptsig = ptsig->NEXT)
	if(ptsig->INDEX == index) return ptsig ;
	return addlosig(ptfig, index, (chain_list *)NULL, 'I', 0.0);
}

void spi_addcapa(ptsigx,ptsigy,capa)
losig_list *ptsigx,*ptsigy;
double capa;
{
if(ptsigx!=(losig_list *)NULL) 
	addcapa(ptsigx,capa);
if(ptsigy!=(losig_list *)NULL) 
	addcapa(ptsigy,capa);
}

void spi_addlocname(ptfig,locname,ptdic)
lofig_list *ptfig;
spi_triplet_list *ptdic;
char *locname;
{
char *str;

	if(isalpha(locname[0]))
                {
		locon_list *locon = addlocon(ptfig,locname,givelosig(ptfig,(long)spi_giveindex(locname)),UNKNOWN);

                /* ajout PAYAM du 20/06/93 pour ne pas perdre les noms des connecteurs */
                locon->SIG->NAMECHAIN = addchain(locon->SIG->NAMECHAIN,locon->NAME) ;
                }
	else{
		if (atoi(locname) > MAXSIGINDEX)
		{
			fprintf(stderr, "*** parser spice error *****\n");
			fprintf(stderr, "line %d : index too big, you must change MAXSIGINDEX\n");
			exit(-1);
		}
		addlocon(ptfig,concatname("mbk",locname),givelosig(ptfig,atoi(locname)),UNKNOWN);

	    }
}
	

void spi_drive_subckt(lofig)
lofig_list *lofig;
{
locon_list *ptlocon = (locon_list *) NULL;
lotrs_list *ptlotrs = (lotrs_list *) NULL;
losig_list *ptlosig = (losig_list *) NULL;
losig_list *pt_aux = (losig_list *) NULL;
loins_list *ptloins = (loins_list *) NULL;
int countt, countc;
char drived_cell();

int vdd =1,vss=0 ,loci=0, flagvdd=0, flagvss=0, maxindex=0;

        if (drived_cell(already_drived, lofig->NAME)) return;

        already_drived = addchain(already_drived, namealloc(lofig->NAME));

        fprintf(file_out,"\n.SUBCKT %s ",lofig->NAME);
                lofig ->LOCON=(locon_list*)reverse((chain_list*)lofig->LOCON);
                for(ptlocon=lofig->LOCON;ptlocon!=NULL;ptlocon=ptlocon->NEXT)
                {
                if(isvdd(ptlocon->NAME)) 
			{vdd=ptlocon->SIG->INDEX; flagvdd =1;}
                if(isvss(ptlocon->NAME)) 
			{vss=ptlocon->SIG->INDEX; flagvss =1;}

        	fprintf(file_out,"%d ",ptlocon->SIG->INDEX);
		loci++;

                /*-----------------------------------------------------*/
		/* correction PAYAM du 03/06/1993: avant: si loci = 20 */
                /* on ne faisait que rajouter '+' en oubliant en oubli-*/
                /* le nom du 20-eme connecteur.                        */
                /*-----------------------------------------------------*/
		if((loci % 20) == 0)
		fprintf(file_out,"\n+");
                }
		/* Recherche des signaux vdd et vss */
		for(pt_aux=lofig->LOSIG;pt_aux!=NULL;pt_aux=pt_aux->NEXT)
		{
		if(pt_aux->INDEX > maxindex) maxindex = pt_aux->INDEX;
		if(isvdd(getsigname(pt_aux)))
			if(flagvdd != 1) {vdd = pt_aux->INDEX;flagvdd = 1;}
		if(isvss(getsigname(pt_aux)))
			if(flagvss != 1) {vss = pt_aux->INDEX;flagvss = 1;}
		}
		if(flagvdd !=1)
		{
		vdd = maxindex + 1;
		fprintf(stdout,"From parser SPICE\n");
		fprintf(stdout," WARNING : No VDD Connector or Signal in %s\n",lofig->NAME); 
		}
		if(flagvss !=1)
		{
		vss = maxindex + 2;
		fprintf(stdout,"From parser SPICE\n");
		fprintf(stdout," WARNING : No VSS Connector or Signal in %s\n",lofig->NAME); 
		}
                lofig ->LOCON=(locon_list*)reverse((chain_list*)lofig->LOCON);
        fprintf(file_out,"\n");
                lofig ->LOTRS=(lotrs_list*)reverse((chain_list*)lofig->LOTRS);
                for(ptlotrs=lofig->LOTRS,countt=1;ptlotrs!=NULL;ptlotrs=ptlotrs->NEXT)
                {
                fprintf(file_out,"M%d ",countt++);
 
                if(ptlotrs->DRAIN->SIG != NULL)
                fprintf(file_out,"%d ",(ptlotrs->DRAIN->SIG->INDEX));
                else{
		fprintf(stderr, "******* from driver spice ********\n");
		fprintf(stderr, "signal with no index in figure %s\n",lofig->NAME); exit(1);}
 
                if(ptlotrs->GRID->SIG != NULL)
                fprintf(file_out,"%d ",(ptlotrs->GRID->SIG->INDEX));
                else{
		fprintf(stderr, "******* from driver spice ********\n");
		fprintf(stderr, "signal with no index in figure %s\n",lofig->NAME); exit(1);}
 
                if(ptlotrs->SOURCE->SIG != NULL)
                fprintf(file_out,"%d ",(ptlotrs->SOURCE->SIG->INDEX));
                else{
		fprintf(stderr, "******* from driver spice ********\n");
		fprintf(stderr, "signal with no index in figure %s\n",lofig->NAME); exit(1);}
 
 

                fprintf(file_out,"%d %s L=%.3leU W=%.3leU",
                       ptlotrs->TYPE==TRANSN? vss : vdd,
                       ptlotrs->TYPE==TRANSN? modn : modp,
                       (double)((double) (ptlotrs-> LENGTH) / SCALE_X),
                       (double)((double) (ptlotrs-> WIDTH) / SCALE_X));

                /* ecriture de la geometrie du transistor: surface source */
                if(ptlotrs->XS != 0)
                fprintf(file_out," AS=%.2fP",(float)
                        (ptlotrs->XS * ptlotrs->WIDTH)/(SCALE_X*SCALE_X)) ;

                /* ecriture de la geometrie du transistor: surface drain */
                if(ptlotrs->XD != 0)
                fprintf(file_out," AD=%.2fP",(float)
                        (ptlotrs->XD * ptlotrs->WIDTH)/(SCALE_X*SCALE_X)) ;

                /* ecriture de la geometrie du transistor: perimetre source */
                if(ptlotrs->PS != 0)
                fprintf(file_out," PS=%.2fU",(float)ptlotrs->PS/SCALE_X) ;

                /* ecriture de la geometrie du transistor: perimetre drain */
                if(ptlotrs->PD != 0)
                fprintf(file_out," PD=%.2fU",(float)ptlotrs->PD/SCALE_X) ;

                fprintf(file_out,"\n");
                }
                lofig ->LOTRS=(lotrs_list*)reverse((chain_list*)lofig->LOTRS);
        fprintf(file_out,"\n");
                lofig ->LOSIG=(losig_list*)reverse((chain_list*)lofig->LOSIG);
                for(ptlosig=lofig->LOSIG,countc=1;ptlosig!=NULL;ptlosig=ptlosig->NEXT) 
                {
			/* Laurent TRICHES le 21/08/92 */
                if ( (ptlosig->CAPA != 0.0000 ) && (ptlosig->INDEX != vss) )
                        {
                fprintf(file_out,"C%d %d  %d  %.4fPF\n",countc++,(ptlosig->INDEX),vss, (ptlosig->CAPA ));
                        }
                }
                lofig ->LOSIG=(losig_list*)reverse((chain_list*)lofig->LOSIG);
        fprintf(file_out,"\n");
                lofig ->LOINS=(loins_list*)reverse((chain_list*)lofig->LOINS);
                for(ptloins=lofig->LOINS;ptloins!=NULL;ptloins=ptloins->NEXT)
                {
		/* TRICHES laurent rajout le 21/08/92 */
		if (ptloins->INSNAME[ 0 ] != 'x')
                	fprintf(file_out,"X%s ",spi_busname(ptloins->INSNAME));
		else
			fprintf(file_out,"%s ",spi_busname(ptloins->INSNAME));
                ptloins ->LOCON=(locon_list*)reverse((chain_list*)ptloins->LOCON);     
                        for(ptlocon=ptloins->LOCON;ptlocon!=NULL;ptlocon=ptlocon->NEXT)
                        {
                        /*fprintf(file_out," %s",spi_busname(ptlocon->NAME));*/
                        fprintf(file_out," %d",ptlocon->SIG->INDEX);
                        }
                        fprintf(file_out," %s",ptloins->FIGNAME);
                ptloins ->LOCON=(locon_list*)reverse((chain_list*)ptloins->LOCON);
        fprintf(file_out,"\n");
                }
        fprintf(file_out,".ENDS %s\n",lofig->NAME);
                lofig ->LOINS=(loins_list*)reverse((chain_list*)lofig->LOINS);
}
 
/*------------------------------------------------------------------------------*/
/*      Driving of basic cells (leaves) available in figure "ptlofig".
 */
/*------------------------------------------------------------------------------*/
 
void drive_basic_cells(ptlofig)
lofig_list *ptlofig;
{
        chain_list *ptchain = (chain_list *) NULL;
        lofig_list *ptlfig = (lofig_list *)NULL;
        void      spi_drive_subckt();
 
        for (ptchain = ptlofig->MODELCHAIN; ptchain; ptchain = ptchain->NEXT)
        {
                ptlfig = getlofig((char *)ptchain->DATA, 'A');
                if (ptlfig->MODELCHAIN == (chain_list *) NULL)
                        spi_drive_subckt(ptlfig);
        }
}
 
 
 /*------------------------------------------------------------------------------*/
/*              Returns 0 if a cell has not already been written.
 */
/*------------------------------------------------------------------------------*/
 
char drived_cell(ptchain, cell_name)
chain_list *ptchain;
char       *cell_name;
{
        chain_list *chainp =(chain_list *) NULL;
 
        for(chainp = ptchain; chainp; chainp = chainp->NEXT)
                if ((char *)chainp->DATA == cell_name) return 1;
 
        return 0;
}
 
