#ifdef SYSTEMC
/*
 * $Id: Stat_List_unit_transition.cpp 123 2009-06-08 20:43:30Z rosiere $
 *
 * [ Description ]
 * 
 */

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

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


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

    if (PORT_READ(in_NRESET) == 0)
      {
	uint32_t gpr = 0;
	uint32_t spr = 0;
	
	for (uint32_t i=0; i<_param->_nb_bank; i++)
	  {
	    for (uint32_t j=0; j<_param->_nb_general_register_by_bank; j++)
	      gpr_stat_list [i][j].reset((gpr++)<_param->_nb_gpr_use_init);
	    for (uint32_t j=0; j<_param->_nb_special_register_by_bank; j++)
	      spr_stat_list [i][j].reset((spr++)<_param->_nb_spr_use_init);
	  }
	reg_GPR_PTR_FREE = 0;
	reg_SPR_PTR_FREE = 0;
      }
    else
      {
#ifdef DEBUG_TEST
        {
          uint32_t free_list_nb_gpr_free     = PORT_READ(in_INFO_NB_GPR_FREE);
          uint32_t free_list_nb_spr_free     = PORT_READ(in_INFO_NB_SPR_FREE);
          uint32_t stat_list_nb_gpr_free     = 0;
          uint32_t stat_list_nb_spr_free     = 0;
          uint32_t stat_list_nb_gpr_can_free = 0;
          uint32_t stat_list_nb_spr_can_free = 0;
          uint32_t stat_list_nb_gpr_link     = 0;
          uint32_t stat_list_nb_spr_link     = 0;
          uint32_t stat_list_nb_gpr_use      = 0;
          uint32_t stat_list_nb_spr_use      = 0;

          for (uint32_t i=0; i<_param->_nb_bank; i++)
            {
              for (uint32_t j=0; j<_param->_nb_general_register_by_bank; j++)
                {
                  if (gpr_stat_list [i][j]._is_free)
                    stat_list_nb_gpr_free ++;
                  if (gpr_stat_list [i][j]._is_link)
                    stat_list_nb_gpr_link ++;
                  if (gpr_stat_list [i][j]._is_use)
                    stat_list_nb_gpr_use ++;
                  if (gpr_stat_list [i][j].can_free())
                    stat_list_nb_gpr_can_free ++;
                }
              for (uint32_t j=0; j<_param->_nb_special_register_by_bank; j++)
                {
                  if (spr_stat_list [i][j]._is_free)
                    stat_list_nb_spr_free ++;
                  if (spr_stat_list [i][j]._is_link)
                    stat_list_nb_spr_link ++;
                  if (spr_stat_list [i][j]._is_use)
                    stat_list_nb_spr_use ++;
                  if (spr_stat_list [i][j].can_free())
                    stat_list_nb_spr_can_free ++;
                }
            }

          uint32_t  nb_gpr_free = stat_list_nb_gpr_free+stat_list_nb_gpr_can_free;
          uint32_t  nb_spr_free = stat_list_nb_spr_free+stat_list_nb_spr_can_free;
          uint32_t _nb_gpr_free = (_param->_nb_general_register - _param->_nb_gpr_use_init); 
          uint32_t _nb_spr_free = (_param->_nb_special_register - _param->_nb_spr_use_init); 
          uint32_t  nb_gpr_link = stat_list_nb_gpr_link - _param->_nb_gpr_use_init;
          uint32_t  nb_spr_link = stat_list_nb_spr_link - _param->_nb_spr_use_init;
          uint32_t  nb_gpr_use  = stat_list_nb_gpr_use - _param->_nb_gpr_use_init;
          uint32_t  nb_spr_use  = stat_list_nb_spr_use - _param->_nb_spr_use_init;

          log_printf(TRACE,Stat_List_unit,FUNCTION,"  * nb_gpr_free : stat_list %d - free_list %d - free %d, link %d (%d), use %d (%d)",stat_list_nb_gpr_free,free_list_nb_gpr_free,nb_gpr_free,nb_gpr_link,stat_list_nb_gpr_link,nb_gpr_use,stat_list_nb_gpr_use);
          log_printf(TRACE,Stat_List_unit,FUNCTION,"  * nb_spr_free : stat_list %d - free_list %d - free %d, link %d (%d), use %d (%d)",stat_list_nb_spr_free,free_list_nb_spr_free,nb_spr_free,nb_spr_link,stat_list_nb_spr_link,nb_spr_use,stat_list_nb_spr_use);

          if (free_list_nb_gpr_free != stat_list_nb_gpr_free)
            throw ERRORMORPHEO(FUNCTION,toString(_("Number of free general register is not valid. %d in Stat_List and %d in Free_list.\n"),stat_list_nb_gpr_free,free_list_nb_gpr_free));
          if (free_list_nb_spr_free != stat_list_nb_spr_free)
            throw ERRORMORPHEO(FUNCTION,toString(_("Number of free general register is not valid. %d in Stat_List and %d in Free_list.\n"),stat_list_nb_spr_free,free_list_nb_spr_free));

          if (PORT_READ(in_INFO_ROB_EMPTY) and (nb_gpr_free != _nb_gpr_free))
            throw ERRORMORPHEO(FUNCTION,toString(_("Rob is empty but they have %d general registers free or can_free and must be %d registers."),nb_gpr_free,_nb_gpr_free));

          if (PORT_READ(in_INFO_ROB_EMPTY) and (nb_spr_free != _nb_spr_free))
            throw ERRORMORPHEO(FUNCTION,toString(_("Rob is empty but they have %d special registers free or can_free and must be %d registers."),nb_spr_free,_nb_spr_free));
        }
#endif

	// =====================================================
	// =====[ INSERT ]======================================
	// =====================================================
	for (uint32_t i=0; i<_param->_nb_inst_insert; i++)
	  if (PORT_READ(in_INSERT_VAL[i]) and internal_INSERT_ACK[i])
	    {
              log_printf(TRACE,Stat_List_unit,FUNCTION,"  * INSERT [%d]",i);
              
// 	      if (PORT_READ(in_INSERT_READ_RA [i]))
// 		{
// 		  Tgeneral_address_t num_reg = PORT_READ(in_INSERT_NUM_REG_RA_PHY [i]);

//                   log_printf(TRACE,Stat_List_unit,FUNCTION,"    * READ_RA  - num_reg     : %d",num_reg);

// 		  uint32_t bank = num_reg >> _param->_shift_gpr;
// 		  uint32_t reg  = num_reg  & _param->_mask_gpr ;
// 		  gpr_stat_list [bank][reg].insert_read();
// 		}

// 	      if (PORT_READ(in_INSERT_READ_RB [i]))
// 		{
// 		  Tgeneral_address_t num_reg = PORT_READ(in_INSERT_NUM_REG_RB_PHY [i]);

//                   log_printf(TRACE,Stat_List_unit,FUNCTION,"    * READ_RB  - num_reg     : %d",num_reg);

// 		  uint32_t bank = num_reg >> _param->_shift_gpr;
// 		  uint32_t reg  = num_reg  & _param->_mask_gpr ;
// 		  gpr_stat_list [bank][reg].insert_read();
// 		}

// 	      if (PORT_READ(in_INSERT_READ_RC [i]))
// 		{
// 		  Tgeneral_address_t num_reg = PORT_READ(in_INSERT_NUM_REG_RC_PHY [i]);

//                   log_printf(TRACE,Stat_List_unit,FUNCTION,"    * READ_RC  - num_reg     : %d",num_reg);

// 		  uint32_t bank = num_reg >> _param->_shift_spr;
// 		  uint32_t reg  = num_reg  & _param->_mask_spr ;
// 		  spr_stat_list [bank][reg].insert_read();
// 		}

	      if (PORT_READ(in_INSERT_WRITE_RD [i]))
		{
                  {
                    Tgeneral_address_t num_reg = PORT_READ(in_INSERT_NUM_REG_RD_PHY_OLD [i]);
                    
                    log_printf(TRACE,Stat_List_unit,FUNCTION,"    * WRITE_RD - num_reg old : %d",num_reg);
                    
                    uint32_t bank = num_reg >> _param->_shift_gpr;
                    uint32_t reg  = num_reg  & _param->_mask_gpr ;
                    gpr_stat_list [bank][reg].insert_write_old();
                  }
                  {
                    Tgeneral_address_t num_reg = PORT_READ(in_INSERT_NUM_REG_RD_PHY_NEW [i]);
                    
                    log_printf(TRACE,Stat_List_unit,FUNCTION,"    * WRITE_RD - num_reg new : %d",num_reg);
                    
                    uint32_t bank = num_reg >> _param->_shift_gpr;
                    uint32_t reg  = num_reg  & _param->_mask_gpr ;
                    gpr_stat_list [bank][reg].insert_write_new();
                  }
		}

	      if (PORT_READ(in_INSERT_WRITE_RE [i]))
		{
                  {
                    Tspecial_address_t num_reg = PORT_READ(in_INSERT_NUM_REG_RE_PHY_OLD [i]);
                    
                    log_printf(TRACE,Stat_List_unit,FUNCTION,"    * WRITE_RE - num_reg old : %d",num_reg);
                    
                    uint32_t bank = num_reg >> _param->_shift_spr;
                    uint32_t reg  = num_reg  & _param->_mask_spr ;
                    spr_stat_list [bank][reg].insert_write_old();
                  }
                  {
                    Tspecial_address_t num_reg = PORT_READ(in_INSERT_NUM_REG_RE_PHY_NEW [i]);
                    
                    log_printf(TRACE,Stat_List_unit,FUNCTION,"    * WRITE_RE - num_reg new : %d",num_reg);
                    
                    uint32_t bank = num_reg >> _param->_shift_spr;
                    uint32_t reg  = num_reg  & _param->_mask_spr ;
                    spr_stat_list [bank][reg].insert_write_new();
                  }
                }
	    }

	// =====================================================
	// =====[ RETIRE ]======================================
	// =====================================================
	for (uint32_t i=0; i<_param->_nb_inst_retire; i++)
	  if (PORT_READ(in_RETIRE_VAL[i]) and internal_RETIRE_ACK[i])
	    {
              log_printf(TRACE,Stat_List_unit,FUNCTION,"  * RETIRE [%d]",i);

              Tcontrol_t restore = PORT_READ(in_RETIRE_RESTORE [i]);

              log_printf(TRACE,Stat_List_unit,FUNCTION,"    * restore : %d",restore);

// 	      if (PORT_READ(in_RETIRE_READ_RA [i]))
// 		{
// 		  Tgeneral_address_t num_reg = PORT_READ(in_RETIRE_NUM_REG_RA_PHY [i]);

//                   log_printf(TRACE,Stat_List_unit,FUNCTION,"    * READ_RA  - num_reg     : %d",num_reg);

// 		  uint32_t bank = num_reg >> _param->_shift_gpr;
// 		  uint32_t reg  = num_reg  & _param->_mask_gpr ;
// 		  gpr_stat_list [bank][reg].retire_read();
// 		}

// 	      if (PORT_READ(in_RETIRE_READ_RB [i]))
// 		{
// 		  Tgeneral_address_t num_reg = PORT_READ(in_RETIRE_NUM_REG_RB_PHY [i]);

//                   log_printf(TRACE,Stat_List_unit,FUNCTION,"    * READ_RB  - num_reg     : %d",num_reg);

// 		  uint32_t bank = num_reg >> _param->_shift_gpr;
// 		  uint32_t reg  = num_reg  & _param->_mask_gpr ;
// 		  gpr_stat_list [bank][reg].retire_read();
// 		}

// 	      if (PORT_READ(in_RETIRE_READ_RC [i]))
// 		{
// 		  Tgeneral_address_t num_reg = PORT_READ(in_RETIRE_NUM_REG_RC_PHY [i]);

//                   log_printf(TRACE,Stat_List_unit,FUNCTION,"    * READ_RC  - num_reg     : %d",num_reg);

// 		  uint32_t bank = num_reg >> _param->_shift_spr;
// 		  uint32_t reg  = num_reg  & _param->_mask_spr ;
// 		  spr_stat_list [bank][reg].retire_read();
// 		}

	      if (PORT_READ(in_RETIRE_WRITE_RD [i]))
		{
                  Tcontrol_t restore_old = PORT_READ(in_RETIRE_RESTORE_RD_PHY_OLD [i]);

                  log_printf(TRACE,Stat_List_unit,FUNCTION,"    * WRITE_RD - restore_old : %d",restore_old);

		  {
		    Tgeneral_address_t num_reg = PORT_READ(in_RETIRE_NUM_REG_RD_PHY_OLD [i]);

                    log_printf(TRACE,Stat_List_unit,FUNCTION,"                 num_reg_old : %d",num_reg);
                  
		    uint32_t bank = num_reg >> _param->_shift_gpr;
		    uint32_t reg  = num_reg  & _param->_mask_gpr ;
		    gpr_stat_list [bank][reg].retire_write_old(restore, restore_old);
		  }
		  {
		    Tgeneral_address_t num_reg = PORT_READ(in_RETIRE_NUM_REG_RD_PHY_NEW [i]);

                    log_printf(TRACE,Stat_List_unit,FUNCTION,"                 num_reg_new : %d",num_reg);

		    uint32_t bank = num_reg >> _param->_shift_gpr;
		    uint32_t reg  = num_reg  & _param->_mask_gpr ;
		    gpr_stat_list [bank][reg].retire_write_new(restore, restore_old);
		  }
		}

	      if (PORT_READ(in_RETIRE_WRITE_RE [i]))
		{
                  Tcontrol_t restore_old = PORT_READ(in_RETIRE_RESTORE_RE_PHY_OLD [i]);

                  log_printf(TRACE,Stat_List_unit,FUNCTION,"    * WRITE_RE - restore_old : %d",restore_old);

		  {
		    Tspecial_address_t num_reg = PORT_READ(in_RETIRE_NUM_REG_RE_PHY_OLD [i]);

                    log_printf(TRACE,Stat_List_unit,FUNCTION,"                 num_reg_old : %d",num_reg);

		    uint32_t bank = num_reg >> _param->_shift_spr;
		    uint32_t reg  = num_reg  & _param->_mask_spr ;
		    spr_stat_list [bank][reg].retire_write_old(restore, restore_old);
		  }
		  {
		    Tspecial_address_t num_reg = PORT_READ(in_RETIRE_NUM_REG_RE_PHY_NEW [i]);

                    log_printf(TRACE,Stat_List_unit,FUNCTION,"                 num_reg_new : %d",num_reg);

		    uint32_t bank = num_reg >> _param->_shift_spr;
		    uint32_t reg  = num_reg  & _param->_mask_spr ;
		    spr_stat_list [bank][reg].retire_write_new(restore, restore_old);
		  }
		}
	    }

	for (uint32_t i=0; i<_param->_nb_reg_free; i++)
	  {
	    // =====================================================
	    // =====[ PUSH_GPR ]====================================
	    // =====================================================
	    if (internal_PUSH_GPR_VAL [i] and PORT_READ(in_PUSH_GPR_ACK [i]))
	      gpr_stat_list[internal_PUSH_GPR_NUM_BANK [i]][internal_PUSH_GPR_NUM_REG [i]].free();
	    
	    // =====================================================
	    // =====[ PUSH_SPR ]====================================
	    // =====================================================
	    if (internal_PUSH_SPR_VAL [i] and PORT_READ(in_PUSH_SPR_ACK [i]))
	      spr_stat_list[internal_PUSH_SPR_NUM_BANK [i]][internal_PUSH_SPR_NUM_REG [i]].free();
	  }

	// Update pointer
	reg_GPR_PTR_FREE = ((reg_GPR_PTR_FREE==0)?_param->_nb_general_register_by_bank:reg_GPR_PTR_FREE)-1;
	reg_SPR_PTR_FREE = ((reg_SPR_PTR_FREE==0)?_param->_nb_special_register_by_bank:reg_SPR_PTR_FREE)-1;
      }


#if (DEBUG >= DEBUG_TRACE)
    {
      log_printf(TRACE,Stat_List_unit,FUNCTION,"  * Dump Stat List");
      log_printf(TRACE,Stat_List_unit,FUNCTION,"    * reg_GPR_PTR_FREE : %d",reg_GPR_PTR_FREE);
      log_printf(TRACE,Stat_List_unit,FUNCTION,"    * reg_SPR_PTR_FREE : %d",reg_SPR_PTR_FREE);
      
      for (uint32_t i=0; i<_param->_nb_bank; i++)
        for (uint32_t j=0; j<_param->_nb_general_register_by_bank; j++)
          log_printf(TRACE,Stat_List_unit,FUNCTION,"    * GPR[%.4d][%.5d] (%.5d) - free %.1d, link %.1d, use %.1d",
                     i,
                     j,
                     (i<<_param->_shift_gpr)|j,
                     gpr_stat_list[i][j]._is_free,
                     gpr_stat_list[i][j]._is_link,
                     gpr_stat_list[i][j]._is_use// ,
//                      gpr_stat_list[i][j]._is_valid,
//                      gpr_stat_list[i][j]._counter
                     );
      for (uint32_t i=0; i<_param->_nb_bank; i++)
        for (uint32_t j=0; j<_param->_nb_special_register_by_bank; j++)
          log_printf(TRACE,Stat_List_unit,FUNCTION,"    * SPR[%.4d][%.5d] (%.5d) - free %.1d, link %.1d, use %.1d",
                     i,
                     j,
                     (i<<_param->_shift_spr)|j,
                     spr_stat_list[i][j]._is_free,
                     spr_stat_list[i][j]._is_link,
                     spr_stat_list[i][j]._is_use// ,
//                      spr_stat_list[i][j]._is_valid,
//                      spr_stat_list[i][j]._counter
                     );
    }
#endif

#ifdef DEBUG_TEST
# if 0
    {
      uint32_t size_rob   = 64;
      uint32_t nb_context = 1;
      
      {
        uint32_t nb_is_link = 0;
        uint32_t nb_reg = 32;
        for (uint32_t i=0; i<_param->_nb_bank; i++)
          for (uint32_t j=0; j<_param->_nb_general_register_by_bank; j++)
            if (gpr_stat_list[i][j]._is_link)
              nb_is_link ++;
        
        log_printf(TRACE,Stat_List_unit,FUNCTION,"    * nb_GPR_IS_LINK   : %d",nb_is_link);
        
        if (nb_is_link > size_rob+nb_context*nb_reg)
          throw ERRORMORPHEO(FUNCTION,toString(_("They are %d linked gpr register, but max is size_rob+nb_context*%d = %d+%d*%d = %d"),nb_is_link,nb_reg,size_rob,nb_context,nb_reg,size_rob+nb_context*nb_reg));
      }
      
      {
        uint32_t nb_is_link = 0;
        uint32_t nb_reg = 2;
        for (uint32_t i=0; i<_param->_nb_bank; i++)
          for (uint32_t j=0; j<_param->_nb_special_register_by_bank; j++)
            if (spr_stat_list[i][j]._is_link)
              nb_is_link ++;
        
        log_printf(TRACE,Stat_List_unit,FUNCTION,"    * nb_SPR_IS_LINK   : %d",nb_is_link);
        
        if (nb_is_link > size_rob+nb_context*nb_reg)
          throw ERRORMORPHEO(FUNCTION,toString(_("They are %d linked spr register, but max is size_rob+nb_context*%d = %d+%d*%d = %d"),nb_is_link,nb_reg,size_rob,nb_context,nb_reg,size_rob+nb_context*nb_reg));
      }
    }
# endif
#endif
                

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

    log_end(Stat_List_unit,FUNCTION);
  };

}; // end namespace stat_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
