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

#include <queue>
#include "Behavioural/Core/Multi_Execute_loop/Execute_loop/Multi_Execute_unit/Execute_unit/Load_store_unit/SelfTest/include/test.h"

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

#define LABEL(str)							\
  {									\
    cout << "{"+toString(static_cast<uint32_t>(sc_simulation_time()))+"} " << str << endl; \
  } 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)


//===================================================================={test}
void test1 (string name,
	   morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::Parameters * _param)
{
  cout << "<" << name << "> : Simulation SystemC" << endl;

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

  Load_store_unit * _Load_store_unit = new Load_store_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");

  sc_signal<Tcontrol_t        > *   in_MEMORY_IN_VAL                   = new sc_signal<Tcontrol_t        > (rename.c_str());
  sc_signal<Tcontrol_t        > *  out_MEMORY_IN_ACK                   = new sc_signal<Tcontrol_t        > (rename.c_str());
  sc_signal<Tcontext_t        > *   in_MEMORY_IN_CONTEXT_ID            = new sc_signal<Tcontext_t        > (rename.c_str());
  sc_signal<Tcontext_t        > *   in_MEMORY_IN_FRONT_END_ID          = new sc_signal<Tcontext_t        > (rename.c_str());
  sc_signal<Tcontext_t        > *   in_MEMORY_IN_OOO_ENGINE_ID         = new sc_signal<Tcontext_t        > (rename.c_str());
  sc_signal<Tpacket_t         > *   in_MEMORY_IN_PACKET_ID             = new sc_signal<Tpacket_t         > (rename.c_str());
  sc_signal<Toperation_t      > *   in_MEMORY_IN_OPERATION             = new sc_signal<Toperation_t      > (rename.c_str());
  sc_signal<Ttype_t           > *   in_MEMORY_IN_TYPE                  = new sc_signal<Ttype_t           > (rename.c_str());
  sc_signal<Tlsq_ptr_t        > *   in_MEMORY_IN_STORE_QUEUE_PTR_WRITE = new sc_signal<Tlsq_ptr_t        > (rename.c_str());
  sc_signal<Tlsq_ptr_t        > *   in_MEMORY_IN_LOAD_QUEUE_PTR_WRITE  = new sc_signal<Tlsq_ptr_t        > (rename.c_str());
  sc_signal<Tcontrol_t        > *   in_MEMORY_IN_HAS_IMMEDIAT          = new sc_signal<Tcontrol_t        > (rename.c_str());
  sc_signal<Tgeneral_data_t   > *   in_MEMORY_IN_IMMEDIAT              = new sc_signal<Tgeneral_data_t   > (rename.c_str());
  sc_signal<Tgeneral_data_t   > *   in_MEMORY_IN_DATA_RA               = new sc_signal<Tgeneral_data_t   > (rename.c_str());
  sc_signal<Tgeneral_data_t   > *   in_MEMORY_IN_DATA_RB               = new sc_signal<Tgeneral_data_t   > (rename.c_str());
  sc_signal<Tspecial_data_t   > *   in_MEMORY_IN_DATA_RC               = new sc_signal<Tspecial_data_t   > (rename.c_str());
  sc_signal<Tcontrol_t        > *   in_MEMORY_IN_WRITE_RD              = new sc_signal<Tcontrol_t        > (rename.c_str());
  sc_signal<Tgeneral_address_t> *   in_MEMORY_IN_NUM_REG_RD            = new sc_signal<Tgeneral_address_t> (rename.c_str());
  sc_signal<Tcontrol_t        > *   in_MEMORY_IN_WRITE_RE              = new sc_signal<Tcontrol_t        > (rename.c_str());
  sc_signal<Tspecial_address_t> *   in_MEMORY_IN_NUM_REG_RE            = new sc_signal<Tspecial_address_t> (rename.c_str());

  sc_signal<Tcontrol_t	      > *  out_MEMORY_OUT_VAL           = new sc_signal<Tcontrol_t	  >(rename.c_str());
  sc_signal<Tcontrol_t	      > *   in_MEMORY_OUT_ACK           = new sc_signal<Tcontrol_t	  >(rename.c_str());
  sc_signal<Tcontext_t        > *  out_MEMORY_OUT_CONTEXT_ID    = new sc_signal<Tcontext_t        >(rename.c_str());
  sc_signal<Tcontext_t        > *  out_MEMORY_OUT_FRONT_END_ID  = new sc_signal<Tcontext_t        >(rename.c_str());
  sc_signal<Tcontext_t        > *  out_MEMORY_OUT_OOO_ENGINE_ID = new sc_signal<Tcontext_t        >(rename.c_str());
  sc_signal<Tpacket_t         > *  out_MEMORY_OUT_PACKET_ID     = new sc_signal<Tpacket_t         >(rename.c_str());
//   sc_signal<Toperation_t      > *  out_MEMORY_OUT_OPERATION     = new sc_signal<Toperation_t      >(rename.c_str());
  sc_signal<Ttype_t           > *  out_MEMORY_OUT_TYPE          = new sc_signal<Ttype_t           >(rename.c_str());
  sc_signal<Tcontrol_t        > *  out_MEMORY_OUT_WRITE_RD      = new sc_signal<Tcontrol_t        >(rename.c_str());
  sc_signal<Tgeneral_address_t> *  out_MEMORY_OUT_NUM_REG_RD    = new sc_signal<Tgeneral_address_t>(rename.c_str());
  sc_signal<Tgeneral_data_t   > *  out_MEMORY_OUT_DATA_RD       = new sc_signal<Tgeneral_data_t   >(rename.c_str());
  sc_signal<Tcontrol_t        > *  out_MEMORY_OUT_WRITE_RE      = new sc_signal<Tcontrol_t        >(rename.c_str());
  sc_signal<Tspecial_address_t> *  out_MEMORY_OUT_NUM_REG_RE    = new sc_signal<Tspecial_address_t>(rename.c_str());
  sc_signal<Tspecial_data_t   > *  out_MEMORY_OUT_DATA_RE       = new sc_signal<Tspecial_data_t   >(rename.c_str());
  sc_signal<Texception_t      > *  out_MEMORY_OUT_EXCEPTION     = new sc_signal<Texception_t      >(rename.c_str());
  sc_signal<Tcontrol_t        > *  out_MEMORY_OUT_NO_SEQUENCE   = new sc_signal<Tcontrol_t        >(rename.c_str());
  sc_signal<Tgeneral_data_t   > *  out_MEMORY_OUT_ADDRESS       = new sc_signal<Tgeneral_data_t   >(rename.c_str());

  sc_signal<Tcontrol_t        > * out_DCACHE_REQ_VAL        = new sc_signal<Tcontrol_t        >(rename.c_str());
  sc_signal<Tcontrol_t        > *  in_DCACHE_REQ_ACK        = new sc_signal<Tcontrol_t        >(rename.c_str());
  sc_signal<Tcontext_t        > * out_DCACHE_REQ_CONTEXT_ID = new sc_signal<Tcontext_t        >(rename.c_str());
  sc_signal<Tpacket_t         > * out_DCACHE_REQ_PACKET_ID  = new sc_signal<Tpacket_t         >(rename.c_str());
  sc_signal<Tdcache_address_t > * out_DCACHE_REQ_ADDRESS    = new sc_signal<Tdcache_address_t >(rename.c_str());
  sc_signal<Tdcache_type_t    > * out_DCACHE_REQ_TYPE       = new sc_signal<Tdcache_type_t    >(rename.c_str());
  sc_signal<Tdcache_data_t    > * out_DCACHE_REQ_WDATA      = new sc_signal<Tdcache_data_t    >(rename.c_str());
  
  sc_signal<Tcontrol_t        > *  in_DCACHE_RSP_VAL        = new sc_signal<Tcontrol_t        >(rename.c_str());
  sc_signal<Tcontrol_t        > * out_DCACHE_RSP_ACK        = new sc_signal<Tcontrol_t        >(rename.c_str());
  sc_signal<Tcontext_t        > *  in_DCACHE_RSP_CONTEXT_ID = new sc_signal<Tcontext_t        >(rename.c_str());
  sc_signal<Tpacket_t         > *  in_DCACHE_RSP_PACKET_ID  = new sc_signal<Tpacket_t         >(rename.c_str());
  sc_signal<Tdcache_data_t    > *  in_DCACHE_RSP_RDATA      = new sc_signal<Tdcache_data_t    >(rename.c_str());
  sc_signal<Tdcache_error_t   > *  in_DCACHE_RSP_ERROR      = new sc_signal<Tdcache_error_t   >(rename.c_str());
  
  sc_signal<Tcontrol_t        > ** out_BYPASS_MEMORY_VAL           = new sc_signal<Tcontrol_t        > * [_param->_nb_bypass_memory];
  sc_signal<Tcontext_t        > ** out_BYPASS_MEMORY_OOO_ENGINE_ID = new sc_signal<Tcontext_t        > * [_param->_nb_bypass_memory];
  sc_signal<Tgeneral_address_t> ** out_BYPASS_MEMORY_NUM_REG       = new sc_signal<Tgeneral_address_t> * [_param->_nb_bypass_memory];
  sc_signal<Tgeneral_data_t   > ** out_BYPASS_MEMORY_DATA          = new sc_signal<Tgeneral_data_t   > * [_param->_nb_bypass_memory];
    
  for (uint32_t i=0; i<_param->_nb_bypass_memory; i++)
    {
      out_BYPASS_MEMORY_VAL           [i] = new sc_signal<Tcontrol_t        >(rename.c_str());
      out_BYPASS_MEMORY_OOO_ENGINE_ID [i] = new sc_signal<Tcontext_t        >(rename.c_str());
      out_BYPASS_MEMORY_NUM_REG       [i] = new sc_signal<Tgeneral_address_t>(rename.c_str());
      out_BYPASS_MEMORY_DATA          [i] = new sc_signal<Tgeneral_data_t   >(rename.c_str());
    }
  
  /********************************************************
   * Instanciation
   ********************************************************/
  
  cout << "<" << name << "> Instanciation of _Load_store_unit" << endl;
  
  (*(_Load_store_unit->in_CLOCK))        (*(in_CLOCK));
  (*(_Load_store_unit->in_NRESET))       (*(in_NRESET));

  (*(_Load_store_unit-> in_MEMORY_IN_VAL                  ))(*( in_MEMORY_IN_VAL                  ));
  (*(_Load_store_unit->out_MEMORY_IN_ACK                  ))(*(out_MEMORY_IN_ACK                  ));
  if (_param->_have_port_context_id)
  (*(_Load_store_unit-> in_MEMORY_IN_CONTEXT_ID           ))(*( in_MEMORY_IN_CONTEXT_ID           ));
  if (_param->_have_port_front_end_id)
  (*(_Load_store_unit-> in_MEMORY_IN_FRONT_END_ID         ))(*( in_MEMORY_IN_FRONT_END_ID         ));
  if (_param->_have_port_ooo_engine_id)
  (*(_Load_store_unit-> in_MEMORY_IN_OOO_ENGINE_ID        ))(*( in_MEMORY_IN_OOO_ENGINE_ID        ));
  if (_param->_have_port_packet_id)
  (*(_Load_store_unit-> in_MEMORY_IN_PACKET_ID            ))(*( in_MEMORY_IN_PACKET_ID            ));
  (*(_Load_store_unit-> in_MEMORY_IN_OPERATION            ))(*( in_MEMORY_IN_OPERATION            ));
  (*(_Load_store_unit-> in_MEMORY_IN_TYPE                 ))(*( in_MEMORY_IN_TYPE                 ));
  (*(_Load_store_unit-> in_MEMORY_IN_STORE_QUEUE_PTR_WRITE))(*( in_MEMORY_IN_STORE_QUEUE_PTR_WRITE));
  if (_param->_have_port_load_queue_ptr)
  (*(_Load_store_unit-> in_MEMORY_IN_LOAD_QUEUE_PTR_WRITE ))(*( in_MEMORY_IN_LOAD_QUEUE_PTR_WRITE ));
  (*(_Load_store_unit-> in_MEMORY_IN_HAS_IMMEDIAT         ))(*( in_MEMORY_IN_HAS_IMMEDIAT         ));
  (*(_Load_store_unit-> in_MEMORY_IN_IMMEDIAT             ))(*( in_MEMORY_IN_IMMEDIAT             ));
  (*(_Load_store_unit-> in_MEMORY_IN_DATA_RA              ))(*( in_MEMORY_IN_DATA_RA              ));
  (*(_Load_store_unit-> in_MEMORY_IN_DATA_RB              ))(*( in_MEMORY_IN_DATA_RB              ));
  (*(_Load_store_unit-> in_MEMORY_IN_DATA_RC              ))(*( in_MEMORY_IN_DATA_RC              ));
  (*(_Load_store_unit-> in_MEMORY_IN_WRITE_RD             ))(*( in_MEMORY_IN_WRITE_RD             ));
  (*(_Load_store_unit-> in_MEMORY_IN_NUM_REG_RD           ))(*( in_MEMORY_IN_NUM_REG_RD           ));
  (*(_Load_store_unit-> in_MEMORY_IN_WRITE_RE             ))(*( in_MEMORY_IN_WRITE_RE             ));
  (*(_Load_store_unit-> in_MEMORY_IN_NUM_REG_RE           ))(*( in_MEMORY_IN_NUM_REG_RE           ));
  
  (*(_Load_store_unit->out_MEMORY_OUT_VAL           ))(*(out_MEMORY_OUT_VAL           ));
  (*(_Load_store_unit-> in_MEMORY_OUT_ACK           ))(*( in_MEMORY_OUT_ACK           ));
  if (_param->_have_port_context_id)
  (*(_Load_store_unit->out_MEMORY_OUT_CONTEXT_ID    ))(*(out_MEMORY_OUT_CONTEXT_ID    ));
  if (_param->_have_port_front_end_id)
  (*(_Load_store_unit->out_MEMORY_OUT_FRONT_END_ID  ))(*(out_MEMORY_OUT_FRONT_END_ID  ));
  if (_param->_have_port_ooo_engine_id)
  (*(_Load_store_unit->out_MEMORY_OUT_OOO_ENGINE_ID ))(*(out_MEMORY_OUT_OOO_ENGINE_ID ));
  if (_param->_have_port_packet_id)
  (*(_Load_store_unit->out_MEMORY_OUT_PACKET_ID     ))(*(out_MEMORY_OUT_PACKET_ID     ));
//   (*(_Load_store_unit->out_MEMORY_OUT_OPERATION     ))(*(out_MEMORY_OUT_OPERATION     ));
  (*(_Load_store_unit->out_MEMORY_OUT_TYPE          ))(*(out_MEMORY_OUT_TYPE          ));
  (*(_Load_store_unit->out_MEMORY_OUT_WRITE_RD      ))(*(out_MEMORY_OUT_WRITE_RD      ));
  (*(_Load_store_unit->out_MEMORY_OUT_NUM_REG_RD    ))(*(out_MEMORY_OUT_NUM_REG_RD    ));
  (*(_Load_store_unit->out_MEMORY_OUT_DATA_RD       ))(*(out_MEMORY_OUT_DATA_RD       ));
  (*(_Load_store_unit->out_MEMORY_OUT_WRITE_RE      ))(*(out_MEMORY_OUT_WRITE_RE      ));
  (*(_Load_store_unit->out_MEMORY_OUT_NUM_REG_RE    ))(*(out_MEMORY_OUT_NUM_REG_RE    ));
  (*(_Load_store_unit->out_MEMORY_OUT_DATA_RE       ))(*(out_MEMORY_OUT_DATA_RE       ));
  (*(_Load_store_unit->out_MEMORY_OUT_EXCEPTION     ))(*(out_MEMORY_OUT_EXCEPTION     ));
  (*(_Load_store_unit->out_MEMORY_OUT_NO_SEQUENCE   ))(*(out_MEMORY_OUT_NO_SEQUENCE   ));
  (*(_Load_store_unit->out_MEMORY_OUT_ADDRESS       ))(*(out_MEMORY_OUT_ADDRESS       ));

  (*(_Load_store_unit->out_DCACHE_REQ_VAL       ))(*(out_DCACHE_REQ_VAL       ));
  (*(_Load_store_unit-> in_DCACHE_REQ_ACK       ))(*( in_DCACHE_REQ_ACK       ));
  if (_param->_have_port_dcache_context_id)
    (*(_Load_store_unit->out_DCACHE_REQ_CONTEXT_ID))(*(out_DCACHE_REQ_CONTEXT_ID));
  (*(_Load_store_unit->out_DCACHE_REQ_PACKET_ID ))(*(out_DCACHE_REQ_PACKET_ID ));
  (*(_Load_store_unit->out_DCACHE_REQ_ADDRESS   ))(*(out_DCACHE_REQ_ADDRESS   ));
  (*(_Load_store_unit->out_DCACHE_REQ_TYPE      ))(*(out_DCACHE_REQ_TYPE      ));
  (*(_Load_store_unit->out_DCACHE_REQ_WDATA     ))(*(out_DCACHE_REQ_WDATA     ));

  (*(_Load_store_unit-> in_DCACHE_RSP_VAL       ))(*( in_DCACHE_RSP_VAL       ));
  (*(_Load_store_unit->out_DCACHE_RSP_ACK       ))(*(out_DCACHE_RSP_ACK       ));
  if (_param->_have_port_dcache_context_id)
    (*(_Load_store_unit-> in_DCACHE_RSP_CONTEXT_ID))(*( in_DCACHE_RSP_CONTEXT_ID));
  (*(_Load_store_unit-> in_DCACHE_RSP_PACKET_ID ))(*( in_DCACHE_RSP_PACKET_ID ));
  (*(_Load_store_unit-> in_DCACHE_RSP_RDATA     ))(*( in_DCACHE_RSP_RDATA     ));
  (*(_Load_store_unit-> in_DCACHE_RSP_ERROR     ))(*( in_DCACHE_RSP_ERROR     ));

    {
      for (uint32_t i=0; i<_param->_nb_bypass_memory; i++)
	{
	  (*(_Load_store_unit->out_BYPASS_MEMORY_VAL           [i]))(*(out_BYPASS_MEMORY_VAL           [i]));
	  if (_param->_have_port_ooo_engine_id)    
	    (*(_Load_store_unit->out_BYPASS_MEMORY_OOO_ENGINE_ID [i]))(*(out_BYPASS_MEMORY_OOO_ENGINE_ID [i]));
	  (*(_Load_store_unit->out_BYPASS_MEMORY_NUM_REG       [i]))(*(out_BYPASS_MEMORY_NUM_REG       [i]));
	  (*(_Load_store_unit->out_BYPASS_MEMORY_DATA          [i]))(*(out_BYPASS_MEMORY_DATA          [i]));
	}
    }
  cout << "<" << name << "> Start Simulation ............" << endl;
  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 uint32_t     nb_request   = _param->_nb_packet;
  const uint32_t     nb_word      = nb_request;

  //const int32_t      percent_transaction_memory_in  = 100;
  const int32_t      percent_transaction_memory_out =  75;
  const int32_t      percent_transaction_dcache     =  75;

  const int32_t      percent_exception              =   0;
  const int32_t      percent_type_load              =   0;
  const int32_t      percent_type_store             =  50;
  const int32_t      percent_miss_spec              =  20;
  
  const uint32_t     miss_rate                      =  10;
  const uint32_t     miss_penality                  =   5;

  if ((percent_type_load  +
       percent_type_store ) > 100)
    TEST_KO("sum of percent_type > 100");

  const int32_t      seuil_type_load    = percent_type_load;
  const int32_t      seuil_type_store   = percent_type_store+percent_type_load;

  uint32_t           nb_request_memory_in ;
  uint32_t           nb_request_memory_out;
  uint32_t           nb_request_dcache    ;

  MemoryRequest_t                 tab_request  [nb_request];
  priority_queue<MemoryRequest_t> fifo_request;

  // emulation of memory
  Memory_t                      * _memory = new Memory_t (1<<_param->_size_dcache_context_id, nb_word, _param->_size_general_data);
  Cache_t                       * _cache  = new Cache_t  (miss_rate, miss_penality);


  SC_START(0);

  LABEL("Initialisation");

  in_MEMORY_IN_VAL ->write(0);
  in_MEMORY_OUT_ACK->write(0);
  in_DCACHE_REQ_ACK->write(0);
  in_DCACHE_RSP_VAL->write(0);

  in_NRESET        ->write(0);
  SC_START(5);
  in_NRESET        ->write(5);

  LABEL("Loop of Test");

  try 
    {
      for (uint32_t iteration=0; iteration<NB_ITERATION; iteration ++)
	{
	  LABEL("Iteration "+toString(iteration));

	  LABEL("Structure's initialisation");

	  nb_request_memory_in  = 0;
	  nb_request_memory_out = 0;
	  nb_request_dcache     = 0;
      
	  // Fill the request_queue
      
	  Tlsq_ptr_t         store_queue_ptr_write = 0;
	  Tlsq_ptr_t         load_queue_ptr_write  = 0;

	  bool               store_queue_use [_param->_size_store_queue];
	  uint32_t           nb_store_slot_use = 0;
	  bool               load_queue_use  [_param->_size_load_queue ];

	  for (uint32_t i=0; i<_param->_size_store_queue; i++)
	    store_queue_use [i] = false;
	  for (uint32_t i=0; i<_param->_size_load_queue ; i++)
	    load_queue_use  [i] = false;

	  double             current_cycle = sc_simulation_time();
	  double             cycle_min     = current_cycle;

	  Toperation_t       operation_store [4] = {OPERATION_MEMORY_STORE_8,
						    OPERATION_MEMORY_STORE_16,
						    OPERATION_MEMORY_STORE_32,
						    OPERATION_MEMORY_STORE_64};

	  Toperation_t       operation_load  [8] = {OPERATION_MEMORY_LOAD_8_Z,
						    OPERATION_MEMORY_LOAD_8_S,
						    OPERATION_MEMORY_LOAD_16_Z,
						    OPERATION_MEMORY_LOAD_16_S,
						    OPERATION_MEMORY_LOAD_32_Z,
						    OPERATION_MEMORY_LOAD_32_S,
						    OPERATION_MEMORY_LOAD_64_Z,
						    OPERATION_MEMORY_LOAD_64_S};

	  Toperation_t       operation_other [5] = {OPERATION_MEMORY_LOCK           ,
						    OPERATION_MEMORY_INVALIDATE     ,
						    OPERATION_MEMORY_PREFETCH       ,
						    OPERATION_MEMORY_FLUSH          ,
						    OPERATION_MEMORY_SYNCHRONIZATION};


	  const uint32_t nb_operation_store =   (log2(_param->_size_general_data/8)+1);
	  const uint32_t nb_operation_load  = 2*(log2(_param->_size_general_data/8)+1);
	  const uint32_t nb_operation_other = 5;

	  LABEL("Fifo request initialisation");
	  // Init fifo_request
	  for (uint32_t i=0; i<nb_request; i++)
	    {
	      double       cycle;
	      Tcontext_t   context_id                = 0;
	      Tcontext_t   front_end_id              = 0;
	      Tcontext_t   ooo_engine_id             = rand () % _param->_nb_ooo_engine;
	      Tpacket_t    packet_id                 = i;
	      Tlsq_ptr_t   store_queue_ptr_write_old = store_queue_ptr_write;
	      Tlsq_ptr_t   load_queue_ptr_write_old  = load_queue_ptr_write ;
	      Toperation_t operation;
	  
	      int32_t      percent = rand()%100;

	      uint32_t     size_queue;
	 
	      if (percent < seuil_type_load)
		{
		  LABEL(" * LOAD");
		  operation            = operation_load[(rand()%nb_operation_load)];
		  size_queue           = _param->_size_load_queue;
		  load_queue_ptr_write = (load_queue_ptr_write+1) % (size_queue);
		}
	      else
		{
		  if (percent < seuil_type_store)
		    {
		      LABEL(" * STORE");
		  
		  
		      operation             = operation_store[(rand()%nb_operation_store)];
		      size_queue            = _param->_size_store_queue;
		      store_queue_ptr_write = (store_queue_ptr_write+1) % (size_queue);
		    }
		  else
		    {
		      LABEL(" * OTHERS");
		      operation            = operation_other[(rand()%nb_operation_other)];
		      // 		  operation            = operation_other[4];
		      size_queue           = _param->_size_load_queue;
		      load_queue_ptr_write = (load_queue_ptr_write+1) % (size_queue);
		    }
		}

	      cycle = cycle_min;
	      cycle_min ++;

	      Ttype_t            type    = TYPE_MEMORY;
	      Tgeneral_data_t    address = rand()%(nb_word);
	      Tgeneral_data_t    offset  = rand()%(nb_word);

	      // LABEL ("Address step 1 : "+toString(address)+" - "+toString(offset));

	      percent = rand()%100;
	      if (percent > percent_exception) 
		address = address & (~ mask_memory_access(operation));
	  
	      // LABEL ("Address step 2 : "+toString(address)+" - mask : "+toString((~ mask_memory_access(operation))));

	      if (offset > address) // max
		offset  = address;

	      Tgeneral_data_t    immediat      = offset;
	      Tgeneral_data_t    data_ra       = address - offset;

	      // LABEL ("Address step 3 : "+toString(address)+", "+toString(data_ra)+" - "+toString(immediat));
	  
	      Tgeneral_data_t    data_rb       = static_cast<Tgeneral_data_t>(rand());
	      Tcontrol_t         write_rd      = 0;
	      Tgeneral_address_t num_reg_rd    = 0;
	      bool               write_spec_ko = is_operation_memory_store(operation) and ((rand()%100)<percent_miss_spec);

	      tab_request [i].modif(cycle                    ,
				    context_id               ,
				    front_end_id             ,
				    ooo_engine_id            ,
				    packet_id                ,
				    operation                ,
				    type                     ,
				    store_queue_ptr_write_old,
				    load_queue_ptr_write_old ,
				    immediat                 ,
				    data_ra                  ,
				    data_rb                  ,
				    write_rd                 ,
				    num_reg_rd               ,
				    write_spec_ko);

	      cout << tab_request [i] << endl;
	
	      fifo_request.push(tab_request [i]);

	      double cycle_head = 0;

	      if (is_operation_memory_store(operation))
		{
		  cycle_head = cycle_min;
		  cycle_min ++;

		  cout << "         * Write head : " << toString(cycle_head) 
		       << endl
		       << endl;
	      
		  fifo_request.push(MemoryRequest_t(cycle_head,
						    context_id,
						    front_end_id,
						    ooo_engine_id,
						    packet_id,
						    (write_spec_ko==true)?OPERATION_MEMORY_STORE_HEAD_KO:OPERATION_MEMORY_STORE_HEAD_OK,
						    type,
						    store_queue_ptr_write_old,
						    0,
						    0,
						    0,
						    0,
						    0,
						    0,
						    write_spec_ko));
		}
	    }
        
	  LABEL("Simulation of this iteration ...");
    
	  while (nb_request_memory_out < nb_request)
	    {
	      cout << "*********************************************" << endl;
	      cout << "Dump STORE_QUEUE_USE : " << endl;
	      cout << " use " << nb_store_slot_use << endl;
	      for (uint32_t i=0; i<_param->_size_store_queue; i++)
		cout << "  [" << i << "] " << store_queue_use [i] << endl;
	      cout << "Dump LOAD_QUEUE_USE : " << endl;
	      for (uint32_t i=0; i<_param->_size_load_queue ; i++)
		cout << "  [" << i << "] " << load_queue_use [i] << endl;
	      cout << "*********************************************" << endl;


	      // ***** MEMORY_IN *****

	      // memory_in_val depends of three factors :
	      //  1) request's fifo is not empty ?
	      //  2) the slot destination is free ?
	      //  3) The head of request's fifo can be issue : the number of cycle is more than current cycle

	      bool can_execute = false;

	      if (is_operation_memory_store(fifo_request.top()._operation))
		can_execute = (not store_queue_use [fifo_request.top()._store_queue_ptr_write] and (nb_store_slot_use < _param->_size_store_queue-1)) or is_operation_memory_store_head(fifo_request.top()._operation);
	      else
		can_execute = not load_queue_use  [fifo_request.top()._load_queue_ptr_write];
	  
	      in_MEMORY_IN_VAL ->write((not fifo_request.empty()) and 
				       can_execute                and 
				       (sc_simulation_time() >= fifo_request.top()._cycle));

	      if (_param->_have_port_context_id)
		in_MEMORY_IN_CONTEXT_ID           ->write (fifo_request.top()._context_id           );
	      if (_param->_have_port_front_end_id)
		in_MEMORY_IN_FRONT_END_ID         ->write (fifo_request.top()._front_end_id         );
	      if (_param->_have_port_ooo_engine_id)
		in_MEMORY_IN_OOO_ENGINE_ID        ->write (fifo_request.top()._ooo_engine_id        );
	      if (_param->_have_port_packet_id)
		in_MEMORY_IN_PACKET_ID            ->write (fifo_request.top()._packet_id            );
	      in_MEMORY_IN_OPERATION            ->write (fifo_request.top()._operation            );
	      in_MEMORY_IN_TYPE                 ->write (fifo_request.top()._type                 );
	      in_MEMORY_IN_STORE_QUEUE_PTR_WRITE->write (fifo_request.top()._store_queue_ptr_write);
	      if (_param->_have_port_load_queue_ptr)
	      in_MEMORY_IN_LOAD_QUEUE_PTR_WRITE ->write (fifo_request.top()._load_queue_ptr_write );
	      in_MEMORY_IN_IMMEDIAT             ->write (fifo_request.top()._immediat             );
	      in_MEMORY_IN_DATA_RA              ->write (fifo_request.top()._data_ra              );
	      in_MEMORY_IN_DATA_RB              ->write (fifo_request.top()._data_rb              );
// 	      in_MEMORY_IN_WRITE_RD             ->write (fifo_request.top()._write_rd             );
	      in_MEMORY_IN_NUM_REG_RD           ->write (fifo_request.top()._num_reg_rd           );

	      in_MEMORY_OUT_ACK->write((rand()%100)<percent_transaction_memory_out);

	      // ***** DCACHE_REQ *****
	      in_DCACHE_REQ_ACK->write((rand()%100)<percent_transaction_dcache);

	      // ***** DCACHE_RSP *****
	      bool have_rsp = _cache->have_rsp ();
	      in_DCACHE_RSP_VAL->write(have_rsp);

	      if (have_rsp)
		{
		  in_DCACHE_RSP_CONTEXT_ID->write(_cache->front()._context_id);
		  in_DCACHE_RSP_PACKET_ID ->write(_cache->front()._packet_id );
		  in_DCACHE_RSP_RDATA     ->write(_cache->front()._rdata     );
		  in_DCACHE_RSP_ERROR     ->write(_cache->front()._error     );
		}

	      SC_START(0);

	      LABEL("MEMORY_IN  : "+toString(in_MEMORY_IN_VAL ->read())+" - "+toString(out_MEMORY_IN_ACK ->read()));
	      LABEL("  * fifo_request.empty                     : "+toString(fifo_request.empty()));
	      LABEL("  * fifo_request.top.cycle                 : "+toString(fifo_request.top()._cycle));
	      LABEL("  * fifo_request.top.store_queue_ptr_write : "+toString(static_cast<uint32_t>(fifo_request.top()._store_queue_ptr_write)));
	      LABEL("  * fifo_request.top.load_queue_ptr_write  : "+toString(static_cast<uint32_t>(fifo_request.top()._load_queue_ptr_write)));
	      LABEL("  * fifo_request.top.operation             : "+toString(static_cast<uint32_t>(fifo_request.top()._operation           )));
	      LABEL("  * can_execute                            : "+toString(can_execute));

	      if ( in_MEMORY_IN_VAL ->read() and out_MEMORY_IN_ACK ->read())
		{
		  LABEL(" * Accepted MEMORY_IN  : " + toString(nb_request_memory_in));
		  cout << fifo_request.top();

		  if (is_operation_memory_store(fifo_request.top()._operation))
		    {
		      if (not is_operation_memory_store_head(fifo_request.top()._operation))
			{
			  store_queue_use [fifo_request.top()._store_queue_ptr_write] = true;
			  nb_store_slot_use ++;
			}
		    }
		  else
		    load_queue_use [fifo_request.top()._load_queue_ptr_write] = true;

		  fifo_request.pop();
	      
		  nb_request_memory_in ++;
		}

	      LABEL("MEMORY_OUT : "+toString(out_MEMORY_OUT_VAL->read())+" - "+toString(in_MEMORY_OUT_ACK ->read()));
	      if (out_MEMORY_OUT_VAL->read() and  in_MEMORY_OUT_ACK->read())
		{
		  Tpacket_t  packet_id = out_MEMORY_OUT_PACKET_ID->read();

		  LABEL(" * Accepted MEMORY_OUT : " + toString(packet_id));

		  if (is_operation_memory_store(tab_request[packet_id]._operation))
		    {
		      store_queue_use [tab_request[packet_id]._store_queue_ptr_write] = false;
		      nb_store_slot_use --;
		    }
		  else
		    load_queue_use  [tab_request[packet_id]._load_queue_ptr_write] = false;

		  nb_request_memory_out ++;

		  // a lot of test
		  TEST(Tcontext_t        , out_MEMORY_OUT_CONTEXT_ID   ->read(), tab_request[packet_id]._context_id   );
		  TEST(Tcontext_t        , out_MEMORY_OUT_FRONT_END_ID ->read(), tab_request[packet_id]._front_end_id );
		  TEST(Tcontext_t        , out_MEMORY_OUT_OOO_ENGINE_ID->read(), tab_request[packet_id]._ooo_engine_id);
		  TEST(Tpacket_t         , out_MEMORY_OUT_PACKET_ID    ->read(), tab_request[packet_id]._packet_id    );
// 		  TEST(Toperation_t      , out_MEMORY_OUT_OPERATION    ->read(), tab_request[packet_id]._operation    );
		  TEST(Ttype_t           , out_MEMORY_OUT_TYPE         ->read(), TYPE_MEMORY                          );
		  TEST(Tcontrol_t        , out_MEMORY_OUT_WRITE_RD     ->read(), tab_request[packet_id]._write_rd     );
		  TEST(Tgeneral_address_t, out_MEMORY_OUT_NUM_REG_RD   ->read(), tab_request[packet_id]._num_reg_rd   );

		  Tgeneral_data_t address = tab_request[packet_id]._data_ra + tab_request[packet_id]._immediat;
		  if (address != (address & (~ mask_memory_access(tab_request[packet_id]._operation))))
		    TEST(Texception_t      , out_MEMORY_OUT_EXCEPTION    ->read(), EXCEPTION_MEMORY_ALIGNMENT);
		  else
		    {
		      if (tab_request[packet_id]._write_spec_ko)
			TEST(Texception_t, out_MEMORY_OUT_EXCEPTION    ->read(), EXCEPTION_MEMORY_MISS_SPECULATION);
		      else
			{
			  TEST(Texception_t, out_MEMORY_OUT_EXCEPTION    ->read(), EXCEPTION_MEMORY_NONE);

			  if (is_operation_memory_load(tab_request[packet_id]._operation))
			    {
			      Tgeneral_data_t read_lsq = _memory->read_lsq (((tab_request[packet_id]._ooo_engine_id<<(_param->_size_context_id + _param->_size_front_end_id )) |
									     (tab_request[packet_id]._front_end_id <<(_param->_size_context_id)) |
									     (tab_request[packet_id]._context_id)),
									    (tab_request[packet_id]._immediat +
									     tab_request[packet_id]._data_ra), 
									    tab_request[packet_id]._operation);
			      cout << "MEMORY_OUT is a LOAD" << endl
				   << "  * operation       : " << tab_request[packet_id]._operation << endl
				   << std::hex
				   << "  * address         : " << (tab_request[packet_id]._immediat +
								   tab_request[packet_id]._data_ra) << endl
				   << "  * read_lsq        : " << read_lsq << endl
				   << "  * memory_out_data : " << out_MEMORY_OUT_DATA_RD->read() << endl
				   << std::dec;
			  
// 			      TEST(Tgeneral_data_t   , out_MEMORY_OUT_DATA_RD->read(), read_lsq);
			    }
			}
		    }
		}

	      LABEL("DCACHE_REQ : "+toString(out_DCACHE_REQ_VAL->read())+" - "+toString(in_DCACHE_REQ_ACK ->read()));
	      if (out_DCACHE_REQ_VAL->read() and  in_DCACHE_REQ_ACK->read())
		{
		  Tcontext_t   context_id;
		  Tpacket_t    packet_id ; 
		  if (_param->_have_port_dcache_context_id)
		    context_id = out_DCACHE_REQ_CONTEXT_ID->read();
		  else
		    context_id = 0;

		  packet_id  = (out_DCACHE_REQ_PACKET_ID ->read())>>1;
	      
		  LABEL(" * Accepted DCACHE_REQ : " + toString(packet_id));

// 		  TEST(Tcontext_t       ,out_DCACHE_REQ_CONTEXT_ID->read(),((tab_request[packet_id]._ooo_engine_id<<(_param->_size_context_id + _param->_size_front_end_id )) |
// 									    (tab_request[packet_id]._front_end_id <<(_param->_size_context_id)) |
// 									    (tab_request[packet_id]._context_id)));
// 		  TEST(Tdcache_address_t,out_DCACHE_REQ_ADDRESS   ->read(),(tab_request[packet_id]._immediat +
// 									    tab_request[packet_id]._data_ra) );
// 		  TEST(Tdcache_type_t   ,out_DCACHE_REQ_TYPE      ->read(), operation_to_dcache_type(operation));
		  
// 		  if (is_operation_memory_store(operation))
// 		    TEST(Tdcache_data_t   ,out_DCACHE_REQ_WDATA     ->read(),tab_request[packet_id]._data_rb);

		  Tdcache_data_t rdata = _memory->access (context_id, out_DCACHE_REQ_ADDRESS->read(), out_DCACHE_REQ_TYPE->read(), out_DCACHE_REQ_WDATA->read());

		  // test type : send or not a respons !
		  LABEL("   * rdata : " + toString(rdata));

		  if ((out_DCACHE_REQ_TYPE->read() == DCACHE_TYPE_SYNCHRONIZATION) or
		      (out_DCACHE_REQ_TYPE->read() == DCACHE_TYPE_LOAD))
		    {
		      LABEL("     * have_dcache_rsp");
		  
		      _cache->push (context_id,
				    out_DCACHE_REQ_PACKET_ID ->read(),
				    rdata     ,
				    0);
		    }
		}

	      LABEL("DCACHE_RSP : "+toString(in_DCACHE_RSP_VAL->read())+" - "+toString(out_DCACHE_RSP_ACK ->read()));
	      if (in_DCACHE_RSP_VAL->read() and out_DCACHE_RSP_ACK->read())
		{
		  _cache->pop();
		}

	      _cache->end_cycle();

	      SC_START(1);
	    }
	}
    }
  catch (morpheo::ErrorMorpheo & error)
    {
      _memory->trace();
      throw (error);
    }

  _memory->trace();

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

  TEST_OK ("End of Simulation");
  delete _time;
  cout << "<" << name << "> ............ Stop Simulation" << endl;

  delete     in_CLOCK;
  delete     in_NRESET;

  delete     in_MEMORY_IN_VAL         ;
  delete    out_MEMORY_IN_ACK         ;
  delete     in_MEMORY_IN_CONTEXT_ID  ;
  delete     in_MEMORY_IN_FRONT_END_ID  ;
  delete     in_MEMORY_IN_OOO_ENGINE_ID  ;
  delete     in_MEMORY_IN_PACKET_ID   ;
  delete     in_MEMORY_IN_OPERATION   ;
  delete     in_MEMORY_IN_STORE_QUEUE_PTR_WRITE;
  delete     in_MEMORY_IN_LOAD_QUEUE_PTR_WRITE ;
  delete     in_MEMORY_IN_HAS_IMMEDIAT;
  delete     in_MEMORY_IN_IMMEDIAT    ;
  delete     in_MEMORY_IN_DATA_RA     ;
  delete     in_MEMORY_IN_DATA_RB     ;
  delete     in_MEMORY_IN_DATA_RC     ;
  delete     in_MEMORY_IN_WRITE_RD    ;
  delete     in_MEMORY_IN_NUM_REG_RD  ;
  delete     in_MEMORY_IN_WRITE_RE    ;
  delete     in_MEMORY_IN_NUM_REG_RE  ;
    
  delete    out_MEMORY_OUT_VAL       ;
  delete     in_MEMORY_OUT_ACK       ;
  delete    out_MEMORY_OUT_CONTEXT_ID;
  delete    out_MEMORY_OUT_FRONT_END_ID;
  delete    out_MEMORY_OUT_OOO_ENGINE_ID;
  delete    out_MEMORY_OUT_PACKET_ID ;
//   delete    out_MEMORY_OUT_OPERATION ;
  delete    out_MEMORY_OUT_TYPE      ;
  delete    out_MEMORY_OUT_WRITE_RD  ;
  delete    out_MEMORY_OUT_NUM_REG_RD;
  delete    out_MEMORY_OUT_DATA_RD   ;
  delete    out_MEMORY_OUT_WRITE_RE  ;
  delete    out_MEMORY_OUT_NUM_REG_RE;
  delete    out_MEMORY_OUT_DATA_RE   ;
  delete    out_MEMORY_OUT_EXCEPTION ;
  delete    out_MEMORY_OUT_NO_SEQUENCE;
  delete    out_MEMORY_OUT_ADDRESS   ;
  
  delete    out_DCACHE_REQ_VAL       ;
  delete     in_DCACHE_REQ_ACK       ;
  delete    out_DCACHE_REQ_CONTEXT_ID;
  delete    out_DCACHE_REQ_PACKET_ID ;
  delete    out_DCACHE_REQ_ADDRESS   ;
  delete    out_DCACHE_REQ_TYPE      ;
  delete    out_DCACHE_REQ_WDATA     ;
  
  delete     in_DCACHE_RSP_VAL       ;
  delete    out_DCACHE_RSP_ACK       ;
  delete     in_DCACHE_RSP_CONTEXT_ID;
  delete     in_DCACHE_RSP_PACKET_ID ;
  delete     in_DCACHE_RSP_RDATA     ;
  delete     in_DCACHE_RSP_ERROR     ;
  
    {
      delete [] out_BYPASS_MEMORY_VAL       ;
      delete [] out_BYPASS_MEMORY_OOO_ENGINE_ID;
      delete [] out_BYPASS_MEMORY_NUM_REG   ;
      delete [] out_BYPASS_MEMORY_DATA      ;
    }
#endif

  delete _Load_store_unit;
  delete _memory;
  delete _cache;
#ifdef STATISTICS
  delete _parameters_statistics;
#endif
}
