/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit : DESB  v2.n                                                  */
/*    Fichier : instance.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 : 27/01/1993     */
/*                                                                          */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*                                                                          */
/****************************************************************************/
#include "declar.h"


static short cmpOccur();
static void affPathModel();
static short cmpPathModel();
static char * reducModel();
static void calcVarOccur();
static void calcVarPoids();
static void addConePathModel();
static void addConeModel();
static void cleanConePathPoids();
static void cleanPoidsIncone();

/****************************************************************************
 *                         fonction dsbMakeConeModel();                     *
 ****************************************************************************/
void dsbMakeConeModel(cone)
cone_list * cone ;
{
calcVarOccur(cone);
calcVarPoids(cone);
addConePathModel(cone);
addConeModel(cone);
/* affConeModel(cone); */
cleanConePathPoids(cone);
cleanPoidsIncone(cone);
}

/****************************************************************************
 *                         fonction calcVarOccur();                         *
 ****************************************************************************/
static void  calcVarOccur(cone)  
cone_list * cone ;

{
char       * res ;
list_list  * path ;
link_list  * link ;
cone_list  * incone ;
locon_list * connect ;
ptype_list * user   ;
biint      * occur ;

   /*------------------------------------------------+
   | On incremente l'occurence de chaque variable    |
   +------------------------------------------------*/
   for(path=cone->PATH;path!=NULL;path=path->NEXT)
   {
      if((path->TYPE & BLEEDER)==BLEEDER) continue ;

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

         if((link->TYPE & TP)==TP)
         {
         incone=(cone_list*)link->TRANS->GRID;
         user=getptype(incone->USER,DSB_POIDS);
            if(user==NULL)
            {
            occur = (biint*) mbkalloc(sizeof(biint)) ;
            occur->NEG=1;
            occur->POS=0;
            incone->USER=addptype(incone->USER,DSB_POIDS,(void*)occur);
            continue ;
            }
            else
            {
            occur=(biint*)user->DATA;
            occur->NEG++;
            continue ;
            }
         }
         if((link->TYPE & TN)==TN)
         {
         incone=(cone_list*)link->TRANS->GRID;
         user=getptype(incone->USER,DSB_POIDS);
            if(user==NULL)
            {
            occur = (biint*)mbkalloc(sizeof(biint));
            occur->NEG=0;
            occur->POS=1;
            incone->USER=addptype(incone->USER,DSB_POIDS,(void*)occur);
            continue ;
            }
            else
            {
            occur=(biint*)user->DATA;
            occur->POS++;
            continue ;
            }
         }
         else /* maillon connecteur */
         {
         connect=(locon_list*)link->TRANS;
         user=getptype(connect->USER,DSB_POIDS);
            if(user==NULL)
            {
            occur = (biint*)mbkalloc(sizeof(biint));
            occur->NEG=1;
            occur->POS=0;
            connect->USER=addptype(connect->USER,DSB_POIDS,(void*)occur);
            continue ;
            }
            else
            {
            occur=(biint*)user->DATA;
            occur->POS++;
            continue ;
            }
         }
      }
   }
}
        

/****************************************************************************
 *                         fonction calcVarPoids();                         *
 ****************************************************************************/
static void  calcVarPoids(cone)  
/*------------------------------------------------------------------+
| On donne le poids + eleve  aux variable d'occurence la + elevee   |
| En cas d'egalite c'est le premier qui prendra le poid le + faible |
| Le poids est range dans le user 'DSB_POIDS' du cone/connecteur    |
| d'entree, PUIS dans le user 'DSB_POIDS' du incone designant le    |
| cone/connecteur                                                   |
+------------------------------------------------------------------*/
cone_list * cone ;
{
list_list  * tabIn[400];
list_list  * incone    ;
long         poids = 1 ;
int          iMax  = 0 ;
int          i     = 0 ;
int          j     = 0 ;

   /*-----------------------------------+
   | On constitue le tableau de incones |
   +-----------------------------------*/
   for(incone=cone->INCONE;incone!=NULL;incone=incone->NEXT)
   {
      if((incone->TYPE & LOOP)==LOOP) continue ;
      else tabIn[i++]=incone ;
      if(i>=400)
      {
      printf("calcVarPoids : tabIn overflow \n");
      exit(-1);
      }
   }
iMax=i;
   /*-----------------------------------------+
   | On effectue le tri sur le tableau de in  |
   +-----------------------------------------*/
   for(i=0 ; i < iMax - 1 ; i++)
   {
      for(j=0 ; j < iMax - 1 -i ; j++ )
      {
      list_list * in ;
      ptype_list * user1 ;
      ptype_list * user2 ;
      biint *         occur1 ;
      biint *         occur2 ;

      in=tabIn[j];

         if(((in->TYPE & CONE_TYPE )==CONE_TYPE) ||
            ((in->TYPE & VDD )==VDD) ||
            ((in->TYPE & VSS )==VSS) )
         user1=getptype(((cone_list*)in->DATA)->USER,DSB_POIDS);
         else
         user1=getptype(((locon_list*)in->DATA)->USER,DSB_POIDS);

      occur1=(biint*)user1->DATA ;
      in=tabIn[j+1];

         if(((in->TYPE & CONE_TYPE )==CONE_TYPE) ||
            ((in->TYPE & VDD )==VDD) ||
            ((in->TYPE & VSS )==VSS) )
         user2=getptype(((cone_list*)in->DATA)->USER,DSB_POIDS);
         else
         user2=getptype(((locon_list*)in->DATA)->USER,DSB_POIDS);

      occur2=(biint*)user2->DATA ;

         if(cmpOccur(occur1,occur2)==1)    /*  occur1 > occur2  */
         {
         list_list * save ;
         save = tabIn[j] ;
         tabIn[j]=tabIn[j+1];
         tabIn[j+1] = save ;
         }
      }
   }

   /*--------------------------------------------------+
   | le poids est determine puis range dans le user du |
   | du cone : il remplace l'occurence biint           |
   +--------------------------------------------------*/
   for(i=0 ; i < iMax ; i++)
   {
   ptype_list * user ;
   list_list * in = tabIn[i] ;

      if(((in->TYPE & CONE_TYPE )==CONE_TYPE) ||
         ((in->TYPE & VDD )==VDD) ||
         ((in->TYPE & VSS )==VSS) )
      user = getptype(((cone_list*)in->DATA)->USER,DSB_POIDS);
      else 
      user = getptype(((locon_list*)in->DATA)->USER,DSB_POIDS);
   free(user->DATA);
   user->DATA=(void*)poids++;
   }
   /*-------------------------------------------+
   | On recopie ce poids dans le user du incone |
   +-------------------------------------------*/
   for(i=0 ; i < iMax ; i++)
   {
   ptype_list * user ;
   list_list * in = tabIn[i] ;
      if(((in->TYPE & CONE_TYPE )==CONE_TYPE) ||
         ((in->TYPE & VDD )==VDD) ||
         ((in->TYPE & VSS )==VSS) )
      user = getptype(((cone_list*)in->DATA)->USER,DSB_POIDS);
      else 
      user = getptype(((locon_list*)in->DATA)->USER,DSB_POIDS);
   poids=(long)user->DATA ;
   in->USER=addptype(in->USER,DSB_POIDS,(void*)poids);
   }
}
         
/****************************************************************************
 *                         fonction cleanPoidsIncone();                       *
 ****************************************************************************/
static void cleanPoidsIncone(cone)
cone_list * cone ;
{
list_list * in ;

   for (in=cone->INCONE;in!=NULL;in=in->NEXT)
   {
      if((in->TYPE & LOOP)==LOOP) continue ;
      if(((in->TYPE & CONE_TYPE )==CONE_TYPE) ||
         ((in->TYPE & VDD )==VDD) ||
         ((in->TYPE & VSS )==VSS) )
      ((cone_list*)in->DATA)->USER=delptype(((cone_list*)in->DATA)->USER,DSB_POIDS);
      else
      ((locon_list*)in->DATA)->USER=delptype(((locon_list*)in->DATA)->USER,DSB_POIDS);
   }
}

/****************************************************************************
 *                         fonction affPoidsCone();                         *
 ****************************************************************************/
void affPoidsCone(cone)
cone_list * cone ;
{
list_list * in ;

printf(" -------- affPoidsCone -------- sur (%d)\n",cone->INDEX);
fflush(stdout);

   for (in=cone->INCONE;in!=NULL;in=in->NEXT)
   {
      if((in->TYPE & LOOP)==LOOP) continue ;
      if(((in->TYPE & CONE_TYPE )==CONE_TYPE) ||
         ((in->TYPE & VDD )==VDD) ||
         ((in->TYPE & VSS )==VSS) )
      {
      ptype_list * user ;
      user=getptype(((cone_list*)in->DATA)->USER,DSB_POIDS);
      printf("inCone (%d) poids=%d\n",((cone_list*)in->DATA)->INDEX,(long)user->DATA);
      fflush(stdout);
      }
      else
      {
      ptype_list * user ;
      user=getptype(((locon_list*)in->DATA)->USER,DSB_POIDS);
      printf("inConect(%s) poids=%d\n",((locon_list*)in->DATA)->NAME,(long)user->DATA);
      fflush(stdout);
      }
   }
}


/****************************************************************************
 *                         fonction affOccurCone();                         *
 ****************************************************************************/
void affOccurCone(cone)
cone_list * cone ;
{
list_list * in ;
biint     * occur ;

printf(" -------- affOccurCone -------- sur (%d)\n",cone->INDEX);
fflush(stdout);

   for (in=cone->INCONE;in!=NULL;in=in->NEXT)
   {
      if((in->TYPE & LOOP)==LOOP) continue ;
      if(((in->TYPE & CONE_TYPE )==CONE_TYPE) ||
         ((in->TYPE & VDD )==VDD) ||
         ((in->TYPE & VSS )==VSS) )
      {
      ptype_list * user ;
      user=getptype(((cone_list*)in->DATA)->USER,DSB_POIDS);
      occur=(biint*)user->DATA;
      printf("in(%d) occur=(%d,%d)\n",((cone_list*)in->DATA)->INDEX,occur->POS,occur->NEG);
      fflush(stdout);
      }
      else
      {
      ptype_list * user ;
      user=getptype(((locon_list*)in->DATA)->USER,DSB_POIDS);
      occur=(biint*)user->DATA;
      printf("Xin(%s) occur=(%d,%d)\n",((locon_list*)in->DATA)->NAME,occur->POS,occur->NEG);
      fflush(stdout);
      }
   }
}



/****************************************************************************
 *                         fonction cmpOccur();                            *
 ****************************************************************************/
/*--------------------------------------------------------------------------+
| Retourne 1 si oc1 > oc2                                                   |
|          2 si oc2 > oc1                                                   |
|          0 si oc1=oc2                                                     |
+--------------------------------------------------------------------------*/
static short cmpOccur(oc1,oc2)
biint * oc1 ;
biint * oc2 ;
{
   if(oc1->POS > oc2->POS) return(1);
   else if(oc1->POS < oc2->POS) return(2);
   else 
   {
      if(oc1->NEG > oc2->NEG) return(1);
      else if(oc1->NEG < oc2->NEG) return(2);
      else return(0);
   }
}

/****************************************************************************
 *                         fonction addPathModel();                         *
 ****************************************************************************/
/*--------------------------------------------------------------------------+
| exprime la fonctionalite de la branche enfonction du poids des variable   |
| Les variable de poids les plus faibles sont a gauche des variables de     |
| poids + eleve. Le resultat est un char * qui est rqnge dans le USER       |
| DSB_POIDS du pointeur de branche 'path'                                   |
+--------------------------------------------------------------------------*/
static void addPathModel(path)
list_list * path ;
{
cone_list  * incone ;
locon_list * connect ;
link_list * link ;
ptype_list  * user ;
long tabVar[10] ;
short idx = 0 ;
short j   = 0 ;
short iMax = 0 ;
char * expr ;
char   buff[100];

buff[0]='\0' ;

   /*----------------------------------------------------------+
   | On constitue le tableau exprimant le produit de variables |
   | que l'on ordone ensuite en fonction du poids              |
   +----------------------------------------------------------*/
   for(link=(link_list*)path->DATA;link!=NULL;link=link->NEXT)
   {

      if((link->TYPE & TP)==TP)
      {
      incone=(cone_list*)link->TRANS->GRID;
      user=getptype(incone->USER,DSB_POIDS);
         if(user==NULL)
         {
         exit(-1);
         }
         else
         {
         tabVar[idx++]=(-1)*((long)user->DATA) ;
         continue ;
         }
      }
      if((link->TYPE & TN)==TN)
      {
      incone=(cone_list*)link->TRANS->GRID;
      user=getptype(incone->USER,DSB_POIDS);
         if(user==NULL)
         {
         exit(-1);
         }
         else
         {
         tabVar[idx++]=((long)user->DATA) ;
         continue ;
         }
      }
      else       /* maillon connecteur */
      {
      connect=(locon_list*)link->TRANS;
      user=getptype(connect->USER,DSB_POIDS);
         if(user==NULL)
         {
         exit(-1);
         }
         else
         {
         tabVar[idx++]=((long)user->DATA) ;
         continue ;
         }
      }
   }

iMax=idx;
   /*-----------------------------------------+
   | On effectue le tri sur le tableau de Var |
   +-----------------------------------------*/
   for(idx=0 ; idx < iMax - 1 ; idx++)
   {
      for(j=0 ; j < iMax - 1 -idx ; j++ )
      {
         if(tabVar[j]>tabVar[j+1]) 
         {
         int  save ;
         save = tabVar[j] ;
         tabVar[j]=tabVar[j+1];
         tabVar[j+1] = save ;
         }
      }
   }

   /*---------------------------------------------+
   | On construit l'expression  du terme          |
   +---------------------------------------------*/
   for(idx=0;idx < iMax ; idx++)
   {
   char  tmp[100];
      if(tabVar[idx] >= 0 ) sprintf(tmp,"+%d",tabVar[idx]);
      else sprintf(tmp,"%d",tabVar[idx]);
   strcat(buff,tmp);
   }

expr=(char*)mbkalloc(strlen(buff)+1);
strcpy(expr,buff);

/*-------------------------------------------+
| On range l'expression dans le USER du path |
+-------------------------------------------*/
path->USER = addptype(path->USER,DSB_POIDS,(void*)expr);
}


/****************************************************************************
 *                         fonction affPathModel();                         *
 ****************************************************************************/
static void affPathModel(path)
list_list * path ;
{
ptype_list * user ;

   user=getptype(path->USER,DSB_POIDS);

   if(user==NULL)
   {
   printf("Path without USER 'DSB_POIDS'\n");
   fflush(stdout);
   exit(-1);
   }

printf("path='%s'\n",(char*)user->DATA);
fflush(stdout);

}

/****************************************************************************
 *                         fonction affConePathModel();                     *
 ****************************************************************************/
void affConePathModel(cone)
cone_list * cone ;
{
list_list * path ;

printf("--- affConePathModel sur (%d) ---\n",cone->INDEX);
fflush(stdout);

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

/****************************************************************************
 *                         fonction addConePathModel();                     *
 ****************************************************************************/
static void addConePathModel(cone)
cone_list * cone ;
{
list_list * path ;
   for(path=cone->PATH;path!=NULL;path=path->NEXT)
   {
      if((path->TYPE & BLEEDER)==BLEEDER) continue ;
      else addPathModel(path);
   }
} 


/****************************************************************************
 *                         fonction cleanConePathPoids();                   *
 ****************************************************************************/
/*--------------------------------------------------------------------------+
| nettoie tous les user 'DSB_POIDS' des branche du cone                     |
+--------------------------------------------------------------------------*/
static void cleanConePathPoids(cone)
cone_list * cone ;
{
list_list * path ;
   for(path=cone->PATH;path!=NULL;path=path->NEXT)
   {
      if((path->TYPE & BLEEDER) == BLEEDER) continue ;
      else
      {
      ptype_list * user ;
         if((user=getptype(path->USER,DSB_POIDS))!=NULL)
         {
         free(user->DATA);
         path->USER=delptype(path->USER,DSB_POIDS);
         }
         else
         {
         dsbBug(5,"cleanConePathPoids",cone->NAME,"DSB_POIDS",0);
         }
      }
   }
}



/****************************************************************************
 *                         fonction cmpPathModel();                         *
 ****************************************************************************/
/*--------------------------------------------------------------------------+
| compare les expression modeles des path en vue de les classer             |
| retourne 1 si exp1 > exp2                                                 |
|          2 si exp1 < exp2                                                 |
|          0 si exp1 = exp2                                                 |
+--------------------------------------------------------------------------*/
static short cmpPathModel(exp1,exp2,signe)
char * exp1 ;
char * exp2 ;
int   signe ;
{
char * p1 ;
char * p2 ;

p1 = exp1 ;
p2 = exp2 ;

   if (*p1=='+' || *p1=='-' || *p1=='\0' ||
       *p2=='+' || *p2=='-' || *p2=='\0' )
   {
      /*----------------+
      | cas  '+' vs 'x' |
      +----------------*/
      if(*p1=='+' && *p2=='+')
      {
      p1++;
      p2++;
      return(cmpPathModel(p1,p2,1));
      }
      else if(*p1=='+')              /* *p2=='-' || *p2=='\0' */
      {
      return(1);
      }
      /*----------------+
      | cas  '-' vs 'x' |
      +----------------*/
      else if(*p1=='-' && *p2=='+')
      {
      return(2);
      }
      else if(*p1=='-' && *p2=='-')
      {
      p1++;
      p2++;
      return(cmpPathModel(p1,p2,-1));
      }
      else if(*p1=='-' && *p2=='\0')
      {
      return(1);
      }
      /*-----------------+
      | cas  '\0' vs 'x' |
      +-----------------*/
      else if(*p1=='\0' && *p2=='\0')
      {
      return(0);
      }
      else if(*p1=='\0')          /*  *p2=='+' || *p2=='-'  */
      {
      return(2);
      }
      else 
      {
      printf("[err] cmpPathModel ambiguous case \n");
      fflush(stdout);
      exit(-1);
      }
   }

   else 
   {
   char tp1[6];
   char tp2[6];
   short i = 0 ;
   int ps1 ;
   int ps2 ;

      while((*p1!='+')&&(*p1!='-')&&(*p1!='\0'))
      {
      tp1[i++]= *p1;
      p1++;
      }

   tp1[i]='\0';
   i=0;

      while((*p2!='+')&&(*p2!='-')&&(*p2!='\0'))
      {
      tp2[i++]= *p2;
      p2++;
      }
   tp2[i]='\0';

   ps1=atoi(tp1)*signe ;
   ps2=atoi(tp2)*signe ;

      if( ps1 > ps2 ) return(1);
      else if( ps1 < ps2 ) return(2);
      else return(cmpPathModel(p1,p2,signe));
   }
}

/****************************************************************************
 *                         fonction addConeModel();                        *
 ****************************************************************************/
/*-------------------------------------------------------------------------+
| fabrique  l'expression Modele ordonnee                                   |
| On le range dans le user 'DSB_MODEL'                                     |
+-------------------------------------------------------------------------*/
static void  addConeModel(cone)
cone_list * cone ;
{
list_list * path ;
char * res ;
int maxLength  ;
int i         = 0  ;
int iMax      = 0 ;
int j         = 0 ;
long type ;
char * tabPath[515];
list_list * tabBran[515];


   /*--------------------------------------------+
   | On constitue le tableau des expressions sur |
   | lequel sera effectue le tri                 |
   +--------------------------------------------*/
   for(path=cone->PATH;path!=NULL;path=path->NEXT)
   {
   ptype_list * user ;

      if((path->TYPE & BLEEDER) == BLEEDER) continue ;
  
   user=getptype(path->USER,DSB_POIDS);

      if(user==NULL)
      {
      dsbBug(5,"addConeModel",cone->NAME,"DSB_POIDS",0);
      }
   tabBran[i]=path ;
   tabPath[i++]=(char*)user->DATA ;
     if(i>514) 
     {
     dsbBug(6,"addConeModel",NULL,NULL,0);
     }
   }

iMax = i ;

   /*-------------------------------------------_+
   | On effectue le tri                          |
   +--------------------------------------------*/
   for(i=0; i < iMax - 1 ; i++)
   {
      for(j=0; j< iMax -1 -i ; j++)
      {
      short test  ;

         if((test=cmpPathModel(tabPath[j],tabPath[j+1]))==1) /*[j]>[j+1]*/
         {
         char * save ;
         list_list * lsave ;
         save = tabPath[j];
         tabPath[j]=tabPath[j+1];
         tabPath[j+1]=save ;

         lsave = tabBran[j];
         tabBran[j]=tabBran[j+1];
         tabBran[j+1]=lsave ;
         }
      }
   }

/*-----------------------------------------------+
| On constitue la'somme' ordonnee de tout ca !!  |
+-----------------------------------------------*/
res=(char*)malloc(200);
maxLength=100 ;
res[0]='\0' ;
j=1 ;

   for(i=0 ; i < iMax - 1 ; i++)
   {
   type = (tabBran[i])->TYPE;

      if((type & VDD)==VDD) strcat(res,"U");
      else if ((type & VSS)==VSS) strcat(res,"D");
      else strcat(res,"E");

   strcat(res,tabPath[i]);
   strcat(res,"_");

      if(strlen(res)>maxLength) 
      {
      res=(char*)realloc(res,(200)+(j*100));
         if(res==NULL)
         {
         dsbBug(15,"addConeModel",NULL,NULL,0);
         }
      maxLength += 100 ;
      j++ ;
      }
   }

type=(tabBran[iMax-1])->TYPE ;

   if((type & VDD)==VDD) strcat(res,"U");
   else if ((type & VSS)==VSS) strcat(res,"D");
   else strcat(res,"E");

strcat(res,tabPath[iMax-1]);
res = reducModel(res);       /* On supprimme les branche en parallele */
cone->USER=addptype(cone->USER,DSB_MODEL,(void*)namealloc(res));
}

/****************************************************************************
 *                         fonction affConeModel();                         *
 ****************************************************************************/
void affConeModel(cone)
cone_list * cone ;
{
ptype_list * user ;

   user=getptype(cone->USER,DSB_MODEL);
   if(user==NULL)
   {
   dsbBug(4,"addConeModel",cone->NAME,NULL,0);
   }

   else 
   {
   printf("coneModel(%d) = '%s'\n",cone->INDEX,reducModel((char*)user->DATA));
   fflush(stdout);
   }
}

static char * reducModel(expr)
char * expr ;
{
char       * res ;
char         buff[30];
chain_list * ptchain ;
short        simplify = 0 ;
chain_list * chaine   = NULL ;
char       * pt1      = expr ;

   while(*pt1!='\0') 
   {
   char * pt2 = pt1 ;
   char * tmp ;
   int i = 0 ;
      if(*pt2 == '_') pt2++;

      while((*pt2 != '_')&&(*pt2!='\0'))
      {
      buff[i++] = *pt2 ;
      pt2++;
      }

   buff[i] = '\0';
   tmp = namealloc(buff);

      if(chaine==NULL)  
      {
      chaine=addchain(chaine,(void*)tmp);
      pt1=pt2;
      }
      else if((char*)chaine->DATA != tmp)
      {
      chaine=addchain(chaine,(void*)tmp);
      pt1=pt2;
      }
      else 
      {
      pt1=pt2;
      simplify=1;
      }
   }
   if(simplify == 0) return(expr);

res = (char *)mbkalloc(strlen(expr)+1);
res[0]='\0';
chaine = reverse (chaine);

   for(ptchain=chaine;ptchain!=NULL;ptchain=ptchain->NEXT)
   {
   strcat(res,(char*)ptchain->DATA);
      if(ptchain->NEXT != NULL)
      strcat(res,"_");
   }

freechain(chaine);
return(namealloc(res));
}


      
