/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit : Synthetiseur logique                                        */
/*    Fichier : regles.c                                                    */
/*                                                                          */
/*    (c) copyright 1991 Laboratoire MASI equipe CAO & VLSI                 */
/*    Tous droits reserves                                                  */
/*    Support : e-mail cao-vlsi@masi.ibp.fr                                 */
/*                                                                          */
/*    Auteur(s) :   DICTUS N.                           le : 14/08/1991     */
/*                                                                          */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*                                                                          */
/****************************************************************************/
#include <stdio.h>
#include MUT_H
#include LOG_H
#include BEH_H
#include "types.h"
#include "../compil/lax_param.h"
#include "../synthe/sl_type.h"
#include "regles.h"
#include "mapper.h"
#include "cout.h"
#include "oper.h"
#include "display.h"
int nbre=0;

/****************************************************************************/
/****************************************************************************/
/********* simple : test si c'est une cellule NAND, AND, OR ou NOR **********/
/****************************************************************************/
short simple(exp)
chain_list *exp;

{
chain_list *args;
int atom;

if (ATOM(exp)) return 1;
if (OPER(exp) == NOT) return simple(CADR(exp));
if ( (OPER(exp) != AND) && (OPER(exp) != NAND) && (OPER(exp) != OR) && (OPER(exp) != NOR) ) return 0;
   atom = 0;
   for(args = CDR(exp);args;args = args->NEXT) if (ATOM(CAR(args))) atom++;
   if (atom == lengthExpr(exp)) return 1;
   atom = 0;
   for(args = CDR(exp);args;args = args->NEXT) 
      if (!ATOM(CAR(args)) && OPER(CAR(args)) == NOT && ATOM(CADR(CAR(args)))) atom++;
   if (atom == lengthExpr(exp)) return 1;
return 0;
}

/****************************************************************************/
/********* simpleInverse : test si c'est une cellule NAND ou NOR ************/
/****************************************************************************/
short simpleInverse(exp)
chain_list *exp;

{
chain_list *args;

if (!simple(exp)) return 0;
if (OPER(exp) == NOT) return simpleInverse(CADR(exp));
for(args = CDR(exp);args;args = args->NEXT)
	if (profExpr(CAR(args)) != 1) return 0;
return 1;
}

/****************************************************************************/
/****** cellOpose : renvoie la cellule duale de la bibliotheque ou NULL *****/
/****************************************************************************/
char *cellOpose(nom)
char *nom;

{
char *nomOposeAux,*nomOpose;
unsigned int len = strlen(nom)+2;

   if (nom[0] == 'n')
   {
	nomOposeAux = nom+1;
	nomOpose = namealloc(nomOposeAux);
   }
   else
   {
   nomOposeAux = (char *)mbkalloc(len);

	sprintf(nomOposeAux,"n%s",nom);
	nomOpose = namealloc(nomOposeAux);
#if MACHINE != pc
   mbkfree(nomOposeAux);		/* PC... */
#endif
   }
   if (testObj(nomOpose,'c')) return nomOpose;
   return (char *)NULL;
}

/****************************************************************************/
/************ cellXor : test si c'est une cellule XOR ou NXOR ***************/
/****************************************************************************/
short cellXor(cell)
cellList *cell;

{
char *car = (char *)mbkalloc((unsigned) 6);
short retour;

if (cell->nomlog[0] == 'n')
  {
  strncpy(car,cell->nomlog,4);
  retour = !strncmp(car,"nxor",4);
  }
  else
  {
  (void *)strncpy(car,cell->nomlog,3);
  retour = !strncmp(car,"xor",3);
  }
  mbkfree(car);
return retour;
}

/******************************************************************************/
/***** invOper : renvoie l'operateur inverse **********************************/
/******************************************************************************/
short invOper(oper)
short oper;

{
char *cellOp;

if (oper == AND) return NAND;
if (oper == NAND) return AND;
if (oper == NOR) return OR;
if (oper == OR) return NOR;
if (oper == XOR) return NXOR;
if (oper == NXOR) return XOR;
if (cellOp = cellOpose(searchCharOper(oper))) return searchNumOper(cellOp);
return -1;
}

/******************************************************************************/
/***** morgOper : renvoie l'operateur trouve par application de Morgan ********/
/******************************************************************************/
short morgOper(oper)
short oper;

{
if (oper == AND) return NOR;
else
if (oper == NAND) return OR;
else
if (oper == NOR) return AND;
else
if (oper == OR) return NAND;
else return NULL;
}

/******************************************************************************/
/***** moinsNot : simplifie les NOT au premier niveau *************************/
/******************************************************************************/
chain_list *moinsNot(exp)
chain_list *exp;

{
if (ATOM(exp)) return copyExpr(exp);
if (OPER(exp) == NOT)
	{
	chain_list *arg,*exprInv,*a;

	arg = CADR(exp);
	if (ATOM(arg)) return copyExpr(exp);
	if (OPER(arg) == NOT) return copyExpr(CADR(arg));
	exprInv = createExpr(invOper(OPER(arg)));
	for(a=CDR(arg);a;a=CDR(a))
		addQExpr(exprInv,copyExpr(CAR(a)));
	return exprInv;
	}
return copyExpr(exp);
}

/******************************************************************************/
/* numberOcVarExpr : retourne le nbre d'occurrences d'une variable dans un ABL*/
/******************************************************************************/
int numberOcVarExpr(exp,name)
chain_list *exp;
char *name;

{
if (ATOM(exp))
   {
   if (name == VALUE_ATOM(exp))
	return 1;
   else
        return 0;
   }
else
   {
   int cpt = 0;
   chain_list *args;

   for(args = CDR(exp);args;args = CDR(args))
	cpt += numberOcVarExpr(CAR(args),name);
   return cpt;
   }
}

/******************************************************************************/
/***** simplifNot : simplifie les NOT a tous les niveaux **********************/
/******************************************************************************/
chain_list *simplifNot(exp)
chain_list *exp;

{
if (ATOM(exp)) return copyExpr(exp);
if (OPER(exp) == NOT)
	{
	chain_list *arg,*exprInv,*a;

	arg = CADR(exp);
	if (ATOM(arg)) return copyExpr(exp);
	if (OPER(arg) == NOT) return simplifNot(CADR(arg));
	exprInv = createExpr(invOper(OPER(arg)));
	for(a=CDR(arg);a;a=CDR(a))
		addQExpr(exprInv,simplifNot(CAR(a)));
	return exprInv;
	}
else
	{
	chain_list *expr,*a;

	expr = createExpr(OPER(exp));
	for(a=CDR(exp);a;a=CDR(a))
		addQExpr(expr,simplifNot(CAR(a)));
	return expr;
	}
}

/******************************************************************************/
/** appendChain_list : fait un append entre les deux listes l1 et l2, retourne l1 ***/
/******************************************************************************/
chain_list *appendChain_list(l1,l2)
chain_list *l1,*l2;

{
chain_list *a;

if (!l1) return l2;
if (!l2) return l1;
for(a = l1;a->NEXT;a = a->NEXT)
	;
a->NEXT = l2;
return l1;
}

/******************************************************************************/
/*** combin : retourne toutes les combinaisons entre des listes d'arguments ***/
/******************************************************************************/
chain_list *combin(list)
chain_list *list;

{
if (list->NEXT == NULL)
	{
	chain_list *maillonHead = NULL,*a;
	
	for(a = CAR(list);a;a = a->NEXT)
	{
	   chain_list *maillonData = createATOM(copyExpr(CAR(a)));
	   maillonHead = addchain(maillonHead,(void *)maillonData);
	}
	return maillonHead; 
	}
if (list->DATA == NULL)
	return (chain_list *)NULL;
else
	{
	chain_list *combi1,*combi2,*combi3,*prem,*a;

	combi1 = combin(list->NEXT);
	prem = CAR(list);
	for(a = combi1;a;a = a->NEXT)
	      a->DATA = (void *)addchain(CAR(a), (void *)copyExpr(CAR(prem)));
	combi2 = addchain(list->NEXT,(void *)(CAR(list)->NEXT));
	combi3 = combin(combi2);
	return appendChain_list(combi1,combi3);
	}
}

/******************************************************************************/
/** solutions : retourne toutes les combinaisons entre des listes d'arguments */
/******************************************************************************/
chain_list *solutions(exp,signe,op)
chain_list *exp;
short signe;
short op;

{
chain_list *headArg = NULL,*arg,*sols = NULL;

for(arg = CDR(exp);arg;arg = CDR(arg))
	if (signe)
	  headArg = addchain(headArg,(void *)fct(CAR(arg)));
	else
	  {
	  chain_list *aux = inversArg(CAR(arg));
	  chain_list *aux2 = simplifNot(aux);

	  headArg = addchain(headArg,(void *)fct(aux2));
	  freeExpr(aux2);
	  freeExpr(aux);
	  }
for(arg = combin(headArg);arg;arg = arg->NEXT)
	{
	chain_list *a;
	chain_list *DATA = createExpr(op); 

	for(a = CAR(arg);a;a = a->NEXT)
	   addQExpr(DATA,(chain_list *)a->DATA);
	sols = addchain(sols,(void *)DATA);
	}
return sols;
}

/******************************************************************************/
/*** fct : retourne toutes les premisses obtenues par Morgan ******************/
/******************************************************************************/
chain_list *fct(exp)
chain_list *exp;

{
if (nivNot(exp) == 0)
	return createATOM(copyExpr(exp));
else
	return  appendChain_list(solutions(exp,1,OPER(exp)),solutions(exp,0,morgOper(OPER(exp))));
}

/******************************************************************************/
/*** findEqual : cherche si abl apparait dans liste ***************************/
/******************************************************************************/
short findEqual(abl,liste)
chain_list *abl,*liste;

{
chain_list *l;

if (!liste) return 0;
for(l = liste;l;l = l->NEXT)
	if (equalVarExpr(abl,CAR(l))) return 1;
return 0;
}

/******************************************************************************/
/**** triCommut : elimine les premisses redondantes  **************************/
/******************************************************************************/
chain_list *triCommut(liste)
chain_list *liste;

{
chain_list *l,*listeNormExpr = NULL;

for(l = liste;l; l = l->NEXT)
   if (lengthExpr(supportChain_listExpr(CAR(l)))+1 == numberAtomExpr(CAR(l)))
	 normExpr(CAR(l));
if (!liste->NEXT) return liste;
for(l = liste;l; l = l->NEXT)
	if (!findEqual(CAR(l),l->NEXT))
		listeNormExpr = addchain(listeNormExpr,(void *)CAR(l));
	else freeExpr(CAR(l));
return listeNormExpr;
}

/******************************************************************************/
/********* consExpr : construit une expression avec un op et des entrees ******/
/******************************************************************************/
chain_list *consExpr(oper,e)
int oper;
Alist *e;

{
chain_list *exp;
Alist *in;

if (oper == -1)
   printf("consExpr : oper = -1\n");
exp = createExpr(oper);
for(in = e;in;in = in->NEXT)
	addQExpr(exp,createATOM(in->name));
return exp;
}

/******************************************************************************/
/********* regOpposee : regle correspondant a la cellule opposee **************/
/******************************************************************************/
chain_list *regOpposee(cell)
cellList *cell;

{
chain_list *regleOp;

if (cellXor(cell))
   if (cell->nomlog[0] == 'n')
	{
	chain_list *aux = consExpr(XOR,cell->entrees);

	regleOp = addchain(consExpr(searchNumOper(cell->nomlog),cell->entrees),
			   (void *)inversArg(aux));
	freeExpr(aux);
	}
   else
	{
	chain_list *aux = consExpr(searchNumOper(cellOpose(cell->nomlog)),cell->entrees);

	regleOp = addchain(consExpr(XOR,cell->entrees),(void *)inversArg(aux));
	freeExpr(aux);
	}
else
   {
   chain_list *aux = consExpr(invOper(fonc(cell)),cell->entrees);

   regleOp = addchain(consExpr(fonc(cell),cell->entrees),
		      (void *)inversArg(aux));
   freeExpr(aux);
   }
return regleOp;
}

/******************************************************************************/
/********************* opposees : regles opposees a la liste ******************/
/******************************************************************************/
chain_list *opposees(liste)
chain_list *liste;

{
chain_list *r,*head = NULL;

for(r = liste;r;r = r->NEXT)
	{
	chain_list *prem = CAR(CAR(r)),*conc = CDR(CAR(r));
	chain_list *aux = inversArg(prem);
	chain_list *expr = addchain(conc,(void *)prem);
	chain_list *exprOp = addchain(inversArg(conc),(void *)simplifNot(aux));

	freeExpr(aux);
	head = addchain(addchain(head,(void *)exprOp),(void *)expr);
	}
return head;
}

/******************************************************************************/
/************** conclu : liste de couples premisse-conclusion *****************/
/******************************************************************************/
chain_list *conclu(prems,conc)
chain_list *prems,*conc;

{
chain_list *p,*head = NULL;

for(p = prems;p;p = p->NEXT)
	{
	chain_list *couple;

	if (equalVarExpr(CAR(p),conc)) 
	   freeExpr(CAR(p));
	else
 	   {
	   couple = addchain(conc,p->DATA);
	   head = addchain(head,(void *)couple);
	   }
	}
return head;
}

/******************************************************************************/
/************** acons : donne une valeur a une entree (champ ptChain) ********/
/******************************************************************************/
void acons(aListe,in,var)
Alist *aListe;
char *in,*var;

{
Alist *i;

for(i = aListe;i;i = i->NEXT)
	if (!strcmp(i->name,in))
		i->ptChain = (chain_list *)var;
}

/******************************************************************************/
/*********** cassqVal : renvoie l' entree de la valeur ************************/
/******************************************************************************/
char *cassqVal(aListe,val)
Alist *aListe;
char *val;

{
Alist *i;

for(i = aListe;i;i = i->NEXT)
	{
	if (!i->ptChain) continue;
	if (strcmp((char *)i->ptChain,val) == 0)
		return i->name;
	}
return (char *)NULL;
}

/******************************************************************************/
/************** alistEntrees : marque les entrees qui sont inversees **********/
/******************************************************************************/
void alistEntrees(premisse,entrees)
chain_list *premisse;
Alist *entrees;

{
if (ATOM(premisse))
	{
	char *res;

	if (! (res = cassq(entrees,VALUE_ATOM(premisse))) )
		acons(entrees,VALUE_ATOM(premisse),"p");
	else
		if (strcmp(res,"n") == 0)
		   acons(entrees,VALUE_ATOM(premisse),"d");
	}
else if (OPER(premisse) != NOT)
	{
	chain_list *arg;

	for(arg = CDR(premisse);arg;arg = arg->NEXT)
		alistEntrees(CAR(arg),entrees);
	}
     else if (ATOM(CADR(premisse)))
		{
		char *res;

		if (! (res = cassq(entrees,VALUE_ATOM(CADR(premisse)))) )
			acons(entrees,VALUE_ATOM(CADR(premisse)),"n");
		else if (strcmp(res,"p") == 0)
			acons(entrees,VALUE_ATOM(CADR(premisse)),"d");
		}
	  else alistEntrees(CADR(premisse),entrees);
}

/******************************************************************************/
/************** readAlist : lecture d'une alist *******************************/
/******************************************************************************/
void readAlist(in)
Alist *in;

{
Alist *i;

printf("    ");
for(i = in;i;i = i->NEXT)
	printf(" %s = %s,",i->name,(char *)i->ptChain);
printf("\n");
}

/******************************************************************************/
/************** alistPrem : supprime les inverseurs de la premisse ************/
/******************************************************************************/
chain_list *alistPrem(premisse,entrees)
chain_list *premisse;
Alist *entrees;

{
if (ATOM(premisse))
	return copyExpr(premisse);
else if (OPER(premisse) != NOT)
	{
	chain_list *arg,*expr = createExpr(OPER(premisse));

	for(arg = CDR(premisse);arg;arg = arg->NEXT)
		addQExpr(expr,alistPrem(CAR(arg),entrees));
	return expr;
	}
     else if (ATOM(CADR(premisse)))
		{
		if (strcmp(cassq(entrees,VALUE_ATOM(CADR(premisse))),"n") == 0)
			return copyExpr(CADR(premisse));
		else return copyExpr(premisse);
		}
	  else
		{
		chain_list *expr = createExpr(NOT);

		addHExpr(expr,alistPrem(CADR(premisse),entrees));
		return expr;
		}
}

/******************************************************************************/
/************** alistConc : ajoute les inverseurs dans la conclusion **********/
/******************************************************************************/
chain_list *alistConc(conc,entrees)
chain_list *conc;
Alist *entrees;

{
if (ATOM(conc))
	{
	if (!cassq(entrees,VALUE_ATOM(conc)))
	   return createAtom(entrees->name);
	if (strcmp(cassq(entrees,VALUE_ATOM(conc)),"n") == 0)
		return inversArg(conc);
	return copyExpr(conc);
	}
else if (OPER(conc) != NOT)
	{
	chain_list *arg,*expr = createExpr(OPER(conc));

	for(arg = CDR(conc);arg;arg = arg->NEXT)
		addQExpr(expr,alistConc(CAR(arg),entrees));
	return expr;
	}
     else if (ATOM(CADR(conc)))
		{
		if (strcmp(cassq(entrees,VALUE_ATOM(CADR(conc))),"n") == 0)
			return copyExpr(CADR(conc));
		else return  copyExpr(conc);
		}
	  else
		{
		chain_list *expr = createExpr(NOT);
		
		addHExpr(expr,alistConc(CADR(conc),entrees));
		return expr;
		}
}

/******************************************************************************/
/***** reportNot : reporte les inverseurs de la premisse vers la conclusion ***/
/******************************************************************************/
void reportNot(liste,cell)
chain_list *liste;
cellList *cell;

{
chain_list *l;

for(l = liste;l;l = l->NEXT)
	{
	chain_list *aux;

nbre++;
	if ((OPER(CAR(CAR(l))) == NOT) && (profExpr(CAR(CAR(l))) < 2))
	   continue;
	resetAlist(cell->entrees,0);
	alistEntrees(CAR(CAR(l)),cell->entrees);
	aux = CAR(CAR(l));
	CAR(l)->DATA = (void *)alistPrem(CAR(CAR(l)),cell->entrees);
	CAR(l)->NEXT = alistConc(CDR(CAR(l)),cell->entrees);
	freeExpr(aux);
	}
}

/******************************************************************************/
/***** reglesXor : construit les regles specifiques aux XOR et NXOR **********/
/******************************************************************************/
chain_list *reglesXor(cell)
cellList *cell;

{
chain_list *in,*prem,*conc;

if (fonc(cell) == XOR)
   {
   prem = consExpr(XOR,cell->entrees);
   conc = copyExpr(prem);
   for(in = CDR(conc);in;in = in->NEXT)
	{
	chain_list *aux = CAR(in);

	in->DATA = (void *)inversArg(CAR(in));
	freeExpr(aux);
	}
   }
else
   {
   chain_list *aux;

   prem = consExpr(XOR,cell->entrees);
   aux = CAR(CDR(prem));
   prem->NEXT->DATA = (void *)inversArg(CAR(CDR(prem)));
   freeExpr(aux);
   conc = consExpr(searchNumOper(cell->nomlog),cell->entrees); 
   }

return createATOM(addchain(conc,(void *)prem));
}

/******************************************************************************/
/***** reglesCellLogique : construit les regles des cellules logiques *********/
/******************************************************************************/
chain_list *reglesCellLogique(cell)
cellList *cell;

{
if (cell->nomlog == nameNot1)
	{
	chain_list *aux = consExpr(NOT,cell->entrees);
	chain_list *reg = addchain(createATOM(cell->entrees->name),
				   (void *)inversArg(aux));

	freeExpr(aux);

	return createATOM(reg);
	}
if (cellXor(cell)) 
	{
	chain_list *deb = NULL;

	deb = reglesXor(cell);
	if (cellOpose(cell->nomlog))
	    deb = addchain(deb,(void *)regOpposee(cell));
	return deb;
	}
if (simple(cell->val_abl->VALABL))
	{
	chain_list *simplifXon = simplifNot(cell->val_abl->VALABL);
	chain_list *suite;
	char *cellOp;

	suite = conclu(triCommut(fct(simplifXon)),consExpr(fonc(cell),cell->entrees));
	if (cellOp = cellOpose(cell->nomlog))
		suite = addchain(suite,(void *)regOpposee(cell));
	else suite = opposees(suite);
	if ((!cellOp) && testOperVHDL(cell))
		regleOperVHDL(cell);
	freeExpr(simplifXon);
	return suite;
	}
else
	{
	chain_list *simplifXon = simplifNot(cell->val_abl->VALABL);
	chain_list *deb;

	deb = conclu(triCommut(fct(simplifXon)),consExpr(fonc(cell),cell->entrees));
	if (cellOpose(cell->nomlog))
		deb = addchain(deb,(void *)regOpposee(cell));
	else deb = opposees(deb);
	freeExpr(simplifXon);
	return deb;
	}
}

/******************************************************************************/
/**************** fonc : retourne l'operateur d'une cellule *******************/
/******************************************************************************/
int fonc(cell)
cellList *cell;

{
if (cell->type == 'l')
	{
	if (cellXor(cell))
		{
		if (cell->nomlog[0] != 'n')
			return XOR;
		return searchNumOper(cell->nomlog);
		}
	if (simple(cell->val_abl->VALABL))
		{
		chain_list *simpNot = simplifNot(cell->val_abl->VALABL);
		int retour;

		if (cell->nomlog == nameNot1) return NOT;
		if (simpleInverse(cell->val_abl->VALABL))
		      retour =  morgOper(OPER(simpNot));
		else
		      retour =  OPER(simpNot);
		freeExpr(simpNot);
		return retour;
		}
	}
return searchNumOper(cell->nomlog);
}

/******************************************************************************/
/********* regleOperVHDL : regle pour une cellule VHDL et non duale ***********/
/******************************************************************************/
void regleOperVHDL(cell)
cellList *cell;

{
chain_list *reg;
cellList *cellNot = (cellList *)testObj(nameNot1,'c');
chain_list *aux;
regle_list *regAd;

   aux = consExpr(fonc(cell),cell->entrees);
   reg = addchain(inversArg(aux),(void *)consExpr(invOper(fonc(cell)),cell->entrees));
   freeExpr(aux);
   filtrage(reg,cell);
   addArite(CAR(reg));
   if (!cellNot)
   {
   	declenList *decl = mappSys->ptdecl;

   	while (strcmp(decl->name,"not")) decl = decl->NEXT;
   	if (!decl->regles) 
      	{
      	   fprintf(stderr,"regleOperVhdl : incomplete library...\n");
      	   return;
      	}
	aux = CDR(reg);
   	CDR(reg)= remplaceNot(CDR(reg),findBestNot(decl->regles)); 
	freeExpr(aux);
   }
addArite(CDR(reg));
regAd = genereObj(reg);
addDeclen(regAd,namealloc("pol"));
}

/******************************************************************************/
/********* testOperVHDL : test si la cellule est VHDL *************************/
/******************************************************************************/
short testOperVHDL(cell)
cellList *cell;

{
if (fonc(cell) == AND || fonc(cell) == OR || fonc(cell) == XOR 
    || fonc(cell) == NAND || fonc(cell) == NOR)
	return 1;
return 0;
}

/***************************** filtrage ***************************************/

/******************************************************************************/
/********* varF : construit une variable de filtrage **************************/
/******************************************************************************/
char *varF(n,var)
short n;
char *var;

{
unsigned int len = strlen(var)+2;
char *ch = (char *)mbkalloc(len);
char *retour;

if (n == 1) sprintf(ch,"*%s",var);
else sprintf(ch,"!%s",var);
retour = namealloc(ch);
#if MACHINE != pc
   mbkfree(ch);			/* PC... */
#endif
return retour;
}

/******************************************************************************/
/***** parcoursConclu : recherche les entrees inversees dans la conclusion ****/
/******************************************************************************/
void parcoursConclu(conclusion,entrees)
chain_list *conclusion;
Alist *entrees;

{
if (ATOM(conclusion))
	acons(entrees,VALUE_ATOM(conclusion),"p");
else if (OPER(conclusion) != NOT)
	{
	chain_list *arg;

	for(arg = CDR(conclusion);arg;arg = arg->NEXT)
		parcoursConclu(CAR(arg),entrees);
	}
     else if (ATOM(CADR(conclusion)))
		acons(entrees,VALUE_ATOM(CADR(conclusion)),"n");
	  else parcoursConclu(CADR(conclusion),entrees);
}

/******************************************************************************/
/***** filtrePremisse : ajoute les variables de filtrage dans la premisse ****/
/******************************************************************************/
void filtrePremisse(prem,cell,pTList)
chain_list *prem;
cellList *cell;
ptype_list *pTList;

{
chain_list *arg;

for(arg = CDR(prem);arg;arg = CDR(arg))
	{
	if (ATOM(CAR(arg)))
		{
		if ( (VALUE_ATOM(CAR(arg)) != nameUn) &&
			(VALUE_ATOM(CAR(arg)) != nameZero) )
			{
			char *var = varF(2,VALUE_ATOM(CAR(arg)));
			chain_list *aux = CAR(arg);

			acons(cell->entrees,VALUE_ATOM(CAR(arg)),var);
			arg->DATA = (void *)createATOM(var);
			freeExpr(aux);
			}
		}
	else
		argsSsexpr(CDR(CAR(arg)),cell,pTList);
	}
}

/******************************************************************************/
/***** filtreConclusion : ajoute les var de filtrage dans la conclusion *******/
/******************************************************************************/
chain_list *filtreConclusion(conc,cell)
chain_list *conc;
cellList *cell;

{
if (ATOM(conc))
	{
	if ( (VALUE_ATOM(conc) == nameUn) || (VALUE_ATOM(conc) == nameZero) ) 
        return copyExpr(conc);
	else
	  {
	  char *res = cassq(cell->entrees,VALUE_ATOM(conc));

	  if ((strcmp(res,"n") == 0) || (strcmp(res,"p") == 0))
	    return createAtom((char*)(cell->entrees->ptChain));
	  else
	    return createAtom(res);
	  }
	}
else
	{
	chain_list *arg,*retour = createExpr(OPER(conc));

	for(arg = CDR(conc);arg;arg = arg->NEXT)
		addQExpr(retour,filtreConclusion(CAR(arg),cell));
	return retour;
	}
}

/******************************************************************************/
/** argsSsexpr : ajoute les var de filtrage dans les arguments de la premisse */
/******************************************************************************/
void argsSsexpr(args,cell,pTList)
chain_list *args;
cellList *cell;
ptype_list *pTList;

{
if (args)
	{
	if (ATOM(CAR(args)))
		if ( (searchPtype(pTList,VALUE_ATOM(CAR(args))) > 1)
		    || (CDR(args)) )
			{
			char *var = varF(2,VALUE_ATOM(CAR(args)));
			chain_list *aux;

			acons(cell->entrees,VALUE_ATOM(CAR(args)),var);
			aux = CAR(args);
			args->DATA = (void *)createATOM(var);
			freeExpr(aux);
			argsSsexpr(CDR(args),cell,pTList);
			}
		else
			{
			if (strcmp(cassq(cell->entrees,VALUE_ATOM(CAR(args))),"p") == 0)
				{
				char *var = varF(1,VALUE_ATOM(CAR(args)));
				chain_list *aux;

				acons(cell->entrees,VALUE_ATOM(CAR(args)),var);
				aux = CAR(args);
				args->DATA = (void *)createATOM(var);
				freeExpr(aux);
				}
			else
				{
				char *var = varF(1,VALUE_ATOM(CAR(args)));
				chain_list *aux;

				acons(cell->entrees,VALUE_ATOM(CAR(args)),var);
				aux = CAR(args);
				args->DATA = (void *)createATOM(var);
				freeExpr(aux);
				}
			}
	else
		{
		argsSsexpr(CDR(CAR(args)),cell,pTList);
		argsSsexpr(CDR(args),cell,pTList);
		}
	}
}

/******************************************************************************/
/******* filtrage : ajoute les var de filtrage dans une regle *****************/
/******************************************************************************/
void filtrage(Regle,cell)
chain_list *Regle;
cellList *cell;

{
ptype_list *p,*pTL = NULL;
chain_list *aux;

resetAlist(cell->entrees,0);
parcoursConclu(CDR(Regle),cell->entrees);
pTL = supportPtype_listExpr(CAR(Regle));
for(p = pTL;p;p = CDR(p))
	p->TYPE = numberOcVarExpr(CAR(Regle),(char *)p->DATA);
if ((cell->type == 'l') && (OPER(CAR(Regle)) != NOT)) normExpr(CAR(Regle));
filtrePremisse(CAR(Regle),cell,pTL);
aux =  CDR(Regle);
Regle->NEXT = filtreConclusion(aux,cell);
freeExpr(aux);
}

/******************************************************************************/
/************** reglesCellRegistre : regles pour les registres ****************/
/******************************************************************************/
chain_list *reglesCellRegistre(cell,type)
cellList *cell;
char type;

{
chain_list *prem,*conc,*reg,*lstReg;
struct biabl *abl;
int op = searchNumOper(cell->nomlog);

   if (type == 'r')
      prem = createExpr(searchNumOper(nameLatch));
   else
      prem = createExpr(searchNumOper(nameBD));
   for(abl = cell->val_abl;abl;abl = abl->NEXT)
   {
	/* on ne genere pas de regle pour un latch inverseur */
	if (!ATOM (abl->VALABL) && OPER(abl->VALABL) == NOT)
	{
	   freeExpr(prem);
	   return NULL;
	}
	addHExpr(prem,copyExpr(abl->CNDABL));
	addHExpr(prem,copyExpr(abl->VALABL));
   }
   conc = consExpr(op,cell->entrees);
   /* ajoute le 24/11/92 : traitement des multiplexes  */
   if (profExpr(prem) > 1)
   {
   chain_list *liste = triCommut(fct(CADR(prem)));
      reg = NULL;
      do
      {
      chain_list *prembis = copyExpr(prem);
         prembis->NEXT->DATA = liste->DATA;
         reg = addchain(reg,prembis);
      }
      while (liste = CDR(liste));
      freeExpr(prem);
      lstReg = conclu(reg,conc);
      return lstReg;
   }
   reg = addchain(conc,(void *)prem);
   return createATOM(reg);
}

/******************************************************************************/
/************** reglesCellBus : regles pour les Bus **************************/
/******************************************************************************/
chain_list *reglesCellBus(cell)
cellList *cell;

{
chain_list *c;
chain_list *prem,*conc,*reg;
struct biabl *abl;

prem = createExpr(searchNumOper(nameBus));
conc = consExpr(searchNumOper(cell->nomlog),cell->entrees);

for(abl = cell->val_abl;abl;abl = abl->NEXT)
     {
     char *cmdPos,*cmdNeg;
     chain_list *realSupportCmd = NULL, *supCmd;
     chain_list *supportCmd = supportChain_listExpr(abl->CNDABL);
     chain_list *supportVal = supportChain_listExpr(abl->VALABL);

	/* calcul du support des commandes du bus (elimination de la donnee) */
     for(supCmd = supportCmd; supCmd; supCmd = supCmd->NEXT)
        {
        if (!memberChain_list (supCmd->DATA, supportVal))
           realSupportCmd = addchain(realSupportCmd, supCmd->DATA);
        else 
           PRINTF("Warning : %s data's shouldn't be in guarded expression\n",cell->nom);
        }

     if (realSupportCmd->NEXT)
	{
		/* pour les bus qui ont 2 commandes exclusives (nt1_y) */
	chain_list *aux;

	resetAlist(cell->entrees,0);
	alistEntrees(cell->val_abl->CNDABL,cell->entrees);
	cmdPos = cassqVal(cell->entrees,"p");
	cmdNeg = cassqVal(cell->entrees,"n");
	aux = createAtom(cmdPos);
	conc = substExpr(conc,cmdNeg,inversArg(aux));
	freeExpr(aux);
        addHExpr(prem,createAtom(cmdPos));
	}
     else
        {
		/* on ajoute la commande a la premisse */
	addHExpr(prem,createAtom((char *)realSupportCmd->DATA));
        }
		/* on ajoute la donne (ou son inverse) a la premisse */
     addHExpr(prem,copyExpr(abl->VALABL));
     }

reg = addchain(conc,(void *)prem);
return createATOM(reg);
}

/******************************************************************************/
/**** remplaceNot : remplace les not dans la conclusion si NOT n'existe pas ***/
/******************************************************************************/
chain_list *remplaceNot(abl,conc)
chain_list *abl,*conc;
{
if (ATOM(abl))
   return copyExpr(abl);
if (OPER(abl) != NOT)
   {
   chain_list *res = createExpr(OPER(abl));
   chain_list *arg;

   for(arg = CDR(abl);arg;arg = CDR(arg))
	addQExpr(res,remplaceNot(CAR(arg),conc));
   return res;
   }
   else
   {
   chain_list *resNot = createExpr(OPER(conc)),*args;

   for(args = CDR(conc);args;args = CDR(args))
	{
	if (ATOM(CAR(args)) && (VALUE_ATOM(CAR(args)) == nameUn))
	   addHExpr(resNot,createATOM(nameUn));
	else
	  if (ATOM(CAR(args)) && (VALUE_ATOM(CAR(args)) == nameZero))
	     addHExpr(resNot,createATOM(nameZero));
	  else
	   addHExpr(resNot,remplaceNot(CADR(abl),conc));
	}
   return resNot;
   }
}

/******************************************************************************/
/********* findBestNot : retourne la meilleure facon de generer le NOT ********/
/******************************************************************************/
chain_list *findBestNot(regles)
regle_list *regles;
{

while (regles && !ATOM(CADR(regles->premisse)))
      regles = CDR(regles);
if (!regles)
   {
   fprintf(stderr,"findBestNot : no rule to generate a NOT\n");
   exit(-1);
   }
if (!regles->NEXT)
   return regles->conclusion;
else
   {
   int prix = cout(regles->conclusion),c;
   regle_list *find = regles, *r;

   for(r = regles->NEXT;r;r = r->NEXT)
      if (ATOM(CADR(r->premisse)) && ((c = cout(r->conclusion)) < prix))
	{
	prix = c;
	find = r;
	}
   if (SL_TRACE == 2) 
   {printf("findBestNot <--");
    displayArite(find->conclusion);printf("\n");}
   return find->conclusion;
   }
}

/******************** generation des regles ***********************************/
void reglesCellules()

{
cellList *cellNot = (cellList *)testObj(nameNot1,'c'),*c;
chain_list *newNot;

if (!cellNot)
    {
    declenList *decl = mappSys->ptdecl;

    while (strcmp(decl->name,"not")) decl = decl->NEXT;
    if (!decl->regles) 
      	{
      	printf("generation de regles : pas de NOT et pas moyen d'y arriver ...\n");
      	 exit(-1);
      	}
    newNot = findBestNot(decl->regles); 
    }
for(c=mappSys->ptcell;c;c = c->NEXT)
    {	
    chain_list *regles;

    switch (c->type)
	{
	case 'l' : regles = reglesCellLogique(c);break;
	case 'r' :
        case 'd' : regles = reglesCellRegistre(c,c->type);break;
        case 'b' : regles = reglesCellBus(c);break;
	default : regles = (chain_list *)NULL;break;
	}
    if (regles)
	{
	chain_list *r;

	if (c->nomlog != nameNot1)
		reportNot(regles,c);

	for(r = regles;r;r = CDR(r))
	   {
	   regle_list *reg;

	   filtrage(CAR(r),c);
	   addArite(CAR(CAR(r)));
	   if (!cellNot)
   	      	{
		chain_list *aux = CDR(CAR(r));

   		CAR(r)->NEXT =remplaceNot(CDR(CAR(r)),newNot);
		freeExpr(aux);
   		}
	   addArite(CDR(CAR(r)));
	   reg = genereObj(CAR(r));
	   if (reg) addDeclen(reg,searchCharOper(OPER(CAR(CAR(r)))));
	   }
	}
    }
/*printf("%d regles\n",nbre);*/
}

/******************************************************************************/
/************** genereObj : generation des objets regles **********************/
/******************************************************************************/
regle_list *genereObj(Regle)
chain_list *Regle;

{
cellList *cellPrem = operToCell(CAR(Regle));
cellList *cellConc = operToCell(CDR(Regle));

if (cellPrem && (cellPrem == cellConc) && (OPER(CAR(Regle)) != XOR))
  {
  printf("unused rule :");
  displayArite(CAR(Regle));printf("->");
  displayArite(CDR(Regle));printf("\n");
  return NULL;
  }
else
  {
  regle_list *reg = (regle_list *)mbkalloc(sizeof(regle_list));

  if (OPER(CAR(Regle)) != NOT) addQExpr(CAR(Regle),createATOM(nameRest));
  reg->premisse = CAR(Regle);
  reg->conclusion = CDR(Regle);
  reg->prof_premi = profExpr(CAR(Regle));
  reg->util = 0;
  if (OPER(reg->premisse) == searchNumOper(nameLatch) ||
      OPER(reg->premisse) == searchNumOper(nameBD))
     reg->condition = 1;
  else
     reg->condition = 0;
  return reg;
  }
}

void addDeclen(regle,nameDeclen)
regle_list *regle;
char *nameDeclen;
{
declenList *m;

for(m = mappSys->ptdecl;m;m = m->NEXT)
	{
	if (m->name == nameDeclen) 
		{
		regle->NEXT = m->regles;
		m->regles = regle;
		}
	}
}
