/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit :  Compilateur de cellules                                    */
/*    Fichier :  sens.c                                                     */
/*                                                                          */
/*    (c) copyright 1991 Laboratoire MASI equipe CAO & VLSI                 */
/*    Tous droits reserves                                                  */
/*    Support : e-mail cao-vlsi@masi.ibp.fr                                 */
/*                                                                          */
/*    Auteur(s) :  L. Burgun                            le : 25/05/1992     */
/*                                                                          */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*                                                                          */
/****************************************************************************/

#include <stdio.h>
#include MUT_H
#include MLO_H
#include LOG_H
#include "sens.h"

      
/*------------------------------------------------------------------------------
freeCarac        : desallocation d'une structure ptl pour la caracterisation. 
-------------------------------------------------------
parametres 	 : une ptype_list 
-------------------------------------------------------
return 		 : un void
------------------------------------------------------------------------------*/

void freeCarac(ptl)
ptype_list *ptl;
{
ptype_list *ptlint = ptl;

while (ptlint)
   {
   char *name = (char *) ptlint->TYPE;

   if (strcmp(name,"fanout") && strcmp(name,"type"))
      freeptype(ptlint->DATA);
   else
      mbkfree(ptlint->DATA);

   ptlint = ptlint->NEXT;
   }
freeptype(ptl);
}

/*------------------------------------------------------------------------------
getCaracInput    : cherche dans une structure ptl le champs name associe
                   a l'entree input. 
-------------------------------------------------------
parametres 	 : une ptype_list 
-------------------------------------------------------
return 		 : un void
------------------------------------------------------------------------------*/

int getCaracInput(ptl,name,input)
ptype_list *ptl;
char *name;
char *input;
{
int *res;
ptype_list *ptlint;

ptlint = getptype(ptl,namealloc(input));

if (ptlint == NULL)
   return 0;

return (getCarac(ptlint->DATA,name));
}

/*------------------------------------------------------------------------------
getCarac         : cherche dans une structure ptl le champs name.
-------------------------------------------------------
parametres 	 : une ptype_list 
-------------------------------------------------------
return 		 : un void
------------------------------------------------------------------------------*/

int getCarac(ptl,name)
ptype_list *ptl;
char *name;
{
int *res;

ptl = getptype(ptl,namealloc(name));

if (ptl == NULL)
   return 0;

res = (int *) ptl->DATA;
return(*res);
}

/*------------------------------------------------------------------------------
addCaracInput    : ajoute dans une structure ptl le champs name associe
                   a l'entree input. 
-------------------------------------------------------
parametres 	 : une ptype_list 
-------------------------------------------------------
return 		 : un void
------------------------------------------------------------------------------*/

ptype_list *addCaracInput(ptl,name,val,input)
ptype_list *ptl;
char *name;
int val;
char *input;
{

ptype_list *ptlint = getptype(ptl,namealloc(input));

if (ptlint == NULL)
   {
   ptl = addptype (ptl,namealloc(input),NULL);
   ptlint = getptype(ptl,namealloc(input));
   }

ptlint->DATA = (void *)addCarac(ptlint->DATA,name,val);

return(ptl);
}

/*------------------------------------------------------------------------------
addCarac         : ajoute dans une structure ptl le champs name.
-------------------------------------------------------
parametres 	 : une ptype_list 
-------------------------------------------------------
return 		 : une ptype_list
------------------------------------------------------------------------------*/

ptype_list *addCarac(ptl,name,val)
ptype_list *ptl;
char *name;
int val;
{
int *res;

res = (int *) mbkalloc (sizeof(int));
*res = val;
return (addptype(ptl,namealloc(name),(void *) res));
}

/*------------------------------------------------------------------------------
caracLofig       : caracterise une lofig et renvoie dans une lpt toutes
                   les informations relatives a cette lofig. 
-------------------------------------------------------
parametres 	 : un nom de cellule a charger 
-------------------------------------------------------
return 		 : une ptype_list
------------------------------------------------------------------------------*/

ptype_list *caracLofig(name)
char *name;
{
lofig_list *fig = getlofig(name,'A');
locon_list *con;
lotrs_list *trs;
pTH pRTH;
pTH nRTH;
pTH nCTH,pCTH;
pTH nameTH;
pTH RupTH; 
pTH RdownTH;
pTH TphlTH; 
pTH TplhTH;
ptype_list *res = NULL;
int maxR=0;

	/* chainage des champs USER des equipotentielles */

lofigchain(fig);

	/* chargement des parametres technologiques */

chargeTechno(&RN,&RP,&CD,&CG,&TP);


if (RN == 0 || RP == 0 || CD == 0)
   {
   printf("chargeTechno : error - bad parameters\n");
   exit(-1);
   }

	/* calcul des numeros d'index de Vdd et Vss */

con = fig->LOCON;
while (con)
   {
   if (!strcmp(con->NAME,"vdd")) 
      indexVDD = (con->SIG)->INDEX;
   if (!strcmp(con->NAME,"vss")) 
      indexVSS = (con->SIG)->INDEX;
   con = con->NEXT;
   }

sens(fig);

		/* calcul du signal et de l'index de la sortie */

sigOUT = calculSigOut(fig,'N');
indexOUT = sigOUT->INDEX;

if (sigOUT == calculSigOut(fig,'P'))
   positiveFun = 0; 
else
   positiveFun = 1; 

res = addCarac(res,"type",positiveFun);

		/* remplissage de nameTH (trs,input) */

nameTH = createTH(20);

con = fig->LOCON;
while (con)
   {
   if (con->DIRECTION == IN) 
      {
      chain_list *cl,*oldCl;

      cl = getTrsGridSig(con->SIG,TRANSN);
      oldCl = cl;
      while (cl)
         {
         addTH(nameTH,cl->DATA,con->NAME);
         cl = cl->NEXT;
         }
      freechain(oldCl);

      cl = getTrsGridSig(con->SIG,TRANSP);
      oldCl = cl;
      while (cl)
         {
         addTH(nameTH,cl->DATA,con->NAME);
         cl = cl->NEXT;
         }
      freechain(oldCl);
      }
   con = con->NEXT;
   }

 

		/* remplissage des tables de hachages */

		/* les donnees relatives aux transistors */

pRTH = createTH(20);
nRTH = createTH(20);

con = fig->LOCON;
while (con)
   {
   if (con->DIRECTION == IN) 
      {
      chain_list *cl = ALLCON(con->SIG);
      chain_list *oldCl = cl;

      while (cl)
         {
         locon_list *conint = (locon_list *) cl->DATA; 
         if (conint->TYPE != EXTERNAL)
            {
            lotrs_list *trs = (lotrs_list *) conint->ROOT;
            if (trs->TYPE == TRANSN)
               {
			/* RN*L/W */

               addTH(nRTH,con->NAME,(RN*trs->LENGTH)/trs->WIDTH);
               }
            else
               {
                       /* RP*L/W */

               addTH(pRTH,con->NAME,(RP*trs->LENGTH)/trs->WIDTH);
               }
            }
         cl = cl->NEXT;
         }
      }
   con = con->NEXT;
   }

		/* les capacites */

nCTH = createTH(20);
pCTH = createTH(20);


con = fig->LOCON;
while (con)
   {
   if (con->DIRECTION == IN) 
      {
      chain_list *cl = ALLCON(con->SIG);
      chain_list *oldCl = cl;

      while (cl)
         {
         locon_list *conint = (locon_list *) cl->DATA; 

		/* selection du connecteur de grille du transistor */

         if (conint->TYPE != EXTERNAL)
            {
            lotrs_list *trs = (lotrs_list *) conint->ROOT;
            chain_list *clint;
            long somW = 0;
            long capa;
            locon_list *conout;

            conout = CONOUT(trs);

		/* conout est le connecteur vers la sortie */

            if (conout == NULL)
               {
               printf("sens : error - transistor non oriente \n");
               exit(-1);
               }

		/* on recupere les transistors associes au signal
                   pointe par conout (connecteur vers la sortie ) */

            clint = getTrsSig(conout->SIG,trs->TYPE);
            while (clint)
               {
               lotrs_list *trsint = (lotrs_list *) clint->DATA ;
               locon_list *conoutint = CONOUT(trsint);

               if (conoutint == NULL)
                  {
                  printf("sens : error - transistor non oriente \n");
                  exit(-1);
                  }

			/* on somme les W des transitors ayant le meme 
                           signal accroche au connecteur conout */
               
               if (trsint->TYPE == trs->TYPE)
                  {
                  somW = somW + trsint->WIDTH;
                  }
               clint = clint->NEXT;
               }

      		/* prise en compte de la capa d'interconnexion */


            capa = (CD*somW + (int) ((conout->SIG)->CAPA * 10000))/10;
            if (trs->TYPE == TRANSN)
               addTH(nCTH,con->NAME,capa);
            else
               addTH(pCTH,con->NAME,capa);
            }
         cl = cl->NEXT;
         }
      }
   con = con->NEXT;
   }

		/* calcul des capa de grille */

trs = fig->LOTRS;
while (trs)
   {
   int val = searchTH(nameTH,trs);
   if (val != EMPTYTH)
      res = addCaracInput(res, "cin",
                          (CG*(trs->WIDTH)*(trs->LENGTH))/100, (char *) val);
   trs = trs->NEXT;
   }


RupTH = createTH(20);
RdownTH = createTH(20);
TphlTH = createTH(20);
TplhTH = createTH(20);

		/* calcul des TPXX et Rup Rdown */

con = fig->LOCON;
while (con)
   {
   if (con->DIRECTION == IN) 
      {
      chain_list *cl = ALLCON(con->SIG);
      chain_list *oldCl = cl;

      while (cl)
         {
         locon_list *conint = (locon_list *) cl->DATA; 
         if (conint->TYPE != EXTERNAL)
            {
            lotrs_list *trs = (lotrs_list *) conint->ROOT;
            chain_list *clOut = chercheBrancheActive(trs,indexOUT,nameTH);
            chain_list *clAlim;
            chain_list *clint;
            int Rint;
            int Ca,Cb;
            int tpLH,tpHL;

            if (trs->TYPE == TRANSN)	/* RDown et TPHL */
               {
               int Rdown = 0;
               clAlim = chercheBrancheActive(trs,indexVSS,nameTH);


				/* calcul de Rdown */

               clint = clOut;
               while (clint)
                  {
                  Rdown = Rdown + searchTH(nRTH,clint->DATA);
                  clint = clint->NEXT;
                  }

               clint = clAlim->NEXT;
               while (clint)
                  {
                  Rdown = Rdown + searchTH(nRTH,clint->DATA);
                  clint = clint->NEXT;
                  }

		/* calcul de la resistance de l'alim vers l'entree */

               clint = clAlim->NEXT;
               Rint = 0;
               while (clint)
                  {
                  Rint = Rint + searchTH(nRTH,clint->DATA); 
                  clint = clint->NEXT;
                  }
			/* calcul de Ca */

               Ca = 0;
               clint = clOut;
               while (clint)
                  {
                  Rint = Rint + searchTH(nRTH,clint->DATA); 
                  Ca = Ca + (searchTH(nCTH,clint->DATA)*Rint)/Rdown;
                  clint = clint->NEXT;
                  }            
               clint = concatCL(clAlim,clOut->NEXT);
               Cb = calculCapaPassif(clint,TRANSP,nameTH,nCTH,pCTH);
               freechain(clint);
               tpHL = (Rdown*(Ca+Cb))/1000;	/* ohm x fempto-farad */

/*
               printf("Rdown(%s) = %d ", con->NAME,Rdown);
               printf("Ca(%s) = %d ",con->NAME,Ca);
               printf("Cb(%s) = %d ",con->NAME,Cb);
               printf("tpHL(%s) = %d\n",con->NAME,tpHL);
*/

               if (Rdown > maxR)
                  maxR = Rdown;

               addTH(RdownTH,con->NAME,Rdown);
               addTH(TphlTH,con->NAME,tpHL);

               if (!positiveFun)
                  {
                  res = addCaracInput(res, "rdown",Rdown, con->NAME);
                  res = addCaracInput(res, "tphl",tpHL, con->NAME);
                  }
               }
            else			/* Rup et TPLH */
               {
               int Rup = 0;
               clAlim = chercheBrancheActive(trs,indexVDD,nameTH);
                  

				/* calcul de Rup */

               clint = clOut;
               while (clint)
                  {
                  Rup = Rup + searchTH(pRTH,clint->DATA);
                  clint = clint->NEXT;
                  }

               clint = clAlim->NEXT;
               while (clint)
                  {
                  Rup = Rup + searchTH(pRTH,clint->DATA);
                  clint = clint->NEXT;
                  }

		/* calcul de la resistance de l'alim vers l'entree */

               clint = clAlim->NEXT;
               Rint = 0;
               while (clint)
                  {
                  Rint = Rint + searchTH(pRTH,clint->DATA); 
                  clint = clint->NEXT;
                  }
			/* calcul de Ca */

               Ca = 0;
               clint = clOut;
               while (clint)
                  {
                  Rint = Rint + searchTH(pRTH,clint->DATA); 
                  Ca = Ca + (searchTH(pCTH,clint->DATA)*Rint)/Rup;
                  clint = clint->NEXT;
                  }            
               clint = concatCL(clAlim,clOut->NEXT);
               Cb = calculCapaPassif(clint,TRANSN,nameTH,nCTH,pCTH);
               freechain(clint);

               tpLH = (Rup*(Ca+Cb))/1000;	/* ohm x fempto-farad */

/*
               printf("Rup(%s) = %d ", con->NAME,Rup);
               printf("Ca(%s) = %d ",con->NAME,Ca);
               printf("Cb(%s) = %d ",con->NAME,Cb);
               printf("tpLH(%s) = %d\n",con->NAME,tpLH);
*/

               if (Rup > maxR)
                  maxR = Rup;

               addTH(RupTH,con->NAME,Rup);
               addTH(TplhTH,con->NAME,tpLH);

               if (!positiveFun)
                  {
                  res = addCaracInput(res, "rup",Rup, con->NAME);
                  res = addCaracInput(res, "tplh",tpLH, con->NAME);
                  }
               }
            freechain(clOut);
            freechain(clAlim);
            }
         cl = cl->NEXT;
         }
      }
   con = con->NEXT;
   }


if (positiveFun)
   {
   int Wp=0;
   int Wn=0;
   int Ln=0;
   int Lp=0;
   int tpHH;
   int tpLL;
   int RupInv;   
   int RdownInv;   
   int C0;
   chain_list *cl;
   lotrs_list *trs;
   losig_list *sig = calculSigOut(fig,'P');

   cl = getTrsSig(sig,TRANSN);
   trs = (lotrs_list *) cl->DATA;

   Wn = trs->WIDTH;
   Ln = trs->LENGTH;
         
   freechain(cl);

   cl = getTrsSig(sig,TRANSP);
   trs = (lotrs_list *) cl->DATA;

   Wp = trs->WIDTH;
   Lp = trs->LENGTH;

   freechain(cl);

   RupInv   = (RP*Lp)/Wp; 
   RdownInv = (RN*Ln)/Wn; 
   if (RupInv > RdownInv)
      maxR = RupInv;
   else
      maxR = RdownInv;

   C0 = CD*(Wp + Wn)/10;			/* en fait Ca + Cb */
   C0 = C0 + (sig->CAPA)*100;		/* + capa d'interconnexion */

/*
   printf("RdownInv = %d ",RdownInv);
   printf("RupInv = %d ",RupInv);
   printf("C0 = %d \n",C0);
*/

   con = fig->LOCON;
   while (con)
      {
      if (con->DIRECTION == IN) 
         {
         int tpHL = searchTH(TphlTH,con->NAME);
         int tpLH = searchTH(TplhTH,con->NAME);
         int Rup = searchTH(RupTH,con->NAME);
         int Rdown = searchTH(RdownTH,con->NAME);

         tpHH = tpHL + Rdown*CG*(Lp*Wp + Ln*Wn)/100000 + RupInv*C0/1000;
         tpLL = tpLH + Rup*CG*(Ln*Wn + Lp*Wp)/100000 + RdownInv*C0/1000;

/*
         printf("tpHH(%s) = %d\n",con->NAME,tpHH);
         printf("tpLL(%s) = %d\n",con->NAME,tpLL);
*/

         res = addCaracInput(res, "rdown",RdownInv, con->NAME);
         res = addCaracInput(res, "tphh",tpHH, con->NAME);
         res = addCaracInput(res, "rup",RupInv, con->NAME);
         res = addCaracInput(res, "tpll",tpLL, con->NAME);
         }
      con = con->NEXT;
      }
   res = addCarac(res,"fanout",calculFanout(maxR,C0,TP,60));
   }   
else
   {
   int C0;

   lotrs_list *trs;
   losig_list *sig = calculSigOut(fig,'N');
   chain_list *cl;

   cl = getTrsSig(sig,TRANSN);
   trs = (lotrs_list *) cl->DATA;
   C0 = searchTH(nCTH,searchTH(nameTH,trs));
   freechain(cl);

   cl = getTrsSig(sig,TRANSP);
   trs = (lotrs_list *) cl->DATA;
   C0 = C0 + searchTH(nCTH,searchTH(nameTH,trs));
   freechain(cl);

   
   res = addCarac(res,"fanout",calculFanout(maxR,C0,TP,60));
   }
   

destroyTH(nCTH);
destroyTH(pCTH);
destroyTH(nRTH);
destroyTH(pRTH);
destroyTH(nameTH);

destroyTH(RdownTH);
destroyTH(RupTH);
destroyTH(TphlTH); 
destroyTH(TplhTH);
dellofig(name);
return(res);
}

/*------------------------------------------------------------------------------
calculFanout     : calcule le fanout max. pour la cellule 
-------------------------------------------------------
parametres 	 : R C TP et le fanout min. 
-------------------------------------------------------
return 		 : une ptype_list
------------------------------------------------------------------------------*/

int calculFanout(R,C,TP,min)
int R;
int C;
int TP; 
{
int res;
res =  (TP*1000)/R - C/2;
if (res < min)
   res = min;
return(res);
}

/*------------------------------------------------------------------------------
calculCapaInt    : calcule la capa du reseau passif (Cb). 
-------------------------------------------------------
parametres 	 : la liste des entrees actives, l'index de l'alim vers laquelle
                   on se dirige (Vdd ou Vss) ...
-------------------------------------------------------
return 		 : une int
------------------------------------------------------------------------------*/

int calculCapaInt(clActif,index,nameTH,sig,dejaTraite,nCTH,pCTH)
chain_list *clActif;
long index;
pTH nameTH;
losig_list *sig;
pTH dejaTraite;
pTH nCTH,pCTH;
{
chain_list *cl,*clint;
int val = searchTH(dejaTraite,sig);

		/* on ne recalcule pas les capa... */

if (val != EMPTYTH)
   return(0);


	/* calcul des transistors menant aux alims */

if (index == indexVDD)
   cl = getTrsOrientSig(sig,index,TRANSP);
else
   cl = getTrsOrientSig(sig,index,TRANSN);

		/* la capa du signal */

if (cl)
   {
   if (index == indexVDD)
      val = searchTH(pCTH,(char *) searchTH(nameTH,cl->DATA));
   else
      val = searchTH(nCTH,(char *) searchTH(nameTH,cl->DATA));
   }
else
   {
   val = 0;
   }

		/* parcours de la liste des transistors connectes */

clint = cl;
while (clint)
   {
   char *name = (char *) searchTH(nameTH,clint->DATA);

	/* le transistor est attaque par une entree non active */

   if (!inChainList(clActif,name))
      {
      locon_list *con;
      lotrs_list *trs = (lotrs_list *) clint->DATA;

	/* calcul du connecteur par lequel on effectue la recherche */

      if (CONOUT(trs) == trs->DRAIN)
         con = trs->SOURCE;
      else
         con = trs->DRAIN;
       
      val = val + calculCapaInt(clActif,index,nameTH,con->SIG,
                                dejaTraite,nCTH,pCTH);
      }
   clint = clint->NEXT;
   }

addTH(dejaTraite,sig,1);
return val;
}

/*------------------------------------------------------------------------------
calculCapa       : calcule la capa du reseau passif (Cb). 
-------------------------------------------------------
parametres 	 : la liste des entrees actives, le type du reseau, la table
                   des (trs,input), les tables de capacite dans les 2 reseaux. 
-------------------------------------------------------
return 		 : une int
------------------------------------------------------------------------------*/

int calculCapaPassif(clActif,type,nameTH,nCTH,pCTH)
chain_list *clActif;
char type;
pTH nameTH;
pTH nCTH,pCTH;
{
pTH dejaTraite = createTH(20);
int res;

if (type == TRANSN)
   res = calculCapaInt(clActif,indexVSS,nameTH,sigOUT,dejaTraite,nCTH,pCTH);
else
   res = calculCapaInt(clActif,indexVDD,nameTH,sigOUT,dejaTraite,nCTH,pCTH);
destroyTH(dejaTraite);
return res;
}

/*------------------------------------------------------------------------------
concatCL         : concatene 2 listes chainees (avec recopie) 
-------------------------------------------------------
parametres 	 : 2 listes chainees. 
-------------------------------------------------------
return 		 : une int
------------------------------------------------------------------------------*/

chain_list *concatCL(lc1,lc2)
chain_list *lc1, *lc2;
{
chain_list *res=NULL;
while (lc1)
   {
   res = addchain(res,lc1->DATA);
   lc1 = lc1->NEXT;
   }
while (lc2)
   {
   res = addchain(res,lc2->DATA);
   lc2 = lc2->NEXT;
   }
return (res);
}

/*------------------------------------------------------------------------------
calculSigmaRTrs  : calcul une somme de resistance pour determiner par la suite
                   la branche active (la plus resistive). 
-------------------------------------------------------
parametres 	 : un transistor, un index et une table (trs, somme) 
-------------------------------------------------------
return 		 : une int
------------------------------------------------------------------------------*/

int calculSigmaRTrs(trs,index,sigmaRTrs)
lotrs_list *trs;
long index;
pTH sigmaRTrs;
{
locon_list *con;
chain_list *cl;
int val;

val = searchTH(sigmaRTrs,trs);

if (val != EMPTYTH)
   return val;
 
	/* calcul du connecteur par lequel on effectue la recherche */

if (index == indexOUT)
   con = CONOUT(trs);
else
   if (CONOUT(trs) == trs->DRAIN)
      con = trs->SOURCE;
   else
      con = trs->DRAIN;

cl = getTrsOrientSig(con->SIG,index,trs->TYPE);

if (trs->TYPE == TRANSN)
   val = (RN*trs->LENGTH)/trs->WIDTH;  /* RN*L/W */
else
   val = (RP*trs->LENGTH)/trs->WIDTH;  /* RP*L/W */

if (cl)
   {
   int max = 0,inter;

		/* calcul du max */
   while (cl)
      {
      inter = calculSigmaRTrs(cl->DATA,index,sigmaRTrs);
      if (max < inter)
         max = inter;
      cl = cl->NEXT;
      }
   val = val + max;
   }
addTH(sigmaRTrs,trs,val);
return val;      
}

/*------------------------------------------------------------------------------
calculCheminResistif  : calcul du chemin le + resistif 
-------------------------------------------------------
parametres 	 : un transistor, un index , une table (trs, somme) 
                   et une table (trs, input)
-------------------------------------------------------
return 		 : une int
------------------------------------------------------------------------------*/

chain_list *calculCheminResistif(trs,index,sigmaRTrs,nameTH)
lotrs_list *trs;
long index;
pTH sigmaRTrs;
pTH nameTH;
{
locon_list *con;
chain_list *cl, *res;


	/* calcul du connecteur par lequel on effectue la recherche */

if (index == indexOUT)
   con = CONOUT(trs);
else
   if (CONOUT(trs) == trs->DRAIN)
      con = trs->SOURCE;
   else
      con = trs->DRAIN;

cl = getTrsOrientSig(con->SIG,index,trs->TYPE);

if (cl)
   {
   if (cl->NEXT == NULL)
      res = addchain(calculCheminResistif(cl->DATA,index,sigmaRTrs,nameTH),
                     searchTH(nameTH,trs));
    else
      {
      int max = 0;
      int inter;
      lotrs_list *trsint = NULL;
      
      while (cl)
         {
         inter =  searchTH(sigmaRTrs,cl->DATA);
         if (inter > max)
            {
            max = inter;
            trsint = (lotrs_list *) cl->DATA;
            }
         cl = cl->NEXT;
         }
      res = addchain(calculCheminResistif(trsint,index,sigmaRTrs,nameTH),
                     searchTH(nameTH,trs));
      }
   }
else
   res = addchain(NULL,searchTH(nameTH,trs));

return(res);
}

/*------------------------------------------------------------------------------
chercheBrancheActive  : calcule la branche active 
-------------------------------------------------------
parametres 	 : un transistor, un index , une table (trs, somme) 
                   et une table (trs, input)
-------------------------------------------------------
return 		 : une chain_list *
------------------------------------------------------------------------------*/

chain_list *chercheBrancheActive(trs,index,nameTH)
lotrs_list *trs;
long index;
pTH nameTH;
{
pTH sigmaRTrs;
chain_list *res;

sigmaRTrs = createTH(20);

calculSigmaRTrs(trs,index,sigmaRTrs);


		/* selection de la branche la plus resistive */

res = calculCheminResistif(trs,index,sigmaRTrs,nameTH);
destroyTH(sigmaRTrs);
return(res);
}

/*------------------------------------------------------------------------------
displayCL        : affiche une liste chainee 
-------------------------------------------------------
parametres 	 : une chain_list *
-------------------------------------------------------
return 		 : void 
------------------------------------------------------------------------------*/

void displayCL(cl)
chain_list *cl;
{
while (cl)
   {
   if ((int) cl->DATA == EMPTYTH)
      {
      printf("\ndisplayCL : error - bad value -1\n");
      exit(-1);
      }
   printf("%s ",cl->DATA);
   cl = cl->NEXT;
   }
printf("\n");
}

/*------------------------------------------------------------------------------
inChainList      : verifie l'appartenance a une liste chainee 
-------------------------------------------------------
parametres 	 : une chain_list et une valeur (long)
-------------------------------------------------------
return 		 : 0 ou 1 
------------------------------------------------------------------------------*/

int inChainList(cl,value)
chain_list *cl;
long value;
{
while (cl)
   {
   if ((long) cl->DATA == value)
      return(1);
   cl = cl->NEXT;
   }
return(0);
}

/*------------------------------------------------------------------------------
getTrsOrientSig  : mets dans une liste chainee les transistors de type 'type'
                   oriente vers l'index 'index' rattache au signal 'sig par la
                   source ou le drain. 
-------------------------------------------------------
parametres 	 : un signal, un index et un type 
-------------------------------------------------------
return 		 : une chain_list *
------------------------------------------------------------------------------*/

chain_list *getTrsOrientSig(sig,index,type)
losig_list *sig;
long index;
char type;
{
chain_list *res = NULL;
chain_list *cl = ALLCON(sig);

while (cl)
   {
   locon_list *conint = (locon_list *) cl->DATA; 
   if (conint->TYPE != EXTERNAL)
      {
      lotrs_list *trs = (lotrs_list *) conint->ROOT;

	/* transistor de type "type" et attaque par le drain ou la source */

      if (trs->TYPE == type && conint != trs->GRID)
         {
         		/* res correctement oriente ? */

         if (index == indexOUT && CONOUT(trs) != conint)
            res = addchain(res,(void *) trs);
         if (index != indexOUT && CONOUT(trs) == conint)
            res = addchain(res,(void *) trs);
         }
      } 
   cl = cl->NEXT;
   }
return res;
}

/*------------------------------------------------------------------------------
getTrsOrientSig  : mets dans une liste chainee les transistors de type 'type'
                   rattache a sig par la grille
-------------------------------------------------------
parametres 	 : un signal et un type 
-------------------------------------------------------
return 		 : une chain_list *
------------------------------------------------------------------------------*/

chain_list *getTrsGridSig(sig,type)
losig_list *sig;
char type;
{
chain_list *res = NULL;
chain_list *cl = ALLCON(sig);

while (cl)
   {
   locon_list *conint = (locon_list *) cl->DATA; 
   if (conint->TYPE != EXTERNAL)
      {
      lotrs_list *trs = (lotrs_list *) conint->ROOT;


      if (trs->TYPE == type && conint == trs->GRID)
         res = addchain(res,(void *) trs);
      } 
   cl = cl->NEXT;
   }
return res;
}

/*------------------------------------------------------------------------------
getTrsSig 	 : mets dans une liste chainee les transistors de type 'type'
                   rattache a sig par le drain ou la source.
-------------------------------------------------------
parametres 	 : un signal et un type 
-------------------------------------------------------
return 		 : une chain_list *
------------------------------------------------------------------------------*/

chain_list *getTrsSig(sig,type)
losig_list *sig;
char type;
{
chain_list *res = NULL;
chain_list *cl = ALLCON(sig);

while (cl)
   {
   locon_list *conint = (locon_list *) cl->DATA; 
   if (conint->TYPE != EXTERNAL)
      {
      lotrs_list *trs = (lotrs_list *) conint->ROOT;

	/* transistor de type "type" et attaque par le drain ou la source */

      if (trs->TYPE == type && conint != trs->GRID)
         res = addchain(res,(void *) trs);
      } 
   cl = cl->NEXT;
   }
return res;
}

/*------------------------------------------------------------------------------
getConSig 	 : mets dans une liste chainee les connecteurs associes a un 
                   transistor de type 'type' rattache a sig par le drain ou
                   la source.
-------------------------------------------------------
parametres 	 : un signal et un type 
-------------------------------------------------------
return 		 : une chain_list *
------------------------------------------------------------------------------*/

chain_list *getConSig(sig,type)
losig_list *sig;
char type;
{
chain_list *res = NULL;
chain_list *cl = ALLCON(sig);

while (cl)
   {
   locon_list *conint = (locon_list *) cl->DATA; 
   if (conint->TYPE != EXTERNAL)
      {
      lotrs_list *trs = (lotrs_list *) conint->ROOT;

	/* transistor de type "type" et attaque par le drain ou la source */

      if (trs->TYPE == type && conint != trs->GRID)
         res = addchain(res,(void *) conint);
      } 
   cl = cl->NEXT;
   }
return res;
}

/*------------------------------------------------------------------------------
chercheChemin 	 : cherche un chemin dans le graphe de type 'type' pour 
                   orienter les transistors.
-------------------------------------------------------
parametres 	 : une figure logique, un signal, une pile de signaux
                   par lesquels on est deja passe pour eviter de boucler
                   et un type de graphe.
-------------------------------------------------------
return 		 : un int. 1 si OK  -   0 si bouclage par ce chemin
------------------------------------------------------------------------------*/

int chercheChemin(fig,sig,pPileIndex,type,dejaTraite)
lofig_list *fig;
losig_list *sig;
chain_list **pPileIndex;
char type;
pTH dejaTraite;
{

		/* boucle */

if (inChainList(*pPileIndex,sig->INDEX))
   {
   return(0);
   }

		/* terminaison de la recursion */

if (sig->INDEX == indexVDD || sig->INDEX == indexVSS)
   {
   return(1);
   }
else
   {
   int existChemin = 0;
   chain_list *cl = getConSig(sig,type);

         		/* ajout sur la pile */

   *pPileIndex = addchain(*pPileIndex,sig->INDEX);

   while (cl)
      {
      locon_list *conint = (locon_list *) cl->DATA;
      lotrs_list *trs = (lotrs_list *) conint->ROOT;
      losig_list *sigint;
      int val = searchTH(dejaTraite,trs);

      if (val == EMPTYTH || val == DELETETH)
         {
         
         addTH(dejaTraite,trs,2);

        		/* appel recursif */

         if (conint == trs->DRAIN)
            sigint = (trs->SOURCE)->SIG;
         if (conint == trs->SOURCE)
            sigint = (trs->DRAIN)->SIG;
         if (conint == trs->GRID)
            {
            printf("chercheChemin : error - signal on grid\n");
            exit(-1);
            }
         if (chercheChemin(fig,sigint,pPileIndex,type,dejaTraite) == 1)
            {
			/* conint est du cote de la sortie */

            addTH(dejaTraite,trs,1);
            trs->USER = addptype(trs->USER,ORIENT,conint);
            existChemin = 1;
            }
         else
            deleteTH(dejaTraite,trs);
         }
      else	/* un transistor oriente ==> chemin vers Vss ou Vdd possible */
         {
         if (val == 1) 
            {
            *pPileIndex = (*pPileIndex)->NEXT;
            return(1);
            }
         }

      cl = cl->NEXT;
      }

			/* on depile */

   *pPileIndex = (*pPileIndex)->NEXT;

		/* existait-il un chemin menant aux alimentations ? */

   if (existChemin == 1)
      return(1);
   else
      return(0);
   }   
}

/*------------------------------------------------------------------------------
orientation 	 : orientation le graphe de type 'type' de la figure fig.
-------------------------------------------------------
parametres 	 : une figure logique, un signal et un type de graphe.
-------------------------------------------------------
return 		 : un int. 1 si OK  
------------------------------------------------------------------------------*/

int orientation(fig,sig,type,dejaTraite)
lofig_list *fig;
losig_list *sig;
char type;
pTH dejaTraite;
{
chain_list *pileIndex = NULL;

return chercheChemin(fig,sig,&pileIndex,type,dejaTraite);
}

/*------------------------------------------------------------------------------
sens 	 	 : orientation une figure 
-------------------------------------------------------
parametres 	 : une figure logique
-------------------------------------------------------
return 		 : un void. 
------------------------------------------------------------------------------*/

void sens(fig)
lofig_list *fig;
{
locon_list *con;
losig_list *outSig;
pTH dejaTraite;

	/* orientation des connecteurs externes */

con = fig->LOCON;
while (con)
   {
   if (!strcmp(con->NAME,"vss") || !strcmp(con->NAME,"vdd"))
      con->DIRECTION = INOUT;
   else
      {
      chain_list *cl = ALLCON(con->SIG);
      while (cl && con->DIRECTION == UNKNOWN)
         {
         locon_list *conint = (locon_list *) cl->DATA; 
         if (conint->TYPE != EXTERNAL)
            {
            lotrs_list *trs = (lotrs_list *) conint->ROOT;
            if (trs->GRID == conint) 			/* entree */
               con->DIRECTION = IN;
            else					/* sortie */
               con->DIRECTION = OUT;
            }
         cl = cl->NEXT;
         }
      }
   con = con->NEXT;
   }

		/* calcul de l'equipotentielle de sortie */

outSig = calculSigOut(fig,'N');

dejaTraite = createTH(20);
orientation(fig,outSig,TRANSN,dejaTraite);
orientation(fig,outSig,TRANSP,dejaTraite);

outSig = calculSigOut(fig,'P');
orientation(fig,outSig,TRANSN,dejaTraite);
orientation(fig,outSig,TRANSP,dejaTraite);
destroyTH(dejaTraite);
}

/*------------------------------------------------------------------------------
positive 	 : renvoie 1 si la figure correspond a une fonction positive
                   0 sinon 
-------------------------------------------------------
parametres 	 : une figure logique et un connecteur de depart (sortie)
-------------------------------------------------------
return 		 : un int. 
------------------------------------------------------------------------------*/

int positive(fig,con)
lofig_list *fig;
locon_list *con;
{
int res;
chain_list *cl1 = getTrsSig(con->SIG,TRANSN);
chain_list *cl2 = getTrsSig(con->SIG,TRANSP);

if (cl1->NEXT == NULL && cl2->NEXT == NULL)
   res = 1;
else
   res = 0;
freechain(cl1);
freechain(cl2);
return res;
}

/*------------------------------------------------------------------------------
calculSigOut 	 : calcul le signal de sortie de la figure logique 
                   si type = 'P' la sortie generale
                   si type = 'N' la sortie interne ( avant inverseur)
-------------------------------------------------------
parametres 	 : une figure logique et un type  
-------------------------------------------------------
return 		 : un int. 
------------------------------------------------------------------------------*/

losig_list *calculSigOut(fig,type)
lofig_list *fig;
char type;
{
locon_list *con;
losig_list *res;

res = NULL;
con = fig->LOCON;
while (con)
   {
   if (con->DIRECTION == OUT)
      {
      if (type == 'N' && positive(fig,con))
         {
      		/* cellule positive ou negative */
          
         chain_list *cl = getTrsSig(con->SIG,TRANSN);
         lotrs_list *trs = (lotrs_list *) cl->DATA;
         
         res = (trs->GRID)->SIG;
         } 
      else
         res = con->SIG;
      }
   con = con->NEXT;
   }
return (res);
}

/*------------------------------------------------------------------------------
chargeTechno 	 : charge les parametres technologiques 
                   Rn  - resistance unitaire transistors N
                   Rp  - resistance unitaire transistors P
                   Cd  - capacite unitaire des source & drain
                   Cg  - capacite unitaire des grilles 
                   Tp  - temps de propagation pour le calcul du fanout
-------------------------------------------------------
parametres 	 : les adresses des differents parametres 
-------------------------------------------------------
return 		 : un void. 
------------------------------------------------------------------------------*/

void chargeTechno(Rn,Rp,Cd,Cg,Tp)
int *Rn,*Rp,*Cd,*Cg,*Tp;
{
FILE *Pfile;
char c;

if (( Pfile = fopen("techno","rt" )) != NULL )
        {

        c = fgetc( Pfile );                /* lecture de 'RN' */
        c = fgetc( Pfile );
        c = fgetc( Pfile );                /* lecture de '\n' */
        fscanf( Pfile, "%d", Rn );
 
        c = fgetc( Pfile );                /* lecture de '\n' */
        c = fgetc( Pfile );                /* lecture de 'RP */
        c = fgetc( Pfile );
        c = fgetc( Pfile );                /* lecture de '\n' */
        fscanf( Pfile, "%d", Rp );
 
        c = fgetc( Pfile );                /* lecture de '\n' */
        c = fgetc( Pfile );                /* lecture de 'CD' */
        c = fgetc( Pfile );
        c = fgetc( Pfile );                /* lecture de '\n' */
        fscanf( Pfile, "%d", Cd );

        c = fgetc( Pfile );                /* lecture de '\n' */
        c = fgetc( Pfile );                /* lecture de 'CG' */
        c = fgetc( Pfile );
        c = fgetc( Pfile );                /* lecture de '\n' */
        fscanf( Pfile, "%d", Cg );

        c = fgetc( Pfile );                /* lecture de '\n' */
        c = fgetc( Pfile );                /* lecture de 'TP' */
        c = fgetc( Pfile );
        c = fgetc( Pfile );                /* lecture de '\n' */
        fscanf( Pfile, "%d", Tp );
        fclose(Pfile);
        }
else
   {
		/* parametres par defaut */

   *Rn = 13000;
   *Rp = 35000;
   *Cd = 8;
   *Cg = 4;
   *Tp = 1000;
   }
} 
