/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit : synthetiseur logique                                        */
/*    Fichier : util.c                                                      */
/*                                                                          */
/*    (c) copyright 1991 Laboratoire MASI equipe CAO & VLSI                 */
/*    Tous droits reserves                                                  */
/*    Support : e-mail cao-vlsi@masi.ibp.fr                                 */
/*                                                                          */
/*    Auteur(s) :     P. Allegre                        le : 21/08/91       */
/*                                                                          */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*                                                                          */
/****************************************************************************/

#include <stdio.h>
#include MUT_H
#include LOG_H
#include BEH_H
#include "../compil/lax_param.h"
#include "../synthe/sl_type.h"
#include "types.h"
#include "display.h"
#include "compile.h"
#include "regles.h"
#include "oper.h"
#include "moteur.h"
#include "mapper.h"
#include "util.h"

/*--------------------------------------------------------------------------
minPtype   	: recherche du type minimum
----------------------------------------------------------------------------
retour 		: pointeur sur le ptype
--------------------------------------------------------------------------*/

ptype_list *minPtype(liste)
ptype_list *liste;
{
ptype_list *min = liste;

   do
      if (liste->TYPE < min->TYPE)
         min = liste;
   while (liste = CDR(liste));
   return min;
}

/*--------------------------------------------------------------------------
displayAlist 	: affiche le contenu d'une liste associative 
----------------------------------------------------------------------------
retour 		: void. 
--------------------------------------------------------------------------*/

void displayAlist(ptTL)
Alist *ptTL;
{
chain_list *expr;
printf("-----------------------------------------------\n");
while (ptTL)
   {
   printf(" var = %s    expr = ",ptTL->name);fflush(stdout);
   expr = ptTL->ptChain;
   if (expr)
     if (ptTL->name[0] == '*')
         {
         printf("(");
         do
            displayArite(CAR(expr));
         while (expr = CDR(expr));
         printf(")");
         } 
      else
         displayArite(expr);
   else
      printf("NULL");
   ptTL = ptTL->NEXT;
   printf("\n");
   }
}

/*--------------------------------------------------------------------------
initAlist 	: mise a jour des valeurs d'une tablist
----------------------------------------------------------------------------
retour 		: void
--------------------------------------------------------------------------*/

void initAlist(expr,tab)
chain_list *expr;
Alist *tab;
{
   while ((expr = CDR(expr)) && tab)
   {
      tab->ptChain = copyExpr(CAR(expr));
      tab = CDR(tab);
   }
}

/*--------------------------------------------------------------------------
delAlist 	: mise a jour des valeurs d'une tablist
----------------------------------------------------------------------------
retour 		: void
--------------------------------------------------------------------------*/
Alist *delAlist(alist, name)
Alist *alist;
char *name;
{
if (!alist)
   return (Alist *)NULL;

if (name == alist->name)
   return alist->NEXT;
else
   {
   Alist *p1 = alist;
   Alist *p2 = alist->NEXT;

   while (p2 && (p2->name != name))
      {
      p2 = p2->NEXT;
      p1 = p1->NEXT;
      }
   if (p2 && (p2->name == name))
      {
      p1->NEXT = p2->NEXT;
      p2->NEXT = NULL;
      freeptype(p2);
      }
   return alist;
   }
}

/*------------------------------------------------------------------------
cassq 		: renvoie la valeur de l' entree (champ ptChain) 
-------------------------------------------------------------------------*/
char *cassq(ptTL,name)
Alist *ptTL;
char *name;

{
Alist *i;

for(i = ptTL;i;i = i->NEXT)
	if (i->name == name)
		return (char *)i->ptChain;
return (char *)NULL;
}

/*--------------------------------------------------------------------------
resetAlist 	: vide une liste associative de variables.
		  type = 1 expression, type = 0 (char *)
----------------------------------------------------------------------------
retour 		: void. 
--------------------------------------------------------------------------*/
void resetAlist(ptTL,type)
Alist *ptTL;
short type;
{
   do 
     if (ptTL->ptChain != NULL)
     {
     char *nom = ptTL->name;

       if (type == 1) freeExpr(ptTL->ptChain);
       if (type == 2 && nom[0] != '*') freeExpr(ptTL->ptChain);
       ptTL->ptChain = NULL;
     }
   while (ptTL = ptTL->NEXT);
}

/*--------------------------------------------------------------------------
freeAlist 	: detruit une liste associative de variables.
----------------------------------------------------------------------------
retour 		: void. 
--------------------------------------------------------------------------*/
freeAlist(ptTL)
Alist *ptTL;
{
Alist *aux;

   resetAlist(ptTL,1);
   while (aux = ptTL)
   {
      ptTL = CDR(ptTL);
      mbkfree((void *)aux);
   }
}

/*--------------------------------------------------------------------------
exprToCharRed  	: transforme un abl sur un niveau en chaine de caracteres 
----------------------------------------------------------------------------
retour 		: chaine de caracteres.
--------------------------------------------------------------------------*/

char *exprToCharRed(expr)
chain_list *expr;
{
static char chaine[BUFSIZE];
char *res;

   if (ATOM(expr))
      return VALUE_ATOM(expr);
   strcpy(chaine,searchCharOper(OPER(expr)));
   while (expr = CDR(expr))
   {
      strncat(chaine," ",1);
      strcat(chaine,VALUE_ATOM(CAR(expr)));
   }
   res = namealloc(chaine);
   return res;
}

/*--------------------------------------------------------------------------
displayRef     	: affiche le contenu de la reference
----------------------------------------------------------------------------
retour 		: void. 
--------------------------------------------------------------------------*/

void displayRef()
{
ptype_list *ref;
chain_list *elt;

printf("==> Reference\n");
for(ref = mappSys->ref;ref;ref = ref->NEXT)
	{
        printf("level %d : ",ref->TYPE);
	for(elt = CAR(ref);elt;elt = CDR(elt))
		printf("%s ",elt->DATA);
	printf("\n");
	}
}

/*--------------------------------------------------------------------------
createRef     	: creation d'un niveau de la reference
----------------------------------------------------------------------------
retour 		: void. 
--------------------------------------------------------------------------*/

void createRef(niv)
long niv;
{
   if (!(mappSys->ref) || ((mappSys->ref)->TYPE < niv))
      {
      mappSys->ref = addptype(mappSys->ref,niv,(void *)NULL);
      }
}

/*--------------------------------------------------------------------------
addRef     	: ajout d'une cellule virtuelle a un niveau
----------------------------------------------------------------------------
retour 		: void. 
--------------------------------------------------------------------------*/

void addRef(cell,niv)
char *cell;
long niv;
{
ptype_list *refCour = searchRefNiv(niv);

   if (!refCour)
      {
      createRef(niv);
      refCour = mappSys->ref;
      }
/*
printf("addRef :niv trouve %d, %s\n",niv,(refCour->DATA) ? "pas vide" : "vide");
printf("cellule : %s\n",cell);
*/
   if (!searchRefName(cell,niv))
      refCour->DATA = (void *)addchain(refCour->DATA,cell);
}

/*--------------------------------------------------------------------------
delRef     	: destruction d'une cellule virtuelle a un niveau
----------------------------------------------------------------------------
retour 		: void. 
--------------------------------------------------------------------------*/

void delRef(cell)
char *cell;
{
ptype_list *refCour;
 
   while (refCour = searchRef(cell))
   {
      chain_list *aux = searchRefName(cell,refCour->TYPE);
      refCour->DATA = (void *)delchain(refCour->DATA,aux);
   }
}

/*--------------------------------------------------------------------------
searchRefNiv  	: recherche d'un niveau de la reference
----------------------------------------------------------------------------
retour 		: pointeur sur le niveau.
--------------------------------------------------------------------------*/

ptype_list *searchRefNiv(niv)
long niv;
{
ptype_list *auxref = mappSys->ref;

   while (auxref)
      {
      if (auxref->TYPE == niv) 
         return auxref;
      else
         auxref = auxref->NEXT;
      }
   return NULL;
}

/*--------------------------------------------------------------------------
searchRefName 	: recherche d'un virtuel de la reference dans un niveau
----------------------------------------------------------------------------
retour 		: pointeur sur le name ou NULL.
--------------------------------------------------------------------------*/

chain_list *searchRefName(name,niv)
char *name;
long niv;
{
chain_list *virtCour = CAR(searchRefNiv(niv));

   while (virtCour)
   {
      if ((char *)virtCour->DATA == name) return virtCour;
      virtCour = CDR(virtCour);
   }
   return NULL;
}

/*--------------------------------------------------------------------------
searchRef     	: recherche d'un virtuel de la reference
----------------------------------------------------------------------------
retour 		: pointeur sur le niveau ou NULL.
--------------------------------------------------------------------------*/

ptype_list *searchRef(name)
char *name;
{
ptype_list *p = mappSys->ref;

   do
      if (searchRefName(name,p->TYPE))
         return p;
   while (p = CDR(p));
   return 0;
}

chain_list *expanse(abl)
chain_list *abl;
{
if (ATOM(abl))
   {
   if (VALUE_ATOM(abl) == nameUn ||
       VALUE_ATOM(abl) == nameZero) 
      return copyExpr(abl);
   else
      {
      virtuelList *virt = (virtuelList *)testObj(VALUE_ATOM(abl),'v');

      if (testObj(VALUE_ATOM(abl),'s'))
	   return copyExpr(abl);
      if (virt)
	return expanse(CAR(virt->solutions));
      printf("expanse : atome ni virtuel ni signal : %s\n",VALUE_ATOM(abl));
	   return createAtom("..?");
      }
   }
else
   {
   chain_list *args;
   chain_list *newExpr = createExpr(OPER(abl));

   for(args = CDR(abl);args;args = CDR(args))
	addQExpr(newExpr,expanse(CAR(args)));
   addArite(newExpr);
   return newExpr;
   }
}

void statistiques()
{
int i,j,surface = 0;
pElemTH pEl;
ptype_list *Crit,*RcCrit,*cheminReg,*RcReg;
FILE *fic,*fopen();
char *nom = (char *) mbkalloc(strlen(SL_BEH->NAME) +6);
cellList *cell;
declenList *decl;
int transistors = 0;

Crit = addptype((ptype_list *)NULL,(long)0,(void *)NULL);
RcCrit = addptype((ptype_list *)NULL,(long)0,(void *)NULL);
/*
cheminReg = addptype((ptype_list *)NULL,(long)0,(void *)NULL);
RcReg = addptype((ptype_list *)NULL,(long)0,(void *)NULL);
sprintf(nom,"%s%d.syn",SL_BEH->NAME,SL_OPTIM);
fic = fopen(nom,"w");*/
  for (j = 2;j<6;j++)
   for (i=0,pEl=mappSys->sig_hash->pElem;i<mappSys->sig_hash->length;i++,pEl++)
   {
      if ((pEl->value != VIDETH) && (pEl->value != DELETETH) &&
          (pEl->value != 1))
      {
      sig *sigAux = (sig *)pEl->value;

	if (sigAux->type == j)
	  {
	  virtuelList *virt = 
		   (virtuelList *)testObj(VALUE_ATOM(CAR(sigAux->ablList)),'v');

	  	/*fprintf(fic, "SIGNAL = %s ",pEl->key);*/
		if (sigAux->type == 5)
		{
		   if (virt && ((Crit->TYPE) < virt->delais))
		   {
		      Crit->TYPE = virt->delais;
		      Crit->DATA = (void *)pEl->key;
		   }
		   if (virt && ((RcCrit->TYPE) < virt->del_rc))
		   {
		      RcCrit->TYPE = virt->del_rc;
		      RcCrit->DATA = (void *)pEl->key;
		   }
		}
/*
		if (sigAux->type == 4)
		{
		   if (cheminReg->TYPE < sigAux->delais_in)
		   {
		      cheminReg->TYPE = sigAux->delais_in;
                      cheminReg->DATA = (void *)pEl->key;
		      RcReg->TYPE = virt->del_rc;
		      RcReg->DATA = (void *)pEl->key;
		   }
		}
		fprintf(fic,"\tCAPA : %d",sigAux->capa);
		if (virt) fprintf(fic,"\tDEL_RC : %d\n",virt->del_rc);
		else      fprintf(fic,"\n");*/
	  }
      }
      
   }
   for (i=0,pEl = mappSys->virt_hash->pElem;i<mappSys->virt_hash->length;
        i++,pEl++)
      if ((pEl->value != VIDETH) && (pEl->value != DELETETH))
      {
      virtuelList *virt = (virtuelList *)pEl->value;

	 if ((pEl->value != 1) && virt && (virt->op_log))
	 {
            surface += virt->op_log->surface;
	    transistors += searchGeneric(virt->op_log,virt->op_log->nom,"trans");
	 }
      }

    /*fprintf(fic,"\n\n\n\n\n");*/
   /*if (testObj(RcCrit->DATA,'v'))*/
    printf("\n\nCritical path Signal %s : %d (%s : %d)\n",
		RcCrit->DATA,RcCrit->TYPE,
		Crit->DATA,Crit->TYPE);
/*
    if (RcReg->TYPE)
       fprintf(fic,"\tCritical path Register or Bus %s : %d\n",
		   RcReg->DATA,cheminReg->TYPE);
    fprintf(fic,"\tCells generated        %d\n",mappSys->virt_hash->count);
    fprintf(fic,"\tGlobal area            %ld (%ld)\n",surface,surface*252);
    fprintf(fic,"\tTransistor pairs       %d\n\n\n",transistors);
    freeptype(RcCrit);
    freeptype(RcReg);
    i = 1;
    for (cell = mappSys->ptcell;cell;cell = CDR(cell))
    {
 	if (cell->util >0)
	{
	   fprintf(fic,"%s : %d",cell->nom,cell->util);
	   i++;
	   if (i < 6)
	      fprintf(fic,"\t");
	   else
	   {
	      fprintf(fic,"\n");i = 1;
	   }
	}
    }
    fprintf(fic,"\n");
   decl = mappSys->ptdecl;
   while (decl) 
   {
   regle_list *reg = decl->regles;
   while (reg)
   {
      printf("%d ",reg->util);
      reg = CDR(reg);
   }
   printf("\n");
   decl = decl->NEXT; 
   }
    fclose(fic);
    PRINTF("file %s generated\n",nom);
*/
#if MACHINE != pc
   mbkfree(nom);
#endif
}

chain_list *changeExpr(interf,exp,sortie)
chain_list *interf,*exp,*sortie;
{
if (ATOM(sortie))
	{
	chain_list *i,*e;

	for(i = CDR(interf),e = CDR(exp);i;i = CDR(i),e = CDR(e))
		if (VALUE_ATOM(CAR(i)) == VALUE_ATOM(sortie))
			return CAR(e);
	printf("changeExpr : ERREUR sur les entrees de l'interface\n");
	return NULL;
	}
else
	{
	int oper = OPER(sortie);
	chain_list *res = createExpr(oper),*args;

	for(args = CDR(sortie);args;args = CDR(args))
		addQExpr(res,changeExpr(interf,exp,CAR(args)));
	return res;
	}
}

/*--------------------------------------------------------------------------
createAux  	 : Creation recursive de variables auxilliaires
----------------------------------------------------------------------------
retour 		: void
--------------------------------------------------------------------------*/

void createAux(nom,ptVirt,type)
char *nom;
virtuelList *ptVirt;
char type;
{
chain_list *args, *abl = CAR(ptVirt->solutions);

/* traitement atomique ajoute le 30/07/93 */
   if (ATOM(abl) && !testObj(VALUE_ATOM(abl),'s'))
   {
    createAux(VALUE_ATOM(abl),(virtuelList *)testObj(VALUE_ATOM(abl),'v'),type);
   }
   for(args= CDR(abl);args;args = CDR(args))
   {
   char *name = VALUE_ATOM(CAR(args));
   sig *sigAux = (sig *)testObj(name,'s');

	  if ((!sigAux) && (searchTH(sigBeh,name) != 1))
	  {
	     virtuelList *virtFils = (virtuelList *)testObj(name,'v');

	     if (virtFils) createAux(name,virtFils,'l');
	     else
	     {
	     char *highLow;

		if (name == nameZero)
	     	{
		   highLow = namealloc("ic_0");
	  	   args->DATA = (void *)createATOM(highLow);
		   if (!testObj(highLow,'v'))
		   {
		      addTH(mappSys->virt_hash,highLow,1);
		      SL_BEH->BEAUX =
			 beh_addbeaux(SL_BEH->BEAUX,highLow,createATOM(nameLow),NULL);
		   }
	        }
	        if (name == nameUn)
	     	{
		   highLow = namealloc("ic_1");
	  	   args->DATA = (void *)createATOM(highLow);
		   if (!testObj(highLow,'v'))
		   {
		      addTH(mappSys->virt_hash,highLow,1);
		      SL_BEH->BEAUX =
			 beh_addbeaux(SL_BEH->BEAUX,highLow,createATOM(nameHigh),NULL);
		   }
	        }
	     }
	  }
   }

   if ((searchTH(sigBeh,nom)== VIDETH) || (searchTH(sigBeh,nom)== DELETETH))
   {
   if (!testObj(nom,'s') && (type != 'b'))
      {
      	   addTH(sigBeh,nom,1);
      	   SL_BEH->BEAUX = beh_addbeaux(SL_BEH->BEAUX,nom,abl,NULL);
      }
   }
}

void newBefig()
{
beout_list *o;
beaux_list *a;
bereg_list *r;
bebus_list *b;
bebux_list *u;
berin_list *i;

sigBeh = createTH(1000);

/*
for(i = SL_BEH->BERIN;i;i = CDR(i))
{
sig *sigIn = (sig *)testObj(i->NAME,'s');

   if (sigIn->capa > 1000)
   {
   char *newVirt1 = (char *)gensym("bufsc",cptVirtuel++);
   char *newVirt2 = (char *)gensym("bufsc",cptVirtuel++);
   chain_list *newAbl = notExpr(createAtom(i->NAME));

	printf("\n%s - %d : ",i->NAME,sigIn->capa);
	addArite(newAbl);
	SL_BEH->BEAUX = beh_addbeaux(SL_BEH->BEAUX,newVirt1,newAbl,NULL);
	newAbl = notExpr(createAtom(newVirt1));
	addArite(newAbl);
	SL_BEH->BEAUX = beh_addbeaux(SL_BEH->BEAUX,newVirt2,newAbl,NULL);
	for (newAbl=sigIn->util;newAbl;newAbl=CDR(newAbl))
	{
	virtuelList *virt = (virtuelList *)testObj((char *)newAbl->DATA,'v');
	  if (virt)
	   substPhyExpr(CAR(virt->solutions),i->NAME,createAtom(newVirt2));
	}
	freechain(sigIn->util);
	sigIn->util = addchain(NULL,(void *)newVirt1);
    	printf("Two inverters added");
   }
}
*/
   for(a = SL_BEH->BEAUX;a;a = a->NEXT)
      if (!(a->ABL))
      {
	virtuelList *virt = (virtuelList *)testObj(a->NAME,'v');
	char *nameVirt;

	if (!virt)
	{
	   sig *sigAux = (sig *)testObj(a->NAME,'s');

			/* cas des bus (nom virtuel <> nom signal) */
	   if (sigAux)
	      {
	      nameVirt = VALUE_ATOM(CAR(sigAux->ablList));
	      virt = (virtuelList *)testObj(nameVirt,'v');
	      }
	}
	else nameVirt = a->NAME;

	if (virt)
	{
	   	createAux(nameVirt,virt,'l');
	   	a->ABL = copyExpr(CAR(virt->solutions));
	}
	else 
	{
		printf("\nthe signal %s is never referenced\n",a->NAME);
		printf("Mapping aborted\n");
		exit(-1);
	}
      }
   	else
   	{
           if (VALUE_ATOM(a->ABL) == nameZero)
           {
	      freeExpr(a->ABL);
	      a->ABL = createATOM(nameLow);
	   }
           if (VALUE_ATOM(a->ABL) == nameUn)
           {
	      freeExpr(a->ABL);
	      a->ABL = createATOM(nameHigh);
	   }
	}
for(o = SL_BEH->BEOUT;o;o = CDR(o))
	if (!(o->ABL))
	{
	sig *sigAux = (sig *)testObj(o->NAME,'s');
	char *nameVirt = VALUE_ATOM(CAR(sigAux->ablList));
	virtuelList *virt = (virtuelList *)testObj(nameVirt,'v');

	if (virt)
	  {
	  createAux(nameVirt,virt,'l');
	  o->ABL = copyExpr(CAR(virt->solutions));
	  }
	}
   	else
   	{
	sig *sigAux = (sig *)testObj(o->NAME,'s');
	char *nameVirt = VALUE_ATOM(CAR(sigAux->ablList));
	sig *sigIn = (sig *)testObj(nameVirt,'s');

           if (VALUE_ATOM(o->ABL) == nameZero)
           {
	      freeExpr(o->ABL);
	      o->ABL = createATOM(nameLow);
	   }
           if (VALUE_ATOM(o->ABL) == nameUn)
           {
	      freeExpr(o->ABL);
	      o->ABL = createATOM(nameHigh);
	   }
	  if (sigIn)
	  {
	  int s2aux = 0;
	  chain_list *s2a;
	  sig *sigOut;

	     for (s2a=sigIn->util;s2a;s2a=CDR(s2a))
	     {
	        sigOut = (sig *)testObj((char *)s2a->DATA,'s');
	        
		if (sigOut && sigOut->type == 5 &&
		   !testObj((char *)s2a->DATA,'v')) s2aux++;
	     }
/* cas de la sortie connectee a l'entree */
/* cas de deux connecteurs de sortie connectes a un aux */
	  if (sigIn->type == 1 || s2aux > 1)
	  {
	  chain_list *s2a,*newAbl = CAR(sigAux->ablList);
	  char *newVirt = (char *)gensym("auxsc",cptVirtuel++);

	  if (s2aux < 2)
	    PRINTF("\noutput %s connected to input %s : 2 inverters added",o->NAME,nameVirt);
	  else
	    PRINTF("\n2 outputs connected to %s : 2 inverters added for %s",nameVirt,o->NAME);
	    newAbl = notExpr(newAbl);
	    addArite(newAbl);
	    SL_BEH->BEAUX = beh_addbeaux(SL_BEH->BEAUX,newVirt,newAbl,NULL);
	    newAbl = createAtom(newVirt);
	    o->ABL = notExpr(newAbl);
	    addArite(o->ABL);
	    s2a=sigIn->util;
            while ((char *)s2a->DATA != o->NAME) s2a=CDR(s2a);
	    sigIn->util = delchain(sigIn->util,s2a);
	  }
	  }
        }
for(r = SL_BEH->BEREG;r;r = CDR(r))
	{
	sig *sigAux = (sig *)testObj(r->NAME,'s');
	char *nameVirt = VALUE_ATOM(CAR(sigAux->ablList));
	virtuelList *virt = (virtuelList *)testObj(nameVirt,'v');

	if (virt)
	  {
	  createAux(nameVirt,virt,'r');
	  r->BIABL->VALABL = copyExpr(CAR(virt->solutions));
	  }
	}

for(b = SL_BEH->BEBUS;b;b = CDR(b))
	{
	sig *sigAux = (sig *)testObj(b->NAME,'s');
	chain_list *bus;
	biabl_list *beh;

	for(bus = sigAux->ablList,beh = b->BIABL;bus;bus = CDR(bus),beh = CDR(beh))
	   {
	   char *nameVirt = VALUE_ATOM(CAR(bus));
	   virtuelList *virt = (virtuelList *)testObj(nameVirt,'v');

printf("%s\n",nameVirt);
	   createAux(nameVirt,virt,'b');
	   beh->VALABL = copyExpr(CAR(virt->solutions));
	   }
	}

for(u = SL_BEH->BEBUX;u;u = CDR(u))
	{
	sig *sigAux = (sig *)testObj(u->NAME,'s');
	chain_list *bux;
	biabl_list *beh;

	for(bux = sigAux->ablList,beh = u->BIABL;bux;bux = CDR(bux),beh = CDR(beh))
	   {
	   char *nameVirt = VALUE_ATOM(CAR(bux));
	   virtuelList *virt = (virtuelList *)testObj(nameVirt,'v');

	   createAux(nameVirt,virt,'b');
	   beh->VALABL = copyExpr(CAR(virt->solutions));
	   }
	}

destroyTH(sigBeh);
}

void changeAblBeh()
{
beout_list *o;
beaux_list *a;
bereg_list *r;
bebus_list *b;
bebux_list *u;
cellList *cell;

   for(o = SL_BEH->BEOUT;o;o = o->NEXT)
   {
      if (!ATOM(o->ABL))
      {
         cell = operToCell(o->ABL);
         initAlist(o->ABL,cell->entrees);
	 freeExpr(o->ABL);
         o->ABL = remplace(cell->val_abl->VALABL,cell->entrees);
	 resetAlist(cell->entrees,1);
      }
      else
      {
       	if (VALUE_ATOM(o->ABL) == nameHigh)
       	{
	  freeExpr(o->ABL);
	  o->ABL = createATOM(nameUn);
	}
       else
        if (VALUE_ATOM(o->ABL) == nameLow)
	{	
	  freeExpr(o->ABL);
	  o->ABL = createATOM(nameZero);
	}
      }
   }
   for(a = SL_BEH->BEAUX;a;a = a->NEXT)
   {
      if (!ATOM(a->ABL))
      {
         cell = operToCell(a->ABL);
         initAlist(a->ABL,cell->entrees);
	 freeExpr(a->ABL);
         a->ABL =remplace(cell->val_abl->VALABL,cell->entrees);
      }
      else
      {
       if (VALUE_ATOM(a->ABL) == nameHigh)
	{
	  freeExpr(a->ABL);
	  a->ABL = createATOM(nameUn);
	}
       else
        if (VALUE_ATOM(a->ABL) == nameLow)
	{
	  freeExpr(a->ABL);
	  a->ABL = createATOM(nameZero);
	}
      }
   }

   for(b = SL_BEH->BEBUS;b;b = b->NEXT)
   {
   biabl_list *listeabl;

      for(listeabl = b->BIABL;listeabl;listeabl = CDR(listeabl))
      {
      chain_list *abl = listeabl->VALABL;

         cell = operToCell(abl);
         initAlist(abl,cell->entrees);
	 freeExpr(abl);
	 listeabl->VALABL = remplace(cell->val_abl->VALABL,cell->entrees);
	 listeabl->CNDABL = remplace(cell->val_abl->CNDABL,cell->entrees);
	 resetAlist(cell->entrees,1);
      }
   }

   for(u = SL_BEH->BEBUX;u;u = u->NEXT)
   {
   biabl_list *listeabl;

      for(listeabl = u->BIABL;listeabl;listeabl = CDR(listeabl))
      {
      chain_list *abl = listeabl->VALABL;

         cell = operToCell(abl);
         initAlist(abl,cell->entrees);
	 freeExpr(abl);
	 listeabl->VALABL = remplace(cell->val_abl->VALABL,cell->entrees);
	 listeabl->CNDABL = remplace(cell->val_abl->CNDABL,cell->entrees);
	 resetAlist(cell->entrees,1);
      }
   }

   for(r = SL_BEH->BEREG;r;r = r->NEXT)
   {
   chain_list *abl = r->BIABL->VALABL;
   biabl_list *bi,*c;

      cell = operToCell(abl);
      initAlist(abl,cell->entrees);
      freeExpr(abl);
      for(bi = r->BIABL,c = cell->val_abl;bi;bi = CDR(bi),c = CDR(c))
      {
         if (ATOM(c->VALABL) &&
             (VALUE_ATOM(c->VALABL) == nameUn ||
              VALUE_ATOM(c->VALABL) == nameZero))
            bi->VALABL = c-> VALABL;
         else
            bi->VALABL = remplace(c->VALABL,cell->entrees);
         bi->CNDABL = remplace(c->CNDABL,cell->entrees);
      }
      resetAlist(cell->entrees,1);
   }
}

/*------------------------------------------------------------------
  FUNCTION : trie les arguments d'une expression a partir d'une fonction
  	     func1 renvoyant un int.
	     Si deux arguments sont egaux on les departage avec func2
            direction = 1 croissant direction = 0 decroissant 
  ------------------------------------------------------------------ */

void sort2Expr(expr,func1,func2,dir1,dir2)
chain_list *expr;
int (*func1)(),(*func2)();
int dir1,dir2;
{
chain_list *expr1;
int okPermu = 1;

   if (!ATOM(expr))                /* ce n'est pas un atome */
   {
      while (okPermu)
      {
         expr1 = CDR(expr);
         okPermu = 0;
         while (CDR(expr1))
         {
	 int r1 = (*func1) CAR(expr1);
	 int r2 = (*func1) CADR(expr1);


          if ((dir1 == 1 && r1 > r2) || (dir1 == 0 && r1 < r2) ||
              (r1 == r2 && 
	     ((dir2 == 1 && (*func2) CAR(expr1) > (*func2) CADR(expr1)) ||
              (dir2 == 0 && (*func2) CAR(expr1) < (*func2) CADR(expr1)))))
            {
            chain_list *permu;

               permu = CAR(expr1);
               expr1->DATA = (void *)CADR(expr1);
               (expr1->NEXT)->DATA = (void *)permu;
               okPermu = 1;
            }
            expr1 = CDR(expr1);
         }
      }   
   }   
}

/*------------------------------------------------------------------
  IDENT : funcNorm2
  ------------------------------------------------------------------
  FUNCTION : normalise une expression a tous les niveaux
		variable = pointeur d'allocation
		expression = numero d'operateur. 
             ex : (and a (xor w g) b (or x f) (or e g o) (xor t h k))
                --> (and (or x f) (or e o g) (xor g w) (xor t h k) b a)
  ------------------------------------------------------------------ */

int funcNorm2(expr)
chain_list *expr;
{
if (ATOM(expr))
   return ((int) VALUE_ATOM(expr));
else
   if (OPER(expr) == NOT)
      if (ATOM(CADR(expr)))
         return(NOT*1000 + (int) VALUE_ATOM(CADR(expr)));
      else
         return(NOT*1000 + OPER(CADR(expr)));
   return(OPER(expr)*1000 + lengthExpr(expr));
}

