/*
 * $Id$
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_Front_end/Front_end/Prediction_unit/Direction/Direction_Glue/include/Direction_Glue.h"

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_front_end {
namespace front_end {
namespace prediction_unit {
namespace direction {
namespace direction_glue {


#undef  FUNCTION
#define FUNCTION "Direction_Glue::Direction_Glue"
  Direction_Glue::Direction_Glue 
  (
#ifdef SYSTEMC
   sc_module_name name,
#else
   string name,
#endif
#ifdef STATISTICS
   morpheo::behavioural::Parameters_Statistics * param_statistics,
#endif
   morpheo::behavioural::core::multi_front_end::front_end::prediction_unit::direction::direction_glue::Parameters * param,
   morpheo::behavioural::Tusage_t usage
   ):
    _name              (name)
    ,_param            (param)
    ,_usage            (usage)
  {
    log_printf(FUNC,Direction_Glue,FUNCTION,"Begin");

    log_printf(INFO,Direction_Glue,FUNCTION,"Allocation");

    allocation (
#ifdef STATISTICS
		param_statistics
#endif
		);

#ifdef STATISTICS
    if (_usage & USE_STATISTICS)
      {	
	log_printf(INFO,Direction_Glue,FUNCTION,"Allocation of statistics");

	statistics_allocation(param_statistics);
      }
#endif

#ifdef VHDL
    if (_usage & USE_VHDL)
      {
	// generate the vhdl
	log_printf(INFO,Direction_Glue,FUNCTION,"Generate the vhdl");
	
	vhdl();
      }
#endif

#ifdef SYSTEMC
    if (_usage & USE_SYSTEMC)
      {
	bool need_genmealy_predict = true;
	bool need_genmealy_update  = true;

	// Constant
	if (not _param->_have_component_meta_predictor)
	  {
	    // no need update
	    need_genmealy_update = false;
	    for (uint32_t i=0; i<_param->_nb_inst_update; i++)
	      PORT_WRITE(out_UPDATE_ACK [i], 1);

	    // always ack
	    for (uint32_t i=0; i<_param->_nb_inst_predict; i++)
	      {
		PORT_WRITE(out_PREDICT_ACK [i], 1);
		
		// constant direction : never / always 
		switch (_param->_predictor_scheme)
		  {
		  case PREDICTOR_NEVER_TAKE  :
		    {
		      need_genmealy_predict = false;
		      PORT_WRITE(out_PREDICT_DIRECTION [i], 0);
		      break;
		    }
		  case PREDICTOR_ALWAYS_TAKE :
		    {
		      need_genmealy_predict = false;
		      PORT_WRITE(out_PREDICT_DIRECTION [i], 1);
		      break;
		    }
		  default : break;
		  }
	      }
	  }

# if defined(STATISTICS) or defined(VHDL_TESTBENCH)
	log_printf(INFO,Direction_Glue,FUNCTION,"Method - transition");
	
	SC_METHOD (transition);
	dont_initialize ();
	sensitive << (*(in_CLOCK)).pos();
	
#  ifdef SYSTEMCASS_SPECIFIC
	// List dependency information
#  endif    
# endif	

	if (need_genmealy_predict)
	  {
	    log_printf(INFO,Direction_Glue,FUNCTION,"Method - genMealy_predict");
	    
	    SC_METHOD (genMealy_predict);
	    dont_initialize ();
// 	    sensitive << (*(in_CLOCK)).neg(); // don't use internal register
	    for (uint32_t i=0; i<_param->_nb_inst_predict; i++)
	      {
		switch (_param->_predictor_scheme)
		  {
		  case PREDICTOR_STATIC      :
		    {
		      sensitive << (*(in_PREDICT_STATIC               [i]));
		      break;
		    }
		  case PREDICTOR_LAST_TAKE   :
		    {
		      sensitive << (*(in_PREDICT_LAST_TAKE            [i]));
		      break;
		    }
		  case PREDICTOR_COUNTER     :
		  case PREDICTOR_LOCAL       :
		  case PREDICTOR_GLOBAL      :
		  case PREDICTOR_META        :
		  case PREDICTOR_CUSTOM      :
		    {
		      sensitive << (*(in_PREDICT_VAL                  [i]))
				<< (*(in_PREDICT_ADDRESS_SRC          [i]))
				<< (*(in_PREDICT_PREDICTOR_ACK        [i]))
				<< (*(in_PREDICT_PREDICTOR_HISTORY    [i]))
				<< (*(in_PREDICT_PREDICTOR_DIRECTION  [i]));
		      break;
		    }
		  default :
		    {
		      break;
		    }
		  }
	      }

#  ifdef SYSTEMCASS_SPECIFIC
	    // List dependency information
	    for (uint32_t i=0; i<_param->_nb_inst_predict; i++)
	      {

		switch (_param->_predictor_scheme)
		  {
		  case PREDICTOR_STATIC      :
		    {
		      (*(out_PREDICT_DIRECTION             [i])) (*(in_PREDICT_STATIC               [i]));

		      break;
		    }
		  case PREDICTOR_LAST_TAKE   :
		    {
		      (*(out_PREDICT_DIRECTION             [i])) (*(in_PREDICT_LAST_TAKE            [i]));

		      break;
		    }
		  case PREDICTOR_COUNTER     :
		  case PREDICTOR_LOCAL       :
		  case PREDICTOR_GLOBAL      :
		  case PREDICTOR_META        :
		  case PREDICTOR_CUSTOM      :
		    {
		      (*(out_PREDICT_ACK                   [i])) (*(in_PREDICT_PREDICTOR_ACK        [i]));
		      (*(out_PREDICT_HISTORY               [i])) (*(in_PREDICT_PREDICTOR_HISTORY    [i]));
		      (*(out_PREDICT_DIRECTION             [i])) (*(in_PREDICT_PREDICTOR_DIRECTION  [i]));
		      (*(out_PREDICT_PREDICTOR_VAL         [i])) (*(in_PREDICT_VAL                  [i]));
		      (*(out_PREDICT_PREDICTOR_ADDRESS_SRC [i])) (*(in_PREDICT_ADDRESS_SRC          [i]));

		      break;
		    }
		  default :
		    {
		      break;
		    }
		  }
	      }
#  endif    
	  }

	if (need_genmealy_update)
	  {
	    log_printf(INFO,Direction_Glue,FUNCTION,"Method - genMealy_update");
	    
	    SC_METHOD (genMealy_update);
	    dont_initialize ();
// 	    sensitive << (*(in_CLOCK)).neg(); // don't use internal register
	    for (uint32_t i=0; i<_param->_nb_inst_update; i++)
	      sensitive << (*(in_UPDATE_VAL           [i]))
			<< (*(in_UPDATE_PREDICTOR_ACK [i]))
			<< (*(in_UPDATE_ADDRESS       [i]))
			<< (*(in_UPDATE_HISTORY       [i]))
			<< (*(in_UPDATE_DIRECTION     [i]));

#  ifdef SYSTEMCASS_SPECIFIC
	    // List dependency information
	    for (uint32_t i=0; i<_param->_nb_inst_update; i++)
	      {
		(*(out_UPDATE_PREDICTOR_VAL       [i])) (*(in_UPDATE_VAL           [i]));
		(*(out_UPDATE_ACK                 [i])) (*(in_UPDATE_PREDICTOR_ACK [i]));
		(*(out_UPDATE_PREDICTOR_ADDRESS   [i])) (*(in_UPDATE_ADDRESS       [i]));
		(*(out_UPDATE_PREDICTOR_HISTORY   [i])) (*(in_UPDATE_HISTORY       [i]));
		(*(out_UPDATE_PREDICTOR_DIRECTION [i])) (*(in_UPDATE_DIRECTION     [i]));
	      }
#  endif    
	  }
#endif
      }
    log_printf(FUNC,Direction_Glue,FUNCTION,"End");
  };
    
#undef  FUNCTION
#define FUNCTION "Direction_Glue::~Direction_Glue"
  Direction_Glue::~Direction_Glue (void)
  {
    log_printf(FUNC,Direction_Glue,FUNCTION,"Begin");

#ifdef STATISTICS
    if (_usage & USE_STATISTICS)
      {
	statistics_deallocation();
      }
#endif

    log_printf(INFO,Direction_Glue,FUNCTION,"Deallocation");
    deallocation ();

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

}; // end namespace direction_glue
}; // end namespace direction
}; // end namespace prediction_unit
}; // end namespace front_end
}; // end namespace multi_front_end
}; // end namespace core

}; // end namespace behavioural
}; // end namespace morpheo              
