/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit :  NetOptim                                                   */
/*    Fichier :  neto.c                                                     */
/*                                                                          */
/*    (c) copyright 1992 Laboratoire MASI equipe CAO & VLSI                 */
/*    Tous droits reserves                                                  */
/*    Support : e-mail cao-vlsi@masi.ibp.fr                                 */
/*                                                                          */
/*    Auteur(s) : N. Dictus                             le : 10/04/1992     */
/*                                                                          */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*                                                                          */
/****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include MUT_H
#include LOG_H
#include MLO_H
#include "types_map.h"
#include "../net/no_type.h"
#include "../net/no_system.h"
#include BEH_H
#include "util.h"
#include "neto.h"
#include "../mapping/generic.h"

#define FACTEURMULTIPLICATIF 4

extern char *VERSION;
char *gensym();
Alist *createAlist();

/*---------------------------------------------------------------------------
memberAlist	: retourne si la Alist contient name
-----------------------------------------------------------------------------
retour		: *Alist ou NULL
---------------------------------------------------------------------------*/
Alist *memberAlist(name, liste)
char *name;
Alist *liste;
{
Alist *l;

for(l = liste; l; l = l->NEXT)
   if (l->name == name)
      return l;
return NULL;
}

/*---------------------------------------------------------------------------
cellLoadEnvel	: retourne l'enveloppe de la cellule
-----------------------------------------------------------------------------
retour		: *chain_list
---------------------------------------------------------------------------*/
chain_list *cellLoadEnvel(name)
char *name;
{
int val = searchTH(NO_CELLTH,name);

if (val == EMPTYTH)
   {
   printf("\ncellLoadEnvel : le modele %s n'est pas charge en memoire (cellLoad !)\n",name);
   exit(1);
   }

return ((cellList *)val)->envel;
}
/*---------------------------------------------------------------------------
cellLoadIn	: retourne la liste chainee des entrees.
-----------------------------------------------------------------------------
retour		: *Alist
---------------------------------------------------------------------------*/
Alist *cellLoadIn(name)
char *name;
{
int val = searchTH(NO_CELLTH,name);

if (val == EMPTYTH)
   {
   printf("\ncellLoadIn : le modele %s n'est pas charge en memoire (cellLoad !)\n",name);
   exit(1);
   }

return ((cellList *)val)->entrees;
}

/*---------------------------------------------------------------------------
cellLoadOut	: retourne la liste chainee des sorties.
-----------------------------------------------------------------------------
retour		: *chain_list
---------------------------------------------------------------------------*/
chain_list *cellLoadOut(name)
char *name;
{
int val = searchTH(NO_CELLTH,name);

if (val == EMPTYTH)
   {
   printf("\ncellLoadOut : le modele %s n'est pas charge en memoire (cellLoad !)\n",name);
   exit(1);
   }

return ((cellList *)val)->sorties;
}

/*---------------------------------------------------------------------------
cellLoadPolarity: retourne la polarite d'une cellule.
-----------------------------------------------------------------------------
retour		: NEG, POS ou AUT
---------------------------------------------------------------------------*/
int cellLoadPolarity(name)
char *name;
{
int val = searchTH(NO_CELLTH,name);
cellList *cell;
chain_list *flatAbl;
int retour;

if (val == EMPTYTH)
   {
   printf("\ncellLoadPolarity : le modele %s n'est pas charge en memoire (cellLoad !)\n",name);
   exit(1);
   }
cell = (cellList *)val;

if (cell->type == 'r' || cell->type == 'd' || cell->type == 'b' || cell->type == 'c')
   return AUT;

if (searchOperExpr(cell->val_abl->VALABL,XOR))
   {
   chain_list *sansXor = devXorExpr(cell->val_abl->VALABL);

   flatAbl = flatPolarityExpr(sansXor, 1);
   freeExpr(sansXor);
   } 
else 
   flatAbl = flatPolarityExpr(cell->val_abl->VALABL, 1);
retour = polarityExpr(flatAbl);
freeExpr(flatAbl);
return retour;
}

/*---------------------------------------------------------------------------
cellLoadType	: retourne le type d'une cellule.
-----------------------------------------------------------------------------
retour		: COMBI, REG, BUS, CONST, BUFF
---------------------------------------------------------------------------*/
int cellLoadType(name)
char *name;
{
int val = searchTH(NO_CELLTH,name);
cellList *cell;

if (val == EMPTYTH)
   {
   printf("\ncellLoadType : le modele %s n'est pas charge en memoire (cellLoad !)\n",name);
   exit(1);
   }
cell = (cellList *)val;

if (cell->type == 'l')
   return COMBI;
if (cell->type == 'r' || cell->type == 'd')
   return REG;
if (cell->type == 'b')
   return BUS;
if (cell->type == 'c')
   return CONST;
if (cell->type == 't')
   return BUFF;
printf("\ncellLoadType - warning : le type de %s est %c\n",name,cell->type);
return ERR;
}

/*---------------------------------------------------------------------------
cellLoadSurface	: retourne la surface d'une cellule.
-----------------------------------------------------------------------------
retour		: int
---------------------------------------------------------------------------*/
long cellLoadSurface(name)
char *name;
{
int val = searchTH(NO_CELLTH,name);

if (val == EMPTYTH)
   {
   printf("\ncellLoadSurface : le modele %s n'est pas charge en memoire (cellLoad !)\n",name);
   exit(1);
   }

return searchGeneric((cellList *)val,name,"area");
}

/*---------------------------------------------------------------------------
cellLoadFanout	: retourne le fanout d'une cellule.
-----------------------------------------------------------------------------
retour		: int 
---------------------------------------------------------------------------*/
long cellLoadFanout(name)
char *name;
{
int val = searchTH(NO_CELLTH,name);
chain_list *out;

if (val == EMPTYTH)
   {
   printf("\ncellLoadFanout : le modele %s n'est pas charge en memoire (cellLoad !)\n",name);
   exit(1);
   }

if (NO_FACTOR == 0)
   {
   printf("Le facteur de fanout est a 0 : valeur a partir de 100\n");
   exit(1);
   }
out = cellLoadOut(name);
if (out && !out->NEXT)
   return (NO_FACTOR * searchGeneric((cellList *)val,name,"fanout")) / 1000;
printf("'%s' a un nombre de sorties different de 1\n",name);
exit(1);
}

/*---------------------------------------------------------------------------
cellLoadCin	: retourne la Cin de l'entree d'une cellule.
-----------------------------------------------------------------------------
retour		: int 
---------------------------------------------------------------------------*/
long cellLoadCin(name, in)
char *name;	/* nom du modele ou NULL pour un connecteur */
char *in;	/* nom du connecteur d'entree */
{
if (name == (char *)NULL)
   {
   ptype_list *p;

   for(p = NO_CAPAPO; p; p = p->NEXT)
      if (in == (char *)p->DATA)
         return (int)p->TYPE;
   return (FACTEURMULTIPLICATIF * capaNot());
   }
else
   {
   int val = searchTH(NO_CELLTH,name);
   char *CIN = (char *)mbkalloc(5 + strlen(in));
   long retour;

   if (val == EMPTYTH)
      {
      printf("\ncellLoadCin : le modele %s n'est pas charge en memoire (cellLoad !)\n",name);
      exit(1);
      }

   sprintf(CIN, "cin_%s", in);
   retour = searchGeneric((cellList *)val,name, CIN);
#if MACHINE != pc
   mbkfree(CIN);
#endif
   return retour;
   }
}
/*---------------------------------------------------------------------------
cellLoadR	: retourne la Resistance de l'entree d'une cellule.
-----------------------------------------------------------------------------
retour		: int 
---------------------------------------------------------------------------*/
long cellLoadR(name, in, type)
char *name;
char *in;
int type;
{
int val = searchTH(NO_CELLTH,name);
cellList *cell;

if (val == EMPTYTH)
   {
   printf("\ncellLoadR : le modele %s n'est pas charge en memoire (cellLoad !)\n",name);
   exit(1);
   }

cell = (cellList *)val;

if (cell->type == 'r' || cell->type == 'd')
   if (type == UP)
      return searchGeneric(cell,name,"rup");
   else
      if (type == DOWN)
         return searchGeneric(cell,name,"rdown");
      else
         {
         long somR = 0;

         somR += searchGeneric(cell,name,"rdown");
         somR += searchGeneric(cell,name,"rup");
         return somR / 2;
         }

if (cell->type == 'c')
   {
   long somR = 0;

   if (type == DOWN)
      if ((somR = searchGeneric(cell,name,"rdown")) > 1)
         return somR;
      else
         return (long)0;
   else
      if (type == UP)
         if ((somR = searchGeneric(cell,name,"rup")) > 1)
            return somR;
         else
            return (long)0;
      else
         {
         printf("\ncellLoadR - error : mauvais type : %d pour %s (DOWN ou UP)\n",
                type,name);
         exit(1);
         }
   }

if (!in)
   {
   Alist *entrees = cell->entrees;
   Alist *e;
   long somR = 0, nb = 0;

   for(e = entrees; e; e = e->NEXT)
      if (type == UP)
         {
         char *RUP = (char *)mbkalloc(5 + strlen(e->name));

         sprintf(RUP, "rup_%s", e->name);
         somR += searchGeneric(cell,name, RUP);
         nb++;
#if MACHINE != pc
      mbkfree(RUP);
#endif
         }
      else
         {
         char *RDW = (char *)mbkalloc(7 + strlen(e->name));

         sprintf(RDW, "rdown_%s", e->name);
         somR += searchGeneric(cell,name, RDW);
         nb++;
#if MACHINE != pc
      mbkfree(RDW);
#endif
         }
   if (nb == 0)
      return 0;
   return somR / nb;
   }

if (type == DOWN)
   {
   long retour;
   char *RDW = (char *)mbkalloc(7 + strlen(in));

   sprintf(RDW, "rdown_%s", in);
   retour = searchGeneric(cell, name, RDW);
#if MACHINE != pc
   mbkfree(RDW);
#endif
   return retour;
   }
if (type == UP)
   {
   long retour;
   char *RUP = (char *)mbkalloc(5 + strlen(in));

   sprintf(RUP, "rup_%s", in);
   retour = searchGeneric(cell,name, RUP);

#if MACHINE != pc
   mbkfree(RUP);
#endif
   return retour;
   }
printf("\ncellLoadR - error : mauvais type : %d pour %s (DOWN ou UP)\n",
       type,name);
exit(1);
}

/*---------------------------------------------------------------------------
cellLoadTp	: retourne le delai de l'entree d'une cellule.
-----------------------------------------------------------------------------
retour		: int 
---------------------------------------------------------------------------*/
long cellLoadTp(name, in, type)
char *name;
char *in;
int type;
{
int val = searchTH(NO_CELLTH,name);
cellList *cell;
char *aux;
long retour;

if (val == EMPTYTH)
   {
   printf("\ncellLoadTp : le modele %s n'est pas charge en memoire (cellLoad !)\n",name);
   exit(1);
   }
cell = (cellList *)val;

aux = (char *)mbkalloc(strlen(in) + 6);
if (type == LL)
   sprintf(aux,"tpll_%s",in);
else if (type == LH)
        sprintf(aux,"tplh_%s",in);
     else if (type == HL)
             sprintf(aux,"tphl_%s",in);
          else if (type == HH)
                  sprintf(aux,"tphh_%s",in);
               else
                  {
                  printf("\ncellLoadTp - error : mauvaise transition = %d pour l'entree %s de %s\n",type,in,name);
                  exit(1);
                  }
retour = searchGeneric(cell,name,aux);
#if MACHINE != pc
   mbkfree(aux);	/* chaine */
#endif
return retour;
}

/******************************************************************************/
/** appendChain: fait un append entre les deux listes l1 et l2, retourne l1 ***/
/******************************************************************************/
chain_list *appendChain(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;
}

/******************************************************************************/
/************************** createCell ****************************************/
/******************************************************************************/
void createCell(befigList)
befig_list *befigList;
{
befig_list *bList;
int numBus =0, numReg =0;
char *one = namealloc("'1'"); 
char *zero = namealloc("'0'"); 
char *high = namealloc("high"); 
char *low = namealloc("low"); 
char *buffer = namealloc("buffer"); 
cellList *c;

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

/* printf("*** elimination des cellules physiques non conformes ***\n"); */
for (bList = befigList; bList; bList = bList->NEXT)
   {
   if ( (!bList->BEOUT || bList->BEOUT->NEXT) &&
        (!bList->BEBUS || bList->BEBUS->NEXT ) )
      {
/*
      printf("  * %s * non conforme\n",bList->NAME);
*/
      bList->NAME = NULL;
      }
   }

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

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

   if (bList->NAME)
      {
		/* cellule conforme */
      cellList *cell = (cellList *)mbkalloc(sizeof(cellList));
      biabl_list *r,*b;
      Alist  *e;
      num_list *p;

		/* calcul du type et du nom logique */
      if (bList->BEBUS || bList->BEBUX)
         {
         cell->type = 'b';
         cell->nomlog= gensym("_bus",numBus++);
         }
      else
	if (ATOM(bList->BEOUT->ABL) &&
	    (VALUE_ATOM(bList->BEOUT->ABL) == one))
           {
			/* constante */
	   cell->type = 'c';
   	   cell->nomlog=high;
   	   }
	else if (ATOM(bList->BEOUT->ABL) &&
	            (VALUE_ATOM(bList->BEOUT->ABL) == zero))
		   {
			/* constante */
		   cell->type = 'c';
        	   cell->nomlog=low;
        	   }
     	        else if (ATOM(bList->BEOUT->ABL) && !(bList->BEREG)) 
		   	{
		   	cell->type = 't';	/* buffer ou retard */
             		cell->nomlog=buffer;
			}
         	     else if (bList->BEREG) 
      			     {
   				/* traitement des BDs*/
                             if (bList->BEREG->BIABL->USER)
                                {
					/* bascules D */
                                cell->type = 'd';
                                cell->nomlog = gensym("_bd",numReg++);
                                }
                             else
                                {
      			        cell->type = 'r';
      			        cell->nomlog= gensym("_reg",numReg++);
                                }
      			     }
      			  else
         		     {
         		     cell->type = 'l';
         		     cell->nomlog= identExpr((bList->BEOUT)->ABL);
         		     }
      cell->interface = initPort(bList->BEPOR);
      if (cell->type == 'l')
         cell->entrees = createAlist((Alist *)NULL,bList->BEOUT->ABL);
      else
         if (cell->type == 'b')
         {
         Alist *in = NULL;

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

              for(r = bList->BEREG->BIABL;r;r = r->NEXT)
	        {
	        in = createAlist(in,r->VALABL);
	        in = createAlist(in,r->CNDABL);
	        }
              cell->entrees = in;
              }
           else cell->entrees = initIn(bList->BERIN,bList->BEREG);
      cell->entrees = triOrdreInterface(cell->entrees,cell->interface);
      if (cell->type == 'b') 
         if (bList->BEBUS)
           cell->sorties = initOut((beout_list *)bList->BEBUS);
         else
            cell->sorties = initOut(bList->BEOUT);
      else 
         cell->sorties = initOut(bList->BEOUT);

      if (cell->type == 'l')		/* cellule logique */
      	{
	cell->val_abl = (biabl_list *)mbkalloc(sizeof(biabl_list));
	cell->val_abl->VALABL = normMappingExpr(bList->BEOUT->ABL); 
	addArite(cell->val_abl->VALABL);
	cell->val_abl->CNDABL = NULL; 
	cell->val_abl->NEXT = NULL; 
	cell->envel = copyExpr(cell->val_abl->VALABL);
   	cell->BDD = bList->BEOUT->NODE;
   	cell->circuit = bList->CIRCUI;
	}
      else
	{
	cell->envel = NULL;
   	cell->BDD = NULL;
   	cell->circuit = NULL;
	if (cell->type == 'r' || cell->type == 'd')
	   {
	   if ((nivNot(bList->BEOUT->ABL) != 0) || (lengthExpr(bList->BEOUT->ABL) != 1))
		printf("initCellList : Pb sur le champ BEOUT de la befig\n");
	   if (ATOM(bList->BEOUT->ABL))
           	cell->val_abl = reCopyBiabl(bList->BEREG->BIABL,0);
	   else cell->val_abl = reCopyBiabl(bList->BEREG->BIABL,1);
	   }
        else
           if (cell->type == 'b')
              if (bList->BEBUS)
	         cell->val_abl = reCopyBiabl(bList->BEBUS->BIABL,0);
              else
                 {
	         cell->val_abl = (biabl_list *)mbkalloc(sizeof(biabl_list));
	         cell->val_abl->VALABL = copyExpr(bList->BEOUT->ABL); 
	         addArite(cell->val_abl->VALABL);
	         cell->val_abl->CNDABL = NULL; 
	         cell->val_abl->NEXT = NULL; 
	         }
	   else
	      {
	      cell->val_abl = (biabl_list *)mbkalloc(sizeof(biabl_list));
	      cell->val_abl->VALABL = normMappingExpr(bList->BEOUT->ABL); 
	      addArite(cell->val_abl->VALABL);
	      cell->val_abl->CNDABL = NULL; 
	      cell->val_abl->NEXT = NULL; 
	      }
	}
      cell->generic = NULL;
      cell->resistance_tech = NULL;
      cell->surface_tech = NULL;
      cell->delais_tech = NULL;
      cell->capa_tech = NULL;
      addTH(NO_CELLTH,bList->NAME,(int)cell);
      recupGeneric(bList,cell);

		/* chainage des cellules logiques */
      cell->NEXT = NO_CELLS;
      NO_CELLS = cell;

		/* recherche des befig egales */
      for (behAux = bList->NEXT;behAux;behAux = behAux->NEXT)
          {
          if (behAux->NAME != NULL)
             {
			/* cas des cellules combinatoires */

             if (cell->type == 'l' && !behAux->BEREG && !behAux->BEBUS)
                {
                short porOK = 1;
                bepor_list *porList, *porAux;

                for(porList = bList->BEPOR, porAux = behAux->BEPOR;
                    porList && porAux;
                    porList = porList->NEXT, porAux = porAux->NEXT)
                   if (porList->NAME != porAux->NAME)
                      porOK = 0;
                if (porOK && (bList->BEOUT)->NODE == (behAux->BEOUT)->NODE)
                   { 
                   addTH(NO_CELLTH,behAux->NAME,(int)cell);
                   recupGeneric(behAux,cell);
                   behAux->NAME = NULL;
                   }
                }
             else
                if (proofBeh(behAux,bList,0,1) == 0)
                   {
                   addTH(NO_CELLTH,behAux->NAME,(int)cell);
                   recupGeneric(behAux,cell);
                   behAux->NAME = NULL;
                   }
             }
          }

     /* --- pour recuperer les GENERICS de la cellule par defaut ---- */

        if (cell->generic)
           {
	   cell->nom = findResistanceGen(cell);
	   cell->surface = searchGeneric(cell,cell->nom,"area");
	   cell->delais = findDelaisGen(cell,cell->nom,
				         resistance(cell,cell->nom)/10);

	   for(e = cell->entrees, p = cell->delais;
               p && e;
               e = e->NEXT, p = p->NEXT)
              e->ptChain = (chain_list *)p->DATA ; 
           if (cell->type == 'l')
	      {
	      calculEnvel(cell->envel);
	      triExpr(cell->envel,cell);
              }
           }
       }
   }
/*
if (NO_TRACE > 2)
   for(c = NO_CELLS; c; c = c->NEXT)
      displayCell(c);
*/
}

/*---------------------------------------------------------------------------
cellLoad	: charge une cellule en memoire.
-----------------------------------------------------------------------------
retour		: rien
---------------------------------------------------------------------------*/
short cellLoad(listeModel)
chain_list *listeModel;
{
chain_list *SLgetFile();
FILE *fic;
chain_list *l;
chain_list *listeCellules = NULL;
chain_list *filelib = (chain_list *)NULL;

PRINTF("Loading models ...");
for(l = listeModel; l; l = l->NEXT)
   {
   char *name = (char *)l->DATA;
   short nontrouve = 1;
   ptype_list *bibs;

   for(bibs = NO_CATA_LIB; bibs && nontrouve; bibs = bibs->NEXT)
      {
      char *rep = (char *)mbkalloc(strlen(name) + strlen((char *)bibs->DATA) 
                                   + 5);

      sprintf(rep,"%s/%s.vbe", (char *)bibs->DATA, name);
      if ((fic = fopen(rep,"r")))
         {
         chain_list *fileVbe = (chain_list *)NULL;

         nontrouve = 0;

         fclose(fic);

         if (bibs->TYPE == 0)
            {
            bibs->TYPE = 1;

            PRINTF(" in %s\n", (char *)bibs->DATA);

		/* chargement de toutes les cellules */
            fileVbe = SLgetFile((char *)bibs->DATA,"vbe");
            listeCellules = appendChain(listeCellules, fileVbe);
            }
         }
#if MACHINE != pc
      mbkfree(rep);
#endif
      }
   if (nontrouve == 1)
      {
      printf("\nERROR : Model %s not found in MBK_CATA_LIB\n", name);
#ifdef LAX
            return 0;
#else
            exit(-1) ;
#endif
      }
   }

for(filelib = listeCellules; filelib;filelib = filelib->NEXT)
   {
   compileVHDL((char *)(filelib->DATA),NULL,0,NULL,1,0,1,1,0,NULL,NULL);
   }
for(filelib = listeCellules; filelib;filelib = filelib->NEXT)
#ifndef leo
   mbkfree((char *)filelib->DATA);
#endif
freechain(listeCellules);

	/* creation des cellules logiques */
if (VHB_HEDFIG)
   createCell(VHB_HEDFIG);
else
   {
   printf("Pas de cellules compilees\n");
   exit(1);
   }

	/* FREE des Befig des modeles */
beh_frebefig(VHB_HEDFIG);
VHB_HEDFIG = NULL;
return 1;
}

/*---------------------------------------------------------------------------
cellInit	: initialise le systeme de chargement de cellules .
-----------------------------------------------------------------------------
retour		: rien
---------------------------------------------------------------------------*/
void cellInit()
{
initializeBdd(MEDIUM_BDD);

	/* creation de la TH des cellules deja chargees */
NO_CELLTH = createTH(100);
NO_CELLS = NULL;
}
