/*
 * $Id: main.cpp 115 2009-04-20 21:29:17Z rosiere $
 *
 * [ 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                           [nb_read_unit]                                         (uint32_t           )\n"));
  err (_(" * size_reservation_station                  [nb_read_unit]                                         (uint32_t           )\n"));
  err (_(" * nb_inst_retire                            [nb_read_unit]                                         (uint32_t           )\n"));
  err (_(" * nb_inst_functionnal_unit                  [nb_functionnal_unit]                                  (uint32_t           )\n"));
  err (_(" * size_store_queue                          [nb_load_store_unit]                                   (uint32_t           )\n"));
  err (_(" * size_load_queue                           [nb_load_store_unit]                                   (uint32_t           )\n"));
  err (_(" * size_speculative_access_queue             [nb_load_store_unit]                                   (uint32_t           )\n"));
  err (_(" * nb_port_check                             [nb_load_store_unit]                                   (uint32_t           )\n"));
  err (_(" * speculative_load                          [nb_load_store_unit]                                   (Tspeculative_load_t)\n"));
  err (_(" * nb_bypass_memory                          [nb_load_store_unit]                                   (uint32_t           )\n"));
  err (_(" * nb_cache_port                             [nb_load_store_unit]                                   (uint32_t           )\n"));
  err (_(" * nb_inst_memory                            [nb_load_store_unit]                                   (uint32_t           )\n"));
  err (_(" * size_write_queue                          [nb_write_unit]                                        (uint32_t           )\n"));
  err (_(" * size_execute_queue                        [nb_write_unit]                                        (uint32_t           )\n"));
  err (_(" * nb_bypass_write                           [nb_write_unit]                                        (uint32_t           )\n"));
  err (_(" * write_queue_scheme                        [nb_write_unit]                                        (Twrite_queue_scheme_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_execute_unit_port][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][nb_execute_unit_port]  (bool               )\n"));
  err (_(" * read_unit_to_execution_unit_table_thread  [nb_execute_unit][nb_thread]                           (bool               )\n"));
  err (_(" * is_load_store_unit                        [nb_execute_unit]                                      (bool               )\n"));
  err (_(" * translate_num_execute_unit                [nb_execute_unit]                                      (uint32_t           )\n"));


  exit (1);
}

#ifndef SYSTEMC
int main    (int argc, char * argv[])
#else
int sc_main (int argc, char * argv[])
#endif
{
  // Command
  for (int32_t i=0; i<argc; ++i)
    msg("%s ",argv[i]);
  msg("\n");
  
  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+
		       1*nb_functionnal_unit+
		       8*nb_load_store_unit+
		       4*nb_write_unit+
		       4*nb_ooo_engine+
// 		       sum_execute_unit_port*nb_write_unit+
		       nb_write_unit*nb_thread+
// 		       nb_read_unit*sum_execute_unit_port+
		       nb_execute_unit*nb_thread+
                       2*nb_execute_unit);
  
  if (argc <= 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            * nb_inst_functionnal_unit = new uint32_t [nb_functionnal_unit];
  for (uint32_t i=0; i<nb_functionnal_unit; i++)
    nb_inst_functionnal_unit [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          * nb_cache_port                 = new uint32_t [nb_load_store_unit];
  for (uint32_t i=0; i<nb_load_store_unit; i++)
    nb_cache_port                 [i] = atoi(argv[x++]);

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


  uint32_t sum_execute_unit_port = 0;
  for (uint32_t i=0; i<nb_load_store_unit; i++)
    sum_execute_unit_port += nb_inst_memory[i];
  for (uint32_t i=0; i<nb_functionnal_unit; i++)
    sum_execute_unit_port += nb_inst_functionnal_unit[i];

  nb_params = (2+NB_PARAMS+
	       3*nb_read_unit+
	       1*nb_functionnal_unit+
	       8*nb_load_store_unit+
	       4*nb_write_unit+
	       4*nb_ooo_engine+
	       sum_execute_unit_port*nb_write_unit+
	       nb_write_unit*nb_thread+
	       nb_read_unit*sum_execute_unit_port+
	       nb_execute_unit*nb_thread+
               2*nb_execute_unit);
  
  if (argc != nb_params)
    {
      msg("nb_functionnal_unit   : %d\n",nb_functionnal_unit);
      msg("nb_load_store_unit    : %d\n",nb_load_store_unit );
      msg("sum_execute_unit_port : %d.\n",sum_execute_unit_port);
      msg(_("Have %d parameters.\n"),argc     );
      msg(_("Need %d parameters.\n"),nb_params);
      usage (argc, argv);
    }

  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++]);

  multi_write_unit::write_unit::write_queue::Twrite_queue_scheme_t * write_queue_scheme    = new multi_write_unit::write_unit::write_queue::Twrite_queue_scheme_t [nb_write_unit];
  for (uint32_t i=0; i<nb_write_unit; i++)
    write_queue_scheme    [i] = fromString<multi_write_unit::write_unit::write_queue::Twrite_queue_scheme_t>(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++)
    {
      uint32_t nb_execute_unit_port = (i<nb_load_store_unit)?nb_inst_memory[i]:nb_inst_functionnal_unit[i-nb_load_store_unit];

      execution_unit_to_write_unit_table_routing [i] = new bool * [nb_execute_unit_port];
      
      for (uint32_t j=0; j<nb_execute_unit_port; j++)
	{
	  execution_unit_to_write_unit_table_routing [i][j] = new bool [nb_write_unit];
	  
	  for (uint32_t k=0; k<nb_write_unit; k++)
	    execution_unit_to_write_unit_table_routing [i][j][k] = 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++)
	{
	  uint32_t nb_execute_unit_port = (j<nb_load_store_unit)?nb_inst_memory[j]:nb_inst_functionnal_unit[j-nb_load_store_unit];
	  read_unit_to_execution_unit_table_routing [i][j] = new bool [nb_execute_unit_port];

	  for (uint32_t k=0; k<nb_execute_unit_port; k++)
	    read_unit_to_execution_unit_table_routing [i][j][k] = 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++]);
    }

  bool * is_load_store_unit = new bool [nb_execute_unit];
  for (uint32_t i=0; i<nb_execute_unit; i++)
    is_load_store_unit [i] = fromString<bool>(argv[x++]);

  uint32_t * translate_num_execute_unit = new uint32_t [nb_execute_unit];
  for (uint32_t i=0; i<nb_execute_unit; i++)
    translate_num_execute_unit [i] = fromString<uint32_t>(argv[x++]);

  execute_timing_t *** timing = new execute_timing_t ** [nb_functionnal_unit];
  // alloc and reset timing array
  for (uint32_t i=0; i< nb_functionnal_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_functionnal_unit; i++)
    for (uint32_t j=0; j< MAX_TYPE; j++)
      {
	if ( (j != TYPE_MEMORY) and
	     not ((i!=0) and ((j == TYPE_SPECIAL) or
			      (j == TYPE_CUSTOM))))
	  for (uint32_t k=0; k< MAX_OPERATION; k++)
	    timing[i][j][k]._delay = timing[i][j][k]._latence = 1;
      }

  morpheo::behavioural::custom::custom_information_t (*get_custom_information) (void) = &(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                                ,

	 nb_inst_functionnal_unit                      ,
	 timing                                        ,
	 get_custom_information                        ,
	 			
	 size_store_queue                              ,
	 size_load_queue                               ,
	 size_speculative_access_queue                 ,
	 nb_port_check                                 ,
	 speculative_load                              ,
	 nb_bypass_memory                              ,
	 nb_cache_port                                 ,
	 nb_inst_memory                                ,

	 size_write_queue                              ,
	 size_execute_queue                            ,
	 nb_bypass_write                               ,
	 write_queue_scheme                            ,
	 
	 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      ,

         is_load_store_unit                            , //[nb_execute_unit]
         translate_num_execute_unit                    , //[nb_execute_unit]
         true // is_toplevel
         );
      
      test (name,param);
    }
  catch (morpheo::ErrorMorpheo & error)
    {
      msg (_("%s\n"),error.what ());
      exit (EXIT_FAILURE);
    }
  catch (...)
    {
      err (_("This test must generate a error.\n"));
      exit (EXIT_FAILURE);
    }

  return (EXIT_SUCCESS);
}

