/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit : DESB  v2.n                                                  */
/*    Fichier : regist.c                                                    */
/*                                                                          */
/*    (c) copyright 1993 Laboratoire MASI equipe CAO & VLSI                 */
/*    Tous droits reserves                                                  */
/*    Support : e-mail cao-vlsi@masi.ibp.fr                                 */
/*                                                                          */
/*    Auteur(s) : Marc LAURENTIN                        le : 15/02/1993     */
/*                                                                          */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*                                                                          */
/****************************************************************************/
#include"declar.h"

#define DSB_INV   ((long)0x00000001)
#define DSB_BLE   ((long)0x00000002)
#define DSB_NAN   ((long)0x00000004)
#define DSB_NOR   ((long)0x00000008)
#define DSB_ANDOR ((long)0x00000010)
#define DSB_SW1   ((long)0x00000020)
#define DSB_SW2   ((long)0x00000040)
#define DSB_PAS   ((long)0x00000080)
#define DSB_DEF   ((long)0x80000000)  /* default pour typage commandes */

static long whichLoop();
static int  isRegist();
static long invBoucl();
static long bleBoucl();
static long nanBoucl();
static long norBoucl();
static long sw1Boucl();
static long sw2Boucl();
static long pasBoucl();
static long andOrBoucl();
static chain_list* paralBleed();
static chain_list * invChain();
static short AinvchainB();
static short latchRolMar();


/****************************************************************************
 *                         fonction test_latch();                           *
 ****************************************************************************/
int test_latch(cone,dualBoucle,fig)
cone_list * cone ;
int * dualBoucle ;
desafig_list * fig ;
{
list_list * input ;
list_list * output ;
cone_list * bclCone ;
int res ;

   for(input=cone->INCONE;input!=NULL;input=input->NEXT)
   {
      for(output=cone->OUTCONE;output!=NULL;output=output->NEXT)
      {
         if(((input->TYPE & EXT )!=EXT) &&
            ((output->TYPE & EXT)!=EXT) &&
            (output->DATA == input->DATA) &&
            ((output->TYPE & LOOP)!=LOOP) &&
            ((input->TYPE & LOOP)!=LOOP) &&
            ((input->TYPE & NOTLATCH)!=NOTLATCH)&&
            ((output->TYPE & NOTLATCH)!=NOTLATCH))

         {

         bclCone=(cone_list*)output->DATA ;
         res=isRegist(cone,bclCone,fig);

            if(res==3) return(3); 
            else if (res==0)
            {
            mark_inout(cone,bclCone,NOTLATCH);
            mark_inout(bclCone,cone,NOTLATCH);
            }
         continue ;
         }
      }
   }
}

/****************************************************************************
 *                         fonction isRegist();                             *
 ****************************************************************************/
static int isRegist(cone0,cone1,fig)
cone_list * cone0 ;
cone_list * cone1 ;
desafig_list * fig ;
{
long res0 ;
long res1 ;
long result ;


res0 = whichLoop(cone0,cone1) ;
   if ( res0==0) return(0) ;

res1 = whichLoop(cone1,cone0) ;
   if(res1==0) return(0) ;

result = res0 | res1 ;

   switch (result) 
   {
   /*-----------------------------------------+
   |  BLEEDER                                 |
   +-----------------------------------------*/
   case (DSB_BLE | DSB_INV) :
   case (DSB_BLE | DSB_NAN) :
   case (DSB_BLE | DSB_NOR) :
   {
   cone_list * blCone ;
   cone_list * othCone ;
   list_list * path ;
   chain_list * chain ;
   chain_list * chainParal ;
   
      if (res0 == DSB_BLE)
      { 
      blCone = cone0 ;
      othCone = cone1 ;
      }
      else
      {
      blCone=cone1 ;
      othCone=cone0 ;
      }

      for(path=blCone->PATH;path!=NULL;path=path->NEXT)
      {
         if((path->TYPE & EXT    )==EXT    ) continue ;
         if((cone_list*) (((link_list*)path->DATA)->TRANS->GRID)!=othCone)
         continue ;
         if((path->TYPE & BLEEDER)==BLEEDER) continue ;
         if((path->TYPE & TNINVDD)==TNINVDD) continue ;
         if((path->TYPE & TPINVSS)==TPINVSS) continue ;
         if(((link_list*)path->DATA)->NEXT != NULL) continue ;
      break ;
      } 

   blCone->TYPE |= BLEEDER ;
   path->TYPE |= BLEEDER ;
   
   chain=addchain(NULL,(void*)path);
   blCone->USER=addptype(blCone->USER,BLEEDER,(void*)chain);

   chain=addchain(NULL,(void*)(((link_list*)path->DATA)->TRANS));
   chainParal=paralBleed(blCone);
   chain=append(chain,chainParal);
   fx_chem1(chain,blCone,othCone,fig);
   chain=delchain(chain,chain);
   mark_inout(blCone,othCone,(LOOP|LATCH));
   marq_incone(blCone);

   return(2);

   break ;
   }

   /*------------------------------------------------+
   | 2 INVERSEURS REBOUCLES                          |
   +------------------------------------------------*/
   case (DSB_INV) :  
   {
   list_list* path0 ;
   list_list* path01;
   list_list* path02 ;
   list_list* path1 ;
   list_list* path11;
   list_list* path12 ;
   link_list* link0 ;
   link_list* link1 ;
   lotrs_list* trans0 ;
   lotrs_list* trans1 ;
   chain_list * chain ;

      /*-------------------------------------------------------------+
      | On recherche les branches de contre reaction                 |
      +-------------------------------------------------------------*/
      for (path0=cone0->PATH;path0!=NULL;path0=path0->NEXT)
      {
         if((path0->TYPE & EXT    )==EXT    ) continue ;
         if((cone_list*) (((link_list*)path0->DATA)->TRANS->GRID)!=cone1)
         continue ;
         if((path0->TYPE & BLEEDER)==BLEEDER) continue ;
         if((path0->TYPE & TNINVDD)==TNINVDD) continue ;
         if((path0->TYPE & TPINVSS)==TPINVSS) continue ;
         if(((link_list*)path0->DATA)->NEXT != NULL) continue ;
       
         if((path0->TYPE & VSS)==VSS)
         path02=path0 ;
         else 
         {
         link0 = (link_list*)path0->DATA ;
         path01=path0 ;
         }
      }

      for(path1=cone1->PATH ; path1!=NULL ; path1=path1->NEXT )
      {
         if((path1->TYPE & EXT    )==EXT    ) continue ;
         if((cone_list*) (((link_list*)path1->DATA)->TRANS->GRID)!=cone0)
         continue ;
         if((path1->TYPE & BLEEDER)==BLEEDER) continue ;
         if((path1->TYPE & TNINVDD)==TNINVDD) continue ;
         if((path1->TYPE & TPINVSS)==TPINVSS) continue ;
         if(((link_list*)path1->DATA)->NEXT != NULL) continue ;

         if((path1->TYPE & VSS)==VSS)
         path12=path1 ;
         else 
         {
         link1=(link_list*)path1->DATA ;
         path11=path1;
         }
      }

   trans0=link0->TRANS ; 
   trans1=link1->TRANS ; 
   
      if((float)(trans0->WIDTH/trans0->LENGTH) >  
         (float)(trans1->WIDTH/trans1->LENGTH) )
      {
      /* c'est le cone qui a l'inverseur le plus faible qui est le latch */
      cone1->TYPE |= LATCH;
      chain=addchain(NULL,(void*)path11);
      chain=addchain(chain,(void*)path12);
      cone1->USER=addptype(cone1->USER,BLEEDER,(void*)chain);             
      path11->TYPE|=BLEEDER;
      path12->TYPE|=BLEEDER;
      mark_inout(cone1,cone0,(LATCH|LOOP));
      paralBleed(cone1);
      fig->REG=addchain(fig->REG,(void*)cone1);
      type_com_lat(cone1,DSB_INV);
      }
   
      else if((float)(trans0->WIDTH/trans0->LENGTH) <  
         (float)(trans1->WIDTH/trans1->LENGTH) )
      {
      cone0->TYPE |= LATCH;
      chain=addchain(NULL,(void*)path01);
      chain=addchain(chain,(void*)path02);
      cone0->USER=addptype(cone0->USER,BLEEDER,(void*)chain);             
      path01->TYPE|=BLEEDER;
      path02->TYPE|=BLEEDER;
      mark_inout(cone0,cone1,(LATCH|LOOP));
      paralBleed(cone0);
      fig->REG=addchain(fig->REG,(void*)cone0);
      type_com_lat(cone0,DSB_INV);
      }
   
      else if((float)(trans0->WIDTH/trans0->LENGTH) ==  
         (float)(trans1->WIDTH/trans1->LENGTH) )
      {
      cone0->TYPE |= MEMORY;
      cone1->TYPE |= MEMORY;
      path01->TYPE|=BLEEDER;
      path02->TYPE|=BLEEDER;
      path11->TYPE|=BLEEDER;
      path12->TYPE|=BLEEDER;

      chain=addchain(NULL,(void*)path01);
      chain=addchain(chain,(void*)path02);
      cone0->USER=addptype(cone0->USER,BLEEDER,(void*)chain);             

      chain=addchain(NULL,(void*)path11);
      chain=addchain(chain,(void*)path12);
      cone1->USER=addptype(cone1->USER,BLEEDER,(void*)chain);             

      cone0->USER=addptype(cone0->USER,MEMORY,(void*)cone1);
      cone1->USER=addptype(cone1->USER,MEMORY,(void*)cone0);
   
      mark_inout(cone0,cone1,(LOOP|LATCH));
      mark_inout(cone1,cone0,(LOOP|LATCH));
      marq_incone(cone0);
      marq_incone(cone1);

      fig->REG=addchain(fig->REG,(void*)cone1);
      fig->REG=addchain(fig->REG,(void*)cone0);

      type_com_lat(cone0,DSB_DEF);
      type_com_lat(cone1,DSB_DEF);

      }

   return(3);
   break ;
   }

   case (DSB_INV | DSB_NAN) :
   case (DSB_INV | DSB_NOR) :
   {
   /*------------------------------------------------------+
   | C'est le cone qui contient l'inverseur qui est considere |
   | comme le point latch                                     |
   +---------------------------------------------------------*/
   cone_list * latch ;
   cone_list * other ;
   list_list * path ;
   link_list * link ;
   chain_list * chain = NULL ;

      if(res0==DSB_INV)
      {
      latch=cone0 ;
      other = cone1 ;
      }
      else 
      {
      latch = cone1 ;
      other = cone0 ;
      } 
      
      for(path=latch->PATH;path!=NULL;path=path->NEXT)
      {
         if((path->TYPE & EXT)==EXT) continue ;
         if((path->TYPE & BLEEDER)==BLEEDER) continue ;
         if((path->TYPE & TNINVDD)==TNINVDD) continue ;
         if((path->TYPE & TPINVSS)==TPINVSS) continue ;
         if(((link_list*)path->DATA)->NEXT!=NULL) continue ;
         if((cone_list*)((link_list*)path->DATA)->TRANS->GRID!=other)
         continue ;

      chain=addchain(chain,(void*)path);
      path->TYPE |= BLEEDER ;
      } 
   
   latch->USER=addptype(latch->USER,BLEEDER,(void*)chain);
   latch->TYPE |= LATCH ;
   fig->REG=addchain(fig->REG,(void*)latch);
   mark_inout(latch,other,(LOOP|LATCH));
   marq_incone(latch) ;
   type_com_lat(latch,DSB_DEF);
   return(3);
   }
   break ;

   /*--------------------------*
   | LATCH SANS CONFLIT        |
   +--------------------------*/
   case (DSB_NOR | DSB_PAS) :
   case (DSB_NAN | DSB_PAS) :
   case (DSB_INV | DSB_PAS) :

   case (DSB_NOR | DSB_SW2) :
   case (DSB_NAN | DSB_SW2) :
   case (DSB_INV | DSB_SW2) :

   case (DSB_NOR | DSB_SW1) :
   case (DSB_NAN | DSB_SW1) :
   case (DSB_INV | DSB_SW1) :
   {
   cone_list * latch ;
   cone_list * other ;
   list_list * path ;
   link_list * link ;
   chain_list * chain=NULL ;
   short nbLink = 0 ;
      
      if((res0==DSB_SW1)||(res0==DSB_SW2)||(res0==DSB_PAS))      
      {
      latch=cone0 ;
      other=cone1 ;
      }
      else
      {
      latch=cone1 ;
      other=cone0;
      }

      for(path=latch->PATH;path!=NULL;path=path->NEXT)
      {
      nbLink=0;
         if((path->TYPE & EXT)==EXT) continue ;
         if((path->TYPE & BLEEDER)==BLEEDER) continue ;
         for(link=(link_list*)path->DATA;link->NEXT!=NULL;link=link->NEXT)
         nbLink++;
         if(nbLink!=1) continue ;
         if((cone_list*)link->TRANS->GRID != other) continue ;
      path->TYPE |= BLEEDER ;
      chain=addchain(chain,(void*)path);
      }

   latch->TYPE |= LATCH ;
   latch->USER=addptype(latch->USER,BLEEDER,(void*)chain);
   fig->REG=addchain(fig->REG,(void*)latch);
   mark_inout(latch,other,(LOOP|LATCH));
   marq_incone(latch);
   type_com_lat(latch,DSB_DEF);
   return(3);
   }
   break ;

   case (DSB_ANDOR | DSB_SW2) :
   {
   cone_list * latch ;
   cone_list * other ;
   list_list * path ;
   link_list * link ;
   chain_list * chain=NULL ;
   short nbLink = 0 ;
      
      if(res0==DSB_SW2)      
      {
      latch=cone0 ;
      other=cone1 ;
      }
      else
      {
      latch=cone1 ;
      other=cone0;
      }

      for(path=latch->PATH;path!=NULL;path=path->NEXT)
      {
      nbLink=0;
         if((path->TYPE & EXT)==EXT) continue ;
         if((path->TYPE & BLEEDER)==BLEEDER) continue ;
         for(link=(link_list*)path->DATA;link->NEXT!=NULL;link=link->NEXT)
         nbLink++;
         if(nbLink!=1) continue ;
         if((cone_list*)link->TRANS->GRID != other) continue ;
      path->TYPE |= BLEEDER ;
      chain=addchain(chain,(void*)path);
      }

   latch->TYPE |= LATCH ;
   latch->USER=addptype(latch->USER,BLEEDER,(void*)chain);
   fig->REG=addchain(fig->REG,(void*)latch);
   mark_inout(latch,other,(LOOP|LATCH));
   marq_incone(latch);
   type_com_lat(latch,DSB_DEF);
   return(3);
   }
   break ;

   case (DSB_NOR ) :
   case (DSB_NAN ) :
   /* ERROR */
   return(0);
   break ;

   }
}

/****************************************************************************
 *                         fonction whichLoop();                            *
 ****************************************************************************/
static long whichLoop(cone0,cone1)
cone_list * cone0 ;
cone_list * cone1 ;
{
long res = invBoucl(cone0,cone1);
   if(res==0) res = bleBoucl(cone0,cone1);
   if(res==0) res = nanBoucl(cone0,cone1);
   if(res==0) res = norBoucl(cone0,cone1);
   if(res==0) res = pasBoucl(cone0,cone1);
   if(res==0) res = sw1Boucl(cone0,cone1);
   if(res==0) res = sw2Boucl(cone0,cone1);
   if(res==0) res = andOrBoucl(cone0,cone1);
return(res);
}



/****************************************************************************
 *                         fonction andOrBoucl();                           *
 ****************************************************************************/
 /*-------------------------------------------------------------------------+
 | Cone0 est il drive par cone1 a travers un ET-OU. On doit avoir           |
 | cone1=(cone0 ET a) OR b . On doit trouver deux branches de deux maillons |
 | chacune, dont le premier est drive par cone0, et respectivement a et b   |
 | pour les autres. Il faut une branche vss d'un maillon drive par b, et une|
 | branchede vdd de deux maillons drive par b et a                          |
 +-------------------------------------------------------------------------*/
static long andOrBoucl(cone0,cone1)
cone_list * cone0;
cone_list * cone1;
{
list_list * path ;
link_list * link ;
cone_list * set ;
cone_list * reset ;
short       nSet = 0 ;
short       nReset = 0 ;

   for(path=cone0->PATH;path!=NULL;path=path->NEXT)
   {
      if((path->TYPE & BLEEDER)==BLEEDER) continue ;
      if((path->TYPE & EXT)==EXT) continue ;
      if((path->TYPE & TNINVDD)==TNINVDD) continue ;
      if((path->TYPE & TPINVSS)==TPINVSS) continue ;

   link=(link_list*)path->DATA;

      if((cone_list*)link->TRANS->GRID != cone1) continue ;
      else
      {
         if(link->NEXT != NULL)
         {
            if(link->NEXT->NEXT==NULL)
            {
               if((path->TYPE & VDD)==VDD) 
               {
               nSet++;
               set=(cone_list*)link->NEXT->TRANS->GRID ;
               }
               else
               {
               nReset++;
               reset=(cone_list*)link->NEXT->TRANS->GRID ;
               }
            }
            else return(0);
         }
         else return(0);
      }
   }

   if((nSet!=1)||(nReset!=1)) return(0);


   /*-----------------------------------------------------+
   | On cherche alors les duex autres branches            |
   +-----------------------------------------------------*/
   for(path=cone0->PATH;path!=NULL;path=path->NEXT)
   {
      if((path->TYPE & BLEEDER)==BLEEDER) continue ;
      if((path->TYPE & EXT)==EXT) continue ;
      if((path->TYPE & TNINVDD)==TNINVDD) continue ;
      if((path->TYPE & TPINVSS)==TPINVSS) continue ;

   link=(link_list*)path->DATA;

      if((cone_list*)link->TRANS->GRID == set) 
      {
         if ((path->TYPE & VSS)!=VSS) return(0);
         if (link->NEXT != NULL) return(0);
      nSet++;
      }

      if((cone_list*)link->TRANS->GRID == reset)
      {
         if((path->TYPE & VDD)!=VDD) return(0);
         if(link->NEXT == NULL) return(0);
         else
         {
         link=link->NEXT;
            if(link->NEXT != NULL) return(0);
            if((cone_list*)link->TRANS->GRID != set) return(0);
            else
            nReset++;
         }
      }
   }

   if((nSet!=2)||(nReset!=2)) return(0);
   else return(DSB_ANDOR);
}
      
/****************************************************************************
 *                         fonction invBoucl();                             *
 ****************************************************************************/
   /*-----------------------------------------------------+
   |  cone0 est il drive par cone1 a travers un inverseur |
   +-----------------------------------------------------*/
static long invBoucl(cone0,cone1)
cone_list * cone0 ;
cone_list * cone1 ;
{
list_list * path0 ;
list_list * path1 ;
link_list * link ;

   for(path0=cone0->PATH;path0!=NULL;path0=path0->NEXT)
   {
      if((path0->TYPE & EXT    )==EXT    ) continue ;
      if((cone_list*) (((link_list*)path0->DATA)->TRANS->GRID)!=cone1)
      continue ;
      if((path0->TYPE & BLEEDER)==BLEEDER) continue ;
      if((path0->TYPE & TNINVDD)==TNINVDD) continue ;
      if((path0->TYPE & TPINVSS)==TPINVSS) continue ;
      if(((link_list*)path0->DATA)->NEXT != NULL) continue ;

      for(path1=path0->NEXT ; path1!=NULL ; path1=path1->NEXT )
      {
         if(((path1->TYPE | path0->TYPE) & (VDD | VSS))!=(VDD|VSS))
         continue ;
         if((cone_list*) (((link_list*)path1->DATA)->TRANS->GRID)!=cone1)
         continue ;
         if((path1->TYPE & BLEEDER)==BLEEDER) continue ;
         if((path1->TYPE & TNINVDD)==TNINVDD) continue ;
         if((path1->TYPE & TPINVSS)==TPINVSS) continue ;
         if(((link_list*)path1->DATA)->NEXT != NULL) continue ;

      return(DSB_INV);
      }
   }
return(0);
}

/****************************************************************************
 *                         fonction bleBoucl();                       *
 ****************************************************************************/
   /*-----------------------------------------------------+
   |  cone0 est il drive par cone1 a travers un Bleeder   |
   +-----------------------------------------------------*/
static long bleBoucl(cone0,cone1)
cone_list * cone0 ;
cone_list * cone1 ;
{
list_list * path ;
link_list * link ;
short nbLink ;
short maxNbLink ;
long linkType = 0 ;

   for(path=cone0->PATH;path!=NULL;path=path->NEXT)
   {
      if((path->TYPE & BLEEDER)==BLEEDER) continue ;
      else nbLink = 0 ;

      for(link=(link_list*)path->DATA;link!=NULL;link=link->NEXT)
      {
      nbLink++; 
         if(((link->TYPE & TP)!=TP)&&((link->TYPE & TN)!=TN))   
         continue ;

         if((cone_list*) (link->TRANS->GRID)==cone1)
         {
            if(nbLink>1) return(0) ;
            if((path->TYPE & TNINVDD)==TNINVDD) return(0);
            if((path->TYPE & TPINVSS)==TPINVSS) return(0);
            if((path->TYPE & EXT)==EXT) return(0) ;
         linkType |= link->TYPE ;
         }
      }
   }
   if((linkType & (TP | TN)) == 0) return(0); 
   if( ((linkType & TP)==TP) && ((linkType & TN)==TN)) return(0);
   else return (DSB_BLE);      
}

/****************************************************************************
 *                         fonction paralBleed                              *
 ****************************************************************************/
/*--------------------------------------------------------------------------+
| Entree un cone latch ou Bleeder                                           |
| Sortie NULL aucune branche Bleeder parallele n'a ete trouvee              |
|        La liste des transistors // constituant la contre reaction        |
*--------------------------------------------------------------------------*/
static chain_list * paralBleed(cone)
cone_list * cone ;
{
ptype_list * user ;
chain_list * chain ;
list_list * path0;
list_list * path1;
link_list * link0;
link_list * link1;
chain_list * chainRes= NULL ;
chain_list * chainPath=NULL ;

user = getptype(cone->USER,BLEEDER);
   if(user==NULL)
   {
   dsbBug(12,"paralBleed",cone->NAME,"BLEEDER",0);
   }

chain=(chain_list*)user->DATA ;

   for(chain=(chain_list*)user->DATA;
       chain != NULL ;
       chain = chain->NEXT)
   {
   path0=(list_list*)chain->DATA;
   link0=(link_list*)path0->DATA;
      for(path1=cone->PATH;path1!=NULL;path1=path1->NEXT)
      {
         if((path1->TYPE & BLEEDER)==BLEEDER) continue ;
      link1=(link_list*)path1->DATA;

         if(link1->NEXT!=NULL) continue ;
         if((link0->TYPE & link1->TYPE & (TN|TP)) == (long)0) continue ;
         if((path0->TYPE & path1->TYPE & (VDD|VSS))==(long)0) continue ;
         if(link0->TRANS->GRID!=link1->TRANS->GRID) continue ;
      path1->TYPE |= BLEEDER ;
      chainPath=addchain(chainPath,(void*)path1);
      chainRes=addchain(chainRes,(void*)link1->TRANS);
      }
   }
   if(chainRes!=NULL) 
   user->DATA=(void*)append((chain_list*)user->DATA,chainPath);
   
return(chainRes);
}

/****************************************************************************
 *                         fonction pasBoucl()                              *
 ****************************************************************************/
 /*------------------------------------------------------------------------+
 | Detecte si le rebouclage est constitue d'un pass transistor suivi d'un  |
 | inverseur                                                               |
 | On doit trouver deux branches : Une VSS pure , et une VDD degrade pas-  |
 | par le meme transistor de passge que l'autre . Les deux transistors de  |
 | fin de branche doivent constituer un inverseur                          |
 +------------------------------------------------------------------------*/
static long pasBoucl(cone0,cone1) 
cone_list * cone0 ;
cone_list * cone1 ;
{
list_list  * path0 ;
link_list  * link0 ;
int          nbPath = 0 ;
int          nbLink ;
long         pathType;
lotrs_list * pass ;
lotrs_list * finalPass = NULL ;

   for(path0=cone0->PATH;path0!=NULL;path0=path0->NEXT)
   {
   nbLink = 0 ;

      if((path0->TYPE & BLEEDER)==BLEEDER) continue ;
      if((path0->TYPE & EXT)==EXT) continue ;

      for(link0=(link_list*)path0->DATA;link0->NEXT!=NULL;link0=link0->NEXT)
      {
      nbLink++;
      pass = link0->TRANS ;
      }

      if(nbLink>1) continue ;

      if((cone_list*)link0->TRANS->GRID != cone1) continue ;
      else 
      {
         if((finalPass != NULL) && (finalPass!=pass)) return(0);
         else finalPass = pass ;

      nbPath++;
      pathType |= path0->TYPE ;
      }
   }

   if(nbPath!=2) return(0);
   if((pathType & (TPINVSS | TNINVDD))==(TPINVSS | TNINVDD)) return(0);
   if((pathType & (VDD | VSS)) != (VDD|VSS)) return(0);

return(DSB_PAS);
}

/****************************************************************************
 *                         fonction sw1Boucl                                *
 ****************************************************************************/
/*--------------------------------------------------------------------------+
| Detecte si les deux cones reboucles fournis en entree constituent un      |
| latch de type CNET2                                                       |
|                                                                           |
| Ce latch a pour particularite d'avoir pour feedBack un switch cmos suivi  |
| d'un inverseur.                                                           |
|                                                                           | 
| Un des deux cone en entree doit contenir 4 branches  de deux maillons     |
| dont le dernier transistor est attaque par l'autre cone .                 |
|                                                                           | 
| Il doit y avoir                                                           |
|    Une branche VSS pure                                                   |
|    Une branche VDD pure                                                   |
|    une branche VSS degradee  par le premier transistor seulement          |
|    Une branche VDD degradee  par le premier transistor seulement          |
|                                                                           | 
| Les premier transistors des branches doivent etre identiques si ils       |
| sont du meme type.                                                        |
|                                                                           |
| Entree: qcCone Le cone qui sera eventuellement le Latch                   |
|         dlCone Le cone 1                                                  |
|                                                                           |
| Retour:  DSB_SW1 si le feedback est trouve                                | 
|          0 sinon                                                          |
+--------------------------------------------------------------------------*/
static long sw1Boucl(cone1,cone2)
cone_list * cone1 ;
cone_list * cone2 ;
{
list_list * path = NULL ;
link_list * link = NULL ;
list_list * tabPath[5] ;
short       idxTab = 0 ;
short       nbLink = 0 ;
short       i      = 0 ;
chain_list * chain = NULL ;
lotrs_list * nInVss = NULL ;
lotrs_list * pInVss = NULL ;
lotrs_list * nInVdd = NULL ;
lotrs_list * pInVdd = NULL ;

   /* detection des branches de rebouclages */
   for(path=cone1->PATH;path!=NULL;path=path->NEXT)
   {
   nbLink=0;

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

      for(link=(link_list*)path->DATA; link->NEXT!=NULL; link=link->NEXT)
      nbLink++; 
      if(nbLink>2) continue ;

      if((cone_list*)link->TRANS->GRID != cone2) continue ;

      if(idxTab==4) return(0) ;

   tabPath[idxTab]=path ;
   idxTab++;
   }

   if(idxTab != 4) return(0);


   /* Pour chaque branche de rebouclage */
   for(i=0;i<4;i++)
   {
   link_list * link0 ;
   link_list * link1 ;

   path=tabPath[i] ;
   link0=(link_list*)path->DATA ;
   link1=link0->NEXT ;

      /* Branche VDD */
      if((path->TYPE & VDD)==VDD)
      {
         if((path->TYPE & TNINVDD)==TNINVDD)
         {
            if( ((link0->TYPE & TN )!=TN)
                 ||((link1->TYPE & TP)!=TP) ) return(0) ;
         nInVdd=link0->TRANS;
         continue ;
         }
         else 
         {
            if( ((link0->TYPE & TP )!=TP)
                ||((link1->TYPE & TP)!=TP) ) return(0) ;
          pInVdd=link0->TRANS;
          continue ;
          }
      }

      /* Branche VSS */
      else if ((path->TYPE & VSS)==VSS)
      {
         if((path->TYPE & TPINVSS)==TPINVSS)
         {
            if( ((link0->TYPE & TP )!=TP)
                ||((link1->TYPE & TN)!=TN) ) return(0) ;
         pInVss=link0->TRANS; 
         continue ;
         }
         else
         {
            if( ((link0->TYPE & TN )!=TN)
                ||((link1->TYPE & TN)!=TN) ) return(0) ;
         nInVss=link0->TRANS;
         continue;
         }
      }
   }
   /* Il manque une des 4 branches Possible ?? */
   if((nInVdd==NULL)||(pInVdd==NULL)||
      (pInVss==NULL)||(nInVss==NULL)) return(0);

   /* Les transistors qui doivent etre identiques
      le sont ils ?? */
   if((nInVdd!=nInVss)||(pInVdd!=pInVss)) return(0);

return(DSB_SW1);
}



/****************************************************************************
 *                         fonction sw2Boucl                                *
 ****************************************************************************/
/*--------------------------------------------------------------------------+
| Detecte si les deux cones reboucles fournis en entree constituent un      |
| latch de type CNET3                                                       |
| Le cone1 doit contenir deux branches non degradeede type differents de 2  |
| maillons chacunes. le premier maillon de chacune doit etre de type differ |
|                                                                           |
| Entree: cone1                                                             |
|         cone2                                                             |
|                                                                           |
| Retour:  DSB_SW2 le feedback attendu est rencontre                        |
|          0 dans le cas contraire                                          |
+--------------------------------------------------------------------------*/
static long sw2Boucl(cone1,cone2)
cone_list * cone1 ;
cone_list * cone2 ;
{
list_list * path = NULL ;
link_list * link = NULL ;
list_list * tabPath[3] ;
link_list * tabLink[3] ;
short       idxTab = 0 ;
short       nbLink = 0 ;
long        typePath = 0 ;
long        typeLink = 0 ;
chain_list * chain = NULL ;

   for(path=cone1->PATH;path!=NULL;path=path->NEXT)
   {
   nbLink=0;

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

      for(link=(link_list*)path->DATA; link->NEXT!=NULL; link=link->NEXT)
      nbLink++; 
      if(nbLink>1) continue ;

      if((cone_list*)link->TRANS->GRID != cone2) continue ;

      if(idxTab==2) return(0) ;

   tabLink[idxTab]=link ;
   tabPath[idxTab]=path ;
   idxTab++;
   }

   if(idxTab!=2) return(0);

typePath = (tabPath[0])->TYPE | (tabPath[1])->TYPE ; 
typeLink = (tabLink[0])->TYPE | (tabLink[1])->TYPE ;

   if((typePath & VDD)!=VDD) return(0);
   if((typePath & VSS)!=VSS) return(0);
   if((typePath & TNINVDD)==TNINVDD) return(0);
   if((typePath & TPINVSS)==TPINVSS) return(0);

return(DSB_SW2);
}


/****************************************************************************
 *                         fonction norBoucl                                *
 ****************************************************************************/
 /*------------------------------------------------------------------------+
 | Teste si cone0 est drive par cone1 a travers un Nor . On cherche d'abord|
 | une branche de deux maillons dont un transistor est drive par cone1. On |
 | note qui est l'autre entree de la branche. Reste a trouver ensuite deux |
 | branche d'un maillon chacune dont les entrees respectives sont celles   |
 | trouvees precedemment                                                   |
 +------------------------------------------------------------------------*/
long static norBoucl(cone0,cone1)
cone_list * cone0 ;
cone_list * cone1 ;
{
list_list * path ;
list_list * path1 ;
link_list * link ;
short nbLink        ;
cone_list * tabIn[2] ;
short       in0 = 0 ;
short       in1 = 0 ;

   for (path=cone0->PATH;path!=NULL;path=path->NEXT)
   {
      if((path->TYPE & VSS )==VSS) continue ;
      if((path->TYPE & TNINVDD)==TNINVDD) continue ;
      if((path->TYPE & EXT)==EXT) continue ;
      if((path->TYPE & BLEEDER)==BLEEDER) continue ;

   nbLink=0;

      for(link=(link_list*)path->DATA;link!=NULL;link=link->NEXT)
      {
         if(nbLink>1) 
         {
         nbLink++;
         break ;
         }
      tabIn[nbLink++]=(cone_list*)link->TRANS->GRID ;
      }

      if(nbLink!=2) continue ;

      if((tabIn[0]!=cone1) && (tabIn[1]!=cone1) ) continue ;
      else
      {
         for (path1=cone0->PATH;path1!=NULL;path1=path1->NEXT)
         {
         link_list * norLink ;
            if((path1->TYPE & VDD)==VDD) continue ;
            if((path1->TYPE & TPINVSS)==TPINVSS) continue ;
            if((path1->TYPE & EXT)==EXT) continue ;
            if((path1->TYPE & BLEEDER)==BLEEDER) continue ;
         norLink=(link_list*)path1->DATA ;
            if(norLink->NEXT != NULL) continue ;
            if((cone_list *)norLink->TRANS->GRID==tabIn[0])
            in0 ++ ;
            if((cone_list *)norLink->TRANS->GRID==tabIn[1])
            in1++; 
         }
         if((in0!=1) && (in1!=1)) continue ;
         else return( DSB_NOR );
      }
   }
return(0);
}
/****************************************************************************
 *                         fonction nanBoucl                                *
 ****************************************************************************/
 /*------------------------------------------------------------------------+
 | Teste si cone0 est druve par cone1 a travers un Nand. On cherche d'abord|
 | une branche de deux maillons dont un transistor est drive par cone1. On |
 | note qui est l'autre entree de la branche. Reste a trouver ensuite deux |
 | branche d'un maillon chacune dont les entrees respectives sont celles   |
 | trouvees precedemment                                                   |
 +------------------------------------------------------------------------*/
long static nanBoucl(cone0,cone1)
cone_list * cone0 ;
cone_list * cone1 ;
{
list_list * path ;
list_list * path1 ;
link_list * link ;
short nbLink        ;
cone_list * tabIn[2] ;
short       in0 = 0 ;
short       in1 = 0 ;

   for (path=cone0->PATH;path!=NULL;path=path->NEXT)
   {
      if((path->TYPE & VDD )==VDD) continue ;
      if((path->TYPE & TPINVSS)==TPINVSS) continue ;
      if((path->TYPE & EXT)==EXT) continue ;
      if((path->TYPE & BLEEDER)==BLEEDER) continue ;

   nbLink=0;

      for(link=(link_list*)path->DATA;link!=NULL;link=link->NEXT)
      {
         if(nbLink>1) 
         {
         nbLink++;
         break ;
         }
      tabIn[nbLink++]=(cone_list*)link->TRANS->GRID ;
      }

      if(nbLink!=2) continue ;

      if((tabIn[0]!=cone1) && (tabIn[1]!=cone1) ) continue ;
      else
      {
         for (path1=cone0->PATH;path1!=NULL;path1=path1->NEXT)
         {
         link_list * nanLink ;
            if((path1->TYPE & VSS)==VSS) continue ;
            if((path1->TYPE & TNINVDD)==TNINVDD) continue ;
            if((path1->TYPE & EXT)==EXT) continue ;
            if((path1->TYPE & BLEEDER)==BLEEDER) continue ;
         nanLink=(link_list*)path1->DATA ;
            if(nanLink->NEXT != NULL) continue ;
            if((cone_list *)nanLink->TRANS->GRID==tabIn[0])
            in0 ++ ;
            if((cone_list *)nanLink->TRANS->GRID==tabIn[1])
            in1++; 
         }
         if((in0!=1) && (in1!=1)) continue ;
         else return( DSB_NAN );
      }
   }
return(0);
}
      

/****************************************************************************
 *                         fonction mark_inout();                           *
 ****************************************************************************/

     /*----------------------------------------------------*
      |  marque type l INCONE du cone latch visant le cone |
      |  de rebouclage et l'OUTCONE du cone de rebouclage  |
      |  visant le cone Latch.                             |
      |                                                    |
      |  entree : autre_cone (le Latch)                    |
      |         : dual_cone (le cone de rebouclage)        |
      |                                                    |
      |  sortie : neant                                    |
      *----------------------------------------------------*/

void mark_inout(autre_cone, dual_cone,type)

cone_list      *dual_cone,
               *autre_cone;
long            type ;
{
    list_list      *pt_list;


    for (pt_list=(list_list*)dual_cone->OUTCONE;pt_list;pt_list=pt_list->NEXT)
    {
	if (autre_cone == (cone_list *) pt_list->DATA)
	{
	    pt_list->TYPE |= type;
	    break;
	}
    }
    if (pt_list==NULL) 
    {
    dsbBug(7,"mark_inout",autre_cone->NAME,dual_cone->NAME,0);
    }

    for(pt_list=(list_list*)autre_cone->INCONE;pt_list;pt_list=pt_list->NEXT)
    {
	if (dual_cone == (cone_list *) pt_list->DATA)
	{
	    pt_list->TYPE |= type;
	    break;
	}
    }
    if (pt_list==NULL) 
    {
    dsbBug(8,"mark_inout",dual_cone->NAME,autre_cone->NAME,0);
    }
}


/****************************************************************************
 *                         fonction detect_inv();                           *
 ****************************************************************************/

    /*------------------------------------------*
     |  Teste si un cone est un inverseur       |
     |  Entree : un pointeur de cone            |
     |  Sortie : 1 si le cone est un inverseur  |
     |           0 dans le cas contraire        |
     *------------------------------------------*/
 
int detect_inv(pt_cone)
cone_list      *pt_cone;
{
    link_list      *pt_link0,
                   *pt_link1;
    list_list      *pt_list0,
                   *pt_list1,
                   *pt_tmp;


    if (((pt_list0 = (list_list *) pt_cone->PATH) == NULL) || ((pt_list1 = (list_list *) pt_list0->NEXT) == NULL))
    {
	return (0);		/* moins de deux chemins  */
    }

    if (pt_list1->NEXT != NULL)
    {
	return (0);		/* plus de deux chemins  */
    }

    if (((pt_list0->TYPE) & VDD) == VDD)
    {
	pt_tmp = pt_list0;
	pt_list0 = pt_list1;
	pt_list1 = pt_tmp;
    }

    pt_link0 = (link_list *) pt_list0->DATA;
    pt_link1 = (link_list *) pt_list1->DATA;
    if ((pt_link0->NEXT != NULL) || (pt_link1->NEXT != NULL))
    {
	return (0);		/* plus d'un maillon par chemin  */
    }

    if (((pt_list0->TYPE & VSS) == VSS) && ((pt_list1->TYPE & VDD) == VDD))
    {
	if (pt_link0->TRANS->GRID->SIG == pt_link1->TRANS->GRID->SIG)
	    return (1);
	else
	{
	    return (0);
	}
    }
    else
    {
	return (0);
    }
}


/****************************************************************************
 *                         fonction test_loop();                            *
 ****************************************************************************/

       /*--------------------------------------------------------* 
        |     teste les boucles sur deux cones en tenant compte  | 
        |     du TYPE LOOP                                       | 
        *--------------------------------------------------------*/

void test_loop(ptcone,errLoop,warLoop)
cone_list * ptcone;
int * errLoop ;
int * warLoop ;
{
list_list * incone=NULL;
list_list * outcone=NULL;
int loopErr = 0 ;

   for(incone=ptcone->INCONE;incone;incone=incone->NEXT)
   {
      for (outcone=ptcone->OUTCONE;outcone;outcone=outcone->NEXT)
      {
         if (  ( outcone->DATA==incone->DATA ) && 
               ((incone->TYPE & LOOP)!=LOOP)   && 
               ((outcone->TYPE & LOOP) != LOOP ) && 
               ((incone->TYPE & EXT) != EXT)      )
         {

            if(((ptcone->TYPE & LATCH)==LATCH) &&
               ((((cone_list*)incone->DATA)->TYPE & LATCH)==LATCH ) )
            {
            (*warLoop)++;
            dsbWarning(14,test_loop, ptcone->NAME,
                          ((cone_list*)incone->DATA)->NAME,
                           0);
            }
            else
            {
            (*errLoop)++;
            dsbError(4,"test_loop",ptcone->NAME,ptcone->INDEX,
                        (((cone_list *)outcone->DATA)->NAME),
                        ((cone_list*)outcone->DATA)->INDEX);
            }
         }
      }
   }
}

/****************************************************************************
 *                         fonction oldlatchRolMar();                       *
 ****************************************************************************/
 /*------------------------------------------------------------------------+
 | test si le latch constitue de deux inverseurs reboucles est de type Rol |
 | ie : c'est in inverseur tristate qui permet d'ecrire dans le latch et   |
 | les commandes attaquent les transistors les plus proches des alimentati |
 | Cette fonction teste  si les premiers maillons des branches fonctionell |
 | du latch, par ailleurs contituees de deux maillons, sont bien attaquees |
 | par le meme cone, c'est a dire DATA.                                    |
 |                                                                         |
 | Entree : cone = pointeur de cone latch                                  |
 | Retour : 0 le pattern decrit plus haut est reconnu                      |
 |         -1 Le pattern n'est pas reconnu                                 |
 +------------------------------------------------------------------------*/
static short oldlatchRolMar(cone)
cone_list * cone ;
{
list_list * path , *tabPath[2] ;
link_list * link , *tabLink[2] ;
int      nbLink = 0 ;
int      nbPath = 0 ;
int      linkTab = 0 ;

   for (path=cone->PATH;path!=NULL;path=path->NEXT)
   {
      if((path->TYPE & BLEEDER)==BLEEDER) continue ;
      if((path->TYPE & EXT)    ==EXT    ) return(-1) ;
      if((path->TYPE & TNINVDD)==TNINVDD) return(-1) ;
      if((path->TYPE & TPINVSS)==TPINVSS) return(-1) ;
      
      if(nbPath > 1) 
      {
      nbPath++ ;
      break ;
      }
   tabPath[nbPath++]=path ;
   }

   if(nbPath != 2) return (-1) ;
  
   for(nbPath=0;nbPath<2;nbPath++)
   {
   nbLink = 0 ;
      for(link=(link_list*)tabPath[nbPath]->DATA;link!=NULL;link=link->NEXT)
      {
         if (nbLink==0) tabLink[linkTab++]=link ;
         if(nbLink > 1) 
         {
          nbLink++;
          break ; 
          }
      nbLink++ ;
      }
      if(nbLink!=2) return (-1) ;
   }

   if ((cone_list*)((tabLink[0])->TRANS->GRID)== 
       (cone_list*)((tabLink[1])->TRANS->GRID) ) return(0);
   else return(-1);
}
      

/****************************************************************************
 *                         fonction latchRolMar();                          *
 ****************************************************************************/
 /*------------------------------------------------------------------------+
 | test si le latch constitue de deux inverseurs reboucles est de type Rol |
 | ie : c'est in inverseur tristate qui permet d'ecrire dans le latch et   |
 | les commandes attaquent les transistors les plus proches des alimentati |
 | Cette fonction teste  si les premiers maillons des branches fonctionell |
 | du latch, par ailleurs contituees de deux maillons, sont bien attaquees |
 | par le meme cone, c'est a dire DATA.                                    |
 | Ce qui precede decrit explicitement ce type de latch a UNE entree : il  |
 | generaliser aux latch a plusieurs entrees. Pour chaque branche vdd il   |
 | trouver la branche vss corrspondante                                    |
 |                                                                         |
 | Entree : cone = pointeur de cone latch                                  |
 | Retour : 0 le pattern decrit plus haut est reconnu                      |
 |         -1 Le pattern n'est pas reconnu                                 |
 +------------------------------------------------------------------------*/
static short latchRolMar(cone)
cone_list * cone ;
{
list_list * dataList  = NULL ;
list_list * path ;
list_list * plist ;
short res ;

   for(path=cone->PATH;path!=NULL;path=path->NEXT)
   {
   int nbLink = 0 ;
   cone_list * inData ;
   link_list * link ;

      if((path->TYPE & EXT)    ==EXT    ) return(-1) ;
      if((path->TYPE & TNINVDD)==TNINVDD) return(-1) ;
      if((path->TYPE & TPINVSS)==TPINVSS) return(-1) ;
      if((path->TYPE & BLEEDER)==BLEEDER) continue ;

      for(link=(link_list*)path->DATA ; link!=NULL;link=link->NEXT)
      nbLink++;

      if(nbLink != 2) return(-1);

   inData = (cone_list*)((link_list*)path->DATA)->TRANS->GRID ;      

      for(plist=dataList;plist!=NULL;plist=plist->NEXT)
         if(plist->DATA==(void*)inData) break ;
      
      if(plist==NULL) 
      dataList=add_list(dataList,(void*)inData,(path->TYPE)&(VDD|VSS));
      else 
      {
         if(((path->TYPE & (VDD|VSS)) & (plist->TYPE)) != 0)
         {
            if(dataList != NULL) freeliste(dataList);
         return(-1);
         }
         else plist->TYPE |= (path->TYPE & (VDD|VSS));  
      }
   }

   if(dataList == NULL) return(-1) ;

   for(plist=dataList;plist!=NULL;plist=plist->NEXT)
      if((plist->TYPE & (VDD|VSS)) != (VDD|VSS)) break ;
 
   if(plist != NULL) res = -1 ;
   else res = 0 ;

freeliste(dataList) ;
return(res);
}
   

/****************************************************************************
 *                         fonction type_com_lat();                         *
 ****************************************************************************/
 /*-------------------------------------------------------------------------+
 |  Type COMMAND les signaux de commandes des latchs                        |
 +-------------------------------------------------------------------------*/
void type_com_lat(cone,type)
cone_list * cone;
long        type;
{
list_list * path = NULL;
list_list * tabPath[2];
list_list * path0 , *path1 ;
link_list * tabLink[2];
link_list * link ;
int         nbLink = 0 ;
int         nbPath=0;

   switch(type)
   {

   case DSB_INV :  /* inverseur reboucles */
   {
      /*------------------------------------------+
      | Cas des latch RolMar : inverseur tristate |
      | commandes a l'exterieur                   |
      +------------------------------------------*/
      if(latchRolMar(cone)==0)
      {
      cone_list * in = NULL;
      list_list * incone = NULL;

         for(path=cone->PATH;path!=NULL;path=path->NEXT)
         {
            if((path->TYPE & BLEEDER)==BLEEDER) continue ;
         link=((link_list*)path->DATA)->NEXT;
         in=(cone_list*)link->TRANS->GRID ;
            for(incone=cone->INCONE;incone!=NULL;incone=incone->NEXT)
            {
               if(incone->DATA==(void*)in) 
               {
               incone->TYPE |= COMMAND ;
               break ;
               }
            }
          }
      break ;
      }
      else 
      {
      type_com_lat(cone,DSB_DEF) ;
      break ;
      }
   }

   case DSB_DEF :  /* default  On type command le premier maillon 
                      de chaque branche fonctionnelle            */
   {
      for (path=cone->PATH;path != NULL;path=path->NEXT)
      {
      cone_list * in = NULL;
      list_list * incone = NULL;

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

      in=((cone_list *) ((link_list*)path->DATA)->TRANS->GRID);

         for (incone=cone->INCONE; incone != NULL; incone=incone->NEXT)
         {
            if ((incone->TYPE & LOOP)==LOOP) continue;
            if (incone->DATA==(char*)in) 
            {
            (incone->TYPE)|=COMMAND;
            break;
            }
         }

         if (incone==NULL) 
         {
         dsbBug(11,"type_com_lat",cone->NAME,NULL,0);
         }
      }
   break ;
   }

   default : 
   break ;
   }
}

      


/****************************************************************************
 *                         fonction affich_inetout();                       *
 ****************************************************************************/

     /*---------------------------------------------------*
      |  Affiche les INCONE et OUTCONE  d'un cone         |
      |  (utilise en fait pour debugger test_latch!!)     |
      *---------------------------------------------------*/

void affich_inetout(ptcone)
cone_list *ptcone;
{
list_list *ptin;
list_list *ptout;
printf("Liste des incones:\n");
   for(ptin=ptcone->INCONE;ptin;ptin=ptin->NEXT)
   {
   if((ptin->TYPE & CONE_TYPE)==CONE_TYPE)
    printf("incone;(%d)%s\n",((cone_list*)ptin->DATA)->INDEX,((cone_list*)ptin->DATA)->NAME);
   }
printf("Liste des outcones:\n");
   for(ptout=ptcone->OUTCONE;ptout;ptout=ptout->NEXT)
   {
   if((ptout->TYPE & CONE_TYPE)==CONE_TYPE)
   printf("outcone:(%d)%s\n",((cone_list*)ptout->DATA)->INDEX,((cone_list*)ptout->DATA)->NAME);
  }
}



/****************************************************************************
 *                         fonction fx_chem1();                             *
 ****************************************************************************/

      /*---------------------------------------------------------* 
       | void fx_chem1                                           | 
       | Marque les fx_chem1 du aux  bleeders et aux latch       | 
       | Les chemins ne sont pas supprimes                       | 
       | Entree : l'input du bleeder ou du maillon CR            | 
       |          le pointeur de figure desa                     | 
       |          le transistor constituant le bleeder ou CR     | 
       | Sortie : Neant                                          | 
       *---------------------------------------------------------*/

void  fx_chem1 (ptchain,ptconelb,ptcone,ptfig)
chain_list * ptchain;  /* chaine de transistors constituant les branches bleeder */ 
cone_list *ptcone;     /* l'input du latch ou du bleeder */
cone_list *ptconelb;   /* le cone latch ou bleeder */
desafig_list *ptfig;

{
cone_list * ptconei = NULL;
list_list * ptouti = NULL;
int flag;


   for (ptouti=ptcone->OUTCONE;ptouti;ptouti=ptouti->NEXT)
   {
   /* pour chaque cone qu'attaque le cone de rebouclage */
   list_list  * ptlist  = NULL;
   locon_list * ptconct = NULL;
   list_list  * ptpath  = NULL;
   flag = 0;
      if (( ptouti->TYPE & CONE_TYPE)==CONE_TYPE)
      ptconei=(cone_list*)ptouti->DATA;
      else /* outcone de type connecteur */
      {
      ptype_list * ptuser ;
      ptconct=(locon_list*)ptouti->DATA;
      ptuser=getptype(ptconct->USER,(short)EXT);
      ptconei=(cone_list*)ptuser->DATA;
      }
      if(ptconei==ptconelb) continue ;
      
            for(ptpath=ptconei->PATH;ptpath;ptpath=ptpath->NEXT)
            {
            link_list * ptlink;
               for(ptlink=(link_list*)ptpath->DATA;ptlink;ptlink=ptlink->NEXT)
               {
                  if ( ((ptlink->TYPE & TP)==TP)||((ptlink->TYPE & TN)==TN) )
                  {
                  chain_list * ptchain0;
                     for(ptchain0=ptchain;ptchain0;ptchain0=ptchain0->NEXT)
                     {
                        if((char*)ptlink->TRANS==(char *)ptchain0->DATA)
                        {
                        (ptpath->TYPE)|=BLEEDER;
                        flag=1;
                        /* on marque LOOP l'outcone de ptcone qui pointe ptconei */
            /*            marq_outcone(ptcone,ptconei);*/
                        }
                     }
                  }
               }   /* fin balayage maillon */
            }   /* fin balayage chemin */
      if (flag==1) 
      {
      /* on marque LOOP les incones en trop du conei dus aux faux chemins */
      marq_incone(ptconei);
      }
   } /* fin balayage cones */
} /* fin fonction */



/****************************************************************************
 *                         fonction marq_incone();                          *
 ****************************************************************************/

      /*------------------------------------------------------*
       | Marque les incone de ptcone dus aux chemins BLEEDER  |
       | si ils n'apparaissent pas dans d'autres chemins      |
       | fonctionnels                                         | 
       | on en profite pour marquer l'outcone de incone qui   |
       | pointe sur ptcone                                    |
       *------------------------------------------------------*/

void marq_incone(ptcone)
cone_list * ptcone;
{
list_list * ptpath;
chain_list * ptchain = NULL; /* liste des incone qui devront etre supprimes */  
int in_fonc=0;


   for(ptpath=ptcone->PATH;ptpath;ptpath=ptpath->NEXT)
   {
    /*--------------------------------------------*/
    /* on cherche les incones des chemins BLEEDER */
    /*--------------------------------------------*/
      if((ptpath->TYPE & BLEEDER)==BLEEDER)
      {
      /* si chemin non fonctionnel  */
      link_list * ptmail;
         for(ptmail=(link_list*)ptpath->DATA;ptmail;ptmail=ptmail->NEXT)
         {
            if ( ((ptmail->TYPE & TN)==TN)||((ptmail->TYPE & TP)==TP) )
            {
            /*----------------------------------------------*/
            /* incone de type cone                          */
            /*----------------------------------------------*/
            char  * incone;
            list_list * ptpath1;
            incone=((char*)(ptmail->TRANS->GRID));
            in_fonc=0;
            /*---------------------------------------------*/
            /* on cherche si l'incone est present dans un  */
            /*     chemin non marque BLEEDER               */
            /*---------------------------------------------*/
               for (ptpath1=ptcone->PATH;ptpath1;ptpath1=ptpath1->NEXT)
               {
                  if ( (ptpath1->TYPE & BLEEDER)!=BLEEDER)
                  {
                  link_list * ptmail1;
                     for(ptmail1=(link_list*)ptpath1->DATA;ptmail1;ptmail1=ptmail1->NEXT)
                     {
                     char * ptcone1;
                        if ( ((ptmail1->TYPE & TN)==TN)||((ptmail1->TYPE & TP)==TP) )
                        {
                        ptcone1=(char*)ptmail1->TRANS->GRID;
                           if(ptcone1==incone) 
                           {
                           /*----------------------------------------*/
                           /* l'incone du au chemin non fonc         */
                           /* est retrouve dans un chemin fonctionnel */
                           /*----------------------------------------*/
                           in_fonc=1;
                           break;
                           } 
                        }
                     } /* finfor maillon de chemin fonc */
                  }    /* finif chemin fonc             */
                  if (in_fonc==1) break;
               }       /* finfor chemin fonc(?)  */

            /*-------------------------------------------------------------*/
            /* si a l'issue du balayage des chemins fonc l'incone          */
            /* du a un faux chemin n'a pas ete trouve, on le marque LOOP   */
            /*-------------------------------------------------------------*/

               if (in_fonc==0) 
               {
               list_list * in=NULL;
                  for (in=ptcone->INCONE;in;in=in->NEXT)
                  {
                     if ( incone==(char*)(in->DATA) ) 
                     {
                     (in->TYPE) |= LOOP ; 
                     marq_outcone((cone_list*)incone,ptcone);
                     break;
                     }
                  }

                  if (in==NULL) 
                  {
                  dsbBug(9,"marq_incone",ptcone->NAME,NULL,0);
                  }
                  
               }
            }   /* finif mail tp ou tn */
            else
            {
            /*----------------------------------------------*/
            /* incone de type connecteur                    */
            /*----------------------------------------------*/
            char       * connect = NULL;
            list_list  * ptpath2 = NULL;
            in_fonc = 0;
            connect=(char*)ptmail->TRANS;
               for (ptpath2=ptcone->PATH;ptpath2;ptpath2=ptpath2->NEXT)
               {
                  if ( ((ptpath2->TYPE & BLEEDER)!=BLEEDER) &&
                       ((ptpath2->TYPE & EXT)==EXT)    )
                  {
                  link_list *ptmail2 = NULL;
                     for (ptmail2=(link_list*)ptpath2->DATA;ptmail2->NEXT;ptmail2=ptmail2->NEXT);
                     if (connect==(char*)ptmail2->TRANS) 
                     {
                     in_fonc=1;
                     break;
                     }
                  }
               }

               if (in_fonc==0)
               {
               list_list *in = NULL;
                  for (in=ptcone->INCONE;in;in=in->NEXT)
                  {
                     if (connect==(char*)in->DATA)
                     {
                     in->TYPE |= LOOP;
                     break;
                     }
                  }
               }
            }
         } /* finfor maillon de faux chemin  */ 
      } /* finif chemin non fonc    */
   }    /* finfor chemin */
}


/****************************************************************************
 *                         fonction marq_outcone();                         *
 ****************************************************************************/

     /*---------------------------------------------------------*
      |  marq_outcone : marque LOOP l'outcone pointe par output | 
      |  du cone pointe par ptcone                              |
      *---------------------------------------------------------*/

void marq_outcone(ptcone,output)
cone_list * ptcone;
cone_list * output;
{
list_list * ptout=NULL;

   for (ptout=ptcone->OUTCONE;ptout;ptout=ptout->NEXT)
   {
      if ( ptout->DATA==((char*)output) )
      {
      (ptout->TYPE)|= LOOP;
      break;
      }
   }

   if (ptout==NULL) 
   {
   dsbBug(10,"marq_outcone",ptcone->NAME,NULL,0);
   }
}
   
      

/****************************************************************************
 *                         fonction del_listincone();                       *
 ****************************************************************************/

      /*--------------------------------------------------------* 
       | supprime dans la liste des incones ,les incones        | 
       |  contenus dans la chaine pointee par ptchain           | 
       *--------------------------------------------------------*/

list_list * del_listincone (ptlist,ptchain)
list_list *ptlist;
chain_list * ptchain;
{
chain_list * pt1=NULL;


   if ( (ptlist==NULL)||(ptchain==NULL) )
   {
   dsbBug(1,"del_listincone",NULL,NULL,0);
   }

   for (pt1=ptchain;pt1;pt1=pt1->NEXT)
   {
   ptlist=rmv_list(ptlist,pt1->DATA);
   }
return(ptlist);
}



/****************************************************************************
 *                         fonction affich_link();                          *
 ****************************************************************************/

void affich_link(ptlink,ptlist,ptcone)
link_list * ptlink;
list_list * ptlist;
cone_list * ptcone;
{
   if (ptlink->NEXT != NULL) fprintf(DESB_ERR_FILE,"  Next Link Non Null \n");
   if (ptcone != (cone_list*)ptlink->TRANS->GRID) 
   {
   fprintf(DESB_ERR_FILE,"  Grilles  %s -LV- %s \n",ptcone->NAME,(cone_list*)(ptlink->TRANS->GRID)->NAME);
   }
   if ( (ptlist->TYPE & TPINVSS) == TPINVSS)  fprintf(DESB_ERR_FILE,"  Degrade bas \n");
   if ( (ptlist->TYPE & TNINVDD) == TNINVDD)  fprintf(DESB_ERR_FILE,"  Degrade haut \n");
   if ( (ptlist->TYPE & EXT) == EXT) fprintf(DESB_ERR_FILE,"  Externe \n");
fprintf(DESB_ERR_FILE,"\n");
} 
 

/****************************************************************************
 *                         fonction memoryToLatch();                        *
 ****************************************************************************/
 /*-------------------------------------------------------------------------+
 | Type Latch un des deux pointss MEMORY : Les points MEMORY sont constitues|
 | de deux inverseurs reboucles de grille A et B. Un branche part resp de A |
 | et B : elle est constituee de deux transistors N vers VSS. Le premier est|
 | dive par CK (pour les deux branches) tandis que le second est drive par  |
 | Data (resp. Data barre). Normalement Data bare est genere par un inver-  |
 | seur drive par Data.                                                     |
 | On choisit pour l'instant de typer B LATCH car c'est lui qui vaut Data   |
 | car decharche pour Data barre.                                           |
 | Cette fonction cherche donc a trouver qui des deux cones MEMORY doit etre|
 | interprete comme A ou B                                                  |
 |                                                                          |
 | Entree : deux cone MEMORY                                                |
 |                                                                          |
 | Retour : 0 Un point latch a ete affecte                                  |
 |         -1 Dans le cas contraire                                         |
 +-------------------------------------------------------------------------*/
short memoryToLatch(cone0,cone1)
cone_list * cone0 ,
          * cone1 ;
{
list_list * path ,
          * path0 ,
          * path1 ;
link_list * link0 ,
          * link1  ;
cone_list * incone0 ,
          * incone1 ;
short nb_path = 0 ;
long  test = 0 ;

   /*-------------------------------------------------------------------+
   | On recupere l'entree du 2me maillon de la branche (1) de decharge |
   +-------------------------------------------------------------------*/
   for(path=cone0->PATH;path!=NULL;path=path->NEXT)
   {
      if((path->TYPE & BLEEDER)==BLEEDER) continue ;
      else 
      {
      nb_path++;
      path0 = path ;
      }
   }

   if(nb_path != 1) return(-1) ; 
   if(((path0->TYPE)&(TNINVDD | TPINVSS | VDD | EXT))!=0) return(-1);

link0=(link_list*)path0->DATA ;

   if(link0->NEXT == NULL) return(-1);
   else 
   {
      if(link0->NEXT->NEXT!=NULL) return(-1);
      else incone0 = (cone_list*)link0->NEXT->TRANS->GRID ;
   }

/*-------------------------------------------------------------------+
| On recupere l'entree du 2me maillon de la branche (2) de decharge |
+-------------------------------------------------------------------*/
nb_path = 0 ;
   for(path=cone1->PATH;path!=NULL;path=path->NEXT)
   {
      if((path->TYPE & BLEEDER)==BLEEDER) continue ;
      else 
      {
      nb_path++;
      path1 = path ;
      }
   }

   if(nb_path != 1) return(-1) ; 
   if(((path1->TYPE)&(TNINVDD | TPINVSS | VDD | EXT))!=0) return(-1);

link1=(link_list*)path1->DATA ;

   if(link1->NEXT == NULL) return(-1);
   else 
   {
      if(link1->NEXT->NEXT!=NULL) return(-1);
      else incone1 = (cone_list*)link1->NEXT->TRANS->GRID ;
   }

   /*-------------------------------------------------------------------+
   | On teste si les deux incones sont de type MEMORY eux aussi: C'est  |
   | le cas lorsque l'on est en presence d'un bascule faite a l'aide de |
   | ce latch particulier. Dans ce cas, on lance recursivement la       |
   | fonction sur ces deux cones. En retour l'un des deux cone sera type|
   | LATCH. C'est la branche de decharche dont l'incone n'est pas typee |
   | LATCH qui designera qui d'entre cone0 et cone1 doit etre type LATCH|
   +-------------------------------------------------------------------*/
   if( ((incone0->TYPE & (MEMORY | LATCH))==MEMORY) &&
       ((incone1->TYPE & (MEMORY | LATCH))==MEMORY)  )
   {
   test = memoryToLatch(incone0,incone1);
      if(test == -1) return(-1) ;
      else if (test==1)
      {
      cone0->TYPE |= LATCH ;
      return(0) ;
      }
      else if (test==0)
      {
      cone1->TYPE |= LATCH ;
      return(1);
      }
   }
   else if( ((incone0->TYPE & (LATCH|MEMORY)) == MEMORY) &&
            ((incone1->TYPE & (LATCH|MEMORY))== (MEMORY|LATCH)))
   {
   cone0->TYPE |= LATCH ;
   return(0) ;
   }
   else if( ((incone1->TYPE & (LATCH|MEMORY)) == MEMORY) &&
            ((incone0->TYPE & (LATCH|MEMORY))== (MEMORY|LATCH)))
   {
   cone1->TYPE |= LATCH ;
   return(0) ;
   }
   else
   { 
   /*--------------------------------------------------------------------+
   | on teste qui des deux incone est drive par l'autre par un inverseur |
   +--------------------------------------------------------------------*/
   test = invBoucl(incone0,incone1);
      if(test == DSB_INV) 
      {
      cone0->TYPE |= LATCH ;
      return(0);
      }
   test = invBoucl(incone1,incone0) ;
      if(test == DSB_INV ) 
      {
      cone1->TYPE |= LATCH ;
      return(1);
      }
      else return(-1);
   }
}


/****************************************************************************
 *                         fonction dsbMemoryMasterSlave();                 *
 ****************************************************************************/
/*--------------------------------------------------------------------------+
 | Teste si le cone MEMORY, et  LATCH, fait partie d'une        |
 | bascule :                                                                |
 | On recupere le DATA (dML1) du latch (ML1), puis le DATA (dM1) du memory  |
 | associe(M1), ainsi que la clock (C1) des deux qui doit bien sur etre     |
 | identique                                                                |
 | On verifie que (dML1) est un M2 et que dM1 est le ML2 associe a M2.      |
 | Deplus la clock C2 doit etre inverse de C1.                              |
 | Dans ce cas, ML1 est type SLAVE et ML2 est MAST                          |
 +-------------------------------------------------------------------------*/
short dsbMemoryMasterSlave(cone)  
cone_list * cone ;
{
cone_list * memLat1 = cone ;
cone_list * memLat2 ;
cone_list * mem1    ;
cone_list * mem2    ;
ptype_list* user    ;
list_list * path    ;
list_list * path1    ;
link_list * link ;
cone_list * c2    ;
cone_list * c1    ;

user=getptype(memLat1->USER,MEMORY);
mem1=(cone_list*)user->DATA ;

   for(path=memLat1->PATH;path!=NULL;path=path->NEXT)
      if((path->TYPE & BLEEDER)==BLEEDER) continue ;
      else path1=path ;

link=(link_list*)path1->DATA ;
c1=(cone_list *)link->TRANS->GRID ;
mem2=(cone_list*)link->NEXT->TRANS->GRID ;

   for(path=mem1->PATH;path!=NULL;path=path->NEXT)
      if((path->TYPE & BLEEDER)==BLEEDER) continue ;
      else path1=path ;

link=(link_list*)path1->DATA ;
memLat2=(cone_list*)link->NEXT->TRANS->GRID ;

   if((mem2->TYPE & (MEMORY | LATCH)) != MEMORY ) return(-1);
   if((memLat2->TYPE & (MEMORY | LATCH)) != (MEMORY | LATCH)) return(-1);

user=getptype(memLat2->USER,MEMORY);
   if(mem2 != (cone_list*)user->DATA) return(-1);

   for(path=mem2->PATH;path!=NULL;path=path->NEXT)
      if((path->TYPE & BLEEDER)==BLEEDER) continue ;
      else path1=path ;

link=(link_list*)path1->DATA ;
c2=(cone_list *)link->TRANS->GRID ;

   /* if(invBoucl(c1,c2)!=DSB_INV) return(-1); */
   if(AinvchainB(c1,c2)!=0) return(-1);
   else 
   {
   memLat1->TYPE |= SLAVE ;
   memLat2->TYPE |= MAST ;

   memLat1->USER=addptype(memLat1->USER,MAST,(void*)memLat2);
   memLat2->USER=addptype(memLat2->USER,SLAVE,(void*)memLat1);
   
   mem2->TYPE |= INUTIL ;
   c1->TYPE   |= INUTIL ;
   return(0);
   }
}



/****************************************************************************
 *                         fonction dsbMasterSlave();                       *
 ****************************************************************************/
/*--------------------------------------------------------------------------+
| test si le cone detecte LATCH fait partie d'une maitre esclave sclib      |
| il s'agit de deux latch dont l'un crache dans l'autre a travers un invrs  |
| la commande du deuxieme (slave) est inverse du maitre. ceci es fait a     |
| l'aide exclusivement d'un inverseur drive par la commande du maitre       |
| 
| On regarde si on est sur le slave. si oui, on cher l'incone de l'incone   |
| data su slave. on verifie que les deux commandes sont inverse l'une de    |
| l'autre a travers un inverseur                                            |
+--------------------------------------------------------------------------*/
short dsbMasterSlave(cone)
cone_list * cone ;
{
list_list * in ;
list_list * inData;
list_list * inComSlv = NULL;
list_list * inComMst = NULL;
cone_list * incone ;
cone_list * mastCone ;
cone_list * inutilCone ;
int nbIn = 0 ;
int nbComMst = 0  ;
int nbComSlv = 0  ;

   /* On compte les entrees du slave */
   for(in = cone->INCONE ; in!=NULL;in=in->NEXT) 
   {
      if((in->TYPE & LOOP)==LOOP) continue ;
   nbIn++ ;
      if((in->TYPE & COMMAND)!=COMMAND) 
      {
      inData = in ;
      }
      else
      {
      inComSlv=in ;
      nbComSlv++;
      }
   }
   if(nbComSlv != 1 ) return(-1) ;
   if(nbIn != 2)        return(-1);
   if((inData->TYPE & CONE_TYPE)!=CONE_TYPE)    return(-1);
   if((inComSlv->TYPE & CONE_TYPE)!=CONE_TYPE)  return(-1) ; 

incone=(cone_list*)inData->DATA ;        /* incone est la sortie du maitre ? */
   if(detect_inv(incone)==0) return(-1); /* incone doit etre un inverseur  */  

inutilCone=incone ;     /* on sauve le noeud entre sortie maitre et entree 
                           inverseur entree slave  pour le vbe           */
in=incone->INCONE;      /* entree de l'inverseur de sortie du maitre */
   if((in->TYPE & CONE_TYPE)!=CONE_TYPE) return(-1);

incone = (cone_list*) in->DATA ; /* incone est il le maitre */
   if((incone->TYPE & LATCH) != LATCH) return(-1);
   
   /* On compte les entrees du Master */
   for(in=incone->INCONE; in!=NULL;in=in->NEXT)
   {
      if((in->TYPE & LOOP)==LOOP) continue ;
      if((in->TYPE & COMMAND)==COMMAND) 
      {
      inComMst=in ;
      nbComMst++;
      }
   }
   if(nbComMst != 1) return(-1) ;

mastCone=incone;

incone=(cone_list*)inComSlv->DATA ;       /* cone commande du slave */

   if(AinvchainB((cone_list*)inComSlv->DATA,(cone_list*)inComMst->DATA) !=0 )
   return(-1);

incone->TYPE |= INUTIL ;
inutilCone->TYPE |= INUTIL ;
cone->TYPE |= SLAVE ;
mastCone->TYPE |= MAST ;
cone->USER=addptype(cone->USER,MAST,(void*)mastCone);
mastCone->USER=addptype(mastCone->USER,SLAVE,(void*)cone);
return(0);
}

/****************************************************************************
 *                         fonction invChain();                             *
 ****************************************************************************/
 /*-------------------------------------------------------------------------+
 | remonte les couches de cones  tant que ceux ci sont des inverseurs. Au   |
 | fur et a mesure, on constitue une liste chainee des cones remontes       |
 +-------------------------------------------------------------------------*/
static chain_list * invChain(cone,chaine)
cone_list * cone ;
chain_list * chaine ;
{
cone_list * incone ;
list_list * in ;
int nbIn = 0 ;

   for(in=cone->INCONE;in!=NULL;in=in->NEXT)
   {
      if((in->TYPE & LOOP)==LOOP) continue ;
      else 
      {
      nbIn++;
         if((in->TYPE & CONE_TYPE)==CONE_TYPE)
         incone=(cone_list*)in->DATA ;
      }
   }

   if(nbIn != 1) return(chaine) ;

   if(invBoucl(cone,incone)!=DSB_INV) return(chaine);
   else
   {
   chaine=addchain(chaine,(void*)incone) ;
   chaine = invChain(incone,chaine);
   return(chaine);
   }
}
   
/****************************************************************************
 *                         fonction AinvchainB();                           *
 ****************************************************************************/
 /*-------------------------------------------------------------------------+
 | remonte a partir de A d'une part, et de B, d'autre part, les couches     
 | d'inverseur le plus loin possible. Lorsque le dernier cone atteint est le|
 | meme pour les deux, on regarde si il ya une difference de parite sur le  |
 | nombre de couche pour l'un par rapport a l'autre                         |
 +-------------------------------------------------------------------------*/
static short AinvchainB(coneA,coneB)
cone_list * coneA ;
cone_list * coneB ;
{
short res = 0 ;
chain_list * chainA = addchain(NULL,(void*)coneA) ;
chain_list * chainB = addchain(NULL,(void*)coneB) ;

chainA=invChain(coneA,chainA);
chainB=invChain(coneB,chainB);

   if(chainA->DATA != chainB->DATA)  res = -1 ;
   else 
   {
   int nbA = 0  ;
   int nbB = 0 ;

      while ((chainA!=NULL)&&(chainB!=NULL)&&(chainA->DATA == chainB->DATA))
      {
      chainA=chainA->NEXT ;
      chainB=chainB->NEXT ;
      }

      while(chainA!=NULL)
      {
      nbA++;
      chainA=chainA->NEXT;
      }

      while(chainB!=NULL)
      {
      nbB++;
      chainB=chainB->NEXT;
      }

      if(((nbA % 2)+(nbB % 2)) != 1)  res = -1 ;
   }

freechain(chainA);
freechain(chainB);
return(res);
}
      
   


   
