/* ###--------------------------------------------------------------### */
/*									*/
/* file		: sl_compile.c						*/
/* date		: november 20 91					*/
/*                June 23 92                                            */
/* author	: BURGUN L.						*/
/*									*/
/*									*/
/* ###--------------------------------------------------------------### */

#include MUT_H
#include LOG_H
#include <math.h>
#include BEH_H
#include BVL_H
#include "lax_param.h"
#include "../synthe/sl_type.h"
#include "sl_util.h"


/*----------------------------------------------------------------------------
compileVHDL   	: compile un vbe , cree eventuellement les BDD et verifie la 
		  coherence de la description. 
		  orderPI = permet d'imposer un ordonnancement initial
		  si sauveaux = 1 on conserve les variables intermediaires
		  si gcOk = 1 on peut effectuer un garbage collector.
		  si vhb_reorder > 1 on peut re-ordonnancer les bdds du circuit.
                  makeBdd = 1 : creation de BDD
		     -> Le systeme des BDD doit etre initialise auparavant.
		  trace : mode trace
		  func : fonction de renomage des signaux internes
		  beh : si <> NULL, la befig a deja ete compilee
------------------------------------------------------------------------------
retour		: NULL si la compilation n'a pas fonctionne 
                  l'ordonnancement des variables d'entrees sinon.
------------------------------------------------------------------------------*/

chain_list *compileVHDL(file,orderPI,order,par,saveaux,gcOK,vhb_reorder,makeBdd,trace,func,beh)
char *file;
chain_list *orderPI;
int order;
param *par;
int saveaux;
int gcOK;
int vhb_reorder;
int makeBdd;
int trace;
char *(*func)();
befig_list *beh;
{
befig_list *vhdlloadbefig();
beaux_list *aux;
berin_list *in;
chain_list *ptChain;
chain_list *makeOrderAbl();
chain_list *makeOrderBddBeh();
bebus_list *bus;
bebux_list *bux;
biabl_list *biabl;
bereg_list *reg;
int coInter;
char *path;
int i;
int indice = 0;
char *filep;
char *namePUTENV;
chain_list *liste, *pAux=NULL;


		/* si BEH est NULL, on appelle le compilateur */

   if (beh == NULL)
      {
		/* calcul des variables d'environnement et des string */

      filep = (char *) mbkalloc (strlen(file) + 1);

      strcpy(filep,file);

      file = filep;

      for (i=0; i< strlen(file); i++)
          if (file[i] == '/')
             indice = i; 

      if (indice == 0)
         {
         path = ".";
         file[strlen(file) - 4] = '\0';
         } 
      else
         {
         path = (char *) mbkalloc (indice + 1);
         strncpy(path,file,indice);
         path[indice] = '\0';
         for (i=0;i<=indice;i++)
            file++;
         file[strlen(file) - 4] = '\0';
         }

		/* maj des var. d'environnement du compilateur */

      BVL_ERRFLG = 0;

		/* compilation du VHDL */

      beh = vhdlloadbefig (NULL,file,trace);
      }

   if (beh->ERRFLG != 0)
      {
      return(NULL);
      }

		/* on empile sur VHB_HEDFIG */

   beh->NEXT = VHB_HEDFIG;
   VHB_HEDFIG = beh;
   
		/* mise a NULL du champ USER pour les registres */

   reg = beh->BEREG;
   while (reg)
      {
      biabl = reg->BIABL;
      while (biabl)
         {
         biabl->USER = NULL;
         biabl = biabl->NEXT;
         }
      reg = reg->NEXT;
      }


	/* verification de la declaration correcte d'attribut 'stable

           forme valide      (l = '0') and not l'stable   : front descendant
                             (and (not l) (not (stable l)))

           ou                (l = '1') and not l'stable   : front montant
                             (and l (not (stable l)))
         */ 

   if (beh->TYPE & BEH_STABLE)
      {
      reg = beh->BEREG;
      while (reg)
         {
         biabl = reg->BIABL;
         while (biabl)
            {
            chain_list *inter = biabl->CNDABL;

		/* patch eliminant les egalites avec NXOR */

            biabl->CNDABL = remegalExpr(biabl->CNDABL);
            if (searchOperExpr(biabl->CNDABL,STABLE))
               {
               chain_list *pattern1,*pattern2;

               pattern1 = charToExpr("(and (not x) (not (stable x)))");
               pattern2 = charToExpr("(and x (not (stable x)))");

               if (!PMExpr(biabl->CNDABL,pattern1) &&
                   !PMExpr(biabl->CNDABL,pattern2))
                  {
                  PRINTF("VHDL : Error - bad usage of the 'stable' attribut\n");
                  return(NULL);
                  }
               else
                  {
                  biabl->USER = addptype(NULL,0,0); 
                  }

               /*    (and (not x) (not (stable x))) --> x */
               /*    (and x (not (stable x))) --> (not x) */

               if (ATOM(CADR(biabl->CNDABL)))
                  biabl->CNDABL = notExpr(CADR(biabl->CNDABL));
               else
                  biabl->CNDABL = CADR(CADR(biabl->CNDABL));
               
               freeExpr(pattern1);
               freeExpr(pattern2);
               }
            freeExpr(inter);
            biabl = biabl->NEXT;
            }
         reg = reg->NEXT;
         }
      }


	/* on renomme les variables de la befig pour les vecteurs */

   if (func != NULL)
      renameBeh(beh,func);

	/* mise a plat des expressions binaires */ 

   mapExprBeh(beh,flatArityExpr);


	/*=====  On cree des BDD =====*/

   if (makeBdd)
      {
		/* calcul de l'ordonnancement si automatique
                   ou pas de calcul precedent de l'ordonnancement */

      if (orderPI == NULL || order)		/* pas d'ordonnancement */
         {
         orderPI = makeOrderAbl(beh,order,trace);
         if (trace == 2)
            {
   	    printf("\nMakeOrderAbl : automatic order : \n" );
	    afficheLC(orderPI);
            }
         }

      coInter = 0;

		/* ajout des var. auxiliaires pour ne pas les eliminer */

      if (saveaux == 1)
         {
         aux = beh->BEAUX;
         while (aux)
            {
            orderPI = addchain(orderPI,aux->NAME); 
            aux = aux->NEXT ;
            coInter++;
            }
         }
      else
		/* pour le circuit synthetise ajout des aux de intermediate */
         {
         if (par)
            {
            chain_list *intermediate; 
 
            intermediate = par->intermediate; 
            while ( intermediate)
               { 
               if (existAuxBeh(beh,intermediate->DATA)) 
                  orderPI = addchain(orderPI,intermediate->DATA); 
               intermediate = intermediate->NEXT; 
               coInter++;
               } 
            }
         }

      beh->CIRCUI =  initializeCct("figure",coInter+2*countInputBeh(beh),50);

      ptChain = orderPI;
      while (ptChain)
        {
        addInputCct(beh->CIRCUI,ptChain->DATA);
        ptChain = ptChain->NEXT ;
        }


		/* si l'ordonnancement n'est pas complet */

      ptChain = berinToChain_list(beh);
      while (ptChain) 
        {
        if (searchInputCct(beh->CIRCUI,ptChain->DATA) == EMPTYTH)
           addInputCct(beh->CIRCUI,ptChain->DATA);
        ptChain = ptChain->NEXT ;
        } 

      while ( makeBddBeh(beh,beh->CIRCUI,vhb_reorder,trace,50,100,&pAux) == 1 )
         {
         if (trace)
            {
            printf("Running makeOrderBddBeh ...");
            }

         if (gcOK)
            gcNodeBeh(beh);

         if (trace == 2)
            {
            printf("\n---> Number of nodes = %d",numberNodeAllBdd());
            if (gcOK)
               printf("(%d)\n\n",numberNodeAllBdd());
            else
               printf("\n\n");
            }

         if (numberNodeAllBdd() > 2000)
            orderPI = makeOrderBddBeh (beh,0,NULL,NULL,2,10,gcOK,0,8,0,NULL);
         if (trace == 2)
            {
   	    printf("\nAutomatic Re-ordering : \n" );
	    afficheLC(orderPI);
            }
         vhb_reorder--;
         if (trace)
            printf("\n");
         }

      liste = pAux;
/*
      printf("intermediate + ");
*/
      while (liste)
         {
/*
         printf(" %s",liste->DATA);
*/
         par->intermediate = addchain(par->intermediate,liste->DATA);
         liste = liste->NEXT;
         }

      if (trace)
         printf("---> Final number of nodes = %d",numberNodeAllBdd());

      if (gcOK)
         {
         gcNodeBeh(beh);
         if (trace)
            printf("(%d)\n\n",numberNodeAllBdd());
         }
      }


		/* retour liste triee des entrees */
   if (makeBdd)
      return(orderPI);
   else
      return((chain_list *)1);
}

/*----------------------------------------------------------------------------
remegalExpr   	: elimine les horreurs du style 
                        (not (xor a '0'))  --> not a
                        (not (xor a '1'))  --> a
------------------------------------------------------------------------------
retour		: une expression
------------------------------------------------------------------------------*/

chain_list *remegalExpr(expr)
chain_list *expr;
{
if (ATOM(expr))
   return(copyExpr(expr));
else
   {
   chain_list *ret;

   if ((OPER(expr) == NOT) && !ATOM(CADR(expr)) && (OPER(CADR(expr)) == XOR))
      {
      chain_list *filsExpr;
      chain_list *filsCst;

      filsExpr = CADR(expr);
      filsCst = CADR(CDR(filsExpr));

      if (ATOM(filsCst) && !strcmp(VALUE_ATOM(filsCst),"'1'"))
         {
         return(copyExpr(CADR(filsExpr))); 
         } 
      if (ATOM(filsCst) && !strcmp(VALUE_ATOM(filsCst),"'0'"))
         {
         return(notExpr(copyExpr(CADR(filsExpr))));
         } 
      }

   ret = createExpr(OPER(expr));
   
   while (expr = CDR(expr))
      {
      addQExpr(ret,remegalExpr(CAR(expr)));
      }
   return(ret);
   }
}

/*----------------------------------------------------------------------------
decompileVHDL   : decompile une befig vers un vbe
                  reecrit les BD
------------------------------------------------------------------------------
retour		: void
------------------------------------------------------------------------------*/

void decompileVHDL(beh,name,trace)
befig_list *beh;
char *name;
int trace;
{
begen_list *tete,*savebeg;
char *saveName;
bereg_list *reg;

		/* remise a jour des BD */

reg = beh->BEREG;
while (reg)
   {
   biabl_list *biabl;
   
   biabl = reg->BIABL;
   while (biabl)
      {
      if (biabl->USER)	/* BD detectee */
         {
         chain_list *expr;

         if (ATOM(biabl->CNDABL))    	/* CNDABL = ck */
            {
            expr = charToExpr("(and (not x) (not (stable x)))");
            substPhyExpr(expr,"x",biabl->CNDABL);
            }
         else				/* CNDABL = (not ck) */
            {
            expr = charToExpr("(and x (not (stable x)))");
            substPhyExpr(expr,"x",CADR(biabl->CNDABL));
            }

         freeExpr(biabl->CNDABL);
         biabl->CNDABL = expr;
         }
      biabl = biabl->NEXT;
      } 
   reg = reg->NEXT;
   }

if (name)
   {
   saveName = beh->NAME;
   beh->NAME = name;
   }

savebeg =  NULL;
tete = beh->BEGEN;

while (tete)
   {
   savebeg = beh_addbegen(savebeg,tete->NAME,tete->TYPE,tete->VALUE);
   tete = tete->NEXT;
   }

vhdlsavebefig(beh,trace);

beh->BEGEN = savebeg;

if (name)
   {
   beh->NAME = saveName;
   }
}
