/*
 * $Id: Parameters_msg_error.cpp 138 2010-05-12 17:34:01Z rosiere $
 *
 * [ Description ]
 * 
 */

#include "Behavioural/include/Types.h"
#include "Behavioural/Core/include/Parameters.h"
#include "Common/include/Max.h"
#include <sstream>

namespace morpheo                    {
namespace behavioural {
namespace core {


#undef  FUNCTION
#define FUNCTION "Core::msg_error"
  Parameters_test Parameters::msg_error(void)
  {
    log_begin(Core,FUNCTION);

    Parameters_test test ("Core");

    // Test if value is valid
    {
      // initialisation
      uint32_t nb_link_context [_nb_front_end][max<uint32_t>(_nb_context,_nb_front_end)];
      
      for (uint32_t i=0; i<_nb_front_end; ++i)
        for (uint32_t j=0; j<_nb_context[i];++j)
          nb_link_context [i][j] = 0;
      
      // set link
      for (uint32_t i=0; i<_nb_thread; ++i)
        nb_link_context[_link_context_with_thread[i].first][_link_context_with_thread[i].second] ++;

      // test
      for (uint32_t i=0; i<_nb_front_end; ++i)
        for (uint32_t j=0; j<_nb_context[i];++j)
          {
            if (nb_link_context[i][j] == 0)
              test.error(toString(_("Context [%d][%d] is not link with a thread.\n"),i,j));
            if (nb_link_context[i][j]  > 1)
              test.error(toString(_("Context [%d][%d] is linked with 2 or more threads.\n"),i,j));
          }
    }

    {
      // initialisation
      uint32_t nb_link_decod_unit [_nb_front_end][max<uint32_t>(_nb_decod_unit,_nb_front_end)];
      
      for (uint32_t i=0; i<_nb_front_end; ++i)
        for (uint32_t j=0; j<_nb_decod_unit[i];++j)
          nb_link_decod_unit [i][j] = 0;
      
      // set link
      for (uint32_t i=0; i<_nb_decod_bloc; ++i)
        {
          uint32_t num_front_end  = _link_decod_unit_with_decod_bloc[i].first;
          uint32_t num_decod_unit = _link_decod_unit_with_decod_bloc[i].second;

          bool error = false;

          if (num_front_end >= _nb_front_end)
            {
              error = true;
              test.error(toString(_("Decod_bloc [%d] is connected with an invalid front_end (%d).\n"),i,num_front_end));
            }

          if (num_decod_unit >= _nb_decod_unit[num_front_end])
            {
              error = true;
              test.error(toString(_("Decod_bloc [%d] is connected with an invalid decod_unit (%d.%d).\n"),i,num_front_end,num_decod_unit));
            }

          if (not error)
            nb_link_decod_unit[num_front_end][num_decod_unit] ++;
        }
      // test
      for (uint32_t i=0; i<_nb_front_end; ++i)
        for (uint32_t j=0; j<_nb_decod_unit[i];++j)
          {
            if (nb_link_decod_unit[i][j] == 0)
              test.error(toString(_("Decod_Unit [%d][%d] is not link with a decod_bloc.\n"),i,j));
            if (nb_link_decod_unit[i][j]  > 1)
              test.error(toString(_("Decod_Unit [%d][%d] is linked with 2 or more decod_bloc.\n"),i,j));
          }
    }

    {
      // initialisation
      uint32_t nb_link_rename_unit [_nb_ooo_engine][max<uint32_t>(_nb_rename_unit,_nb_ooo_engine)];
      
      for (uint32_t i=0; i<_nb_ooo_engine; ++i)
        for (uint32_t j=0; j<_nb_rename_unit[i];++j)
          nb_link_rename_unit [i][j] = 0;
      
      // set link
      for (uint32_t i=0; i<_nb_rename_bloc; ++i)
        nb_link_rename_unit[_link_rename_unit_with_rename_bloc[i].first][_link_rename_unit_with_rename_bloc[i].second] ++;

      // test
      for (uint32_t i=0; i<_nb_ooo_engine; ++i)
        for (uint32_t j=0; j<_nb_rename_unit[i];++j)
          {
            if (nb_link_rename_unit[i][j] == 0)
              test.error(toString(_("Rename_Unit [%d][%d] is not link with a rename_bloc.\n"),i,j));
            if (nb_link_rename_unit[i][j]  > 1)
              test.error(toString(_("Rename_Unit [%d][%d] is linked with 2 or more rename_bloc.\n"),i,j));
          }
    }

    {
      // initialisation
      uint32_t nb_link_read_unit [_nb_execute_loop][max<uint32_t>(_nb_read_unit,_nb_execute_loop)];
      
      for (uint32_t i=0; i<_nb_execute_loop; ++i)
        for (uint32_t j=0; j<_nb_read_unit[i];++j)
          nb_link_read_unit [i][j] = 0;
      
      // set link
      for (uint32_t i=0; i<_nb_read_bloc; ++i)
        nb_link_read_unit[_link_read_unit_with_read_bloc[i].first][_link_read_unit_with_read_bloc[i].second] ++;

      // test
      for (uint32_t i=0; i<_nb_execute_loop; ++i)
        for (uint32_t j=0; j<_nb_read_unit[i];++j)
          {
            if (nb_link_read_unit[i][j] == 0)
              test.error(toString(_("Read_Unit [%d][%d] is not link with a read_bloc.\n"),i,j));
            if (nb_link_read_unit[i][j]  > 1)
              test.error(toString(_("Read_Unit [%d][%d] is linked with 2 or more read_bloc.\n"),i,j));
          }
    }

    {
      // initialisation
      uint32_t nb_link_write_unit [_nb_execute_loop][max<uint32_t>(_nb_write_unit,_nb_execute_loop)];
      
      for (uint32_t i=0; i<_nb_execute_loop; ++i)
        for (uint32_t j=0; j<_nb_write_unit[i];++j)
          nb_link_write_unit [i][j] = 0;
      
      // set link
      for (uint32_t i=0; i<_nb_write_bloc; ++i)
        nb_link_write_unit[_link_write_unit_with_write_bloc[i].first][_link_write_unit_with_write_bloc[i].second] ++;

      // test
      for (uint32_t i=0; i<_nb_execute_loop; ++i)
        for (uint32_t j=0; j<_nb_write_unit[i];++j)
          {
            if (nb_link_write_unit[i][j] == 0)
              test.error(toString(_("Write_Unit [%d][%d] is not link with a write_bloc.\n"),i,j));
            if (nb_link_write_unit[i][j]  > 1)
              test.error(toString(_("Write_Unit [%d][%d] is linked with 2 or more write_bloc.\n"),i,j));
          }
    }

    {
      // initialisation
      uint32_t nb_link_execute_unit [_nb_execute_loop][max<uint32_t>(_nb_execute_unit,_nb_execute_loop)];
//       uint32_t nb_functionnal_unit  [_nb_functionnal_unit];
//       uint32_t nb_load_store_unit   [_nb_load_store_unit];

//       for (uint32_t i=0; i<_nb_functionnal_unit; ++i)
//         nb_functionnal_unit [i] = 0;
      
//       for (uint32_t i=0; i<_nb_load_store_unit; ++i)
//         nb_load_store_unit  [i] = 0;
      
      for (uint32_t i=0; i<_nb_execute_loop; ++i)
        for (uint32_t j=0; j<_nb_execute_unit[i];++j)
          nb_link_execute_unit [i][j] = 0;

      // set link
      for (uint32_t i=0; i<_nb_functionnal_unit; ++i)
        {
          uint32_t num_execute_loop = _link_execute_unit_with_functionnal_unit [i].first;
          uint32_t num_execute_unit = _link_execute_unit_with_functionnal_unit [i].second;

          log_printf(TRACE,Core,FUNCTION,"  * _link_execute_unit_with_functionnal_unit [%d] = %d.%d",i,num_execute_loop,num_execute_unit);

          nb_link_execute_unit [num_execute_loop][num_execute_unit] ++;
//           nb_functionnal_unit  [i] ++;
        }
      for (uint32_t i=0; i<_nb_load_store_unit; ++i)
        {
          uint32_t num_execute_loop = _link_execute_unit_with_load_store_unit [i].first;
          uint32_t num_execute_unit = _link_execute_unit_with_load_store_unit [i].second;

          log_printf(TRACE,Core,FUNCTION,"  * _link_execute_unit_with_load_store_unit  [%d] = %d.%d",i,num_execute_loop,num_execute_unit);

          nb_link_execute_unit [num_execute_loop][num_execute_unit] ++;
//           nb_load_store_unit   [i] ++;
        }

      // test
      for (uint32_t i=0; i<_nb_execute_loop; ++i)
        for (uint32_t j=0; j<_nb_execute_unit[i];++j)
          {
            if (nb_link_execute_unit[i][j] == 0)
              test.error(toString(_("Execute_Unit [%d][%d] is not link with a load_store_unit or functionnal_unit.\n"),i,j));
            if (nb_link_execute_unit[i][j]  > 1)
              test.error(toString(_("Execute_Unit [%d][%d] is linked with 2 or more time.\n"),i,j));
          }

//       for (uint32_t i=0; i<_nb_functionnal_unit; ++i)
//         {
//           if (nb_functionnal_unit[i] == 0)
//             test.error(toString(_("Functionnal_Unit [%d] is not instanced.\n"),i));
//           if (nb_functionnal_unit[i]  > 1)
//             test.error(toString(_("Functionnal_Unit [%d] is linked with 2 or more time.\n"),i));
//         }

//       for (uint32_t i=0; i<_nb_load_store_unit; ++i)
//         {
//           if (nb_load_store_unit[i] == 0)
//             test.error(toString(_("Load_Store_Unit [%d] is not instanced.\n"),i));
//           if (nb_load_store_unit[i]  > 1)
//             test.error(toString(_("Load_Store_Unit [%d] is linked with 2 or more time.\n"),i));
//         }
    }
    
    {
      bool     read_bloc_link_with_load_store_unit  [_nb_read_bloc];
      bool     read_bloc_link_with_functionnal_unit [_nb_read_bloc];
      uint32_t nb_link_functionnal_unit [_nb_functionnal_unit];
      
      for (uint32_t i=0; i<_nb_read_bloc; ++i)
        {
          read_bloc_link_with_load_store_unit  [i] = false;
          read_bloc_link_with_functionnal_unit [i] = false;
        }
      for (uint32_t i=0; i<_nb_functionnal_unit; ++i)
        nb_link_functionnal_unit [i] = 0;
      
      for (uint32_t i=0; i<_nb_load_store_unit; ++i)
        read_bloc_link_with_load_store_unit [_link_read_bloc_with_load_store_unit[i]] = true;
      
      for (uint32_t i=0; i<_nb_read_bloc; ++i)
        for (uint32_t j=0; j<_nb_functionnal_unit; ++j)
          if (_link_read_bloc_and_functionnal_unit [i][j])
            {
              nb_link_functionnal_unit [j] ++;
              read_bloc_link_with_functionnal_unit [i] = true;
            }

      for (uint32_t i=0; i<_nb_read_bloc; ++i)
        {
          if (not read_bloc_link_with_load_store_unit  [i] and
              not read_bloc_link_with_functionnal_unit [i])
            test.error(toString(_("Read_bloc [%d] is not link with an execute_unit.\n"),i));
          if (    read_bloc_link_with_load_store_unit  [i] and
                  read_bloc_link_with_functionnal_unit [i])
            test.error(toString(_("Read_bloc [%d] is linked with an load store unit and functionnal unit.\n"),i));
        }
      for (uint32_t i=0; i<_nb_functionnal_unit; ++i)
        if (nb_link_functionnal_unit [i] == 0)
          test.error(toString(_("functionnal_unit [%d] is not link with a read_bloc.\n"),i));
    }

    {
      uint32_t nb_link_write_bloc       [_nb_write_bloc];
      uint32_t nb_link_functionnal_unit [_nb_functionnal_unit];

      for (uint32_t i=0; i<_nb_write_bloc; ++i)
        nb_link_write_bloc [i] = 0;
      for (uint32_t i=0; i<_nb_functionnal_unit; ++i)
        nb_link_functionnal_unit [i] = 0;

      for (uint32_t i=0; i<_nb_load_store_unit; ++i)
        nb_link_write_bloc [_link_write_bloc_with_load_store_unit[i]] = true;

      for (uint32_t i=0; i<_nb_write_bloc; ++i)
        for (uint32_t j=0; j<_nb_functionnal_unit; ++j)
          if (_link_write_bloc_and_functionnal_unit [i][j])
            {
              nb_link_write_bloc       [i] ++;
              nb_link_functionnal_unit [j] ++;
            }

      for (uint32_t i=0; i<_nb_write_bloc; ++i)
        if (nb_link_write_bloc [i] == 0)
          test.error(toString(_("Write_bloc [%d] is not link with an execute_unit.\n"),i));
      for (uint32_t i=0; i<_nb_functionnal_unit; ++i)
        if (nb_link_functionnal_unit [i] == 0)
          test.error(toString(_("functionnal_unit [%d] is not link with a write_bloc.\n"),i));
    }

    {
      uint32_t nb_link_thread                      [_nb_thread];
      uint32_t nb_link_load_store_unit             [_nb_load_store_unit];
      uint32_t nb_link_functionnal_unit            [_nb_functionnal_unit];
      bool     link_front_end_with_execute_loop    [_nb_front_end][_nb_execute_loop];
      uint32_t nb_link_front_end_with_execute_loop [_nb_front_end];

      for (uint32_t i=0; i<_nb_thread; ++i)
        nb_link_thread [i] = 0;
      for (uint32_t i=0; i<_nb_load_store_unit; ++i)
        nb_link_load_store_unit [i] = 0;
      for (uint32_t i=0; i<_nb_functionnal_unit; ++i)
        nb_link_functionnal_unit [i] = 0;
      for (uint32_t i=0; i<_nb_front_end; ++i)
        {
          nb_link_front_end_with_execute_loop [i] = 0;
          for (uint32_t j=0; j<_nb_execute_loop; ++j)
            link_front_end_with_execute_loop [i][j] = false;
        }

      for (uint32_t i=0; i<_nb_thread; ++i)
        {
          uint32_t num_front_end = _link_context_with_thread [i].first;

          {
            uint32_t num_load_store_unit = _link_load_store_unit_with_thread [i];
            uint32_t num_execute_loop    = _link_execute_unit_with_load_store_unit [i].first;
            
            nb_link_thread           [i] ++;
            nb_link_load_store_unit  [num_load_store_unit] ++;

            if (not link_front_end_with_execute_loop [num_front_end][num_execute_loop])
              nb_link_front_end_with_execute_loop [num_front_end] ++;
            link_front_end_with_execute_loop [num_front_end][num_execute_loop] = true;
          }

          for (uint32_t j=0; j<_nb_functionnal_unit; ++j)
            if (_link_thread_and_functionnal_unit [i][j])
              {
                uint32_t num_execute_loop = _link_execute_unit_with_functionnal_unit [i].first;

                nb_link_thread           [i] ++;
                nb_link_functionnal_unit [j] ++;
                
                if (not link_front_end_with_execute_loop [num_front_end][num_execute_loop])
                  nb_link_front_end_with_execute_loop [num_front_end] ++;
                link_front_end_with_execute_loop [num_front_end][num_execute_loop] = true;
              }
        }

      for (uint32_t i=0; i<_nb_thread; ++i)
        if (nb_link_thread [i] < 2)
          test.error(toString(_("Thread [%d] is not link with a load_store_unit and a functionnal_unit.\n"),i));
      for (uint32_t i=0; i<_nb_load_store_unit; ++i)
        if (nb_link_load_store_unit [i] == 0)
          test.error(toString(_("Load_store_unit [%d] is not link with a thread.\n"),i));
      for (uint32_t i=0; i<_nb_functionnal_unit; ++i)
        if (nb_link_functionnal_unit [i] == 0)
          test.error(toString(_("Functionnal_unit [%d] is not link with a thread.\n"),i));
      for (uint32_t i=0; i<_nb_front_end; ++i)
        if (nb_link_front_end_with_execute_loop [i] != 1)
          test.error(toString(_("Front end [%d] is link with many execute_loop.\n"),i));
    }
    
    {
      uint32_t nb_link_icache_port [_nb_icache_port];

      for (uint32_t i=0; i<_nb_icache_port; ++i)
        nb_link_icache_port [i] = 0;

      for (uint32_t i=0; i<_nb_thread; ++i)
        nb_link_icache_port [_link_icache_port_with_thread [i]] ++;
      
      for (uint32_t i=0; i<_nb_icache_port; ++i)
        if (nb_link_icache_port [i] == 0)
          test.error(toString(_("Icache port [%d] is not link with a thread.\n"),i));
    }

    {
      uint32_t nb_link_dcache_port [_nb_dcache_port];

      for (uint32_t i=0; i<_nb_dcache_port; ++i)
        nb_link_dcache_port [i] = 0;
          
      for (uint32_t i=0; i<_nb_load_store_unit; ++i)
        for (uint32_t j=0; j<_nb_cache_port[i]; ++j)
          nb_link_dcache_port [_link_dcache_port_with_load_store_unit[i][j]] ++;
      
      for (uint32_t i=0; i<_nb_dcache_port; ++i)
        if (nb_link_dcache_port [i] == 0)
          test.error(toString(_("Dcache port [%d] is not link with a port of load store unit.\n"),i));
    }

    log_end(Core,FUNCTION);

    return test;
  };

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