#ifdef SYSTEMC
/*
 * $Id: Register_Address_Translation_unit_transition.cpp 88 2008-12-10 18:31:39Z rosiere $
 *
 * [ Description ]
 * 
 */

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

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


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

    if (PORT_READ(in_NRESET) == 0)
      {
	uint32_t gpr = 1;
	uint32_t spr = 0;

	for (uint32_t i=0; i<_param->_nb_front_end; i++)
	  for (uint32_t j=0; j<_param->_nb_context[i]; j++)
	    {
	      rat_gpr [i][j][0] = 0;

	      for (uint32_t k=1; k<_param->_nb_general_register_logic; k++)
		rat_gpr [i][j][k] = gpr++;
	      for (uint32_t k=0; k<_param->_nb_special_register_logic; k++)
		rat_spr [i][j][k] = spr++;
	    }
      }
    else
      {
	// Note : GPR[0] is never write (in decod's stage : write_rd = 0 when num_reg_rd_log == 0)

	// =====================================================
	// ====[ INSERT ]=======================================
	// =====================================================
	// First : interface insert
	for (uint32_t i=0; i<_param->_nb_inst_insert; i++)
	  // Test transaction
	  if (PORT_READ(in_INSERT_VAL [i]) and internal_INSERT_ACK  [i])
	    {
	      Tcontext_t front_end_id = (_param->_have_port_front_end_id)?PORT_READ(in_RENAME_FRONT_END_ID [i]):0;
	      Tcontext_t context_id   = (_param->_have_port_context_id  )?PORT_READ(in_RENAME_CONTEXT_ID   [i]):0;
	      
	      // Test if write
	      if (PORT_READ(in_INSERT_WRITE_RD [i]) == 1)
		rat_gpr[front_end_id][context_id][PORT_READ(in_INSERT_NUM_REG_RD_LOG [i])] = PORT_READ(in_INSERT_NUM_REG_RD_PHY [i]);
	      if (PORT_READ(in_INSERT_WRITE_RE [i]) == 1)
		rat_spr[front_end_id][context_id][PORT_READ(in_INSERT_NUM_REG_RE_LOG [i])] = PORT_READ(in_INSERT_NUM_REG_RE_PHY [i]);
	    }

	// =====================================================
	// ====[ RETIRE ]=======================================
	// =====================================================
	// Second : interface retire
	//  (because if an event on the same thread : the instruction is already renamed)
	for (uint32_t i=0; i<_param->_nb_inst_retire; i++)
	  if (PORT_READ(in_RETIRE_VAL [i]) and internal_RETIRE_ACK [i])
	    {
	      // if no event : no effect, because the RAT content the most recently register
	      // but if they have a event (exception or miss speculation), the rat must restore the oldest value
	      // To restore the oldest valid value, we use the rat_update_table. if the bit is unset, also they have none update on this register
	      // the retire interface became of the Re Order Buffer, also is in program sequence !
	      if (PORT_READ(in_RETIRE_EVENT_STATE [i]) != EVENT_STATE_NO_EVENT)
		{
		  Tcontext_t         front_end_id = (_param->_have_port_front_end_id)?PORT_READ(in_RETIRE_FRONT_END_ID [i]):0;
		  Tcontext_t         context_id   = (_param->_have_port_context_id  )?PORT_READ(in_RETIRE_CONTEXT_ID   [i]):0;

		  // Test if event have just occure
		  if (PORT_READ(in_RETIRE_EVENT_STATE [i]) == EVENT_STATE_EVENT)
		    {
		      // Reset update_table
		      for (uint32_t j=0; j<_param->_nb_general_register_logic; j++)
			rat_gpr_update_table[front_end_id][context_id][j] = 0;
		      for (uint32_t j=0; j<_param->_nb_special_register_logic; j++)
			rat_spr_update_table[front_end_id][context_id][j] = 0;
		    }

 		  // Test if write and have not a previous update
		  if (PORT_READ(in_RETIRE_WRITE_RD [i]) == 1)
		    {
		      Tgeneral_address_t rd_log = PORT_READ(in_RETIRE_NUM_REG_RD_LOG [i]);
		      
		      log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"  * retire[%d]",i);
		      log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * front_end_id : %d",front_end_id);
		      log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * context_id   : %d",context_id  );
		      log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * rd_log       : %d",rd_log      );
		      
// 		      if (RETIRE_RESTORE_RD_PHY_OLD [i])
		      if (rat_gpr_update_table[front_end_id][context_id][rd_log] == 0)
			{
			  rat_gpr             [front_end_id][context_id][rd_log] = PORT_READ(in_RETIRE_NUM_REG_RD_PHY_OLD [i]);
			  rat_gpr_update_table[front_end_id][context_id][rd_log] = 1;
			}
		    }

		  if (PORT_READ(in_RETIRE_WRITE_RE [i]) == 1)
		    {
		      Tspecial_address_t re_log = PORT_READ(in_RETIRE_NUM_REG_RE_LOG [i]);

// 		      if (RETIRE_RESTORE_RE_PHY_OLD [i])
		      if (rat_spr_update_table[front_end_id][context_id][re_log] == 0)
			{
			  rat_spr             [front_end_id][context_id][re_log] = PORT_READ(in_RETIRE_NUM_REG_RE_PHY_OLD [i]);
			  rat_spr_update_table[front_end_id][context_id][re_log] = 1;
			}
		    }
		}
	    }
      }

#if (DEBUG >= DEBUG_TRACE) and (DEBUG_Register_Address_Translation_unit == true)
    log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"  * Dump RAT (Register_Address_Translation_unit)");
    for (uint32_t i=0; i<_param->_nb_front_end; ++i)
      for (uint32_t j=0; j<_param->_nb_context[i]; ++j)
        {
          log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * front_end[%d].context[%d]",i,j);

          for (uint32_t k=0; k<_param->_nb_general_register_logic; ++k)
            log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"      * GPR[%.2d] - %.5d %.1d",k,rat_gpr[i][j][k],rat_gpr_update_table[i][j][k]);

          for (uint32_t k=0; k<_param->_nb_special_register_logic; ++k)
            log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"      * SPR[%.2d] - %.5d %.1d",k,rat_spr[i][j][k],rat_spr_update_table[i][j][k]);
        }
#endif

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

    log_end(Register_Address_Translation_unit,FUNCTION);
  };

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