/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit :  synthese FPGA                                              */
/*    Fichier :  cost.c                                                     */
/*                                                                          */
/*    (c) copyright 1991 Laboratoire MASI equipe CAO & VLSI                 */
/*    Tous droits reserves                                                  */
/*    Support : e-mail cao-vlsi@masi.ibp.fr                                 */
/*                                                                          */
/*    Auteur(s) :  Eudes Prado Lopes                       le : 20 /10/1993 */
/*                                                                          */
/*    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 "../compil/sl_util.h"
#include "../bddorder/bdd_order.h"
#include "fp_type.h"
#include "fpga.h"

/*----------------------------------------------------------------------------
costIntFPGA	: fonction interne de cout des FPGA pour guider 
                  le re-odonnancement
------------------------------------------------------------------------------
retour		: un pointeur de liste chainee (support)
                  un cout (entier) -> par adresse
------------------------------------------------------------------------------*/
chain_list *costIntFPGA(pt,pCount)
pNode pt;
int *pCount;
{
chain_list *lstLow, *lstHigh;
chain_list *res;
int lenRes;
pNode pBdd, low, high;

if (pt->index < 2)	/* noeud terminal */
   return (NULL);

if ((pt->low)->index < 2 && (pt->high)->index < 2)	/* noeud atomique */
   {
   return(addchain(NULL,pt->index));
   }

			/* noeud deja traite */

if (pt->mark == 1)	/* CLB de fonction directe */
   {
   return(addchain(NULL,pt));
   }

if (pt->mark == 2)	/* CLB de fonction inverse */
   {
   return(addchain(NULL,notBdd(pt)));
   }

		/* simplifications eventuelles avant l'appel
                   recursif sur les fils */

if (RULES_DC)
   {
   pBdd = applyBinBdd(AND,pt->high,pt->low);

   if (pBdd == pt->low)
      high = simplifDcOneBdd(pt->high,pt->low);
   else
      high = pt->high;

   if (pBdd == pt->high)
      low = simplifDcOneBdd(pt->low,pt->high);
   else
      low = pt->low;
   }
else
   {
   high = pt->high;
   low = pt->low;
   }

lstLow = costIntFPGA(low,pCount);
lstHigh = costIntFPGA(high,pCount);

while (1)
   {
   pNode ptInv;
   chain_list *toto;

	 /* fusion lexico-graphique des listes chainees */	

   res = (chain_list *) fusionLC(lstLow,lstHigh);

   lenRes = countChain_list(res);

   if (lenRes < SUPPORTMAX)
      {
      freechain(lstLow);
      freechain(lstHigh);
      return(addchain(res,pt->index));
      }
   if (lenRes == SUPPORTMAX)	/* CLB */
      {
      freechain(lstLow);
      freechain(lstHigh);
      freechain(res);
      pt->mark = 1;
      ptInv = notBdd(pt);
      ptInv->mark = 2; 
      *pCount = *pCount + 1;
      return(addchain(NULL,pt));
      }
   if (lenRes > SUPPORTMAX)	/* on coupe un fils */
      {
      int lenHigh, lenLow;

      lenLow  = countChain_list(lstLow);
      lenHigh = countChain_list(lstHigh);

      if (countChain_list(lstLow) > countChain_list(lstHigh))
         {
			/* on cree un CLB pour low */

         low->mark = 1;
         ptInv = notBdd(low);
         ptInv->mark = 2; 
         *pCount = *pCount + 1;
         freechain(lstLow);
         freechain(res);
         lstLow = addchain(NULL,low);
         }
      else
			/* on cree un CLB pour high */
         {
         high->mark = 1;
         ptInv = notBdd(high);
         ptInv->mark = 2; 
         *pCount = *pCount + 1;
         freechain(lstHigh);
         freechain(res);
         lstHigh = addchain(NULL,high);
         }
      }
   }
}
/*----------------------------------------------------------------------------
costFPGA	: fonction de cout des FPGA pour guider le re-odonnancement
------------------------------------------------------------------------------
retour		: un cout (entier)
------------------------------------------------------------------------------*/
int costFPGA(pt)
pNode pt;
{
chain_list *res;
pNode ptInv;
int count = 0;		/* nombre de CLB utilises */

res = costIntFPGA(pt,&count);
if (res == NULL || (res->NEXT == NULL && pt->mark != 2))
   {
   if (res) freechain(res);
   return(count);
   }
else
   {
   freechain(res);
   pt->mark = 1;
   ptInv = notBdd(pt);
   ptInv->mark = 2; 
   return(1 + count);
   }
}

/*-------------------------------------------------------------------------
costFpgaBeh 	: calcule le cout FPGA d'une befig 
---------------------------------------------------------------------------
retour		: un void.
---------------------------------------------------------------------------*/
void costFpgaBeh(beh,func,numCLB,depthCLB)
befig_list *beh;
int (*func)();
int *numCLB;
int *depthCLB;
{
beout_list *out;
beaux_list *aux;
bereg_list *reg;
bebus_list *bus;
bebux_list *bux;
binode_list *binode;
biabl_list *biabl;

*numCLB = 0;
*depthCLB = 0;

markAllBdd(0);

if (FP_AUX)
   {
   aux = beh->BEAUX;
   while (aux) 
      {
      if (aux->NODE)
         {
         *numCLB = *numCLB + (int)(*func)(aux->NODE);
         }
      aux = aux->NEXT;
      }
   }

out = beh->BEOUT;
while (out) 
   {
   if (out->NODE)
      {
      *numCLB = *numCLB + (int)(*func)(out->NODE);
      }
   out = out->NEXT;
   }

reg = beh->BEREG;
while (reg) 
   {
   binode = reg->BINODE;
   while (binode)
      {
      if (binode->CNDNODE && binode->VALNODE)
         {
         *numCLB = *numCLB + (int)(*func)(binode->VALNODE);
         *numCLB = *numCLB + (int)(*func)(binode->CNDNODE);
         }
      binode = binode->NEXT;
      }
   reg = reg->NEXT;
   }
}

