/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit :  NetOptim                                                   */
/*    Fichier :  no_global.c                                                */
/*                                                                          */
/*    (c) copyright 1992 Laboratoire MASI equipe CAO & VLSI                 */
/*    Tous droits reserves                                                  */
/*    Support : e-mail cao-vlsi@masi.ibp.fr                                 */
/*                                                                          */
/*    Auteur(s) : N. Dictus                             le : 28/10/1993     */
/*                                                                          */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*                                                                          */
/****************************************************************************/

#include <stdio.h>
#include MUT_H
#include LOG_H
#include MLO_H
#include BEH_H
#include "types_map.h"
#include "../net/no_type.h"
#include "../net/no_system.h"
#include "neto.h"
#include "../mapping/generic.h"
#include "no_optim.h"
#include "delai.h"

/*---------------------------------------------------------------------------
triFanout  : tri le fanout de inst en slack croissant
-----------------------------------------------------------------------------
retour : ptype_list triee en ordre croissant du slack minimum
---------------------------------------------------------------------------*/
ptype_list *triFanout(inst, conIn, sens)
loins_list *inst;
locon_list *conIn;
int sens;
{
ptype_list *userOut = (ptype_list *)NULL;
locon_list *conOut;
losig_list *sigOut;
ptype_list *liste;
chain_list *lstCon;
ptype_list *lstFanout = (ptype_list *)NULL;

if (inst)
   userOut = getptype(inst->USER, (long)LOCONOUT);
 
if (userOut)
   conOut = (locon_list *)userOut->DATA;
else
   if (conIn)
      conOut = conIn;
   else
      {
      if (inst)
         PRINTF("ERROR triFanout : No type LOCONOUT for %s\n", inst->INSNAME);
      exit(1);
      }

sigOut = conOut->SIG;
liste = getptype(sigOut->USER, (long)LOFIGCHAIN);

for(lstCon = (chain_list *)liste->DATA; lstCon; lstCon = lstCon->NEXT)
   {
   locon_list *conAux = (locon_list *)lstCon->DATA;

   if ((inst && (conAux->ROOT != (void *)inst)) || (conIn && (conAux != conIn)))
      {
      if (conAux->TYPE == INTERNAL)
             /* connecteur interne */
         if (conAux->DIRECTION == IN)
            {
            loins_list *cellOut = (loins_list *)conAux->ROOT;

                     /* portes attaquees par l'instance a traiter */
            long slack = MIN(getInfoInst(cellOut, SLACKUP), getInfoInst(cellOut, SLACKDW));
/*
            printf("Fanout de %s = %s (slack MIN = %d)\n",
                   inst->INSNAME, cellOut->INSNAME, slack);
*/
            lstFanout = tripType(lstFanout, slack, cellOut, sens);
            }
      }
   }
return lstFanout;
}

/*---------------------------------------------------------------------------
RAZTiming  : 
-----------------------------------------------------------------------------
retour : 
---------------------------------------------------------------------------*/
void RAZTiming(lofig, inst)
lofig_list *lofig;
loins_list *inst;
{
if (inst && (searchTH(RAZTH, inst->INSNAME) == EMPTYTH))
   {
   ptype_list *userOut = getptype(inst->USER, (long)LOCONOUT);
   losig_list *sigOut;
   ptype_list *liste;
   chain_list *lstCon;

/*
   printf("RAZ %s\n", inst->INSNAME);
*/
   addTH(RAZTH, inst->INSNAME, 1);

   if (userOut)
      {
      sigOut = ((locon_list *)userOut->DATA)->SIG;
      liste = getptype(sigOut->USER, (long)LOFIGCHAIN);
      }
   else
      {
      PRINTF("RAZTIMING : No type LOCONOUT for %s\n", inst->INSNAME);
      exit(1);
      }

   if (!liste)
      {
      PRINTF("ERROR : RAZTiming : No type LOFIGCHAIN for %s\n", inst->INSNAME);
      exit(1);
      }

   if (sigOut->USER && getptype(sigOut->USER, (long)DELAIUP))
      sigOut->USER = delptype(sigOut->USER, (long)DELAIUP);
   if (sigOut->USER && getptype(sigOut->USER, (long)DELAIDW))
      sigOut->USER = delptype(sigOut->USER, (long)DELAIDW);
   if (sigOut->USER && getptype(sigOut->USER, (long)PROF))
      sigOut->USER = delptype(sigOut->USER, (long)PROF);
   if (sigOut->USER && getptype(sigOut->USER, (long)TOTCAPA))
      sigOut->USER = delptype(sigOut->USER, (long)TOTCAPA);
   if (sigOut->USER && getptype(sigOut->USER, (long)LOINSUP))
      sigOut->USER = delptype(sigOut->USER, (long)LOINSUP);
   if (sigOut->USER && getptype(sigOut->USER, (long)LOINSDW))
      sigOut->USER = delptype(sigOut->USER, (long)LOINSDW);
   if (sigOut->USER && getptype(sigOut->USER, (long)LOCONUP))
      sigOut->USER = delptype(sigOut->USER, (long)LOCONUP);
   if (sigOut->USER && getptype(sigOut->USER, (long)LOCONDW))
      sigOut->USER = delptype(sigOut->USER, (long)LOCONDW);
   if (!sigOut->USER)
      printf("WARNING : RAZTiming = No USER for %s\n", inst->INSNAME);

    /* on  parcourt les connecteurs attaches au connecteur de sortie de inst */
   for(lstCon = (chain_list *)liste->DATA; lstCon; lstCon = lstCon->NEXT)
      {
      locon_list *conAux = (locon_list *)lstCon->DATA;
   
      if (conAux->ROOT != (void *)inst && conAux->TYPE == INTERNAL)
         {
         loins_list *fanout = (loins_list *)conAux->ROOT;

		/* on doit pouvoir memoriser les cellules sur lesquelles
	le menage est deja fait pour eviter les appels redondants ... TH */

         RAZTiming((lofig_list *)NULL, fanout);
         }
      }
   }

if (lofig)
   {
   loins_list *cell;

   for(cell = lofig->LOINS; cell; cell = cell->NEXT)
      {
      ptype_list *userOut = getptype(cell->USER, (long)LOCONOUT);
      losig_list *sigOut;
 
      if (userOut)
         sigOut = ((locon_list *)userOut->DATA)->SIG;
      else
         {
         PRINTF("RAZTIMING : No type LOCONOUT for %s\n", inst->INSNAME);
         exit(1);
         }

      if (sigOut->USER && getptype(sigOut->USER, (long)REQUIUP))
         {
         sigOut->USER = delptype(sigOut->USER, (long)REQUIUP);
         sigOut->USER = delptype(sigOut->USER, (long)REQUIDW);
         sigOut->USER = delptype(sigOut->USER, (long)SLACKUP);
         sigOut->USER = delptype(sigOut->USER, (long)SLACKDW);
         sigOut->USER = delptype(sigOut->USER, (long)CRITIC);
         }
      }
   }
}

/*---------------------------------------------------------------------------
puissanceLofig  : 
-----------------------------------------------------------------------------
retour : 
---------------------------------------------------------------------------*/
void puissanceLofig(limite)
int limite;
{
ptype_list *pinst;
int nbTraite = 0, nbIter = 0;
short OK = 1;
pTH puissanceTH = createTH(500);

PRINTF("\nPower Gate Optimization\n");

while (OK == 1)
   {
   OK = 0;
/*
   printf("--- ITERATION %d ---\n", nbIter);
*/

   nbTraite = 0;
   for(pinst = listeCritic; pinst && (nbTraite == 0); pinst = pinst->NEXT)
      {
      loins_list *inst = (loins_list *)pinst->DATA;
      cellList *model = (cellList *)searchTH(NO_CELLTH, inst->FIGNAME);
      locon_list *conOut = (locon_list *)getptype(inst->USER, (long)LOCONOUT)->DATA;
      long sCin = (long)getptype(conOut->SIG->USER, (long)TOTCAPA)->DATA;

      if ((searchTH(puissanceTH, inst->INSNAME) == EMPTYTH) && 
          (model->surface_tech->NEXT))
         {
	   /* il existe plusieurs versions de cette instance */
         ptype_list *modelPuissant;
         long delai = 0, delaiCon = 0, delaiPuissant;
         locon_list *con;
         char *modelMin = inst->FIGNAME;

		/* calcul du delai intrinseque de l'instance */
         for (con = inst->LOCON; con; con = con->NEXT)
            if ((con->DIRECTION == IN) && 
                !isvdd(con->NAME) && !isvss(con->NAME))
               {
               long rcUp = (cellLoadR(inst->FIGNAME, con->NAME, UP)   * sCin) / 1000;
               long rcDw = (cellLoadR(inst->FIGNAME, con->NAME, DOWN) * sCin) / 1000;

               switch (cellLoadPolarity(inst->FIGNAME))
                  {
                  case POS :
                     delaiCon= MAX (
                          (cellLoadTp(inst->FIGNAME, con->NAME, HH) + rcUp),
                          (cellLoadTp(inst->FIGNAME, con->NAME, LL) + rcDw));
                  case NEG :
                     delaiCon= MAX (
                          (cellLoadTp(inst->FIGNAME, con->NAME, LH) + rcUp),
                          (cellLoadTp(inst->FIGNAME, con->NAME, HL) + rcDw));
                  case AUT :
                     delaiCon= MAX (
                          MAX((cellLoadTp(inst->FIGNAME, con->NAME, LH) + rcUp),
                          (cellLoadTp(inst->FIGNAME, con->NAME, HH) + rcUp)),
                          MAX((cellLoadTp(inst->FIGNAME, con->NAME, HL) + rcDw),
                          (cellLoadTp(inst->FIGNAME, con->NAME, LL) + rcDw)));
                  }
               if (delaiCon > delai)
                  delai = delaiCon;
               }

         if (NO_TRACE >= 1)
            PRINTF("* Power for %s [%s] (critic = %d) sum Cin = %d delay = %d\n",
                   inst->INSNAME, inst->FIGNAME, pinst->TYPE, sCin, delai);

         delaiPuissant = delai;
         for(modelPuissant = model->surface_tech; modelPuissant; 
             modelPuissant = modelPuissant->NEXT)
            {
            long delaiIntrinseque = 0;
            char *nameModel = (char *)modelPuissant->DATA;

            if (nameModel != inst->FIGNAME)
               {
               for (con = inst->LOCON; con; con = con->NEXT)
                  if ((con->DIRECTION == IN) && 
                      !isvdd(con->NAME) && !isvss(con->NAME))
                     {
                     long delaiIntrinsequeCon = 0;
                     long delaiIntrinsequeConUp = 0;
                     long delaiIntrinsequeConDw = 0;
                     long rcUpPerte = 0;
                     long rcDwPerte = 0;
                     long rcUp = (cellLoadR(nameModel, con->NAME, UP)   *sCin) / 1000;
                     long rcDw = (cellLoadR(nameModel, con->NAME, DOWN) *sCin) / 1000;
                     ptype_list *gener = getptype(con->SIG->USER, (long)GENER);
                     loins_list *instGener;
   
                     if (gener)
                        {
                        long rUp;
                        long rDw;
                        long diffCin = cellLoadCin(nameModel, con->NAME) - cellLoadCin(inst->FIGNAME, con->NAME);
                        instGener = (loins_list *)gener->DATA;
                        rUp = cellLoadR(instGener->FIGNAME, (char *)NULL, UP);
                        rDw = cellLoadR(instGener->FIGNAME, (char *)NULL, DOWN);
                        rcUpPerte = (rUp * diffCin) / 1000;
                        rcDwPerte = (rDw * diffCin) / 1000;
/*
                        if (NO_TRACE >= 2)
                           printf("      porte genere = %s (diff = %d), perte UP = %d DW = %d\n", instGener->FIGNAME, diffCin, rcUpPerte, rcDwPerte);
*/
                        }
                     else
                        {
                        long rUp = resistanceNot(UP);
                        long rDw = resistanceNot(DOWN);
                        long diffCin = cellLoadCin(nameModel, con->NAME) - cellLoadCin(inst->FIGNAME, con->NAME);
                        rcUpPerte = (rUp * diffCin) / 1000;
                        rcDwPerte = (rDw * diffCin) / 1000;
/*
                        if (NO_TRACE >= 2)
                           printf("      connecteur E (diff = %d), perte UP = %d DW = %d\n", diffCin, rcUpPerte, rcDwPerte);
*/
                        }
                     switch (cellLoadPolarity(nameModel))
                        {
                        case POS :
                           delaiIntrinsequeConUp =
                              rcUpPerte + cellLoadTp(nameModel, con->NAME, HH) + rcUp;
                           delaiIntrinsequeConDw =
                              rcDwPerte + cellLoadTp(nameModel, con->NAME, LL) + rcDw;
                           break;
                        case NEG :
                           delaiIntrinsequeConUp =
                              rcDwPerte + cellLoadTp(nameModel, con->NAME, LH) + rcUp;
                           delaiIntrinsequeConDw =
                              rcUpPerte + cellLoadTp(nameModel, con->NAME, HL) + rcDw;
                           break;
                        case AUT :
                           delaiIntrinsequeConUp = MAX (
                              rcDwPerte + cellLoadTp(nameModel, con->NAME, LH) + rcUp,
                                    rcUpPerte + cellLoadTp(nameModel, con->NAME, HH) + rcUp);
                           delaiIntrinsequeConDw = MAX (
                              rcUpPerte + cellLoadTp(nameModel, con->NAME, HL) + rcDw,
                              rcDwPerte + cellLoadTp(nameModel, con->NAME, LL) + rcDw);
                           break;
                        }
                     delaiIntrinsequeCon = MAX( delaiIntrinsequeConUp, 
                                                delaiIntrinsequeConDw);
                     if (delaiIntrinsequeCon > delaiIntrinseque)
                         delaiIntrinseque = delaiIntrinsequeCon;
                     }
/*
                  if (NO_TRACE >= 2)
                     printf("    delai intrinseque [%s] = %d\n",
                            nameModel, delaiIntrinseque);
*/
                  if ((delaiIntrinseque < delai) && (delaiIntrinseque < delaiPuissant))
                     {
                     delaiPuissant = delaiIntrinseque;
                     modelMin = nameModel;
                     }
               }
            }
         if (inst->FIGNAME != modelMin)
            {
            long gain = delai - delaiPuissant;

            if (((pinst->TYPE == 0) && (gain >= limite)) || 
                ((pinst->TYPE != 0) && (gain >= limite*nbIter)))
               {
               if (NO_TRACE >= 3)
                  displayTimingInst(inst, 0);
               PRINTF("    ==> Model to use for %s [%s] : %s\n", inst->INSNAME, inst->FIGNAME, modelMin);
               inst->FIGNAME = modelMin;
               addTH(puissanceTH, inst->INSNAME, 1);
               nbTraite++;
               calcul_delai(NO_LOG, 0);
               calcul_requi(NO_LOG, delaiCriticUp, delaiCriticDw, 1);
               if (NO_TRACE == 2)
                  displayTimingInst(inst, 0);
               OK = 1;
               }
            }
/*
         else
            PRINTF("    ==> Modele a utiliser : %s\n", modelMin);
*/
         }
      else
         if (NO_TRACE >= 3)
            printf("No power model for %s [%s]\n",
                   inst->INSNAME, inst->FIGNAME);
      }   /* parcours des instances de la lofig */
   nbIter++;
   }      /* while OK */
destroyTH(puissanceTH);
}

/*---------------------------------------------------------------------------
checheBuffer: 
-----------------------------------------------------------------------------
retour : 
---------------------------------------------------------------------------*/
void chercheBuffer(porteCritic, type)
loins_list *porteCritic;
long type;
{
loins_list *porte = porteCritic;
loins_list *porteSuiv = porteCritic;
ptype_list *chemin;
short continu = 1;

/*
printf("Cherche BUFFER %s : ", (type == UP)?"UP":"DW");
PRINTI("<-%s[%s]", porte->INSNAME, porte->FIGNAME);
*/
while (continu && (chemin = getptype(porte->USER, (long)((type == UP)?LOINSUP:LOINSDW))))
   if (chemin)
      {
      if ((type== UP) && (cellLoadPolarity(porte->FIGNAME) == NEG))
         type= DOWN;
      else
         if ((type== DOWN) && (cellLoadPolarity(porte->FIGNAME) == NEG))
            type= UP;
      porteSuiv = porte;
      porte = (loins_list *)chemin->DATA;
/*
      PRINTI("<-%s[%s]", porte->INSNAME, porte->FIGNAME);
*/
      if (cellLoadType(porte->FIGNAME) == BUFF)
         {
         losig_list *buffSigOut = ((locon_list *)getptype(porte->USER, (long)LOCONOUT)->DATA)->SIG;
         locon_list *conInSuiv, *con;
         locon_list *conOut = (locon_list *)getptype(porte->USER, (long)LOCONOUT)->DATA;
         ptype_list *liste = getptype(conOut->SIG->USER, (long)LOFIGCHAIN);
         ptype_list *critic = getptype(porte->USER, (long)LOINSUP);
         chain_list *lstCon;
         locon_list *conOutCritic;
         ptype_list *listeCritic;
         long cinBuff = (long)getptype(conOut->SIG->USER, (long)TOTCAPA)->DATA;
         long retardBuffUp = cellLoadTp(porte->FIGNAME, cellLoadIn(porte->FIGNAME)->name, HH) + ((cellLoadR(porte->FIGNAME, cellLoadIn(porte->FIGNAME)->name, UP) * cinBuff) / 1000);
         long retardBuffDw = cellLoadTp(porte->FIGNAME, cellLoadIn(porte->FIGNAME)->name, LL) + ((cellLoadR(porte->FIGNAME, cellLoadIn(porte->FIGNAME)->name, DOWN) * cinBuff) / 1000);
         long retardBuff = MAX(retardBuffUp, retardBuffDw);
         ptype_list *triFan, *triFanBuff, *tri;

         PRINTI("  BUFFER(Suiv %s)\n  ", porteSuiv->INSNAME);
         displayTimingInst(porte, 0);

         if (!critic)
            {
		/* connecteur d'entree attaque le buffer */
            conOutCritic = (locon_list *)getptype(porte->USER, (long)LOCONUP)->DATA;
            triFan = triFanout((loins_list *)NULL, conOutCritic, DOWN);
            }
         else
            {
            conOutCritic = (locon_list *)getptype(((loins_list *)critic->DATA)->USER, (long)LOCONOUT)->DATA;
            triFan = triFanout((loins_list *)critic->DATA, (locon_list *)NULL, DOWN);
            }

         listeCritic = getptype(conOutCritic->SIG->USER, (long)LOFIGCHAIN);

         if (critic)
            printf("Fanout of %s\n", ((loins_list *)critic->DATA)->INSNAME);
         else
            printf("Fanout of input %s\n", conOutCritic->NAME);
/*
         for(lstCon = (chain_list *)listeCritic->DATA; lstCon; lstCon = lstCon->NEXT)
            {
            locon_list *conAux = (locon_list *)lstCon->DATA;

            if (conAux->ROOT != (void *)porte)
               if (conAux->TYPE == INTERNAL)
                  if (conAux->DIRECTION == IN)
                     {
                     loins_list *cellOut = (loins_list *)conAux->ROOT;
                     locon_list *conOut = (locon_list *)getptype(cellOut->USER, (long)LOCONOUT)->DATA;
                     ptype_list *slackUp = getptype(conOut->SIG->USER, (long)SLACKUP);
                     ptype_list *slackDw = getptype(conOut->SIG->USER, (long)SLACKDW);
   
                     printf("Slack of %s : Up = %d - Dw = %d\n", cellOut->INSNAME,
(long)slackUp->DATA, (long)slackDw->DATA);
                     }
            }
*/

         tri = triFan;
         while (tri && tri->TYPE > retardBuff)
            {
            loins_list *cellFan = (loins_list *)tri->DATA;

            printf("retardBuff = %d (cin = %d) - slack of %s = %d\n", retardBuff, cinBuff, 
                  cellFan->INSNAME, tri->TYPE);
            if (critic)
               {
               for(con = cellFan->LOCON; con; con = con->NEXT)
                  if (con->SIG == conOutCritic->SIG)
                     cinBuff += cellLoadCin(cellFan->FIGNAME, con->NAME);
               }
            else
               cinBuff += cellLoadCin((char *)NULL, conOutCritic->NAME);
            retardBuffUp = cellLoadTp(porte->FIGNAME, cellLoadIn(porte->FIGNAME)->name, HH) + ((cellLoadR(porte->FIGNAME, cellLoadIn(porte->FIGNAME)->name, UP) * cinBuff) / 1000);
            retardBuffDw = cellLoadTp(porte->FIGNAME, cellLoadIn(porte->FIGNAME)->name, LL) + ((cellLoadR(porte->FIGNAME, cellLoadIn(porte->FIGNAME)->name, DOWN) * cinBuff) / 1000);
            retardBuff = MAX(retardBuffUp, retardBuffDw);
            tri= tri->NEXT;
            }
         if (tri&& tri->NEXT)
            {
            freeptype(tri->NEXT);
            tri->NEXT = NULL;
            }

         printf("Fanout of %s\n", porte->INSNAME);
         triFanBuff = triFanout(porte, (locon_list *)NULL, UP);

/*
         for(lstCon = (chain_list *)liste->DATA; lstCon; lstCon = lstCon->NEXT)
            {
            locon_list *conAux = (locon_list *)lstCon->DATA;

            if (conAux->ROOT != (void *)porte)
               if (conAux->TYPE == INTERNAL)
                  if (conAux->DIRECTION == IN)
                     {
                     loins_list *cellOut = (loins_list *)conAux->ROOT;
                     locon_list *conOut = (locon_list *)getptype(cellOut->USER, (long)LOCONOUT)->DATA;
                     ptype_list *slackUp = getptype(conOut->SIG->USER, (long)SLACKUP);
                     ptype_list *slackDw = getptype(conOut->SIG->USER, (long)SLACKDW);
                
                     printf("Slack of %s : Up = %d - Dw = %d\n", cellOut->INSNAME, (long)slackUp->DATA, (long)slackDw->DATA);
                     }
            }
*/

         tri = triFanBuff;
         while (tri && (tri->TYPE < retardBuff / 4))
            {
            printf("porte %s slack = %d\n", ((loins_list *)tri->DATA)->INSNAME, tri->TYPE);
		/* on deconnecte le chemin critique du buffer */
            for(con = ((loins_list *)tri->DATA)->LOCON; con; con = con->NEXT)
               if ((con->DIRECTION == IN) && (con->SIG == buffSigOut))
                  conInSuiv = con; 
            for(con = porte->LOCON; con; con = con->NEXT)
               if ((con->DIRECTION == IN) && !isvdd(con->NAME) && !isvss(con->NAME))
                  conInSuiv->SIG = con->SIG; 
            tri = tri->NEXT;
            }
         freeptype(triFanBuff);

		/* on connecte triFan au buffer */
         for(tri = triFan; tri; tri = tri->NEXT)
            {
            loins_list *cellFan = (loins_list *)tri->DATA;

            for(con = cellFan->LOCON; con; con = con->NEXT)
               if (con->SIG == conOutCritic->SIG)
                  con->SIG = conOut->SIG;

            }

         calcul_delai(NO_LOG, 2);
         calcul_requi(NO_LOG, delaiCriticUp, delaiCriticDw, 0);
         continu = 0;
         }
      }
printf("\n");
}

/*---------------------------------------------------------------------------
insereBuffer : 
-----------------------------------------------------------------------------
retour : 
---------------------------------------------------------------------------*/
void insereBuffer(instTraite, conIn, pOk, pEncore, minFan, nameBuff)
loins_list *instTraite;
locon_list *conIn;
short *pOk, *pEncore;
int minFan;
char *nameBuff;
{
ptype_list *pt, *p;
int nbFan = 0;
ptype_list *triFan;


if (instTraite)
   triFan = triFanout(instTraite, (locon_list *)NULL, UP);
else
   triFan = triFanout((loins_list *)NULL, conIn, UP);
   
for(pt = triFan; pt && (nbFan < minFan); pt = pt->NEXT)
   nbFan++;

if (nbFan >= minFan)
   {
   ptype_list *tri, *t;
   loins_list *instDirect =  (loins_list *)triFan->DATA;
   ptype_list *fanoutInst = addptype((ptype_list *)NULL,
                                        triFan->TYPE, triFan->DATA);
   long chargeBuff = 0;
   long retardBuffDw;
   long retardBuffUp;
   long retardBuff;
   int nbChargeBuff = 0;
   locon_list *con;
   short continu = 1;
   short nbDirect = 1;
   losig_list *sigOut;
   long sCin;
   long ROutUp;
   long ROutDw;

   if (instTraite)
      {
      sigOut = ((locon_list *)getptype(instTraite->USER, (long)LOCONOUT)->DATA)->SIG;
      ROutUp = cellLoadR(instTraite->FIGNAME, (char *)NULL, UP);
      ROutDw = cellLoadR(instTraite->FIGNAME, (char *)NULL, DOWN);
      }
   else
      {
      sigOut = conIn->SIG;
      ROutUp = resistanceNot(UP);
      ROutDw = resistanceNot(DOWN);
      }
   sCin = (long)getptype(sigOut->USER, (long)TOTCAPA)->DATA;

   for(con = ((loins_list *)triFan->DATA)->LOCON; con; con = con->NEXT)
      if (con->SIG == sigOut)
         chargeBuff = sCin - cellLoadCin(instDirect->FIGNAME, con->NAME);

/*
   if (instTraite)
      printf("  sur %s[%s] capa %d : %s[%s] slack %d-...",
             instTraite->INSNAME, instTraite->FIGNAME, sCin,
             ((loins_list *)triFan->DATA)->INSNAME,
             ((loins_list *)triFan->DATA)->FIGNAME,
             triFan->TYPE);
   else
      printf("  sur %s capa %d : %s[%s] slack %d-...",
             conIn->NAME, sCin,
             ((loins_list *)triFan->DATA)->INSNAME,
             ((loins_list *)triFan->DATA)->FIGNAME,
             triFan->TYPE);
*/

   tri = triFan->NEXT;

   while (tri && continu)
      {
      long cin = 0;
      char *inBuff = cellLoadIn(nameBuff)->name;
      instDirect =  (loins_list *)tri->DATA;

      for(con = instDirect->LOCON; con; con = con->NEXT)
         if (con->SIG == sigOut)
            cin = cellLoadCin(instDirect->FIGNAME, con->NAME);

      retardBuffUp = ((cellLoadR(nameBuff, inBuff, UP) * chargeBuff) -
                      (ROutUp * cin)) / 1000 +
                     cellLoadTp(nameBuff, inBuff, HH);
      retardBuffDw = ((cellLoadR(nameBuff, inBuff, DOWN) * chargeBuff) -
                      (ROutDw * cin)) / 1000 +
                     cellLoadTp(nameBuff, inBuff, LL);
      retardBuff = MAX(retardBuffUp , retardBuffDw);

      if (NO_TRACE >= 3)
         printf(" Gate %s (slack %d) delay = %d\n",
                ((loins_list *)tri->DATA)->INSNAME, tri->TYPE, retardBuff);
      if (tri->TYPE < retardBuff)
         {
/*
         printf(" %s %d-", ((loins_list *)tri->DATA)->INSNAME, tri->TYPE);
*/
         fanoutInst = addptype(fanoutInst, tri->TYPE, tri->DATA);
         chargeBuff -= cin;
         nbDirect++; 
         tri = tri->NEXT;
         }
      else
         continu = 0;
      }

/*
   printf(" %d fanouts\n", nbDirect);
   printf("\n     sur %s :", nameBuff);
*/
   if (tri)
      {
      t = tri;
/*
      printf(" %s %d-", ((loins_list *)t->DATA)->INSNAME, t->TYPE);
*/
      while (t)
         {
         nbChargeBuff++;
         t = t->NEXT;
         }
/*
      if (nbChargeBuff > 1)
         printf(" ..... buff fanout = %d\n", nbChargeBuff);
      else
         printf("\n");
*/
      }
   freeptype(triFan);

          /* ajout d'un buffer conditionnel */
   if (nbChargeBuff > 1)
      {
      if (instTraite)
         addBufferCond(NO_LOG, instTraite, (locon_list *)NULL, nameBuff, fanoutInst);
      else
         addBufferCond(NO_LOG, (loins_list *)NULL, conIn, nameBuff, fanoutInst);

      freeptype(fanoutInst);
      *pOk = 0;
      *pEncore = 1;

          /* remise a jour des retards */
      calcul_delai(NO_LOG, 0);
      calcul_requi(NO_LOG, delaiCriticUp, delaiCriticDw, 0);
/*
      if (delaiCriticUp > delaiCriticDw)
         chercheBuffer(porteCriticUp, UP);
      else
         chercheBuffer(porteCriticDw, DOWN);
*/
      }
   }
}

/*---------------------------------------------------------------------------
bufferLofig  : 
-----------------------------------------------------------------------------
retour : 
---------------------------------------------------------------------------*/
void bufferLofig(minFanIn, minFanInst)
int minFanIn, minFanInst;
{
cellList *cells = NO_CELLS;

while (cells && cells->type != 't')
   cells = cells->NEXT;
if (cells)
   {
   ptype_list *cellsPhy;
   long minR = 9999999;
   char *nameBuff = (char *)NULL;
   short fois = 0;
   short OK = 1, encore = 1;

   PRINTF("\nBuffer Optimization\n");
	/* on choisit le buffer le moins resistif */
   for(cellsPhy = cells->resistance_tech; cellsPhy;
       cellsPhy=cellsPhy->NEXT)
      {
      char *nameCellsPhy = (char *)cellsPhy->DATA;
      long ROutUp = cellLoadR(nameCellsPhy, (char *)NULL, UP);
      if (ROutUp < minR)
         {
         minR = ROutUp;
         nameBuff = nameCellsPhy;
         }
      }

   assignTH = createTH(50);

   while (encore)
      {
      ptype_list *p;
      int val;
      long oldDelaiUp = delaiCriticUp;
      long oldDelaiDw = delaiCriticDw;

      OK = 1;
      encore = 0;

	   /* traitement de l'entree */
      if (listeCritic->DATA)
         if ((val = searchTH(assignTH, ((locon_list *)listeCritic->DATA)->NAME)) < 2)
            {
            if (val == EMPTYTH)
               val = 0;
            addTH(assignTH, ((locon_list *)listeCritic->DATA)->NAME, val+1);
            insereBuffer((loins_list *)NULL, (locon_list *)listeCritic->DATA, &OK, 
                         &encore, minFanIn, nameBuff);
            }

	/* traitement des instances */
      for(p = listeCritic->NEXT; p && OK; p = p->NEXT)
         {
         loins_list *instTraite = (loins_list *)p->DATA;

/*
         displayTimingInst(instTraite, 0);
*/
         insereBuffer(instTraite, (locon_list *)NULL, &OK, &encore, minFanInst, nameBuff);
         }
/*
      displayLofig(NO_LOG, 4);
*/
      if (((oldDelaiUp - delaiCriticUp) + (oldDelaiDw - delaiCriticDw)) < 200)
         fois++;
      else
         fois = 0;
      if (fois >= 4)
         encore = 0;
/*
      printf("fois = %d\n", fois);
*/
      }
   destroyTH(assignTH);
   }
}
