/*
 * $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"
#include "Common/include/Test.h"
#include "Common/include/BitManipulation.h"

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

#define LABEL(str)                                                                       \
{                                                                                        \
  cout << "{"+toString(static_cast<uint32_t>(sc_simulation_time()))+"} " << str << endl; \
} while(0)

static uint32_t cycle = 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_current != cycle)                                           \
    {                                                                   \
      cycle = cycle_current;                                            \
      cout << "##########[ cycle "<< cycle << " ]" << endl;             \
    }                                                                   \
                                                                        \
  if (cycle_current > CYCLE_MAX)                                        \
    {                                                                   \
      TEST_KO("Maximal cycles Reached");                                \
    }                                                                   \
  sc_start(cycle_offset);                                               \
/*cout << "SC_START (end  )" << endl;*/                                 \
} while(0)



//========================================================={MemoryRequest_t}
class MemoryRequest_t
{
public : double             _cycle                ;
public : Tcontext_t         _context_id           ;
public : Tpacket_t          _packet_id            ;
public : Toperation_t       _operation            ;
public : Ttype_t            _type                 ;
public : Tlsq_ptr_t         _store_queue_ptr_write;
public : Tlsq_ptr_t         _load_queue_ptr_write ;
public : Tgeneral_data_t    _immediat             ;
public : Tgeneral_data_t    _data_ra              ;
public : Tgeneral_data_t    _data_rb              ;
public : Tcontrol_t         _write_rd             ;
public : Tgeneral_address_t _num_reg_rd           ;
public : bool               _write_spec_ko        ;

  MemoryRequest_t (void) 
  {
    _cycle                 = 0;
    _context_id            = 0;
    _packet_id             = 0;
    _operation             = 0;
    _type                  = 0;
    _store_queue_ptr_write = 0;
    _load_queue_ptr_write  = 0;
    _immediat              = 0;
    _data_ra               = 0;
    _data_rb               = 0;
    _write_rd              = 0;
    _num_reg_rd            = 0;
    _write_spec_ko         = 0;
  };

  MemoryRequest_t (double             cycle                ,
		   Tcontext_t         context_id           ,
		   Tpacket_t          packet_id            ,
		   Toperation_t       operation            ,
		   Ttype_t            type                 ,
		   Tlsq_ptr_t         store_queue_ptr_write,
		   Tlsq_ptr_t         load_queue_ptr_write ,
		   Tgeneral_data_t    immediat             ,
		   Tgeneral_data_t    data_ra              ,
		   Tgeneral_data_t    data_rb              ,
		   Tcontrol_t         write_rd             ,
		   Tgeneral_address_t num_reg_rd           ,
		   bool               write_spec_ko        )
  {
    _cycle                 = cycle                ;
    _context_id            = context_id           ;
    _packet_id             = packet_id            ;
    _operation             = operation            ;
    _type                  = type                 ;
    _store_queue_ptr_write = store_queue_ptr_write;
    _load_queue_ptr_write  = load_queue_ptr_write ;
    _immediat              = immediat             ;
    _data_ra               = data_ra              ;
    _data_rb               = data_rb              ;
    _write_rd              = write_rd             ;
    _num_reg_rd            = num_reg_rd           ;
    _write_spec_ko         = write_spec_ko        ;
  }

  void modif (double             cycle                ,
	      Tcontext_t         context_id           ,
	      Tpacket_t          packet_id            ,
	      Toperation_t       operation            ,
	      Ttype_t            type                 ,
	      Tlsq_ptr_t         store_queue_ptr_write,
	      Tlsq_ptr_t         load_queue_ptr_write ,
	      Tgeneral_data_t    immediat             ,
	      Tgeneral_data_t    data_ra              ,
	      Tgeneral_data_t    data_rb              ,
	      Tcontrol_t         write_rd             ,
	      Tgeneral_address_t num_reg_rd           ,
	      bool               write_spec_ko        )
  {
    _cycle                 = cycle                ;
    _context_id            = context_id           ;
    _packet_id             = packet_id            ;
    _operation             = operation            ;
    _type                  = type                 ;
    _store_queue_ptr_write = store_queue_ptr_write;
    _load_queue_ptr_write  = load_queue_ptr_write ;
    _immediat              = immediat             ;
    _data_ra               = data_ra              ;
    _data_rb               = data_rb              ;
    _write_rd              = write_rd             ;
    _num_reg_rd            = num_reg_rd           ;
    _write_spec_ko         = write_spec_ko        ;
  }

  bool operator< (const MemoryRequest_t & right) const 
  {
    return _cycle > right._cycle; 
  }

  friend ostream& operator<<(ostream &, const MemoryRequest_t &);
};

ostream & operator << (ostream& os, const MemoryRequest_t & x) 
{
  return os << "<" << toString(x._cycle) << "> : "
	    << "{" << toString(static_cast<uint32_t>(x._packet_id)) << "}" << endl
	    << "\t * context_id                        : " << toString(static_cast<uint32_t>(x._context_id)) << endl
	    << "\t * operation  / type / write_spec_ko : " << toString(static_cast<uint32_t>(x._operation)) << " " << toString(static_cast<uint32_t>(x._type)) << " " << toString(static_cast<uint32_t>(x._write_spec_ko)) << endl
	    << "\t * ptr_write store/load              : " << toString(static_cast<uint32_t>(x._store_queue_ptr_write)) << " " << toString(static_cast<uint32_t>(x._load_queue_ptr_write)) << endl
	    << "\t * immediat / data_ra / data_rb      : " << toString(static_cast<uint32_t>(x._immediat)) << " - " << toString(static_cast<uint32_t>(x._data_ra)) << " - " << toString(static_cast<uint32_t>(x._data_rb)) << endl
	    << "\t * write_rd / num_reg_rd             : " << toString(static_cast<uint32_t>(x._write_rd)) << " " << toString(static_cast<uint32_t>(x._num_reg_rd)) << endl;
}

//================================================================{Memory_t}
class Memory_t
{
private : const uint32_t    _nb_context;
private : const uint32_t    _nb_word   ;
private : const uint32_t    _size_data ;
private : const Tdcache_address_t _mask_addr ;
private : Tdcache_data_t ** _data;
  
public  : Memory_t (uint32_t nb_context, 
		    uint32_t nb_word, 
		    uint32_t size_data):
  _nb_context   (nb_context),
  _nb_word      (nb_word   ),
  _size_data    (size_data ),
  _mask_addr    (gen_mask<Tdcache_address_t>(static_cast<uint32_t>(log2(ceil(static_cast<double>(size_data))))))
  {
    _data = new Tdcache_data_t * [nb_context];
    
    for (uint32_t i=0; i<nb_context; i++)
      {
	_data [i] = new Tdcache_data_t [nb_word];
	
	for (uint32_t j=0; j<nb_word; j++)
	  _data [i][j] = rand()%(size_data);
      }
  }

public  : ~Memory_t (void)
  {
    delete [] _data;
  }

public  : Tdcache_data_t access (uint32_t          context, 
				 Tdcache_address_t address,
				 Tdcache_type_t    type,
				 Tdcache_data_t    data)
  {
    return 0;
  }

public  : Tdcache_data_t read (uint32_t          context,
			       Tdcache_address_t address,
			       Tdcache_type_t    type)
  {
    // Address's Read must be aligned

    if ((address & _mask_addr) != 0)
      TEST_KO("<Memory_t::read> Address is not aligned");

    if (context>_nb_context)
      TEST_KO("<Memory_t::read> nb context is too high");

    if (address>_nb_word)
      TEST_KO("<Memory_t::read> address is too high");
    
    return _data [context][address];
  }

public  : void write (uint32_t          context, 
		      Tdcache_address_t address,
		      Tdcache_type_t    type,
		      Tdcache_data_t    data)
  {
    if (context>_nb_context)
      TEST_KO("<Memory_t::read> nb context is too high");

    if (address>_nb_word)
      TEST_KO("<Memory_t::read> address is too high");

    Tdcache_address_t LSB = address &  _mask;
    Tdcache_address_t MSB = address & ~_mask;
  
    Tdcache_data_t write_data = data;
    Tdcache_data_t read_data  = _data [context][MSB];

    // exemple to size_data = 32b
    // LSB index_min
    // 0   0
    // 1   8
    // 2   16
    // 3   24
    uint32_t index_min = LSB<<3;
    uint32_t index_max = index_min;
    // index max, dependant of access's size

    switch (type)
      {


      }
  }
};

//===================================================================={test}
void test (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,50);
#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<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<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_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<Tcontrol_t        > * out_DCACHE_REQ_UNCACHED   = new sc_signal<Tcontrol_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->_size_load_queue];
  sc_signal<Tcontext_t        > ** out_BYPASS_MEMORY_CONTEXT_ID = new sc_signal<Tcontext_t        > * [_param->_size_load_queue];
  sc_signal<Tgeneral_address_t> ** out_BYPASS_MEMORY_NUM_REG    = new sc_signal<Tgeneral_address_t> * [_param->_size_load_queue];
  sc_signal<Tgeneral_data_t   > ** out_BYPASS_MEMORY_DATA       = new sc_signal<Tgeneral_data_t   > * [_param->_size_load_queue];
    
    for (uint32_t i=0; i<_param->_size_load_queue; i++)
      {
	out_BYPASS_MEMORY_VAL        [i] = new sc_signal<Tcontrol_t        >;
	out_BYPASS_MEMORY_CONTEXT_ID [i] = new sc_signal<Tcontext_t        >;
	out_BYPASS_MEMORY_NUM_REG    [i] = new sc_signal<Tgeneral_address_t>;
	out_BYPASS_MEMORY_DATA       [i] = new sc_signal<Tgeneral_data_t   >;
      }
  
  /********************************************************
   * 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                  ));
  (*(_Load_store_unit-> in_MEMORY_IN_CONTEXT_ID           ))(*( in_MEMORY_IN_CONTEXT_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_STORE_QUEUE_PTR_WRITE))(*( in_MEMORY_IN_STORE_QUEUE_PTR_WRITE));
  (*(_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        ));
  (*(_Load_store_unit->out_MEMORY_OUT_CONTEXT_ID ))(*(out_MEMORY_OUT_CONTEXT_ID ));
  (*(_Load_store_unit->out_MEMORY_OUT_PACKET_ID  ))(*(out_MEMORY_OUT_PACKET_ID  ));
  (*(_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_DCACHE_REQ_VAL       ))(*(out_DCACHE_REQ_VAL       ));
  (*(_Load_store_unit-> in_DCACHE_REQ_ACK       ))(*( in_DCACHE_REQ_ACK       ));
  (*(_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_UNCACHED  ))(*(out_DCACHE_REQ_UNCACHED  ));
  (*(_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       ));
  (*(_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     ));

  if (_param->_speculative_load == SPECULATIVE_LOAD_BYPASS)
    {
      for (uint32_t i=0; i<_param->_size_load_queue; i++)
	{
	  (*(_Load_store_unit->out_BYPASS_MEMORY_VAL        [i]))(*(out_BYPASS_MEMORY_VAL        [i]));
	  (*(_Load_store_unit->out_BYPASS_MEMORY_CONTEXT_ID [i]))(*(out_BYPASS_MEMORY_CONTEXT_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 = 100;
  const int32_t      percent_transaction_dcache     = 100;

  const int32_t      percent_exception              =   5;
  const int32_t      percent_type_load              =   0;
  const int32_t      percent_type_store             = 100;
  const int32_t      percent_miss_spec              =   0;

  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 cache
  Tdcache_data_t     cache_data                [_param->_nb_context][nb_word];

  SC_START(0);

  LABEL("Initialisation");

  // emulate a memory
  for (uint32_t i=0; i<_param->_nb_context; i++)
    for (uint32_t j=0; j<nb_word; j++)
      cache_data [i][j] = rand()%(1<<_param->_size_general_data);

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

  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];
      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;

      LABEL("Fifo request initialisation");
      // Init fifo_request
      for (uint32_t i=0; i<nb_request; i++)
	{
	  double             cycle;
	  Tcontext_t         context_id                = rand () % _param->_nb_context;
	  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_MEMORY_LOAD_16_S;
	      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_MEMORY_STORE_16;
		  size_queue            = _param->_size_store_queue;
		  store_queue_ptr_write = (store_queue_ptr_write+1) % (size_queue);
		}
	      else
		{
// 		  LABEL(" * OTHERS");
		  operation            = OPERATION_MEMORY_PREFETCH;
		  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);

	  percent = rand()%100;
	  if (percent > percent_exception) 
	    address = address & (not mask_memory_access(operation));

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

	  Tgeneral_data_t    immediat              = offset;
	  Tgeneral_data_t    data_ra               = address - offset;
	  Tgeneral_data_t    data_rb               = rand()%(1<<_param->_size_general_data);
	  Tcontrol_t         write_rd              = 0;
	  Tgeneral_address_t num_reg_rd            = 0;
	  bool               write_spec_ko         = ((rand()%100)<percent_miss_spec);

	  tab_request [i].modif(cycle                ,
				context_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,
						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)
	{
	  // ***** 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]) 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));

	  in_MEMORY_IN_CONTEXT_ID           ->write (fifo_request.top()._context_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);
   	  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);

	  SC_START(0);
  
	  SC_START(1);

	  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;
		}
	      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())
	    {
	      LABEL(" * Accepted MEMORY_OUT : " + toString(static_cast<uint32_t>(out_MEMORY_OUT_PACKET_ID->read())));

	      if (is_operation_memory_store(tab_request[out_MEMORY_OUT_PACKET_ID->read()]._operation))
		store_queue_use [tab_request[out_MEMORY_OUT_PACKET_ID->read()]._store_queue_ptr_write] = false;
	      else
		load_queue_use  [tab_request[out_MEMORY_OUT_PACKET_ID->read()]._load_queue_ptr_write] = false;

	      nb_request_memory_out ++;
	    }

	  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())
	    {
	      LABEL(" * Accepted DCACHE_REQ : " + toString(static_cast<uint32_t>(out_DCACHE_REQ_PACKET_ID->read())));

	      // test type : send or not a respons !
	    }

	}
    }
  
  /********************************************************
   * 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_PACKET_ID            ;
  delete     in_MEMORY_IN_OPERATION            ;
  delete     in_MEMORY_IN_TYPE                 ;
  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_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_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_UNCACHED  ;
  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_CONTEXT_ID;
  delete [] out_BYPASS_MEMORY_NUM_REG   ;
  delete [] out_BYPASS_MEMORY_DATA      ;

#endif

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