/*
 * $Id: Parameters.cpp 128 2009-06-26 08:43:23Z rosiere $
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Dcache_Access/include/Parameters.h"
#include "Common/include/Max.h"
#include "Common/include/BitManipulation.h"

namespace morpheo {
namespace behavioural {
namespace core {
namespace dcache_access {


#undef  FUNCTION
#define FUNCTION "Dcache_Access::Parameters"
  Parameters::Parameters (uint32_t             nb_thread              ,
                          uint32_t             nb_execute_loop        ,
			  uint32_t           * nb_load_store_unit     ,
			  uint32_t           * nb_context             ,
			  uint32_t          ** nb_cache_access        ,
			  uint32_t             nb_dcache_port         ,
			  uint32_t             size_address           ,
			  uint32_t             size_data              ,
                          uint32_t             size_dcache_thread_id  ,
                          uint32_t             size_dcache_packet_id  ,
			  uint32_t          ** size_thread_id         ,
			  uint32_t          ** size_packet_id         ,
			  uint32_t         *** table_routing          ,
			  Tpriority_t          priority               ,
			  Tload_balancing_t    load_balancing         ,
                          uint32_t         *** translate_load_store_unit_to_thread,
                          bool                 is_toplevel            )
  {
    log_begin(Dcache_Access,FUNCTION);

    _nb_thread              = nb_thread         ;
    _nb_execute_loop        = nb_execute_loop   ;
    _nb_load_store_unit     = nb_load_store_unit;
    _nb_context             = nb_context        ;
    _nb_cache_access        = nb_cache_access   ;
    _nb_dcache_port         = nb_dcache_port    ;
    _size_address           = size_address      ;
    _size_data              = size_data         ;
    _size_dcache_thread_id  = size_dcache_thread_id;
    _size_dcache_packet_id  = size_dcache_packet_id;
    _size_thread_id         = size_thread_id    ;
    _size_packet_id         = size_packet_id    ;
    _table_routing          = table_routing     ;
    _priority               = priority          ;
    _load_balancing         = load_balancing    ;
    _translate_load_store_unit_to_thread = translate_load_store_unit_to_thread;

//     log_printf(TRACE,Dcache_Access,FUNCTION,"  * table_routing");
//     for (uint32_t i=0; i<_nb_execute_loop; i++)
//       for (uint32_t j=0; j<_nb_load_store_unit [i]; ++j)
// 	for (uint32_t k=0; k<_nb_cache_access [i][j]; ++k)
//           log_printf(TRACE,Dcache_Access,FUNCTION,"    [%d][%d][%d] %d",i,j,k,_table_routing [i][j][k]);

//     log_printf(TRACE,Dcache_Access,FUNCTION,"  * translate_load_store_unit_to_thread");
//     for (uint32_t i=0; i<_nb_execute_loop; i++)
//       for (uint32_t j=0; j<_nb_load_store_unit [i]; j++)
//         for (uint32_t k=0; k<_nb_context[i]; k++)
//           log_printf(TRACE,Dcache_Access,FUNCTION,"    [%d][%d][%d] %d",i,j,k,_translate_load_store_unit_to_thread [i][j][k]);

    test();

    _max_nb_load_store_unit = max<uint32_t>(_nb_load_store_unit,  nb_execute_loop);
    _max_nb_cache_access    = max<uint32_t>(_nb_cache_access   , _nb_execute_loop, _nb_load_store_unit);
    
//     _size_dcache_thread_id  = (log2(_nb_execute_loop) +
// 			       log2(_max_nb_load_store_unit) +
// 			       log2(_max_nb_cache_access) +
// 			       _max_size_thread_id);

    uint32_t max_size_packet_id=  max<uint32_t>(_size_packet_id    , _nb_execute_loop, _nb_load_store_unit);

    _shift_num_cache_access    = max_size_packet_id;
    _mask_num_cache_access     = gen_mask<Tpacket_t>(log2(_max_nb_cache_access));
    _mask_num_lsq_packet       = gen_mask<Tpacket_t>(max_size_packet_id);

    _have_port_dcache_thread_id= _size_dcache_thread_id > 0;
    _have_port_dcache_packet_id= _size_dcache_packet_id > 0;
    
    _have_port_lsq_thread_id   = new bool * [_nb_execute_loop];
    _have_port_lsq_packet_id   = new bool * [_nb_execute_loop];

    for (uint32_t i=0; i<_nb_execute_loop; ++i)
      {
	_have_port_lsq_thread_id [i] = new bool [_nb_load_store_unit [i]];
	_have_port_lsq_packet_id [i] = new bool [_nb_load_store_unit [i]];

	for (uint32_t j=0; j<_nb_load_store_unit [i]; ++j)
	  {
	    _have_port_lsq_thread_id [i][j] = _size_thread_id[i][j] > 0;
	    _have_port_lsq_packet_id [i][j] = _size_packet_id[i][j] > 0;
	  }
      }

    _translate_thread_to_execute_loop    = new uint32_t [nb_thread];
    _translate_thread_to_load_store_unit = new uint32_t [nb_thread];
    _translate_thread_to_context         = new uint32_t [nb_thread];

    log_printf(TRACE,Dcache_Access,FUNCTION,"  * translate_load_store_unit_to_thread");

    for (uint32_t i=0; i<_nb_execute_loop; ++i)
      for (uint32_t j=0; j<_nb_load_store_unit [i]; ++j)
        for (uint32_t k=0; k<_nb_context[i]; ++k)
          {
            uint32_t num_thread = _translate_load_store_unit_to_thread [i][j][k];
            
            log_printf(TRACE,Dcache_Access,FUNCTION,"    [%d][%d][%d] %d",i,j,k,_translate_load_store_unit_to_thread [i][j][k]);

            if (num_thread < _nb_thread)
              {
            _translate_thread_to_execute_loop    [num_thread] = i;
            _translate_thread_to_load_store_unit [num_thread] = j;
            _translate_thread_to_context         [num_thread] = k;
              }
            else
              {
            _translate_thread_to_execute_loop    [num_thread] = _nb_execute_loop;
            _translate_thread_to_load_store_unit [num_thread] = _nb_load_store_unit [i];
            _translate_thread_to_context         [num_thread] = _nb_context [i];
              }
          }

    if (is_toplevel)
      {
        copy();
      }

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

#undef  FUNCTION
#define FUNCTION "Dcache_Access::~Parameters"
  Parameters::~Parameters (void) 
  {
    log_begin(Dcache_Access,FUNCTION);

    delete [] _translate_thread_to_context        ;
    delete [] _translate_thread_to_load_store_unit;
    delete [] _translate_thread_to_execute_loop   ;

    for (uint32_t i=0; i<_nb_execute_loop; ++i)
      {
	delete [] _have_port_lsq_thread_id [i];
	delete [] _have_port_lsq_packet_id [i];
      }
    delete [] _have_port_lsq_thread_id;
    delete [] _have_port_lsq_packet_id;

    log_end(Dcache_Access,FUNCTION);
  };

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

}; // end namespace dcache_access
}; // end namespace core

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