/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit : DESB  v2.n                                                  */
/*    Fichier : tautol.c                                                    */
/*                                                                          */
/*    (c) copyright 1991 Laboratoire MASI equipe CAO & VLSI                 */
/*    Tous droits reserves                                                  */
/*    Support : e-mail cao-vlsi@masi.ibp.fr                                 */
/*                                                                          */
/*    Auteur(s) : Marc LAURENTIN                        le : 06/09/1991     */
/*                                                                          */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*                                                                          */
/****************************************************************************/

#include "declar.h"


static void cleanBddUser();
static chain_list * makeLocalOrder();
static chain_list * coneInOrder();
static chain_list * insertConeInOrder();

/****************************************************************************
 *                         fonction test_conflict();                        *
 ****************************************************************************/
/*-------------------------------------------------------------------------+
| teste si le cone est localement conflictuel. TOUTES les branches conflic |
| sont typees comme telle.                                                 |
| Entree: Un pointeur de cone ptcone                                       |
| Sortie: Neant                                                            |
+-------------------------------------------------------------------------*/
long            test_conflict(ptcone)
cone_list      *ptcone;
{
link_list      *ptlink0, *ptlink1;
list_list      *ptlist0, *ptlist1;
short           conflict = 0;
long            count_flict = 0;

/*------------------------------------------------------*/
/*       nettoyage des champs                           */
/*------------------------------------------------------*/
ptcone->TYPE = (ptcone->TYPE & ~CONFLICT);

   for (ptlist0 = ptcone->PATH; ptlist0 != NULL; ptlist0 = ptlist0->NEXT)
   { 
   ptlist0->TYPE = (ptlist0->TYPE & ~CONFLICT);
   }


   /*------------------------------------------------------*/
   /*     recherche des branches conflictuelles            */
   /*------------------------------------------------------*/
   for (ptlist0 = ptcone->PATH; ptlist0 != NULL; ptlist0 = ptlist0->NEXT)
   {
      for (ptlist1 = ptlist0->NEXT; ptlist1 != NULL; ptlist1 = ptlist1->NEXT)
      {
         if  ( (((((ptlist0->TYPE & VDD) == VDD) || ((ptlist0->TYPE & EXT) == EXT))
         && (((ptlist1->TYPE & VSS) == VSS) || ((ptlist1->TYPE & EXT) == EXT)))
         || ((((ptlist0->TYPE & VSS) == VSS) || ((ptlist0->TYPE & EXT) == EXT))
         && (((ptlist1->TYPE & VDD) == VDD) || ((ptlist1->TYPE & EXT) == EXT))))
         && ((ptlist1->TYPE & BLEEDER)!=BLEEDER)
         && ((ptlist0->TYPE & BLEEDER)!=BLEEDER) )
         {
         conflict = 1;
            for (ptlink0 = (link_list*)ptlist0->DATA; ptlink0 != NULL;
             ptlink0 = ptlink0->NEXT)
            {
               if (((ptlink0->TYPE & TP) == TP) || ((ptlink0->TYPE & TN) == TN))
               {
                  for (ptlink1 = (link_list*)ptlist1->DATA; ptlink1 != NULL;
                 ptlink1 = ptlink1->NEXT)
                  {
                     if ((((ptlink1->TYPE & TP) == TP)
                      && ((ptlink0->TYPE & TN) == TN))
                      || (((ptlink1->TYPE & TN) == TN)
                      && ((ptlink0->TYPE & TP) == TP)))
                     {
                        if (ptlink1->TRANS->GRID == ptlink0->TRANS->GRID)
                        {
                        conflict = 0;
                        break;
                        }
                     }
                  }
               }
               if (conflict == 0) { break; } 
            }
         }

         if (conflict == 1)
         {
         ptcone->TYPE = (ptcone->TYPE | CONFLICT);
         return(1);
         }
      }
   }
/* pas de conflit detecte */
return(0);
}


/****************************************************************************
 *                         fonction test_hz();                              *
 ****************************************************************************/

          /*-------------------------------------------*
           | entree : cone, un pointeur de cone        |
           | sortie : 0 si le cone est not HZ          |
           |        : 1 sinon                          |
           *-------------------------------------------*/

short test_hz(cone)
cone_list * cone;
{
pNode sup        = zero;        /* Fup  initialisee a 0   */
pNode sext       = zero;        /* Fext initualisee a 0   */
pNode stot       = zero;        /* la somme des trois     */
list_list *path  = NULL;
link_list *link  = NULL;
short test       = 1;
long index      = 2;           /* index des entrees suivant leur */
                                /* ordre d'apparition             */
chain_list * order = NULL;
chain_list * ch ;


   if (((cone->TYPE & VDD)==VDD) || ((cone->TYPE & VSS)==VSS)) 
   {
   (cone->TYPE)&=(~HZ);
   return(0);
   }
   if ((test=test_pullx(cone)) == 0) 
   {
   (cone->TYPE)&=(~HZ);
   return(0);
   }

(cone->TYPE)|=(HZ);

/*------------------------------------------------------------+
| Ordonnancement des Bdd puis affectation des index aux cones |
+------------------------------------------------------------*/
order = makeLocalOrder(cone) ;
   for(ch=order;ch!=NULL;ch=ch->NEXT)
   {
   cone_list* var = (cone_list*) ch->DATA ;
   var->USER=addptype(var->USER,BDD_INDEX,(void*)index++);
   }
freechain(order);

   for (path=cone->PATH;path!=NULL;path=path->NEXT)
   {
   
      if ((path->TYPE & BLEEDER)==BLEEDER) continue;

      /*--------------------------------------------------------*
       | On ajoute sans distinction Sup et Sdwn                 |
       *--------------------------------------------------------*/
      if ( ((path->TYPE & VDD)==VDD) || ((path->TYPE & VSS)==VSS) )
      {
      pNode term = one;
         for(link=(link_list *)path->DATA;link!=NULL;link=link->NEXT)
         {
         cone_list *grille = NULL;
         pNode     symbole ;
         ptype_list * user;

            if ((link->TYPE & RESIST)==RESIST) continue;

         grille=(cone_list*)link->TRANS->GRID;
         user=getptype(grille->USER,BDD_INDEX);

            if (user == NULL)
            {
            grille->USER=addptype(grille->USER,BDD_INDEX,(void*)index);
            symbole = createNodeTermBdd(index++);
            }
            else symbole=createNodeTermBdd((short)((long)user->DATA));

            if ((link->TYPE & TP)==TP) symbole=notBdd(symbole);

         term=applyBinBdd(AND,term,symbole);
         }
      sup=applyBinBdd(OR,sup,term);
      }

      else if ((path->TYPE & EXT)==EXT)
      {
      pNode term = one;
         for(link=(link_list *)path->DATA;link!=NULL;link=link->NEXT)
         {
         cone_list *grille = NULL;
         pNode     symbole = NULL;
         ptype_list * user;

            if ((link->TYPE & RESIST)==RESIST) continue;
            if (link->NEXT == NULL) break;

         grille=(cone_list*)link->TRANS->GRID;
         user=getptype(grille->USER,BDD_INDEX);

            if (user == NULL)
            {
            grille->USER=addptype(grille->USER,BDD_INDEX,(void*)index);
            symbole = createNodeTermBdd(index++);
            }
            else symbole=createNodeTermBdd((short)((long)user->DATA));

            if ((link->TYPE & TP)==TP) symbole=notBdd(symbole);

         term=applyBinBdd(AND,term,symbole);
         }
      sext=applyBinBdd(OR,sext,term);
      }
      else 
      {
      dsbBug(13,"test_hz",cone->NAME,NULL,0);
      }
   }
cleanBddUser(cone);
stot=applyBinBdd(OR,sup,sext);

   if(stot==one) 
   {
   (cone->TYPE)&=(~HZ);
   MaxNoeud=(MaxNoeud<sysBdd.pRT->compteur ? sysBdd.pRT->compteur : MaxNoeud);
   resetBdd();
   return(0);
   }
   else 
   {
   MaxNoeud=(MaxNoeud<sysBdd.pRT->compteur ? sysBdd.pRT->compteur : MaxNoeud);
   resetBdd();
   return(1); 
   }
}

/****************************************************************************
 *                         fonction makeLocalOrder();                       *
 ****************************************************************************/
/*--------------------------------------------------------------------------+
| Petit algo d'ordonnancement des bdd pour l'analyse locale : Pour chaque   |
| branche est constitue la liste(locale) des var qui attaquent les trans de |
| celle ci. Si  aucune d'entre elles n'est deja presente dans l'ordre       |
| alors l'ordre est directement enrichi  de la liste locale. Dans le cas    |
| contraire, on insere les variables inedites de la liste locale apres la   |
| la variable locale qui se trouvait  deja dans l'ordre                     |
+--------------------------------------------------------------------------*/
static chain_list*  makeLocalOrder(cone)
cone_list * cone ;
{
list_list * path ;
chain_list * chloc ;
chain_list * order = NULL ;

   for(path=cone->PATH;path!=NULL;path=path->NEXT)
   {
   link_list * link ;
   chain_list * p1 ;
   chain_list * test ;
   chloc = NULL ;

      if((path->TYPE & BLEEDER)==BLEEDER) continue ;

      /* On constitue la liste locale */ 
      for(link=(link_list*)path->DATA;link!=NULL;link=link->NEXT)
      {
         if((link->TYPE & RESIST)==RESIST) continue ;
         if((link->NEXT==NULL)&&((path->TYPE & EXT)==EXT)) continue ;
      chloc = addchain(chloc,(void*)link->TRANS->GRID);
      }

      /*  les variables de la liste locale sont elle inedites ? */
      for(p1=chloc;p1!=NULL;p1=p1->NEXT)
         if((test=coneInOrder(order,(cone_list*)p1->DATA))!=NULL) break;

      if (test==NULL) /* pas de cone deja dans order*/
      order=append(order,chloc);
      else
      {
         for(p1=chloc;p1!=NULL;p1=p1->NEXT)
            if(coneInOrder(order,(cone_list*)p1->DATA)==NULL)
            order=insertConeInOrder(order,(cone_list*)test->DATA,
                                          (cone_list*)p1->DATA);
      freechain(p1);
      }
   }
return(order);
}
         
/****************************************************************************
 *                         fonction coneInOrder();                          *
 ****************************************************************************/
static chain_list * coneInOrder(order,cone)
chain_list * order ;
cone_list * cone ;
{
chain_list * pchain ;

   for(pchain=order;pchain!=NULL;pchain=pchain->NEXT)
      if(pchain->DATA == (void*)cone) return(pchain);

return(NULL);
}

/****************************************************************************
 *                         fonction insertConeInOrder();                    *
 ****************************************************************************/
static chain_list * insertConeInOrder(order,prevCone,cone)
chain_list * order ;
cone_list * cone   , *prevCone;
{
chain_list * pchain ;
chain_list * insert = addchain(NULL,(void*)cone);

   if(order==NULL) return(insert);

   for(pchain=order;pchain!=NULL;pchain=pchain->NEXT)
   {
      if(pchain->DATA == (void*)prevCone)
      {
         if(pchain->NEXT==NULL)
         pchain->NEXT=insert ;
         else
         {
         chain_list * sav = pchain->NEXT ;
         pchain->NEXT = insert ;
         insert->NEXT = sav ;
         }
      break ;
      }
   }
return(order);
}

/****************************************************************************
 *                         fonction test_pullx();                           *
 ****************************************************************************/

             /*-----------------------------------------*
              | test si le cone contient un chemin      |
              | essentiellememt constitue de resistance |
              | renvoie : 1 si non trouve               |
              |         : 0 si un tel chemin est trouve |
              *-----------------------------------------*/

short test_pullx(ptcone)
cone_list * ptcone;
{
list_list *ptpath = NULL;
link_list *ptlink = NULL;
int flag = 0;

   for (ptpath=ptcone->PATH;ptpath;ptpath=ptpath->NEXT)
   {
      if ((ptpath->TYPE & BLEEDER)==BLEEDER) continue;

   flag=0;

      for(ptlink=(link_list*)ptpath->DATA;ptlink;ptlink=ptlink->NEXT)
      {
         if((ptlink->TYPE & RESIST)==RESIST) continue;
         else if (((ptlink->TYPE & IN)==IN)||((ptlink->TYPE & INOUT)==INOUT) ) continue;
      flag=1;
      break;
      }

      if(flag==0) return(0);
   }
return(1);
}


/********************************************
 * fonction tjr_actif ();                    *
 * teste pour chaque branche si le cone est  *
 * encore not HZ si on l enleve du cone.     *
 * si oui la branche est typee BLEEDER       *
 * entree: un cone conflictuel et not HZ     *
 * sortie: neant                             *
 *********************************************/
void tjr_actif(cone)
cone_list * cone;
{
list_list *path;
short test=0;
short flag=0;
short chemindex=1;

   if ((cone->TYPE & EXT)==EXT) return;

   for (path=cone->PATH;path!=NULL;path=path->NEXT)
   {
   chemindex++;
      if ((path->TYPE & BLEEDER)==BLEEDER) continue;
   (path->TYPE)|=BLEEDER;
   test=test_hz(cone);
      if (test==0) 
      {
      flag=1;
      continue;
      }
      else (path->TYPE)&=(~BLEEDER);
   }

   if (flag ==1) 
   {
   marq_incone(cone);
   }
}



/****************************************************************************
 *                         fonction clean_bdduser();                        *
 ****************************************************************************/
void clean_bdduser(cone)
cone_list * cone;
{
list_list * in = NULL;

   for (in=cone->INCONE;in!=NULL;in=in->NEXT)
   {
   cone_list * pcone;
   ptype_list * user;

      if ( ((in->TYPE & CONE_TYPE)!=CONE_TYPE) ||
           ((in->TYPE & LOOP)==LOOP) ) continue ;

   pcone=(cone_list *)in->DATA;
   user=getptype(pcone->USER,BDD_INDEX);

      if(user != NULL) pcone->USER=delptype(pcone->USER,BDD_INDEX);
   }
}

/****************************************************************************
 *                         fonction cleanBddUser();                         *
 ****************************************************************************/
static void cleanBddUser(cone)
cone_list * cone ;
{
cone_list * in ;
link_list * link;
list_list * path ;
ptype_list * user ;

   for (path=cone->PATH;path != NULL;path=path->NEXT)
   {
      if((path->TYPE & BLEEDER)==BLEEDER) continue ;
   
      for(link=(link_list*)path->DATA;link != NULL ;link=link->NEXT)
      {
         if((link->TYPE & RESIST)==RESIST) continue ;

         if((link->NEXT ==NULL)&&((path->TYPE & EXT)==EXT))
         continue ;

      in = (cone_list*)link->TRANS->GRID ;
      user=getptype(in->USER,BDD_INDEX);

         if(user!=NULL) in->USER=delptype(in->USER,BDD_INDEX);
      }
   }
}
         


/****************************************************************************
 *                         fonction test_dual();                            *
 ****************************************************************************/

                   /* detection des cones DUAL CMOS */

void test_dual( pt_cone )

cone_list	*pt_cone ;

{
int flagup = 0;
int flagdwn = 0;
list_list *ptpath = NULL;

(pt_cone->TYPE) &= ~DUAL ;


if ( ( pt_cone->TYPE & (AUTRE | TPINVSS | TNINVDD | CONFLICT | HZ | VDD | VSS ) ) == 0L )
   {
      for (ptpath=pt_cone->PATH;ptpath;ptpath=ptpath->NEXT)
      {
         if ((ptpath->TYPE & VDD)==VDD) flagup =1;
         if ((ptpath->TYPE & VSS)==VSS) flagdwn=1;
      }
      if ((flagup==1)&&(flagdwn==1))	(pt_cone->TYPE) |= DUAL ;
      else	(pt_cone->TYPE) |= DUAL ;
   }
   else	(pt_cone->TYPE) &= ~DUAL ;
}

