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

#define NB_ITERATION 1

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

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

  Two_Level_Branch_Predictor * _Two_Level_Branch_Predictor = new Two_Level_Branch_Predictor (name.c_str(),
#ifdef STATISTICS
					     morpheo::behavioural::Parameters_Statistics(5,50),
#endif
					     param);
  
#ifdef SYSTEMC

  /*********************************************************************
   * Déclarations des signaux
   *********************************************************************/
  sc_clock                              *  CLOCK ("clock", 1.0, 0.5);

  sc_signal<Tcontrol_t>                 *  PREDICT_VAL                 [param._nb_prediction];
  sc_signal<Tcontrol_t>                 *  PREDICT_ACK                 [param._nb_prediction];
  sc_signal<Taddress_t>                 *  PREDICT_ADDRESS             [param._nb_prediction];
  sc_signal<Tbht_history_t>             *  PREDICT_BHT_HISTORY         [param._nb_prediction];
  sc_signal<Tpht_history_t>             *  PREDICT_PHT_HISTORY         [param._nb_prediction];
				      	 
  sc_signal<Tcontrol_t>                 *  BRANCH_COMPLETE_VAL         [param._nb_branch_complete];
  sc_signal<Tcontrol_t>                 *  BRANCH_COMPLETE_ACK         [param._nb_branch_complete];
  sc_signal<Taddress_t>                 *  BRANCH_COMPLETE_ADDRESS     [param._nb_branch_complete];
  sc_signal<Tbht_history_t>             *  BRANCH_COMPLETE_BHT_HISTORY [param._nb_branch_complete];
  sc_signal<Tpht_history_t>             *  BRANCH_COMPLETE_PHT_HISTORY [param._nb_branch_complete];
  sc_signal<Tcontrol_t>                 *  BRANCH_COMPLETE_HIT         [param._nb_branch_complete];

  // Rename signal

  string rename;

  CLOCK = new sc_clock ("clock", 1.0, 0.5);

  for (uint32_t i=0; i<param._nb_prediction; i++)
    {
      rename = "PREDICT_VAL_"        +toString(i);
      PREDICT_VAL                 [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_ADDRESS_"    +toString(i);
      PREDICT_ADDRESS             [i] = new sc_signal<Taddress_t>     (rename.c_str());
      rename = "PREDICT_BHT_HISTORY_"+toString(i);
      PREDICT_BHT_HISTORY         [i] = new sc_signal<Tbht_history_t> (rename.c_str());
      rename = "PREDICT_PHT_HISTORY_"+toString(i);
      PREDICT_PHT_HISTORY         [i] = new sc_signal<Tpht_history_t> (rename.c_str());
    }
  
  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_ACK_"        +toString(i);
      BRANCH_COMPLETE_ACK         [i] = new sc_signal<Tcontrol_t>     (rename.c_str());
      rename = "BRANCH_COMPLETE_ADDRESS_"    +toString(i);
      BRANCH_COMPLETE_ADDRESS     [i] = new sc_signal<Taddress_t>     (rename.c_str());
      rename = "BRANCH_COMPLETE_BHT_HISTORY_"+toString(i);
      BRANCH_COMPLETE_BHT_HISTORY [i] = new sc_signal<Tbht_history_t> (rename.c_str());
      rename = "BRANCH_COMPLETE_PHT_HISTORY_"+toString(i);
      BRANCH_COMPLETE_PHT_HISTORY [i] = new sc_signal<Tpht_history_t> (rename.c_str());
      rename = "BRANCH_COMPLETE_HIT_"        +toString(i);
      BRANCH_COMPLETE_HIT         [i] = new sc_signal<Tcontrol_t>     (rename.c_str());
    }

  /********************************************************
   * Instanciation
   ********************************************************/
  
  cout << "<" << name << "> Instanciation of _Two_Level_Branch_Predictor" << endl;
  
  (*(_Two_Level_Branch_Predictor->in_CLOCK))        (*(CLOCK));

    for (uint32_t i=0; i<param._nb_prediction; i++)
      {
	(*(_Two_Level_Branch_Predictor-> in_PREDICT_VAL                 [i])) (*(PREDICT_VAL                  [i]));
	(*(_Two_Level_Branch_Predictor->out_PREDICT_ACK                 [i])) (*(PREDICT_ACK                  [i]));
	(*(_Two_Level_Branch_Predictor-> in_PREDICT_ADDRESS             [i])) (*(PREDICT_ADDRESS              [i]));
	if (param._have_bht)						       				       
	(*(_Two_Level_Branch_Predictor->out_PREDICT_BHT_HISTORY         [i])) (*(PREDICT_BHT_HISTORY          [i]));
	if (param._have_pht)						       				       
	(*(_Two_Level_Branch_Predictor->out_PREDICT_PHT_HISTORY         [i])) (*(PREDICT_PHT_HISTORY          [i]));
      }

    for (uint32_t i=0; i<param._nb_branch_complete; i++)
      {
	(*(_Two_Level_Branch_Predictor-> in_BRANCH_COMPLETE_VAL         [i])) (*(BRANCH_COMPLETE_VAL          [i]));
	(*(_Two_Level_Branch_Predictor->out_BRANCH_COMPLETE_ACK         [i])) (*(BRANCH_COMPLETE_ACK          [i]));
	(*(_Two_Level_Branch_Predictor-> in_BRANCH_COMPLETE_ADDRESS     [i])) (*(BRANCH_COMPLETE_ADDRESS      [i]));
	if (param._have_bht)						       					
	(*(_Two_Level_Branch_Predictor-> in_BRANCH_COMPLETE_BHT_HISTORY [i])) (*(BRANCH_COMPLETE_BHT_HISTORY  [i]));
	if (param._have_bht)						       					
	(*(_Two_Level_Branch_Predictor-> in_BRANCH_COMPLETE_PHT_HISTORY [i])) (*(BRANCH_COMPLETE_PHT_HISTORY  [i]));
	(*(_Two_Level_Branch_Predictor-> in_BRANCH_COMPLETE_HIT         [i])) (*(BRANCH_COMPLETE_HIT          [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);

  for (uint32_t i=0; i<param._nb_prediction; i++)
    PREDICT_VAL                  [i]->write(0);
  for (uint32_t i=0; i<param._nb_branch_complete; i++)
    BRANCH_COMPLETE_VAL          [i]->write(0);

  _Two_Level_Branch_Predictor->vhdl_testbench_label("Initialisation");
  cout << "{"+toString(static_cast<uint32_t>(sc_simulation_time()))+"} Initialisation" << endl;

  // Step 1
  BRANCH_COMPLETE_VAL          [0]->write(1);
  BRANCH_COMPLETE_HIT          [0]->write(0);

  if (param._have_bht)						       					
    {
      BRANCH_COMPLETE_BHT_HISTORY  [0]->write(0);
      
      _Two_Level_Branch_Predictor->vhdl_testbench_label("Init bht");
      cout << "{"+toString(static_cast<uint32_t>(sc_simulation_time()))+"} Init bht" << endl;
      
      for (uint32_t i=0; i<param._bht_nb_shifter; i++)
	{
	  BRANCH_COMPLETE_ADDRESS [0]->write(i);

	  sc_start(1);
	}

      // wait ackwolegde
      while (BRANCH_COMPLETE_ACK [0] -> read() == 0)
	sc_start(1);
    }

  if (param._have_pht)						       					
    {
      BRANCH_COMPLETE_BHT_HISTORY  [0]->write(0);
      BRANCH_COMPLETE_PHT_HISTORY  [0]->write(0);
      
      _Two_Level_Branch_Predictor->vhdl_testbench_label("Init bht");
      cout << "{"+toString(static_cast<uint32_t>(sc_simulation_time()))+"} Init bht" << endl;
      
      for (uint32_t i=0; i<param._bht_nb_shifter; i++)
	{
	  BRANCH_COMPLETE_ADDRESS [0]->write(i);

	  sc_start(1);
	}

      // wait ackwolegde
      while (BRANCH_COMPLETE_ACK [0] -> read() == 0)
	sc_start(1);
    }



  // Step 2
  _Two_Level_Branch_Predictor->vhdl_testbench_label("Loop of Test");
  cout << "{"+toString(static_cast<uint32_t>(sc_simulation_time()))+"} Loop of Test" << endl;

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

      sc_start(1);
    }

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

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

#endif

  delete _Two_Level_Branch_Predictor;
}
