/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit : DESB  v2.n                                                  */
/*    Fichier : test_ext.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"

chain_list *CHAIN = NULL ;

/****************************************************************************
 *                         fonction test_ext();                             *
 ****************************************************************************/

                    /* test des connecteurs externes */

int     test_ext( pt_con )

locon_list  *pt_con ;

{
cone_list  *pt_cone 	= NULL ;
list_list  *pt_path 	= NULL ;
list_list  *pt_extpath 	= NULL ;
int dirConnectErr = 0 ;



   /* traitement des transparences */
   if ( pt_con->DIRECTION == 'T' )
   {
   return(0) ;
   }

/*------------------------------------------*
 | on cherche le cone associe au connecteur |
 *------------------------------------------*/
pt_cone = ( cone_list *)getptype( pt_con->USER , ( long )EXT )->DATA ;

   if( pt_cone != NULL )
   {
   int n_alim = 0;
   int n_ext  = 0;

      for( pt_path = pt_cone->PATH ; pt_path != NULL ; pt_path = pt_path->NEXT )
      {
      /*----------------------------------------------------------*
      | on cherche des chemins vers les alimentations et externes |
      *-----------------------------------------------------------*/
         if ( ( ( pt_path->TYPE & VDD ) == VDD ) 
         || ( ( pt_path->TYPE & VSS ) == VSS ) )
         n_alim++;
         if  ((pt_path->TYPE & EXT)== EXT) n_ext++;
      }

      if  (( n_alim == 0 )&&( n_ext==1)) 
      {
      /*-------------------------------------------------*
       | pas de chemin VSS ou VDD : connecteur d'ENTREE  |
       | un seul chemin vers le connecteur               |
       *-------------------------------------------------*/
         if (( pt_con->DIRECTION != 'I') && (pt_con->DIRECTION != 'X'))
         {
         DESB_NB_ERR++;
         dirConnectErr ++ ;
            if(DESB_LANG=='F')
            {
            fprintf(DESB_ERR_FILE,"ERR_dsb test_ext : direction (%c) du connecteur %s erronee =>(INPUT) \n" , pt_con->DIRECTION , pt_con->NAME ) ;
            }
            else if(DESB_LANG=='E')
            {
            fprintf(DESB_ERR_FILE,"ERR_dsb test_ext :bad direction (%c) of connector %s  => (INPUT) \n" , pt_con->DIRECTION , pt_con->NAME ) ;
            }
         }
      pt_con->DIRECTION = 'I' ;
      }

      else 
      {
      /*------------------------------------------------------------------*
       | chemin VSS ou VDD ou plus d'un chemin externe  on cherche le     |
       | chemin vers le connecteur , on l'enleve temporairementdu cone    |
       *------------------------------------------------------------------*/
      short inout =0;
         if (((link_list*)pt_cone->PATH->DATA)->TRANS == (trans_list *)pt_con)
         {
         pt_extpath = pt_cone->PATH ;
         pt_cone->PATH = pt_cone->PATH->NEXT ;
         }
         else 
            for ( pt_path = pt_cone->PATH;pt_path!= NULL;pt_path=pt_path->NEXT )
            {
               if (pt_path->NEXT != NULL )
               {
                  if (((link_list *)pt_path->NEXT->DATA )->TRANS == (trans_list * )pt_con )
                  {
                  pt_extpath = pt_path->NEXT ;
                  pt_path->NEXT = pt_path->NEXT->NEXT ;
                  break ;
                  }
               }
            }

         if ( pt_extpath == NULL )
         {
            if(DESB_LANG=='F')
            fprintf(stdout,"[ERR] Le cone %s n'a pas de chemin vers le connecteur \n",pt_cone->NAME ) ;
            else if(DESB_LANG=='E')
            fprintf(stdout,"[ERR] Cone %s can't reach connector \n",pt_cone->NAME ) ;
         exit( -1 ) ;
         }

          /*----------------------------------*
           | on teste la presence d'une autre |
           | branche maillon connecteur       |
           *----------------------------------*/
         {
         list_list * path=NULL;
            for(path=pt_cone->PATH;path != NULL; path=path->NEXT)
            {
               if( ( ((link_list*)path->DATA)->NEXT == NULL) &&
                     ((path->TYPE & EXT)==EXT)  )
               {
               /* deux connecteurs equipotentiel, on laisse INOUT  */
               inout=1;
               }
            }
         }

         test_hz( pt_cone ) ;

         if ( ( ( pt_cone->TYPE & HZ  ) == 0 ) && (inout==0) )
         {
         /*-------------------+
	 |  c'est une SORTIE  |
         +-------------------*/
         ptype_list	*pt_user = NULL ;

            if ( ( pt_con->DIRECTION != 'O' ) && ( pt_con->DIRECTION != 'X' ) )
            {
            DESB_NB_ERR++;
            dirConnectErr++;
               if(DESB_LANG=='F')
               {
               fprintf(DESB_ERR_FILE,"[ERR] Direction (%c) du connecteur %s erronee =>(OUTPUT) \n" , pt_con->DIRECTION , pt_con->NAME ) ;
               }
               else if(DESB_LANG=='E')
               {
               fprintf(DESB_ERR_FILE,"[ERR] Bad direction (%c) for connector %s  => (OUTPUT) \n" , pt_con->DIRECTION , pt_con->NAME ) ;
               }
            }
         pt_con->DIRECTION = 'O' ;
         pt_cone->OUTCONE = add_list( pt_cone->OUTCONE,(char*)pt_con,EXT) ;
         }

         /*---------------------------------------------+
         |  ON NE PEUT PAS CONCLURE : on fait confiance |
         +---------------------------------------------*/
         else 
         {
            if ( pt_con->DIRECTION == 'I' )
            {
            /* si c'est une ENTREE on remet le chemin */
            pt_extpath->NEXT = pt_cone->PATH ;
            pt_cone->PATH = pt_extpath ;
            }
            else if ( pt_con->DIRECTION == 'O' )
            {
            /* si c'est une SORTIE  */
            ptype_list	*pt_user = NULL ;
            pt_cone->OUTCONE = add_list( pt_cone->OUTCONE,(char*)pt_con,EXT) ;
            }
            else if ( pt_con->DIRECTION == 'X' )
            {
            ptype_list	*pt_user = NULL ;
            pt_cone->OUTCONE=add_list(pt_cone->OUTCONE,(char*)pt_con,EXT);
             /* on remet le chemin vers le connecteur */
            pt_extpath->NEXT = pt_cone->PATH ;
            pt_cone->PATH = pt_extpath ;
            }
         } /* finif doute sur entree ou sortie */
      }
   }

   else
   {
   /*-----------------------------------------------*
    | le connecteur n'a pas de connecteur associe   |
    | C'est une entree                              |
    *----------------------------------------------*/
      if ( ( pt_con->SIG->TYPE != VDD ) 
         && ( pt_con->SIG->TYPE != VSS )
         && ( pt_con->SIG->TYPE != 'T' ) )
      {
         if ( ( pt_con->DIRECTION != 'I' ) && ( pt_con->DIRECTION != 'X' ) )
         {
         DESB_NB_ERR++;
         dirConnectErr++;
            if (DESB_LANG=='F')
            {
            fprintf(DESB_ERR_FILE,"[ERR] Direction (%c) du connecteur %s erronee => (INPUT) \n" , pt_con->DIRECTION , pt_con->NAME ) ;
            }
            else if (DESB_LANG=='E')
            {
            fprintf(DESB_ERR_FILE,"[ERR] Bad direction (%c) for connector %s => (INPUT) \n" , pt_con->DIRECTION , pt_con->NAME ) ;
            }
         }
      pt_con->DIRECTION = 'I' ;
      }
   }
return(dirConnectErr);
}

/****************************************************************************
 *                         fonction dsbBleeDriveX();                        *
 ****************************************************************************/

     /*---------------------------------------------------------* 
      | tes_ext2(); Surtype les connecteurs qui n'ont que des   | 
      |             chemins non fonctionnel (BLEEDER)           | 
      | Entree : Un conncteur type INOUT                        |
      | sortie : 0 le connecteur est surtype IN                 |
      |          1 le connecteur reste inchange                 |
      *---------------------------------------------------------*/
short dsbBleeDriveX(conect)
locon_list * conect;
{
ptype_list *user = NULL;
cone_list  *cone = NULL;
list_list  *path = NULL;
link_list  *link = NULL;
short n_path = 0;
short n_bleed = 0;
short test = 1;

   if ( ( conect->SIG->TYPE == VDD ) 
	|| ( conect->SIG->TYPE == VSS )
	|| ( conect->SIG->TYPE == 'T' ) ) return(1);

   if((conect->DIRECTION) != 'X') return(1);

user=getptype(conect->USER,EXT);
cone=(cone_list*)user->DATA;

   for(path=cone->PATH;(path!=NULL);path=path->NEXT)
   {
   n_path++;
      if((path->TYPE & BLEEDER)==BLEEDER) n_bleed++;
   }

   if (n_path==(n_bleed+1))
   {
   /*--------------------------------------------*
    | il faut changer la direction du connecteur |
    | et le type du maillon dans tous les cones  |
    | qui le contiennent en entree               |
    *--------------------------------------------*/

   conect->DIRECTION = 'I';

   user=getptype(conect->USER,CONE_TYPE);
      if (user != NULL)
      {
      chain_list * pchain;
       /*-----------------------------------------------*
        |  pour chaque cone qui contient le connecteur  |
        |  on change le type du maillon INOUT en IN     |
        *-----------------------------------------------*/
         for(pchain=(chain_list*)user->DATA; pchain!=NULL;pchain=pchain->NEXT)
         {
         cone_list * pcone;
         pcone=(cone_list*)pchain->DATA;

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

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

              if((locon_list*)link->TRANS==conect)
              {
              (link->TYPE)&=~(IN|INOUT);
              (link->TYPE)|=IN;
              }
           }
         }
       }
       else 
       {
       dsbBug(14,"dsbBleedDriveX",conect->NAME,"CONE_TYPE",0);
       }
      
   (cone->TYPE)&=(~HZ);

      /*----------------------------------------------------------------*
       | si le cone n'est reference par aucun autre cone on le supprime | 
       | sinon on supprime l'outcone correspondant au connecteur        |
       *----------------------------------------------------------------*/

      if((cone->OUTCONE->NEXT)==NULL)  vide_cone(cone);
      else cone->OUTCONE=(list_list*)rmv_list(cone->OUTCONE,(char*)conect);
   return(0);
   }
   else return(1);
}

/****************************************************************************
 *                         fonction dsbXDriveNoGate();                    *
 ****************************************************************************/
/*--------------------------------------------------------------------+
|  Si le connecteur INOUT n'est en entree d'aucun autre cone, il doit |
|  etre surtype OUT                                                   |
+--------------------------------------------------------------------*/
void dsbXDriveNoGate(conect)
locon_list * conect ;
{
   if ( ( conect->SIG->TYPE == VDD ) 
	|| ( conect->SIG->TYPE == VSS )
	|| ( conect->SIG->TYPE == 'T' ) ) return;

   if((conect->DIRECTION)!='X') return ;

   if(dsbXDriveGate(conect)!=0) /*le connecteur n'attaque aucune grille*/
   {
   dsbTypeXOut(conect);
   }
}

/****************************************************************************
 *                         fonction dsbXDriveGate();                        *
 ****************************************************************************/
/*--------------------------------------------------------------------------+
| retourne 1 si le connecteur n'attaque aucune grille                       |
|          0 si le connecteur en attaque i , le cone associe est  i fois en |
|            entree d'un  cone.                                             |
+--------------------------------------------------------------------------*/
short dsbXDriveGate(conect)
locon_list * conect ;
{
ptype_list * user      ;
cone_list * cone       ;
list_list * out        ;
chain_list * chain ;
int         nbCone = 0 ;

user=getptype(conect->USER,CONE_TYPE);

   if(user == NULL)
   {
   dsbBug(14,"dsbXdriveGate",conect->NAME,"CONE_TYPE",0);
   }
   /*------------------------------------------------------------+
   | On compte le nombre de cones qui ont ce conecteur en entree |
   +------------------------------------------------------------*/
   for(chain=(chain_list*)user->DATA;chain!=NULL;chain=chain->NEXT) 
   {
   nbCone ++;
   }

   
   if(nbCone>=2) /* attaque une grille : il y a deux cones qui dependent de*/
   return(0);    /*ce connecteur. le cone qui est monte sur lui, ET un autre|
                 | cone qui contient une branche qui se termine par ce      |
                 | connecteur                                              */
   else 
   {
   /*------------------------------------------------+
   | Si non on regarde le nombre de sorties du cone  |
   | qui est monte sur le connecteur                 |
   +------------------------------------------------*/
   list_list * out = NULL;
   short nbOut=0;

   user = getptype (conect->USER,EXT);

      if(user == NULL)
      {
      dsbBug(14,"dsbXDriveGate",conect->NAME,"EXT",0);
      }

   cone=(cone_list*)user->DATA ;

      for(out=cone->OUTCONE;out != NULL;out=out->NEXT)
      {
         if((out->TYPE & LOOP)==LOOP)continue ;
         if((out->TYPE & CONE_TYPE)==CONE_TYPE)
         nbOut++;
      }
      if(nbOut !=0) return(0);
      else return(1);
   }
}


/****************************************************************************
 *                         fonction dsbTypeXOut();                          *
 ****************************************************************************/
/*--------------------------------------------------------------------------+
| Surtype Out le connecteur externe qui etait inout avant par exemple. Il   |
| faut supprimer tous les maillons qui ont ce connecteur type INOUT de tous |
| les cones Les path sont types BLEEDER                                     |
+--------------------------------------------------------------------------*/
short dsbTypeXOut(conect)
locon_list *conect ;
{
list_list * path ;
ptype_list * user ;
list_list * out ;
chain_list * chain;

conect->DIRECTION='O' ;

   /*------------------------------------------------------------+
   | Pour tous les cones dont ce connecteur est une entree       |
   +------------------------------------------------------------*/
user=getptype(conect->USER,CONE_TYPE);
   
   if(user == NULL)
   {
   dsbBug(14,"dsbTypeXOut",conect->NAME,"CONE_TYPE",0);
   }

   for(chain=(chain_list*)user->DATA;chain!=NULL;chain=chain->NEXT)
   {
   list_list* path = NULL ;
   list_list * in ;
   cone_list * cone ;

   cone=(cone_list*)chain->DATA;

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

         if((path->TYPE & EXT)!=EXT) continue ;
      
         for(link=(link_list*)path->DATA;link->NEXT!=NULL;link=link->NEXT) ;

         if((locon_list*)link->TRANS==conect)
         path->TYPE |= BLEEDER ;
      }
      /*-------------------------------------------+
      | On marque loop les in qui doivent l'etre   |
      for(in=cone->INCONE; in; in=in->NEXT)
      {
         if ((in->TYPE & EXT) != EXT) continue;
         else
         if ((locon_list*)in->DATA == conect)
         {  
         in->TYPE |= LOOP;
         break;
         }
      }
      +-------------------------------------------*/
   marq_incone(cone);
   }
   freechain(chain);
   user->DATA=NULL;
}

   
/****************************************************************************
 *                         fonction dsbExtIII();                            *
 ****************************************************************************/
void dsbExtIII(desafig)
desafig_list * desafig ;
{
locon_list * connect ;
ptype_list * user ;
cone_list * cone ;

   for(connect=desafig->LOCON;connect!=NULL;connect=connect->NEXT)
   {
      if(connect->DIRECTION=='A') continue ;
      else if(connect->DIRECTION=='I') continue ;
      else if(connect->DIRECTION=='T') 
      {
      connect->DIRECTION='X' ;
      continue ;
      }
      else if(connect->DIRECTION=='X') 
      {
      connect->DIRECTION='T' ;
      continue ;
      }
      else if(connect->DIRECTION=='O')
      {
      /*----------------------------+
      | On recupere le cone associe |
      +----------------------------*/
      user=getptype(connect->USER,EXT);
      cone=(cone_list*)user->DATA;

         /*-----------------------------------------------------+
         | Cas du cone HZ,=>une seule sortie,c'est deja verifie |
         +-----------------------------------------------------*/ 
         if((cone->TYPE & HZ)==HZ) 
         {
         connect->DIRECTION='Z' ;
         continue ;
         }
    
         /*------------------------------------+
         | Cas du cone ~HZ,deux sortie,=> 'B'  |
         +------------------------------------*/ 
         else if((cone->TYPE & HZ) != HZ)
         {
         list_list * out ;
         short nOut = 0 ;
            for(out=cone->OUTCONE;out!=NULL;out=out->NEXT) nOut++;
            if(nOut >= 2) 
            {
            connect->DIRECTION='B' ;
            continue ;
            }
            else continue ;
         }
      }
   }
   for(cone=desafig->CONE;cone!=NULL;cone=cone->NEXT)
   {
   list_list * path;
   link_list * link ;
   
      for(path=cone->PATH;path!=NULL;path=path->NEXT)
      {
         for(link=(link_list*)path->DATA;link!=NULL;link=link->NEXT)
         {
         trans_list * tran ;
         losig_list * sig ;
         ptype_list * user ;
         cone_list * coneSig ;

            if(((link->TYPE & TN) != TN)&&((link->TYPE&TP)!=TP)) continue ;
            else tran=link->TRANS ;

         /*-----------------------------------+
         | On regarde le drain pour commencer |
         +----------------------------------*/
         sig=tran->DRAIN->SIG ;
         user=getptype(sig->USER,CONE_TYPE);

            if(user!=NULL)
            {
            coneSig=(cone_list*)user->DATA ;

               if(coneSig==cone) continue ;
               if(((coneSig->TYPE & EXT)==EXT)&&
                  ((coneSig->TYPE & HZ)!=HZ)  &&
                  (coneSig->USER != NULL)  )
               {
               ptype_list * userConect ;
               locon_list * connectSig ;
               userConect=getptype(coneSig->USER,EXT);
               connectSig=(locon_list*)userConect->DATA ;
                  if(connectSig->DIRECTION=='O') connectSig->DIRECTION='B';
               }
            }

         /*----------------------------------+
         | On regarde la source pour finir   |
         +----------------------------------*/
         sig=tran->SOURCE->SIG ;
         user=getptype(sig->USER,CONE_TYPE);

            if(user!=NULL)
            {
            coneSig=(cone_list*)user->DATA ;

               if(coneSig==cone) continue ;

               if(((coneSig->TYPE & EXT)==EXT) &&
                  ((coneSig->TYPE & HZ)!=HZ)   &&
                  (coneSig->USER != NULL) ) 
               {
               ptype_list * userConect ;
               locon_list * connectSig ;
               userConect=getptype(coneSig->USER,EXT);
               connectSig=(locon_list*)userConect->DATA ;
                  if(connectSig->DIRECTION=='O') connectSig->DIRECTION='B';
               }
            }
         }
      }
   }
}
   
   
void  dsbAddCapaTransp(desafig)
desafig_list * desafig ;
{
locon_list * conect ;
   for(conect=desafig->LOCON;conect!=NULL;conect=conect->NEXT)
   {
      if(conect->DIRECTION=='X')
      {
      long capa ;
      capa=(long)(conect->SIG->CAPA * 1000.0);
      conect->USER=addptype(conect->USER,CAPA_TSP,(void*)capa);
      }
   }
}
