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


/****************************************************************************
 *                         fonction trans_chain();                          *
 ****************************************************************************/

            /* remplissage des champs GRID des transistors */

void trans_chain( pt_trans )
trans_list	*pt_trans ;
{ 
losig_list	*ptsig = NULL ;
ptype_list      * user = NULL ;

ptsig = pt_trans->GRID->SIG ;

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

   if(user!=NULL) pt_trans->GRID=(locon_list*)user->DATA ;
   else pt_trans->GRID=NULL;

}


/****************************************************************************
 *                         fonction test_ch_bloque();                       *
 ****************************************************************************/

          /* destruction des chemins bloques ou auto-referents */

void test_ch_bloque( pt_cone , N_autoref , N_bloque )

cone_list	*pt_cone ;
long		*N_bloque	;
long		*N_autoref	;
{
list_list	*pt_path		= NULL ;
list_list	*pt_sav	                = NULL ;
link_list	*pt_link		= NULL ;
link_list	*pt2_link		= NULL ;
int             index=0;
short           del_flag = 0;


   for ( pt_path =  pt_cone->PATH ; pt_path != NULL ; )
   {
   /* pour chaque branche */
   index++;
   del_flag=0;
      for ( pt_link = ( link_list * )pt_path->DATA ;
         pt_link != NULL ;
         pt_link = pt_link->NEXT )
      {
         /* pour chaque maillon */
         if ( ( ( pt_link->TYPE & TN ) ==TN )||(( pt_link->TYPE & TP ) ==TP ) )
         {
         /* si c'est un transistor */
            if ( ( cone_list * )pt_link->TRANS->GRID == pt_cone )
            {
            /* le cone est auto-referentiel : on le detruit */
            ( *N_autoref )++ ;
            pt_sav=pt_path->NEXT;
            del_path( pt_cone , pt_path ) ;
            pt_path = pt_sav ;
            del_flag=1;
            break ;
            }
            else if (((((cone_list *)pt_link->TRANS->GRID )->TYPE == VSS ) 
                     && ( ((pt_link->TRANS->TYPE)&TN)== TN ) )
                  || ( ( ( ( cone_list * )pt_link->TRANS->GRID )->TYPE == VDD)
                     && ( ((pt_link->TRANS->TYPE)&TP)== TP ) ) )
            {
            /* le chemin est bloque : on le detruit */
            ( *N_bloque )++ ;
            blq_trans(pt_path);
            pt_sav=pt_path->NEXT;
            del_path( pt_cone , pt_path ) ;
            pt_path = pt_sav ;
            del_flag=1;
            break ;
            }
            else 
            {
            /* on cherche un autre transistor commande par le meme cone */
               for ( pt2_link = pt_link->NEXT ; pt2_link != NULL ; pt2_link = pt2_link->NEXT )
               {
               /* pour chaque maillon suivant */
                  if ((( pt2_link->TYPE & TN ) == TN ) || (( pt2_link->TYPE & TP ) == TP ))
                  {
                  /* si c'est un transistor */
                     if ( ( pt2_link->TRANS->GRID == pt_link->TRANS->GRID )
                     && ( pt2_link->TRANS->TYPE != pt_link->TRANS->TYPE ) )
                     {
                     /* le chemin est bloque */
                     break ;
                     }
                  }
               }
               if ( pt2_link != NULL )
               {
                  /* le chemin est bloque : on le detruit */
               ( *N_bloque )++ ;
               blq_trans(pt_path);
               pt_sav=pt_path->NEXT;
               del_path( pt_cone , pt_path ) ;
               pt_path = pt_sav ;
               del_flag=1;
               break ;
               }
            }
         }
      }
      if (del_flag==0) pt_path=pt_path->NEXT;
   }
}


/****************************************************************************
 *                         fonction cone_chain();                           *
 ****************************************************************************/
         /*---------------------------------------------------*
          | remplissage des champs INCONE et OUTCONE des cones|
          *---------------------------------------------------*/

void cone_chain( pt_cone )
cone_list	*pt_cone ;
{
list_list	*pt_path		= NULL ;
list_list	*pt_prevpath	= NULL ;
link_list	*pt_link		= NULL ;
list_list	*pt_list		= NULL ;

/*----------------------------------------------* 
 | suppression eventuelle des branches externes | 
 | Celles terminees par un connecteur OUT       |
 *----------------------------------------------*/
   for(pt_path=pt_cone->PATH ; pt_path != NULL ; /* rien */)
   {
      if ( ( pt_path->TYPE & EXT ) == EXT )
      {
      list_list * pt_save ;

         for (pt_link=(link_list*)pt_path->DATA;
              pt_link->NEXT!=NULL;
              pt_link = pt_link->NEXT )
         {
         /* on va sur le dernier maillon */
         }

         switch(((locon_list *)pt_link->TRANS)->DIRECTION)
         {
            case 'I' :
	    {
            pt_link->TYPE &= ~( IN | INOUT ) ;
            pt_link->TYPE |= IN ;
            pt_path=pt_path->NEXT ;
            break ;
            }

            case 'O' :
            {
            pt_save=pt_path->NEXT;
            del_path(pt_cone,pt_path);
            pt_path=pt_save;
            break ;
            }

            case 'X' :
            {
            pt_link->TYPE &= ~( IN | INOUT ) ;
            pt_link->TYPE |= INOUT ;
            pt_path=pt_path->NEXT ;
            break ;
            }

            default :
            {
            dsbFatalError(6,"conechain",NULL,0);
            }
         }
      }
      else pt_path=pt_path->NEXT ;
   }

    /*---------------------------*
    | cone_chain proprement dit | 
    *---------------------------*/
   for ( pt_path = pt_cone->PATH ; pt_path != NULL ; pt_path = pt_path->NEXT )
   {
      for (pt_link=(link_list*)pt_path->DATA;pt_link!=NULL;pt_link=pt_link->NEXT)
      {

         /*------------------------------+
         |  Maillon  transistor          |
         +------------------------------*/
         if (((pt_link->TYPE & TN )==TN) || ((pt_link->TYPE & TP )==TP ))
         {
            /*----------------------------------------------------------+
            |  on en profite pour detecter les TN dans les branches VDD |
            |  et les TP dans les branches VSS                          |
            +----------------------------------------------------------*/
            if (((pt_link->TYPE & TP ) == TP ) 
                  && (((pt_path->TYPE & VSS)  == VSS ) || 
                      (pt_path->TYPE & EXT) == EXT ) )
            {
            pt_path->TYPE |= TPINVSS ;	
            pt_cone->TYPE |= TPINVSS ;	
            }
            else if ( ( ( pt_link->TYPE & TN ) == TN ) 
                    && ( ( (pt_path->TYPE & VDD ) == VDD ) 
                    || (pt_path->TYPE & EXT) == EXT ) )
            {
            pt_path->TYPE |= TNINVDD ;	
            pt_cone->TYPE |= TNINVDD ;	
            }
         /*-------------------------------------------------------------+
         |  on en profite pour marquer USED les transistors qui servent |
         +-------------------------------------------------------------*/
         pt_link->TRANS->TYPE |= USED ;

            /*-----------------------------------------------+
            |  on verifie que le cone en entree du transistor|
            |  n'est  pas deja dans la liste des INCONE      |
            +-----------------------------------------------*/
            for (pt_list=pt_cone->INCONE;pt_list!=NULL;pt_list = pt_list->NEXT ) 
            {
               if (pt_list->DATA == (char *)(pt_link->TRANS->GRID)) break ;
            }

            if ( pt_list == NULL )
            {
            cone_list *pt_incone ;
            pt_incone = ( cone_list * )pt_link->TRANS->GRID ;
               if ( ( pt_incone->TYPE != VDD )
                  && ( pt_incone->TYPE != VSS ) )
               {
               pt_cone->INCONE = add_list( pt_cone->INCONE , (char *)( pt_incone ) , ( long )CONE_TYPE ) ;
               }
               else
               {
               pt_cone->INCONE = add_list( pt_cone->INCONE , (char *)( pt_incone ) , ( long )pt_incone->TYPE ) ;
               }
            /* ainsi que dans la liste des OUTCONE du 
               cone en entree du transistor */
            pt_incone->OUTCONE = add_list( pt_incone->OUTCONE , ( char * )pt_cone , ( long )CONE_TYPE ) ;
            }
         }

         /*------------------------------+
         |  Maillon  connecteur externe  |
         +------------------------------*/
         else if ( ( pt_link->TYPE & ( IN | INOUT ) ) != 0 )
         {
         ptype_list	*pt_user = NULL ;
            /*----------------------------------------------------------+
            |  Si il n'est pas deja dans la liste des incones on        | 
            | l'ajoute dans la liste des entrees et                     | 
            |  On rajoute le cone dans le USER CONE_TYPE du connecteur  |
            +----------------------------------------------------------*/
            for (pt_list=pt_cone->INCONE;pt_list!=NULL;pt_list = pt_list->NEXT ) 
            {
               if (pt_list->DATA == (char *)(pt_link->TRANS)) break ;
            }
            if ( pt_list == NULL )
            {
            pt_cone->INCONE = add_list( pt_cone->INCONE , ( char *)( pt_link->TRANS ) , ( long )EXT ) ;
            pt_user=getptype(((locon_list *)pt_link->TRANS )->USER,CONE_TYPE);
            pt_user->DATA=(void *)addchain(pt_user->DATA,(void *)pt_cone);
            }
         }
         else 
         {
         dsbBug(16,"conechain",pt_cone->NAME,NULL,0);
         }
      }
   }
}


/****************************************************************************
 *                         fonction blq_trans();                            *
 ****************************************************************************/
   /*----------------------------------------------------------* 
    | Type les transistors qui sont dans des branches bloquees |
    *----------------------------------------------------------*/
void blq_trans(path)
list_list * path;
{
link_list * maill = NULL;

   for(maill=((link_list*)path->DATA);maill;maill=maill->NEXT)
   {
      if ( ((maill->TYPE & TN)!=TN) && ((maill->TYPE & TP)!=TP) ) continue;
   (maill->TRANS)->TYPE |= IN_CH_BL;
   }
}
