/*
 * $Id: Parameters.cpp 124 2009-06-17 12:11:25Z rosiere $
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_Front_end/Front_end/Prediction_unit/Direction/Meta_Predictor/Two_Level_Branch_Predictor/include/Parameters.h"
#include "Common/include/BitManipulation.h"

namespace morpheo {
namespace behavioural {
namespace core {
namespace multi_front_end {
namespace front_end {
namespace prediction_unit {
namespace direction {
namespace meta_predictor {
namespace two_level_branch_predictor {


#undef  FUNCTION
#define FUNCTION "Two_Level_Branch_Predictor::Parameters"
  Parameters::Parameters (uint32_t nb_inst_predict       ,
                          uint32_t nb_inst_update        ,
                          uint32_t size_address          ,
                          bool     have_bht              ,
                          uint32_t bht_size_shifter      ,
                          uint32_t bht_nb_shifter        ,
                          bool     have_pht              ,
                          uint32_t pht_size_counter      ,
                          uint32_t pht_nb_counter        ,
                          uint32_t pht_size_address_share,
                          bool     update_on_prediction  ,
                          bool is_toplevel)
  {
    log_begin(Two_Level_Branch_Predictor,FUNCTION);

    _nb_inst_predict         = nb_inst_predict       ;
    _nb_inst_update          = nb_inst_update        ;
    _size_address            = size_address          ;
    _have_bht                = have_bht              ;
    _bht_size_shifter        = (have_bht)?(bht_size_shifter):0;
    _bht_nb_shifter          = (have_bht)?(bht_nb_shifter  ):0;
    _have_pht                = have_pht              ;
    _pht_size_counter        = (have_pht)?(pht_size_counter):0;
    _pht_nb_counter          = (have_pht)?(pht_nb_counter  ):0;
    _pht_size_address_share  = (have_bht and have_pht)?(pht_size_address_share):0;
    _update_on_prediction    = update_on_prediction  ;
                             
    _bht_size_address        = (_have_bht)?log2(_bht_nb_shifter):0;
    _pht_size_address        = (_have_pht)?log2(_pht_nb_counter):0;
                             
    test();                  

    // history to update_prediction_table :
    //  MSB : pht_history
    //  LSB : bht_history
    log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _have_bht                 : %d",_have_bht        );
    log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _bht_size_shifter         : %d",_bht_size_shifter);
    log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _bht_nb_shifter           : %d",_bht_nb_shifter  );

    log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _have_pht                 : %d",_have_pht        );
    log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _pht_size_counter         : %d",_pht_size_counter);
    log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _pht_nb_counter           : %d",_pht_nb_counter  );
                       
    _size_history            = _bht_size_shifter + _pht_size_counter;
    _bht_history_mask        = gen_mask<Thistory_t>(_bht_size_shifter);
    _bht_history_shift       = 0;
    _pht_history_mask        = gen_mask<Thistory_t>(_pht_size_counter);
    _pht_history_shift       = _bht_size_shifter;
                             
    log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _size_history             : %d",_size_history  );
    log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _bht_history_mask         : 0x%llx",_bht_history_mask  );
    log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _bht_history_shift        : %lld",_bht_history_shift );
    log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _pht_history_mask         : 0x%llx",_pht_history_mask  );
    log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _pht_history_shift        : %lld",_pht_history_shift );

    _bht_init_take           = static_cast<Thistory_t>(-1)&_bht_history_mask;
    _bht_init_ntake          = 0;
    _pht_init_take           = (1<<(_pht_size_counter-1)); // size = 4 : 1000/2
    _pht_init_ntake          = _pht_init_take-1;           // size = 4 : 0111/2

    log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _bht_init_take            : 0x%llx",_bht_init_take );
    log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _bht_init_ntake           : 0x%llx",_bht_init_ntake);
    log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _pht_init_take            : 0x%llx",_pht_init_take );
    log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _pht_init_ntake           : 0x%llx",_pht_init_ntake);
    
    if (_have_bht)
      {
        _bht_address_mask        = gen_mask<Taddress_t>(_bht_size_address);

        log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _bht_address_mask         : 0x%x",_bht_address_mask  );
      }

    if (_have_pht)
      {
        _pht_counter_max         = (1<<_pht_size_counter)-1;
        
        _pht_size_bank           = (_have_bht)?(1<<_bht_size_shifter):1;
        _pht_nb_bank             = _pht_nb_counter / _pht_size_bank;

	// -------->|
	//   +---+  |
	//   |   |  |--->
	// ---> --->|
	//   |   |  |
	//   +---+
	//

        _pht_address_share_mask  = gen_mask<Taddress_t>(_pht_size_address_share);
        _pht_address_share_shift = _bht_size_shifter-_pht_size_address_share;
        _pht_address_bank_mask   = gen_mask<Taddress_t>(log2(_pht_nb_bank));
        _pht_address_bank_shift  = _pht_size_address_share;

        log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _pht_nb_bank              : %d"  ,_pht_nb_bank   );
        log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _pht_size_bank            : %d"  ,_pht_size_bank );
        log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _pht_address_share_mask   : 0x%x",_pht_address_share_mask  );
        log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _pht_address_share_shift  : %d"  ,_pht_address_share_shift );
        log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _pht_address_bank_mask    : 0x%x",_pht_address_bank_mask   );
        log_printf(TRACE,Two_Level_Branch_Predictor,FUNCTION,"  * _pht_address_bank_shift   : %d"  ,_pht_address_bank_shift  );
      }

    if (is_toplevel)
      copy();

    log_end(Two_Level_Branch_Predictor,FUNCTION);
  };
  
// #undef  FUNCTION
// #define FUNCTION "Two_Level_Branch_Predictor::Parameters (copy)"
//   Parameters::Parameters (Parameters & param)
//   {
//     log_begin(Two_Level_Branch_Predictor,FUNCTION);
//     test();
//     log_end(Two_Level_Branch_Predictor,FUNCTION);
//   };

#undef  FUNCTION
#define FUNCTION "Two_Level_Branch_Predictor::~Parameters"
  Parameters::~Parameters (void) 
  {
    log_begin(Two_Level_Branch_Predictor,FUNCTION);
    log_end(Two_Level_Branch_Predictor,FUNCTION);
  };

#undef  FUNCTION
#define FUNCTION "Two_Level_Branch_Predictor::copy"
  void Parameters::copy (void) 
  {
    log_begin(Two_Level_Branch_Predictor,FUNCTION);
    log_end(Two_Level_Branch_Predictor,FUNCTION);
  };

}; // end namespace two_level_branch_predictor
}; // end namespace meta_predictor
}; // 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              
