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

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

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


#undef  FUNCTION
#define FUNCTION "Return_Address_Stack::transition"
  void Return_Address_Stack::transition (void)
  {
    log_printf(FUNC,Return_Address_Stack,FUNCTION,"Begin");

    if (PORT_READ(in_NRESET))
      {
	for (uint32_t i=0; i<_param->_nb_context; i++)
	  {
	    reg_TOP    [i] = 0;
	    reg_BOTTOM [i] = 0;

	    reg_PREDICT_TOP    [i] = 0;
	    reg_PREDICT_BOTTOM [i] = 0;

	    for (uint32_t j=0; j<_param->_size_queue [i]; j++)
	      reg_stack[i][j]._val = false;
	  }
      }
    else
      {
	// ===================================================================
	// =====[ PREDICT ]===================================================
	// ===================================================================
	for (uint32_t i=0; i<_param->_nb_inst_predict; i++)
	  if (PORT_READ(in_PREDICT_VAL [i]) and internal_PREDICT_ACK [i])
	    {
	      Tcontrol_t context = (_param->_have_port_context_id)?PORT_READ(in_PREDICT_CONTEXT_ID [i]):0;
	      Tcontrol_t push    = PORT_READ(in_PREDICT_PUSH [i]);
	      Tptr_t     top_old = reg_PREDICT_TOP [i];
	      Tptr_t     top_new;

	      if (internal_PREDICT_HIT [i])
		{
		  if (push)
		    {
		      // push
		      top_new = (top_old+1)%_param->_size_queue[context];
		      
		      reg_stack [context][top_new]._val     = true; // New addr
		      reg_stack [context][top_new]._predict = true; // Is speculative (erase a old addr)
		    //reg_stack [context][top_new]._miss    = ;
		      reg_stack [context][top_new]._address = PORT_READ(in_PREDICT_ADDRESS_PUSH [i]);

		      // the stack is full, erase the most old stack
		      if (top_new == reg_PREDICT_BOTTOM [i])
			reg_PREDICT_BOTTOM [i] = (reg_PREDICT_BOTTOM [i]+1)%_param->_size_queue[context];
		    }
		  else
		    {
		      // pop
		      top_new = (top_old==0)?(_param->_size_queue[context]-1):(top_old-1);
		      
		    //reg_stack [context][top_new]._val     = ;
		    //reg_stack [context][top_new]._predict = ;
		    //reg_stack [context][top_new]._miss    = ;
		    //reg_stack [context][top_new]._address = ; 

		      // the stack is empty
		      if (top_old == reg_PREDICT_BOTTOM [i])
			reg_PREDICT_BOTTOM [i] = top_new;

		    }
		  
		  reg_PREDICT_TOP [i] = top_new;
		}
	    }

// 	// ===================================================================
// 	// =====[ DECOD ]=====================================================
// 	// ===================================================================
// 	for (uint32_t i=0; i<_param->_nb_inst_decod; i++)
// 	  if (PORT_READ(in_DECOD_VAL [i]) and internal_DECOD_ACK [i])
// 	    {
// 	      Tcontrol_t context = (_param->_have_port_context_id)?PORT_READ(in_DECOD_CONTEXT_ID [i]):0;
// 	      Tcontrol_t push    = PORT_READ(in_DECOD_PUSH [i]);
// 	      Tptr_t     top_old = reg_TOP [i];
// 	      Tptr_t     top_new;

// 	      Tcontrol_t hit  = PORT_READ(in_DECOD_HIT             [i]);
// 	      Tcontrol_t miss = PORT_READ(in_DECOD_MISS_PREDICTION [i]);

// 	      if (push)
// 		{
// 		  // push
// 		  top_new = (top_old+1)%_param->_size_queue[context];

// 		  reg_stack [context][top_new]._val     = true;
// 		  reg_stack [context][top_new]._predict = false;
// 		  reg_stack [context][top_new]._miss    = false;
// 		  reg_stack [context][top_new]._address = PORT_READ(in_DECOD_ADDRESS_PUSH [i]);

// 		  // the stack is full, erase the most old stack
// 		  if (top_old == reg_BOTTOM [i])
// 		    reg_BOTTOM [i] = top_new;
// 		}
// 	      else
// 		{
// 		  // pop
// 		  top_new = (top_old==0)?(_param->_size_queue[context]-1):(top_old-1);

// 		//reg_stack [context][top_new]._val     = ;
// 		//reg_stack [context][top_new]._predict = ;
// 		//reg_stack [context][top_new]._miss    = ;
// 		//reg_stack [context][top_new]._address = ; 
// 		}

// 	      reg_TOP [i] = top_new;

// 	      // have previous miss of ifetch ?
// 	      // 2 miss : 
// 	      //   1) miss predict : is very limited (local at context), can be update very quickly
// 	      //   2) miss decod   : result is in commit stage ... 
// 	      if (miss)
// 		{
// 		  reg_PREDICT_BOTTOM [i] = reg_BOTTOM [i];
// 		  reg_PREDICT_TOP    [i] = reg_TOP    [i];

// 		  for (uint32_t j=0; j<_param->_size_queue [i]; j++)
// 		    if (reg_stack [context][top_new]._predict)
// 		      {
// 			reg_stack [context][top_new]._predict = false;
// 			reg_stack [context][top_new]._miss    = true;
// 		      }
// 		}
// 	    }

	// ===================================================================
	// =====[ UPDATE ]===================================================
	// ===================================================================
	for (uint32_t i=0; i<_param->_nb_inst_update; i++)
	  if (PORT_READ(in_UPDATE_VAL [i]) and internal_UPDATE_ACK [i])
	    {
	      Tcontrol_t context = (_param->_have_port_context_id)?PORT_READ(in_UPDATE_CONTEXT_ID [i]):0;
	      Tcontrol_t push    = PORT_READ(in_UPDATE_PUSH  [i]);
	      Tptr_t     index   = PORT_READ(in_UPDATE_INDEX [i]);
	      
	      if (PORT_READ(in_UPDATE_MISS_PREDICTION [i]))
		{
		  if (push)
		    {
		      // push
		      top_new = (top_old+1)%_param->_size_queue[context];
		      
		      reg_stack [context][index]._val     = true;
		      reg_stack [context][index]._predict = false;
		      reg_stack [context][index]._miss    = false;
		      reg_stack [context][index]._address = PORT_READ(in_UPDATE_ADDRESS [i]);

		    }
		  else
		    {
		    //reg_stack [context][top_new]._val     = ;
		    //reg_stack [context][top_new]._predict = ;
		    //reg_stack [context][top_new]._miss    = ;
		    //reg_stack [context][top_new]._address = ; 
		    }
		  
		  // Mouais bof .......
		  reg_PREDICT_TOP [i] = index;
		}
	    }
      }

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

    log_printf(FUNC,Return_Address_Stack,FUNCTION,"End");
  };

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

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