/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit :  NetOptim & synthese logique                                */
/*    Fichier :  generic.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 : 03/08/1992     */
/*                                                                          */
/*    Modifie par : N. Dictus (Nouveaux generics SCLIB) le : 26/01/1993     */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*                                                                          */
/****************************************************************************/

	/* ATTENTION : fichier commun a logic et netoptim !!! */
	/* pour l'installation de NETOPTIM : remplacer 
                ../load/types_map.h par ../load/types_map.h 
                ../load/util.h par ../load/util.h */

#include <stdio.h>
#include MUT_H
#include LOG_H
#include BEH_H
#include "../load/types_map.h"
#include "../compil/lax_param.h"
#include "../synthe/sl_type.h"
#include "generic.h"
#include "../load/util.h"

/* --------------------------------------------------------------------------*/
/*  --------- FONCTIONS calculant les generics de la structure cellule logique,               a partir du champ generic --- */
/* --------------------------------------------------------------------------*/

/* ----------------------------------------------------------------------------
---- searchGeneric : pour une cellule logique (cell) et une de ses cellules
		physiques (cellPhy) retourne la valeur du generique name ------
---- return : un entier = valeur du generique ---------------------------------
-----------------------------------------------------------------------------*/
long searchGeneric(cell,cellPhy,name)
cellList *cell;
char *cellPhy;
char *name;
{
void *get;
void *value = NULL;
begen_list *gen;

	/* accede a la liste des generiques de cellPhy parmi toutes les
	   cellules de meme fonctionalite */

long ptype = searchPtype(cell->generic,namealloc(cellPhy));

if (ptype == 0)
   {
   PRINTF("\nsearchGeneric - error : no generics for physical cell %s\n",
           cellPhy);
   exit(-1);
   }

	/* accede au generic voulu pour cellPhy */

gen = (begen_list *)ptype;
while (gen)
   {
   if (!strcmp(gen->NAME,name))
      value = gen->VALUE;
   gen = gen->NEXT;
   }
if (!value)
   {
	/* Pas le generic recherche */
/*
   if (cell->type != 'b' && toto[0] != 't' )
      PRINTF("searchGeneric - warning : No generic '%s' for the cell %s (return 1)\n", toto, cellPhy);
*/
   return 1;
   }
return *(long *)value;
}

/*---------------------------------------------------------------------------
loadPolarity: retourne la polarite d'une cellule.
-----------------------------------------------------------------------------
retour          : NEG, POS ou AUT
---------------------------------------------------------------------------*/
int loadPolarity(cell)
cellList *cell;
{
chain_list *flatAbl;
int retour;

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);
   freeExpr(sansXor);
   }
else
   flatAbl = flatPolarityExpr(cell->val_abl->VALABL,1);
retour = polarityExpr(flatAbl);
freeExpr(flatAbl);
return retour;
}

/* ----------------------------------------------------------------------------
---- resistIn : pour une cellule logique (cell) et une de ses cellules
		physiques (nomPhy) retourne la resistance d'une entree (nameIn) 
---- return : un entier = valeur de la moyenne des resistances ----------------
-----------------------------------------------------------------------------*/
long resistIn(cell,nomPhy,nameIn)
cellList *cell;
char *nomPhy,*nameIn;
{
long som = 0;

if (!cell->entrees)
   return 0;
if (cell->type == 'r' || cell->type == 'd')
   {
   som += searchGeneric(cell,nomPhy,"rdown");
   som += searchGeneric(cell,nomPhy,"rup");
   }
else
   {
   char *aux = (char *)mbkalloc(7 + strlen(nameIn));

   sprintf(aux,"rdown_%s",nameIn);
   som += searchGeneric(cell,nomPhy,aux);

   sprintf(aux,"rup_%s",nameIn);
   som += searchGeneric(cell,nomPhy,aux);

#if MACHINE != pc
   mbkfree(aux);	/* attention PC */
#endif
   }
return som / 2;
}

/* ----------------------------------------------------------------------------
---- delaiIn : pour une cellule logique (cell) et une de ses cellules
		physiques (nomPhy) retourne le delai d'une entree (nameIn) ----
---- return : un entier = valeur de la moyenne des delais ---------------------
-----------------------------------------------------------------------------*/
long delaiIn(cell,nomPhy,nameIn)
cellList *cell;
char *nomPhy,*nameIn;
{
long delai = 0, del;
long compt = 0;
int polarite = loadPolarity(cell);
char *aux;

if (cell->type == 'r' || cell->type == 'd')
   return 1;
if (polarite == POS || polarite == AUT)
   {
   aux = (char *)mbkalloc(6 + strlen(nameIn));

   sprintf(aux,"tphh_%s",nameIn);
   if ((del = searchGeneric(cell,nomPhy,aux)) != 0)
      {
      compt++;
      delai += del;
      }
#if MACHINE != pc
   mbkfree((void *)aux);	/* chaine */
#endif

   aux = (char *)mbkalloc(6 + strlen(nameIn));
   sprintf(aux,"tpll_%s",nameIn);
   if ((del = searchGeneric(cell,nomPhy,aux)) != 0)
      {
      compt++;
      delai += del;
      }
#if MACHINE != pc
   mbkfree((void *)aux);	/* chaine */
#endif
   }
if (polarite == NEG || polarite == AUT)
   {
   aux = (char *)mbkalloc(6 + strlen(nameIn));
   sprintf(aux,"tplh_%s",nameIn);
   if ((del = searchGeneric(cell,nomPhy,aux)) != 0)
      {
      compt++;
      delai += del;
      }
#if MACHINE != pc
   mbkfree((void *)aux);	/* chaine */
#endif

   aux = (char *)mbkalloc(6 + strlen(nameIn));
   sprintf(aux,"tphl_%s",nameIn);
   if ((del = searchGeneric(cell,nomPhy,aux)) != 0)
      {
      compt++;
      delai += del;
      }
#if MACHINE != pc
   mbkfree((void *)aux);	/* chaine */
#endif
   }
if (delai && compt)		/* en betonne... */
  return delai / compt;

return 1;
}

/* ----------------------------------------------------------------------------
---- findDelaisGen : pour une cellule logique (cell) et une de ses cellules
		physiques (nomPhy) retourne la liste des delais ---------------
---- return : un pointeur de num_list = liste delais dans l'ordre des entrees -
-----------------------------------------------------------------------------*/
num_list *findDelaisGen(cell,nomPhy,resist)
cellList *cell;
char *nomPhy;
int resist;
{
/*
if (!cell->entrees || cell->type == 'r' || cell->type == 'd')
   return NULL;
else
  {
*/
  num_list *head = NULL;
  Alist *in;

  for(in = cell->entrees;in;in = in->NEXT)
     if (resist)
        head = addnum(head,delaiIn(cell,nomPhy,in->name) + 
                           (150 * resistIn(cell, nomPhy, in->name))/1000);
     else
        head = addnum(head,delaiIn(cell,nomPhy,in->name));
  return (num_list *)reverse((chain_list *)head);
}

/* ----------------------------------------------------------------------------
---- findCapaGen : pour une cellule logique (cell) et une de ses cellules
		physiques (nomPhy) retourne la liste des capas ---------------
---- return : un pointeur de num_list = liste capas dans l'ordre des entrees -
-----------------------------------------------------------------------------*/
num_list *findCapaGen(cell,nomPhy)
cellList *cell;
char *nomPhy;
{
if (!cell->entrees) return NULL;
else
  {
  num_list *head = NULL;
  Alist *in;

  for(in = cell->entrees;in;in = in->NEXT)
     {
     char *aux = (char *)mbkalloc(6 + strlen(in->name));
  
     sprintf(aux,"cin_%s",in->name);
     head = addnum(head,searchGeneric(cell,nomPhy,aux));
#if MACHINE != pc
     mbkfree(aux);	/* chaine */
#endif
     }
  return (num_list *)reverse((chain_list *)head);
  }
}
/* ----------------------------------------------------------------------------
---- resistance : pour une cellule logique (cell) et une de ses cellules
		physiques (nomPhy) retourne la resistance = moyenne des 
                resistances des entrees                                    ----
---- return : un entier = valeur de la resistance -----------------------------
-----------------------------------------------------------------------------*/
int resistance (cell,nomPhy)
cellList *cell;
char *nomPhy;
{
if (!cell->entrees || cell->type == 'r' || cell->type == 'd') 
   return 0;
else
   {
   Alist *in;
   int som = 0;
   int max = 0;

   for(in = cell->entrees;in;in = in->NEXT)
      {
      char *aux = (char *)mbkalloc(7 + strlen(in->name));

      sprintf(aux,"rdown_%s",in->name);
      som = searchGeneric(cell,nomPhy,aux);
      if (som > max) max = som;

      sprintf(aux,"rup_%s",in->name);
      som = searchGeneric(cell,nomPhy,aux);
      if (som > max) max = som;

#if MACHINE != pc
      mbkfree(aux);	/* chaine */
#endif
      }

   return max;
   }
}

/* ----------------------------------------------------------------------------
---- findResistanceGen : pour une cellule logique (cell) retourne le nom de la
 		cellule physiques la plus resistive ---------------------------
---- return : un char * = nom d'une cellule physique --------------------------
-----------------------------------------------------------------------------*/
char *findResistanceGen(cell)
cellList *cell;
{
ptype_list *gen;
char *nameMax = NULL; 
int RMax = 0, Rres;
int AMin = 1000000, Ares;

for(gen = cell->generic;gen;gen = gen->NEXT)
   {
   if ((Ares = searchGeneric(cell,(char *)(gen->DATA),"area")) < AMin)
      {
      AMin = Ares;
      nameMax = (char *)gen->DATA;
      }
   else
      {
      if (Ares == AMin)
         {
         if ((Rres = resistance(cell,(char *)(gen->DATA))) > RMax)
            {
            RMax = Rres;
            nameMax = (char *)gen->DATA;
            }
         }
      }
   }
if (nameMax == NULL && CDR(cell->generic))
   {
   PRINTF("Mapping SC : Error - logic cannot find the default cell\n");
   PRINTF("             for the %s\n\n",cell->nomlog);
   exit(-1);
   }
return nameMax;
}

/******************************************************************************/
/************** recupGeneric : met a jour les champs delais_tech, capa_tech,
 surface_tech et resistance_tech pour une nouvelle cellule physique ***********/
/******************************************************************************/
void recupGeneric(beh,cell)
befig_list *beh;
cellList *cell;
{
tabNumList *d_tech,*c_tech;

if (!beh->BEGEN)
   {
   fprintf(stderr, "recupGeneric : No field BEGEN in befig : %s!\n",beh->NAME);
   return;
   }
else
   {
   long fanout = 1;
   long maxdel = 1;
   Alist *in;
   begen_list *gen;
   ptype_list *bidon;
   long *pval;
   long res;

		/* surface calculee en pitches */
   for(gen = beh->BEGEN; gen; gen = gen->NEXT)
      if (gen->NAME == namealloc("area"))
      {
	 if (*(long *)gen->VALUE >= 252)
	 {
	    pval = (long *) mbkalloc (sizeof(long));
            *pval = *(long *)gen->VALUE / (42 * 6);
	    mbkfree(gen->VALUE);
            gen->VALUE = (void *)pval;
	 }
      }

	/* ajout des generics au champ generic de la cellule */
   cell->generic = addptype(cell->generic,(long)beh->BEGEN,(void *)beh->NAME);

	/***************** calcul du fanout (04/02/93) *****************/

   pval = (long *) mbkalloc (sizeof(long));
   if ((cell->type != 'r') && (cell->type != 'd') && (cell->entrees))
      for(in = cell->entrees;in;in = in->NEXT)
         {
         char *aux = (char *)mbkalloc(7 + strlen(in->name));

         sprintf(aux,"rdown_%s",in->name);
         if ((res = searchGeneric(cell,beh->NAME,aux)) > fanout)
            fanout = res;

#if MACHINE != pc
         mbkfree(aux);
#endif
         aux = (char *)mbkalloc(7 + strlen(in->name));
         sprintf(aux,"rup_%s",in->name);
         if ((res = searchGeneric(cell,beh->NAME,aux)) > fanout)
            fanout = res;
#if MACHINE != pc
         mbkfree(aux);
#endif
            }
   else
      {
      if ((res = searchGeneric(cell,beh->NAME,"rdown")) > fanout)
         fanout = res;

      if ((res = searchGeneric(cell,beh->NAME,"rup")) > fanout)
         fanout = res;
      }

   *pval = (long)700000 / fanout;

   (cell->generic)->TYPE = (long)beh_addbegen(beh->BEGEN, "fanout", "natural", (void *)pval);


		/* Suppression des generics  dans la befig */
		/* pour pouvoir faire un FREE des cellules */
   bidon = getptype(beh->USER,BEH_GENERIC);
   if (bidon) bidon->DATA = NULL;
   beh->BEGEN = NULL;
   }

d_tech = (tabNumList *)mbkalloc(sizeof(tabNumList));
d_tech->name = beh->NAME;
d_tech->ptNum = findDelaisGen(cell,beh->NAME,0);
d_tech->NEXT = cell->delais_tech;
cell->delais_tech = d_tech;

c_tech = (tabNumList *)mbkalloc(sizeof(tabNumList));
c_tech->name = beh->NAME;
c_tech->ptNum = findCapaGen(cell,beh->NAME);
c_tech->NEXT = cell->capa_tech;
cell->capa_tech = c_tech;
	 
cell->resistance_tech = addptype(cell->resistance_tech,
                                 (long)resistance(cell,beh->NAME),
                                 (void *)beh->NAME);

cell->surface_tech = addptype(cell->surface_tech,
                              searchGeneric(cell,beh->NAME,"area"),
                              (void *)beh->NAME);
}

/******************************************************************************/
/****** getDelai : renvoie le delai d'une expression (moyenne des entrees) ****/
/******************************************************************************/
long getDelai(cell,expr)
cellList	*cell;
chain_list	*expr;

{
Alist *searchAlist();

if (ATOM(expr))
	return (long)(searchAlist(cell->entrees,VALUE_ATOM(expr)) ->ptChain);
else
	{
	int	tot = 0,nb;
	chain_list *arg;

	for(arg = CDR(expr),nb = 0;arg;arg = arg->NEXT,nb++)
		tot += getDelai(cell,CAR(arg));
	return tot / nb;
	}
}

/*------------------------------------------------------------------
  IDENT : triExpr
  ------------------------------------------------------------------
  FUNCTION : trie les arguments d'une expression en fonction des delais
  croissants sur tous les niveaux.
  ------------------------------------------------------------------ */

void triExpr(expr,cell)
chain_list *expr;
cellList *cell;

{
chain_list *expr1;
int okPermu = 1;

if (!ATOM(expr))		/* ce n'est pas un atome */
   {
   chain_list *arg;

   if (ARITE(expr))
   while (okPermu)
      {
      expr1 = CDR(expr);
      okPermu = 0;
      while (CDR(expr1))
          {
          if (getDelai(cell,CAR(expr1)) > getDelai(cell,CADR(expr1)))
             {
             chain_list *permu;

             permu = CAR(expr1);
             expr1->DATA = (void *)CADR(expr1);
             (expr1->NEXT)->DATA = (void *)permu;
             okPermu = 1;
             }
          expr1 = CDR(expr1);
          }
      }
   for(arg = CDR(expr);arg;arg = arg->NEXT)
	triExpr(CAR(arg),cell);
   }
}

/******************************************************************************/
/*** okInterface : verifie l'interface des entrees-sorties    d'une cellule ***/
/******************************************************************************/
short okInterface(beh,cell)
befig_list *beh;
cellList *cell;
{
berin_list	*i;
beout_list	*o;
Alist		*e;
chain_list 	*s;

		/* input */

for (i = beh->BERIN,e = cell->entrees; i && e; i = i->NEXT,e = e->NEXT)
	if (i->NAME != e->name)
	   { 
	   PRINTF("Erreur dans les entrees\n");
	   return(0);
	   }

		/* output */

for (o = beh->BEOUT,s = cell->sorties; o && s; o = o->NEXT,s = s->NEXT)
	if (o->NAME != (char *)s->DATA)
	   { 
	   PRINTF("Erreur dans les sorties\n");
	   return(0);
	   }
return(1);
}

/******************************************************************************/
/*** memberChain_list : teste l'appartenance a une chain_list *****************/
/******************************************************************************/
chain_list *memberChain_list(data,chaine)
void *data;
chain_list *chaine;
{
chain_list *r;

for(r = chaine;r;r = CDR(r))
	if (data == r->DATA) return r;
return NULL;
}

/******************************************************************************/
/*** member : teste l'appartenance d'une entree aux registres *****************/
/******************************************************************************/
short member(in,regList)
char *in;
bereg_list *regList;
{
bereg_list *r;

for(r = regList;r;r = r->NEXT)
	if (strcmp(in,r->NAME) == 0) return 1;
return 0;
}

/******************************************************************************/
/*** initPort    							    ***/
/******************************************************************************/
Alist *initPort(portList)
bepor_list *portList;
{
Alist *head = NULL,*aux;

   do
   {
        
	aux = (Alist *)mbkalloc(sizeof(Alist));
	aux->name = portList->NAME;
	aux->ptChain = NULL; 
	aux->NEXT = head;
	head = aux;
   }
   while (portList = CDR(portList));
   return head;
}

/******************************************************************************/
/*** initIn : initialise la liste des entrees de la nouvelle cellule logique */
/******************************************************************************/
Alist *initIn(inList,regList)
berin_list *inList;
bereg_list *regList;

{
berin_list *i;
Alist *headIn = NULL;

for(i = inList;i;i = i->NEXT)
	{
	Alist *auxIn;

	if ((i->NAME == namealloc("vss")) || 
            (i->NAME == namealloc("vdd")) || 
            (member(i->NAME,regList))) 
          continue;
	auxIn = (Alist *)mbkalloc(sizeof(Alist));
	auxIn->name = i->NAME;
	auxIn->ptChain = NULL; 
	auxIn->NEXT = headIn;
	headIn = auxIn;
	}
return headIn;
}

/******************************************************************************/
/*** initOut : initialise la liste des sorties de la nouvelle cellule logique */
/******************************************************************************/
chain_list *initOut(outList)
beout_list *outList;

{
if (!outList)
   return (chain_list *)NULL;
else
   {
   chain_list *auxOut;

   auxOut = addchain(initOut(outList->NEXT),(void *)outList->NAME);
   return auxOut;
   }
}

/******************************************************************************/
/*** Commut : calcul la commutativite au premier niveau ***/
/******************************************************************************/
short commut(exp)
chain_list	*exp;

{
chain_list *prem_arg;

if (OPER(exp) == NOT) return 0;

exp = CDR(exp);
prem_arg = CAR(exp);

while (exp = CDR(exp))
   if (!equalVarExpr(prem_arg,CAR(exp)))
      return 0;
return 1;
} 

/******************************************************************************/
/*** calculEnvel : calcul de la commutativite a tous les niveaux **************/
/******************************************************************************/
void calculEnvel(expr)
chain_list *expr;
{
if (!ATOM(expr))
   {
   chain_list *sup = supportChain_listExpr(expr);
   short nbre = lengthExpr(sup) + 1;

   freechain(sup);
   if (nbre < numberAtomExpr(expr))
      return;

   ((chain_list *)(expr->DATA))->NEXT = (chain_list *)commut(expr);
   while (expr = CDR(expr))
      calculEnvel(CAR(expr)); 
   }
}

/******************************************************************************/
/************** reCopyBiabl : recopie un Biabl recursivement ******************/
/******************************************************************************/
biabl_list *reCopyBiabl(biabl,n)
biabl_list *biabl;
short n;	/* si n=1 valabl est innverse */

{
if (biabl == NULL)
   return (biabl_list *)NULL;
else
   {
   biabl_list *biablAux = (biabl_list *) mbkalloc (sizeof(biabl_list));

   biablAux->VALABL = copyExpr(biabl->VALABL);
   if (n == 1) 
      biablAux->VALABL = notExpr(biablAux->VALABL);
   biablAux->CNDABL = copyExpr(biabl->CNDABL);
   addArite(biablAux->VALABL);
   addArite(biablAux->CNDABL);
   biablAux->NEXT = reCopyBiabl(biabl->NEXT,n);
   return biablAux;
   }
}

Alist *triOrdreInterface(entrees,interface)
Alist *entrees,*interface;
{
Alist *aux,*tri = NULL;

for(aux = interface;aux;aux = aux->NEXT)
   if (searchAlist(entrees,aux->name))
	{
	Alist *ptTL = (Alist *)mbkalloc(sizeof(Alist));

	ptTL->name = aux->name;
	ptTL->ptChain= NULL;
	ptTL->NEXT = tri;
	tri = ptTL;
	}
return (Alist *)reverse((chain_list *)tri);
}

/*************************************************************************/
/* IDENT :	mirrorExpr						 */
/* 		effectue un reverse a tous les niveaux de l'expression   */
/* RETURN :	void (expression modifiee physiquement)			 */
/*************************************************************************/
void mirrorExpr(expr)
chain_list *expr;
{
   expr->NEXT = (chain_list *)reverse(CDR(expr));
   while (expr = CDR(expr)) mirrorExpr(CAR(expr));
}

/******************************************************************************/
/***** normMappingExpr ***/
/******************************************************************************/
chain_list *normMappingExpr(expr)
chain_list *expr;
{
chain_list *e,*ep;

   mirrorExpr(expr);
   e = copyExpr(expr);
   flatArityExpr(e);
   if (searchOperExpr(e,NOT))
      {
      if (!searchOperExpr(e,XOR))
         {
         ep = flatPolarityExpr(e,1);
         freeExpr(e);
/* ajout 30/07/93 */
 	 if (searchOperExpr(ep,NOT))
            {
            e = notExpr(flatPolarityExpr(ep,0) );
            freeExpr(ep);
	    ep = e;
            }
/**/
   	 flatArityExpr(ep);
         return(ep); 
         } 
      else
         return(e);
      }
   else
      return(e);
}

