/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit :  NetOptim                                                   */
/*    Fichier :  no_optim.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 : 10/04/1992     */
/*                                                                          */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*                                                                          */
/****************************************************************************/

#include <stdio.h>
#include MUT_H
#include MLO_H
#include LOG_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 "delai.h"
#include "no_optim.h"
#include "no_global.h"

/*---------------------------------------------------------------------------
addmodel        : ajoute un modele s'il n'existe pas dans la liste des modeles
-----------------------------------------------------------------------------
retour          : chain_list * des modeles
---------------------------------------------------------------------------*/
chain_list *addmodel(liste, modele)
chain_list *liste;
char *modele;
{
chain_list *l;

for(l = liste; l; l = l->NEXT)
   if (modele == (char *)l->DATA)
      return liste;
return addchain(liste, (void *)modele);
}

/*---------------------------------------------------------------------------
clearmodel : remet a jour la liste des modeles
-----------------------------------------------------------------------------
retour     : chain_list * des modeles utilises dans la lofig
---------------------------------------------------------------------------*/
void clearmodel(ptfig)
lofig_list *ptfig;
{
loins_list *liste;

freechain(ptfig->MODELCHAIN);
ptfig->MODELCHAIN = (chain_list *)NULL;

for(liste = ptfig->LOINS; liste; liste = liste->NEXT)
   ptfig->MODELCHAIN = addmodel(ptfig->MODELCHAIN, liste->FIGNAME);
}

/*---------------------------------------------------------------------------
adaptePuissance : recherche la porte la plus appropriee parmi les cellules phy
                  fanout >= sCin & surface minimale
-----------------------------------------------------------------------------
retour          : char * = le nom de modele de la porte puissante
---------------------------------------------------------------------------*/
char *adaptePuissance(liste, sCin)
cellList *liste;
long sCin;
{
char *porteOK = (char *)(liste->resistance_tech->DATA);
int cout = cellLoadSurface(porteOK);
int minDiff = cellLoadFanout(porteOK) - sCin;
ptype_list *p;

for(p = liste->resistance_tech->NEXT; p; p = p->NEXT)
      {
      int diff = cellLoadFanout((char *)p->DATA) - sCin;

      if (diff >= 0)
         {
                /* cellule resoud le probleme */
         if (minDiff < 0)
            {
            minDiff = diff;
            cout = cellLoadSurface((char *)p->DATA);
            porteOK = (char *)p->DATA;
            }
         else
           if (cellLoadSurface((char *)p->DATA) < cout)
              {
              minDiff = diff;
              cout = cellLoadSurface((char *)p->DATA);
              porteOK = (char *)p->DATA;
              }
            else
              if (cellLoadSurface((char *)p->DATA) == cout)
                 if (cellLoadFanout((char *)p->DATA) < cellLoadFanout(porteOK))
                    {
                        /* si surface egale alors plus petit fanout */
                    minDiff = diff;
                    cout = cellLoadSurface((char *)p->DATA);
                    porteOK = (char *)p->DATA;
                    }
         }
      else
         if ((minDiff < 0) && (diff > minDiff))
            {
            minDiff = diff;
            cout = cellLoadSurface((char *)p->DATA);
            porteOK = (char *)p->DATA;
            }
      }
return porteOK;
}

/*---------------------------------------------------------------------------
addPuissante    : remplace par une porte puissante
-----------------------------------------------------------------------------
retour          : void
---------------------------------------------------------------------------*/
void addPuissante(ptfig, inst, puissante)
lofig_list *ptfig;
loins_list *inst;
char *puissante;
{
PRINTF("    ==> POWER GATE %s [%s / area = %d / fanout = %d]\n",inst->INSNAME,
       puissante, cellLoadSurface(puissante), cellLoadFanout(puissante));
inst->FIGNAME = puissante;

ptfig->MODELCHAIN = addmodel(ptfig->MODELCHAIN, puissante);
}

/*---------------------------------------------------------------------------
addBufferCond       : Ajout d'un buffer conditionnel
-----------------------------------------------------------------------------
retour          : instance du buffer ajoute
---------------------------------------------------------------------------*/
loins_list *addBufferCond(ptfig, inst, conIn, nameBuff, listeCond)
lofig_list *ptfig;
loins_list *inst;       /* instance apres laquelle on ajoute le buffer ou NULL*/
locon_list *conIn;      /* connecteur IN apres lequel on ajoute le buffer */
char *nameBuff;         /* nom du modele du buffer a ajouter */
ptype_list *listeCond;	/* liste des instances a ne pas bufferisees */
{
lofig_list *figBuffer = getlofig(nameBuff,'P');
losig_list *newSig;
locon_list *conAux;
locon_list *conBuffer;
chain_list *signal = (chain_list *)NULL;
ptype_list *l;
loins_list *instBuf;
int cinBuff = 0;
losig_list *oldSig;

        /* calcul du 1er index non utilise */
indexMaximum++;

                        /* creation d'un nouveau signal */
newSig = addlosig(ptfig, indexMaximum,
                        addchain((chain_list *)NULL,
                                 (void *)genNAME("netops%d",indexMaximum)),
                        INTERNAL, 0.0);

/* DEBUG
if (inst)
   {
   printf("INST %s [%s]\n", inst->INSNAME, inst->FIGNAME);
   for(conBuffer = inst->LOCON; conBuffer ; conBuffer = conBuffer->NEXT)
      printf("con : %s == %s (%d)\n",conBuffer->NAME,
             conBuffer->SIG->NAMECHAIN->DATA, conBuffer->SIG->INDEX);
   }
*/

   /* creation de la liste des signaux attaches aux connecteurs du buffer */
for(conBuffer = figBuffer->LOCON; conBuffer; conBuffer = conBuffer->NEXT)
   if (isvdd(conBuffer->NAME) || isvss(conBuffer->NAME))
      {
      conBuffer->DIRECTION = IN;

        /* recherche des signaux vss ou vdd dans inst */

      if (inst)
         {
         for(conAux = inst->LOCON; conAux; conAux = conAux->NEXT)
            if (((isvdd(getsigname(conAux->SIG))) && isvdd(conBuffer->NAME)) ||
                ((isvss(getsigname(conAux->SIG))) && isvss(conBuffer->NAME)))
               signal = addchain(signal, (void *)conAux->SIG);
         }
      else
         {
         conAux = ptfig->LOCON;
         while (conAux &&
                !((isvdd(getsigname(conAux->SIG)) && 
                  isvdd(conBuffer->NAME))  ||
                 (isvss(getsigname(conAux->SIG)) && 
                  isvss(conBuffer->NAME))))
           conAux = conAux->NEXT;
         if (conAux)
            signal = addchain(signal, (void *)conAux->SIG);
         else
            {
            printf("ERROR : no VDD or VSS in %s\n", ptfig->NAME);
            exit(1);
            }
         }
      }
   else
      {
      chain_list *out = cellLoadOut(figBuffer->NAME);
      Alist      *in  =  cellLoadIn(figBuffer->NAME);
      locon_list *con;

      if (memberChain_list(conBuffer->NAME,out))
         {
                /* connecteur de sortie */
         conBuffer->DIRECTION = OUT;
         if (inst)
            {
                /* on ajoute un buffer apres une instance */
            for(con = inst->LOCON; con ; con = con->NEXT)
               if (con->DIRECTION == OUT)
                  {
                  oldSig = con->SIG;
                  signal = addchain(signal, (void *)oldSig);
                  con->SIG = newSig;
                  newSig->USER = addptype((ptype_list *)NULL, (long)GENER, (void *)inst);
                  }
            }
         else
            {
                    /* on ajoute un buffer apres un connecteur */
            oldSig = conIn->SIG;
                  /* Inversion des noms et index de signaux (bug du driver) */
            freechain(newSig->NAMECHAIN);
            newSig->NAMECHAIN = addchain((chain_list *)NULL, conIn->SIG->NAMECHAIN->DATA);
            newSig->INDEX = conIn->SIG->INDEX;
            freechain(conIn->SIG->NAMECHAIN);
            conIn->SIG->INDEX = indexMaximum;
            conIn->SIG->NAMECHAIN = addchain((chain_list *)NULL,
                                       (void *)genNAME("netops%d",indexMaximum));

            conIn->SIG->TYPE = INTERNAL;
            signal = addchain(signal, (void *)(conIn->SIG));
            conIn->SIG = newSig;
            conIn->SIG->TYPE = EXTERNAL;
            }
         }
      else
         {
                /* connecteur d'entree */
         cinBuff = cellLoadCin(nameBuff, conBuffer->NAME);
         conBuffer->DIRECTION = IN;
         if (memberAlist(conBuffer->NAME,in))
            signal = addchain(signal, (void *)(newSig));
         }
      }

        /* remise a jour de l'ordre des connecteurs */
signal = reverse(signal);

        /* verif !!!!
if (1)
   {
   chain_list *s;

   printf("BUFFER %s \n", figBuffer->NAME);
   for(conBuffer = figBuffer->LOCON,s = signal; conBuffer && s;
       conBuffer = conBuffer->NEXT, s = s->NEXT)
         printf("con : %s == %s (%d)\n",conBuffer->NAME,
                (char *)(((losig_list *)(s->DATA))->NAMECHAIN->DATA),
                (char *)(((losig_list *)(s->DATA))->INDEX));
   }

if (inst)
   {
   printf("INST %s [%s]\n", inst->INSNAME, inst->FIGNAME);
   for(conBuffer = inst->LOCON; conBuffer ; conBuffer = conBuffer->NEXT)
      printf("con : %s == %s (%d)\n",conBuffer->NAME,
             conBuffer->SIG->NAMECHAIN->DATA, conBuffer->SIG->INDEX);
   }
*/

        /* mise a jour de la capa de l'instance */
newSig->CAPA = (float)cinBuff / 1000;

        /* ajout du buffer dans la lofig */
instBuf = addloins(ptfig, namealloc((char *)genNAME("netopi%d",indexMaximum)),
                         figBuffer, signal);
	/* recherche du connecteur de sortie du buffer */
for(conBuffer = instBuf->LOCON; conBuffer; conBuffer = conBuffer->NEXT)
   if (conBuffer->DIRECTION == OUT)
      instBuf->USER = addptype((ptype_list *)NULL, (long)LOCONOUT,
                               (void *)conBuffer);

if (inst)
   oldSig->USER = addptype((ptype_list *)NULL, (long)GENER, (void *)instBuf);

	/* on remet les instances de listeCond a la sortie de inst */
for(l = listeCond; l; l= l->NEXT)
   {
/*
   printf("  %s\n", ((loins_list *)l->DATA)->INSNAME);
*/
   for(conAux = ((loins_list *)l->DATA)->LOCON; conAux; conAux = conAux->NEXT)
      if (conAux->DIRECTION == IN && conAux->SIG == oldSig)
         conAux->SIG = newSig;
   }

        /* Affichage */
if (inst)
   PRINTF("    ==> BUFFER added after %s : %s [%s / area = %d]\n",
          inst->INSNAME,
          instBuf->INSNAME,
          nameBuff,
          cellLoadSurface(nameBuff));
else
   PRINTF("    ==> BUFFER added after input %s : %s [%s / area = %d]\n",
          conIn->NAME,
          instBuf->INSNAME,
          nameBuff,
          cellLoadSurface(nameBuff));

        /* chainages signaux -> connecteurs */

freechain(signal);
lofigchain(ptfig);
dellofig(figBuffer->NAME);
return instBuf;
}

/*---------------------------------------------------------------------------
addBuffer       : Ajout d'un buffer
-----------------------------------------------------------------------------
retour          : instance du buffer ajoute
---------------------------------------------------------------------------*/
loins_list *addBuffer(ptfig, inst, conIn, nameBuff)
lofig_list *ptfig;
loins_list *inst;       /* instance apres laquelle on ajoute le buffer ou NULL*/
locon_list *conIn;      /* connecteur IN apres lequel on ajoute le buffer */
char *nameBuff;         /* nom du modele du buffer a ajouter */
{
lofig_list *figBuffer = getlofig(nameBuff,'P');
losig_list *newSig;
locon_list *conAux;
locon_list *conBuffer;
chain_list *signal = (chain_list *)NULL;
loins_list *instBuf;
int cinBuff = 0;


        /* calcul du 1er index non utilise */
indexMaximum++;
                        /* creation d'un nouveau signal */
newSig = addlosig(ptfig, indexMaximum,
                        addchain((chain_list *)NULL,
                           (void *)genNAME("netops%d",indexMaximum)),
                        INTERNAL, 0.0);
/*
if (inst)
   {
   printf("INST %s [%s]\n", inst->INSNAME, inst->FIGNAME);
   for(conBuffer = inst->LOCON; conBuffer ; conBuffer = conBuffer->NEXT)
      printf("con : %s == %s (%d)\n",conBuffer->NAME,
             conBuffer->SIG->NAMECHAIN->DATA, conBuffer->SIG->INDEX);
   }

printf("indexMaximum = %d\n", indexMaximum);
*/

   /* creation de la liste des signaux attaches aux connecteurs du buffer */
for(conBuffer = figBuffer->LOCON; conBuffer; conBuffer = conBuffer->NEXT)
   if (isvdd(conBuffer->NAME) || isvss(conBuffer->NAME))
      {
      conBuffer->DIRECTION = IN;

        /* recherche des signaux vss ou vdd dans inst */

      if (inst)
         {
         for(conAux = inst->LOCON; conAux; conAux = conAux->NEXT)
            if (((isvdd(getsigname(conAux->SIG))) && isvdd(conBuffer->NAME)) ||
                ((isvss(getsigname(conAux->SIG))) && isvss(conBuffer->NAME)))
               signal = addchain(signal, (void *)conAux->SIG);
         }
      else
         {
         conAux = ptfig->LOCON;
         while (conAux &&
                !((isvdd((char *)(conAux->SIG->NAMECHAIN->DATA)) && 
                  isvdd(conBuffer->NAME))  ||
                 (isvss((char *)(conAux->SIG->NAMECHAIN->DATA)) && 
                  isvss(conBuffer->NAME))))
           conAux = conAux->NEXT;
         if (conAux)
            signal = addchain(signal, (void *)conAux->SIG);
         else
            {
            printf("not found\n");
            exit(1);
            }
         }
      }
   else
      {
      chain_list *out = cellLoadOut(figBuffer->NAME);
      Alist      *in  =  cellLoadIn(figBuffer->NAME);
      locon_list *con;

      if (memberChain_list(conBuffer->NAME,out))
         {
                /* connecteur de sortie */
         conBuffer->DIRECTION = OUT;
         if (inst)
            {
                /* on ajoute un buffer apres une instance */
            for(con = inst->LOCON; con ; con = con->NEXT)
               if (con->DIRECTION == OUT)
                  {
                  signal = addchain(signal, (void *)(con->SIG));
                  con->SIG = newSig;
                  }
            }
         else
            {
                    /* on ajoute un buffer apres un connecteur */
        /* Inversion des noms et des index de signaux (bug du driver ...) */
            freechain(newSig->NAMECHAIN);
            newSig->NAMECHAIN = addchain((chain_list *)NULL, conIn->SIG->NAMECHAIN->DATA);
            newSig->INDEX = conIn->SIG->INDEX;
            freechain(conIn->SIG->NAMECHAIN);
            conIn->SIG->INDEX = indexMaximum;
            conIn->SIG->NAMECHAIN = addchain((chain_list *)NULL,
                                       (void *)genNAME("netops%d",indexMaximum));
            conIn->SIG->TYPE = INTERNAL;
            signal = addchain(signal, (void *)(conIn->SIG));
            conIn->SIG = newSig;
            conIn->SIG->TYPE = EXTERNAL;
            }
         }
      else
         {
                /* connecteur d'entree */
         cinBuff = cellLoadCin(nameBuff, conBuffer->NAME);
         conBuffer->DIRECTION = IN;
         if (memberAlist(conBuffer->NAME,in))
            signal = addchain(signal, (void *)(newSig));
         }
      }

        /* remise a jour de l'ordre des connecteurs */
signal = reverse(signal);

        /* verif !!!!
if (1)
   {
   chain_list *s;

   printf("BUFFER %s \n", figBuffer->NAME);
   for(conBuffer = figBuffer->LOCON,s = signal; conBuffer && s;
       conBuffer = conBuffer->NEXT, s = s->NEXT)
         printf("con : %s == %s (%d)\n",conBuffer->NAME,
                (char *)(((losig_list *)(s->DATA))->NAMECHAIN->DATA),
                (char *)(((losig_list *)(s->DATA))->INDEX));
   }

if (inst)
   {
   printf("INST %s [%s]\n", inst->INSNAME, inst->FIGNAME);
   for(conBuffer = inst->LOCON; conBuffer ; conBuffer = conBuffer->NEXT)
      printf("con : %s == %s (%d)\n",conBuffer->NAME,
             conBuffer->SIG->NAMECHAIN->DATA, conBuffer->SIG->INDEX);
   }
*/

        /* mise a jour de la capa de l'instance */
newSig->CAPA = (float)cinBuff / 1000;

        /* ajout du buffer dans la lofig */
instBuf = addloins(ptfig, namealloc(genNAME("netopi%d",indexMaximum)),
                         figBuffer, signal);

addTH(dejaTraite, (char *)namealloc(genNAME("netopi%d", indexMaximum)), 1);

        /* Affichage */
if (inst)
   PRINTF("    ==> BUFFER added after %s : %s [%s / area = %d]\n",
          inst->INSNAME,
          instBuf->INSNAME,
          nameBuff,
          cellLoadSurface(nameBuff));
else
   PRINTF("    ==> BUFFER added after %s : %s [%s / area = %d]\n",
          conIn->NAME,
          instBuf->INSNAME,
          nameBuff,
          cellLoadSurface(nameBuff));

        /* chainages signaux -> connecteurs */

lofigchain(ptfig);
dellofig(figBuffer->NAME);

/*
NO_LOG->NAME = NO_FILEOUT;
printf("Saving %s/%s...\n",NO_LOG_LIB, NO_LOG->NAME);
savelofig(NO_LOG);
*/

return instBuf;
}

/*---------------------------------------------------------------------------
dupliqueInst    : duplique une instance de porte (nb fois)
-----------------------------------------------------------------------------
retour          : void (insertion d'instances dans la lofig)
---------------------------------------------------------------------------*/
void dupliqueInst(ptfig, inst, solution)
lofig_list *ptfig;
loins_list *inst;       /* instance a dupliquer */
sol_list *solution;
{
locon_list *conFig, *conI, *conF;
int nbExt = 0;
losig_list *sigOut = NULL;
ptype_list *fan, *instDupl, *p;

indexMaximum++;

if (inst->FIGNAME != (char *)solution->NAME->DATA)
   addPuissante(ptfig, inst, (char *)solution->NAME->DATA);

PRINTF("    ==> %d DUPLICATION%s of %s ", solution->NOMBRE-1,
       (solution->NOMBRE-1>1)?"S":"", inst->INSNAME);
fflush(stdout);

        /* MAJ de la capa sur signal de sortie de l'instance a dupliquer */
for(conFig = inst->LOCON; conFig ; conFig = conFig->NEXT)
   if (conFig->DIRECTION == OUT)
     conFig->SIG->CAPA = (float) solution->ARBRE->TYPE / 1000;

        /* duplication (nb -1 fois) */
for(fan = solution->ARBRE->NEXT, instDupl = solution->NAME->NEXT;
    fan;
    fan = fan->NEXT, instDupl = instDupl->NEXT)
   {
   chain_list *signal = NULL, *s;
   lofig_list *fig;

                /* creation d'un nouveau signal */
   losig_list *newSig = addlosig(ptfig, indexMaximum,
                                 addchain((chain_list *)NULL,
                                          (void *)genNAME("netops%d",indexMaximum)),
                                 INTERNAL, 0.0);

   fig = getlofig((char *)instDupl->DATA,'P');

/*
   printf(".");
   fflush(stdout);
*/

        /* mise a jour de la capa pour le nveau signal */
   newSig->CAPA = (float)fan->TYPE / 1000;

  /* creation de la liste des signaux attaches aux connecteurs de l'instance */

   for(conFig = inst->LOCON, conF = fig->LOCON; conFig ;
       conFig = conFig->NEXT, conF = conF->NEXT)
      {
      if (conFig->NAME != conF->NAME)
         {
         printf("erreur dans les connecteurs de la lofig %s\n", inst->INSNAME);
         exit(-1);
         }
                /* Ajout de la direction des connecteurs */
      conF->DIRECTION = conFig->DIRECTION;
      if (conFig->DIRECTION == OUT)
         {
                /* connecteur de sortie */

         signal = addchain(signal, (void *)newSig);
         sigOut = conFig->SIG;
         }
      else
        /* connecteur vss, vdd ou entree */
         signal = addchain(signal, (void *)(conFig->SIG));
      }

        /* remise a jour de l'ordre des connecteurs de l'instance creee */
   signal = reverse(signal);

  /* mise a jour des signaux sur les portes attaquees par le nveau signal */
   for(p = (ptype_list *)(fan->DATA); p; p = p->NEXT)
      if (p->DATA)
         {
                /* on attaque une instance */
         for(conI = ((loins_list *)(p->DATA))->LOCON; conI; conI = conI->NEXT)
            if (conI->NAME == (char *)(p->TYPE))
               conI->SIG = newSig;
         }
      else
         {
                /* on attaque un connecteur EXTERNE */
         nbExt ++;
         if (nbExt > 1)
            printf("WARNING : la porte %s attaque au moins deux connecteurs EXT\n",inst->INSNAME);

         printf(" connector EXTERNAL %s",(char *)(p->TYPE));

         newSig->TYPE = EXTERNAL;
         newSig->NAMECHAIN = addchain((chain_list *)NULL,
                                      (void *)(sigOut->NAMECHAIN->DATA));
         newSig->INDEX = sigOut->INDEX;
         sigOut->NAMECHAIN = addchain((chain_list *)NULL,
                                      (void *)genNAME("netops%d",indexMaximum));
         sigOut->TYPE = INTERNAL;
         sigOut->INDEX = indexMaximum;

                /* recherche du connecteur EXT dans la lofig */
         for(conI = ptfig->LOCON; conI; conI = conI->NEXT)
            if (conI->NAME == (char *)(p->TYPE))
               conI->SIG = newSig;
         }

        /* ajout de l'instance dans la lofig */
   addloins(ptfig, namealloc((char *)genNAME("netopi%d",indexMaximum)),
                             fig, signal);

   addTH(dejaTraite, (char *)namealloc(genNAME("netopi%d", indexMaximum)), 1);

   indexMaximum++;
   dellofig(fig->NAME);

        /* verif !!!!
for(conFig = inst->LOCON,s = signal; conFig && s;
    conFig = conFig->NEXT, s = s->NEXT)
   printf("dupl con : %s == %s (%d)\n",conFig->NAME,
          (char *)(((losig_list *)(s->DATA))->NAMECHAIN->DATA),
          (char *)(((losig_list *)(s->DATA))->INDEX));
         */
   }
PRINTF("\n");

        /* chainages signaux -> connecteurs */
lofigchain(ptfig);
}

/*---------------------------------------------------------------------------
void freeSol    : liberation memoire des solutions
-----------------------------------------------------------------------------
retour          :
---------------------------------------------------------------------------*/
void freeSol(sol)
sol_list *sol;
{
sol_list *auxSol;

while (sol)
   {
   auxSol = sol->NEXT;
   freeptype(sol->NAME);
   freeptype(sol->ARBRE);
   mbkfree((void *)sol);
   sol = auxSol;
   }
}

/*---------------------------------------------------------------------------
triInstance     : repartit les instances du fanout en sous-listes
-----------------------------------------------------------------------------
retour          : liste de solutions, le champ ARBRE a la forme suivante :
                 ptype_list *
                  TYPE = Somme Cin
                  DATA = ptype_list *
                          TYPE = char * : nom du connecteur attaque
                          DATA = loins_list *
---------------------------------------------------------------------------*/
sol_list *triInstance(fanout, nameCell, type, sol)
ptype_list *fanout;
char *nameCell;
short type;
sol_list *sol;
{
long valMax = cellLoadFanout(nameCell);
ptype_list *tri = addptype((ptype_list *)NULL, (long)0, (void *)NULL);
ptype_list *p;
sol_list *newSol = (sol_list*)mbkalloc(sizeof(sol_list));
cellList *lstCells = (cellList *)NULL;

while (fanout)
      {
      long cin = 0;

                /* connecteur INTERNE : recherche du Cin de la porte */
      if (fanout->DATA)
         cin = cellLoadCin(((loins_list *)fanout->DATA)->FIGNAME,
                           (char *)fanout->TYPE);
      else
         cin = cellLoadCin((char *)NULL, (char *)fanout->TYPE);

      if ((tri->DATA == NULL) || ((cin + tri->TYPE) <= valMax))
         {
         tri->DATA = (void *)addptype((ptype_list *)tri->DATA,
                                      fanout->TYPE, fanout->DATA);
         tri->TYPE += cin;
         fanout = fanout->NEXT;
         }
      else
         {
         short nonInsere = 1;
         ptype_list *triParcours;

         triParcours = tri->NEXT;
         while (nonInsere && triParcours)
               if ((triParcours->DATA == NULL) ||
                   ((cin + triParcours->TYPE) <= valMax))
                  {
                  triParcours->DATA = (void *)addptype((ptype_list *)triParcours->DATA,
                                               fanout->TYPE, fanout->DATA);
                  if (fanout->DATA)
                     cin = cellLoadCin(((loins_list *)fanout->DATA)->FIGNAME,
                                       (char *)fanout->TYPE);
                  else
                     cin = cellLoadCin((char *)NULL, (char *)fanout->TYPE);
                  triParcours->TYPE += cin;
                  fanout = fanout->NEXT;
                  nonInsere = 0;
                  }
               else
                  triParcours = triParcours->NEXT;
         if (nonInsere == 1)
            tri = addptype(tri, (long)0, (void *)NULL);
         }
      }

newSol->NAME = (ptype_list *)NULL;
newSol->SURFACE = 0;
newSol->SUMCIN  = 0;
newSol->NOMBRE  = 0;
lstCells = (cellList *)searchTH(NO_CELLTH, nameCell);
for(p = tri; p ; p = p->NEXT)
   {
   newSol->NOMBRE++;
   newSol->NAME = addptype(newSol->NAME, p->TYPE,
                           (void *)adaptePuissance(lstCells, p->TYPE));
   newSol->SURFACE += cellLoadSurface((char *)newSol->NAME->DATA);
   newSol->SUMCIN  += cellLoadCin((char *)newSol->NAME->DATA,
                                  cellLoadIn((char *)newSol->NAME->DATA)->name);
   }
newSol->TYPE = type;
newSol->NAME = (ptype_list *)reverse((chain_list *)newSol->NAME);
newSol->ARBRE = tri;
newSol->NEXT = sol;
return newSol;
}

/*---------------------------------------------------------------------------
addConDir       : ajoute la direction des connecteurs d'une instance
-----------------------------------------------------------------------------
retour          : void
void addConDir(inst)
loins_list *inst;
{
locon_list *con;
Alist * in =  cellLoadIn(inst->FIGNAME);
chain_list * out = cellLoadOut(inst->FIGNAME);

for(con = inst->LOCON; con; con = con->NEXT)
   {
   if (memberChain_list(con->NAME,out))
      con->DIRECTION = OUT;
   else
      if (memberAlist(con->NAME,in))
         con->DIRECTION = IN;
      else
         if (!isvdd(con->NAME) && !isvss(con->NAME))
            {
            printf("addConDir : Unknown direction of %s in %s\n",
                   con->NAME, inst->FIGNAME);
            exit(1);
            }
         else 
            con->DIRECTION = IN;
   }
}
---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------
calculProf : calcul de la profondeur pour les instances d'une LOFIG
-----------------------------------------------------------------------------
retour       : la profondeur est memorisee dans le champ USER des signaux
---------------------------------------------------------------------------*/
void calculProf(lofig)
lofig_list *lofig;
{
loins_list *inst;
locon_list *con;
 
prepareLofig(lofig);
profondeurCircuit = 0;
instProf = NULL;
 
        /* Parcours des connecteurs externes d'entree (profondeur = 0) */
for(con = lofig->LOCON; con; con = con->NEXT)
   if (con->DIRECTION == IN && !isvdd(con->NAME) && !isvss(con->NAME))
      {
      con->SIG->USER = addptype(con->SIG->USER, (long)PROF, (void *)0);
      con->SIG->USER = addptype(con->SIG->USER, (long)GENCON, (void *)con);
      }
 
        /* parcours des instances de la figure */
for(inst = lofig->LOINS; inst; inst = inst->NEXT)
   {
   locon_list *conOut = (locon_list *)(getptype(inst->USER, (long)LOCONOUT)->DATA);
 
   if (!getptype(conOut->SIG->USER,(long)PROF))
      profondeur(inst);
   }
 
printf("PROFONDEUR MAX = %d sur %s[%s]\n\n", profondeurCircuit, instProf->INSNAME,
                                       instProf->FIGNAME);
}
 
/*---------------------------------------------------------------------------
profondeur      :  
-----------------------------------------------------------------------------
retour          : 
---------------------------------------------------------------------------*/
void profondeur(inst)
loins_list *inst;
{
if (cellLoadType(inst->FIGNAME) == REG)
   {
   locon_list *conOut = (locon_list *)getptype(inst->USER, (long)LOCONOUT)->DATA;

        /* memorisation du delai sur le signal de sortie de inst */
   conOut->SIG->USER = addptype(conOut->SIG->USER, (long)PROF, (void *)0);
   return;
   }
if (cellLoadType(inst->FIGNAME) == BUS)
   {
   PRINTF("ERROR : The gate %s [%s] is not treated actually\n",
          inst->INSNAME, inst->FIGNAME);
   exit(1);
   }
else
   {
   ptype_list *userOut = getptype(inst->USER, (long)LOCONOUT);
   locon_list *conOut;
   losig_list *sigOut;
   ptype_list *liste;

   long maxProfond = 0;
   locon_list *con;

if (userOut)
      {
      conOut = (locon_list *)userOut->DATA;
      sigOut = conOut->SIG;
      liste = getptype(sigOut->USER, (long)LOFIGCHAIN);
      }
   else
      {
      PRINTF("TIMING ANALYSIS : No type LOCONOUT for %s\n", inst->INSNAME);
      exit(1);
      }
 
   if (!liste)
      {
      PRINTF("TIMING ANALYSIS : No type LOFIGCHAIN for %s\n", inst->INSNAME);      exit(1);
      }
 
   if (NO_TRACE >= 2)
      printf(" Computing profondeur on %s [%s]\n", inst->INSNAME, inst->FIGNAME);
 
        /* Parcours des connecteurs de l'instance a traiter pour
        trouver les connecteurs d'entree et recuperer les profondeurs
        des signaux sur ces connecteurs */
 
   for(con = inst->LOCON; con; con = con->NEXT)
      {
      if (con->DIRECTION == IN &&
          !isvdd(con->NAME) && !isvss(con->NAME))
         {
         loins_list *cellGenere = (loins_list *)NULL;
         locon_list *conGenere = (locon_list *)NULL;
         long profond = 0;
         ptype_list *user;
         ptype_list *gener = (ptype_list *)NULL;
 
         if (user = getptype(con->SIG->USER, (long)PROF))
            {
                   /* profondeur deja calculee ... */
            profond = (long)user->DATA;
            if (gener = getptype(con->SIG->USER, (long)GENER))
                        /* C'est une porte qui genere le signal */
               cellGenere = (loins_list *)gener->DATA;
            else
                        /* C'est un connecteur qui genere le signal */
               conGenere = (locon_list *)getptype(con->SIG->USER, (long)GENCON)->DATA;
            }
         else
            {
                /* On recherche la porte qui genere le signal */
             if (gener = getptype(con->SIG->USER, (long)GENER))
               {
                        /* C'est une porte qui genere le signal */
               cellGenere = (loins_list *)gener->DATA;

                   /* appel recursif pour la porte qui genere le signal */
               profondeur(cellGenere);

               if (user = getptype(con->SIG->USER, (long)PROF))
                  {
                        /* on recupere la profondeur tout juste calculee */
                  profond = (long)user->DATA;
                  }
               else
                  {
                  PRINTF("ERROR profondeur : no profondeur on inputs of %s\n", inst->INSNAME);
                  exit(1);
                  }
               }
            else
               {
               PRINTF("ERROR TIMING ANALYSIS : no delay on %s[%s]\n", inst->INSNAME, con->NAME);
               }   
            }   /* else : profondeur pas encore calculee */

        if (profond > maxProfond)
            maxProfond = profond;
         }      /* if connecteur d'entree */
      else
         if (con->DIRECTION != OUT && !isvdd(con->NAME) && !isvss(con->NAME))
            PRINTF("TIMING ANALYSIS : Unknown direction for connector %s of %s\n", con->NAME, inst->INSNAME);
 
      }         /* parcours des connecteurs de l'instance (for) */
 
   maxProfond++;

   if (NO_TRACE >= 2)
      printf("   profondeur of %s [%s] = %d \n",
             inst->INSNAME, inst->FIGNAME, maxProfond);
 
        /* memorisation des retards critiques sur le signal de sortie de inst */
   sigOut->USER = addptype(sigOut->USER, (long)PROF, (void *)maxProfond);
 
   if (maxProfond > profondeurCircuit)
      {
      profondeurCircuit = maxProfond;
      instProf = inst;
      }
   }
}

/*---------------------------------------------------------------------------
statistics              :  informations sur la LOFIG : surface, modeles ...
-----------------------------------------------------------------------------
retour          : int = la surface en pitchs
---------------------------------------------------------------------------*/
int statistics(lofig, surfInit)
lofig_list *lofig;
int surfInit;
{
loins_list *inst;
chain_list *mod;
int countMod = 0;
int totalSurf = 0;
int totalInst = 0;
float plus = 0;

if (NO_TRACE >= 2)
   PRINTF("\nFIGNAME : %s\n",lofig->NAME);

        /* parcours des modeles et calcul du nombre d'instances par modele */

for(mod = lofig->MODELCHAIN; mod; mod = mod->NEXT)
   {
   int countInst = 0;

   for(inst = lofig->LOINS; inst; inst = inst->NEXT)
      if (inst->FIGNAME == (char *)mod->DATA)
         countInst++;
   if (NO_TRACE >= 1)
      printf("  Model = %s (area=%d) ==> %d cell%s\n",(char *)(mod->DATA),
             cellLoadSurface((char *)mod->DATA),
             countInst, (countInst > 1) ? "s" : "");
   countMod++;
   totalInst += countInst;
   totalSurf += countInst * cellLoadSurface((char *)mod->DATA);
   }
if (surfInit)
   plus = (float)(100 * (totalSurf - surfInit)) / surfInit;
PRINTF("   %d models - %d cells - %d pitchs",
       countMod, totalInst, totalSurf);
if (plus)
   PRINTF(" (+%5.2f %%)\n\n", plus);
else
   PRINTF("\n\n");
return totalSurf;
}

/*---------------------------------------------------------------------------
capaNot         :  renvoie la capa d'entree du NOT (ou 0 si pas de NOT)
-----------------------------------------------------------------------------
retour          : int
---------------------------------------------------------------------------*/
long capaNot()
{
long cinNot = 0;
cellList *cells = NO_CELLS;
char *Not1 = namealloc("not1");

        /* recherche de la cellule logique NOT */
while (cells && cells->nomlog != Not1)
      cells = cells->NEXT;

        /* si elle existe, calcul de la plus petite capa parmi tous les not */
if (cells)
   {
   ptype_list *c;

   for(c = cells->surface_tech ;c; c = c->NEXT)
      {
      char *CIN = (char *)mbkalloc(5 + strlen(cells->entrees->name));
      long cin;

      sprintf(CIN, "cin_%s",cells->entrees->name);
      cin = (long)searchGeneric(cells, c->DATA, CIN);
      if (cinNot == 0 || cinNot > cin)
         cinNot = cin;
#if MACHINE != pc
      mbkfree((void *)CIN);
#endif
      }
   }
return cinNot;
}

/*---------------------------------------------------------------------------
triConptype     : ajoute un elt d'une ptype_list a sa place
-----------------------------------------------------------------------------
retour          : ptype_list triee en ordre decroissant.
---------------------------------------------------------------------------*/
ptype_list *triConptype(liste, name, data)
ptype_list *liste;
char *name;
void *data;
{
int type = 0;
int tete = 0;

if (data)
   type = cellLoadCin(((loins_list *)data)->FIGNAME, name) ;
else
   type = cellLoadCin((char *)NULL, name);

if (!liste)
   return addptype(liste,(long)name,data);

if (liste->DATA)
   tete = cellLoadCin(((loins_list *)liste->DATA)->FIGNAME,(char *)liste->TYPE);
else
   tete = cellLoadCin((char *)NULL, (char *)liste->TYPE);
if (type >= tete)
   return addptype(liste,(long)name,data);
else
   {
   ptype_list *p1 = liste;
   ptype_list *p2 = liste->NEXT;
   ptype_list *new = (ptype_list *)mbkalloc(sizeof(ptype_list));

   while (p2 && cellLoadCin(((loins_list *)p2->DATA)->FIGNAME,
                             (char *)p2->TYPE) > type)
         {
         p2 = p2->NEXT;
         p1 = p1->NEXT;
         }
   new->TYPE = (long)name;
   new->DATA = data;
   new->NEXT = p2;
   p1->NEXT = new;
   return liste;
   }
}

/*---------------------------------------------------------------------------
capaEntrees     : ajoute la valeur des capa sur les connecteurs de LOFIG
-----------------------------------------------------------------------------
retour          : void
---------------------------------------------------------------------------*/
void capaEntrees()
{
locon_list *conFig;
int cinNot = capaNot();

for(conFig = NO_LOG->LOCON; conFig; conFig = conFig->NEXT)
   {
   if (!isvdd(conFig->NAME) &&
       !isvss(conFig->NAME) &&
       conFig->DIRECTION == IN)
      {
      int sCin = 0;
      chain_list *l;
      ptype_list *liste = getptype(conFig->SIG->USER,(long)LOFIGCHAIN);

      for(l = (chain_list *)liste->DATA; l; l = l->NEXT)
                /* recherche portes attaquees (et pas connecteurs EXT) */
         if (((locon_list *)(l->DATA))->TYPE == INTERNAL &&
             ((locon_list *)(l->DATA))->DIRECTION == IN)
            {
            loins_list *cellOut =
                     (loins_list *)((locon_list *)(l->DATA))->ROOT;

            sCin += cellLoadCin(cellOut->FIGNAME,
                                ((locon_list *)l->DATA)->NAME);
            }
      conFig->SIG->CAPA = (float)sCin / 1000;
      }
   else
      conFig->SIG->CAPA = (float)cinNot / 1000;
   }
}

/*---------------------------------------------------------------------------
optimEntrees    :
-----------------------------------------------------------------------------
retour          :
---------------------------------------------------------------------------*/
void optimEntrees(conIn, fanoutMax)
char *conIn;
long fanoutMax;
{
locon_list *conFig = NO_LOG->LOCON;
ptype_list *liste, *fanout = NULL;
chain_list *l;
int sCin = 0;
int nbPortes = 0;

while(conFig && conFig->NAME != conIn)
     conFig = conFig->NEXT;
if (!conFig)
   {
   printf("Connector '%s' does not exist as primary input\n", conIn);
   printf("(bad parameter file)\n");
   exit(1);
   }

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

for(l = (chain_list *)liste->DATA; l; l = l->NEXT)
   if (((locon_list *)(l->DATA))->ROOT != (void *)NO_LOG)
      {
                /* recherche portes attaquees (et pas connecteurs EXT) */
      if (((locon_list *)(l->DATA))->TYPE == INTERNAL &&
          ((locon_list *)(l->DATA))->DIRECTION == IN)
         {
         loins_list *cellOut =
                  (loins_list *)((locon_list *)(l->DATA))->ROOT;

         sCin += cellLoadCin(cellOut->FIGNAME,
                             ((locon_list *)l->DATA)->NAME);
         nbPortes++;
                /* portes attaquees par le connecteur a traiter */
         fanout = triConptype(fanout,
                              ((locon_list *)(l->DATA))->NAME,
                              (void *)cellOut);
         }
      }
if (sCin > fanoutMax)
   {
   char *Not1 = namealloc("not1");
   sol_list *solutions = (sol_list *)NULL, *lstSol = (sol_list *)NULL;
   sol_list *minSol = (sol_list *)NULL;
   ptype_list *cellsPhy = (ptype_list *)NULL;
   cellList *cells = NO_CELLS;

   if (NO_TRACE >= 0)
      printf("  # Solving %s [Input Connector]\n     %d gates drived - sum Cin = %d - fanout max = %d\n",
             conIn, nbPortes, sCin, fanoutMax);

                /* SOLUTIONS avec BUFFERS */
   while (cells && cells->type != 't')
      cells = cells->NEXT;
   if (cells)
      for(cellsPhy = cells->resistance_tech; cellsPhy;
          cellsPhy=cellsPhy->NEXT)
         {
         char *nameCellsPhy = (char *)cellsPhy->DATA;

         solutions = triInstance(fanout, nameCellsPhy, BUF, solutions);
         if (nbPortes == 1)
            solutions->DIFFCIN = cellLoadFanout(nameCellsPhy)-sCin;
         else
            solutions->DIFFCIN = 0;
         }

                /* SOLUTIONS avec BUFFERS de NOT */
      cells = NO_CELLS;
      while (cells && cells->nomlog != Not1)
         cells = cells->NEXT;
      if (cells)
         {
         for(cellsPhy = cells->resistance_tech; cellsPhy;
             cellsPhy=cellsPhy->NEXT)
            {
            char *nameCellsPhy = (char *)cellsPhy->DATA;
            char *insertNot = (char *)NULL;

            solutions = triInstance(fanout, nameCellsPhy, BUN, solutions);
            insertNot = adaptePuissance(cells,
                         solutions->NOMBRE*cellLoadCin(nameCellsPhy,
                                      cellLoadIn(nameCellsPhy)->name));
            solutions->SURFACE += cellLoadSurface(insertNot);
            solutions->ADAPT = insertNot;
            if (nbPortes == 1)
               solutions->DIFFCIN = cellLoadFanout(nameCellsPhy)-sCin;
            else
               solutions->DIFFCIN = 0;
            }
         }

	/* recherche de la meilleure solution */
      if (solutions)
         {
         minSol = solutions;
         for(lstSol = solutions->NEXT; lstSol; lstSol = lstSol->NEXT)
             if ((lstSol->SURFACE <= minSol->SURFACE) &&
                 (lstSol->DIFFCIN >= 0))
                minSol = lstSol;
         }

                /* mise en oeuvre de la solution */
      if (minSol)
         {
         if (minSol->TYPE == BUF)
            {
            loins_list *instBuff = addBuffer(NO_LOG, (loins_list *)NULL,
                                       conFig, (char *)minSol->NAME->DATA);
            if (minSol->NOMBRE > 1)
               dupliqueInst(NO_LOG, instBuff,minSol);
            }
         if (minSol->TYPE == BUN)
            {
            loins_list *instNot1 = addBuffer(NO_LOG, (loins_list *)NULL,
                                       conFig, minSol->ADAPT);
            loins_list *instNot2 = addBuffer(NO_LOG, instNot1,
                                       (locon_list *)NULL, (char *)minSol->NAME->DATA);
            if (minSol->NOMBRE > 1)
               dupliqueInst(NO_LOG, instNot2, minSol);
            }
         }
      else
         {
         printf("    ==> NO SOLUTION for %s [input connector]\n", conFig->NAME);
         printf("     !!! Merci de me faire une fiche probleme. NATHALIE !!!\n");
         }
      freeSol(solutions);
   }
   freeptype(fanout);
}

/*---------------------------------------------------------------------------
optimiseInst    : optimisation selon le fanout maximum pour une cellule
-----------------------------------------------------------------------------
retour          : void
---------------------------------------------------------------------------*/
void optimiseInst(instTraite)
loins_list *instTraite;
{
if (searchTH(dejaTraite, instTraite->INSNAME) == EMPTYTH)
   {
   ptype_list *fanout = NULL, *fan;
   int nbPortes = 0;
   locon_list *con;
   int sCin = 0;
   int savesCin = 0;

        /* mise dans la table de hachage des instances deja traitees */
   addTH(dejaTraite, instTraite->INSNAME, 1);

        /* parcours des connecteurs de l'instance : calcul du fanout */
   for(con = instTraite->LOCON; con; con = con->NEXT)
      {
        /* recherche du connecteur de sortie */
      if (con->DIRECTION == OUT)
         {
         chain_list *l;

                /* liste des liaisons signaux --> connecteurs */
         ptype_list *liste = getptype(con->SIG->USER,(long)LOFIGCHAIN);

         for(l = (chain_list *)liste->DATA; l; l = l->NEXT)
            if (((locon_list *)(l->DATA))->ROOT != (void *)instTraite)
               {
                        /* recherche portes attaquees (pas con EXTERNE) */
                                /* Pour appel RECURSIF !!! */
               if (((locon_list *)(l->DATA))->TYPE == INTERNAL &&
                   ((locon_list *)(l->DATA))->DIRECTION == IN)
                  {
                  loins_list *cellOut =
                           (loins_list *)((locon_list *)(l->DATA))->ROOT;

                                /* portes attaquees par l'instance a traiter */
                  fanout = triConptype(fanout,
                                       ((locon_list *)(l->DATA))->NAME,
                                       (void *)cellOut);
                  }
               }
          }
      }         /* fin parcours connecteurs */

        /* appel recursif sur les instances du fanout */
   for(fan = fanout; fan; fan = fan->NEXT)
      if (searchTH(dejaTraite, ((loins_list *)fan->DATA)->INSNAME) == EMPTYTH)
         optimiseInst((loins_list *)fan->DATA);

   freeptype(fanout);
   fanout = NULL;

        /* calcul du fanout de l'instance a traiter :
                portes attaquees + connecteurs externes, somme des Cin */

      for(con = instTraite->LOCON; con; con = con->NEXT)
         {
                /* recherche des connecteurs de sortie */
         if (con->DIRECTION == OUT)
            {
                /* liste des liaisons signaux --> connecteurs */
            ptype_list *liste = getptype(con->SIG->USER,(long)LOFIGCHAIN);
            chain_list *l;

            for(l = (chain_list *)liste->DATA; l; l = l->NEXT)
               if (((locon_list *)(l->DATA))->ROOT != (void *)instTraite)
                  {
                        /* connecteur externe */
                  if (((locon_list *)(l->DATA))->TYPE == EXTERNAL)
                     {
                     fanout = triConptype(fanout,
                                          ((locon_list *)(l->DATA))->NAME,
                                          (void *)NULL);
                     sCin += cellLoadCin((char *)NULL, ((locon_list *)l->DATA)->NAME);
                     nbPortes++;
                     }
                  else
                     if (((locon_list *)(l->DATA))->DIRECTION == IN)
                        {
                                /* connecteur interne et entree de porte */
                        loins_list *cellOut =
                                 (loins_list *)((locon_list *)(l->DATA))->ROOT;

                        fanout = triConptype(fanout,
                                             ((locon_list *)(l->DATA))->NAME,
                                             (void *)cellOut);
                        sCin += cellLoadCin(cellOut->FIGNAME,
                                            ((locon_list *)l->DATA)->NAME);
                        nbPortes++;
                        }
                  }
            }
         }

   if (sCin > cellLoadFanout(instTraite->FIGNAME))
      {
        /* la porte est trop chargee */

      char *portePuissanteOK = NULL;

      if (NO_TRACE >= 1)
         printf("  # Solving gate %s [%s / Area = %d]\n     %d gate%s drived - Sum Cin = %d - fanout max = %d\n",
             instTraite->INSNAME, instTraite->FIGNAME, cellLoadSurface(instTraite->FIGNAME),
             nbPortes, nbPortes>1?"s":"",
             sCin, cellLoadFanout(instTraite->FIGNAME));

        /* Recherche d'une SOLUTION */

      savesCin = sCin;
                /* SOLUTION en portes PUISSANTES */
      portePuissanteOK = adaptePuissance((cellList *)searchTH(NO_CELLTH, instTraite->FIGNAME), (long)sCin);
      if (cellLoadFanout(portePuissanteOK) - sCin >= 0)
         {
                /* test porte puissante = OK */
         addPuissante(NO_LOG, instTraite, portePuissanteOK);
         }
      else
         {
         char *Not1 = namealloc("not1");
         sol_list *solutions = (sol_list *)NULL, *lstSol = (sol_list *)NULL;
         sol_list *minSol = (sol_list *)NULL;
         ptype_list *cellsPhy = (ptype_list *)NULL;
         cellList *cells = NO_CELLS;

         sCin = savesCin;

                /* SOLUTIONS avec BUFFERS */
         while (cells && cells->type != 't')
            cells = cells->NEXT;
         if (cells)
            for(cellsPhy = cells->resistance_tech; cellsPhy;
                cellsPhy=cellsPhy->NEXT)
               {
               char *nameCellsPhy = (char *)cellsPhy->DATA;
               cellList *cellsInst;
               char *bonnePuissance = (char *)NULL;

               solutions = triInstance(fanout, nameCellsPhy, BUF, solutions);
               cellsInst = (cellList *)searchTH(NO_CELLTH, instTraite->FIGNAME);
               bonnePuissance = adaptePuissance(cellsInst, solutions->SUMCIN);
               solutions->SURFACE += cellLoadSurface(bonnePuissance);
               solutions->ADAPT = bonnePuissance;
               if (nbPortes == 1)
                  solutions->DIFFCIN = cellLoadFanout(nameCellsPhy)-sCin;
               else
                  solutions->DIFFCIN = 0;
               }

                /* SOLUTIONS de BUFFERS avec des NOT */
         cells = (cellList *)searchTH(NO_CELLTH, instTraite->FIGNAME);
         if (cells->nomlog != Not1)
            {
            cells = NO_CELLS;
            while (cells && cells->nomlog != Not1)
               cells = cells->NEXT;
            if (cells)
               {

               for(cellsPhy = cells->resistance_tech; cellsPhy;
                   cellsPhy=cellsPhy->NEXT)
                  {
                  char *nameCellsPhy = (char *)cellsPhy->DATA;
                  char *insertNot = (char *)NULL;

                  solutions = triInstance(fanout, nameCellsPhy, BUN, solutions);
                  insertNot = adaptePuissance(cells, solutions->SUMCIN);
                  solutions->SURFACE += cellLoadSurface(insertNot);
                  solutions->SURFACE += cellLoadSurface(instTraite->FIGNAME);
                  solutions->ADAPT = insertNot;
                  if (nbPortes == 1)
                     solutions->DIFFCIN = cellLoadFanout(nameCellsPhy)-sCin;
                  else
                     solutions->DIFFCIN = 0;
                  }
               }
            }

                /* SOLUTIONS de DUPLICATIONS */
         if ((cellLoadType(instTraite->FIGNAME) != REG) && (nbPortes > 1))
            {
            cells = (cellList *)searchTH(NO_CELLTH, instTraite->FIGNAME);
            for(cellsPhy = cells->resistance_tech; cellsPhy;
                cellsPhy=cellsPhy->NEXT)
               {
               char *nameCellsPhy = (char *)cellsPhy->DATA;

               solutions = triInstance(fanout, nameCellsPhy, DUP, solutions);
               solutions->ADAPT = (char *)NULL;
               solutions->DIFFCIN = 0;
               }
            }

                /* Choix d'une solution */
         if (solutions)
            {
            minSol = solutions;
            for(lstSol = solutions->NEXT; lstSol; lstSol = lstSol->NEXT)
               {
               if (minSol->DIFFCIN < 0)
                  {
                  if (lstSol->DIFFCIN > minSol->DIFFCIN)
                      minSol = lstSol;
                  }
               else
                  if (lstSol->DIFFCIN >= 0)
                     if (lstSol->SURFACE < minSol->SURFACE)
                        minSol = lstSol;
                     else
                        if (lstSol->SURFACE == minSol->SURFACE)
                           if (lstSol->NOMBRE < minSol->NOMBRE)
                              minSol = lstSol;
               }
            }
                /* mise en oeuvre de la solution */
         if (minSol)
            {
            if (minSol->TYPE == BUF)
               {
               loins_list *instBuff = addBuffer(NO_LOG, instTraite,
                                          (locon_list *)NULL, (char *)minSol->NAME->DATA);
               if (minSol->NOMBRE > 1)
                  dupliqueInst(NO_LOG, instBuff,minSol);
               if (minSol->ADAPT != instTraite->FIGNAME)
                  addPuissante(NO_LOG, instTraite, minSol->ADAPT);
               }
            if (minSol->TYPE == DUP)
               {
/*
               if (instTraite->FIGNAME != minSol->NAME)
                  addPuissante(NO_LOG, instTraite, minSol->NAME);
               if (minSol->NOMBRE > 1)
*/
                  dupliqueInst(NO_LOG, instTraite, minSol);
               }
            if (minSol->TYPE == BUN)
               {
               loins_list *instNot1 = addBuffer(NO_LOG, instTraite,
                                          (locon_list *)NULL, minSol->ADAPT);
               loins_list *instNot2 = addBuffer(NO_LOG, instNot1,
                                          (locon_list *)NULL, (char *)minSol->NAME->DATA);
               if (minSol->NOMBRE > 1)
                  dupliqueInst(NO_LOG, instNot2, minSol);
               }
            }
         else
            {
            printf("    ==> NO SOLUTION for %s\n", instTraite->INSNAME);
            printf("     !!! Merci de me faire une fiche probleme. NATHALIE !!!\n");
            }
                /* LIBERERATION DES SOLUTIONS */
         freeSol(solutions);
         }
      }
   freeptype(fanout);
   }
}

/*---------------------------------------------------------------------------
optimFanMax     : optimisation selon le fanout maximum
-----------------------------------------------------------------------------
retour          : void
---------------------------------------------------------------------------*/
void optimFanMax()
{
loins_list *inst;
long diffMax = 0;
loins_list *instMax = NULL;
int nbPbs = 0;

        /* parcours des instances de la figure */
for(inst = NO_LOG->LOINS; inst; inst = inst->NEXT)
   {
   if (cellLoadType(inst->FIGNAME) == BUS)
     {
        /* remettre a jour dir con BUS */
                /* Ajouter CAPA */
     }
   else
     if (searchTH(dejaTraite,inst->INSNAME) == EMPTYTH)
      {
      long somCin = 0;
      long diffCapa = 0;
      locon_list *con;

        /* parcours des connecteurs de l'instance : calcul du fanout */
      for(con = inst->LOCON; con; con = con->NEXT)
         {
                /* recherche du connecteur de sortie */
         if (con->DIRECTION == OUT)
            {
            chain_list *l;
                /* liste des liaisons signaux --> connecteurs */
            ptype_list *liste = getptype(con->SIG->USER,(long)LOFIGCHAIN);

            for(l = (chain_list *)(liste->DATA); l; l = l->NEXT)
               if (((locon_list *)(l->DATA))->ROOT != (void *)inst)
                  {
                  if (((locon_list *)(l->DATA))->TYPE == EXTERNAL)
                        /* connecteur externe */
                     somCin += (long)cellLoadCin((char *)NULL,
                                                 ((locon_list *)l->DATA)->NAME);
                  else
                     if (((locon_list *)(l->DATA))->DIRECTION == IN)
                        {
                                /* connecteur interne et entree de porte */
                        loins_list *cellOut =
                         (loins_list *)((locon_list *)(l->DATA))->ROOT;

                                /* calcul de la somme des Cin */
                        somCin += (long)cellLoadCin(cellOut->FIGNAME,
                                                    ((locon_list *)l->DATA)->NAME);
                        }
                  }
            con->SIG->CAPA = (float)somCin / 1000;
            }
         }

      if ((somCin > 0) && (cellLoadFanout(inst->FIGNAME) != 0) &&
          ((diffCapa = somCin - (long)cellLoadFanout(inst->FIGNAME)) > 0))
         {
                /* l'instance  ne respecte pas le fanout max */
         nbPbs++;

                /* recherche du + fort pb non encore traite */
         if (diffCapa > diffMax)
            {
            diffMax = diffCapa;
            instMax = inst;
            }
         }
      }
   }    /* fin parcours inst */

if (instMax)
   {
   if (NO_TRACE >= 1)
      PRINTF("\nNumber of problems : %d : cell %s [%s] - Sum Cin =  %d\n",
             nbPbs, instMax->INSNAME, instMax->FIGNAME,
             diffMax + cellLoadFanout(instMax->FIGNAME));

   optimiseInst(instMax);
   optimFanMax();
   }
}

/*---------------------------------------------------------------------------
mainInfo :
-----------------------------------------------------------------------------
retour          :
---------------------------------------------------------------------------*/
void mainInfo(type)
char type;
{
if (type == 'f')
   {
   displayLofig(NO_LOG, 3);
   }
else
   {
   int oldTrace = NO_TRACE;
   NO_TRACE = 1;
   statistics(NO_LOG, 0);
   NO_TRACE = oldTrace;

   calcul_delai(NO_LOG, 2);
   cheminCritique(porteCriticMinUp, UP, delaiCriticMinUp, 2, 1);
   cheminCritique(porteCriticMinDw, DOWN, delaiCriticMinDw, 2, 1);
   printf("\n Maximal depth = %d gates on %s\n\n",
          profondeurCircuit, instProf->INSNAME);

   if (NO_TRACE >= 1)
      {
      calcul_requi(NO_LOG, delaiCriticUp, delaiCriticDw, 0);
      displayTiming(NO_LOG, 0);
      }
   }
}

/*---------------------------------------------------------------------------
mainOptimFanMax :
-----------------------------------------------------------------------------
retour          :
---------------------------------------------------------------------------*/
void mainOptimFanMax()
{
ptype_list *p;
locon_list *con;
FILE *fichStat;
char *fileStat;

int surfaceInit = statistics(NO_LOG, 0);

dejaTraite = createTH(500);
optimFanMax();
printf("\n");

	/* optimisation des entrees primaires */
if (NO_CAPAPI)
   {
   for(p = NO_CAPAPI; p ; p = p->NEXT)
      {
      optimEntrees((char *)p->DATA, p->TYPE);
      addTH(dejaTraite, (char *)p->DATA, 1);
      }
   }
for(con = NO_LOG->LOCON; con; con = con->NEXT)
   if ((con->DIRECTION == IN) && !isvdd(con->NAME) && !isvss(con->NAME))
      if (searchTH(dejaTraite, con->NAME) == EMPTYTH)
         optimEntrees(con->NAME, (long)(4*capaNot()));
   
destroyTH(dejaTraite);
capaEntrees();
clearmodel(NO_LOG);

statistics(NO_LOG, surfaceInit);

NO_LOG->NAME = NO_FILEOUT;
printf("Saving %s/%s...\n",NO_LOG_LIB, NO_LOG->NAME);
savelofig(NO_LOG);

        /* Generation du fichier de statistiques */
fileStat = (char *)mbkalloc(strlen(NO_LOG_LIB)+strlen(NO_LOG->NAME)+8);
sprintf(fileStat, "%s/%s.stat", NO_LOG_LIB, NO_LOG->NAME);
fichStat = fopen(fileStat, "w");
if (fichStat)
   {
   ptype_list *liste;
   chain_list *l;

   printf("\nGeneration of statistics file : %s\n", fileStat);

   for(con = NO_LOG->LOCON; con; con = con->NEXT)
      if ((con->DIRECTION == IN) && !isvdd(con->NAME) && !isvss(con->NAME))
         {
/*
         printf("%f %d\n", con->SIG->CAPA, (int)((con->SIG->CAPA)*10000));
*/
         fprintf(fichStat, "Connector name : %s (IN) - Capa = %d\n",
                 con->NAME, (int)((con->SIG->CAPA)*1000));
         }
      else
         if (con->DIRECTION == OUT)
            {
            liste = getptype(con->SIG->USER,(long)LOFIGCHAIN);

            for(l = (chain_list *)liste->DATA; l; l = l->NEXT)
               {
               loins_list *inst;

               if (((locon_list *)(l->DATA))->TYPE != EXTERNAL)
                  {
                  inst = (loins_list *)((locon_list *)(l->DATA))->ROOT;

                  fprintf(fichStat, "Connector name : %s (OUT) [%s] - max fanout = %d\n",
                          con->NAME, inst->FIGNAME, cellLoadFanout(inst->FIGNAME));
                  }
               }
            }
   fclose(fichStat);
#if MACHINE != pc
   mbkfree((void *)fileStat);
#endif
   }
}

/*---------------------------------------------------------------------------
mainOptimGlobal   :
-----------------------------------------------------------------------------
retour          :
---------------------------------------------------------------------------*/
void mainOptimGlobal()
{
int surfaceInit = statistics(NO_LOG, 0);

listeCritic = (ptype_list *)NULL;

calcul_delai(NO_LOG, 2);

assignFaninLofig(NO_LOG);

calcul_delai(NO_LOG, 1);
calcul_requi(NO_LOG, delaiCriticUp, delaiCriticDw, 1);

puissanceLofig(300);

calcul_delai(NO_LOG, 1);
calcul_requi(NO_LOG, delaiCriticUp, delaiCriticDw, 0);

bufferLofig(6, 4);

calcul_delai(NO_LOG, 1);
calcul_requi(NO_LOG, delaiCriticUp, delaiCriticDw, 1);

puissanceLofig(500);

/*
assignFaninLofig(NO_LOG);
*/

calcul_delai(NO_LOG, 2);
calcul_requi(NO_LOG, delaiCriticUp, delaiCriticDw, 0);
/*
cheminCritique(porteCriticUp, UP, delaiCriticUp, 2, 0);
cheminCritique(porteCriticDw, DOWN, delaiCriticDw, 2, 0);
*/


clearmodel(NO_LOG);
statistics(NO_LOG, surfaceInit);

NO_LOG->NAME = NO_FILEOUT;
printf("Saving %s/%s...\n",NO_LOG_LIB, NO_LOG->NAME);
savelofig(NO_LOG);

/* Fonctions de Vincent : graphe dedouble.
creer_graphe(NO_LOG);
calcul_temps();
debug_graphe();
detruit_graphe();
*/
}
