/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit :  NetOptim                                                   */
/*    Fichier :  delai.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 : 16/07/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 "no_global.h"
#include "delai.h"

/*---------------------------------------------------------------------------
cheminCritique : affichage du chemin critique
-----------------------------------------------------------------------------
retour         : nom des portes des sorties vers les entrees
---------------------------------------------------------------------------*/
void cheminCritique(inst, type, delai, info, min)
loins_list *inst;
int type;
long delai;
short info, min;
{
ptype_list *chemin;
loins_list *porte = inst;
int nbCouches = 1;
chain_list *lstCon;
char *nameConExt = NULL;
loins_list *reg = (loins_list *)NULL;

ptype_list *userOut = getptype(inst->USER, (long)LOCONOUT);
losig_list *sigOut = ((locon_list *)userOut->DATA)->SIG;
ptype_list *liste = getptype(sigOut->USER, (long)LOFIGCHAIN);

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

   if (conAux->ROOT != (void *)inst)
      if (conAux->TYPE == EXTERNAL)
         nameConExt = conAux->NAME;
      else
         if (cellLoadType(((loins_list *)conAux->ROOT)->FIGNAME) == REG)
            reg = ((loins_list *)conAux->ROOT);
   }

if (nameConExt)
   PRINTI(" %sCritical path %s on external connector %s (%d ps)\n",
          (min)?"Minimal ":"", (type == UP)?" UP ":"DOWN", nameConExt, delai);
else
   if (reg)
      PRINTI(" %sCritical path %s on %s [%s] (%d ps)\n", (min)?"Minimal ":"",
             (type == UP)?" UP ":"DOWN",
             reg->INSNAME, reg->FIGNAME, delai);
   else
      {
      printf("ERROR Timing : critical path not on register or external connector (on %s)\n", inst->INSNAME);
      exit(1);
      }

if (info >= 2)
   if(min == 0)
      {
      PRINTI("  %s", porte->INSNAME);
      while (chemin = getptype(porte->USER, (long)((type== UP)?LOINSUP:LOINSDW)))
         {
         if ((type== UP) && (cellLoadPolarity(porte->FIGNAME) == NEG))
            type= DOWN;
         else
            if ((type== DOWN) && (cellLoadPolarity(porte->FIGNAME) == NEG))
               type= UP;
         porte = (loins_list *)chemin->DATA;
         PRINTI("<-%s", porte->INSNAME);
         if (info >= 3)
            {
		/* a condition que les temps requis et slacks soient calcules */
            printf("\n");
            displayTimingInst(porte, 0);
            }
         nbCouches++;
         }
      chemin = getptype(porte->USER, (long)((type== UP)?LOCONUP:LOCONDW));
      if (chemin)
         {
         locon_list *con = (locon_list *)chemin->DATA;
         PRINTI("<-%s", con->NAME);
         }
      PRINTI("\n      => %d gates\n", nbCouches);
      }
   else
      {
      PRINTI("  %s", porte->INSNAME);
      while (chemin = getptype(porte->USER, (long)((type == UP)?LOINSMINUP:LOINSMINDW)))
         {
         if ((type== UP) && (cellLoadPolarity(porte->FIGNAME) == NEG))
            type= DOWN;
         else
            if ((type== DOWN) && (cellLoadPolarity(porte->FIGNAME) == NEG))
               type= UP;
         porte = (loins_list *)chemin->DATA;
         PRINTI("<-%s[%s]", porte->INSNAME, porte->FIGNAME);
         if (info >= 3)
            {
            printf("\n");
            displayTimingInst(porte, 0);
            }
         nbCouches++;
         }
      chemin = getptype(porte->USER, (long)((type == UP)?LOCONMINUP:LOCONMINDW));
      if (chemin)
         {
         locon_list *con = (locon_list *)chemin->DATA;
         PRINTI("<-%s", con->NAME);
         }
      PRINTI("\n      => %d gates\n", nbCouches);
      }
}

/*---------------------------------------------------------------------------
resistanceNot   :  renvoie la resistance de sortie du NOT (ou 0 si pas de NOT)
-----------------------------------------------------------------------------
retour          : int
---------------------------------------------------------------------------*/
long resistanceNot(front)
int front;
{
long rNot = 99999;
cellList *cells = NO_CELLS;
char *Not1 = namealloc("not1");

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

        /* si NOT existe, calcul de la + ptite resistance parmi tous les not */
if (cells)
   {
   ptype_list *c;

   for(c = cells->surface_tech ;c; c = c->NEXT)
      {
      long res;
      char *RES = (char *)mbkalloc(7 + strlen(cells->entrees->name));

      if (front == DOWN)
         {
         sprintf(RES, "rdown_%s",cells->entrees->name);
         res = (long)searchGeneric(cells, c->DATA, RES);
         if (res < rNot)
            rNot = res;
#if MACHINE != pc
         mbkfree(RES);
#endif
         }
      else
         {
         sprintf(RES, "rup_%s",cells->entrees->name);
         res = (long)searchGeneric(cells, c->DATA, RES);
         if (res < rNot)
            rNot = res;
#if MACHINE != pc
         mbkfree(RES);
#endif
         }
      }
   return rNot;
   }
else
   return 1000;
}

/*---------------------------------------------------------------------------
prepareLofig : memorise le connecteur de sortie de chaque instance
               dans son champ USER et pour le signal de sortie l'instance
               qui le genere. Fait un lofigchain sur la netlist.
-----------------------------------------------------------------------------
retour       : RIEN. La lofig est modifiee.
---------------------------------------------------------------------------*/
void prepareLofig(lofig)
lofig_list *lofig;
{
loins_list *inst;
locon_list *con;

for(inst = lofig->LOINS; inst; inst = inst->NEXT)
   {
   if (inst->USER)
      {
      freeptype(inst->USER);
      inst->USER = (ptype_list *)NULL;
      }

   for(con = inst->LOCON; con; con = con->NEXT)
      if (con->DIRECTION == OUT)
         {
         inst->USER = addptype(inst->USER, (long)LOCONOUT, (void *)con);

         if (con->SIG->USER)
            {
            freeptype(con->SIG->USER);
            con->SIG->USER = (ptype_list *)NULL;
            }
         con->SIG->USER = addptype(con->SIG->USER, (long)GENER, (void *)inst);
         }
   }
lofigchain(lofig);
}

/*---------------------------------------------------------------------------
getInfoInst  :
-----------------------------------------------------------------------------
retour : un long 
---------------------------------------------------------------------------*/
long getInfoInst(inst, typeInfo)
loins_list *inst;
long typeInfo;
{
ptype_list *listeUser = getptype(inst->USER, (long)LOCONOUT);

if (listeUser)
   {
   locon_list *conOut = (locon_list *)listeUser->DATA;
   ptype_list *listeInfo = getptype(conOut->SIG->USER, typeInfo);

   if (listeInfo)
      return (long)listeInfo->DATA;
   printf("ERROR : no timing informations on %s [%s]\n",
          inst->INSNAME, inst->FIGNAME);
   exit(1);
   }
else
   {
   printf("ERROR : no timing informations on %s [%s]\n",
          inst->INSNAME, inst->FIGNAME);
   exit(1);
   }
}

/*---------------------------------------------------------------------------
getDelayIn  : retourne le delai d'une entree retardee
-----------------------------------------------------------------------------
retour : un long ou 0.
---------------------------------------------------------------------------*/
long getDelayIn(liste, conName)
ptype_list *liste;
char *conName;
{
ptype_list *l;

for(l = liste; l; l = l->NEXT)
   if ((char *)l->DATA == conName)
      return l->TYPE;
return (long)0;
}

/*---------------------------------------------------------------------------
calcul_delaiIn  : Initialisation des retards et de la profondeur des entrees
-----------------------------------------------------------------------------
retour : RIEN. Memorisation dans le champ USER du signal de sortie
---------------------------------------------------------------------------*/
void calcul_delaiIn(lofig)
lofig_list *lofig;
{
locon_list *con;
long rUp = resistanceNot(UP);
long rDw = resistanceNot(DOWN);

	/* Parcours des connecteurs externes d'entree */
for(con = lofig->LOCON; con; con = con->NEXT)
   if (con->DIRECTION == IN && !isvdd(con->NAME) && !isvss(con->NAME))
      {
      chain_list *lstCon;
      long sCin = 0;
      ptype_list *liste = getptype(con->SIG->USER, (long)LOFIGCHAIN);
      long delIn = getDelayIn(NO_DELAYPI, con->NAME);

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

         if (conAux->ROOT != (void *)lofig)
            {
            if (conAux->TYPE == EXTERNAL)
                   /* connecteur externe */
               sCin += cellLoadCin((char *)NULL, conAux->NAME);
            else
                   /* connecteur interne */
               if (conAux->DIRECTION == IN)
                  {
                  loins_list *cellOut = (loins_list *)conAux->ROOT;

                  sCin += cellLoadCin(cellOut->FIGNAME, conAux->NAME);
                  }
               else
                  PRINTI("DELAY on PRIMARY INPUT : Unknown connector '%s'\n",
                         conAux->NAME);
            }
         }
      con->SIG->USER = addptype(con->SIG->USER, (long)PROF, (void *)0);

        /* memorisation de la somme des capa dans le champ USER du signal */
      con->SIG->USER = addptype(con->SIG->USER, (long)TOTCAPA, (void *)sCin);
      con->SIG->CAPA = (float)sCin/1000;

      con->SIG->USER = addptype(con->SIG->USER, (long)GENCON, (void *)con);

      con->SIG->USER = addptype(con->SIG->USER, (long)DELAIMINUP,
                                (void *)(delIn + rUp*capaNot()/1000));
      con->SIG->USER = addptype(con->SIG->USER, (long)DELAIMINDW,
                                (void *)(delIn + rDw*capaNot()/1000));
      con->SIG->USER = addptype(con->SIG->USER, (long)DELAIUP,
                                (void *)(delIn + rUp*sCin/1000));
      con->SIG->USER = addptype(con->SIG->USER, (long)DELAIDW,
                                (void *)(delIn + rDw*sCin/1000));
      if (NO_TRACE >= 2)
         PRINTI("  delay of %s [input] - UP = %d - DOWN = %d - Cin Sum = %d\n", 
                con->NAME, delIn + rUp*sCin/1000, delIn + rDw*sCin/1000, sCin);
      }
}

/*---------------------------------------------------------------------------
calcul_delai : calcul des retards pour les instances d'une LOFIG
-----------------------------------------------------------------------------
retour       : les retards sont memorises dans le champ USER des signaux
---------------------------------------------------------------------------*/
void calcul_delai(lofig, affich)
lofig_list *lofig;
short affich;
{
loins_list *inst;

prepareLofig(lofig);

calcul_delaiIn(lofig);

delaiCriticUp = delaiCriticDw = 0;
porteCriticUp = porteCriticDw = NULL;
delaiCriticMinUp = delaiCriticMinDw = 0;
profondeurCircuit = 0;
instProf = NULL;

        /* 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)DELAIUP))
      delai(inst);
   }


if (affich)
   {
   cheminCritique(porteCriticUp, UP, delaiCriticUp, affich, 0);
   cheminCritique(porteCriticDw, DOWN, delaiCriticDw, affich, 0);
   if (affich >= 4)
      {
      cheminCritique(porteCriticMinUp, UP, delaiCriticMinUp, affich, 1);
      cheminCritique(porteCriticMinDw, DOWN, delaiCriticMinDw, affich, 1);
      printf("\n Maximal depth = %d sur %s\n\n", 
             profondeurCircuit, instProf->INSNAME);
      }
   }
else
   PRINTF("  Timing Analysis : Delay UP %d (%s) - Delay DW %d (%s)\n", 
          delaiCriticUp, porteCriticUp->INSNAME, delaiCriticDw, porteCriticDw->INSNAME);

/*
PRINTF("End of Timing Analysis on %s\n\n", lofig->NAME);
*/
}

/*---------------------------------------------------------------------------
delai  : calcul du retard et de la profondeur d'une instance 
         (appel recursif sur les entrees)
-----------------------------------------------------------------------------
retour : RIEN. Memorisation dans le champ USER du signal de sortie
         Type DELAIUP, DELAIDW, TOTCAPA et PROF
---------------------------------------------------------------------------*/
void delai(inst)
loins_list *inst;
{
if (cellLoadType(inst->FIGNAME) == REG)
   {
   locon_list *conOut = (locon_list *)getptype(inst->USER, (long)LOCONOUT)->DATA;
   losig_list *sigOut = conOut->SIG;
   ptype_list *liste = getptype(sigOut->USER, (long)LOFIGCHAIN);
   chain_list *lstCon;
   long sCin = 0;
   long rUp = cellLoadR(inst->FIGNAME, NULL, UP);
   long rDw = cellLoadR(inst->FIGNAME, NULL, DOWN);

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

        /* pour le connecteur de sortie, calculer son fanout (somme CIN) */

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

      if (conAux->ROOT != (void *)inst)
         {
         if (conAux->TYPE == EXTERNAL)
                /* connecteur externe */
            sCin += cellLoadCin((char *)NULL, conAux->NAME);
         else
                /* connecteur interne */
            if (conAux->DIRECTION == IN)
               {
               loins_list *cellOut = (loins_list *)conAux->ROOT;

                        /* portes attaquees par l'instance a traiter */
               sCin += cellLoadCin(cellOut->FIGNAME, conAux->NAME);
               }
            else
               {
               PRINTF("TIMING ANALYSIS : Unknown connector '%s' of %s[%s]\n",
                      conAux->NAME, ((loins_list *)conAux->ROOT)->INSNAME,
                      ((loins_list *)conAux->ROOT)->FIGNAME);
               }
         }
     }

        /* memorisation du delai sur le signal de sortie de inst */
   conOut->SIG->USER = addptype(conOut->SIG->USER, (long)DELAIMINUP, (void *)(rUp*capaNot() / 1000));
   conOut->SIG->USER = addptype(conOut->SIG->USER, (long)DELAIMINDW, (void *)(rDw*capaNot() / 1000));
   conOut->SIG->USER = addptype(conOut->SIG->USER, (long)DELAIUP, (void *)(rUp * sCin / 1000));
   conOut->SIG->USER = addptype(conOut->SIG->USER, (long)DELAIDW, (void *)(rDw * sCin / 1000));

        /* memorisation de la profondeur et de SCIN sur le signal de sortie de inst */
   conOut->SIG->USER = addptype(conOut->SIG->USER, (long)PROF, (void *)1);
   conOut->SIG->USER = addptype(conOut->SIG->USER, (long)TOTCAPA, (void *)sCin);

   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;  
   short conExt = 0, conReg = 0;
   long sCin = 0;
   chain_list *lstCon;
   long maxDelUp = 0, maxDelDw = 0;
   long maxDelMinUp = 0, maxDelMinDw = 0;
   void *criticUp = NULL, *criticDw = NULL;
   void *criticMinUp = NULL, *criticMinDw = NULL;
   long maxProfond = 0;
   long genreUp, genreDw;
   long genreMinUp, genreMinDw;
   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);
      }

        /* pour le connecteur de sortie, calculer son fanout (somme CIN) */

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

      if (conAux->ROOT != (void *)inst)
         {
         if (conAux->TYPE == EXTERNAL)
            {
                /* connecteur externe */
            sCin += cellLoadCin((char *)NULL, conAux->NAME);
            conExt += 1;
            }
         else
                /* connecteur interne */
            if (conAux->DIRECTION == IN)
               {
               loins_list *cellOut = (loins_list *)conAux->ROOT;

                        /* portes attaquees par l'instance a traiter */
               sCin += cellLoadCin(cellOut->FIGNAME, conAux->NAME);
               if (cellLoadType(cellOut->FIGNAME) == REG)
                  conReg += 1;
               }
            else
               {
               PRINTF("TIMING ANALYSIS : Unknown connector '%s' of %s[%s]\n",
                      conAux->NAME, ((loins_list *)conAux->ROOT)->INSNAME,
                      ((loins_list *)conAux->ROOT)->FIGNAME);
               }
         }
      }

   if (sCin == 0 && !((chain_list *)liste->DATA)->NEXT)
      {
	/* detection des portes avec la sortie en l'air */
      printf("\n\n\tNetlist %s has gate %s [%s] without fanouts.\n\n",
              NO_LOG->NAME, inst->INSNAME, inst->FIGNAME);
      exit(1);
      }

        /* memorisation de la somme des capa dans le champ USER du signal */
   sigOut->USER = addptype(sigOut->USER, (long)TOTCAPA, (void *)sCin);

   if (NO_TRACE >= 3)
      printf(" Computing delay on %s [%s], sum Cin = %d\n", inst->INSNAME, inst->FIGNAME, sCin);

        /* Parcours des connecteurs de l'instance a traiter pour
        trouver les connecteurs d'entree et recuperer les retards
        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 delaiInstUp = 0, delaiInstDw = 0;
         long delaiInstMinUp = 0, delaiInstMinDw = 0;
         long delaiGenUp = 0, delaiGenDw = 0;
         long delaiGenMinUp = 0, delaiGenMinDw = 0;
         long profond = 0;
         ptype_list *user;
         ptype_list *gener = (ptype_list *)NULL;

         if (user = getptype(con->SIG->USER, (long)DELAIUP))
            {
                   /* retards deja calcules ... */
            delaiGenUp = (long)user->DATA;
            delaiGenDw = (long)(getptype(con->SIG->USER, (long)DELAIDW))->DATA;
            delaiGenMinUp = (long)(getptype(con->SIG->USER, (long)DELAIMINUP))->DATA;
            delaiGenMinDw = (long)(getptype(con->SIG->USER, (long)DELAIMINDW))->DATA;
            profond = (long)(getptype(con->SIG->USER, (long)PROF)->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;
               if (NO_TRACE >= 3)
                  printf("  Gate %s generates signal on connector %s of %s\n",
                         cellGenere->INSNAME, con->NAME, inst->INSNAME);

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

               if (user = getptype(con->SIG->USER, (long)DELAIUP))
                  {
                        /* on recupere les retards tout juste calcules */
                  delaiGenUp = (long)user->DATA;
                  delaiGenDw = (long)(getptype(con->SIG->USER, (long)DELAIDW))->DATA;
                  delaiGenMinUp = (long)(getptype(con->SIG->USER, (long)DELAIMINUP))->DATA;
                  delaiGenMinDw = (long)(getptype(con->SIG->USER, (long)DELAIMINDW))->DATA;
                        /* on recupere la profondeur tout juste calculee */
                  profond = (long)(getptype(con->SIG->USER, (long)PROF)->DATA);
                  }
               else
                  {
                  PRINTF("ERROR TIMING ANALYSIS : no delay 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 : retards pas encore calcules */

                /* Calcul du retard du connecteur de l'instance a traiter
                        en fonction de sa polarite */
         switch (cellLoadPolarity(inst->FIGNAME))
            {
            case POS :
               delaiInstUp = delaiGenUp +
                             cellLoadTp(inst->FIGNAME, con->NAME, HH) +
                             (cellLoadR(inst->FIGNAME, con->NAME, UP) *
                             sCin) / 1000;
               delaiInstDw = delaiGenDw +
                             cellLoadTp(inst->FIGNAME, con->NAME, LL) +
                             (cellLoadR(inst->FIGNAME, con->NAME, DOWN) *
                             sCin) / 1000;
               delaiInstMinUp = delaiGenMinUp +
                             cellLoadTp(inst->FIGNAME, con->NAME, HH) +
                             (cellLoadR(inst->FIGNAME, con->NAME, UP) *
                             capaNot()) / 1000;
               delaiInstMinDw = delaiGenMinDw +
                             cellLoadTp(inst->FIGNAME, con->NAME, LL) +
                             (cellLoadR(inst->FIGNAME, con->NAME, DOWN) *
                             capaNot()) / 1000;
               break;
            case NEG :
               delaiInstUp = delaiGenDw +
                             cellLoadTp(inst->FIGNAME, con->NAME, LH) +
                             (cellLoadR(inst->FIGNAME, con->NAME, UP) *
                             sCin) / 1000;
               delaiInstDw = delaiGenUp +
                             cellLoadTp(inst->FIGNAME, con->NAME, HL) +
                             (cellLoadR(inst->FIGNAME, con->NAME, DOWN) *
                             sCin) / 1000;
               delaiInstMinUp = delaiGenMinDw +
                             cellLoadTp(inst->FIGNAME, con->NAME, LH) +
                             (cellLoadR(inst->FIGNAME, con->NAME, UP) *
                             capaNot()) / 1000;
               delaiInstMinDw = delaiGenMinUp +
                             cellLoadTp(inst->FIGNAME, con->NAME, HL) +
                             (cellLoadR(inst->FIGNAME, con->NAME, DOWN) *
                             capaNot()) / 1000;
               break;
            case AUT :
               delaiInstUp = MAX(
                             delaiGenUp +
                             cellLoadTp(inst->FIGNAME, con->NAME, HH) +
                             (cellLoadR(inst->FIGNAME, con->NAME, UP) *
                             sCin) / 1000,
                             delaiGenDw +
                             cellLoadTp(inst->FIGNAME, con->NAME, LH) +
                             (cellLoadR(inst->FIGNAME, con->NAME, UP) *
                             sCin) / 1000);
               delaiInstDw = MAX(
                             delaiGenUp +
                             cellLoadTp(inst->FIGNAME, con->NAME, HL) +
                             (cellLoadR(inst->FIGNAME, con->NAME, DOWN) *
                             sCin) / 1000,
                             delaiGenDw +
                             cellLoadTp(inst->FIGNAME, con->NAME, LL) +
                             (cellLoadR(inst->FIGNAME, con->NAME, DOWN) *
                             sCin) / 1000);
               delaiInstMinUp = MAX(
                             delaiGenMinUp +
                             cellLoadTp(inst->FIGNAME, con->NAME, HH) +
                             (cellLoadR(inst->FIGNAME, con->NAME, UP) *
                             capaNot()) / 1000,
                             delaiGenMinDw +
                             cellLoadTp(inst->FIGNAME, con->NAME, LH) +
                             (cellLoadR(inst->FIGNAME, con->NAME, UP) *
                             capaNot()) / 1000);
               delaiInstMinDw = MAX(
                             delaiGenMinUp +
                             cellLoadTp(inst->FIGNAME, con->NAME, HL) +
                             (cellLoadR(inst->FIGNAME, con->NAME, DOWN) *
                             capaNot()) / 1000,
                             delaiGenMinDw +
                             cellLoadTp(inst->FIGNAME, con->NAME, LL) +
                             (cellLoadR(inst->FIGNAME, con->NAME, DOWN) *
                             capaNot()) / 1000);
               break;
            }   /* switch sur la polarite */

         if (profond > maxProfond)
            maxProfond = profond;

         if (delaiInstDw > maxDelDw)
            {
            if (cellGenere)
               {
               criticDw = (void *)cellGenere;
               genreDw = LOINSDW;
               }
            else
               {
               criticDw = (void *)conGenere;
               genreDw = LOCONDW;
               }
            maxDelDw = delaiInstDw;
            }
         if (delaiInstUp > maxDelUp)
            {
            if (cellGenere)
               {
               criticUp = (void *)cellGenere;
               genreUp = LOINSUP;
               }
            else
               {
               criticUp = (void *)conGenere;
               genreUp = LOCONUP;
               }
            maxDelUp = delaiInstUp;
            }
         if (delaiInstMinDw > maxDelMinDw)
            {
            if (cellGenere)
               {
               criticMinDw = (void *)cellGenere;
               genreMinDw = LOINSMINDW;
               }
            else
               {
               criticMinDw = (void *)conGenere;
               genreMinDw = LOCONMINDW;
               }
            maxDelMinDw = delaiInstMinDw;
            }
         if (delaiInstMinUp > maxDelMinUp)
            {
            if (cellGenere)
               {
               criticMinUp = (void *)cellGenere;
               genreMinUp = LOINSMINUP;
               }
            else
               {
               criticMinUp = (void *)conGenere;
               genreMinUp = LOCONMINUP;
               }
            maxDelMinUp = delaiInstMinUp;
            }
         if (NO_TRACE >= 3)
            printf("INST %s Con %s Gen [%s] %d %d Delai %d %d\n",
                    inst->INSNAME, con->NAME, (cellGenere)?cellGenere->INSNAME:conGenere->NAME, delaiGenUp, delaiGenDw, delaiInstUp, delaiInstDw);
         }      /* 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) */

   if (maxDelUp == 0 || maxDelDw == 0)
      {
	/* Cas des cellules zero_y et one_y : pas d'entrees */
      maxDelUp = (cellLoadR(inst->FIGNAME, (char *)NULL, UP) * sCin) / 1000;
      maxDelDw = (cellLoadR(inst->FIGNAME, (char *)NULL, DOWN) * sCin) / 1000;
      maxDelMinUp = (cellLoadR(inst->FIGNAME, (char *)NULL, UP) * capaNot()) / 1000;
      maxDelMinDw = (cellLoadR(inst->FIGNAME, (char *)NULL, DOWN) * capaNot()) / 1000;
/*
      printf("WARNING : %s [%s] - DELAY UP = %d - DELAY DW = %d\n",
             inst->INSNAME, inst->FIGNAME, maxDelUp, maxDelDw);
*/
      }

   maxProfond++;

   if (NO_TRACE >= 2)
      printf("  delay of %s [%s] - UP %d - DW %d - Cin Sum %d - Depth = %d\n", 
             inst->INSNAME, inst->FIGNAME, maxDelUp, maxDelDw, sCin, maxProfond);
   if (NO_TRACE >= 3)
      printf("  cell fanin critique : UP %s  DW %s\n", (genreUp == LOINSUP)?((loins_list *)criticUp)->INSNAME : ((locon_list *)criticUp)->NAME, (genreDw == LOINSDW)?((loins_list *)criticDw)->INSNAME:((locon_list *)criticDw)->NAME);

        /* memorisation des retards critiques sur le signal de sortie de inst */
   sigOut->USER = addptype(sigOut->USER, (long)DELAIMINUP, (void *)maxDelMinUp);
   sigOut->USER = addptype(sigOut->USER, (long)DELAIMINDW, (void *)maxDelMinDw);
   sigOut->USER = addptype(sigOut->USER, (long)DELAIUP, (void *)maxDelUp);
   sigOut->USER = addptype(sigOut->USER, (long)DELAIDW, (void *)maxDelDw);

   inst->USER = addptype(inst->USER, genreMinUp, (void *)criticMinUp);
   inst->USER = addptype(inst->USER, genreMinDw, (void *)criticMinDw);
   inst->USER = addptype(inst->USER, genreUp, (void *)criticUp);
   inst->USER = addptype(inst->USER, genreDw, (void *)criticDw);

   sigOut->USER = addptype(sigOut->USER, (long)PROF, (void *)maxProfond);

   if (maxProfond > profondeurCircuit)
      {
      profondeurCircuit = maxProfond;
      instProf = inst;
      }

   if ((conExt > 0) || (conReg > 0))
      {
      if (maxDelUp > delaiCriticUp)
         {
         porteCriticUp = inst;
         delaiCriticUp = maxDelUp;
         }
      if (maxDelDw > delaiCriticDw)
         {
         porteCriticDw = inst;
         delaiCriticDw = maxDelDw;
         }
      if (maxDelMinUp > delaiCriticMinUp)
         {
         porteCriticMinUp = inst;
         delaiCriticMinUp = maxDelMinUp;
         }
      if (maxDelMinDw > delaiCriticMinDw)
         {
         porteCriticMinDw = inst;
         delaiCriticMinDw = maxDelMinDw;
         }
      }
   }
}

/*---------------------------------------------------------------------------
calcul_requiOut  :
-----------------------------------------------------------------------------
retour : RIEN. Memorisation des temps requis dans le champ USER des signaux
---------------------------------------------------------------------------*/
void calcul_requiOut(lofig, requiUp, requiDw)
lofig_list *lofig;
long requiUp, requiDw;
{
locon_list *con;

	/* Parcours des connecteurs externes de sortie */
for(con = lofig->LOCON; con; con = con->NEXT)
   if (con->DIRECTION == OUT)
      {
      loins_list *inst = (loins_list *)getptype(con->SIG->USER, (long)GENER)->DATA;
      long sCin = (long)getptype(con->SIG->USER, (long)TOTCAPA)->DATA;
      long RcUp = (cellLoadR(inst->FIGNAME, (char *)NULL, UP) * sCin) / 1000;
      long RcDw = (cellLoadR(inst->FIGNAME, (char *)NULL, DOWN) * sCin) / 1000;
      long slackUp = requiUp - (long)(getptype(con->SIG->USER, (long)DELAIUP)->DATA);
      long slackDw = requiDw - (long)(getptype(con->SIG->USER, (long)DELAIDW)->DATA);

      losig_list *sigOut = ((locon_list *)(getptype(inst->USER, (long)LOCONOUT)->DATA))->SIG;

      con->SIG->USER = addptype(con->SIG->USER, (long)REQUIUP, (void *)requiUp);
      con->SIG->USER = addptype(con->SIG->USER, (long)REQUIDW, (void *)requiDw);
      con->SIG->USER = addptype(con->SIG->USER, (long)SLACKUP, (void *)slackUp);
      con->SIG->USER = addptype(con->SIG->USER, (long)SLACKDW, (void *)slackDw);

      if ((MAX(RcUp, RcDw)))
         {
         long aspetCritic = ((MIN(slackUp, slackDw)) * (long)getptype(sigOut->USER, (long)PROF)->DATA) / (MAX(RcUp, RcDw));

         con->SIG->USER = addptype(con->SIG->USER, (long)CRITIC, (void *)aspetCritic);
/*
         if (aspetCritic == 0)
            printf("Con %s = critic = %d\n", con->NAME, aspetCritic);
*/

         listeCritic = tripType(listeCritic, aspetCritic, (void *)inst, UP);
         }
      else
         printf("Resistance nulle pour %s [%s]\n", inst->INSNAME, inst->FIGNAME);

      if (NO_TRACE >= 1)
         PRINTI("   required time of %s [output] - UP = %d - DOWN = %d\n", 
                con->NAME, requiUp, requiDw);
      }
}

/*---------------------------------------------------------------------------
tripType : ajoute dans une ptype_list a un elt sa place
           (tri des TYPE)
-----------------------------------------------------------------------------
retour   : ptype_list triee suivant sens (UP ou DOWN)
---------------------------------------------------------------------------*/
ptype_list *tripType(liste, type, data, sens)
ptype_list *liste;
long type;
void *data;
int sens;
{
if (!liste)
   return addptype(liste, type, data);
 
if ((sens == UP) && (type <= liste->TYPE))
   return addptype(liste, type, data);
else
   if ((sens == DOWN) && (type >= liste->TYPE))
      return addptype(liste, type, data);
   else
      {
      ptype_list *p1 = liste;
      ptype_list *p2 = liste->NEXT;
      ptype_list *new = (ptype_list *)mbkalloc(sizeof(ptype_list));

      while (((sens == UP  ) && p2 && (p2->TYPE < type)) || 
             ((sens == DOWN) && p2 && (p2->TYPE > type)))
         {
         p2 = p2->NEXT;
         p1 = p1->NEXT;
         }
      new->TYPE = type;
      new->DATA = data;
      new->NEXT = p2;
      p1->NEXT = new;
      return liste;
      }
}

/*---------------------------------------------------------------------------
calcul_requi : calcul des temps requis pour les instances d'une LOFIG
-----------------------------------------------------------------------------
retour       : les temps requis sont memorises dans le champ USER des signaux
---------------------------------------------------------------------------*/
void calcul_requi(lofig, requiUp, requiDw, tout)
lofig_list *lofig;
long requiUp, requiDw;
short tout;
{
loins_list *inst;

/*
PRINTF("Required times computation on %s\n", lofig->NAME);
*/

if (listeCritic)
   freeptype(listeCritic);
listeCritic = (ptype_list *)NULL;

/*
calcul_requiOut(lofig, requiUp, requiDw);
*/

        /* 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)REQUIUP))
      requi(inst, requiUp, requiDw, tout);
   }

if (!tout)
   {
	/* construction de la lisre critique */
   loins_list *porte = (loins_list *)NULL;
   int type;
   losig_list *porteOut;
   ptype_list *chemin;
   ptype_list *conCritic = (ptype_list *)NULL;

   if (delaiCriticUp > delaiCriticDw)
      {
      porte = porteCriticUp;
      type = UP;
      }
   else
      {
      porte = porteCriticDw;
      type = DOWN;
      }
   porteOut = ((locon_list *)getptype(porte->USER, (long)LOCONOUT)->DATA)->SIG;
   listeCritic = tripType(listeCritic, (long)getptype(porteOut->USER,
                          (long)TOTCAPA)->DATA , (void *)porte, DOWN);
   while (chemin = getptype(porte->USER, (long)((type== UP)?LOINSUP:LOINSDW)))
         {
         if ((type== UP) && (cellLoadPolarity(porte->FIGNAME) == NEG))
            type= DOWN;
         else
            if ((type== DOWN) && (cellLoadPolarity(porte->FIGNAME) == NEG))
               type= UP;
         porte = (loins_list *)chemin->DATA;
         porteOut = ((locon_list *)getptype(porte->USER, (long)LOCONOUT)->DATA)->SIG;
         listeCritic = tripType(listeCritic, (long)getptype(porteOut->USER,
                                (long)TOTCAPA)->DATA , (void *)porte, DOWN);
         }
   conCritic = getptype(porte->USER, (long)((type== UP)?LOCONUP:LOCONDW));
   if (conCritic)
      listeCritic = addptype(listeCritic, (long)0, conCritic->DATA);
   else
      listeCritic = addptype(listeCritic, (long)0, (void *)NULL);
   }

/*
PRINTF("End of required times computation on %s\n\n", lofig->NAME);

if (!tout)
   {
   ptype_list *p;

   for(p = listeCritic; p; p = p->NEXT)
      printf("%s = %d\n", ((loins_list *)p->DATA)->INSNAME, p->TYPE);
   }
*/
}

/*---------------------------------------------------------------------------
requi  : calcul du temps requis d'une instance (appel recursif sur les entrees)
-----------------------------------------------------------------------------
retour : RIEN. Memorisation des temps requis dans le champ USER des signaux
---------------------------------------------------------------------------*/
void requi(inst, requiUp, requiDw, tout)
loins_list *inst;
long requiUp, requiDw;
short tout;	/* tout = 1 : toutes les portes sont mises ds listeCritic
		   sinon seulement si critic = 0 */
{
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;  

   chain_list *lstCon;
   long minRequiUp = 999999, minRequiDw = 999999;
   long RcUp, RcDw, slackUp, slackDw, aspetCritic, slack;

   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 >= 3)
      printf(" Computing required time on %s [%s]\n",
             inst->INSNAME, inst->FIGNAME);

    /* 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)
         {
         long requiInstUp = 0, requiInstDw = 0;

         if (conAux->TYPE == INTERNAL)
            {
            loins_list *fanout = (loins_list *)conAux->ROOT;

            if (cellLoadType(fanout->FIGNAME) == REG)
               {
               requiInstUp = requiUp;
               requiInstDw = requiDw;
               }
            else
               {
               losig_list *fanoutSig;
               locon_list *fanoutCon;
               long requiOutUp = 0, requiOutDw = 0;
               ptype_list *user;
               long sCin = 0;

               fanoutCon = (locon_list *)getptype(fanout->USER, (long)LOCONOUT)->DATA;
               fanoutSig = fanoutCon->SIG;
               sCin = (long)(getptype(fanoutSig->USER, (long)TOTCAPA)->DATA);
/*
               printf("Fanout = %s (sCin = %d)\n", fanout->INSNAME, sCin);
*/

               if (user = getptype(fanoutSig->USER, (long)REQUIUP))
                  {
                   /* required times deja calcules ... */
                  requiOutUp = (long)user->DATA;
                  requiOutDw = (long)(getptype(fanoutSig->USER, (long)REQUIDW))->DATA;
                  }
               else
                  {
                   /* appel recursif pour le fanout */
                  requi(fanout, requiUp, requiDw, tout);
                      /* on recupere les required times tout juste calcules */
                  requiOutUp = (long)(getptype(fanoutSig->USER, (long)REQUIUP))->DATA;
                  requiOutDw = (long)(getptype(fanoutSig->USER, (long)REQUIDW))->DATA;
                  }   /* else : required times pas encore calcules */
   
               RcUp = (cellLoadR(fanout->FIGNAME, conAux->NAME, UP) * sCin) / 1000;
               RcDw = (cellLoadR(fanout->FIGNAME, conAux->NAME, DOWN) * sCin) / 1000;

                /* Calcul du required time */
               switch (cellLoadPolarity(fanout->FIGNAME))
                  {
                  case POS :
                     requiInstUp = requiOutUp -
                                   cellLoadTp(fanout->FIGNAME, conAux->NAME, HH) -
                                   RcUp;
                     requiInstDw = requiOutDw -
                                   cellLoadTp(fanout->FIGNAME, conAux->NAME, LL) -
                                   RcDw;
                     break;
                  case NEG :
                     requiInstUp = requiOutDw -
                                   cellLoadTp(fanout->FIGNAME, conAux->NAME, HL) -
                                   RcDw;
                     requiInstDw = requiOutUp -
                                   cellLoadTp(fanout->FIGNAME, conAux->NAME, LH) -
                                   RcUp;
                     break;
                  case AUT :
                     requiInstUp = MIN(
                                   requiOutUp -
                                   cellLoadTp(fanout->FIGNAME, conAux->NAME, HH) -
                                   RcUp,
                                   requiOutDw -
                                   cellLoadTp(fanout->FIGNAME, conAux->NAME, HL) -
                                   RcDw);
                     requiInstDw = MIN(
                                   requiOutUp -
                                   cellLoadTp(fanout->FIGNAME, conAux->NAME, LH) -
                                   RcUp,
                                   requiOutDw -
                                   cellLoadTp(fanout->FIGNAME, conAux->NAME, LL) -
                                   RcDw);
                     break;
                  }   /* switch sur la polarite */
               }
            }	/* connecteur interne */
         else
            {
/*
            printf("Fanout Con = %s\n", conAux->NAME);
*/
            requiInstUp = requiUp;
            requiInstDw = requiDw;
            }
         if (requiInstDw < minRequiDw)
            minRequiDw = requiInstDw;
         if (requiInstUp < minRequiUp)
            minRequiUp = requiInstUp;
         }
      }         /* parcours des connecteurs du fanout de l'instance (for) */

   if (NO_TRACE >= 2)
      printf("   required time of %s [%s] -UP = %d DW = %d\n", 
             inst->INSNAME, inst->FIGNAME, minRequiUp, minRequiDw);

   slackUp = minRequiUp - (long)(getptype(sigOut->USER, (long)DELAIUP)->DATA);
   slackDw = minRequiDw - (long)(getptype(sigOut->USER, (long)DELAIDW)->DATA);
   RcUp = (cellLoadR(inst->FIGNAME, (char *)NULL, UP  ) * (long)getptype(sigOut->USER, (long)TOTCAPA)->DATA) / 1000;
   RcDw = (cellLoadR(inst->FIGNAME, (char *)NULL, DOWN) * (long)getptype(sigOut->USER, (long)TOTCAPA)->DATA) / 1000;
   slack = (MIN(slackUp, slackDw));

   if ((slack != 0) && (slack *
       (long)getptype(sigOut->USER, (long)PROF)->DATA <=
       (MAX(RcUp, RcDw))))
      aspetCritic = 1;
   else
      aspetCritic = ((MIN(slackUp, slackDw)) * 
                   (long)getptype(sigOut->USER, (long)PROF)->DATA ) / 
                  (MAX(RcUp, RcDw));

        /* memorisation des required times sur le signal de sortie de inst */
   sigOut->USER = addptype(sigOut->USER, (long)REQUIUP, (void *)minRequiUp);
   sigOut->USER = addptype(sigOut->USER, (long)REQUIDW, (void *)minRequiDw);
   sigOut->USER = addptype(sigOut->USER, (long)SLACKUP, (void *)slackUp);
   sigOut->USER = addptype(sigOut->USER, (long)SLACKDW, (void *)slackDw);
   sigOut->USER = addptype(sigOut->USER, (long)CRITIC, (void *)aspetCritic);

   if (RcUp < 0 || RcDw < 0)
      printf(" !!! %s [%s] RC = %d / %d\n", inst->INSNAME, inst->FIGNAME, RcUp, RcDw);
   if (minRequiUp < 0 || minRequiDw < 0)
      printf(" !!! %s [%s] Requi = %d / %d\n", inst->INSNAME, inst->FIGNAME, minRequiUp, minRequiDw);
   if (slackUp < 0 || slackDw < 0)
      printf(" !!! %s [%s] Slack = %d / %d\n", inst->INSNAME, inst->FIGNAME, slackUp, slackDw);
   if (aspetCritic < 0)
      printf(" !!! %s critic = %d\n", inst->INSNAME, aspetCritic);
/*
   if (aspetCritic == 0)
            displayTimingInst(inst, 0);
*/

   if (tout)
      listeCritic = tripType(listeCritic, aspetCritic, (void *)inst, UP);
   }
}

/*---------------------------------------------------------------------------
displayCombi :
-----------------------------------------------------------------------------
retour     :
---------------------------------------------------------------------------*/
void displayCombi(liste)
ptype_list *liste;
{
ptype_list *l, *data;

printf("displayCombi :\n");
for(l = liste; l; l = l->NEXT)
   {
   printf("   %d =", l->TYPE);
   for(data = (ptype_list *)l->DATA; data; data = data->NEXT)
      printf(" %s", (char *)((locon_list *)data->DATA)->NAME);
   printf("\n");
   }
}

/*---------------------------------------------------------------------------
moins :
-----------------------------------------------------------------------------
retour     :
---------------------------------------------------------------------------*/
ptype_list *moins(liste, data)
ptype_list *liste;
void *data;
{
ptype_list *l, *retour = (ptype_list *)NULL;

for(l = liste; l; l = l->NEXT)
   if (l->DATA != data)
      retour = addptype(retour, (long)0, l->DATA);

return retour;
}

/*---------------------------------------------------------------------------
addAll :
-----------------------------------------------------------------------------
retour     :
---------------------------------------------------------------------------*/
ptype_list *addAll(liste, data)
ptype_list *liste;
void *data;
{
ptype_list *l;

for(l = liste; l; l = l->NEXT)
   l->DATA = (void *)addptype((ptype_list *)l->DATA, (long)0, data);

return liste;
}

/*---------------------------------------------------------------------------
combinaison :
-----------------------------------------------------------------------------
retour     :
---------------------------------------------------------------------------*/
ptype_list *combinaison(liste)
ptype_list *liste;
{
if (liste->NEXT)
   {
   ptype_list *l, *retour = (ptype_list *)NULL, *solution = (ptype_list *)NULL;
   ptype_list *sol;

   for(l = liste; l; l = l->NEXT)
      {
      ptype_list *listemoins = moins(liste, l->DATA);

      solution = addAll(combinaison(listemoins), l->DATA);
/*
      freeptype(listemoins);
*/
      for(sol = solution; sol; sol = sol->NEXT)
         retour = addptype(retour, (long)0, (void *)sol->DATA);
      }
   return retour;
   }
else
   return addptype((ptype_list *)NULL, (long)0, (void *)liste);
}

/*---------------------------------------------------------------------------
displayTimingInst : affiche des retards d'une instance
-----------------------------------------------------------------------------
retour        : RIEN. affichage
---------------------------------------------------------------------------*/
void displayTimingInst(inst, tout)
loins_list *inst;
short tout;  /* tout = 1, tous les signaux sont affiches, sinon que la sortie */
{
locon_list *con;
ptype_list *userCriticUp = getptype(inst->USER, (long)LOINSUP);
ptype_list *userCriticDw = getptype(inst->USER, (long)LOINSDW);

for(con = inst->LOCON; con; con = con->NEXT)
   if (!isvdd(con->NAME) && !isvss(con->NAME))
      if (con->DIRECTION == OUT || tout)
         {
         ptype_list *userUp = getptype(con->SIG->USER, (long)DELAIUP);
         ptype_list *userDw = getptype(con->SIG->USER, (long)DELAIDW);
         ptype_list *requiUp = getptype(con->SIG->USER, (long)REQUIUP);
         ptype_list *requiDw = getptype(con->SIG->USER, (long)REQUIDW);
         ptype_list *slackUp = getptype(con->SIG->USER, (long)SLACKUP);
         ptype_list *slackDw = getptype(con->SIG->USER, (long)SLACKDW);
         ptype_list *profond = getptype(con->SIG->USER, (long)PROF);
         ptype_list *capa   = getptype(con->SIG->USER, (long)TOTCAPA);
         ptype_list *critic   = getptype(con->SIG->USER, (long)CRITIC);

         if (userUp)
            printf("  %s [%s/%s] -\tDELAY  - UP = %d - DW = %d - CAPA = %d\n\t\t\tREQUI  - UP = %d - DW = %d\n\t\t\tSLACK  - UP = %d - DW = %d\n\t\t\tRESIST - UP = %d - DW = %d\n\t\t\tDEPTH  = %d  -  CRITICALITY = %d\n",
                   inst->INSNAME, inst->FIGNAME, con->NAME,
                   (long)userUp->DATA, (long)userDw->DATA,
                   (capa)?(long)capa->DATA:0,
                   (long)requiUp->DATA, (long)requiDw->DATA,
                   (long)slackUp->DATA, (long)slackDw->DATA,
                   cellLoadR(inst->FIGNAME, (char *)NULL, UP),
                   cellLoadR(inst->FIGNAME, (char *)NULL, DOWN),
                   (long)profond->DATA, (long)critic->DATA);
         else
            printf("ERROR : no delay for %s [%s/%s]\n",
                   inst->INSNAME, inst->FIGNAME, con->NAME);
         }
if (cellLoadType(inst->FIGNAME) != REG)
   {
   if (userCriticUp)
      printf("\t\t\tCRITIC - UP = %s", 
             ((loins_list *)userCriticUp->DATA)->INSNAME);
   else
      printf("\t\t\tCRITIC - UP = %s", 
             ((locon_list *)getptype(inst->USER, (long)LOCONUP)->DATA)->NAME);
   if (userCriticDw)
      printf(" - DW = %s\n", ((loins_list *)userCriticDw->DATA)->INSNAME);
   else
      printf(" - DW = %s\n", ((locon_list *)getptype(inst->USER, (long)LOCONDW)->DATA)->NAME);
   }
}

/*---------------------------------------------------------------------------
displayTiming : affiche des retards sur les signaux des instances de la LOFIG
-----------------------------------------------------------------------------
retour        : RIEN. affichage
---------------------------------------------------------------------------*/
void displayTiming(lofig, tout)
lofig_list *lofig;
short tout;  /* tout = 1, tous les signaux sont affiches, sinon que la sortie */
{
loins_list *inst;

printf("Display timing results\n");

for(inst = lofig->LOINS; inst; inst = inst->NEXT)
   displayTimingInst(inst, tout);

printf("End display timing results\n");
}


/*---------------------------------------------------------------------------
assignFaninLofig : assignation de fanin
-----------------------------------------------------------------------------
retour      :
---------------------------------------------------------------------------*/
void assignFaninLofig(lofig)
lofig_list *lofig;
{
loins_list *inst;

nbChgt = 0;
assignTH = createTH(1000);

printf("\nPin assignment\n");
for(inst = lofig->LOINS; inst; inst = inst->NEXT)
   assignFaninEx(inst, 1);	/* 1 = meilleur */

destroyTH(assignTH);

printf("  ==> %d new assignments\n", nbChgt);
}

/*---------------------------------------------------------------------------
assignFaninEx : assignation de fanin sur une instance (methode exhaustive)
-----------------------------------------------------------------------------
retour      : les signaux sont eventuellemnt echanges sur les connecteurs
              de l'instance a traiter
---------------------------------------------------------------------------*/
void assignFaninEx(inst, meilleur)
loins_list *inst;
short meilleur;
{
int polarite = cellLoadPolarity(inst->FIGNAME);
long maxDelUp = 0, maxDelDw = 0;

if (cellLoadType(inst->FIGNAME) == REG || cellLoadType(inst->FIGNAME) == BUS ||
    searchTH(assignTH, (char *)inst) != EMPTYTH)
   {
     /* instance deja traitee ou registre */
   return;
   }

      /* table de hachage des instances deja traitees */
addTH(assignTH, (char *)inst, 1);

if (polarite == AUT )
   {
   locon_list *con;
   losig_list *sigOut = ((locon_list *)getptype(inst->USER, (long)LOCONOUT)->DATA)->SIG;
   long sCin = (long)(getptype(sigOut->USER, (long)TOTCAPA)->DATA);

       /*  remise a jour des retards sur l'instance */
   for(con = inst->LOCON; con; con = con->NEXT)
      {
      if (con->DIRECTION == IN &&
          !isvdd(con->NAME) && !isvss(con->NAME))
         {
         long delaiGenUp = (long)(getptype(con->SIG->USER, (long)DELAIUP)->DATA);
         long delaiGenDw = (long)(getptype(con->SIG->USER, (long)DELAIDW)->DATA);

         long delaiInstUp = MAX(
                                delaiGenUp +
                                cellLoadTp(inst->FIGNAME, con->NAME, HH) +
                                (cellLoadR(inst->FIGNAME, con->NAME, UP) *
                                sCin) / 1000,
                                delaiGenDw +
                                cellLoadTp(inst->FIGNAME, con->NAME, LH) +
                                (cellLoadR(inst->FIGNAME, con->NAME, UP) *
                                sCin) / 1000);
         long delaiInstDw = MAX(
                                delaiGenUp +
                                cellLoadTp(inst->FIGNAME, con->NAME, HL) +
                                (cellLoadR(inst->FIGNAME, con->NAME, DOWN) *
                                sCin) / 1000,
                                delaiGenDw +
                                cellLoadTp(inst->FIGNAME, con->NAME, LL) +
                                (cellLoadR(inst->FIGNAME, con->NAME, DOWN) *
                                sCin) / 1000);

         if (delaiInstDw > maxDelDw)
            maxDelDw = delaiInstDw;
         if (delaiInstUp > maxDelUp)
            maxDelUp = delaiInstUp;
         }
      }  /* fin parcours connecteurs */
   if (sigOut->USER && getptype(sigOut->USER, (long)DELAIUP))
      {
      sigOut->USER = delptype(sigOut->USER, (long)DELAIUP);
      sigOut->USER = delptype(sigOut->USER, (long)DELAIDW);
      sigOut->USER = addptype(sigOut->USER, (long)DELAIUP, (void *)maxDelUp);
      sigOut->USER = addptype(sigOut->USER, (long)DELAIDW, (void *)maxDelDw);
      }
   else
      {
      printf("ERROR : No delay for instance %s on output signal %s\n", 
             inst->INSNAME, sigOut->NAMECHAIN->DATA);
      exit(1);
      }
   }
else
   {	/* polarite POS ou NEG */
   long sCin = 0, changement = 0;
   locon_list *con;
   losig_list *sigOut = ((locon_list *)getptype(inst->USER, (long)LOCONOUT)->DATA)->SIG;
   ptype_list *pUser = getptype(sigOut->USER, (long)TOTCAPA);
   long oldUp = (long)getptype(sigOut->USER, (long)DELAIUP)->DATA;
   long oldDw = (long)getptype(sigOut->USER, (long)DELAIDW)->DATA;
   chain_list *enveloppe = cellLoadEnvel(inst->FIGNAME), *env;

        /* Appel recursif sur les entrees */
   for(con = inst->LOCON; con; con = con->NEXT)
      if (con->DIRECTION == IN &&
          !isvdd(con->NAME) && !isvss(con->NAME))
         {
         ptype_list * user = getptype(con->SIG->USER, (long)GENER);

         if (user)
                /* Traitement recursif ... */
            assignFaninEx((loins_list *)(user->DATA), meilleur);
         }

        /* Recherche du fanout (somme des capas) */
   if (pUser)
      sCin = (long)pUser->DATA;
   else
      {
      printf("ERROR : no fanout input capacitances sum for %s\n",
             inst->INSNAME);
      exit(1);
      }

   if (NO_TRACE >= 2)
      {
      PRINTF(" Traitement of %s [%s], input capacitances sum = %d\n",
             inst->INSNAME, inst->FIGNAME, sCin);
      PRINTF("   delay of %s [%s] - UP = %d - DOWN = %d - Cin Sum = %d\n", 
             inst->INSNAME, inst->FIGNAME, oldUp, oldDw, sCin);
      }

        /* Parcours des connecteurs de l'enveloppe de l'instance a traiter */

   for(env = enveloppe; env; env = env->NEXT)
      {
      ptype_list *chainSig = NULL, *lstSig;
      ptype_list *chainCon = NULL, *lstCon;
      ptype_list *allCombi = NULL, *ssLstCon;
      ptype_list *sol;
      long max = 0;
      short nbSol = 0;

         /* on recherche les connecteurs IN faisant partie de l'enveloppe */
      for(con = inst->LOCON; con; con = con->NEXT)
         {
         if (con->DIRECTION == IN &&
             !isvdd(con->NAME) && !isvss(con->NAME) &&
             inListe((chain_list *)env->DATA, con->NAME))
            {
            long delaiConUp, delaiConDw;
            long delUp, delDw;

                /* calcul du Tp+RC Up et Dw pour le connecteur */
            switch (polarite)
               {
               case POS :
                  delaiConUp = cellLoadTp(inst->FIGNAME, con->NAME, HH) +
                               (cellLoadR(inst->FIGNAME, con->NAME, UP) *
                                sCin) / 1000;
                  delaiConDw = cellLoadTp(inst->FIGNAME, con->NAME, LL) +
                               (cellLoadR(inst->FIGNAME, con->NAME, DOWN) *
                                sCin) / 1000;
                  break;
               case NEG :
                  delaiConUp = cellLoadTp(inst->FIGNAME, con->NAME, LH) +
                               (cellLoadR(inst->FIGNAME, con->NAME, UP) *
                                sCin) / 1000;
                  delaiConDw = cellLoadTp(inst->FIGNAME, con->NAME, HL) +
                               (cellLoadR(inst->FIGNAME, con->NAME, DOWN) *
                                sCin) / 1000;
                  break;
               }

            if (NO_TRACE >= 3)
               PRINTF("    on connector %s : intrinsic delay UP = %d - intrinsic delay DOWN = %d\n",
                      con->NAME, delaiConUp, delaiConDw);

                /* sauvegarde des delais par connecteurs dans USER */
            con->USER = addptype(con->USER, (long)LOCONUP, (void *)delaiConUp);
            con->USER = addptype(con->USER, (long)LOCONDW, (void *)delaiConDw);

               /* Liste des signaux et des connecteurs de l'enveloppe */
            chainCon = addptype(chainCon, (long)0, (void *)con);
            chainSig = addptype(chainSig, (long)0, (void *)con->SIG);

                  /* on recupere les retards sur les signaux */
            delUp = (long)getptype(con->SIG->USER, (long)DELAIUP)->DATA;
            delDw = (long)getptype(con->SIG->USER, (long)DELAIDW)->DATA;

            if (NO_TRACE >= 3)
               PRINTF("    on signal %s : delay UP = %d - delay DOWN = %d\n",
                      (char *)con->SIG->NAMECHAIN->DATA, delUp, delDw);

            }   /* if connecteur IN et dans enveloppe */
         }	/* for sur les connecteurs de l'instance */

      allCombi = combinaison(chainCon);

         /* parcours des permutations des connecteurs de l'enveloppe */
      for(lstCon = allCombi; lstCon; lstCon = lstCon->NEXT)
         {
         long max = 0;

/*
         if (NO_TRACE >= 2)
            PRINTF("     Solution number %d\n", ++nbSol);
*/
         for(lstSig = chainSig, ssLstCon = (ptype_list *)lstCon->DATA;
             lstSig;
             lstSig = lstSig->NEXT, ssLstCon = ssLstCon->NEXT)
            {
            long delaiInstUp, delaiInstDw;

               /* on recupere les retards sur les signaux */
            long delaiGenUp =
                 (long)getptype(((losig_list *)(lstSig->DATA))->USER,
                                (long)DELAIUP)->DATA;
            long delaiGenDw = 
                 (long) getptype(((losig_list *)(lstSig->DATA))->USER,
                                 (long)DELAIDW)->DATA;

		/* on recupere les Tp+RC Up et Dw des connecteurs */
            long delaiConUp =
                 (long)getptype(((locon_list *)(ssLstCon->DATA))->USER,
                                (long)LOCONUP)->DATA;
            long delaiConDw = 
                 (long)getptype(((locon_list *)(ssLstCon->DATA))->USER,
                                (long)LOCONDW)->DATA;

                /* pour le connecteur et le signal calcul de :
                   MAX(delaiGenUp + Tp+RC Up, delaiGenDw + Tp+RC Dw) */
            switch (polarite)
               {
               case POS :
                  delaiInstUp = delaiGenUp + delaiConUp;
                  delaiInstDw = delaiGenDw + delaiConDw;
                  break;
               case NEG :
                  delaiInstUp = delaiGenDw + delaiConUp;
                  delaiInstDw = delaiGenUp + delaiConDw;
                  break;
               }
            if (NO_TRACE >= 3)
               PRINTF("       signal %s on connector %s : UP = %d - DOWN = %d\n",
                      (char *)((losig_list *)lstSig->DATA)->NAMECHAIN->DATA,
                      ((locon_list *)ssLstCon->DATA)->NAME,
                      delaiInstUp, delaiInstDw);
            if (max <= (MAX(delaiInstUp, delaiInstDw)))
               max = MAX(delaiInstUp, delaiInstDw);
            }
         lstCon->TYPE = max;
         }  /* fin parcours des permutations */

/*
      displayCombi(allCombi);
*/

      if (meilleur)
         max = 999999;
      else
         max = 0;

      for(lstCon = allCombi; lstCon; lstCon = lstCon->NEXT)
         if (meilleur)
            {
            if (lstCon->TYPE < max)
               {
               max = lstCon->TYPE;
               sol = lstCon;
               }
            }
         else
            if (lstCon->TYPE > max)
               {
               max = lstCon->TYPE;
               sol = lstCon;
               }
      freeptype(chainCon);
      chainCon = (ptype_list *)sol->DATA;

            /* Mise en oeuvre de la solution choisie */
      for(lstSig = chainSig, lstCon = chainCon;
          lstSig; lstSig = lstSig->NEXT, lstCon = lstCon->NEXT)
         {
         long delaiGenUp, delaiGenDw;
         long delaiInstUp, delaiInstDw;
   
         if (((locon_list *)lstCon->DATA)->SIG != (losig_list *)lstSig->DATA)
            {
            ((locon_list *)lstCon->DATA)->SIG = (losig_list *)lstSig->DATA;
            if (changement == 0)
               {
               if (NO_TRACE >= 1)
                  PRINTF("    new assignment on %s[%s] :\n",
                         inst->INSNAME, inst->FIGNAME);
               changement = 1;
               }
            }
         delaiGenUp = (long)(getptype(((losig_list *)lstSig->DATA)->USER, (long)DELAIUP)->DATA);
         delaiGenDw = (long)(getptype(((losig_list *)lstSig->DATA)->USER, (long)DELAIDW)->DATA);
         delaiInstUp = (long)(getptype(((locon_list *)lstCon->DATA)->USER, (long)LOCONUP)->DATA);
         delaiInstDw = (long)(getptype(((locon_list *)lstCon->DATA)->USER, (long)LOCONDW)->DATA);

         switch (polarite)
           {
           case POS : delaiInstUp = delaiGenUp + delaiInstUp;
                      delaiInstDw = delaiGenDw + delaiInstDw;
                      break;
           case NEG : delaiInstUp = delaiGenDw + delaiInstUp;
                      delaiInstDw = delaiGenUp + delaiInstDw;
                      break;
           }
         if (NO_TRACE >= 3)
            PRINTF("     -> signal %s on connector %s\n",
                  ((locon_list *)lstCon->DATA)->SIG->NAMECHAIN->DATA,
                  ((locon_list *)lstCon->DATA)->NAME);
  
         if (delaiInstDw > maxDelDw)
            maxDelDw = delaiInstDw;
         if (delaiInstUp > maxDelUp)
            maxDelUp = delaiInstUp;
         }
/*
      for(pListe = allCombi; pListe; pListe = pListe->NEXT)
         {
         freeptype((ptype_list *)pListe->DATA);
         pListe->DATA = NULL;
         }
*/
      freeptype(allCombi);
      freeptype(chainSig);
      }   /* fin du parcours de l'enveloppe */

          /* sauvegarde du nouveau retard de l'instance */
   if (sigOut->USER && getptype(sigOut->USER, (long)DELAIUP))
      {
      sigOut->USER = delptype(sigOut->USER, (long)DELAIUP);
      sigOut->USER = delptype(sigOut->USER, (long)DELAIDW);
      sigOut->USER = addptype(sigOut->USER, (long)DELAIUP, (void *)maxDelUp);
      sigOut->USER = addptype(sigOut->USER, (long)DELAIDW, (void *)maxDelDw);
      }
   else
      {
      PRINTF("ERROR : No delay for instance %s on output signal %s\n", 
             inst->INSNAME, sigOut->NAMECHAIN->DATA);
      exit(1);
      }
   if (NO_TRACE >= 2)
      PRINTF("   delay of %s [%s] - UP = %d - DOWN = %d - Cin Sum = %d\n", 
             inst->INSNAME, inst->FIGNAME, maxDelUp, maxDelDw, sCin);

   nbChgt = nbChgt + changement;
   }   /* instance de polarite POS ou NEG */
}      /* traitement de l'instance */
