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

#include "Behavioural/Generic/Select/Pseudo_LRU/SelfTest/include/test.h"
#include "Include/Test.h"

void test (string name,
	   morpheo::behavioural::generic::select::pseudo_lru::Parameters param)
{
  cout << "<" << name << "> : Simulation SystemC" << endl;

  if (param._nb_update < 1)
    {
      cerr << "<" << name << "> : To test, need a less one update's port" << endl;
      exit (EXIT_FAILURE);
    }
  
  try 
    {
      cout << param.print(1);
      param.test();
    }
  catch (morpheo::ErrorMorpheo & error)
    {
      cout << "<" << name << "> : " <<  error.what ();
      return;
    }
  catch (...)
    {
      cerr << "<" << name << "> : This test must generate a error" << endl;
      exit (EXIT_FAILURE);
    }
  Pseudo_LRU * _Pseudo_LRU = new Pseudo_LRU (name.c_str(),
#ifdef STATISTICS
					     morpheo::behavioural::Parameters_Statistics(5,50),
#endif
					     param);
  
#ifdef SYSTEMC
  /*********************************************************************
   * Déclarations des signaux
   *********************************************************************/
  sc_clock                                 CLOCK ("clock", 1.0, 0.5);

  sc_signal<Tcontrol_t>                    ACCESS_VAL     [param._nb_access];
  sc_signal<Tcontrol_t>                    ACCESS_ACK     [param._nb_access];
  sc_signal<Taddress_t>                    ACCESS_ADDRESS [param._nb_access];
  sc_signal<Tentity_t >                    ACCESS_ENTITY  [param._nb_access];
  
  sc_signal<Tcontrol_t>                    UPDATE_VAL     [param._nb_update];
  sc_signal<Tcontrol_t>                    UPDATE_ACK     [param._nb_update];
  sc_signal<Taddress_t>                    UPDATE_ADDRESS [param._nb_update];
  sc_signal<Tentity_t >                    UPDATE_ENTITY  [param._nb_update];
  
  /********************************************************
   * Instanciation
   ********************************************************/
  
  cout << "<" << name << "> Instanciation of _Pseudo_LRU" << endl;
  
  (*(_Pseudo_LRU->in_CLOCK))        (CLOCK);

    for (uint32_t i=0; i<param._nb_access; i++)
      {
	(*(_Pseudo_LRU-> in_ACCESS_VAL     [i])) (ACCESS_VAL     [i]);
	(*(_Pseudo_LRU->out_ACCESS_ACK     [i])) (ACCESS_ACK     [i]);
	if (param._size_table>1)
	(*(_Pseudo_LRU-> in_ACCESS_ADDRESS [i])) (ACCESS_ADDRESS [i]);
	(*(_Pseudo_LRU->out_ACCESS_ENTITY  [i])) (ACCESS_ENTITY  [i]);
      }

    for (uint32_t i=0; i<param._nb_update; i++)
      {
	(*(_Pseudo_LRU-> in_UPDATE_VAL     [i])) (UPDATE_VAL     [i]);
	(*(_Pseudo_LRU->out_UPDATE_ACK     [i])) (UPDATE_ACK     [i]);
	if (param._size_table>1)
	(*(_Pseudo_LRU-> in_UPDATE_ADDRESS [i])) (UPDATE_ADDRESS [i]);
	(*(_Pseudo_LRU-> in_UPDATE_ENTITY  [i])) (UPDATE_ENTITY  [i]);
      }
  /********************************************************
   * Simulation - Begin
   ********************************************************/

  cout << "<" << name << "> Start Simulation ............" << endl;
  // Initialisation

  sc_start(0);

  bool array [param._nb_access][param._nb_entity];

  for (uint32_t i=0; i<param._nb_access; i++)
    {
      ACCESS_VAL[i].write(0);
    }
  for (uint32_t i=0; i<param._nb_update; i++)
    {
      UPDATE_VAL[i].write(0);
    }

  sc_start(5);
  cout << "-----[ Test Update ]------------------------------" << endl;
  for (uint32_t i=0; i<param._nb_update; i++)
    {
      UPDATE_VAL[i].write(1);
    }
  
  for (uint32_t j=0; j<param._size_table; j+=param._nb_update)
    for (uint32_t k=0; k<param._nb_entity; k++)
      {
	cout << "time : " << static_cast<uint32_t>(sc_simulation_time()) << endl;
	for (uint32_t i=0; i<param._nb_update; i++)
	  {
	    
	    Tcontrol_t val     = static_cast<Tcontrol_t>((j+i)<param._size_table);
	    Taddress_t addr;
	    if (param._size_table>1)
	      addr = static_cast<Taddress_t>((j+i)%param._size_table);
	    else
	      addr = 0;
	    Tentity_t  entity  = (k+1)%param._nb_entity;
	    UPDATE_VAL     [i].write(val );
	    if (param._size_table>1)
	      UPDATE_ADDRESS [i].write(addr);
	    UPDATE_ENTITY  [i].write(entity);
	    
	    sc_start(0);
	    cout << "\t[" << i << "] " << val << " - " << UPDATE_ACK[i].read() << " addr : " << addr << " -> " << entity << endl;
	  }
	sc_start(1);
      }
		    

  for (uint32_t i=0; i<param._nb_update; i++)
    {
      UPDATE_VAL[i].write(0);
    }

  sc_start(5);

  cout << "-----[ Test Access ]------------------------------" << endl;
  
  
  for (uint32_t j=0; j<param._size_table; j+=param._nb_access)
    {
      // init
      memset(static_cast<void*>(array),0,param._nb_access*param._nb_entity*sizeof(bool));
      
      for (uint32_t k=0; k<param._nb_entity; k++)
	{
	  
	  cout << "time : " << static_cast<uint32_t>(sc_simulation_time()) << endl;
	  for (uint32_t i=0; i<param._nb_access; i++)
	    {
	      Tcontrol_t val     = static_cast<Tcontrol_t>((j+i)<param._size_table);
	      Taddress_t addr    ;
	      if (param._size_table>1)
		addr = static_cast<Taddress_t>((j+i)%param._size_table);
	      else
		addr = 0;
	      ACCESS_VAL     [i].write(val );
	      if (param._size_table>1)
		ACCESS_ADDRESS [i].write(addr);
	      
	      sc_start(0);
	      
	      Tentity_t  entity  = ACCESS_ENTITY [i].read();
	      
	      cout << "\t[" << i << "] " << val << " - " << ACCESS_ACK[i].read() << " addr : " << addr << " -> " << entity << endl;
	      
	      TEST(bool,false,((val == true) && (array[i][entity] == true)));

// 	      if ((val == true) && (array[i][entity] == true))
// 		{
// 		  cout << "Test KO : Have already give this way" << endl;
// 		  exit (1);
// 		}
// 	      else
		array[i][entity] = true;
	    }
	  
	  sc_start(1);
	  
	}
    }

  for (uint32_t i=0; i<param._nb_access; i++)
    {
      ACCESS_VAL[i].write(0);
    }

  sc_start(0);

  /********************************************************
   * Simulation - End
   ********************************************************/

  cout << "<" << name << "> ............ Stop Simulation" << endl;

#endif

  delete _Pseudo_LRU;
}
