/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit : synthetiseur logique                                        */
/*    Fichier : compile.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 : 06/08/1991     */
/*                                                                          */
/*    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 "../proof/proof.h"
#include "../synthe/sl_type.h"
#include "../menu/sl_corps.h"
#include "../compil/sl_util.h"
#include "types.h"
#include "compile.h"
#include "display.h"
#include "oper.h"
#include "regles.h"
#include "util.h"
#include "decomp.h"
#include "generic.h"

/******************************************************************************/
/******************* COMPILATION de BIBLIOTHEQUES *****************************/
/******************************************************************************/

/******************************************************************************/
/******** initCellList : initialise les champs d'une cellule logique **********/
/******************************************************************************/
cellList *initCellList(cellSuite,name,type,phys)
cellList *cellSuite;
char *name,type;
befig_list *phys;

{
cellList *cell = (cellList *)mbkalloc(sizeof(cellList));
biabl_list *r,*b;

cell->type = type;
cell->nomlog = name;
cell->nom= name;
cell->interface = initPort(phys->BEPOR);

if (type == 'l')
   cell->entrees = createAlist((Alist *)NULL,phys->BEOUT->ABL);
else
   if (type == 'b')
      {
      Alist *in = NULL;

      for(b = phys->BEBUS->BIABL;b;b = b->NEXT)
	 {
	 in = createAlist(in,b->VALABL);
	 in = createAlist(in,b->CNDABL);
	 }
      cell->entrees = in;
      }
   else
      {
      if (type == 'r' || type == 'd')
         {
         Alist *in = NULL;

         for(r = phys->BEREG->BIABL;r;r = r->NEXT)
	    {
	    in = createAlist(in,r->VALABL);
	    in = createAlist(in,r->CNDABL);
	    }
         cell->entrees = in;
         }
      else 
         cell->entrees = initIn(phys->BERIN,phys->BEREG);
     }

cell->entrees = triOrdreInterface(cell->entrees,cell->interface);

if (type == 'b') 
   cell->sorties = initOut((beout_list *)phys->BEBUS);
else 
   cell->sorties = initOut(phys->BEOUT);
cell->delais_tech = NULL;
cell->delais= NULL;
cell->capa_tech = NULL;
cell->surface_tech = NULL;
cell->surface= 1;
cell->resistance_tech = (ptype_list *)NULL;
cell->generic = (ptype_list *)NULL;
cell->envel = NULL;
cell->util = 0;

cell->NEXT = cellSuite;
if (type == 'l')		/* cellule logique */
   	{
	cell->val_abl = (biabl_list *)mbkalloc(sizeof(biabl_list));
	cell->val_abl->VALABL = normMappingExpr(phys->BEOUT->ABL); 
	cell->envel = copyExpr(cell->val_abl->VALABL);
	addArite(cell->val_abl->VALABL);
	cell->val_abl->CNDABL = NULL; 
	cell->val_abl->NEXT = NULL; 
   	cell->BDD = phys->BEOUT->NODE;
   	cell->circuit = phys->CIRCUI;
	}
else
	{
	cell->envel = NULL;
   	cell->BDD = NULL;
   	cell->circuit = NULL;
	if (type == 'r' || type == 'd')
	   {
	   if ((nivNot(phys->BEOUT->ABL) != 0) || (lengthExpr(phys->BEOUT->ABL) != 1))
		printf("initCellList : Problem on BEOUT for %s\n", name);
           if (phys->BEOUT->NEXT)
              {
		/* registre a 2 sorties */
              if (((ATOM(phys->BEOUT->ABL)) &&
                  ((ATOM(CADR(phys->BEOUT->NEXT->ABL))) && 
                   (VALUE_ATOM(CADR(phys->BEOUT->NEXT->ABL)) == VALUE_ATOM(phys->BEOUT->ABL)))) ||
                  ((ATOM(phys->BEOUT->NEXT->ABL)) &&
                   ((ATOM(CADR(phys->BEOUT->ABL))) && 
                   (VALUE_ATOM(CADR(phys->BEOUT->ABL)) == VALUE_ATOM(phys->BEOUT->NEXT->ABL)))))
                 {
                 if (ATOM(phys->BEREG->BIABL->VALABL))
                    {
                    if (ATOM(phys->BEOUT->ABL))
                       {
                       cell->sorties = addchain((chain_list *)NULL, phys->BEOUT->NAME);
                       cell->interface = delAlist(cell->interface, phys->BEOUT->NEXT->NAME);
                       }
                    else
                       {
                       cell->sorties = addchain((chain_list *)NULL, phys->BEOUT->NEXT->NAME);
                       cell->interface = delAlist(cell->interface, phys->BEOUT->NAME);
                       }
                    cell->val_abl = reCopyBiabl(phys->BEREG->BIABL,0);
                    }
                 else
                    if ((OPER(phys->BEREG->BIABL->VALABL) == NOT) &&
                        (ATOM(CADR(phys->BEREG->BIABL->VALABL))))
                       { 
                       if (ATOM(phys->BEOUT->ABL))
                          {
                          cell->sorties = addchain((chain_list *)NULL, phys->BEOUT->NEXT->NAME);          
                          cell->interface = delAlist(cell->interface, phys->BEOUT->NAME);                 
                          } 
                       else 
                          {
                          cell->sorties = addchain((chain_list *)NULL, phys->BEOUT->NAME);                
                          cell->interface = delAlist(cell->interface, phys->BEOUT->NEXT->NAME);           
                          } 
                       cell->val_abl = reCopyBiabl(phys->BEREG->BIABL,1);
                       }
                 }
              else
                 {
                 printf("Error on cell %s : the 2 outputs are not inverted\n", name);
                 exit(1);
                 }
              }
           else
		/* registre a une sortie */
	      if (ATOM(phys->BEOUT->ABL))
                 cell->val_abl = reCopyBiabl(phys->BEREG->BIABL,0);
	      else 
                 cell->val_abl = reCopyBiabl(phys->BEREG->BIABL,1);
	   }
        else
           if (type == 'b')
	      cell->val_abl = reCopyBiabl(phys->BEBUS->BIABL,0);
	   else
	   {
	   cell->val_abl = (biabl_list *)mbkalloc(sizeof(biabl_list));
	   cell->val_abl->VALABL = normMappingExpr(phys->BEOUT->ABL); 
	   addArite(cell->val_abl->VALABL);
	   cell->val_abl->CNDABL = NULL; 
	   cell->val_abl->NEXT = NULL; 
	   }
	}
return cell;
}

/******************************************************************************/
/******* initMapping : Initialisation de la variable globale : mappSys ********/
/******************************************************************************/

mapping *initMapping()
{
declenList *p = NULL;
short i;

nameUn = namealloc("'1'");
nameZero = namealloc("'0'");
nameHigh = namealloc("high");
nameLow = namealloc("low");
nameLatch = namealloc("latch");
nameBD = namealloc("bd");
nameBus = namealloc("bus");
nameNot1 = namealloc("not1");
nameRest = namealloc("*_rest");
createTabOper();
addOper(nameLatch);
addOper(nameBus);
addOper(nameBD);

mappSys = (mapping *)mbkalloc(sizeof(mapping));
mappSys->ptcell = NULL;
for(i= 9;i >= 0; i--)
	{
	declenList *aux = (declenList *)mbkalloc(sizeof(declenList));

	aux->name = operToChar(i);

	if (i == NXOR) 
           aux->name = nameLatch;
	if (i == 7) 
           aux->name = nameBus;
        if (i == 8) 
           aux->name = namealloc("pol");
        if (i == 9) 
           aux->name = nameBD; 

	aux->regles = NULL;
	aux->NEXT = p;
	p = aux;
	}
mappSys->ptdecl = p;
mappSys->ref       = NULL;
mappSys->delta = 0;
mappSys->sig_hash = createTH(2000);
mappSys->virt_hash = createTH(5000);
mappSys->abl_hash = createTH(2000);
mappSys->cell_hash = createTH(100);

return(mappSys);
}

cellList *endMapping()
{
regle_list *r,*sauvr;
declenList *d,*sauvd;
pElemTH pEl;
int i;
cellList *retour;

   for (d=mappSys->ptdecl;d;d=sauvd)
   {
      sauvd = CDR(d);
      for (r=d->regles;r;r=sauvr)
      {
         sauvr = CDR(r);
         freeExpr(r->premisse);
         r->premisse = NULL;
         freeExpr(r->conclusion);
         r->conclusion = NULL;
         mbkfree(r);
      }
      d->regles = NULL;
      mbkfree(d);
   }

   pEl = mappSys->sig_hash->pElem;
   for (i=0;i<mappSys->sig_hash->length;i++)
   {
       if (pEl->value != VIDETH && pEl->value != DELETETH)
       {
           mbkfree(pEl->value);
       }
       pEl++;
   }
   destroyTH(mappSys->sig_hash);
   pEl = mappSys->virt_hash->pElem;
   for (i=0;i<mappSys->virt_hash->length;i++)
   {
      if (pEl->value != VIDETH && pEl->value != DELETETH && pEl->value != 1)
      {
      chain_list *s = ((virtuelList *)pEl->value)->solutions;

          freechain(((virtuelList *)pEl->value)->solutions);
          freechain(((virtuelList *)pEl->value)->fanout);
          mbkfree(pEl->value);
      }
      pEl++;
   }
   destroyTH(mappSys->virt_hash);
   destroyTH(mappSys->abl_hash);
   destroyTH(mappSys->cell_hash);
   retour = mappSys->ptcell;
   mbkfree(mappSys);
   return retour;
}

/******************************************************************************/
/************ renameSig : fonction de renommage des signaux          **********/
/******************************************************************************/
char *renameSig(name)
char *name;
{
char *nom,*nom2;

   if (!strcmp(name,"vdd") || !strcmp(name,"vss") ||
       !strcmp(name,"'0'") || !strcmp(name,"'1'"))
      return name;
   nom = mbkalloc(strlen(name) + 2);
   sprintf(nom,"_%s",name);
   nom2 = namealloc(nom);
#if MACHINE != pc
   mbkfree(nom);	/* chaine */
#endif
   return nom2;
}

/******************************************************************************/
/************ compileLibrary : compile toutes les cellules physiques **********/
/******************************************************************************/
void compileLibrary()
{
befig_list	*bList;
cellList	*logicCel;
char		*logic_name;
int		numReg = 0,numBus = 0;
char 		type;
cellList *c;

printf("Running rules generator on '%s'...\n",SL_CATA_LIB);

	/*** elimination des cellules physiques non conformes ***/

if (SL_TRACE == 2) 
   printf("*** Removing the bad cells ***\n");
for (bList = VHB_HEDFIG;bList;bList = bList->NEXT)
   {

   if ( (!bList->BEOUT || bList->BEOUT->NEXT) && 
        (!bList->BEBUS || bList->BEBUS->NEXT ) && 
        (!bList->BEREG) )
      {
      PRINTF("%s Unused\n",bList->NAME);
      bList->NAME = NULL;
      }
          /* elimination des cellules a 3 niveaux d'operateur */
   else
      if (bList->BEOUT && profAOExpr(normMappingExpr(bList->BEOUT->ABL)) > 2)
         {
         printf("%s Unused\n",bList->NAME);
         bList->NAME = NULL;
      	 }
   }

	/*** Traitement de chaque cellule physique ***/

for (bList = VHB_HEDFIG;bList;bList = bList->NEXT)
   {
   befig_list *behAux;

   if (bList->NAME)
      {
	/* cellule conforme */
      if (bList->BEBUS)
         {
         type = 'b';
         logic_name = gensym("_bus",numBus++);
         }
      else
	if (ATOM(bList->BEOUT->ABL) &&
	    (VALUE_ATOM(bList->BEOUT->ABL) == nameUn))
           {
	   type = 'c';
   	   logic_name = nameHigh;
   	   }
	   else if (ATOM(bList->BEOUT->ABL) &&
	            (VALUE_ATOM(bList->BEOUT->ABL) == nameZero))
		   {
		   type = 'c';
        	   logic_name = nameLow;
        	   }
     	        else if (ATOM(bList->BEOUT->ABL) && !(bList->BEREG)) 
		   	{
		   	type = 't';
             		logic_name=namealloc("trans");
			}
         	     else if (bList->BEREG) 
      			     {
				/* traitement des BDs*/

                             if (bList->BEREG->BIABL->USER)
                                {
                                type = 'd';
      			        logic_name = gensym("_bd",numReg++);
                                }
                             else
                                {
      			        type = 'r';
      			        logic_name = gensym("_reg",numReg++);
                                }
      			     }
      			  else
         		     {
         		     type = 'l';
         		     logic_name = identExpr((bList->BEOUT)->ABL);
         		     }
   if (SL_TRACE == 2) 
      printf("    name = %s, type = %c, logic_name = %s\n",
                        bList->NAME, type, logic_name);
   addOper(logic_name);
   if (testObj(logic_name,'c')) 
      {
      PRINTF("compile : Error on the behavioral description %s\n",bList->NAME);
      PRINTF("cells with equivalent fonctionnality but with different interfaces\n");
      exit(-1);
      }

   mappSys->ptcell = initCellList(mappSys->ptcell,logic_name,type,bList);

   recupGeneric(bList,mappSys->ptcell);

   addTH(mappSys->cell_hash,logic_name,(int)(mappSys->ptcell));

	/* recherche des befig egales */
   for (behAux = bList->NEXT;behAux;behAux = behAux->NEXT)
      {
      if (behAux->NAME != NULL && (proofBeh(behAux,bList,0,1) == 0))
         {
         recupGeneric(behAux,mappSys->ptcell);
         behAux->NAME = NULL;
         }
      }
   }   
   }

if (SL_TRACE == 2) 
   printf("*** Computing the reference cell for each logic cell ***\n");

   for(logicCel = mappSys->ptcell;logicCel;logicCel = logicCel->NEXT)
   {
   Alist  *e;
   num_list *p;
   
	/* -------- pour recuperer les GENERICS -------------------*/

   logicCel->nom = findResistanceGen(logicCel);
   logicCel->surface = searchGeneric(logicCel,logicCel->nom,"area");
   logicCel->delais = findDelaisGen(logicCel,logicCel->nom, 1);

   for(e = logicCel->entrees, p = logicCel->delais;
       e && p;
       e = e->NEXT, p = p->NEXT)
      e->ptChain = (chain_list *)p->DATA ; 
   if ((logicCel->type == 'l') && (logicCel->nomlog != nameUn) && 
       (logicCel->nomlog != nameZero))
      {
      chain_list *res = ablContraint(logicCel),*r;

      calculEnvel(logicCel->envel);
      triExpr(logicCel->envel,logicCel);

/*   Trace qui affiche les regles
	printf("apres ablContraint\n");
	for(r = res;r;r = CDR(r))
	   {
	   displayArite(CAR(CAR(r)));
	   printf("->");
	   displayArite(CDR(CAR(r)));
	   printf("\n");
	   }
*/

	/* traitement des regles obtenues par egalites des entrees */

		reportNot(res,logicCel);
		for(r = res;r;r = CDR(r))
	   	   {
		   char *oper;

	           addArite(CAR(CAR(r)));
		   oper = gensym(operToChar(OPER(CAR(CAR(r)))),ARITE(CAR(CAR(r))));

		   if (!testObj(oper,'c') && !cellOpose(oper))
			{
		  /* la cellule et son inverse  n'existent pas */
	           	regle_list *reg;

                        if (SL_TRACE == 2) 
			   printf("ablContraint : %s doesn't exist\n",oper);
	           	filtrage(CAR(r),logicCel);
	           	addArite(CDR(CAR(r)));
	           	reg = genereObj(CAR(r));
	           	addDeclen(reg,searchCharOper(OPER(CAR(CAR(r)))));
			}
	     	   }
	   }
   }
   if (!testObj(nameNot1,'c'))
   {
   declenList *decl = mappSys->ptdecl;
   chain_list *rempNot;
   regle_list *reg;

   	while (strcmp(decl->name,"not")) decl = decl->NEXT;
   	if (!decl->regles) 
        {
      	   fprintf(stderr,"compileLibrary : error incompleted library ...\n");
      	   exit(-1);
        }
	rempNot = findBestNot(decl->regles);
	for(decl = mappSys->ptdecl;decl;decl = decl->NEXT)
	   for(reg = decl->regles;reg;reg = reg->NEXT)
	   {
		reg->conclusion = remplaceNot(reg->conclusion,rempNot);
		addArite(reg->conclusion);
	   }

/* *** Regle equivalente a : (not(not i)) -> i *** */

      if ( (OPER(rempNot) < 10) && (profExpr(rempNot) == 1) )
      {
      int i;
      chain_list *prem2Not,*reg1;
      regle_list *regle;

         prem2Not = createExpr(OPER(rempNot));
         for(i = 0;i != ARITE(rempNot); i++)
            addHExpr(prem2Not,copyExpr(rempNot));
         addArite(prem2Not);
         reg1  = addchain(createATOM(VALUE_ATOM(CADR(rempNot))),
			 (void *)prem2Not);
	 freeExpr(rempNot);
	 PRINTF("Simplification rule : ");
         displayArite(CAR(reg1));printf("->");
         displayArite(CDR(reg1));printf("\n");
         regle = genereObj(reg1);
         addDeclen(regle,searchCharOper(OPER(CAR(reg1))));
      }
   }
if (SL_TRACE == 2)
for(c=mappSys->ptcell;c;c = c->NEXT)
    displayCell(c);
/*
displayTabOper();
*/
reglesCellules();
if (SL_TRACE == 2) displayDeclencheurs();
nbreRegles();
for (bList = VHB_HEDFIG;bList;bList = bList->NEXT)
{
    destroyCct(bList->CIRCUI);
    bList->CIRCUI = NULL;
}
beh_frebefig(VHB_HEDFIG);
}

chain_list *ablContraint(cell)
cellList *cell;
{
Alist *in,*e;
pCircuit circuit = cell->circuit;
pNode bdd = cell->BDD;
chain_list *regles = NULL,*prems = NULL;

/*
printf("ablContraint : traitement de %s\n",cell->nomlog);
*/
if (cellXor(cell) && ((ARITE(cell->val_abl->VALABL) == 2) ||
			( (ARITE(cell->val_abl->VALABL) == 1) &&
			 (ARITE(CADR(cell->val_abl->VALABL)) == 2) ) ) )
   {
   short index1 = searchInputCct(circuit,cell->entrees->name);
   pNode result;

   if (fonc(cell) == XOR)
   	result = constraintBdd(bdd,createNodeTermBdd(index1));
   else
	result = notBdd(constraintBdd(bdd,createNodeTermBdd(index1)));
   if ((result != zero) && (result != one) && (result != bdd))
	    {
	    chain_list *prem = bddToAbl(result,circuit->pNameI);

	    if (!ATOM(prem)) 
		{
	    	chain_list *conc = consExpr(fonc(cell),cell->entrees);
		chain_list *regle;
		chain_list *subst = 
		  (fonc(cell) == XOR) ? createATOM(nameUn) : createATOM(nameZero);

	    	substPhyExpr(conc,cell->entrees->name,subst);
		regle = addchain(conc,(void *)prem);
/*
		printf("prem1 :");displayArite(prem);
		printf("-->");displayArite(conc);printf("\n");
*/
		return createATOM(regle);
		}
	    }
   return NULL;
   }
for(in = cell->entrees;in->NEXT;in = CDR(in))
   {
   short index1 = searchInputCct(circuit,in->name);
   pNode subst = createNodeTermBdd(index1);

   for(e = in->NEXT;e;e = CDR(e))
	{
	short index = searchInputCct(circuit,e->name);
	pNode result = composeBdd(bdd,subst,index);

	if ((result != zero) && (result != one) && (result != bdd))
	    {
	    chain_list *prem = bddToAbl(result,circuit->pNameI);

	    if ((!ATOM(prem)) && (!findEqual(prem,prems)))
		{
	    	    chain_list *conc = consExpr(fonc(cell),cell->entrees);
		    chain_list *regle;

	    	    substPhyExpr(conc,e->name,createATOM(in->name));
		    prems = addchain(prems,(void *)prem);
		    regle = addchain(conc,(void *)prem);
/*
		printf("prem :");displayArite(prem);
		printf("-->");displayArite(conc);printf("\n");
*/
		    regles = addchain(regles,(void *)regle);
		}
   	    }
	}
   }
   return regles;
}
