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

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

#define NB_ITERATION  1
#define CYCLE_MAX     (128*NB_ITERATION)

#define LABEL(str...)							\
  {									\
    msg (_("{%d} "),static_cast<uint32_t>(sc_simulation_time()));	\
    msg (str);								\
    msg (_("\n"));							\
  } while(0)

#define SC_START(cycle_offset)                                                       \
  do									             \
    {									             \
      /*cout << "SC_START (begin)" << endl;*/				             \
									             \
      uint32_t cycle_current = static_cast<uint32_t>(sc_simulation_time());          \
      if (cycle_offset != 0)						             \
	{								             \
	  cout << "##########[ cycle "<< cycle_current+cycle_offset << " ]" << endl; \
	}								             \
									             \
      if (cycle_current > CYCLE_MAX)					             \
	{								             \
	  TEST_KO("Maximal cycles Reached");				             \
	}								             \
									             \
      sc_start(cycle_offset);						             \
									             \
      /*cout << "SC_START (end  )" << endl;*/				             \
    } while(0)

  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  : Tcontrol_t         _write_rd     ;
  public  : Tgeneral_address_t _num_reg_rd   ;
  public  : Tgeneral_data_t    _data_rd      ;
  public  : Tcontrol_t         _write_re     ;
  public  : Tspecial_address_t _num_reg_re   ;
  public  : Tspecial_data_t    _data_re      ;
  public  : Texception_t       _exception    ;
  public  : Tcontrol_t         _no_sequence  ;
  public  : Tgeneral_data_t    _address      ;
    
  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         ,
		     Tcontrol_t         write_rd     ,
		     Tgeneral_address_t num_reg_rd   ,
		     Tgeneral_data_t    data_rd      ,
		     Tcontrol_t         write_re     ,
		     Tspecial_address_t num_reg_re   ,
		     Tspecial_data_t    data_re      ,
		     Texception_t       exception    ,
		     Tcontrol_t         no_sequence  ,
		     Tgeneral_data_t    address      )
    {
      _context_id    = context_id   ;
      _front_end_id  = front_end_id ;
      _ooo_engine_id = ooo_engine_id;
      _packet_id     = packet_id    ;
    //_operation     = operation    ;
      _type          = type         ;
      _write_rd      = write_rd     ;
      _num_reg_rd    = num_reg_rd   ;
      _data_rd       = data_rd      ;
      _write_re      = write_re     ;
      _num_reg_re    = num_reg_re   ;
      _data_re       = data_re      ;
      _exception     = exception    ;
      _no_sequence   = no_sequence  ;
      _address       = address      ;
    };

    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
		    << " * _write_rd      : " << toString(x._write_rd     ) << std::endl
		    << " * _num_reg_rd    : " << toString(x._num_reg_rd   ) << std::endl
		    << " * _data_rd       : " << toString(x._data_rd      ) << std::endl
		    << " * _write_re      : " << toString(x._write_re     ) << std::endl
		    << " * _num_reg_re    : " << toString(x._num_reg_re   ) << std::endl
		    << " * _data_re       : " << toString(x._data_re      ) << std::endl
		    << " * _exception     : " << toString(x._exception    ) << std::endl
		    << " * _no_sequence   : " << toString(x._no_sequence  ) << std::endl
		    << " * _address       : " << toString(x._address      ) << std::endl;

      return output_stream;
    }
  };


void test (string name,
	   morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_write_unit::write_unit::Parameters * _param)
{
  msg(_("<%s> : Simulation SystemC.\n"),name.c_str());

#ifdef STATISTICS
  morpheo::behavioural::Parameters_Statistics * _parameters_statistics = new morpheo::behavioural::Parameters_Statistics (5,50);
#endif

  Write_unit * _Write_unit = new Write_unit (name.c_str(),
#ifdef STATISTICS
					     _parameters_statistics,
#endif
					     _param);
  
#ifdef SYSTEMC
  /*********************************************************************
   * Déclarations des signaux
   *********************************************************************/
  string rename;

  sc_clock              *  in_CLOCK  = new sc_clock ("clock", 1.0, 0.5);	 
  sc_signal<Tcontrol_t> *  in_NRESET = new sc_signal<Tcontrol_t> ("NRESET");

  ALLOC_SC_SIGNAL ( in_WRITE_UNIT_IN_VAL           ," in_WRITE_UNIT_IN_VAL"           , Tcontrol_t        );
  ALLOC_SC_SIGNAL (out_WRITE_UNIT_IN_ACK           ,"out_WRITE_UNIT_IN_ACK"           , Tcontrol_t        );
  ALLOC_SC_SIGNAL ( in_WRITE_UNIT_IN_CONTEXT_ID    ," in_WRITE_UNIT_IN_CONTEXT_ID"    , Tcontext_t        );
  ALLOC_SC_SIGNAL ( in_WRITE_UNIT_IN_FRONT_END_ID  ," in_WRITE_UNIT_IN_FRONT_END_ID"  , Tcontext_t        );
  ALLOC_SC_SIGNAL ( in_WRITE_UNIT_IN_OOO_ENGINE_ID ," in_WRITE_UNIT_IN_OOO_ENGINE_ID" , Tcontext_t        );
  ALLOC_SC_SIGNAL ( in_WRITE_UNIT_IN_PACKET_ID     ," in_WRITE_UNIT_IN_PACKET_ID"     , Tpacket_t         );
//ALLOC_SC_SIGNAL ( in_WRITE_UNIT_IN_OPERATION     ," in_WRITE_UNIT_IN_OPERATION"     , Toperation_t      );
  ALLOC_SC_SIGNAL ( in_WRITE_UNIT_IN_TYPE          ," in_WRITE_UNIT_IN_TYPE"          , Ttype_t           );
  ALLOC_SC_SIGNAL ( in_WRITE_UNIT_IN_WRITE_RD      ," in_WRITE_UNIT_IN_WRITE_RD"      , Tcontrol_t        );
  ALLOC_SC_SIGNAL ( in_WRITE_UNIT_IN_NUM_REG_RD    ," in_WRITE_UNIT_IN_NUM_REG_RD"    , Tgeneral_address_t);
  ALLOC_SC_SIGNAL ( in_WRITE_UNIT_IN_DATA_RD       ," in_WRITE_UNIT_IN_DATA_RD"       , Tgeneral_data_t   );
  ALLOC_SC_SIGNAL ( in_WRITE_UNIT_IN_WRITE_RE      ," in_WRITE_UNIT_IN_WRITE_RE"      , Tcontrol_t        );
  ALLOC_SC_SIGNAL ( in_WRITE_UNIT_IN_NUM_REG_RE    ," in_WRITE_UNIT_IN_NUM_REG_RE"    , Tspecial_address_t);
  ALLOC_SC_SIGNAL ( in_WRITE_UNIT_IN_DATA_RE       ," in_WRITE_UNIT_IN_DATA_RE"       , Tspecial_data_t   );
  ALLOC_SC_SIGNAL ( in_WRITE_UNIT_IN_EXCEPTION     ," in_WRITE_UNIT_IN_EXCEPTION"     , Texception_t      );
  ALLOC_SC_SIGNAL ( in_WRITE_UNIT_IN_NO_SEQUENCE   ," in_WRITE_UNIT_IN_NO_SEQUENCE"   , Tcontrol_t        );
  ALLOC_SC_SIGNAL ( in_WRITE_UNIT_IN_ADDRESS       ," in_WRITE_UNIT_IN_ADDRESS"       , Tgeneral_data_t   );
  ALLOC_SC_SIGNAL (out_WRITE_UNIT_OUT_VAL          ,"out_WRITE_UNIT_OUT_VAL"          , Tcontrol_t        );
  ALLOC_SC_SIGNAL ( in_WRITE_UNIT_OUT_ACK          ," in_WRITE_UNIT_OUT_ACK"          , Tcontrol_t        );
  ALLOC_SC_SIGNAL (out_WRITE_UNIT_OUT_CONTEXT_ID   ,"out_WRITE_UNIT_OUT_CONTEXT_ID"   , Tcontext_t        );
  ALLOC_SC_SIGNAL (out_WRITE_UNIT_OUT_FRONT_END_ID ,"out_WRITE_UNIT_OUT_FRONT_END_ID" , Tcontext_t        );
  ALLOC_SC_SIGNAL (out_WRITE_UNIT_OUT_OOO_ENGINE_ID,"out_WRITE_UNIT_OUT_OOO_ENGINE_ID", Tcontext_t        );
  ALLOC_SC_SIGNAL (out_WRITE_UNIT_OUT_PACKET_ID    ,"out_WRITE_UNIT_OUT_PACKET_ID"    , Tpacket_t         );
//ALLOC_SC_SIGNAL (out_WRITE_UNIT_OUT_OPERATION    ,"out_WRITE_UNIT_OUT_OPERATION"    , Toperation_t      );
//ALLOC_SC_SIGNAL (out_WRITE_UNIT_OUT_TYPE         ,"out_WRITE_UNIT_OUT_TYPE"         , Ttype_t           );
  ALLOC_SC_SIGNAL (out_WRITE_UNIT_OUT_FLAGS        ,"out_WRITE_UNIT_OUT_FLAGS"        , Tspecial_data_t   );
  ALLOC_SC_SIGNAL (out_WRITE_UNIT_OUT_EXCEPTION    ,"out_WRITE_UNIT_OUT_EXCEPTION"    , Texception_t      );
  ALLOC_SC_SIGNAL (out_WRITE_UNIT_OUT_NO_SEQUENCE  ,"out_WRITE_UNIT_OUT_NO_SEQUENCE"  , Tcontrol_t        );
  ALLOC_SC_SIGNAL (out_WRITE_UNIT_OUT_ADDRESS      ,"out_WRITE_UNIT_OUT_ADDRESS"      , Tgeneral_data_t   );
  ALLOC1_SC_SIGNAL(out_GPR_WRITE_VAL                ,"out_GPR_WRITE_VAL"                , Tcontrol_t        , _param->_nb_gpr_write);
  ALLOC1_SC_SIGNAL( in_GPR_WRITE_ACK                ," in_GPR_WRITE_ACK"                , Tcontrol_t        , _param->_nb_gpr_write);
  ALLOC1_SC_SIGNAL(out_GPR_WRITE_OOO_ENGINE_ID      ,"out_GPR_WRITE_OOO_ENGINE_ID"      , Tcontext_t        , _param->_nb_gpr_write);
  ALLOC1_SC_SIGNAL(out_GPR_WRITE_NUM_REG            ,"out_GPR_WRITE_NUM_REG"            , Tgeneral_address_t, _param->_nb_gpr_write);
  ALLOC1_SC_SIGNAL(out_GPR_WRITE_DATA               ,"out_GPR_WRITE_DATA"               , Tgeneral_data_t   , _param->_nb_gpr_write);
  ALLOC1_SC_SIGNAL(out_SPR_WRITE_VAL                ,"out_SPR_WRITE_VAL"                , Tcontrol_t        , _param->_nb_spr_write);
  ALLOC1_SC_SIGNAL( in_SPR_WRITE_ACK                ," in_SPR_WRITE_ACK"                , Tcontrol_t        , _param->_nb_spr_write);
  ALLOC1_SC_SIGNAL(out_SPR_WRITE_OOO_ENGINE_ID      ,"out_SPR_WRITE_OOO_ENGINE_ID"      , Tcontext_t        , _param->_nb_spr_write);
  ALLOC1_SC_SIGNAL(out_SPR_WRITE_NUM_REG            ,"out_SPR_WRITE_NUM_REG"            , Tspecial_address_t, _param->_nb_spr_write);
  ALLOC1_SC_SIGNAL(out_SPR_WRITE_DATA               ,"out_SPR_WRITE_DATA"               , Tspecial_data_t   , _param->_nb_spr_write);
  ALLOC1_SC_SIGNAL(out_BYPASS_WRITE_OOO_ENGINE_ID   ,"out_BYPASS_WRITE_OOO_ENGINE_ID"   , Tcontext_t        , _param->_nb_bypass_write);
  ALLOC1_SC_SIGNAL(out_BYPASS_WRITE_GPR_VAL         ,"out_BYPASS_WRITE_GPR_VAL"         , Tcontrol_t        , _param->_nb_bypass_write);
  ALLOC1_SC_SIGNAL(out_BYPASS_WRITE_GPR_NUM_REG     ,"out_BYPASS_WRITE_GPR_NUM_REG"     , Tgeneral_address_t, _param->_nb_bypass_write);
  ALLOC1_SC_SIGNAL(out_BYPASS_WRITE_GPR_DATA        ,"out_BYPASS_WRITE_GPR_DATA"        , Tgeneral_data_t   , _param->_nb_bypass_write);
  ALLOC1_SC_SIGNAL(out_BYPASS_WRITE_SPR_VAL         ,"out_BYPASS_WRITE_SPR_VAL"         , Tcontrol_t        , _param->_nb_bypass_write);
  ALLOC1_SC_SIGNAL(out_BYPASS_WRITE_SPR_NUM_REG     ,"out_BYPASS_WRITE_SPR_NUM_REG"     , Tspecial_address_t, _param->_nb_bypass_write);
  ALLOC1_SC_SIGNAL(out_BYPASS_WRITE_SPR_DATA        ,"out_BYPASS_WRITE_SPR_DATA"        , Tspecial_data_t   , _param->_nb_bypass_write);
  
  
  /********************************************************
   * Instanciation
   ********************************************************/
  
  msg(_("<%s> : Instanciation of _Write_unit.\n"),name.c_str());

  (*(_Write_unit->in_CLOCK))        (*(in_CLOCK));
  (*(_Write_unit->in_NRESET))       (*(in_NRESET));

  INSTANCE_SC_SIGNAL (_Write_unit,  in_WRITE_UNIT_IN_VAL           );
  INSTANCE_SC_SIGNAL (_Write_unit, out_WRITE_UNIT_IN_ACK           );
  if (_param->_have_port_context_id)
  INSTANCE_SC_SIGNAL (_Write_unit,  in_WRITE_UNIT_IN_CONTEXT_ID    );
  if (_param->_have_port_front_end_id)
  INSTANCE_SC_SIGNAL (_Write_unit,  in_WRITE_UNIT_IN_FRONT_END_ID  );
  if (_param->_have_port_ooo_engine_id)
  INSTANCE_SC_SIGNAL (_Write_unit,  in_WRITE_UNIT_IN_OOO_ENGINE_ID );
  if (_param->_have_port_packet_id)
  INSTANCE_SC_SIGNAL (_Write_unit,  in_WRITE_UNIT_IN_PACKET_ID     );
//INSTANCE_SC_SIGNAL (_Write_unit,  in_WRITE_UNIT_IN_OPERATION     );
  INSTANCE_SC_SIGNAL (_Write_unit,  in_WRITE_UNIT_IN_TYPE          );
  INSTANCE_SC_SIGNAL (_Write_unit,  in_WRITE_UNIT_IN_WRITE_RD      );
  INSTANCE_SC_SIGNAL (_Write_unit,  in_WRITE_UNIT_IN_NUM_REG_RD    );
  INSTANCE_SC_SIGNAL (_Write_unit,  in_WRITE_UNIT_IN_DATA_RD       );
  INSTANCE_SC_SIGNAL (_Write_unit,  in_WRITE_UNIT_IN_WRITE_RE      );
  INSTANCE_SC_SIGNAL (_Write_unit,  in_WRITE_UNIT_IN_NUM_REG_RE    );
  INSTANCE_SC_SIGNAL (_Write_unit,  in_WRITE_UNIT_IN_DATA_RE       );
  INSTANCE_SC_SIGNAL (_Write_unit,  in_WRITE_UNIT_IN_EXCEPTION     );
  INSTANCE_SC_SIGNAL (_Write_unit,  in_WRITE_UNIT_IN_NO_SEQUENCE   );
  INSTANCE_SC_SIGNAL (_Write_unit,  in_WRITE_UNIT_IN_ADDRESS       );
  INSTANCE_SC_SIGNAL (_Write_unit, out_WRITE_UNIT_OUT_VAL          );
  INSTANCE_SC_SIGNAL (_Write_unit,  in_WRITE_UNIT_OUT_ACK          );
  if (_param->_have_port_context_id)
  INSTANCE_SC_SIGNAL (_Write_unit, out_WRITE_UNIT_OUT_CONTEXT_ID   );
  if (_param->_have_port_front_end_id)
  INSTANCE_SC_SIGNAL (_Write_unit, out_WRITE_UNIT_OUT_FRONT_END_ID );
  if (_param->_have_port_ooo_engine_id)
  INSTANCE_SC_SIGNAL (_Write_unit, out_WRITE_UNIT_OUT_OOO_ENGINE_ID);
  if (_param->_have_port_packet_id)
  INSTANCE_SC_SIGNAL (_Write_unit, out_WRITE_UNIT_OUT_PACKET_ID    );
//INSTANCE_SC_SIGNAL (_Write_unit, out_WRITE_UNIT_OUT_OPERATION    );
//INSTANCE_SC_SIGNAL (_Write_unit, out_WRITE_UNIT_OUT_TYPE         );
  INSTANCE_SC_SIGNAL (_Write_unit, out_WRITE_UNIT_OUT_FLAGS        );
  INSTANCE_SC_SIGNAL (_Write_unit, out_WRITE_UNIT_OUT_EXCEPTION    );
  INSTANCE_SC_SIGNAL (_Write_unit, out_WRITE_UNIT_OUT_NO_SEQUENCE  );
  INSTANCE_SC_SIGNAL (_Write_unit, out_WRITE_UNIT_OUT_ADDRESS      );
  INSTANCE1_SC_SIGNAL(_Write_unit, out_GPR_WRITE_VAL                , _param->_nb_gpr_write);
  INSTANCE1_SC_SIGNAL(_Write_unit,  in_GPR_WRITE_ACK                , _param->_nb_gpr_write);
  if (_param->_have_port_ooo_engine_id)
  INSTANCE1_SC_SIGNAL(_Write_unit, out_GPR_WRITE_OOO_ENGINE_ID      , _param->_nb_gpr_write);
  INSTANCE1_SC_SIGNAL(_Write_unit, out_GPR_WRITE_NUM_REG            , _param->_nb_gpr_write);
  INSTANCE1_SC_SIGNAL(_Write_unit, out_GPR_WRITE_DATA               , _param->_nb_gpr_write);
  INSTANCE1_SC_SIGNAL(_Write_unit, out_SPR_WRITE_VAL                , _param->_nb_spr_write);
  INSTANCE1_SC_SIGNAL(_Write_unit,  in_SPR_WRITE_ACK                , _param->_nb_spr_write);
  if (_param->_have_port_ooo_engine_id)
  INSTANCE1_SC_SIGNAL(_Write_unit, out_SPR_WRITE_OOO_ENGINE_ID      , _param->_nb_spr_write);
  INSTANCE1_SC_SIGNAL(_Write_unit, out_SPR_WRITE_NUM_REG            , _param->_nb_spr_write);
  INSTANCE1_SC_SIGNAL(_Write_unit, out_SPR_WRITE_DATA               , _param->_nb_spr_write);
  if (_param->_have_port_ooo_engine_id)
  INSTANCE1_SC_SIGNAL(_Write_unit, out_BYPASS_WRITE_OOO_ENGINE_ID   , _param->_nb_bypass_write);
  INSTANCE1_SC_SIGNAL(_Write_unit, out_BYPASS_WRITE_GPR_VAL         , _param->_nb_bypass_write);
  INSTANCE1_SC_SIGNAL(_Write_unit, out_BYPASS_WRITE_GPR_NUM_REG     , _param->_nb_bypass_write);
  INSTANCE1_SC_SIGNAL(_Write_unit, out_BYPASS_WRITE_GPR_DATA        , _param->_nb_bypass_write);
  INSTANCE1_SC_SIGNAL(_Write_unit, out_BYPASS_WRITE_SPR_VAL         , _param->_nb_bypass_write);
  INSTANCE1_SC_SIGNAL(_Write_unit, out_BYPASS_WRITE_SPR_NUM_REG     , _param->_nb_bypass_write);
  INSTANCE1_SC_SIGNAL(_Write_unit, out_BYPASS_WRITE_SPR_DATA        , _param->_nb_bypass_write);

  msg(_("<%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));

  srand(seed);
  
  const  int32_t percent_transaction_write_unit_in  = 75;
  const  int32_t percent_transaction_write_unit_out = 75;
  const  int32_t percent_transaction_gpr             = 75;
  const  int32_t percent_transaction_spr             = 75;

  bool            gpr_val [_param->_nb_ooo_engine][_param->_nb_general_register];
  bool            gpr_use [_param->_nb_ooo_engine][_param->_nb_general_register];
  Tgeneral_data_t gpr     [_param->_nb_ooo_engine][_param->_nb_general_register];
  bool            spr_val [_param->_nb_ooo_engine][_param->_nb_special_register];
  bool            spr_use [_param->_nb_ooo_engine][_param->_nb_special_register];
  Tgeneral_data_t spr     [_param->_nb_ooo_engine][_param->_nb_special_register];

  entry_t *       request [_param->_nb_packet];
  
  SC_START(0);
  LABEL("Initialisation");

  LABEL("Reset");
  in_NRESET->write(0);
  SC_START(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_ooo_engine; i++)
	{
	  for (uint32_t j=0; j<_param->_nb_general_register; j++)
	    {
	      gpr_val [i][j] = 0;
	      gpr_use [i][j] = 0;
	      gpr     [i][j] = rand();
	    }
	  for (uint32_t j=0; j<_param->_nb_special_register; j++)
	    {
	      spr_val [i][j] = 0;
	      spr_use [i][j] = 0;
	      spr     [i][j] = rand();
	    }
	}

      for (uint32_t i=0; i<_param->_nb_packet; 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<Tcontrol_t        >(rand(),1                             ),
				     range<Tgeneral_address_t>(rand(),_param->_size_general_register),
				     range<Tgeneral_data_t   >(rand(),_param->_size_general_data    ),
				     range<Tcontrol_t        >(rand(),1                             ),
				     range<Tspecial_address_t>(rand(),_param->_size_special_register),
				     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    ));
	}

      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_write_unit_in) and
		    (nb_request_in < _param->_nb_packet) and
		    not (request [nb_request_in]->_write_rd and 
			 gpr_use [request [nb_request_in]->_ooo_engine_id][request [nb_request_in]->_num_reg_rd]) and
		    not (request [nb_request_in]->_write_re and 
			 spr_use [request [nb_request_in]->_ooo_engine_id][request [nb_request_in]->_num_reg_re]));
	
	in_WRITE_UNIT_IN_VAL          ->write(val);
	if (val)
	  {
	    in_WRITE_UNIT_IN_CONTEXT_ID   ->write(request [nb_request_in]->_context_id   );
	    in_WRITE_UNIT_IN_FRONT_END_ID ->write(request [nb_request_in]->_front_end_id );
	    in_WRITE_UNIT_IN_OOO_ENGINE_ID->write(request [nb_request_in]->_ooo_engine_id);
	    in_WRITE_UNIT_IN_PACKET_ID    ->write(request [nb_request_in]->_packet_id    );
	  //in_WRITE_UNIT_IN_OPERATION    ->write(request [nb_request_in]->_operation    );
	    in_WRITE_UNIT_IN_TYPE         ->write(request [nb_request_in]->_type         );
	    in_WRITE_UNIT_IN_WRITE_RD     ->write(request [nb_request_in]->_write_rd     );
	    in_WRITE_UNIT_IN_NUM_REG_RD   ->write(request [nb_request_in]->_num_reg_rd   );
	    in_WRITE_UNIT_IN_DATA_RD      ->write(request [nb_request_in]->_data_rd      );
	    in_WRITE_UNIT_IN_WRITE_RE     ->write(request [nb_request_in]->_write_re     );
	    in_WRITE_UNIT_IN_NUM_REG_RE   ->write(request [nb_request_in]->_num_reg_re   );
	    in_WRITE_UNIT_IN_DATA_RE      ->write(request [nb_request_in]->_data_re      );
	    in_WRITE_UNIT_IN_EXCEPTION    ->write(request [nb_request_in]->_exception    );
	    in_WRITE_UNIT_IN_NO_SEQUENCE  ->write(request [nb_request_in]->_no_sequence  );
	    in_WRITE_UNIT_IN_ADDRESS      ->write(request [nb_request_in]->_address      );
	  }
	in_WRITE_UNIT_OUT_ACK         ->write((rand()%100)<percent_transaction_write_unit_out);
	in_GPR_WRITE_ACK [0]           ->write((rand()%100)<percent_transaction_gpr);
	in_SPR_WRITE_ACK [0]           ->write((rand()%100)<percent_transaction_spr);
	    
	SC_START(0);

	// ======================================================================
	// ======================================================================
	// ======================================================================
	if (out_GPR_WRITE_VAL [0]->read() and
	     in_GPR_WRITE_ACK [0]->read())
	  {
	    Tcontext_t         ooo_engine_id = (_param->_have_port_ooo_engine_id)?out_GPR_WRITE_OOO_ENGINE_ID[0]->read():0;
	    Tgeneral_address_t num_reg       = out_GPR_WRITE_NUM_REG      [0]->read();
	    Tgeneral_data_t    data          = out_GPR_WRITE_DATA         [0]->read();
	    
	    LABEL(" * Accepted GPR_WRITE     in register [%d][%d]", ooo_engine_id,num_reg);

	    TEST(bool           , gpr_val [ooo_engine_id][num_reg], 0);
	    TEST(bool           , gpr_use [ooo_engine_id][num_reg], 1);
	    TEST(Tgeneral_data_t, gpr     [ooo_engine_id][num_reg], data);
	    
	    gpr_val [ooo_engine_id][num_reg] = 1;
	  }

	// ======================================================================
	// ======================================================================
	// ======================================================================
	if (out_SPR_WRITE_VAL [0]->read() and
	     in_SPR_WRITE_ACK [0]->read())
	  {
	    Tcontext_t         ooo_engine_id = (_param->_have_port_ooo_engine_id)?out_SPR_WRITE_OOO_ENGINE_ID[0]->read():0;
	    Tspecial_address_t num_reg       = out_SPR_WRITE_NUM_REG      [0]->read();
	    Tspecial_data_t    data          = out_SPR_WRITE_DATA         [0]->read();
	    
	    LABEL(" * Accepted SPR_WRITE     in register [%d][%d]", ooo_engine_id,num_reg);

	    TEST(bool           , spr_val [ooo_engine_id][num_reg], 0);
	    TEST(bool           , spr_use [ooo_engine_id][num_reg], 1);
	    TEST(Tgeneral_data_t, spr     [ooo_engine_id][num_reg], data);
	    
	    spr_val [ooo_engine_id][num_reg] = 1;
	  }

	// ======================================================================
	// ======================================================================
	// ======================================================================
	for (uint32_t i=0; i<_param->_nb_bypass_write; i++)
	  {
	    Tcontext_t         ooo_engine_id  = (_param->_have_port_ooo_engine_id)?out_BYPASS_WRITE_OOO_ENGINE_ID[i]->read():0;
	    
	    if (out_BYPASS_WRITE_GPR_VAL      [i]->read())
	      {
		Tgeneral_address_t num_reg    = out_BYPASS_WRITE_GPR_NUM_REG  [i]->read(); // RD
		Tgeneral_data_t    data       = out_BYPASS_WRITE_GPR_DATA     [i]->read();

		LABEL(" * Accepted BYPASS_WRITE  in register [%d][%d] (GPR)", ooo_engine_id,num_reg);
			    

		TEST(bool           , gpr_use [ooo_engine_id][num_reg], 1);
		TEST(Tgeneral_data_t, gpr     [ooo_engine_id][num_reg], data);
	      }
	    if (out_BYPASS_WRITE_SPR_VAL      [i]->read())
	      {
		Tspecial_address_t num_reg    = out_BYPASS_WRITE_SPR_NUM_REG  [i]->read(); // RE
		Tspecial_data_t    data       = out_BYPASS_WRITE_SPR_DATA     [i]->read();

		LABEL(" * Accepted BYPASS_WRITE  in register [%d][%d] (SPR)", ooo_engine_id,num_reg);

		TEST(bool           , spr_use [ooo_engine_id][num_reg], 1);
		TEST(Tspecial_data_t, spr     [ooo_engine_id][num_reg], data);
	      }
	  }
	
	// ======================================================================
	// ======================================================================
	// ======================================================================
	if ( in_WRITE_UNIT_IN_VAL->read() and
	    out_WRITE_UNIT_IN_ACK->read())
	  {
	    LABEL(" * Accepted WRITE_UNIT_IN  [%d]",nb_request_in);
// 	    std::cout << *request [nb_request_in] << std::endl;

	    if (request [nb_request_in]->_write_rd)
	      {
		gpr_val [request [nb_request_in]->_ooo_engine_id][request [nb_request_in]->_num_reg_rd] = 0;
		gpr_use [request [nb_request_in]->_ooo_engine_id][request [nb_request_in]->_num_reg_rd] = 1;
		gpr     [request [nb_request_in]->_ooo_engine_id][request [nb_request_in]->_num_reg_rd] = request [nb_request_in]->_data_rd;
	      }
	    if (request [nb_request_in]->_write_re)
	      {
		spr_val [request [nb_request_in]->_ooo_engine_id][request [nb_request_in]->_num_reg_re] = 0;
		spr_use [request [nb_request_in]->_ooo_engine_id][request [nb_request_in]->_num_reg_re] = 1;
		spr     [request [nb_request_in]->_ooo_engine_id][request [nb_request_in]->_num_reg_re] = request [nb_request_in]->_data_re;
	      }
	    nb_request_in ++;
	  }
	
	// ======================================================================
	// ======================================================================
	// ======================================================================
	if (out_WRITE_UNIT_OUT_VAL->read() and
	     in_WRITE_UNIT_OUT_ACK->read())
	  {
	    Tcontext_t packet;
	    if (_param->_have_port_packet_id)
	      packet = out_WRITE_UNIT_OUT_PACKET_ID->read();
	    else
	      packet = 0;

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

	    if (request [packet]->_write_rd)
	      {
		TEST(bool, gpr_val [request [packet]->_ooo_engine_id][request [packet]->_num_reg_rd], 1);
		TEST(bool, gpr_use [request [packet]->_ooo_engine_id][request [packet]->_num_reg_rd], 1);
		gpr_use [request [packet]->_ooo_engine_id][request [packet]->_num_reg_rd] = 0;
	      }
	    if (request [packet]->_write_re)
	      {
		TEST(bool, spr_val [request [packet]->_ooo_engine_id][request [packet]->_num_reg_re], 1);
		TEST(bool, spr_use [request [packet]->_ooo_engine_id][request [packet]->_num_reg_re], 1);
		spr_use [request [packet]->_ooo_engine_id][request [packet]->_num_reg_re] = 0;
	      }

	    if (_param->_have_port_context_id)
	    TEST(Tcontext_t     , out_WRITE_UNIT_OUT_CONTEXT_ID   ->read(), request [packet]->_context_id   );
	    if (_param->_have_port_front_end_id)
	    TEST(Tcontext_t     , out_WRITE_UNIT_OUT_FRONT_END_ID ->read(), request [packet]->_front_end_id );
	    if (_param->_have_port_ooo_engine_id)
	    TEST(Tcontext_t     , out_WRITE_UNIT_OUT_OOO_ENGINE_ID->read(), request [packet]->_ooo_engine_id);
	    
	  //TEST(Toperation_t   , out_WRITE_UNIT_OUT_OPERATION    ->read(), request [packet]->_operation    );
	  //TEST(Ttype_t        , out_WRITE_UNIT_OUT_TYPE         ->read(), request [packet]->_type         );
	    TEST(Tcontrol_t     , out_WRITE_UNIT_OUT_FLAGS        ->read(), request [packet]->_data_re      );
	    TEST(Texception_t   , out_WRITE_UNIT_OUT_EXCEPTION    ->read(), request [packet]->_exception    );
	    TEST(Tcontrol_t     , out_WRITE_UNIT_OUT_NO_SEQUENCE  ->read(), request [packet]->_no_sequence  );
	    TEST(Tgeneral_data_t, out_WRITE_UNIT_OUT_ADDRESS      ->read(), request [packet]->_address      );

	    nb_request_out ++;
	  }

	SC_START(1);
      }

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

    }


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

  TEST_OK ("End of Simulation");
  delete _time;

  msg(_("<%s> : ............ Stop Simulation\n"),name.c_str());

  delete in_CLOCK;
  delete in_NRESET;
#endif

  delete _Write_unit;
#ifdef STATISTICS
  delete _parameters_statistics;
#endif
}
