/*
 * $Id: main.cpp 111 2009-02-27 18:37:40Z rosiere $
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_OOO_Engine/OOO_Engine/SelfTest/include/test.h"
#include "Behavioural/include/Allocation.h"

#define NB_PARAMS 24

void usage (int argc, char * argv[])
{
  err (_("<Usage> %s name_instance list_params.\n"),argv[0]);
  err (_("list_params is :\n"));
  err (_(" * nb_front_end                                                            (uint32_t             )\n"));
  err (_(" * nb_context                        [nb_front_end]                        (uint32_t             )\n"));
  err (_(" * nb_rename_unit                                                          (uint32_t             )\n"));
  err (_(" * nb_execute_loop                                                         (uint32_t             )\n"));
  err (_(" * nb_inst_decod                     [nb_front_end]                        (uint32_t             )\n"));
  err (_(" * nb_inst_insert                    [nb_rename_unit]                      (uint32_t             )\n"));
  err (_(" * nb_inst_retire                    [nb_rename_unit]                      (uint32_t             )\n"));
  err (_(" * nb_inst_issue                                                           (uint32_t             )\n"));
  err (_(" * nb_inst_execute                   [nb_execute_loop]                     (uint32_t             )\n"));
  err (_(" * nb_inst_reexecute                                                       (uint32_t             )\n"));
  err (_(" * nb_inst_commit                                                          (uint32_t             )\n"));
  err (_(" * nb_inst_branch_complete                                                 (uint32_t             )\n"));
  err (_(" * nb_branch_speculated              [nb_front_end][nb_context]            (uint32_t             )\n"));
  err (_(" * size_nb_inst_decod                                                      (uint32_t             )\n"));
  err (_(" * nb_rename_unit_select                                                   (uint32_t             )\n"));
  err (_(" * nb_execute_loop_select                                                  (uint32_t             )\n"));
  err (_(" * size_general_data                                                       (uint32_t             )\n"));
  err (_(" * size_special_data                                                       (uint32_t             )\n"));
  err (_(" * link_rename_unit_with_front_end   [nb_front_end]                        (uint32_t             )\n"));
  err (_(" * size_re_order_buffer                                                    (uint32_t             )\n"));
  err (_(" * nb_re_order_buffer_bank                                                 (uint32_t             )\n"));
  err (_(" * commit_priority                                                         (Tpriority_t          )\n"));
  err (_(" * commit_load_balancing                                                   (Tload_balancing_t    )\n"));
  err (_(" * size_issue_queue                                                        (uint32_t             )\n"));
  err (_(" * issue_queue_scheme                                                      (Tissue_queue_scheme_t)\n"));
  err (_(" * nb_issue_queue_bank                                                     (uint32_t             )\n"));
  err (_(" * issue_priority                                                          (Tpriority_t          )\n"));
  err (_(" * issue_load_balancing                                                    (Tload_balancing_t    )\n"));
  err (_(" * table_routing                     [nb_rename_unit][nb_inst_issue]       (bool                 )\n"));
  err (_(" * table_issue_type                  [nb_inst_issue][nb_type]              (bool                 )\n"));
  err (_("   * TYPE_ALU    \n"));
  err (_("   * TYPE_SHIFT  \n"));
  err (_("   * TYPE_MOVE   \n"));
  err (_("   * TYPE_TEST   \n"));
  err (_("   * TYPE_MUL    \n"));
  err (_("   * TYPE_DIV    \n"));
  err (_("   * TYPE_EXTEND \n"));
  err (_("   * TYPE_FIND   \n"));
  err (_("   * TYPE_SPECIAL\n"));
  err (_("   * TYPE_CUSTOM \n"));
  err (_("   * TYPE_BRANCH \n"));
  err (_("   * TYPE_MEMORY \n"));
  err (_(" * size_reexecute_queue                                                    (uint32_t         )\n"));
  err (_(" * reexecute_priority                                                      (Tpriority_t      )\n"));
  err (_(" * reexecute_load_balancing                                                (Tload_balancing_t)\n"));
  err (_(" * rename_select_priority            [nb_rename_unit]                      (Tpriority_t      )\n"));
  err (_(" * rename_select_load_balancing      [nb_rename_unit]                      (Tload_balancing_t)\n"));
  err (_(" * rename_select_nb_front_end_select [nb_rename_unit]                      (uint32_t         )\n"));
  err (_(" * nb_general_register               [nb_rename_unit]                      (uint32_t         )\n"));
  err (_(" * nb_special_register               [nb_rename_unit]                      (uint32_t         )\n"));
  err (_(" * nb_reg_free                       [nb_rename_unit]                      (uint32_t         )\n"));
  err (_(" * nb_rename_unit_bank               [nb_rename_unit]                      (uint32_t         )\n"));
  err (_(" * size_read_counter                 [nb_rename_unit]                      (uint32_t         )\n"));
  err (_(" * nb_load_store_queue               [nb_rename_unit]                      (uint32_t         )\n"));
  err (_(" * size_store_queue                  [nb_rename_unit][nb_load_store_queue] (uint32_t         )\n"));
  err (_(" * size_load_queue                   [nb_rename_unit][nb_load_store_queue] (uint32_t         )\n"));
  err (_(" * nb_inst_memory                    [nb_rename_unit][nb_load_store_queue] (uint32_t         )\n"));
  err (_(" * link_load_store_unit_with_thread  [nb_front_end][nb_context]            (uint32_t         )\n"));

  exit (1);
}

#ifndef SYSTEMC
int main    (int argc, char * argv[])
#else
int sc_main (int argc, char * argv[])
#endif
{
  if (argc <= static_cast<int>(2+NB_PARAMS))
    usage (argc, argv);

  uint32_t _sum_nb_context          = 0;
  uint32_t _sum_nb_load_store_queue = 0;

  uint32_t x = 1;

  string name = argv[x++];

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

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

  uint32_t            * _nb_context                        = new uint32_t [_nb_front_end];
  for (uint32_t i=0; i<_nb_front_end; i++)
    {
      _nb_context [i] = fromString<uint32_t>(argv[x++]);
      _sum_nb_context += _nb_context [i];
    }
  uint32_t              _nb_rename_unit                    = fromString<uint32_t         >(argv[x++]);
  uint32_t              _nb_execute_loop                   = fromString<uint32_t         >(argv[x++]);
  uint32_t            * _nb_inst_decod                     = new uint32_t [_nb_front_end];
  for (uint32_t i=0; i<_nb_front_end; i++)
    _nb_inst_decod [i] = fromString<uint32_t>(argv[x++]);

  if (argc <= static_cast<int>(2+NB_PARAMS+3*_nb_front_end+2*_sum_nb_context+12*_nb_rename_unit+_nb_execute_loop))
    usage (argc, argv);

  uint32_t            * _nb_inst_insert                    = new uint32_t [_nb_rename_unit];
  uint32_t            * _nb_inst_retire                    = new uint32_t [_nb_rename_unit];
  for (uint32_t i=0; i<_nb_rename_unit; i++)
    _nb_inst_insert [i] = fromString<uint32_t>(argv[x++]);
  for (uint32_t i=0; i<_nb_rename_unit; i++)
    _nb_inst_retire [i] = fromString<uint32_t>(argv[x++]);

  uint32_t              _nb_inst_issue                     = fromString<uint32_t         >(argv[x++]);
  uint32_t            * _nb_inst_execute                   = new uint32_t [_nb_execute_loop];
  for (uint32_t i=0; i<_nb_execute_loop; i++)
    _nb_inst_execute [i] = fromString<uint32_t>(argv[x++]);
  uint32_t              _nb_inst_reexecute                 = fromString<uint32_t         >(argv[x++]);
  uint32_t              _nb_inst_commit                    = fromString<uint32_t         >(argv[x++]);
  uint32_t              _nb_inst_branch_complete           = fromString<uint32_t         >(argv[x++]);
  uint32_t           ** _nb_branch_speculated              = new uint32_t * [_nb_front_end];
  for (uint32_t i=0; i<_nb_front_end; i++)
    {
      _nb_branch_speculated [i] = new uint32_t [_nb_context[i]];
      for (uint32_t j=0; j<_nb_context[i]; j++)
        _nb_branch_speculated [i][j] = fromString<uint32_t>(argv[x++]);
    }
  uint32_t              _size_nb_inst_decod                = fromString<uint32_t         >(argv[x++]);
  uint32_t              _nb_rename_unit_select             = fromString<uint32_t         >(argv[x++]);
  uint32_t              _nb_execute_loop_select            = fromString<uint32_t         >(argv[x++]);
  uint32_t              _size_general_data                 = fromString<uint32_t         >(argv[x++]);
  uint32_t              _size_special_data                 = fromString<uint32_t         >(argv[x++]);
  uint32_t            * _link_rename_unit_with_front_end   = new uint32_t [_nb_front_end];
  for (uint32_t i=0; i<_nb_front_end; i++)
    _link_rename_unit_with_front_end [i] = fromString<uint32_t>(argv[x++]);
  uint32_t              _size_re_order_buffer              = fromString<uint32_t         >(argv[x++]);
  uint32_t              _nb_re_order_buffer_bank           = fromString<uint32_t         >(argv[x++]);
  Tpriority_t           _commit_priority                   = fromString<Tpriority_t      >(argv[x++]);
  Tload_balancing_t     _commit_load_balancing             = fromString<Tload_balancing_t>(argv[x++]);
  uint32_t              _size_issue_queue                  = fromString<uint32_t         >(argv[x++]);
  issue_queue::Tissue_queue_scheme_t 
                        _issue_queue_scheme                = fromString<issue_queue::Tissue_queue_scheme_t>(argv[x++]);
  uint32_t              _nb_issue_queue_bank               = fromString<uint32_t         >(argv[x++]);
  Tpriority_t           _issue_priority                    = fromString<Tpriority_t      >(argv[x++]);
  Tload_balancing_t     _issue_load_balancing              = fromString<Tload_balancing_t>(argv[x++]);
  bool               ** _table_routing                     = new bool * [_nb_rename_unit];
  for (uint32_t i=0; i<_nb_rename_unit; i++)
    {
      _table_routing [i] = new bool [_nb_inst_issue];
      for (uint32_t j=0; j<_nb_inst_issue; j++)
        _table_routing [i][j] = fromString<bool>(argv[x++]);
    }

  if (argc <= static_cast<int>(2+NB_PARAMS+3*_nb_front_end+2*_sum_nb_context+11*_nb_rename_unit+_nb_execute_loop+_nb_rename_unit*_nb_inst_issue+12*_nb_inst_issue))
    usage (argc, argv);
  
  bool               ** _table_issue_type                  = new bool * [_nb_inst_issue];
  for (uint32_t i=0; i<_nb_inst_issue; i++)    
    {
      _table_issue_type [i] = new bool [MAX_TYPE];
      for (uint32_t j=0; j<MAX_TYPE; j++)
        _table_issue_type [i][j] = false;

      _table_issue_type [i][TYPE_ALU    ] = fromString<bool>(argv[x++]);
      _table_issue_type [i][TYPE_SHIFT  ] = fromString<bool>(argv[x++]);
      _table_issue_type [i][TYPE_MOVE   ] = fromString<bool>(argv[x++]);
      _table_issue_type [i][TYPE_TEST   ] = fromString<bool>(argv[x++]);
      _table_issue_type [i][TYPE_MUL    ] = fromString<bool>(argv[x++]);
      _table_issue_type [i][TYPE_DIV    ] = fromString<bool>(argv[x++]);
      _table_issue_type [i][TYPE_EXTEND ] = fromString<bool>(argv[x++]);
      _table_issue_type [i][TYPE_FIND   ] = fromString<bool>(argv[x++]);
      _table_issue_type [i][TYPE_SPECIAL] = fromString<bool>(argv[x++]);
      _table_issue_type [i][TYPE_CUSTOM ] = fromString<bool>(argv[x++]);
      _table_issue_type [i][TYPE_BRANCH ] = fromString<bool>(argv[x++]);
      _table_issue_type [i][TYPE_MEMORY ] = fromString<bool>(argv[x++]);
    }
  
  uint32_t              _size_reexecute_queue              = fromString<uint32_t         >(argv[x++]);
  Tpriority_t           _reexecute_priority                = fromString<Tpriority_t      >(argv[x++]);
  Tload_balancing_t     _reexecute_load_balancing          = fromString<Tload_balancing_t>(argv[x++]);

  Tpriority_t         * _rename_select_priority            = new Tpriority_t       [_nb_rename_unit];
  Tload_balancing_t   * _rename_select_load_balancing      = new Tload_balancing_t [_nb_rename_unit];
  uint32_t            * _rename_select_nb_front_end_select = new uint32_t          [_nb_rename_unit];
  uint32_t            * _nb_general_register               = new uint32_t          [_nb_rename_unit];
  uint32_t            * _nb_special_register               = new uint32_t          [_nb_rename_unit];
  uint32_t            * _nb_reg_free                       = new uint32_t          [_nb_rename_unit];
  uint32_t            * _nb_rename_unit_bank               = new uint32_t          [_nb_rename_unit];
  uint32_t            * _size_read_counter                 = new uint32_t          [_nb_rename_unit];
  uint32_t            * _nb_load_store_queue               = new uint32_t          [_nb_rename_unit];

  for (uint32_t i=0; i<_nb_rename_unit; i++)
    _rename_select_priority            [i] = fromString<Tpriority_t      >(argv[x++]);
  for (uint32_t i=0; i<_nb_rename_unit; i++)
    _rename_select_load_balancing      [i] = fromString<Tload_balancing_t>(argv[x++]);
  for (uint32_t i=0; i<_nb_rename_unit; i++)
    _rename_select_nb_front_end_select [i] = fromString<uint32_t         >(argv[x++]);
  for (uint32_t i=0; i<_nb_rename_unit; i++)
    _nb_general_register               [i] = fromString<uint32_t         >(argv[x++]);
  for (uint32_t i=0; i<_nb_rename_unit; i++)
    _nb_special_register               [i] = fromString<uint32_t         >(argv[x++]);
  for (uint32_t i=0; i<_nb_rename_unit; i++)
    _nb_reg_free                       [i] = fromString<uint32_t         >(argv[x++]);
  for (uint32_t i=0; i<_nb_rename_unit; i++)
    _nb_rename_unit_bank               [i] = fromString<uint32_t         >(argv[x++]);
  for (uint32_t i=0; i<_nb_rename_unit; i++)
    _size_read_counter                 [i] = fromString<uint32_t         >(argv[x++]);
  for (uint32_t i=0; i<_nb_rename_unit; i++)
    {
    _nb_load_store_queue               [i] = fromString<uint32_t         >(argv[x++]);
    _sum_nb_load_store_queue += _nb_load_store_queue [i];
    }

  if (argc != static_cast<int>(2+NB_PARAMS+3*_nb_front_end+2*_sum_nb_context+11*_nb_rename_unit+_nb_execute_loop+_nb_rename_unit*_nb_inst_issue+12*_nb_inst_issue+3*_sum_nb_load_store_queue))
    usage (argc, argv);


  uint32_t           ** _size_store_queue                  = new uint32_t * [_nb_rename_unit];
  for (uint32_t i=0; i<_nb_rename_unit; i++)
    {
      _size_store_queue [i] = new uint32_t [_nb_load_store_queue[i]];
      for (uint32_t j=0; j<_nb_load_store_queue[i]; j++)
        _size_store_queue [i][j] = fromString<uint32_t>(argv[x++]);
    }

  uint32_t           ** _size_load_queue                  = new uint32_t * [_nb_rename_unit];
  for (uint32_t i=0; i<_nb_rename_unit; i++)
    {
      _size_load_queue [i] = new uint32_t [_nb_load_store_queue[i]];
      for (uint32_t j=0; j<_nb_load_store_queue[i]; j++)
        _size_load_queue [i][j] = fromString<uint32_t>(argv[x++]);
    }

  uint32_t           ** _nb_inst_memory                   = new uint32_t * [_nb_rename_unit];
  for (uint32_t i=0; i<_nb_rename_unit; i++)
    {
      _nb_inst_memory  [i] = new uint32_t [_nb_load_store_queue[i]];
      for (uint32_t j=0; j<_nb_load_store_queue[i]; j++)
        _nb_inst_memory  [i][j] = fromString<uint32_t>(argv[x++]);
    }

  uint32_t           ** _link_load_store_unit_with_thread  = new uint32_t * [_nb_front_end];
  for (uint32_t i=0; i<_nb_front_end; i++)
    {
      _link_load_store_unit_with_thread [i] = new uint32_t [_nb_context[i]];
      for (uint32_t j=0; j<_nb_context[i]; j++)
        _link_load_store_unit_with_thread [i][j] = fromString<uint32_t>(argv[x++]);
    }

  bool     *** _implement_group       = new bool ** [_nb_front_end];
  for (uint32_t i=0; i<_nb_front_end; i++)
    {
      _implement_group [i] = new bool * [_nb_context[i]];
      for (uint32_t j=0; j<_nb_context[i]; j++)
	{
	  _implement_group [i][j] = new bool [NB_GROUP];

	  for (uint32_t k=0; k<NB_GROUP; k++)
	    _implement_group [i][j][k] = false;

	  _implement_group [i][j][GROUP_SYSTEM_AND_CONTROL] = true;
	  _implement_group [i][j][GROUP_DCACHE            ] = true;
	}
    }

  uint32_t          _nb_thread                          ;
  uint32_t       ** _translate_num_context_to_num_thread; //[nb_front_end][nb_context]

  ALLOC2(_translate_num_context_to_num_thread,uint32_t,_nb_front_end,_nb_context[it1]);

  _nb_thread = 0;
  for (uint32_t i=0; i<_nb_front_end; i++)
    for (uint32_t j=0; j<_nb_context [i]; j++)
      _translate_num_context_to_num_thread [i][j] = _nb_thread ++;

  int _return = EXIT_SUCCESS;
  try 
    {
      morpheo::behavioural::core::multi_ooo_engine::ooo_engine::Parameters * param = new morpheo::behavioural::core::multi_ooo_engine::ooo_engine::Parameters
        (
         _nb_front_end                     ,
         _nb_context                       ,
         _nb_rename_unit                   ,
         _nb_execute_loop                  ,
         _nb_inst_decod                    ,
         _nb_inst_insert                   ,
         _nb_inst_retire                   ,
         _nb_inst_issue                    ,
         _nb_inst_execute                  ,
         _nb_inst_reexecute                ,
         _nb_inst_commit                   ,
         _nb_inst_branch_complete          ,
         _nb_branch_speculated             ,
         _size_nb_inst_decod               ,
         _nb_rename_unit_select            ,
         _nb_execute_loop_select           ,
         _size_general_data                ,
         _size_special_data                ,
         _link_rename_unit_with_front_end  ,
         _size_re_order_buffer             ,
         _nb_re_order_buffer_bank          ,
         _commit_priority                  ,
         _commit_load_balancing            ,
         _size_issue_queue                 ,
         _issue_queue_scheme               ,
         _nb_issue_queue_bank              ,
         _issue_priority                   ,
         _issue_load_balancing             ,
         _table_routing                    ,
         _table_issue_type                 ,
         _size_reexecute_queue             ,
         _reexecute_priority               ,
         _reexecute_load_balancing         ,
         _rename_select_priority           ,
         _rename_select_load_balancing     ,
         _rename_select_nb_front_end_select,
         _nb_general_register              ,
         _nb_special_register              ,
         _nb_reg_free                      ,
         _nb_rename_unit_bank              ,
         _size_read_counter                ,
         _nb_load_store_queue              ,
         _size_store_queue                 ,
         _size_load_queue                  ,
         _nb_inst_memory                   ,
         _link_load_store_unit_with_thread ,
         _implement_group                  ,
         _nb_thread                          ,
         _translate_num_context_to_num_thread,
         true //is_toplevel
         );
      
      msg(_("%s"),param->print(0).c_str());
      
      test (name,param);

      delete param;
    }
  catch (morpheo::ErrorMorpheo & error)
    {
      msg (_("<%s> :\n%s"),name.c_str(), error.what ());
      _return = EXIT_FAILURE;
    }

  try 
    {
      if (_return == EXIT_SUCCESS)
        TEST_OK("OOO_Engine : no error");
      else
        TEST_KO("OOO_Engine : a lot of error");
    }
  catch (morpheo::ErrorMorpheo & error)
    {
//       msg (_("<%s> :\n%s"),name.c_str(), error.what ());
      _return = EXIT_FAILURE;
    }

  DELETE2(_translate_num_context_to_num_thread,_nb_front_end,_nb_context[it1]);

  for (uint32_t i=0; i<_nb_front_end; i++)
    {
      for (uint32_t j=0; j<_nb_context[i]; j++)
        delete [] _implement_group [i][j];
      delete [] _implement_group [i];
    }
  delete [] _implement_group;

  for (uint32_t i=0; i<_nb_front_end; i++)
    delete [] _link_load_store_unit_with_thread [i];
  delete [] _link_load_store_unit_with_thread;

  for (uint32_t i=0; i<_nb_rename_unit; i++)
    delete [] _nb_inst_memory  [i];
  delete [] _nb_inst_memory ;

  for (uint32_t i=0; i<_nb_rename_unit; i++)
    delete [] _size_load_queue [i];
  delete [] _size_load_queue;

  for (uint32_t i=0; i<_nb_rename_unit; i++)
    delete []_size_store_queue [i];
  delete []_size_store_queue;

  delete [] _nb_load_store_queue               ;
  delete [] _size_read_counter                 ;
  delete [] _nb_rename_unit_bank               ;
  delete [] _nb_reg_free                       ;
  delete [] _nb_special_register               ;
  delete [] _nb_general_register               ;
  delete [] _rename_select_nb_front_end_select ;
  delete [] _rename_select_load_balancing      ;
  delete [] _rename_select_priority            ;

  for (uint32_t i=0; i<_nb_inst_issue; i++)    
    delete [] _table_issue_type [i];
  delete [] _table_issue_type;  

  for (uint32_t i=0; i<_nb_rename_unit; i++)
    delete [] _table_routing [i];
  delete [] _table_routing;

  delete [] _link_rename_unit_with_front_end;

  for (uint32_t i=0; i<_nb_front_end; i++)
    delete [] _nb_branch_speculated [i];
  delete [] _nb_branch_speculated;
  
  delete [] _nb_inst_execute;
  delete [] _nb_inst_retire ;
  delete [] _nb_inst_insert ;
  delete [] _nb_inst_decod  ;
  delete [] _nb_context     ;

  return (_return);
}
