/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit :synthetiseur FSM											    */
/*    Fichier :syf_aux.c                                                    */
/*                                                                          */
/*    (c) copyright 1993 Laboratoire MASI equipe CAO & VLSI                 */
/*    Tous droits reserves                                                  */
/*    Support : e-mail cao-vlsi@masi.ibp.fr                                 */
/*                                                                          */
/*    Auteur(s) :Sarwary C.                              le : 20/09/1993     */
/*                                                                          */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*                                                                          */
/****************************************************************************/
#include <mut312.h>
#include  LOG_H
#include "../beh104/beh104.h"
#include <math.h>
#include "syf_aux.h"

/*-------------------------------------------------------------------------
syf_resetDustExpr 	: remet les champs poubelles d'une expression a 0. 
---------------------------------------------------------------------------
retour		: un void.
---------------------------------------------------------------------------*/
void syf_resetDustExpr(expr)
chain_list *expr;
{
if (!ATOM(expr))
   {
   CDR(CAR(expr)) = 0;
   while (expr = CDR(expr))
      {
      syf_resetDustExpr(CAR(expr));
      }
   }
}
/*-------------------------------------------------------------------------
syf_arity2Expr 	: transforme une expression avec operateur d'arite 2.   
---------------------------------------------------------------------------
retour		: un chain_list *.
---------------------------------------------------------------------------*/
chain_list *syf_arity2Expr(expr)
chain_list *expr;
{
if (ATOM(expr))
   return(copyExpr(expr));
else
   {
   chain_list *resul;
   
   resul = createExpr(OPER(expr));
   if (lengthExpr(expr) <= 2)
      {
      while (expr = CDR(expr))
         addQExpr(resul,syf_arity2Expr(CAR(expr)));
      return(resul);
      }
   else
     {
     int i;
     chain_list *inter = NULL;
      
     for (i = lengthExpr(expr)-1 ; i>0 ; i--)
        {
        resul = createExpr(OPER(expr));
        if (inter == NULL)
           {
           addHExpr(resul,syf_arity2Expr(searchNumExpr(expr,i)));
           addHExpr(resul,syf_arity2Expr(searchNumExpr(expr,i-1)));
           }
        else
           {
           addHExpr(resul,inter);
           addHExpr(resul,syf_arity2Expr(searchNumExpr(expr,i-1)));
           }
        inter = resul;
        } 
     return(resul);
     }
   }
}
/*-------------------------------------------------------------------------
syf_markAblWBddBeh 	: marque le champs user des expressions avec le pNode
                  correspondant dans une befig. 
---------------------------------------------------------------------------
retour		: un pNode.
---------------------------------------------------------------------------*/
pNode syf_markAblWBddBeh(beh,expr)
syf_befig_list *beh;
chain_list *expr;
{
pCircuit pC = beh->CIRCUI;

if (ATOM(expr))

		/* c'est forcement une entree de pC */
   {
   int val;

   if (!strcmp((char *) VALUE_ATOM(expr),"'0'"))
      return(zero);

   if (!strcmp((char *) VALUE_ATOM(expr),"'1'"))
      return(one);

   val = searchInputCct(pC,VALUE_ATOM(expr));
   if (val != EMPTYTH)
      return(createNodeTermBdd(val));
   else
      {
		/* recherche d'un auxiliaire */


      syf_beaux_list *aux = beh->BEAUX;
      pNode node = searchOutputCct(pC,VALUE_ATOM(expr));

		/* deja calcule */

      if (node != NULL)
         return(node);

      while (aux && strcmp(VALUE_ATOM(expr),aux->NAME))
         {
         aux = aux->NEXT;
         }
      if (!aux)
         {
         printf("markAblWBeh : error auxiliary signal %s does'nt exist\n",
                VALUE_ATOM(expr));
         exit(-1);
         }

      node = syf_markAblWBddBeh(beh,aux->ABL);
      addOutputCct(beh->CIRCUI,aux->NAME,node);
      return(node);
      }
   }
else
   {
   short oper;
   pNode pt;
   chain_list *lstGdb;
   chain_list *tete;
   
   tete = expr;
   oper = OPER(expr);
   lstGdb = NULL;
   while (expr = CDR(expr))
      lstGdb = addListBdd(lstGdb,syf_markAblWBddBeh(beh,CAR(expr)));
   pt = applyBdd(oper,lstGdb);
   freechain(lstGdb);

		/* le marquage */

   CDR(CAR(tete)) = (chain_list *) pt;
   return(pt);
   }
}
/*-------------------------------------------------------------------------
syf_occTHBddBeh 	: calcule le nombre d'occurences de chaque graphe. 
---------------------------------------------------------------------------
retour		: un void.
---------------------------------------------------------------------------*/
void syf_occTHBddBeh(expr,pTabNode)
chain_list *expr;
pTH pTabNode;
{
pNode nodeP,nodeN;
int valueN,valueP;

if (!ATOM(expr))
   {
   nodeP = (pNode) CDR(CAR(expr));
   nodeN = notBdd(nodeP);

   valueP = searchTH(pTabNode,(char *) nodeP);
   if (valueP == EMPTYTH)
      valueP = 0;
   valueN = searchTH(pTabNode,(char *) nodeN);
   if (valueN == EMPTYTH)
      valueN = 0;
   

   if (valueN + valueP == 0)
      {
      if (OPER(expr) != NOT)
         addTH(pTabNode,nodeP,1);

		/* appel recursif sur les arguments */

      while (expr = CDR(expr))
         {
         syf_occTHBddBeh(CAR(expr),pTabNode);
         }
      }
   else
      addTH(pTabNode,nodeP,1 + valueP);
   }
}
   
/*-------------------------------------------------------------------------
syf_createVIBeh 	: creation des variables intermediaires. 
---------------------------------------------------------------------------
retour		: une liste des var. aux.
---------------------------------------------------------------------------*/
chain_list *syf_createVIBeh(beh,expr,pTabNode,numberSon)
syf_befig_list *beh;
chain_list *expr;
pTH pTabNode;
int numberSon;
{
static int co=0;
int isNot = 0;

if (expr == NULL)
   {
   printf("syf_createVIBeh : error expr = NULL\n");
   exit(-1);
   }

if (ATOM(expr))
   return(copyExpr(expr));
else
   {
   chain_list *resul;
   pNode nodeP,nodeN;
   int valueP,valueN;	/* le nombre d'occurence des graphes */

   nodeP = (pNode) CDR(CAR(expr));

		/* 1 cas particuliers */

		/* 1. Graphe non calcule            */

   if (nodeP == 0)
      return(copyExpr(expr));


		/* cas normal */

   valueP = abs(searchTH(pTabNode,nodeP));

   if (valueP > MAX_FATHER)
      {
 		/* c'est deja une variable auxiliaire... */

      return(copyExpr((chain_list *) valueP));

		/* carrement ...!!! */
      }

   resul = createExpr(OPER(expr));

	/* on evite de creer trop de variables intermediaires... */


		/* traitement du not */
   

   if (OPER(expr) == NOT)
      {
      if (!(ATOM(CADR(expr))))
         {
         isNot = 1;
         expr = CADR(expr);
         resul = createExpr(OPER(expr));
         }
      else
         return(copyExpr(expr));
      }

   while (expr = CDR(expr))
      {
      addQExpr(resul,syf_createVIBeh(beh,CAR(expr),
                                  pTabNode,numberSon));
      }   
  

   nodeN = notBdd(nodeP);
   valueN = searchTH(pTabNode,nodeN);
   if (valueN == EMPTYTH)
      valueN = 0;
   if (valueP == EMPTYTH)
      {
      printf("error : syf_createVIBeh - expr with empty user NULL\n");
      exit(-1);
      }  
   
		/* la fonction possedent suffisament de peres ? */

   if (valueP + valueN >= 2)
      {
      char *name, *syf_gensym();
      syf_beaux_list *aux;
         
      name = syf_gensym("aux",co++);
/*
if (syf_trace)
   {
printf("Generating %s  P = %d  N = %d\nequation : ",name,valueP,valueN);
displayExpr(resul);
   }
 */        
      if (valueP >= valueN)
         {
         if (isNot)
            beh->BEAUX = syf_beh_addbeaux(beh->BEAUX,name,notExpr(resul),NULL);
         else
            beh->BEAUX = syf_beh_addbeaux(beh->BEAUX,name,resul,NULL);
         aux = beh->BEAUX;

         while (aux && strcmp(aux->NAME,name))
            aux = aux->NEXT;

         if (aux)
            aux->NODE = nodeP;
         else
            {
            printf("syf_createVIBeh error - %s doesn't exist\n",name);
            exit(-1);
            }

         addTH(pTabNode,nodeP,(int) createAtom(name));
         addTH(pTabNode,nodeN,(int) notExpr(createAtom(name))); 
         return(createAtom(name));
         }
      else
         {
         if (isNot)
            beh->BEAUX = syf_beh_addbeaux(beh->BEAUX,name,resul,NULL);
         else
            beh->BEAUX = syf_beh_addbeaux(beh->BEAUX,name,notExpr(resul),NULL);
         aux = beh->BEAUX;
         while(aux)
            {
            if (aux->NAME == name)
               {
               aux->NODE = nodeN;
               aux = NULL;
               }
            else
               aux = aux->NEXT;
            }
         addTH(pTabNode,nodeP,(int) notExpr(createAtom(name))); 
         addTH(pTabNode,nodeN,(int) createAtom(name));
         return(notExpr(createAtom(name)));
         }
      }
		/* pas de variable auxilaire */

   if (isNot)
      resul = notExpr(resul);

   return(resul);
   }
}


/*-------------------------------------------------------------------------
syf_createAuxBeh 	: creation de VI pour une befig 
---------------------------------------------------------------------------
retour		: un void.
---------------------------------------------------------------------------*/
syf_createAuxBeh(beh)
syf_befig_list *beh;
{
syf_beout_list *out;
syf_beaux_list *aux;
syf_bereg_list *reg;
syf_bebus_list *bus;
syf_bebux_list *bux;
biabl_list *biabl;
chain_list *expr;
int numberSon;
pTH pTabNode;

pTabNode = createTH(1999);

syf_mapExprBeh(beh,syf_resetDustExpr);

		/* transformation en arbres ABL binaire */

syf_mapCarExprBeh(beh,syf_arity2Expr);

		/* le marquage des ABL */

   aux = beh->BEAUX;
   while (aux) 
      {
      addOutputCct(beh->CIRCUI,aux->NAME,syf_markAblWBddBeh(beh,aux->ABL));
      aux = aux->NEXT;
      }

   out = beh->BEOUT;
   while (out) 
      {
      syf_markAblWBddBeh(beh,out->ABL);
      out = out->NEXT;
      }

   reg = beh->BEREG;
   while (reg) 
      {
      biabl = reg->BIABL;
      while (biabl)
         {
         syf_markAblWBddBeh(beh,biabl->CNDABL);
         syf_markAblWBddBeh(beh,biabl->VALABL);
         biabl = biabl->NEXT;
         }
      reg = reg->NEXT;
      }


   bus = beh->BEBUS;
   while (bus) 
      {
      biabl = bus->BIABL;
      while (biabl)
         {
         syf_markAblWBddBeh(beh,biabl->CNDABL);
         syf_markAblWBddBeh(beh,biabl->VALABL);
         biabl = biabl->NEXT;
         }
      bus = bus->NEXT;
      }

   bux = beh->BEBUX;
   while (bux) 
      {
      biabl = bux->BIABL;
      while (biabl)
         {
         syf_markAblWBddBeh(beh,biabl->CNDABL);
         syf_markAblWBddBeh(beh,biabl->VALABL);
         biabl = biabl->NEXT;
         }
      bux = bux->NEXT;
      }

		/* le calcul du nombre d'occurence */

   out = beh->BEOUT;
   while (out) 
      {
      syf_occTHBddBeh(out->ABL,pTabNode);
      out = out->NEXT;
      }

   aux = beh->BEAUX;
   while (aux) 
      {
      syf_occTHBddBeh(aux->ABL,pTabNode);
      aux = aux->NEXT;
      }

   reg = beh->BEREG;
   while (reg) 
      {
      biabl = reg->BIABL;
      while (biabl)
         {
         syf_occTHBddBeh(biabl->VALABL,pTabNode);
         syf_occTHBddBeh(biabl->CNDABL,pTabNode);
         biabl = biabl->NEXT;
         }
      reg = reg->NEXT;
      }


   bus = beh->BEBUS;
   while (bus) 
      {
      biabl = bus->BIABL;
      while (biabl)
         {
         syf_occTHBddBeh(biabl->VALABL,pTabNode);
         syf_occTHBddBeh(biabl->CNDABL,pTabNode);
         biabl = biabl->NEXT;
         }
      bus = bus->NEXT;
      }

   bux = beh->BEBUX;
   while (bux) 
      {
      biabl = bux->BIABL;
      while (biabl)
         {
         syf_occTHBddBeh(biabl->VALABL,pTabNode);
         syf_occTHBddBeh(biabl->CNDABL,pTabNode);
         biabl = biabl->NEXT;
         }
      bux = bux->NEXT;
      }
		/* fin du calcul des occurences de pNode
                   Ce calcul etant partiel , il faut necessairement
                   parcourir la befig de la meme maniere pour la
		   la creation des VI            
                 */


   numberSon = 2;

		/* on evite de creer des VI deja existante.... */

   aux = beh->BEAUX;
   while (aux) 
      {
      pNode tete = aux->NODE; 


			/* aux->NAME est deja une variable aux. */

      addTH(pTabNode,tete,createAtom(aux->NAME));
      addTH(pTabNode,notBdd(tete),notExpr(createAtom(aux->NAME)));

      aux = aux->NEXT;
      }

   out = beh->BEOUT;
   while (out) 
      {
      expr =out->ABL;
      out->ABL = syf_createVIBeh(beh,out->ABL,pTabNode,numberSon);
      freeExpr(expr);
      out = out->NEXT;
      }

   aux = beh->BEAUX;
   while (aux) 
      {
      chain_list *resExpr;
      int teteNot = 0;

      if (!ATOM(aux->ABL))     /* traitement special pour eviter de boucler */
         {
         expr =aux->ABL;
         if (OPER(expr) == NOT)
            {
            expr = CADR(expr);
            teteNot = 1;
            }
         if (!ATOM(expr))		/* on evite de traiter x <= not a; */
            {
            resExpr = createExpr(OPER(expr));
            while (expr = CDR(expr))
               {
               addQExpr(resExpr,syf_createVIBeh(beh,CAR(expr),pTabNode,numberSon));
               }
            expr = aux->ABL;
            if (teteNot)
               aux->ABL = notExpr(resExpr);
            else
               aux->ABL = resExpr;
            freeExpr(expr);
            }
         }
      aux = aux->NEXT;
      }

   reg = beh->BEREG;
   while (reg) 
      {
      biabl = reg->BIABL;
      while (biabl)
         {
         expr =biabl->CNDABL;
         biabl->CNDABL = syf_createVIBeh(beh,biabl->CNDABL,pTabNode,numberSon);
         freeExpr(expr);
         expr =biabl->VALABL;
         biabl->VALABL = syf_createVIBeh(beh,biabl->VALABL,pTabNode,numberSon);
         freeExpr(expr);
         biabl = biabl->NEXT;
         }
      reg = reg->NEXT;
      }

   bus = beh->BEBUS;
   while (bus) 
      {
      biabl = bus->BIABL;
      while (biabl)
         {
         expr =biabl->CNDABL;
         biabl->CNDABL = syf_createVIBeh(beh,biabl->CNDABL,pTabNode,numberSon);
         freeExpr(expr);
         expr =biabl->VALABL;
         biabl->VALABL = syf_createVIBeh(beh,biabl->VALABL,pTabNode,numberSon);
         freeExpr(expr);
         biabl = biabl->NEXT;
         }
      bus = bus->NEXT;
      }

   bux = beh->BEBUX;
   while (bux) 
      {
      biabl = bux->BIABL;
      while (biabl)
         {
         expr =biabl->CNDABL;
         biabl->CNDABL = syf_createVIBeh(beh,biabl->CNDABL,pTabNode,numberSon);
         freeExpr(expr);
         expr =biabl->VALABL;
         biabl->VALABL = syf_createVIBeh(beh,biabl->VALABL,pTabNode,numberSon);
         freeExpr(expr);
         biabl = biabl->NEXT;
         }
      bux = bux->NEXT;
      }

   syf_flatArityExprBeh(beh);

   destroyTH(pTabNode);

}
/*-------------------------------------------------------------------------
syf_mapExprBeh	: applique une procedure sur chaque expression d'une befig 
---------------------------------------------------------------------------
retour		: un void.
---------------------------------------------------------------------------*/
syf_mapExprBeh(beh,func)
syf_befig_list *beh;
void (*func)();
{
syf_beout_list *out;
syf_bereg_list *reg;
syf_bebus_list *bus;
syf_bebux_list *bux;
biabl_list *biabl;
syf_beaux_list *aux;

	/* parcours de la befig avec remplissage de pTHOcc */

aux = beh->BEAUX;
while (aux) 
   {
   if (aux->ABL)
      {
      (*func)(aux->ABL);
      }
   aux = aux->NEXT;
   }

out = beh->BEOUT;
while (out) 
   {
   if (out->ABL)
      {
      (*func)(out->ABL);
      }
   out = out->NEXT;
   }

reg = beh->BEREG;
while (reg) 
   {
   biabl = reg->BIABL;
   while (biabl)
      {
      if (biabl->CNDABL && biabl->VALABL)
         {
         (*func)(biabl->CNDABL);
         (*func)(biabl->VALABL);
         }
      biabl = biabl->NEXT;
      }
   reg = reg->NEXT;
   }

bus = beh->BEBUS;
while (bus) 
   {
   biabl = bus->BIABL;
   while (biabl)
      {
      if (biabl->CNDABL && biabl->VALABL)
         {
         (*func)(biabl->CNDABL);
         (*func)(biabl->VALABL);
         }
      biabl = biabl->NEXT;
      }
   bus = bus->NEXT;
   }

bux = beh->BEBUX;
while (bux) 
   {
   biabl = bux->BIABL;
   while (biabl)
      {
      if (biabl->CNDABL && biabl->VALABL)
         {
         (*func)(biabl->CNDABL);
         (*func)(biabl->VALABL);
         }
      biabl = biabl->NEXT;
      }
   bux = bux->NEXT;
   }
}
/*-------------------------------------------------------------------------
syf_flatArityExprBeh: mise a plat (elimination des operateurs redondants)
                  des abl(s) d'une befig. 
---------------------------------------------------------------------------
retour		: un void.
---------------------------------------------------------------------------*/
syf_flatArityExprBeh(beh)
syf_befig_list *beh;
{
syf_beout_list *out;
syf_bereg_list *reg;
syf_bebus_list *bus;
syf_bebux_list *bux;
biabl_list *biabl;
syf_beaux_list *aux;

aux = beh->BEAUX;
while (aux) 
   {
   if (aux->ABL)
      {
      flatArityExpr(aux->ABL);
      }
   aux = aux->NEXT;
   }

out = beh->BEOUT;
while (out) 
   {
   if (out->ABL)
      {
      flatArityExpr(out->ABL);
      }
   out = out->NEXT;
   }

reg = beh->BEREG;
while (reg) 
   {
   biabl = reg->BIABL;
   while (biabl)
      {
      if (biabl->CNDABL && biabl->VALABL)
         {
         flatArityExpr(biabl->CNDABL);
         flatArityExpr(biabl->VALABL);
         }
      biabl = biabl->NEXT;
      }
   reg = reg->NEXT;
   }

bus = beh->BEBUS;
while (bus) 
   {
   biabl = bus->BIABL;
   while (biabl)
      {
      if (biabl->CNDABL && biabl->VALABL)
         {
         flatArityExpr(biabl->CNDABL);
         flatArityExpr(biabl->VALABL);
         }
      biabl = biabl->NEXT;
      }
   bus = bus->NEXT;
   }

bux = beh->BEBUX;
while (bux) 
   {
   biabl = bux->BIABL;
   while (biabl)
      {
      if (biabl->CNDABL && biabl->VALABL)
         {
         flatArityExpr(biabl->CNDABL);
         flatArityExpr(biabl->VALABL);
         }
      biabl = biabl->NEXT;
      }
   bux = bux->NEXT;
   }
}
/*-------------------------------------------------------------------------
syf_gensym 		: calcule un identificateur avec concatenation d'un numero.
---------------------------------------------------------------------------
retour		: un pointeur de chaine de caracteres.
---------------------------------------------------------------------------*/
char *syf_gensym(name,num)
char *name;
int num;
{
char *name1;
char *retour;
int length = strlen(name);

name1 = (char *)  mbkalloc (length+8);
sprintf(name1,"%s_%d",name,num);
retour = namealloc(name1);
#ifndef ARCHI_PC
   mbkfree((void *)name1);	/* chaine */
#endif
return(retour);
}
