/*
 * $Id: top_test.cpp 113 2009-04-14 18:39:12Z rosiere $
 *
 * [ Description ]
 * 
 * Test
 */

#include "Behavioural/Core/Multi_Execute_loop/Execute_loop/Multi_Write_unit/Write_unit/Execute_queue/SelfTest/include/top.h"
#include "Behavioural/include/Allocation.h"
#include "Common/include/BitManipulation.h"

  class entry_t
  {
  public  : Tcontext_t         _context_id   ;
  public  : Tcontext_t         _front_end_id ;
  public  : Tcontext_t         _ooo_engine_id;
  public  : Tpacket_t          _packet_id    ;
//public  : Toperation_t       _operation    ;
//public  : Ttype_t            _type         ;
  public  : Tspecial_data_t    _flags        ;
  public  : Texception_t       _exception    ;
  public  : Tcontrol_t         _no_sequence  ;
  public  : Tgeneral_data_t    _address      ;
  public  : Tgeneral_data_t    _data         ;
    
  public  : entry_t (Tcontext_t         context_id   ,
		     Tcontext_t         front_end_id ,
		     Tcontext_t         ooo_engine_id,
		     Tpacket_t          packet_id    ,
		     //Toperation_t       operation    ,
		     //Ttype_t            type         ,
		     Tspecial_data_t    flags        ,
		     Texception_t       exception    ,
		     Tcontrol_t         no_sequence  ,
		     Tgeneral_data_t    address      ,
		     Tgeneral_data_t    data         )
    {
      _context_id    = context_id   ;
      _front_end_id  = front_end_id ;
      _ooo_engine_id = ooo_engine_id;
      _packet_id     = packet_id    ;
    //_operation     = operation    ;
    //_type          = type         ;
      _flags         = flags        ;
      _exception     = exception    ;
      _no_sequence   = no_sequence  ;
      _address       = address      ;
      _data          = data         ;
    };

    friend std::ostream& operator<< (std::ostream& output_stream,
				     entry_t & x)
    {
      output_stream << " * _context_id    : " << toString(x._context_id   ) << std::endl
		    << " * _front_end_id  : " << toString(x._front_end_id ) << std::endl
		    << " * _ooo_engine_id : " << toString(x._ooo_engine_id) << std::endl
		    << " * _packet_id     : " << toString(x._packet_id    ) << std::endl
		  //<< " * _operation     : " << toString(x._operation    ) << std::endl
		  //<< " * _type          : " << toString(x._type         ) << std::endl
		    << " * _flags         : " << toString(x._flags        ) << std::endl
		    << " * _exception     : " << toString(x._exception    ) << std::endl
		    << " * _no_sequence   : " << toString(x._no_sequence  ) << std::endl
		    << " * _address       : " << toString(x._address      ) << std::endl
		    << " * _data          : " << toString(x._data         ) << std::endl;

      return output_stream;
    }
  };

void top::test (void)
{
#ifdef SYSTEMC
  if (usage_is_set(_usage,USE_SYSTEMC))
    {
      msgInformation(_("<%s> : Start Simulation ............\n"),name.c_str());
      
      Time * _time = new Time();
      
      /********************************************************
       * Simulation - Begin
       ********************************************************/
      
  // Initialisation

  const uint32_t seed = 0;
//const uint32_t seed = static_cast<uint32_t>(time(NULL));

  const  int32_t percent_transaction_execute_queue_in  = 75;
  const  int32_t percent_transaction_execute_queue_out = 75;

  entry_t *      request [_param->_nb_packet];

  for (uint32_t i=0; i<_param->_nb_packet; ++i)
    request[i] = NULL;

  srand(seed);

  SC_CYCLE(0);
  LABEL("Initialisation");

  LABEL("Reset");
  in_NRESET->write(0);
  SC_CYCLE(5);
  in_NRESET->write(1);  

  LABEL("Loop of Test");

  for (uint32_t iteration=0; iteration<NB_ITERATION; iteration ++)
    {
      LABEL("Iteration %d",iteration);

      for (uint32_t i=0; i<_param->_nb_packet; i++)
	{
          if (request[i] != NULL)
            delete request [i];

	  request [i] = new entry_t (range<Tcontext_t        >(rand(),_param->_size_context_id      ),
				     range<Tcontext_t        >(rand(),_param->_size_front_end_id    ),
				     range<Tcontext_t        >(rand(),_param->_size_ooo_engine_id   ),
				     i,
				   //range<Toperation_t      >(rand(),_param->_size_operation       ),
				   //range<Ttype_t           >(rand(),_param->_size_type            ),
				     range<Tspecial_data_t   >(rand(),_param->_size_special_data    ),
				     range<Texception_t      >(rand(),_param->_size_exception       ),
				     range<Tcontrol_t        >(rand(),1                             ),
				     range<Tgeneral_data_t   >(rand(),_param->_size_general_data    ),
				     range<Tgeneral_data_t   >(rand(),_param->_size_general_data    ));
	}

      uint32_t nb_request_in  = 0;
      uint32_t nb_request_out = 0;
      
      while (nb_request_out < _param->_nb_packet)
      {
	bool val = (((rand()%100)<percent_transaction_execute_queue_in) and
		    (nb_request_in < _param->_nb_packet));
	
	in_EXECUTE_QUEUE_IN_VAL          ->write(val);
	if (val)
	  {
	    in_EXECUTE_QUEUE_IN_CONTEXT_ID   ->write(request [nb_request_in]->_context_id   );
	    in_EXECUTE_QUEUE_IN_FRONT_END_ID ->write(request [nb_request_in]->_front_end_id );
	    in_EXECUTE_QUEUE_IN_OOO_ENGINE_ID->write(request [nb_request_in]->_ooo_engine_id);
	    in_EXECUTE_QUEUE_IN_PACKET_ID    ->write(request [nb_request_in]->_packet_id    );
	  //in_EXECUTE_QUEUE_IN_OPERATION    ->write(request [nb_request_in]->_operation    );
	  //in_EXECUTE_QUEUE_IN_TYPE         ->write(request [nb_request_in]->_type         );
	    in_EXECUTE_QUEUE_IN_FLAGS        ->write(request [nb_request_in]->_flags        );
	    in_EXECUTE_QUEUE_IN_EXCEPTION    ->write(request [nb_request_in]->_exception    );
	    in_EXECUTE_QUEUE_IN_NO_SEQUENCE  ->write(request [nb_request_in]->_no_sequence  );
	    in_EXECUTE_QUEUE_IN_ADDRESS      ->write(request [nb_request_in]->_address      );
	    in_EXECUTE_QUEUE_IN_DATA         ->write(request [nb_request_in]->_data         );
	  }
	in_EXECUTE_QUEUE_OUT_ACK         ->write((rand()%100)<percent_transaction_execute_queue_out);
	    
	SC_CYCLE(0);

	
	// ======================================================================
	// ======================================================================
	// ======================================================================
	if ( in_EXECUTE_QUEUE_IN_VAL->read() and
	    out_EXECUTE_QUEUE_IN_ACK->read())
	  {
	    LABEL(" * Accepted EXECUTE_QUEUE_IN  [%d]",nb_request_in);
// 	    std::cout << *request [nb_request_in] << std::endl;

	    nb_request_in ++;
	  }
	
	// ======================================================================
	// ======================================================================
	// ======================================================================
	if (out_EXECUTE_QUEUE_OUT_VAL->read() and
	     in_EXECUTE_QUEUE_OUT_ACK->read())
	  {
	    Tcontext_t packet;
	    if (_param->_have_port_rob_ptr)
	      packet = out_EXECUTE_QUEUE_OUT_PACKET_ID->read();
	    else
	      packet = 0;

	    LABEL(" * Accepted EXECUTE_QUEUE_OUT [%d]",packet);
// 	    std::cout << *request [packet] << std::endl;

	    if (_param->_have_port_context_id)
	    TEST(Tcontext_t     , out_EXECUTE_QUEUE_OUT_CONTEXT_ID   ->read(), request [packet]->_context_id   );
	    if (_param->_have_port_front_end_id)
	    TEST(Tcontext_t     , out_EXECUTE_QUEUE_OUT_FRONT_END_ID ->read(), request [packet]->_front_end_id );
	    if (_param->_have_port_ooo_engine_id)
	    TEST(Tcontext_t     , out_EXECUTE_QUEUE_OUT_OOO_ENGINE_ID->read(), request [packet]->_ooo_engine_id);
	  //TEST(Toperation_t   , out_EXECUTE_QUEUE_OUT_OPERATION    ->read(), request [packet]->_operation    );
	  //TEST(Ttype_t        , out_EXECUTE_QUEUE_OUT_TYPE         ->read(), request [packet]->_type         );
	    TEST(Tcontrol_t     , out_EXECUTE_QUEUE_OUT_FLAGS        ->read(), request [packet]->_flags        );
	    TEST(Texception_t   , out_EXECUTE_QUEUE_OUT_EXCEPTION    ->read(), request [packet]->_exception    );
	    TEST(Tcontrol_t     , out_EXECUTE_QUEUE_OUT_NO_SEQUENCE  ->read(), request [packet]->_no_sequence  );
	    TEST(Tgeneral_data_t, out_EXECUTE_QUEUE_OUT_ADDRESS      ->read(), request [packet]->_address      );
	    TEST(Tgeneral_data_t, out_EXECUTE_QUEUE_OUT_DATA         ->read(), request [packet]->_data         );

	    nb_request_out ++;
	  }

	SC_CYCLE(1);
      }
    }

  for (uint32_t i=0; i<_param->_nb_packet; i++)
    if (request[i] != NULL)
      delete request [i];
  
      /********************************************************
       * Simulation - End
       ********************************************************/
      
      TEST_OK ("");
      
      sc_stop();
      delete _time;
      
      msgInformation(_("<%s> : ............ Stop Simulation\n"),name.c_str());
    }
#endif
}
