#ifdef SYSTEMC
/*
 * $Id$
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_Front_end/Front_end/Prediction_unit/Update_Prediction_Table/include/Update_Prediction_Table.h"

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_front_end {
namespace front_end {
namespace prediction_unit {
namespace update_prediction_table {


#undef  FUNCTION
#define FUNCTION "Update_Prediction_Table::genMoore"
  void Update_Prediction_Table::genMoore (void)
  {
    log_printf(FUNC,Update_Prediction_Table,FUNCTION,"Begin");

    // ===================================================================
    // =====[ DEPTH ]=====================================================
    // ===================================================================

    for (uint32_t i=0; i<_param->_nb_context; i++)
      {
	if (_param->_have_port_depth [i])
	  {
	    PORT_WRITE(out_DEPTH_TAIL      [i], reg_BOTTOM [i]);
	  }
	PORT_WRITE(out_DEPTH_NB_BRANCH [i], reg_NB_ELT [i]);
      }
    // ===================================================================
    // =====[ UPDATE ]====================================================
    // ===================================================================

    Tdepth_t tab_depth [_param->_nb_context];
    for (uint32_t i=0; i<_param->_nb_context; i++)
      tab_depth [i] = reg_BOTTOM [i];

    for (uint32_t i=0; i<_param->_nb_inst_update; i++)
      {
	uint32_t   context = (reg_UPDATE_PRIORITY+i)%_param->_nb_context;
	Tdepth_t   depth   = tab_depth[context];
	state_t    state   = reg_UPDATE_PREDICTION_TABLE [context][depth]._state;
	
	Tcontrol_t val     = ((state == UPDATE_PREDICTION_STATE_OK) or
			      (state == UPDATE_PREDICTION_STATE_KO));

// 	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"UPDATE [%d] (genMoore)",i);
// 	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"  * context     : %d",context);
// 	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"  * depth       : %d",depth);
// 	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"  * state       : %s",toString(state).c_str());
// 	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"  * val         : %d",val);
// 	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"  * addr_src    : %x",reg_UPDATE_PREDICTION_TABLE [context][depth]._address_src );
// 	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"  * addr_dest   : %x",reg_UPDATE_PREDICTION_TABLE [context][depth]._address_dest);

	if (val)
	  {
	    Tbranch_condition_t cond    = reg_UPDATE_PREDICTION_TABLE [context][depth]._condition;
		      
	    Tcontrol_t          ifetch  = reg_UPDATE_PREDICTION_TABLE [context][depth]._ifetch_prediction;
	    Tcontrol_t          btb_val = true;
	    Tcontrol_t          dir_val = (ifetch and // not ifetch == static prediction
					   ((cond == BRANCH_CONDITION_FLAG_UNSET) or
					    (cond == BRANCH_CONDITION_FLAG_SET)));
	    Tcontrol_t          ras_val = ((cond == BRANCH_CONDITION_NONE_WITH_WRITE_STACK) or
					   (cond == BRANCH_CONDITION_READ_REGISTER_WITH_WRITE_STACK) or
					   (cond == BRANCH_CONDITION_READ_STACK));
	    
	    Tcontrol_t          push = ((cond == BRANCH_CONDITION_NONE_WITH_WRITE_STACK) or
					(cond == BRANCH_CONDITION_READ_REGISTER_WITH_WRITE_STACK));

	    if (_param->_have_port_context_id)
	    PORT_WRITE(out_UPDATE_CONTEXT_ID            [i],context);
	    PORT_WRITE(out_UPDATE_MISS_PREDICTION       [i],(state == UPDATE_PREDICTION_STATE_KO));
	    PORT_WRITE(out_UPDATE_DIRECTION_GOOD        [i],reg_UPDATE_PREDICTION_TABLE [context][depth]._good_take   );
	    PORT_WRITE(out_UPDATE_BTB_VAL               [i],btb_val);
	    PORT_WRITE(out_UPDATE_BTB_ADDRESS_SRC       [i],reg_UPDATE_PREDICTION_TABLE [context][depth]._address_src );
	    PORT_WRITE(out_UPDATE_BTB_ADDRESS_DEST      [i],reg_UPDATE_PREDICTION_TABLE [context][depth]._address_dest);
	    PORT_WRITE(out_UPDATE_BTB_CONDITION         [i],cond);
	    PORT_WRITE(out_UPDATE_DIR_VAL               [i],dir_val);
	    if (_param->_have_port_history)
	    PORT_WRITE(out_UPDATE_DIR_HISTORY           [i],reg_UPDATE_PREDICTION_TABLE [context][depth]._history     );
	    PORT_WRITE(out_UPDATE_RAS_VAL               [i],ras_val);
	    PORT_WRITE(out_UPDATE_RAS_PUSH              [i],push);
	    PORT_WRITE(out_UPDATE_RAS_ADDRESS           [i],reg_UPDATE_PREDICTION_TABLE [context][depth]._address_ras );
	    PORT_WRITE(out_UPDATE_RAS_INDEX             [i],reg_UPDATE_PREDICTION_TABLE [context][depth]._index_ras   );
	    PORT_WRITE(out_UPDATE_RAS_PREDICTION_IFETCH [i],ifetch);

	    internal_UPDATE_CONTEXT_ID [i] = context;
	    internal_UPDATE_DEPTH      [i] = depth;

	    tab_depth[context] = (depth+1)%_param->_size_queue[context];
	  }

	internal_UPDATE_VAL [i] = val;
	PORT_WRITE(out_UPDATE_VAL [i], internal_UPDATE_VAL [i]);
      }

    // ===================================================================
    // =====[ BRANCH_EVENT ]==============================================
    // ===================================================================
    for (uint32_t i=0; i<_param->_nb_context; i++)
      {
	Tdepth_t   depth   = (reg_BOTTOM [i] + reg_NB_ELT_UPDATE [i])%_param->_size_queue [i];
	state_t    state   = reg_UPDATE_PREDICTION_TABLE [i][depth]._state;
	
	Tcontrol_t val     = (state == UPDATE_PREDICTION_STATE_EVENT);

	if (val)
	  {
	    PORT_WRITE(out_BRANCH_EVENT_ADDRESS_SRC  [i], reg_UPDATE_PREDICTION_TABLE [i][depth]._address_src );
	    PORT_WRITE(out_BRANCH_EVENT_ADDRESS_DEST [i], reg_UPDATE_PREDICTION_TABLE [i][depth]._address_dest);
	    internal_BRANCH_EVENT_DEPTH [i] = depth;
	  }

	internal_BRANCH_EVENT_VAL   [i] = val;
	PORT_WRITE(out_BRANCH_EVENT_VAL [i], internal_BRANCH_EVENT_VAL [i]);
      }
    log_printf(FUNC,Update_Prediction_Table,FUNCTION,"End");
  };

}; // end namespace update_prediction_table
}; // end namespace prediction_unit
}; // end namespace front_end
}; // end namespace multi_front_end
}; // end namespace core

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