#ifdef SYSTEMC
/*
 * $Id: Free_List_unit_transition.cpp 112 2009-03-18 22:36:26Z rosiere $
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_OOO_Engine/OOO_Engine/Rename_unit/Register_translation_unit/Free_List_unit/include/Free_List_unit.h"

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_ooo_engine {
namespace ooo_engine {
namespace rename_unit {
namespace register_translation_unit {
namespace free_list_unit {


#undef  FUNCTION
#define FUNCTION "Free_List_unit::transition"
  void Free_List_unit::transition (void)
  {
    log_begin(Free_List_unit,FUNCTION);
    log_function(Free_List_unit,FUNCTION,_name.c_str());

    if (PORT_READ(in_NRESET) == 0)
      {
	_priority_gpr->reset();
	_priority_spr->reset();

	for (uint32_t i=0; i<_param->_nb_bank; i++)
	  {
	    _gpr_list[i].clear();
	    _spr_list[i].clear();
	  }
      }
    else
      {
	_priority_gpr->transition();
	_priority_spr->transition();

	// ==================================================
	// =====[ POP ]======================================
	// ==================================================
	for (uint32_t i=0; i<_param->_nb_pop; i++)
	  if (PORT_READ(in_POP_VAL[i]) and internal_POP_ACK [i])
	    {
              log_printf(TRACE,Free_List_unit,FUNCTION,"  * POP [%d]",i);

#ifdef STATISTICS
              if (usage_is_set(_usage,USE_STATISTICS))
                (*_stat_nb_inst_pop) ++;
#endif

	      if (PORT_READ(in_POP_GPR_VAL [i]))
                {
#ifdef STATISTICS
                  if (usage_is_set(_usage,USE_STATISTICS))
                    (*_stat_nb_inst_pop_gpr) ++;
#endif
                  _gpr_list [internal_POP_GPR_BANK[i]].pop_front();
                }
	 
	      if (PORT_READ(in_POP_SPR_VAL [i]))
                {
#ifdef STATISTICS
                  if (usage_is_set(_usage,USE_STATISTICS))
                    (*_stat_nb_inst_pop_spr) ++;
#endif
                  _spr_list [internal_POP_SPR_BANK[i]].pop_front();
                }
	    }

	// ==================================================
	// =====[ PUSH_GPR ]=================================
	// ==================================================
	for (uint32_t i=0; i<_param->_nb_push; i++)
	  if (PORT_READ(in_PUSH_GPR_VAL[i]) and internal_PUSH_GPR_ACK [i])
            {
              log_printf(TRACE,Free_List_unit,FUNCTION,"  * PUSH_GPR[%d]",i);
              log_printf(TRACE,Free_List_unit,FUNCTION,"    * bank    : %d",internal_PUSH_GPR_BANK[i]);
              log_printf(TRACE,Free_List_unit,FUNCTION,"    * num_reg : %d",PORT_READ(in_PUSH_GPR_NUM_REG [i]));

#ifdef STATISTICS
              if (usage_is_set(_usage,USE_STATISTICS))
                (*_stat_nb_inst_push_gpr) ++;
#endif

              _gpr_list [internal_PUSH_GPR_BANK[i]].push_back(PORT_READ(in_PUSH_GPR_NUM_REG [i]));
            }
	// ==================================================
	// =====[ PUSH_SPR ]=================================
	// ==================================================
	for (uint32_t i=0; i<_param->_nb_push; i++)
	  if (PORT_READ(in_PUSH_SPR_VAL[i]) and internal_PUSH_SPR_ACK [i])
            {
              log_printf(TRACE,Free_List_unit,FUNCTION,"  * PUSH_SPR[%d]",i);
              log_printf(TRACE,Free_List_unit,FUNCTION,"    * bank    : %d",internal_PUSH_SPR_BANK[i]);
              log_printf(TRACE,Free_List_unit,FUNCTION,"    * num_reg : %d",PORT_READ(in_PUSH_SPR_NUM_REG [i]));

#ifdef STATISTICS
              if (usage_is_set(_usage,USE_STATISTICS))
                (*_stat_nb_inst_push_spr) ++;
#endif

              _spr_list [internal_PUSH_SPR_BANK[i]].push_back(PORT_READ(in_PUSH_SPR_NUM_REG [i]));
            }

#ifdef STATISTICS
        if (usage_is_set(_usage,USE_STATISTICS))
          for (uint32_t i=0; i<_param->_nb_bank; ++i)
            {
              
              (*(_stat_bank_gpr_nb_elt [i])) += _gpr_list[i].size();
              (*(_stat_bank_spr_nb_elt [i])) += _spr_list[i].size();
            }
#endif

#if (DEBUG >= DEBUG_TRACE) and (DEBUG_Free_List_unit == true)
        {
          uint32_t limit = 4;
      
          log_printf(TRACE,Free_List_unit,FUNCTION,"  * Dump Free List");
          for (uint32_t i=0; i<_param->_nb_bank; ++i)
            {
              log_printf(TRACE,Free_List_unit,FUNCTION,"    * GPR [%d] - NB_ELT : %d",i,_gpr_list[i].size());

              uint32_t j=0;
              for (std::list<Tgeneral_address_t>::iterator it=_gpr_list[i].begin();
                   it!=_gpr_list[i].end();
                   )
                {
                  std::string str = "";
              
                  for (uint32_t x=0; x<limit; x++)
                    {
                      if (it==_gpr_list[i].end())
                        break;
                      else
                        str+=toString("GPR[%.4d][%.4d] : %.5d | ",i,j,*it);
                      ++it;
                      ++j;
                    }
                  log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"      * %s",str.c_str());
                }
            }

          for (uint32_t i=0; i<_param->_nb_bank; ++i)
            {
              log_printf(TRACE,Free_List_unit,FUNCTION,"    * SPR [%d] - NB_ELT : %d",i,_spr_list[i].size());

              uint32_t j=0;
              for (std::list<Tspecial_address_t>::iterator it=_spr_list[i].begin();
                   it!=_spr_list[i].end();
                   )
                {
                  std::string str = "";

                  for (uint32_t x=0; x<limit; x++)
                    {
                      if (it==_spr_list[i].end())
                        break;
                      else
                        str+=toString("SPR[%.4d][%.4d] : %.5d | ",i,j,*it);
                      ++it;
                      ++j;
                    }
                  log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"      * %s",str.c_str());
                }
            }
        }
#endif

#ifdef DEBUG_TEST
        if (1)
          for (uint32_t i=0; i<_param->_nb_bank; ++i)
            {
            for (std::list<Tgeneral_address_t>::iterator it1=_gpr_list[i].begin();
                 it1!=_gpr_list[i].end();
                 ++it1
                 )
              {
                std::list<Tgeneral_address_t>::iterator it2 = it1;

                it2 ++;
                while (it2 != _gpr_list[i].end())
                  {
                    if (*it1 == *it2)
                      throw ERRORMORPHEO (FUNCTION,toString(_("In free list, Same GPR (%d)"),*it1));
                    it2 ++;
                  }
              }

            for (std::list<Tspecial_address_t>::iterator it1=_spr_list[i].begin();
                 it1!=_spr_list[i].end();
                 ++it1
                 )
              {
                std::list<Tspecial_address_t>::iterator it2 = it1;

                it2 ++;
                while (it2 != _spr_list[i].end())
                  {
                    if (*it1 == *it2)
                      throw ERRORMORPHEO (FUNCTION,toString(_("In free list, Same SPR (%d)"),*it1));
                    it2 ++;
                  }
              }
          }
#endif

      }

#if defined(STATISTICS) or defined(VHDL_TESTBENCH)
    end_cycle ();
#endif

    log_end(Free_List_unit,FUNCTION);
  };

}; // end namespace free_list_unit
}; // end namespace register_translation_unit
}; // end namespace rename_unit
}; // end namespace ooo_engine
}; // end namespace multi_ooo_engine
}; // end namespace core

}; // end namespace behavioural
}; // end namespace morpheo              
#endif
