/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit :  synthese FPGA                                              */
/*    Fichier :  x3000.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"

/*----------------------------------------------------------------------------
costIntX3000	: fonction interne de cout des X3000 pour guider 
                  le re-odonnancement
------------------------------------------------------------------------------
retour		: un pointeur de liste chainee (support)
                  un cout (entier) -> par adresse
------------------------------------------------------------------------------*/
chain_list *costIntX3000(pt,pCount,pLstCLB4)
pNode pt;
int *pCount;
chain_list **pLstCLB4;
{
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 = costIntX3000(low,pCount,pLstCLB4);
lstHigh = costIntX3000(high,pCount,pLstCLB4);

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 (lenRes == SUPPORTMAX + 1)
         {
                        /* CLB 2 sorties */

         if (lenLow > 3 && lenHigh > 3)
            {
            low->mark = 1;
            ptInv = notBdd(low);
            ptInv->mark = 2; 

            high->mark = 1;
            ptInv = notBdd(high);
            ptInv->mark = 2; 

            *pCount = *pCount + 1;
            freechain(lstLow);
            freechain(lstHigh);
            freechain(res);
            res = addchain(NULL,high);
            res = addchain(res,low);
            res = addchain(res,pt->index);
            return(res);
            }
         }


                /* en cas d'egalite, on coupe celui qui a le plus
                   d'entrees primaires dans le support */
 
      if (lenLow == lenHigh)
         {
         chain_list *lc;
         int numInputLow = 0;
         int numInputHigh = 0;
            
         lc = lstLow;
         while (lc)
            {
            if ((long)lc->DATA < 1000)
               numInputLow++;
            lc = lc->NEXT;
            }
         lc = lstHigh;
         while (lc)
            {
            if ((long)lc->DATA < 1000)
               numInputHigh++;
            lc = lc->NEXT;
            }
         lenLow = numInputLow;
         lenHigh = numInputHigh;
         }  


      if (lenLow > lenHigh)
         {
			/* on cree un CLB pour low */

         if (regroupeCLB4(pLstCLB4,lstLow))
            *pCount = *pCount - 1;

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

res = costIntX3000(pt,&count,pLstCLB4);

if (res == NULL || (res->NEXT == NULL && pt->mark != 2))
   {
   if (res) freechain(res);
   return(count);
   }
else
   {
   if (countChain_list(res) < 5)
      {
      if (regroupeCLB4(pLstCLB4,res))
         count = count - 1;
      }

   pt->mark = 1;
   ptInv = notBdd(pt);
   ptInv->mark = 2; 
   return(1 + count);
   }
}

/*----------------------------------------------------------------------------
regroupeCLB4	: on regroupe les CLB 4 
                  Attention : res est desalloue si elle est fusionnee
------------------------------------------------------------------------------
retour		: 1 si possible, 0 sinon 
------------------------------------------------------------------------------*/
int regroupeCLB4(pLstCLB4,res)
chain_list **pLstCLB4;
chain_list *res;
{
int regroupe = 0;
chain_list *lst;
chain_list *lc;

lst = *pLstCLB4;
while (lst && (regroupe == 0))
   {
   chain_list *fusion;

   if (lst->DATA)
      {
      fusion = (chain_list *) fusionLC(res,lst->DATA);

			/* la fusion marche ... */

      if (countChain_list(fusion) < 6)
         {
         regroupe = 1;
         freechain(lst->DATA);
         freechain(res);
         lst->DATA = NULL;
         } 
      freechain(fusion);
      }
   lst = lst->NEXT;
   }
		/* pas de fusion possible, ... on ajoute */

if (regroupe == 0)
   {
   *pLstCLB4 = addchain(*pLstCLB4,res);
   }
return regroupe;
}

/*----------------------------------------------------------------------------
regroupeXMap	:  tries to match CLBs with support <= 4 from
                    a chain list             ------------------------------------------------------------------------------
retour		: one integer denoting the number of actual matchs 
------------------------------------------------------------------------------*/
int regroupeXMap(pLstCLB4)
chain_list *pLstCLB4;
{
int count = 0;
chain_list *plst = pLstCLB4;
 

while (plst)
   {
   chain_list *tete = plst->DATA;
   chain_list *suite = plst->NEXT;
   if (tete != NULL)
      {
      while (suite)
         {
          chain_list *fusion;
         if (suite->DATA)
            {
            fusion = (chain_list *) fusionLC(tete,suite->DATA); 
            if (countChain_list(fusion) < 6)
               {
/*d
                printf("J'announce le mariage de \n");
                printList(tete);
               printList(suite->DATA);
*/
                count++; 
                freechain(suite->DATA); 
               suite->DATA = NULL; 
               freechain(fusion);
               suite = NULL;
                }
             }
         if (suite != NULL)
            suite = suite->NEXT;
         }
      }
   plst = plst->NEXT;
   } 
return count;
}


/*-------------------------------------------------------------------------
costX3000Beh     : calcule le cout X3000 d'une befig 
---------------------------------------------------------------------------
retour          : un void.
---------------------------------------------------------------------------*/

void costX3000Beh(beh,numCLB,depthCLB)
befig_list *beh;
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;
chain_list *lstCLB4;
chain_list *tete;

*numCLB = 0;
*depthCLB = 0;
lstCLB4 = NULL;

markAllBdd(0);

if (FP_AUX)
   {
   aux = beh->BEAUX;
   while (aux) 
      {
      if (aux->NODE)
         {
         *numCLB = *numCLB + costX3000(aux->NODE,&lstCLB4);
         }
      aux = aux->NEXT;
      }
   }

out = beh->BEOUT;
while (out) 
   {
   if (out->NODE)
      {
      *numCLB = *numCLB + costX3000(out->NODE,&lstCLB4);
      }
   out = out->NEXT;
   }
reg = beh->BEREG;
while (reg) 
   {
   binode = reg->BINODE;
   while (binode)
      {
      if (binode->CNDNODE && binode->VALNODE)
         {
         *numCLB = *numCLB + costX3000(binode->VALNODE,&lstCLB4);
         *numCLB = *numCLB + costX3000(binode->CNDNODE,&lstCLB4);
         }
      binode = binode->NEXT;
      }
   reg = reg->NEXT;
   }
		/* desallocation de lstCLB4 */

tete = lstCLB4;
while (lstCLB4)
   {
   if (lstCLB4->DATA)
      freechain(lstCLB4->DATA);
   lstCLB4 = lstCLB4->NEXT;
   }
freechain(tete);
}
