#ifdef SYSTEMC
/*
 * $Id: Register_Address_Translation_unit_transition.cpp 128 2009-06-26 08:43:23Z 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_not_speculative   [i][j][0] = 0;
              rat_gpr_speculative_valid [i][j][0] = false;
              rat_gpr_speculative       [i][j][0] = 0    ; // not necessary
              rat_gpr_update_table      [i][j][0] = false; // not necessary

	      for (uint32_t k=1; k<_param->_nb_general_register_logic; k++)
                {
                  rat_gpr_not_speculative    [i][j][k] = gpr++;
                  rat_gpr_speculative_valid  [i][j][k] = false;
                  rat_gpr_speculative        [i][j][k] = 0    ; // not necessary
                  rat_gpr_update_table       [i][j][k] = false; // not necessary
                }
	      for (uint32_t k=0; k<_param->_nb_special_register_logic; k++)
                {
                  rat_spr_not_speculative    [i][j][k] = spr++;
                  rat_spr_speculative_valid  [i][j][k] = false;
                  rat_spr_speculative        [i][j][k] = 0    ; // not necessary
                  rat_spr_update_table       [i][j][k] = false; // not necessary
                }
	    }
      }
    else
      {
	// Note : GPR[0] is never write (in decod's stage : write_rd = 0 when num_reg_rd_log == 0)

	// =====================================================
	// ====[ RETIRE_EVENT ]=================================
	// =====================================================
        for (uint32_t i=0; i<_param->_nb_front_end; ++i)
          for (uint32_t j=0; j<_param->_nb_context[i]; ++j)
            if (PORT_READ(in_RETIRE_EVENT_VAL [i][j]) and internal_RETIRE_EVENT_ACK [i][j])
              // Test if event have just occure
              if (PORT_READ(in_RETIRE_EVENT_STATE [i][j]) == EVENT_STATE_EVENT)
                {
                  log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * Reset Update Table");
                  
                  // Reset update_table and validity table
                  for (uint32_t k=0; k<_param->_nb_general_register_logic; k++)
                    {
                      rat_gpr_update_table      [i][j][k] = false;
                      rat_gpr_speculative_valid [i][j][k] = false;
                    }
                  for (uint32_t k=0; k<_param->_nb_special_register_logic; k++)
                    {
                      rat_spr_update_table      [i][j][k] = false;
                      rat_spr_speculative_valid [i][j][k] = false;
                    }
                }

	// =====================================================
	// ====[ INSERT ]=======================================
	// =====================================================
	// First : interface insert
        // this instruction is speculative !!!
	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])
	    {
              log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"  * INSERT [%d]",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;
              Tcontrol_t write_rd     = PORT_READ(in_INSERT_WRITE_RD [i]);
              Tcontrol_t write_re     = PORT_READ(in_INSERT_WRITE_RE [i]);

              log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * front_end          : %d",front_end_id);
              log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * context            : %d",context_id);
	      
	      // Test if write and modifie RAT
              log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * write_rd           : %d",write_rd);
	      if (write_rd == 1)
                {
                  Tgeneral_address_t num_reg_rd_log = PORT_READ(in_INSERT_NUM_REG_RD_LOG [i]);
                  Tgeneral_address_t num_reg_rd_phy = PORT_READ(in_INSERT_NUM_REG_RD_PHY [i]);

                  log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * num_reg_rd_log     : %d",num_reg_rd_log);
                  log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * num_reg_rd_phy     : %d",num_reg_rd_phy);

                  rat_gpr_speculative       [front_end_id][context_id][num_reg_rd_log] = num_reg_rd_phy;
                  rat_gpr_speculative_valid [front_end_id][context_id][num_reg_rd_log] = true;
                }

              log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * write_re           : %d",write_re);
	      if (write_re == 1)
                {
                  Tspecial_address_t num_reg_re_log = PORT_READ(in_INSERT_NUM_REG_RE_LOG [i]);
                  Tspecial_address_t num_reg_re_phy = PORT_READ(in_INSERT_NUM_REG_RE_PHY [i]);

                  log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * num_reg_re_log     : %d",num_reg_re_log);
                  log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * num_reg_re_phy     : %d",num_reg_re_phy);

                  rat_spr_speculative       [front_end_id][context_id][num_reg_re_log] = num_reg_re_phy;
                  rat_spr_speculative_valid [front_end_id][context_id][num_reg_re_log] = true;
                }
	    }

	// =====================================================
	// ====[ 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])
	    {
              log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"  * RETIRE [%d]",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 !

              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;
              Tcontrol_t write_rd     = PORT_READ(in_RETIRE_WRITE_RD [i]);
              Tcontrol_t write_re     = PORT_READ(in_RETIRE_WRITE_RE [i]);
              Tcontrol_t restore      = internal_RETIRE_RESTORE [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,"    * restore            : %d",restore     );

              // Test if write and have not a previous update
              log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * write_rd           : %d",write_rd);
              if (PORT_READ(in_RETIRE_WRITE_RD [i]) == 1)
                {
                  Tgeneral_address_t num_reg_rd_log     = PORT_READ(in_RETIRE_NUM_REG_RD_LOG     [i]);

                  log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * num_reg_rd_log     : %d",num_reg_rd_log    );

                  if (not restore)
                    {
                  Tgeneral_address_t num_reg_rd_phy_new = PORT_READ(in_RETIRE_NUM_REG_RD_PHY_NEW [i]);

                  log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * num_reg_rd_phy_new : %d",num_reg_rd_phy_new);

                  rat_gpr_not_speculative [front_end_id][context_id][num_reg_rd_log] = num_reg_rd_phy_new;
                    }

                  Tcontrol_t         restore_rd         = internal_RETIRE_RESTORE_RD_PHY_OLD [i];
                  log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * restore_rd         : %d",restore_rd        );
                      
                  if (restore_rd)
                  rat_gpr_update_table    [front_end_id][context_id][num_reg_rd_log] = true;
                }

              log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * write_re           : %d",write_re);
              if (PORT_READ(in_RETIRE_WRITE_RE [i]) == 1)
                {
                  Tspecial_address_t num_reg_re_log     = PORT_READ(in_RETIRE_NUM_REG_RE_LOG     [i]);

                  log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * num_reg_re_log     : %d",num_reg_re_log    );

                  if (not restore)
                    {
                  Tspecial_address_t num_reg_re_phy_new = PORT_READ(in_RETIRE_NUM_REG_RE_PHY_NEW [i]);

                  log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * num_reg_re_phy_new : %d",num_reg_re_phy_new);

                  rat_spr_not_speculative [front_end_id][context_id][num_reg_re_log] = num_reg_re_phy_new;
                    }

                  Tcontrol_t         restore_re         = internal_RETIRE_RESTORE_RE_PHY_OLD [i];
                  log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"    * restore_re         : %d",restore_re        );
                      
                  if (restore_re)
                  rat_spr_update_table    [front_end_id][context_id][num_reg_re_log] = true;
                }

	    }
      }

#if (DEBUG >= DEBUG_TRACE) and (DEBUG_Register_Address_Translation_unit == true)
    {
      uint32_t limit = 4;
      
      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+=limit)
              {
                std::string str = "";
                for (uint32_t x=0; x<limit; x++)
                  {
                    uint32_t index = k+x;
                    if (index >= _param->_nb_general_register_logic)
                      break;
                    else
                      str+=toString("GPR[%.4d] - %.1d %.5d (%.5d) %.1d | ",index,rat_gpr_speculative_valid [i][j][index],rat_gpr_speculative [i][j][index],rat_gpr_not_speculative [i][j][index],rat_gpr_update_table[i][j][index]);
                  }
                log_printf(TRACE,Register_Address_Translation_unit,FUNCTION,"      * %s",str.c_str());
              }
      
            for (uint32_t k=0; k<_param->_nb_special_register_logic; k+=limit)
              {
                std::string str = "";
                
                for (uint32_t x=0; x<limit; x++)
                  {
                    uint32_t index = k+x;
                    if (index >= _param->_nb_special_register_logic)
                      break;
                    else
                      str+=toString("SPR[%.4d] - %.1d %.5d (%.5d) %.1d | ",index,rat_spr_speculative_valid [i][j][index],rat_spr_speculative [i][j][index],rat_spr_not_speculative [i][j][index],rat_spr_update_table[i][j][index]);
                  }
                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_front_end; ++i)
        for (uint32_t j=0; j<_param->_nb_context[i]; ++j)
          {
            for (uint32_t x=0; x<_param->_nb_general_register_logic; ++x)
              for (uint32_t y=x+1; y<_param->_nb_general_register_logic; ++y)
                {
                  if (rat_gpr_speculative_valid [i][j][x] and
                      rat_gpr_speculative_valid [i][j][y] and
                      (rat_gpr_speculative[i][j][x] == rat_gpr_speculative[i][j][y]))
                    throw ERRORMORPHEO (FUNCTION,toString(_("In RAT, rat_gpr_speculative[%d][%d][%d] == rat_gpr_speculative[%d][%d][%d] == %d"),i,j,x,i,j,y,rat_gpr_speculative[i][j][x]));
                  if (rat_gpr_not_speculative[i][j][x] == rat_gpr_not_speculative[i][j][y])
                    throw ERRORMORPHEO (FUNCTION,toString(_("In RAT, rat_gpr_not_speculative[%d][%d][%d] == rat_gpr_not_speculative[%d][%d][%d] == %d"),i,j,x,i,j,y,rat_gpr_not_speculative[i][j][x]));
                  
                }
            for (uint32_t x=0; x<_param->_nb_special_register_logic; ++x)
              for (uint32_t y=x+1; y<_param->_nb_special_register_logic; ++y)
                {
                  if(rat_spr_speculative_valid [i][j][x] and
                     rat_spr_speculative_valid [i][j][y] and
                     (rat_spr_speculative[i][j][x] == rat_spr_speculative[i][j][y]))
                    throw ERRORMORPHEO (FUNCTION,toString(_("In RAT, rat_spr_speculative[%d][%d][%d] == rat_spr_speculative[%d][%d][%d] == %d"),i,j,x,i,j,y,rat_spr_speculative[i][j][x]));
                  if (rat_spr_not_speculative[i][j][x] == rat_spr_not_speculative[i][j][y])
                    throw ERRORMORPHEO (FUNCTION,toString(_("In RAT, rat_spr_not_speculative[%d][%d][%d] == rat_spr_not_speculative[%d][%d][%d] == %d"),i,j,x,i,j,y,rat_spr_not_speculative[i][j][x]));
                  
                }
          }
      
    }
# endif
#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
