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

#include "Behavioural/Core/Multi_Execute_loop/Execute_loop/SelfTest/include/test.h"

#define NB_PARAMS 18

void usage (int argc, char * argv[])
{
  err (_("<Usage> %s name_instance list_params.\n"),argv[0]);
  err (_("list_params is :\n"));
  err (_(" * nb_read_unit                                                               (uint32_t           )\n"));
  err (_(" * nb_functionnal_unit                                                        (uint32_t           )\n"));
  err (_(" * nb_load_store_unit                                                         (uint32_t           )\n"));
  err (_(" * nb_write_unit                                                              (uint32_t           )\n"));
  err (_(" * nb_context                                                                 (uint32_t           )\n"));
  err (_(" * nb_front_end                                                               (uint32_t           )\n"));
  err (_(" * nb_ooo_engine                                                              (uint32_t           )\n"));
  err (_(" * nb_packet                                                                  (uint32_t           )\n"));
  err (_(" * size_general_data                                                          (uint32_t           )\n"));
  err (_(" * size_special_data                                                          (uint32_t           )\n"));
  err (_(" * size_read_queue                           [read_unit]                      (uint32_t           )\n"));
  err (_(" * size_reservation_station                  [read_unit]                      (uint32_t           )\n"));
  err (_(" * nb_inst_retire                            [read_unit]                      (uint32_t           )\n"));
  err (_(" * size_store_queue                          [load_store_unit]                (uint32_t           )\n"));
  err (_(" * size_load_queue                           [load_store_unit]                (uint32_t           )\n"));
  err (_(" * size_speculative_access_queue             [load_store_unit]                (uint32_t           )\n"));
  err (_(" * nb_port_check                             [load_store_unit]                (uint32_t           )\n"));
  err (_(" * speculative_load                          [load_store_unit]                (Tspeculative_load_t)\n"));
  err (_(" * nb_bypass_memory                          [load_store_unit]                (uint32_t           )\n"));
  err (_(" * size_write_queue                          [write_unit]                     (uint32_t           )\n"));
  err (_(" * size_execute_queue                        [write_unit]                     (uint32_t           )\n"));
  err (_(" * nb_bypass_write                           [write_unit]                     (uint32_t           )\n"));
  err (_(" * nb_gpr_bank                                                                (uint32_t           )\n"));
  err (_(" * nb_gpr_port_read_by_bank                                                   (uint32_t           )\n"));
  err (_(" * nb_gpr_port_write_by_bank                                                  (uint32_t           )\n"));
  err (_(" * nb_spr_bank                                                                (uint32_t           )\n"));
  err (_(" * nb_spr_port_read_by_bank                                                   (uint32_t           )\n"));
  err (_(" * nb_spr_port_write_by_bank                                                  (uint32_t           )\n"));
  err (_(" * nb_general_register                       [nb_ooo_engine]                  (uint32_t           )\n"));
  err (_(" * nb_special_register                       [nb_ooo_engine]                  (uint32_t           )\n"));
  err (_(" * nb_inst_insert_rob                        [nb_ooo_engine]                  (uint32_t           )\n"));
  err (_(" * nb_inst_retire_rob                        [nb_ooo_engine]                  (uint32_t           )\n"));
  err (_(" * execution_unit_to_write_unit_priority                                      (Tpriority_t        )\n"));
  err (_(" * execution_unit_to_write_unit_table_routing[nb_execute_unit][nb_write_unit] (bool               )\n"));
  err (_(" * execution_unit_to_write_unit_table_thread [nb_write_unit][nb_thread]       (bool               )\n"));
  err (_(" * read_unit_to_execution_unit_priority                                       (Tpriority_t        )\n"));
  err (_(" * read_unit_to_execution_unit_table_routing [nb_read_unit][nb_execute_unit]  (bool               )\n"));
  err (_(" * read_unit_to_execution_unit_table_thread  [nb_execute_unit][nb_thread]     (bool               )\n"));

  exit (1);
}

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

  uint32_t       x = 1;

  string                name                =      argv[x++];
  uint32_t              nb_read_unit        = atoi(argv[x++]);
  uint32_t              nb_functionnal_unit = atoi(argv[x++]);
  uint32_t              nb_load_store_unit  = atoi(argv[x++]);
  uint32_t              nb_write_unit       = atoi(argv[x++]);
  uint32_t              nb_context          = atoi(argv[x++]);
  uint32_t              nb_front_end        = atoi(argv[x++]);
  uint32_t              nb_ooo_engine       = atoi(argv[x++]);
  uint32_t              nb_packet           = atoi(argv[x++]);
  uint32_t              size_general_data   = atoi(argv[x++]);
  uint32_t              size_special_data   = atoi(argv[x++]);

  uint32_t nb_execute_unit = nb_functionnal_unit + nb_load_store_unit;
  uint32_t nb_thread       = get_nb_thread(nb_context, nb_front_end, nb_ooo_engine);

  int32_t nb_params = (2+NB_PARAMS+
		       3*nb_read_unit+
		       6*nb_load_store_unit+
		       3*nb_write_unit+
		       4*nb_ooo_engine+
		       nb_execute_unit*nb_write_unit+
		       nb_write_unit*nb_thread+
		       nb_read_unit*nb_execute_unit+
		       nb_execute_unit*nb_thread);
  
  
  
  if (argc != nb_params)
    {
      msg(_("Need %d parameters."),nb_params);
      usage (argc, argv);
    }
  uint32_t            * size_read_queue          = new uint32_t [nb_read_unit];
  for (uint32_t i=0; i<nb_read_unit; i++)
    size_read_queue [i] = atoi(argv[x++]);

  uint32_t            * size_reservation_station = new uint32_t [nb_read_unit];
  for (uint32_t i=0; i<nb_read_unit; i++)
    size_reservation_station [i] = atoi(argv[x++]);

  uint32_t            * nb_inst_retire           = new uint32_t [nb_read_unit];
  for (uint32_t i=0; i<nb_read_unit; i++)
    nb_inst_retire [i] = atoi(argv[x++]);

  uint32_t          * size_store_queue              = new uint32_t [nb_load_store_unit];
  for (uint32_t i=0; i<nb_load_store_unit; i++)
    size_store_queue              [i] = atoi(argv[x++]);

  uint32_t          * size_load_queue               = new uint32_t [nb_load_store_unit];
  for (uint32_t i=0; i<nb_load_store_unit; i++)
    size_load_queue               [i] = atoi(argv[x++]);

  uint32_t          * size_speculative_access_queue = new uint32_t [nb_load_store_unit];
  for (uint32_t i=0; i<nb_load_store_unit; i++)
    size_speculative_access_queue [i] = atoi(argv[x++]);

  uint32_t          * nb_port_check                 = new uint32_t [nb_load_store_unit];
  for (uint32_t i=0; i<nb_load_store_unit; i++)
    nb_port_check                 [i] = atoi(argv[x++]);

  Tspeculative_load_t * speculative_load            = new Tspeculative_load_t [nb_load_store_unit];
  for (uint32_t i=0; i<nb_load_store_unit; i++)
    speculative_load              [i] = fromString<Tspeculative_load_t>(argv[x++]);

  uint32_t          * nb_bypass_memory              = new uint32_t [nb_load_store_unit];
  for (uint32_t i=0; i<nb_load_store_unit; i++)
    nb_bypass_memory              [i] = atoi(argv[x++]);

  uint32_t * size_write_queue   = new uint32_t [nb_write_unit];
  for (uint32_t i=0; i<nb_write_unit; i++)
    size_write_queue   [i] = atoi(argv[x++]);
  
  uint32_t * size_execute_queue = new uint32_t [nb_write_unit];
  for (uint32_t i=0; i<nb_write_unit; i++)
    size_execute_queue [i] = atoi(argv[x++]);
  
  uint32_t * nb_bypass_write    = new uint32_t [nb_write_unit];
  for (uint32_t i=0; i<nb_write_unit; i++)
    nb_bypass_write    [i] = atoi(argv[x++]);

  uint32_t nb_gpr_bank                = atoi(argv[x++]);
  uint32_t nb_gpr_port_read_by_bank   = atoi(argv[x++]);
  uint32_t nb_gpr_port_write_by_bank  = atoi(argv[x++]);
  uint32_t nb_spr_bank                = atoi(argv[x++]);
  uint32_t nb_spr_port_read_by_bank   = atoi(argv[x++]);
  uint32_t nb_spr_port_write_by_bank  = atoi(argv[x++]);

  uint32_t * nb_general_register = new uint32_t [nb_ooo_engine];
  for (uint32_t i=0; i<nb_ooo_engine; i++)
    nb_general_register [i] = atoi(argv[x++]);

  uint32_t * nb_special_register = new uint32_t [nb_ooo_engine];
  for (uint32_t i=0; i<nb_ooo_engine; i++)
    nb_special_register [i] = atoi(argv[x++]);

  uint32_t * nb_inst_insert_rob  = new uint32_t [nb_ooo_engine];
  for (uint32_t i=0; i<nb_ooo_engine; i++)
    nb_inst_insert_rob  [i] = atoi(argv[x++]);

  uint32_t * nb_inst_retire_rob  = new uint32_t [nb_ooo_engine];
  for (uint32_t i=0; i<nb_ooo_engine; i++)
    nb_inst_retire_rob  [i] = atoi(argv[x++]);

  Tpriority_t execution_unit_to_write_unit_priority = fromString<Tpriority_t>(argv[x++]);

  bool ** execution_unit_to_write_unit_table_routing = new bool * [nb_execute_unit];
  for (uint32_t i=0; i<nb_execute_unit; i++)
    {
      execution_unit_to_write_unit_table_routing [i] = new bool [nb_write_unit];
      for (uint32_t j=0; j<nb_write_unit; j++)
	execution_unit_to_write_unit_table_routing [i][j] = atoi(argv[x++]);
    }
  bool ** execution_unit_to_write_unit_table_thread = new bool * [nb_write_unit];
  for (uint32_t i=0; i<nb_write_unit; i++)
    {
      execution_unit_to_write_unit_table_thread [i] = new bool [nb_thread];
      for (uint32_t j=0; j<nb_thread; j++)
	execution_unit_to_write_unit_table_thread  [i][j] = atoi(argv[x++]);
    }
  Tpriority_t read_unit_to_execution_unit_priority  = fromString<Tpriority_t>(argv[x++]);

  bool ** read_unit_to_execution_unit_table_routing = new bool * [nb_read_unit];
  for (uint32_t i=0; i<nb_read_unit; i++)
    {
      read_unit_to_execution_unit_table_routing [i] = new bool [nb_execute_unit];
      for (uint32_t j=0; j<nb_execute_unit; j++)
	read_unit_to_execution_unit_table_routing [i][j] = atoi(argv[x++]);
    }
  bool ** read_unit_to_execution_unit_table_thread = new bool * [nb_execute_unit];
  for (uint32_t i=0; i<nb_execute_unit; i++)
    {
      read_unit_to_execution_unit_table_thread [i] = new bool [nb_thread];
      for (uint32_t j=0; j<nb_thread; j++)
	read_unit_to_execution_unit_table_thread [i][j] =  atoi(argv[x++]);
    }
  execute_timing_t *** timing = new execute_timing_t ** [nb_execute_unit];
  
  // alloc and reset timing array
  for (uint32_t i=0; i< nb_execute_unit; i++)
    {
      timing [i] = new execute_timing_t * [MAX_TYPE];
      
      for (uint32_t j=0; j< MAX_TYPE; j++)
	{
	  timing [i][j]= new execute_timing_t [MAX_OPERATION];
	  
	  for (uint32_t k=0; k< MAX_OPERATION; k++)
	    timing[i][j][k]._delay = timing[i][j][k]._latence = 0;
	}
    }
  
  for (uint32_t i=0; i< nb_load_store_unit; i++)
    for (uint32_t k=0; k< MAX_OPERATION; k++)
      timing[i][TYPE_MEMORY][k]._delay = timing[i][TYPE_MEMORY][k]._latence = 1;
  for (uint32_t i=0; i< nb_functionnal_unit; i++)
    for (uint32_t j=0; j< MAX_TYPE; j++)
      if (j != TYPE_MEMORY)
	for (uint32_t k=0; k< MAX_OPERATION; k++)
	  timing[i+nb_load_store_unit][j][k]._delay = timing[i+nb_load_store_unit][j][k]._latence = 1;

  morpheo::behavioural::custom::custom_information_t (*get_custom_information) (uint32_t) = &(morpheo::behavioural::custom::default_get_custom_information);

  try 
    {
      morpheo::behavioural::core::multi_execute_loop::execute_loop::Parameters * param = new morpheo::behavioural::core::multi_execute_loop::execute_loop::Parameters
	(nb_read_unit                                  ,
	 nb_functionnal_unit                           ,
	 nb_load_store_unit                            ,
	 nb_write_unit                                 ,
	 
	 nb_context                                    ,
	 nb_front_end                                  ,
	 nb_ooo_engine                                 ,
	 nb_packet                                     ,
	 size_general_data                             ,
	 size_special_data                             ,
	 
	 size_read_queue                               ,
	 size_reservation_station                      ,
	 nb_inst_retire                                ,
	 
	 timing                                        ,
	 get_custom_information                        ,
	 			
	 size_store_queue                              ,
	 size_load_queue                               ,
	 size_speculative_access_queue                 ,
	 nb_port_check                                 ,
	 speculative_load                              ,
	 
	 nb_bypass_memory                              ,
	 size_write_queue                              ,
	 size_execute_queue                            ,
	 nb_bypass_write                               ,
	 
	 nb_gpr_bank                                   ,
	 nb_gpr_port_read_by_bank                      ,
	 nb_gpr_port_write_by_bank                     ,
	 nb_spr_bank                                   ,
	 nb_spr_port_read_by_bank                      ,
	 nb_spr_port_write_by_bank                     ,
	 nb_general_register                           ,
	 nb_special_register                           ,
	 nb_inst_insert_rob                            ,
	 nb_inst_retire_rob                            ,
	 
	 execution_unit_to_write_unit_priority         ,
	 execution_unit_to_write_unit_table_routing    ,
	 execution_unit_to_write_unit_table_thread     ,
	 
	 read_unit_to_execution_unit_priority          ,
	 read_unit_to_execution_unit_table_routing     ,
	 read_unit_to_execution_unit_table_thread      );
      
      msg(_("%s"),param->print(1).c_str());
      
      test (name,param);
    }
  catch (morpheo::ErrorMorpheo & error)
    {
      msg (_("<%s> : %s.\n"),name.c_str(), error.what ());
      exit (EXIT_FAILURE);
    }
  catch (...)
    {
      err (_("<%s> : This test must generate a error.\n"),name.c_str());
      exit (EXIT_FAILURE);
    }

  return (EXIT_SUCCESS);
}

