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

#define NB_ITERATION 1024

#include "Behavioural/Stage_1_Ifetch/Predictor/Meta_Predictor/Meta_Predictor_Glue/SelfTest/include/test.h"
#include "Include/Test.h"

void test (string name,
	   morpheo::behavioural::stage_1_ifetch::predictor::meta_predictor::meta_predictor_glue::Parameters _param)
{
  cout << "<" << name << "> : Simulation SystemC" << endl;

  Meta_Predictor_Glue * _Meta_Predictor_Glue = new Meta_Predictor_Glue (name.c_str(),
#ifdef STATISTICS
									morpheo::behavioural::Parameters_Statistics(5,50),
#endif
									_param);
  
#ifdef SYSTEMC
  /*********************************************************************
   * Déclarations des signaux
   *********************************************************************/
  sc_clock                         * CLOCK;

    // Interface Predict
  sc_signal<Tcontrol_t>           ** PREDICT_PREDICTOR_0_ACK                ;
  sc_signal<Tcontrol_t>           ** PREDICT_PREDICTOR_1_ACK                ;
  sc_signal<Tcontrol_t>           ** PREDICT_PREDICTOR_2_ACK                ;
  sc_signal<Tcontrol_t>           ** PREDICT_ACK                            ;

  sc_signal<Tbht_history_t>       ** PREDICT_PREDICTOR_0_BHT_HISTORY        ;
  sc_signal<Tpht_history_t>       ** PREDICT_PREDICTOR_0_PHT_HISTORY        ;
  sc_signal<Tbht_history_t>       ** PREDICT_PREDICTOR_1_BHT_HISTORY        ;
  sc_signal<Tpht_history_t>       ** PREDICT_PREDICTOR_1_PHT_HISTORY        ;
  sc_signal<Tbht_history_t>       ** PREDICT_PREDICTOR_2_BHT_HISTORY        ;
  sc_signal<Tpht_history_t>       ** PREDICT_PREDICTOR_2_PHT_HISTORY        ;
  sc_signal<Thistory_t>           ** PREDICT_HISTORY                        ;
  sc_signal<Tcontrol_t>           ** PREDICT_DIRECTION                      ;

    // Interface Branch_complete
  sc_signal<Tcontrol_t>           ** BRANCH_COMPLETE_VAL                    ;
  sc_signal<Tcontrol_t>           ** BRANCH_COMPLETE_PREDICTOR_2_VAL        ;

  sc_signal<Tcontrol_t>           ** BRANCH_COMPLETE_PREDICTOR_0_ACK        ;
  sc_signal<Tcontrol_t>           ** BRANCH_COMPLETE_PREDICTOR_1_ACK        ;
  sc_signal<Tcontrol_t>           ** BRANCH_COMPLETE_PREDICTOR_2_ACK        ;
  sc_signal<Tcontrol_t>           ** BRANCH_COMPLETE_ACK                    ;

  sc_signal<Tbht_history_t>       ** BRANCH_COMPLETE_PREDICTOR_0_BHT_HISTORY;
  sc_signal<Tpht_history_t>       ** BRANCH_COMPLETE_PREDICTOR_0_PHT_HISTORY;
  sc_signal<Tbht_history_t>       ** BRANCH_COMPLETE_PREDICTOR_1_BHT_HISTORY;
  sc_signal<Tpht_history_t>       ** BRANCH_COMPLETE_PREDICTOR_1_PHT_HISTORY;
  sc_signal<Tbht_history_t>       ** BRANCH_COMPLETE_PREDICTOR_2_BHT_HISTORY;
  sc_signal<Tpht_history_t>       ** BRANCH_COMPLETE_PREDICTOR_2_PHT_HISTORY;
  sc_signal<Thistory_t>           ** BRANCH_COMPLETE_HISTORY                ;
  sc_signal<Tcontrol_t>           ** BRANCH_COMPLETE_DIRECTION              ;
  sc_signal<Tcontrol_t>           ** BRANCH_COMPLETE_PREDICTOR_2_DIRECTION  ;
  string rename;

#if defined(STATISTICS) or defined(VHDL_TESTBENCH)
  CLOCK                                  = new sc_clock ("clock", 1.0, 0.5);
#endif  

    // Interface Predict

    PREDICT_PREDICTOR_0_ACK         = new sc_signal<Tcontrol_t>     * [_param._nb_prediction     ];
    PREDICT_PREDICTOR_1_ACK         = new sc_signal<Tcontrol_t>     * [_param._nb_prediction     ];
    PREDICT_PREDICTOR_2_ACK         = new sc_signal<Tcontrol_t>     * [_param._nb_prediction     ];
    PREDICT_ACK                     = new sc_signal<Tcontrol_t>     * [_param._nb_prediction     ];
    PREDICT_PREDICTOR_0_BHT_HISTORY = new sc_signal<Tbht_history_t> * [_param._nb_prediction     ];
    PREDICT_PREDICTOR_0_PHT_HISTORY = new sc_signal<Tpht_history_t> * [_param._nb_prediction     ];
    PREDICT_PREDICTOR_1_BHT_HISTORY = new sc_signal<Tbht_history_t> * [_param._nb_prediction     ];
    PREDICT_PREDICTOR_1_PHT_HISTORY = new sc_signal<Tpht_history_t> * [_param._nb_prediction     ];
    PREDICT_PREDICTOR_2_BHT_HISTORY = new sc_signal<Tbht_history_t> * [_param._nb_prediction     ];
    PREDICT_PREDICTOR_2_PHT_HISTORY = new sc_signal<Tpht_history_t> * [_param._nb_prediction     ];
    PREDICT_HISTORY                 = new sc_signal<Thistory_t>     * [_param._nb_prediction     ];
    PREDICT_DIRECTION               = new sc_signal<Tcontrol_t>     * [_param._nb_prediction     ];

    for (uint32_t i=0; i<_param._nb_prediction; i++)
      {
	rename = "PREDICT_PREDICTOR_0_ACK_"          +toString(i);
	PREDICT_PREDICTOR_0_ACK                   [i] = new sc_signal<Tcontrol_t>     (rename.c_str());
	rename = "PREDICT_PREDICTOR_1_ACK_"          +toString(i);
	PREDICT_PREDICTOR_1_ACK                   [i] = new sc_signal<Tcontrol_t>     (rename.c_str());
	rename = "PREDICT_PREDICTOR_2_ACK_"          +toString(i);
	PREDICT_PREDICTOR_2_ACK                   [i] = new sc_signal<Tcontrol_t>     (rename.c_str());
	rename = "PREDICT_ACK_"                    +toString(i);
	PREDICT_ACK                               [i] = new sc_signal<Tcontrol_t>     (rename.c_str());
	rename = "PREDICT_PREDICTOR_0_BHT_HISTORY_"+toString(i);
	PREDICT_PREDICTOR_0_BHT_HISTORY           [i] = new sc_signal<Tbht_history_t> (rename.c_str());
	rename = "PREDICT_PREDICTOR_0_PHT_HISTORY_"+toString(i);
	PREDICT_PREDICTOR_0_PHT_HISTORY           [i] = new sc_signal<Tpht_history_t> (rename.c_str());
	rename = "PREDICT_PREDICTOR_1_BHT_HISTORY_"+toString(i);
	PREDICT_PREDICTOR_1_BHT_HISTORY           [i] = new sc_signal<Tbht_history_t> (rename.c_str());
	rename = "PREDICT_PREDICTOR_1_PHT_HISTORY_"+toString(i);
	PREDICT_PREDICTOR_1_PHT_HISTORY           [i] = new sc_signal<Tpht_history_t> (rename.c_str());
	rename = "PREDICT_PREDICTOR_2_BHT_HISTORY_"+toString(i);
	PREDICT_PREDICTOR_2_BHT_HISTORY           [i] = new sc_signal<Tbht_history_t> (rename.c_str());
	rename = "PREDICT_PREDICTOR_2_PHT_HISTORY_"+toString(i);
	PREDICT_PREDICTOR_2_PHT_HISTORY           [i] = new sc_signal<Tpht_history_t> (rename.c_str());
	rename = "PREDICT_HISTORY_"                +toString(i);
	PREDICT_HISTORY                           [i] = new sc_signal<Thistory_t>     (rename.c_str());
    	rename = "PREDICT_DIRECTION_"              +toString(i);
	PREDICT_DIRECTION                         [i] = new sc_signal<Tcontrol_t>     (rename.c_str());
      }

    // Interface Branch_complete
    BRANCH_COMPLETE_VAL                     = new sc_signal<Tcontrol_t>     * [_param._nb_branch_complete     ];
    BRANCH_COMPLETE_PREDICTOR_2_VAL         = new sc_signal<Tcontrol_t>     * [_param._nb_branch_complete     ];
    BRANCH_COMPLETE_PREDICTOR_0_ACK         = new sc_signal<Tcontrol_t>     * [_param._nb_branch_complete     ];
    BRANCH_COMPLETE_PREDICTOR_1_ACK         = new sc_signal<Tcontrol_t>     * [_param._nb_branch_complete     ];
    BRANCH_COMPLETE_PREDICTOR_2_ACK         = new sc_signal<Tcontrol_t>     * [_param._nb_branch_complete     ];
    BRANCH_COMPLETE_ACK                     = new sc_signal<Tcontrol_t>     * [_param._nb_branch_complete     ];
    BRANCH_COMPLETE_PREDICTOR_0_BHT_HISTORY = new sc_signal<Tbht_history_t> * [_param._nb_branch_complete     ];
    BRANCH_COMPLETE_PREDICTOR_0_PHT_HISTORY = new sc_signal<Tpht_history_t> * [_param._nb_branch_complete     ];
    BRANCH_COMPLETE_PREDICTOR_1_BHT_HISTORY = new sc_signal<Tbht_history_t> * [_param._nb_branch_complete     ];
    BRANCH_COMPLETE_PREDICTOR_1_PHT_HISTORY = new sc_signal<Tpht_history_t> * [_param._nb_branch_complete     ];
    BRANCH_COMPLETE_PREDICTOR_2_BHT_HISTORY = new sc_signal<Tbht_history_t> * [_param._nb_branch_complete     ];
    BRANCH_COMPLETE_PREDICTOR_2_PHT_HISTORY = new sc_signal<Tpht_history_t> * [_param._nb_branch_complete     ];
    BRANCH_COMPLETE_HISTORY                 = new sc_signal<Thistory_t>     * [_param._nb_branch_complete     ];
    BRANCH_COMPLETE_DIRECTION               = new sc_signal<Tcontrol_t>     * [_param._nb_branch_complete     ];
    BRANCH_COMPLETE_PREDICTOR_2_DIRECTION   = new sc_signal<Tcontrol_t>     * [_param._nb_branch_complete     ];

    for (uint32_t i=0; i<_param._nb_branch_complete; i++)
      {
	rename = "BRANCH_COMPLETE_VAL_"                      +toString(i);
	BRANCH_COMPLETE_VAL                               [i] = new sc_signal<Tcontrol_t>     (rename.c_str());
	rename = "BRANCH_COMPLETE_PREDICTOR_2_VAL_"          +toString(i);
	BRANCH_COMPLETE_PREDICTOR_2_VAL                   [i] = new sc_signal<Tcontrol_t>     (rename.c_str());
	rename = "BRANCH_COMPLETE_PREDICTOR_0_ACK_"          +toString(i);
	BRANCH_COMPLETE_PREDICTOR_0_ACK                   [i] = new sc_signal<Tcontrol_t>     (rename.c_str());
	rename = "BRANCH_COMPLETE_PREDICTOR_1_ACK_"          +toString(i);
	BRANCH_COMPLETE_PREDICTOR_1_ACK                   [i] = new sc_signal<Tcontrol_t>     (rename.c_str());
	rename = "BRANCH_COMPLETE_PREDICTOR_2_ACK_"          +toString(i);
	BRANCH_COMPLETE_PREDICTOR_2_ACK                   [i] = new sc_signal<Tcontrol_t>     (rename.c_str());
	rename = "BRANCH_COMPLETE_ACK_"                    +toString(i);
	BRANCH_COMPLETE_ACK                               [i] = new sc_signal<Tcontrol_t>     (rename.c_str());
	rename = "BRANCH_COMPLETE_PREDICTOR_0_BHT_HISTORY_"+toString(i);
	BRANCH_COMPLETE_PREDICTOR_0_BHT_HISTORY           [i] = new sc_signal<Tbht_history_t> (rename.c_str());
	rename = "BRANCH_COMPLETE_PREDICTOR_0_PHT_HISTORY_"+toString(i);
	BRANCH_COMPLETE_PREDICTOR_0_PHT_HISTORY           [i] = new sc_signal<Tpht_history_t> (rename.c_str());
	rename = "BRANCH_COMPLETE_PREDICTOR_1_BHT_HISTORY_"+toString(i);
	BRANCH_COMPLETE_PREDICTOR_1_BHT_HISTORY           [i] = new sc_signal<Tbht_history_t> (rename.c_str());
	rename = "BRANCH_COMPLETE_PREDICTOR_1_PHT_HISTORY_"+toString(i);
	BRANCH_COMPLETE_PREDICTOR_1_PHT_HISTORY           [i] = new sc_signal<Tpht_history_t> (rename.c_str());
	rename = "BRANCH_COMPLETE_PREDICTOR_2_BHT_HISTORY_"+toString(i);
	BRANCH_COMPLETE_PREDICTOR_2_BHT_HISTORY           [i] = new sc_signal<Tbht_history_t> (rename.c_str());
	rename = "BRANCH_COMPLETE_PREDICTOR_2_PHT_HISTORY_"+toString(i);
	BRANCH_COMPLETE_PREDICTOR_2_PHT_HISTORY           [i] = new sc_signal<Tpht_history_t> (rename.c_str());
	rename = "BRANCH_COMPLETE_HISTORY_"                +toString(i);
	BRANCH_COMPLETE_HISTORY                           [i] = new sc_signal<Thistory_t>     (rename.c_str());
	rename = "BRANCH_COMPLETE_DIRECTION_"              +toString(i);
	BRANCH_COMPLETE_DIRECTION                         [i] = new sc_signal<Tcontrol_t>     (rename.c_str());
	rename = "BRANCH_COMPLETE_PREDICTOR_2_DIRECTION_"  +toString(i);
	BRANCH_COMPLETE_PREDICTOR_2_DIRECTION             [i] = new sc_signal<Tcontrol_t>     (rename.c_str());
      }

  /********************************************************
   * Instanciation
   ********************************************************/
  
  cout << "<" << name << "> Instanciation of _Meta_Predictor_Glue" << endl;
  
#if defined(STATISTICS) or defined(VHDL_TESTBENCH)
  (*(_Meta_Predictor_Glue->in_CLOCK))        (*(CLOCK));
#endif

    // Interface Predict
    for (uint32_t i=0; i<_param._nb_prediction; i++)
      {
	if (_param._have_meta_predictor)
	  {
	(*(_Meta_Predictor_Glue-> in_PREDICT_PREDICTOR_0_ACK                 [i])) (*(PREDICT_PREDICTOR_0_ACK                 [i]));
	(*(_Meta_Predictor_Glue-> in_PREDICT_PREDICTOR_1_ACK                 [i])) (*(PREDICT_PREDICTOR_1_ACK                 [i]));
	  }									      					      
	(*(_Meta_Predictor_Glue-> in_PREDICT_PREDICTOR_2_ACK                 [i])) (*(PREDICT_PREDICTOR_2_ACK                 [i]));
	(*(_Meta_Predictor_Glue->out_PREDICT_ACK                             [i])) (*(PREDICT_ACK                             [i]));
	if (_param._have_meta_predictor)
	  {									      					      
	if (_param._predictor_0_have_bht)
	(*(_Meta_Predictor_Glue-> in_PREDICT_PREDICTOR_0_BHT_HISTORY         [i])) (*(PREDICT_PREDICTOR_0_BHT_HISTORY         [i]));
	if (_param._predictor_0_have_pht)
	(*(_Meta_Predictor_Glue-> in_PREDICT_PREDICTOR_0_PHT_HISTORY         [i])) (*(PREDICT_PREDICTOR_0_PHT_HISTORY         [i]));
	if (_param._predictor_1_have_bht)
	(*(_Meta_Predictor_Glue-> in_PREDICT_PREDICTOR_1_BHT_HISTORY         [i])) (*(PREDICT_PREDICTOR_1_BHT_HISTORY         [i]));
	if (_param._predictor_1_have_pht)
	(*(_Meta_Predictor_Glue-> in_PREDICT_PREDICTOR_1_PHT_HISTORY         [i])) (*(PREDICT_PREDICTOR_1_PHT_HISTORY         [i]));
	  }									      					      
	if (_param._predictor_2_have_bht)
	(*(_Meta_Predictor_Glue-> in_PREDICT_PREDICTOR_2_BHT_HISTORY         [i])) (*(PREDICT_PREDICTOR_2_BHT_HISTORY         [i]));
	if (_param._predictor_2_have_pht)
	(*(_Meta_Predictor_Glue-> in_PREDICT_PREDICTOR_2_PHT_HISTORY         [i])) (*(PREDICT_PREDICTOR_2_PHT_HISTORY         [i]));
	(*(_Meta_Predictor_Glue->out_PREDICT_HISTORY                         [i])) (*(PREDICT_HISTORY                         [i]));
	(*(_Meta_Predictor_Glue->out_PREDICT_DIRECTION                       [i])) (*(PREDICT_DIRECTION                       [i]));
      }

    // Interface Branch_complete
    
    for (uint32_t i=0; i<_param._nb_branch_complete; i++)
      {
	if (_param._have_meta_predictor)
	  {
	(*(_Meta_Predictor_Glue-> in_BRANCH_COMPLETE_VAL                     [i])) (*(BRANCH_COMPLETE_VAL                     [i]));
	(*(_Meta_Predictor_Glue->out_BRANCH_COMPLETE_PREDICTOR_2_VAL         [i])) (*(BRANCH_COMPLETE_PREDICTOR_2_VAL         [i]));

	(*(_Meta_Predictor_Glue-> in_BRANCH_COMPLETE_PREDICTOR_0_ACK         [i])) (*(BRANCH_COMPLETE_PREDICTOR_0_ACK         [i]));
	(*(_Meta_Predictor_Glue-> in_BRANCH_COMPLETE_PREDICTOR_1_ACK         [i])) (*(BRANCH_COMPLETE_PREDICTOR_1_ACK         [i]));
	  }					
	(*(_Meta_Predictor_Glue-> in_BRANCH_COMPLETE_PREDICTOR_2_ACK         [i])) (*(BRANCH_COMPLETE_PREDICTOR_2_ACK         [i]));
	(*(_Meta_Predictor_Glue->out_BRANCH_COMPLETE_ACK                     [i])) (*(BRANCH_COMPLETE_ACK                     [i]));
						
	if (_param._have_meta_predictor)	
	  {					
	if (_param._predictor_0_have_bht)
	(*(_Meta_Predictor_Glue->out_BRANCH_COMPLETE_PREDICTOR_0_BHT_HISTORY [i])) (*(BRANCH_COMPLETE_PREDICTOR_0_BHT_HISTORY [i]));
	if (_param._predictor_0_have_pht)
	(*(_Meta_Predictor_Glue->out_BRANCH_COMPLETE_PREDICTOR_0_PHT_HISTORY [i])) (*(BRANCH_COMPLETE_PREDICTOR_0_PHT_HISTORY [i]));
	if (_param._predictor_1_have_bht)
	(*(_Meta_Predictor_Glue->out_BRANCH_COMPLETE_PREDICTOR_1_BHT_HISTORY [i])) (*(BRANCH_COMPLETE_PREDICTOR_1_BHT_HISTORY [i]));
	if (_param._predictor_1_have_pht)
	(*(_Meta_Predictor_Glue->out_BRANCH_COMPLETE_PREDICTOR_1_PHT_HISTORY [i])) (*(BRANCH_COMPLETE_PREDICTOR_1_PHT_HISTORY [i]));
	  }					
	if (_param._predictor_2_have_bht)
	(*(_Meta_Predictor_Glue->out_BRANCH_COMPLETE_PREDICTOR_2_BHT_HISTORY [i])) (*(BRANCH_COMPLETE_PREDICTOR_2_BHT_HISTORY [i]));
	if (_param._predictor_2_have_pht)
	(*(_Meta_Predictor_Glue->out_BRANCH_COMPLETE_PREDICTOR_2_PHT_HISTORY [i])) (*(BRANCH_COMPLETE_PREDICTOR_2_PHT_HISTORY [i]));
	(*(_Meta_Predictor_Glue-> in_BRANCH_COMPLETE_HISTORY                 [i])) (*(BRANCH_COMPLETE_HISTORY                 [i]));
	if (_param._have_meta_predictor)	
	  {
	(*(_Meta_Predictor_Glue-> in_BRANCH_COMPLETE_DIRECTION               [i])) (*(BRANCH_COMPLETE_DIRECTION               [i]));
	(*(_Meta_Predictor_Glue->out_BRANCH_COMPLETE_PREDICTOR_2_DIRECTION   [i])) (*(BRANCH_COMPLETE_PREDICTOR_2_DIRECTION   [i]));
	  }
      }

  /********************************************************
   * Simulation - Begin
   ********************************************************/

  cout << "<" << name << "> Start Simulation ............" << endl;
  // Initialisation

  const uint32_t seed = 0;
//const uint32_t seed = static_cast<uint32_t>(time(NULL));

  srand(seed);

  sc_start(0);
  _Meta_Predictor_Glue->vhdl_testbench_label("Initialisation");
  cout << "{"+toString(static_cast<uint32_t>(sc_simulation_time()))+"} Initialisation" << endl;
  
  // No need initialisation

  _Meta_Predictor_Glue->vhdl_testbench_label("Loop of Test");
  cout << "{"+toString(static_cast<uint32_t>(sc_simulation_time()))+"} Loop of Test" << endl;
  
  Tcontrol_t     predict_ack                             [_param._nb_prediction];
  Thistory_t     predict_history                         [_param._nb_prediction];
  Tcontrol_t     predict_direction                       [_param._nb_prediction];
	        
  Tcontrol_t     branch_complete_predictor_2_val         [_param._nb_branch_complete];
  Tcontrol_t     branch_complete_ack                     [_param._nb_branch_complete];
  Tbht_history_t branch_complete_predictor_0_bht_history [_param._nb_branch_complete];
  Tpht_history_t branch_complete_predictor_0_pht_history [_param._nb_branch_complete];
  Tbht_history_t branch_complete_predictor_1_bht_history [_param._nb_branch_complete];
  Tpht_history_t branch_complete_predictor_1_pht_history [_param._nb_branch_complete];
  Tbht_history_t branch_complete_predictor_2_bht_history [_param._nb_branch_complete];
  Tpht_history_t branch_complete_predictor_2_pht_history [_param._nb_branch_complete];
  Tcontrol_t     branch_complete_predictor_2_direction   [_param._nb_branch_complete];

  uint32_t shift_0 = 0;
  uint32_t shift_1 = shift_0 + _param._predictor_0_bht_size_shifter;
  uint32_t shift_2 = shift_1 + _param._predictor_0_pht_size_counter;
  uint32_t shift_3 = shift_2 + _param._predictor_1_bht_size_shifter;
  uint32_t shift_4 = shift_3 + _param._predictor_1_pht_size_counter;
  uint32_t shift_5 = shift_4 + _param._predictor_2_bht_size_shifter;
//uint32_t shift_6 = shift_5 + _param._predictor_2_pht_size_counter;

  for (uint32_t iteration=0; iteration<NB_ITERATION; iteration ++)
    {
      _Meta_Predictor_Glue->vhdl_testbench_label("Iteration "+toString(iteration));

      for (uint32_t i=0; i<_param._nb_prediction; i++)
	{
	  Tcontrol_t     predictor_0_ack        , predictor_1_ack        , predictor_2_ack        ;
	  Tpht_history_t predictor_0_pht_history, predictor_1_pht_history, predictor_2_pht_history;
	  Tbht_history_t predictor_0_bht_history, predictor_1_bht_history, predictor_2_bht_history;

	  predictor_0_ack             = not _param._have_meta_predictor or ((rand()%2) != 0);
	  predictor_1_ack             = not _param._have_meta_predictor or ((rand()%2) != 0);
	  predictor_2_ack             =                                    ((rand()%2) != 0);
	  predict_ack             [i] = predictor_0_ack and predictor_1_ack and predictor_2_ack;

	  PREDICT_PREDICTOR_0_ACK [i] ->write (predictor_0_ack);
	  PREDICT_PREDICTOR_1_ACK [i] ->write (predictor_1_ack);
	  PREDICT_PREDICTOR_2_ACK [i] ->write (predictor_2_ack);
				      
	  predictor_0_bht_history     = rand() % (_param._predictor_0_bht_size_shifter+1);
	  predictor_0_pht_history     = rand() % (_param._predictor_0_pht_size_counter+1);
	  predictor_1_bht_history     = rand() % (_param._predictor_1_bht_size_shifter+1);
	  predictor_1_pht_history     = rand() % (_param._predictor_1_pht_size_counter+1);
	  predictor_2_bht_history     = rand() % (_param._predictor_2_bht_size_shifter+1);
	  predictor_2_pht_history     = rand() % (_param._predictor_2_pht_size_counter+1);
				      
	  predict_history         [i] = ( (predictor_0_bht_history << shift_0) |
					  (predictor_0_pht_history << shift_1) |
					  (predictor_1_bht_history << shift_2) |
					  (predictor_1_pht_history << shift_3) |
					  (predictor_2_bht_history << shift_4) |
					  (predictor_2_pht_history << shift_5) );
	  
	  cout << "{"+toString(static_cast<uint32_t>(sc_simulation_time()))+"} predict         [" << i << "]" << endl
	       << "       _2_ " << predictor_2_bht_history << " - " << predictor_2_pht_history << endl
	       << "     _/    " << endl
	       << "    | |-1- " << predictor_1_bht_history << " - " << predictor_1_pht_history << endl
	       << "  --| |    " << endl
	       << "    |_|-0- " << predictor_0_bht_history << " - " << predictor_0_pht_history << endl;


	  Tcontrol_t predict_direction_predictor_2;
	  
	  if (_param._predictor_2_have_pht)
	    predict_direction_predictor_2 = (predictor_2_pht_history & (1<<(_param._predictor_2_pht_size_counter-1))) != 0;
	  else
	    predict_direction_predictor_2 = (predictor_2_bht_history & (1<<(_param._predictor_2_bht_size_shifter-1))) != 0;

	  if (_param._have_meta_predictor == false)
	    predict_direction       [i] = predict_direction_predictor_2;
	  else
	    if (predict_direction_predictor_2 == false)
	      if (_param._predictor_0_have_pht)
		predict_direction       [i] = (predictor_0_pht_history & (1<<(_param._predictor_0_pht_size_counter-1))) != 0;
	      else
		predict_direction       [i] = (predictor_0_bht_history & (1<<(_param._predictor_0_bht_size_shifter-1))) != 0;
	    else
	      if (_param._predictor_1_have_pht)
		predict_direction       [i] = (predictor_1_pht_history & (1<<(_param._predictor_1_pht_size_counter-1))) != 0;
	      else
		predict_direction       [i] = (predictor_1_bht_history & (1<<(_param._predictor_1_bht_size_shifter-1))) != 0;

	  PREDICT_PREDICTOR_0_BHT_HISTORY [i]->write(predictor_0_bht_history);
	  PREDICT_PREDICTOR_0_PHT_HISTORY [i]->write(predictor_0_pht_history);
	  PREDICT_PREDICTOR_1_BHT_HISTORY [i]->write(predictor_1_bht_history);
	  PREDICT_PREDICTOR_1_PHT_HISTORY [i]->write(predictor_1_pht_history);
	  PREDICT_PREDICTOR_2_BHT_HISTORY [i]->write(predictor_2_bht_history);
	  PREDICT_PREDICTOR_2_PHT_HISTORY [i]->write(predictor_2_pht_history);
	}

      for (uint32_t i=0; i<_param._nb_branch_complete; i++)
	{
	  Tcontrol_t     predictor_0_ack        , predictor_1_ack        , predictor_2_ack        ;

	  predictor_0_ack                             = not _param._have_meta_predictor or ((rand()%2) != 0);
	  predictor_1_ack                             = not _param._have_meta_predictor or ((rand()%2) != 0);
	  predictor_2_ack                             =                                    ((rand()%2) != 0);
	  branch_complete_ack                     [i] = predictor_0_ack and predictor_1_ack and predictor_2_ack;

	  BRANCH_COMPLETE_PREDICTOR_0_ACK         [i] ->write (predictor_0_ack);
	  BRANCH_COMPLETE_PREDICTOR_1_ACK         [i] ->write (predictor_1_ack);
	  BRANCH_COMPLETE_PREDICTOR_2_ACK         [i] ->write (predictor_2_ack);

	  branch_complete_predictor_0_bht_history [i] = rand() % (_param._predictor_0_bht_size_shifter+1);
	  branch_complete_predictor_0_pht_history [i] = rand() % (_param._predictor_0_pht_size_counter+1);
	  branch_complete_predictor_1_bht_history [i] = rand() % (_param._predictor_1_bht_size_shifter+1);
	  branch_complete_predictor_1_pht_history [i] = rand() % (_param._predictor_1_pht_size_counter+1);
	  branch_complete_predictor_2_bht_history [i] = rand() % (_param._predictor_2_bht_size_shifter+1);
	  branch_complete_predictor_2_pht_history [i] = rand() % (_param._predictor_2_pht_size_counter+1);
		
	  BRANCH_COMPLETE_HISTORY                 [i]->write((branch_complete_predictor_0_bht_history [i] << shift_0) |
							     (branch_complete_predictor_0_pht_history [i] << shift_1) |
							     (branch_complete_predictor_1_bht_history [i] << shift_2) |
							     (branch_complete_predictor_1_pht_history [i] << shift_3) |
							     (branch_complete_predictor_2_bht_history [i] << shift_4) |
							     (branch_complete_predictor_2_pht_history [i] << shift_5) );

	  Tcontrol_t direction_0 = ((_param._predictor_0_have_pht)?(branch_complete_predictor_0_pht_history [i] >> (_param._predictor_0_pht_size_counter-1)):(branch_complete_predictor_0_bht_history [i] >> (_param._predictor_0_bht_size_shifter-1)))&1;
	  Tcontrol_t direction_1 = ((_param._predictor_1_have_pht)?(branch_complete_predictor_1_pht_history [i] >> (_param._predictor_1_pht_size_counter-1)):(branch_complete_predictor_1_bht_history [i] >> (_param._predictor_1_bht_size_shifter-1)))&1;
	  Tcontrol_t direction_2 = ((_param._predictor_2_have_pht)?(branch_complete_predictor_2_pht_history [i] >> (_param._predictor_2_pht_size_counter-1)):(branch_complete_predictor_2_bht_history [i] >> (_param._predictor_2_bht_size_shifter-1)))&1;

	  Tcontrol_t direction   = ((rand()%2) != 0);
	  Tcontrol_t val         = ((rand()%2) != 0);

	  cout << "{"+toString(static_cast<uint32_t>(sc_simulation_time()))+"} " << endl 
	       << "  * val             : " << val << endl
	       << "  * direction_good  : " << direction << endl
	       << "    * direction_0   : " << direction_0 << endl
	       << "    * direction_1   : " << direction_1 << endl
	       << "    * direction_2   : " << direction_2 << endl;
	  
	  BRANCH_COMPLETE_VAL       [i] ->write (val);
	  BRANCH_COMPLETE_DIRECTION [i] ->write (direction);
	  
	  if (val == 0)
	    {
	      branch_complete_predictor_2_val [i] = val;
	    }
	  else
	    {
	      branch_complete_predictor_2_val [i] = (direction_0 xor direction_1);
	      if (direction_2 == 0)
		if (direction_0 == direction)
		  branch_complete_predictor_2_direction [i] = 0;
		else
		  branch_complete_predictor_2_direction [i] = 1;
	      else
		if (direction_1 == direction)
		  branch_complete_predictor_2_direction [i] = 1;
		else
		  branch_complete_predictor_2_direction [i] = 0;
	    }
	}

      sc_start(1);

      for (uint32_t i=0; i<_param._nb_prediction; i++)
	{
	  TEST(Tcontrol_t    , PREDICT_ACK                             [i]->read(), predict_ack                             [i]);
	  TEST(Tcontrol_t    , PREDICT_HISTORY                         [i]->read(), predict_history                         [i]);
	  TEST(Tcontrol_t    , PREDICT_DIRECTION                       [i]->read(), predict_direction                       [i]);
	}

      for (uint32_t i=0; i<_param._nb_branch_complete; i++)
	{
	  TEST(Tcontrol_t    , BRANCH_COMPLETE_ACK                     [i]->read(), branch_complete_ack                     [i]);

	if (_param._have_meta_predictor)	
	  {					
	  TEST(Tcontrol_t    , BRANCH_COMPLETE_PREDICTOR_2_VAL         [i]->read(), branch_complete_predictor_2_val         [i]);

	  if (branch_complete_predictor_2_val         [i])
	  TEST(Tcontrol_t    , BRANCH_COMPLETE_PREDICTOR_2_DIRECTION   [i]->read(), branch_complete_predictor_2_direction   [i]);  

	if (_param._predictor_0_have_bht)
	  TEST(Tbht_history_t, BRANCH_COMPLETE_PREDICTOR_0_BHT_HISTORY [i]->read(), branch_complete_predictor_0_bht_history [i]);
	if (_param._predictor_0_have_pht)
	  TEST(Tpht_history_t, BRANCH_COMPLETE_PREDICTOR_0_PHT_HISTORY [i]->read(), branch_complete_predictor_0_pht_history [i]);
	if (_param._predictor_1_have_bht)
	  TEST(Tbht_history_t, BRANCH_COMPLETE_PREDICTOR_1_BHT_HISTORY [i]->read(), branch_complete_predictor_1_bht_history [i]);
	if (_param._predictor_1_have_pht)
	  TEST(Tpht_history_t, BRANCH_COMPLETE_PREDICTOR_1_PHT_HISTORY [i]->read(), branch_complete_predictor_1_pht_history [i]);
	  }					
	if (_param._predictor_2_have_bht)
	  TEST(Tbht_history_t, BRANCH_COMPLETE_PREDICTOR_2_BHT_HISTORY [i]->read(), branch_complete_predictor_2_bht_history [i]);
	if (_param._predictor_2_have_pht)
	  TEST(Tpht_history_t, BRANCH_COMPLETE_PREDICTOR_2_PHT_HISTORY [i]->read(), branch_complete_predictor_2_pht_history [i]);
	}
    }

  /********************************************************
   * Simulation - End
   ********************************************************/

  cout << "<" << name << "> ............ Stop Simulation" << endl;

#endif

  delete _Meta_Predictor_Glue;
}
