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

#include "Behavioural/Generic/RegisterFile/RegisterFile_Monolithic/SelfTest/include/test.h"
#include "Include/Test.h"

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

  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);
    }

  RegisterFile_Monolithic * registerfile = new RegisterFile_Monolithic (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>                    NRESET;
  
  sc_signal<Tcontrol_t>                    READ_VAL      [param._nb_port_read];
  sc_signal<Tcontrol_t>                    READ_ACK      [param._nb_port_read];
  sc_signal<Taddress_t>                    READ_ADDRESS  [param._nb_port_read];
  sc_signal<Tdata_t>                       READ_DATA     [param._nb_port_read];

  sc_signal<Tcontrol_t>                    WRITE_VAL     [param._nb_port_write];
  sc_signal<Tcontrol_t>                    WRITE_ACK     [param._nb_port_write];
  sc_signal<Taddress_t>                    WRITE_ADDRESS [param._nb_port_write];
  sc_signal<Tdata_t>                       WRITE_DATA    [param._nb_port_write];

  /********************************************************
   * Instanciation
   ********************************************************/
  
  cout << "<" << name << "> Instanciation of registerfile" << endl;
  
  (*(registerfile->in_CLOCK))        (CLOCK);
  (*(registerfile->in_NRESET))       (NRESET);

  for (uint32_t i=0; i<param._nb_port_read; i++)
    {
      (*(registerfile-> in_READ_VAL      [i]))        (READ_VAL      [i]);
      (*(registerfile->out_READ_ACK      [i]))        (READ_ACK      [i]);
      (*(registerfile-> in_READ_ADDRESS  [i]))        (READ_ADDRESS  [i]);
      (*(registerfile->out_READ_DATA     [i]))        (READ_DATA     [i]);
    }

  for (uint32_t i=0; i<param._nb_port_write; i++)
    {
      (*(registerfile-> in_WRITE_VAL     [i]))        (WRITE_VAL     [i]);
      (*(registerfile->out_WRITE_ACK     [i]))        (WRITE_ACK     [i]);
      (*(registerfile-> in_WRITE_ADDRESS [i]))        (WRITE_ADDRESS [i]);
      (*(registerfile-> in_WRITE_DATA    [i]))        (WRITE_DATA    [i]);
    }
  
  /********************************************************
   * Simulation - Begin
   ********************************************************/

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

  sc_start(0);
  
  for (uint32_t i=0; i<param._nb_port_write; i++)
    WRITE_VAL [i] .write (0);

  for (uint32_t i=0; i<param._nb_port_read; i++)
    READ_VAL  [i] .write (0);

  sc_start(5);

  cout << "<" << name << "> Write the RegisterFile (no read)" << endl;

  uint32_t grain = 0;
  //uint32_t grain = static_cast<uint32_t>(time(NULL));
  
  srand(grain);
  
  Tdata_t    data, data_wait;
  Taddress_t address = 0;

  while (address < param._nb_word)
    {
      uint32_t num_port = 0;
      
      cout << "cycle : " << static_cast<uint32_t> (sc_simulation_time()) << endl;

      while (num_port<param._nb_port_write)
	{
	  data = rand()%(1<<(param._size_word-1));

	  cout << "(" << num_port << ") [" << address << "] <= " << data << endl;
	  WRITE_VAL  [num_port] .write(1);
	  WRITE_DATA    [num_port] .write(data);
	  WRITE_ADDRESS [num_port] .write(address);

	  address  ++;
	  num_port ++;
	  // Address can be not a multiple of nb_port_write
	  if (address >= param._nb_word)
	    break;
	}

      while (num_port<param._nb_port_write)
	{
	  WRITE_VAL  [num_port] .write(0);
	  num_port ++;
	}

      sc_start(1);
    }
  cout << "<" << name << "> Read the RegisterFile (no write)" << endl;

  srand(grain);

  for (uint32_t i=0; i<param._nb_port_write; i++)
    WRITE_VAL [i] .write (0);

  sc_start(1);

  address  = 0;
  while (address < param._nb_word)
    {
      uint32_t num_port = 0;

      cout << "cycle : " << static_cast<uint32_t> (sc_simulation_time()) << endl;
      
      while (num_port<param._nb_port_read)
	{
	  READ_VAL  [num_port] .write(1);
	  READ_ADDRESS [num_port] .write(address);

	  sc_start(0); // evaluation

	  data_wait = rand()%(1<<(param._size_word-1));
	  data      = READ_DATA    [num_port] .read();

	  cout << "(" << num_port << ") [" << address << "] => " << data << endl;

	  TEST(Tdata_t,data,data_wait);

	  address  ++;
	  num_port ++;
	  if (address >= param._nb_word)
	    break;
	}

      while (num_port<param._nb_port_read)
	{
	  READ_VAL  [num_port] .write(0);
	  num_port ++;
	}

      sc_start(1);
    }

  for (uint32_t i=0; i<param._nb_port_read; i++)
    READ_VAL  [i] .write (0);

  sc_start(1);

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

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

#endif

  delete registerfile;
}
