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

#include "Behavioural/include/Types.h"
#include "Behavioural/Core/Multi_Execute_loop/Execute_loop/Network/Read_unit_to_Execution_unit/include/Parameters.h"
#include <sstream>

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_execute_loop {
namespace execute_loop {
namespace network {
namespace read_unit_to_execution_unit {


#undef  FUNCTION
#define FUNCTION "Read_unit_to_Execution_unit::msg_error"
  Parameters_test Parameters::msg_error(void)
  {
    log_printf(FUNC,Read_unit_to_Execution_unit,FUNCTION,"Begin");

    Parameters_test test ("Read_unit_to_Execution_unit");

    // TYPE         | multiple? | Optionnal? | Exclusive? | Comment
    //--------------+-----------+------------+------------+---------
    // TYPE_ALU     |     X     |            |            |
    // TYPE_SHIFT   |     X     |            |            | ror is optionnal
    // TYPE_MOVE    |     X     |            |            | cmov is optionnal
    // TYPE_TEST    |     X     |            |            |
    // TYPE_MUL_DIV |     X     |            |            | div is optionnal
    // TYPE_EXTEND  |     X     |     X      |            |
    // TYPE_FIND    |     X     |     X      |            |
    // TYPE_SPECIAL |           |            |            | mac unit is optionnal
    // TYPE_CUSTOM  |           |     X      |            |
    // TYPE_BRANCH  |     X     |            |            |
    // TYPE_MEMORY  |           |            |     X      |
    
    bool type_valid     [_nb_type];
    bool type_uniq      [_nb_type]; // one thread can have multiple destination for this type ?
    bool type_optionnal [_nb_type]; // this type is optionnal ?
    bool type_exclusive [_nb_type]; // a unit that implement this type must be implement an another type ?

    for (Ttype_t i=0; i<_nb_type; i++)
      {
	type_valid     [i] = false;
	type_uniq      [i] = false;
	type_optionnal [i] = false;
	type_exclusive [i] = false;
      }

    type_valid     [TYPE_ALU    ] = true;
    type_valid     [TYPE_SHIFT  ] = true;
    type_valid     [TYPE_MOVE   ] = true;
    type_valid     [TYPE_TEST   ] = true;
    type_valid     [TYPE_MUL_DIV] = true;
    type_valid     [TYPE_EXTEND ] = true;
    type_valid     [TYPE_FIND   ] = true;
    type_valid     [TYPE_SPECIAL] = true;
    type_valid     [TYPE_CUSTOM ] = true;
    type_valid     [TYPE_BRANCH ] = true;
    type_valid     [TYPE_MEMORY ] = true;

    type_uniq      [TYPE_SPECIAL] = true;
    type_uniq      [TYPE_CUSTOM ] = true;
    type_uniq      [TYPE_MEMORY ] = true;

    type_optionnal [TYPE_EXTEND ] = true;
    type_optionnal [TYPE_FIND   ] = true;
    type_optionnal [TYPE_CUSTOM ] = true;

    type_exclusive [TYPE_MEMORY ] = true;

    bool type_present [_nb_thread][_nb_type];
    for (uint32_t i=0; i<_nb_thread; i++)
      for (Ttype_t j=0; j<_nb_type; j++)
	type_present [i][j] = false;
    
    for (uint32_t i=0; i<_nb_execute_unit; i++)
      for (uint32_t j=0; j<_nb_thread; j++)
	if (_table_execute_thread [i][j] == true)
	  // this execute_unit execute this thread !
	  for (Ttype_t k=0; k<=_nb_type; k++)
	    if (_table_execute_type[i][k] == true)
	      {
		// Test uniq type
		if (type_present [j][k] and type_uniq[k])
		  test.error("The execute_unit '"+toString(i)+"' can execute operation of type '"+toString_type(k)+"' at the thread '"+toString(j)+"'. But an another execute_unit can be execute the same type for the same thread. And the type must be uniq !.");
		
		type_present [j][k] = true;
	      }

    for (Ttype_t j=0; j<_nb_type; j++)
      if (type_valid [j] and not type_optionnal[j])
	for (uint32_t i=0; i<_nb_thread; i++)
	  if (not type_present [i][j])
	    test.error("The thread '"+toString(i)+"' can't access at the execute_unit to execute the type's operation '"+toString_type(j)+"' (and this type is not optionnal !).");
	    
    // Test all excluve type
    for (uint32_t i=0; i<_nb_execute_unit; i++)
      for (Ttype_t j=0; j<=_nb_type; j++)
	if (type_exclusive [j] and _table_execute_type[i][j])
	  for (Ttype_t k=0; k<=_nb_type; k++)
	    if ((j != k) and (_table_execute_type[i][k] == true))
	      {
		test.error("The execute_unit ["+toString(i)+"] implement the type '"+toString_type(j)+"', and this type is exclusive with all others type.");
		break;
	      }

    for (uint32_t i=0; i<_nb_execute_unit; i++)
      {
	uint32_t j;
	for (j=0; j<_nb_thread; j++)
	  if (_table_execute_thread [i][j] == true)
	    break;

	if (j == _nb_thread)
	  test.error("The execute_unit ["+toString(i)+"] have none source's thread.");
      }	  

    if ( (_priority != PRIORITY_STATIC     ) and
	 (_priority != PRIORITY_ROUND_ROBIN))
      test.error("Unsupported priority scheme. It must be Static or Round Robin.");
        
    log_printf(FUNC,Read_unit_to_Execution_unit,FUNCTION,"End");

    return test;
  };

}; // end namespace read_unit_to_execution_unit
}; // end namespace network
}; // end namespace execute_loop
}; // end namespace multi_execute_loop
}; // end namespace core

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