/*
 * $Id: main.cpp 88 2008-12-10 18:31:39Z rosiere $
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Dcache_Access/SelfTest/include/test.h"
#include "Common/include/Max.h"

#define NB_PARAMS 6

void usage (int argc, char * argv[])
{
  err (_("<Usage> %s name_instance list_params.\n"),argv[0]);
  err (_("list_params is :\n"));
  err (_(" * nb_execute_loop                                                           (uint32_t         )\n"));
  err (_(" * nb_load_store_unit [nb_execute_loop]                                      (uint32_t         )\n"));
  err (_(" * nb_cache_access    [nb_execute_loop][nb_load_store_unit]                  (uint32_t         )\n"));
  err (_(" * nb_dcache_port                                                            (uint32_t         )\n"));
  err (_(" * size_address                                                              (uint32_t         )\n"));
  err (_(" * size_data                                                                 (uint32_t         )\n"));
  err (_(" * size_thread_id     [nb_execute_loop][nb_load_store_unit]                  (uint32_t         )\n"));
  err (_(" * size_packet_id     [nb_execute_loop][nb_load_store_unit]                  (uint32_t         )\n"));
  err (_(" * table_routing      [nb_execute_loop][nb_load_store_unit][nb_cache_access] (uint32_t         )\n"));
  err (_(" * priority                                                                  (Tpriority_t      )\n"));
  err (_(" * load_balancing                                                            (Tload_balancing_t)\n"));

  exit (1);
}

#ifndef SYSTEMC
int main    (int argc, char * argv[])
#else
int sc_main (int argc, char * argv[])
#endif
{
  for (int32_t i=0; i<argc; ++i)
    msg("%s ",argv[i]);
  msg("\n");

  if (argc <= static_cast<int>(2+NB_PARAMS))
    usage (argc, argv);

  uint32_t sum_load_store_unit = 0;
  uint32_t sum_nb_cache_access = 0;

  uint32_t x = 1;

  string name = argv[x++];

  uint32_t             _nb_execute_loop        = fromString<uint32_t         >(argv[x++]);

  if (argc <= static_cast<int>(2+NB_PARAMS+_nb_execute_loop))
    usage (argc, argv);

  uint32_t           * _nb_load_store_unit     = new uint32_t [_nb_execute_loop];
  for (uint32_t i=0; i<_nb_execute_loop; ++i)
    {
      _nb_load_store_unit [i] = fromString<uint32_t>(argv[x++]);
      sum_load_store_unit += _nb_load_store_unit [i];
    }
  
  if (argc <= static_cast<int>(2+NB_PARAMS+_nb_execute_loop+3*sum_load_store_unit))
    usage (argc, argv);

  uint32_t          ** _nb_cache_access        = new uint32_t * [_nb_execute_loop];
  for (uint32_t i=0; i<_nb_execute_loop; ++i)
    {
      _nb_cache_access [i] = new uint32_t [_nb_load_store_unit[i]];
      for (uint32_t j=0; j<_nb_load_store_unit[i]; ++j)
	{
	  _nb_cache_access [i][j] = fromString<uint32_t>(argv[x++]);
	  sum_nb_cache_access += _nb_cache_access [i][j];
	}
    }

  if (argc != static_cast<int>(2+NB_PARAMS+_nb_execute_loop+3*sum_load_store_unit+sum_nb_cache_access))
    usage (argc, argv);

  uint32_t             _nb_dcache_port         = fromString<uint32_t         >(argv[x++]);
  uint32_t             _size_address           = fromString<uint32_t         >(argv[x++]);
  uint32_t             _size_data              = fromString<uint32_t         >(argv[x++]);

  
  uint32_t          ** _size_thread_id         = new uint32_t *  [_nb_execute_loop];
  uint32_t          ** _size_packet_id         = new uint32_t *  [_nb_execute_loop];
  uint32_t         *** _table_routing          = new uint32_t ** [_nb_execute_loop];
  for (uint32_t i=0; i<_nb_execute_loop; i++)
    {
      _size_thread_id [i] = new uint32_t   [_nb_load_store_unit [i]];
      _size_packet_id [i] = new uint32_t   [_nb_load_store_unit [i]];
      _table_routing  [i] = new uint32_t * [_nb_load_store_unit [i]];

      for (uint32_t j=0; j<_nb_load_store_unit [i]; ++j)
	_table_routing  [i][j] = new uint32_t [_nb_cache_access [i][j]];
    }

  for (uint32_t i=0; i<_nb_execute_loop; i++)
    for (uint32_t j=0; j<_nb_load_store_unit [i]; ++j)
      _size_thread_id [i][j] = fromString<uint32_t>(argv[x++]);

  for (uint32_t i=0; i<_nb_execute_loop; i++)
    for (uint32_t j=0; j<_nb_load_store_unit [i]; ++j)
      _size_packet_id [i][j] = fromString<uint32_t>(argv[x++]);

  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)
	_table_routing [i][j][k] = fromString<uint32_t>(argv[x++]);

  Tpriority_t          _priority               = fromString<Tpriority_t      >(argv[x++]);
  Tload_balancing_t    _load_balancing         = fromString<Tload_balancing_t>(argv[x++]);

  uint32_t           * _nb_context             = new uint32_t [_nb_execute_loop];
  for (uint32_t i=0; i<_nb_execute_loop; ++i)
    _nb_context [i] = 1<<max<uint32_t>(_size_thread_id[i],_nb_load_store_unit[i]);

  uint32_t             _nb_thread               = 0;
  uint32_t         *** _translate_load_store_unit_to_thread = new uint32_t ** [_nb_execute_loop];

  for (uint32_t i=0; i<_nb_execute_loop; ++i)
    {
      _translate_load_store_unit_to_thread[i] = new uint32_t * [_nb_load_store_unit[i]];
      for (uint32_t j=0; j<_nb_load_store_unit [i]; ++j)
        {
          _translate_load_store_unit_to_thread[i][j] = new uint32_t [_nb_context[i]];
          for (uint32_t k=0; k<_nb_context[i]; ++k)
            _translate_load_store_unit_to_thread[i][j][k] = _nb_thread ++;
        }
    }

  uint32_t _size_dcache_thread_id  = log2(_nb_thread);
  uint32_t _size_dcache_packet_id  = (log2(max<uint32_t>(_nb_cache_access,_nb_execute_loop,_nb_load_store_unit)) +
                                      max<uint32_t>(_size_packet_id,_nb_execute_loop,_nb_load_store_unit));
  
  int _return = EXIT_SUCCESS;
  try 
    {
      morpheo::behavioural::core::dcache_access::Parameters * param = new morpheo::behavioural::core::dcache_access::Parameters
	(_nb_thread              ,
         _nb_execute_loop        ,
	 _nb_load_store_unit     ,
         _nb_context             ,
	 _nb_cache_access        ,
	 _nb_dcache_port         ,
	 _size_address           ,
	 _size_data              ,
         _size_dcache_thread_id  ,
         _size_dcache_packet_id  ,
	 _size_thread_id         ,
	 _size_packet_id         ,
	 _table_routing          ,
	 _priority               ,
	 _load_balancing         ,
         _translate_load_store_unit_to_thread
         );
      
      test (name,param);
    }
  catch (morpheo::ErrorMorpheo & error)
    {
      msg (_("%s\n"), error.what ());
      _return = EXIT_FAILURE;
    }
  
  try 
    {
      if (_return == EXIT_SUCCESS)
	TEST_OK("Dcache_Access : no error");
      else
	TEST_KO("Dcache_Access : a lot of error");
    }
  catch (morpheo::ErrorMorpheo & error)
    {
//       msg (_("<%s> :\n%s"),name.c_str(), error.what ());
      _return = EXIT_FAILURE;
    }

  delete [] _nb_context;

  for (uint32_t i=0; i<_nb_execute_loop; ++i)
    {
      for (uint32_t j=0; j<_nb_load_store_unit [i]; ++j)
        delete [] _translate_load_store_unit_to_thread[i][j];
      delete [] _translate_load_store_unit_to_thread[i];
    }
  delete [] _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)
	delete [] _table_routing  [i][j];

      delete [] _size_thread_id [i];
      delete [] _size_packet_id [i];
      delete [] _table_routing  [i];
    }
  delete [] _size_thread_id;
  delete [] _size_packet_id;
  delete [] _table_routing ;

  for (uint32_t i=0; i<_nb_execute_loop; ++i)
    delete [] _nb_cache_access [i];
  delete [] _nb_cache_access;

  delete [] _nb_load_store_unit;

  return (_return);
}
