#include "../include/Environment.h"

using namespace morpheo;

namespace environment {

  void Environment::transition (void)
  {
    if (NRESET->read() == 0)
      {
	reset ();
      }
    else
      {
	//=============================================================================
	//===== [ ICACHE - RESPONS ]===================================================
	//=============================================================================
	for (uint32_t i = 0; i < param->nb_entity; i++)
	  for (int32_t j=param->icache_dedicated_nb_port [i]-1; j>=0; j--)
	    if (icache_rsp_val [i][j] and ICACHE_RSP_ACK [i][j]->read())
	      {
		delete component_buffer_irsp [i]->read(j)._data;
		component_buffer_irsp [i]->pop(j);
	      }
	//=============================================================================
	//===== [ DCACHE - RESPONS ]===================================================
	//=============================================================================
	for (uint32_t i = 0; i < param->nb_entity; i++)
	  for (int32_t j=param->dcache_dedicated_nb_port [i]-1; j>=0; j--)
	    if (dcache_rsp_val [i][j] and DCACHE_RSP_ACK [i][j]->read())
	      {
		delete component_buffer_drsp [i]->read(j)._data;
		component_buffer_drsp [i]->pop(j);
	      }

	//=============================================================================
	//===== [ ICACHE - RESPONS ]===================================================
	//=============================================================================
	for (uint32_t i=0; i<param->nb_entity; i++)
	  for (uint32_t j=0; j <param->icache_dedicated_nb_port [i]; j++)
	    if (ICACHE_REQ_VAL [i][j]->read() and icache_req_ack [i][j])
	      {
		_cout(ENVIRONMENT, "ICACHE_REQ [%d] : Transaction accepted\n",i);

		Ticache_context_t context   = ICACHE_REQ_CONTEXT_ID [i][j]->read();// TODO : test presence
		Ticache_packet_t  packet    = ICACHE_REQ_PACKET_ID  [i][j]->read();// TODO : test presence
		Ticache_address_t address   = ICACHE_REQ_ADDRESS    [i][j]->read()<<2;
		Ticache_type_t    type      = ICACHE_REQ_TYPE       [i][j]->read();
		uint32_t          size      = (param->iaccess_size_address [i]+2)/8;

		_cout(ENVIRONMENT," * information\n");
		_cout(ENVIRONMENT,"   * context : %d\n" ,static_cast<uint32_t>(context));
		_cout(ENVIRONMENT,"   * packet  : %d\n" ,static_cast<uint32_t>(packet ));
		_cout(ENVIRONMENT,"   * address : %.x\n",static_cast<uint32_t>(address));
		_cout(ENVIRONMENT,"   * type    : %d\n" ,static_cast<uint32_t>(type   ));
		_cout(ENVIRONMENT,"   * size    : %d\n" ,static_cast<uint32_t>(size   ));

		// search the entity
		data::Entity      entity    = component_data->entity(static_cast<uint32_t>(address),size);
		
		bool              uncached ;
		bool              bus_error;
		bool              must_read         = (type == ICACHE_TYPE_LOAD);
		bool              must_ack          = (type == ICACHE_TYPE_LOAD);
		bool              must_ack_on_error = (type == ICACHE_TYPE_LOAD);

		// Test the type of the address : if != MEMORY -> error
		if ((entity.present == true) and 
		    (entity.segment->getType() == data::TYPE_TARGET_MEMORY))
		  {
		    _cout(ENVIRONMENT," * OK !\n");
		    bus_error = false;
		    uncached  = entity.segment->getUncached();
		    
		    if (must_read == true) // Test if must read the ram
		      {
			_cout(ENVIRONMENT,"   * must read\n");
			// Read all instruction
			for (unsigned int k=0; k<param->iaccess_nb_instruction[i]; k++)
			  {
			    uint32_t addr = address+k*(size);
                            _cout(ENVIRONMENT,"   * addr    : %.8x\n",addr);

			    bus_error |= !component_data->read(addr,size,read_iram[k]);

			    // Swap if endienness is different
			    if (endianness::isSameEndianness(context) == false) 
                              {
                                read_iram[k] = endianness::swapBytes(read_iram[k],size,size);
                              }

                            _cout(ENVIRONMENT,"   * inst    :");
                            for (int32_t cpt=(param->iaccess_size_instruction[context]/8)-1; cpt>=0; --cpt)
                              _cout(ENVIRONMENT, "%.2x",0xff&static_cast<uint32_t>(read_iram[k][cpt]));
                            _cout(ENVIRONMENT, "\n");
			  }
		      }
		  }
		else
		  {
		    _cout(ENVIRONMENT, " * KO !\n");
		    _cout(ENVIRONMENT, "   * present : %d\n",entity.present);
		    if (entity.present)
		    _cout(ENVIRONMENT, "   * type    : %d must be data::TYPE_TARGET_MEMORY (%d)\n",entity.segment->getType(), data::TYPE_TARGET_MEMORY);
		      
		    // entity is not present, or is present but is not a memory : have a bus error
		    bus_error = true;
		    uncached  = true;
		  }

		Cache_Access cache_type = ireq_type2cache_type (type,uncached);
		uint32_t latence = component_cache->latence(cache::INSTRUCTION_CACHE,
							    i,
							    j,
							    address,
							    context,
							    cache_type.type,
							    cache_type.direction);
		
		_cout(ENVIRONMENT, "   * latence : %d\n",latence);
		
		// If is a respons -> compute the latence and push in the write_buffer
		if (must_ack or (must_ack_on_error and bus_error))
		  {
		    _cout(ENVIRONMENT, " * must ack\n");
		    
		    if (bus_error == true)
		      {
			std::cout << "Icache : have a bus error" << std::endl
				  << "  * entity     : " << i << std::endl
				  << "  * port       : " << j << std::endl
				  << std::hex
				  << "  * req_addr   : " << address << std::endl
				  << std::dec
				  << "  * req_trdid  : " << context << std::endl
				  << "  * req_pktid  : " << packet  << std::endl;

			// Write in instruction [0] the bad address (only 32bit ....)
			itoa<Ticache_address_t>(address,read_iram[0],param->iaccess_size_instruction[i]/8);
		      }
			    
		    // Simplification : the size of a line is a multiple of size_iword (no test)
		    _cout(ENVIRONMENT, "   * push in buffer_irsp[%d]\n",i);

		    irsp_t * rsp = new irsp_t(context,
					      packet,
					      param->iaccess_nb_instruction[i],
					      size,
					      read_iram,
					      (bus_error==true)?ICACHE_ERROR_BUS_ERROR:ICACHE_ERROR_NONE);
		    component_buffer_irsp [i]->push(latence,rsp);
		  }

		_cout(ENVIRONMENT, " * End request\n");
	      }

	//=============================================================================
	//===== [ DCACHE - REQUEST ]===================================================
	//=============================================================================
	for (uint32_t i=0; i<param->nb_entity; i++)
	  for (uint32_t j=0; j <param->dcache_dedicated_nb_port [i]; j++)
	    if (DCACHE_REQ_VAL [i][j]->read() and dcache_req_ack [i][j])
	      {
		_cout(ENVIRONMENT, "DCACHE_REQ [%d] : Transaction accepted\n",i);

		Tdcache_context_t context   = DCACHE_REQ_CONTEXT_ID [i][j]->read();// TODO : test presence
		Tdcache_packet_t  packet    = DCACHE_REQ_PACKET_ID  [i][j]->read();// TODO : test presence
		Tdcache_address_t address   = DCACHE_REQ_ADDRESS    [i][j]->read();
		Tdcache_data_t    wdata     = DCACHE_REQ_WDATA      [i][j]->read();
		Tdcache_type_t    type      = DCACHE_REQ_TYPE       [i][j]->read();
		uint32_t          size      = param->daccess_size_data [i]/8;

// 		_cout(ENVIRONMENT," * information\n");
// 		_cout(ENVIRONMENT,"   * context : %d\n" ,static_cast<uint32_t>(context));
// 		_cout(ENVIRONMENT,"   * packet  : %d\n" ,static_cast<uint32_t>(packet ));
// 		_cout(ENVIRONMENT,"   * address : %.x\n",static_cast<uint32_t>(address));
// 		_cout(ENVIRONMENT,"   * type    : %d\n" ,static_cast<uint32_t>(type   ));
// 		_cout(ENVIRONMENT,"   * size    : %d\n" ,static_cast<uint32_t>(size   ));

		// search the entity
		data::Entity      entity    = component_data->entity(static_cast<uint32_t>(address),size);

		std::cout << entity << std::endl;

		bool              uncached  = false;
		bool              bus_error = false;

		uint32_t          nb_bytes  = size;
		bool              must_read ;
		bool              must_write;
		bool              must_ack  ;
		bool              must_ack_on_error;
		
		switch (type)
		  {
		  case DCACHE_TYPE_LOAD_8          :{nb_bytes=1; must_read=true ; must_write=false; must_ack=true ; must_ack_on_error=true ; break;}
		  case DCACHE_TYPE_LOAD_16         :{nb_bytes=2; must_read=true ; must_write=false; must_ack=true ; must_ack_on_error=true ; break;}
		  case DCACHE_TYPE_LOAD_32         :{nb_bytes=4; must_read=true ; must_write=false; must_ack=true ; must_ack_on_error=true ; break;}
		  case DCACHE_TYPE_LOAD_64         :{nb_bytes=8; must_read=true ; must_write=false; must_ack=true ; must_ack_on_error=true ; break;}
		  case DCACHE_TYPE_LOCK            :{            must_read=false; must_write=false; must_ack=false; must_ack_on_error=false; break;}
		  case DCACHE_TYPE_INVALIDATE      :{            must_read=false; must_write=false; must_ack=false; must_ack_on_error=false; break;}
		  case DCACHE_TYPE_PREFETCH        :{            must_read=false; must_write=false; must_ack=false; must_ack_on_error=false; break;}
		  case DCACHE_TYPE_FLUSH           :{            must_read=false; must_write=false; must_ack=false; must_ack_on_error=false; break;}
		  case DCACHE_TYPE_SYNCHRONIZATION :{            must_read=false; must_write=false; must_ack=true ; must_ack_on_error=false; break;}
		  case DCACHE_TYPE_STORE_8         :{nb_bytes=1; must_read=false; must_write=true ; must_ack=false; must_ack_on_error=true ; break;}
		  case DCACHE_TYPE_STORE_16        :{nb_bytes=2; must_read=false; must_write=true ; must_ack=false; must_ack_on_error=true ; break;}
		  case DCACHE_TYPE_STORE_32        :{nb_bytes=4; must_read=false; must_write=true ; must_ack=false; must_ack_on_error=true ; break;}
		  case DCACHE_TYPE_STORE_64        :{nb_bytes=8; must_read=false; must_write=true ; must_ack=false; must_ack_on_error=true ; break;}
		  default                          :{            must_read=false; must_write=false; must_ack=false; must_ack_on_error=false; break;} 
		  }
		
		// Test the type of the address
		if (entity.present == true)
		  {
		    switch (entity.segment->getType())
		      {
			//**************************************************************
			//*****[ TTY ]**************************************************
			//**************************************************************
		      case data::TYPE_TARGET_TTY     :
			{
			  // Can't read a tty, must write
			  if (must_write == false)
			    {
			      bus_error = true;
			      break;
			    }

			  uint32_t num_tty   = (address - entity.segment->getBase())>>4;
			  uint32_t num_print = ((address>>2) & 0x3);
			  _cout(ENVIRONMENT," * TYPE_TARGET_TTY : num_tty : %d, num_print : %d\n",num_tty, num_print);
			  
			  switch (num_print)
			    {
			    case 0 : // Write TTY
			      {
				uint32_t num_component_tty = entity.segment->getIndex();
				char     char_write        = static_cast<char>(wdata&0xff);
				bus_error |= !component_tty [num_component_tty]->write(num_tty,char_write);
				break;
			      }
			    case 1 : // STOP
			      {
				printf("\n\t***** [ stop    ] Time : %.10d - Address : %.8x - Wdata[31:0] : %.2x%.2x%.2x%.2x         *****\n"
				       ,static_cast<uint32_t>(sc_simulation_time())
				       ,static_cast<uint32_t>(address		  )
				       ,static_cast<uint32_t>((wdata>>24)&0xff)
				       ,static_cast<uint32_t>((wdata>>16)&0xff)
				       ,static_cast<uint32_t>((wdata>> 8)&0xff)
				       ,static_cast<uint32_t>((wdata>> 0)&0xff)
				       );

                                stop (context);
			    
				break;
			      }
			    case 2 : // PRINT
			      {
				printf("\n\t----- [ print   ] Time : %.10d - Address : %.8x - Wdata[31:0] : %.2x%.2x%.2x%.2x         -----\n"
				       ,static_cast<uint32_t>(sc_simulation_time())
				       ,static_cast<uint32_t>(address		  )
				       ,static_cast<uint32_t>((wdata>>24)&0xff)
				       ,static_cast<uint32_t>((wdata>>16)&0xff)
				       ,static_cast<uint32_t>((wdata>> 8)&0xff)
				       ,static_cast<uint32_t>((wdata>> 0)&0xff)
				       );
				
				break;
			      }
			    default :
			      {
				printf("[address : %.8x] tty %d, reg %d don't exist\n",static_cast<uint32_t>(address),num_tty,num_print);
				bus_error = true;
			      }
			    }
			  break;
			}

			//**************************************************************
			//*****[ MEMORY ]***********************************************
			//**************************************************************
		      case data::TYPE_TARGET_MEMORY  : 
			{
			  _cout(ENVIRONMENT,"MEMORY\n");
			  _cout(ENVIRONMENT,"access : %x\n",address);

			  if (must_read == true)
			    {
			      // Read
			      _cout(ENVIRONMENT," * Read  (%d bytes)\n",size);
			      bus_error |= !component_data->read(address,size,read_dram[0]); // always read a complete word

			      _cout(ENVIRONMENT," * Rdata : ");
			      for (uint32_t i=0; i<size; i++)
				_cout(ENVIRONMENT,"%.2x",0xff&static_cast<uint32_t>(read_dram[0][i]));
			      _cout(ENVIRONMENT,".\n");
			      
			      // Multiple copy
			      for (unsigned int it_size_data = nb_bytes; it_size_data < size; it_size_data+=nb_bytes)
				memcpy(&(read_dram[0][it_size_data]),&(read_dram[0][0]),nb_bytes);
			      
			      // Permutation if problem of endianness
			      if (endianness::isSameEndianness(context) == false) 
				read_dram[0] = endianness::swapBytes(read_dram[0] , size, nb_bytes);
			    }
			  
			  if (must_write == true)
			    {
			      // Write
			      _cout(ENVIRONMENT," * Write (%d bytes)\n",size);
			      _cout(ENVIRONMENT," * Wdata : %x\n",wdata);
			      itoa<Tdcache_data_t>(wdata,write_dram,nb_bytes);

// 			      for (unsigned int it_nb_bytes = 0; it_nb_bytes < size; it_nb_bytes ++)
// 				write_dram [it_nb_bytes] = wdata.range(8*(it_nb_bytes+1)-1,8*it_nb_bytes);
			    }

			  break;
			}
			//**************************************************************
			//*****[ RAMLOCK ]**********************************************
			//**************************************************************
		      case data::TYPE_TARGET_RAMLOCK :
			{
			  // Access is on a byte, else error
			  if (nb_bytes != 1)
			    {
			      bus_error = true;
			      break;
			    }

			  uint32_t num_ramlock           = (address - entity.segment->getBase()); // Char access
			  uint32_t num_component_ramlock = entity.segment->getIndex();

			  // No test : because out of range

// 			  bus_error |= !component_ramlock [num_component_ramlock]->test(num_ramlock);
			  
// 			  if (bus_error == true)
// 			    break;

			  memset (read_dram[0],0,size);
			  
			  if (must_read == true)
			    read_dram [0][0] = static_cast<char>(component_ramlock [num_component_ramlock]->read (num_ramlock));
			  if (must_write == true)
			    read_dram [0][0] = static_cast<char>(component_ramlock [num_component_ramlock]->write(num_ramlock));
			  
			  break;
			}

			//**************************************************************
			//*****[ SIM2OS ]***********************************************
			//**************************************************************
		      case data::TYPE_TARGET_SIM2OS  :
			{
			  // Mapping :
			  // [0]  number of service - Wonly - A write in this register lunch the execution of service
			  // [1]  result            - Ronly - Content the result of the service
			  // [2]  error             - Ronly - Content the code of errno
			  // [3+] argument          - Wonly - it's all argument to execute the service

			  uint32_t num_reg = (address - entity.segment->getBase())>>2;
			  
			  switch (num_reg)
			    {
			    case 0  : // ---> number of service
			      {
				if (must_write == false)
				  {
				    std::cerr << "<Environment::transition> SIM2OS[0] is not accessible in Read" << std::endl;
				    bus_error = true;
				  }
				else
				  {
				    _cout(ENVIRONMENT,"<sim2os> service     : %x\n",wdata);
				    component_sim2os->execute(sim2os::int2service(static_cast<uint32_t>(wdata)));
				  }
				break;
			      }
			    case 1  : // ---> result
			      { 
				if (must_read == false)
				  {
				    std::cerr << "<Environment::transition> SIM2OS[1] is not accessible in Write" << std::endl;
				    bus_error = true;
				  }
				else
				  {
				    // Decomposition en groupe octect
				    Tdcache_data_t result = static_cast<Tdcache_data_t>(reinterpret_cast<uint64_t>(component_sim2os->result));
				    _cout(ENVIRONMENT,"<sim2os> result      : %x\n",result);
				    
				    itoa<Tdcache_data_t>(result,read_dram[0],size);
				  }
				break;
			      }
			    case 2  : // ---> error
			      {
				if (must_read == false)
				  {
				    std::cerr << "<Environment::transition> SIM2OS[2] is not accessible in Write" << std::endl;
				    bus_error = true;
				  }
				else
				  {
				    // Decomposition en groupe octect
				    Tdcache_data_t error = (Tdcache_data_t)component_sim2os->error;
				    _cout(ENVIRONMENT,"<sim2os> error       : %x\n",error);
				    
				    itoa<Tdcache_data_t>(error,read_dram[0],size);
				  }
				
				break;
			      }
			    default : //---> argument
				{ 
				  if (must_write == false)
				    {
				      std::cerr << "<Environment::transition> SIM2OS[" << num_reg << "] is not accessible in Read" << std::endl;
				      bus_error = true;
				    }
				  else
				    {
				      _cout(ENVIRONMENT,"<sim2os> argument[%d] : %x\n",num_reg-1,wdata);
				      component_sim2os->parameter(num_reg-2,(void *)wdata);
				    }
				  break;
				}
			    }
			  
			  break;
			}
			
		      default :
			{
			  std::cerr << "<Environment::transition> Dcache_req : Unknow type" << std::endl;
			  exit(1);
			  break;
			}
		      }
		    uncached |= entity.segment->getUncached();
		  }
		else
		  {
		    // entity is not present, or is present but is not a memory : have a bus error
		    bus_error = true;
		    uncached  = true;
		  }

	      if ((must_write == true) and (bus_error == false))
		{
		  // Permutation if problem of endianness
		  if (endianness::isSameEndianness(context) == false) 
		    write_dram = endianness::swapBytes(write_dram, size, nb_bytes);

		  bus_error |= !component_data->write(address, nb_bytes, write_dram); // take the good access
		}

	      // Acces at the cache !!!
	      // Cache WRITE ALLOCATE (becauce compute latence always; )
	      Cache_Access cache_type = dreq_type2cache_type (type,uncached);
	      uint32_t latence = component_cache->latence(cache::DATA_CACHE,
							  i,
							  j,
							  address,
							  context,
							  cache_type.type,
							  cache_type.direction);
	      
	      // If is a respons -> compute the latence and push in the write_buffer
	      if (must_ack or (must_ack_on_error and bus_error))
		  {
		    if (bus_error == true)
		      {
			std::cout << "Dcache : have a bus error" << std::endl
				  << "  * entity     : " << i << std::endl
				  << "  * port       : " << j << std::endl
				  << std::hex
				  << "  * req_addr   : 0x" << address << std::endl
				  << std::dec
				  << "  * req_trdid  : " << context << std::endl
				  << "  * req_pktid  : " << packet  << std::endl;

			// Write in data [0] the bad address (32bit or 64bits    )
			itoa<Tdcache_data_t>(address,read_dram[0],param->daccess_size_data[i]/8);
		      }
		    
		    // Simplification : the size of a line is a multiple of size_iword (no test)
		    drsp_t * rsp = new drsp_t(context,
					      packet,
					      1,
					      size,
					      read_dram,
					      (bus_error==true)?DCACHE_ERROR_BUS_ERROR:DCACHE_ERROR_NONE);
		    component_buffer_drsp [i]->push(latence,rsp);
		  }
	      }
	//=============================================================================
	//===== [ OTHERS ]=============================================================
	//=============================================================================

	// Transition for each component
	component_cache -> transition();
	for (uint32_t i=0; i<param->nb_entity; i++)
	  {
	    component_buffer_irsp [i]->transition();
	    component_buffer_drsp [i]->transition();
	  }
	component_sim2os->transition();
      }
  }

// 	  // ******************
// 	  // ***** DCACHE *****
// 	  // ******************

// 	  for (uint32_t j = 0; j < nb_dport [i]; j ++)
// 	    {
// 	      // Test if transaction
// // 	      cout << "[" << i << "]"
// // 		   << "[" << j   << "] "
// // 		   << "dreq_val : " << DCACHE [i][j].REQ_VAL.read() << " "
// // 		   << "dreq_ack : " << dreq_ack [i][j] << endl;

// 	      if ( (DCACHE [i][j].REQ_VAL.read() && dreq_ack [i][j]) == false)
// 		continue;
	      
// 	      entity_t             entity         = component_data->entity((uint32_t)DCACHE [i][j].REQ_ADDR.read(), SIZE_DDATA/8);

// 	      bool                 uncached       = DCACHE [i][j].REQ_UNC.read();
// 	      bool                 bus_error      = false;
	      
// 	      uint32_t             addr           = (uint32_t) DCACHE [i][j].REQ_ADDR.read();
// 	      sc_uint<SIZE_DDATA>  wdata          = DCACHE[i][j].REQ_WDATA .read();
// 	      sc_uint<3>           type           = DCACHE[i][j].REQ_TYPE  .read();
// 	      uint32_t             nb_bytes       = access_nb_bytes(DCACHE[i][j].REQ_ACCESS.read());
// 	      // A lot of flag
// 	      bool                 must_read      = ((type == DTYPE_READ      ));
// 	      bool                 must_write     = ((type == DTYPE_WRITE     ) ||
// 						     (type == DTYPE_WRITE_ACK ) );
// 	      bool                 must_ack       = ((type == DTYPE_READ      ) ||
// 						     (type == DTYPE_WRITE_ACK ) );

// 	      // Test the type of the address
// 	      if (entity.present == true)
// 		{
// 		switch (entity.segment->getType())
// 		  {
// 		    // ACCESS AT A RAM
// 		  case data::TYPE_TARGET_MEMORY  : 
// 		    {
// 		      if (must_read == true)
// 			{
// 			  // Read
// 			  bus_error |= !component_data->read(addr         ,
// 							    SIZE_DDATA/8 , // always read a complete word
// 							    read_dram    );
			  
// 			  for (unsigned int it_size_data = nb_bytes; it_size_data < SIZE_DDATA/8; it_size_data+=nb_bytes)
// 			    memcpy(&(read_dram[it_size_data]),&(read_dram[0]),nb_bytes);

// 			  // Permutation if problem of endianness
// 			  if (isSameEndianness((uint32_t)DCACHE[i][j].REQ_TRDID.read()) == false) 
// 			    read_dram  = swapBytes(read_dram , SIZE_DDATA/8, nb_bytes);
// 			}
		      
// 		      if (must_write == true)
// 			{
// 			  // Write
// 			  for (unsigned int it_nb_bytes = 0; it_nb_bytes < SIZE_DDATA / 8; it_nb_bytes ++)
// 			    write_dram [it_nb_bytes] = wdata.range(8*(it_nb_bytes+1)-1,8*it_nb_bytes);
// 			}
// 		      break;
// 		    }
// 		    //ACCESS AT THE TTY
// 		  case TYPE_TTY     :
// 		    {
// 		      if (must_write == false)
// 			{
// 			  bus_error = true;
// 			  break;
// 			}
// 		      uint32_t num_tty           = (addr - entity.segment->getBase())>>4;
// 		      uint32_t num_print         = ((addr>>2) & 0x3);
		      
// 		      switch (num_print)
// 			{
// 			case 0 : // Write TTY
// 			  {
// 			    uint32_t num_component_tty = entity.segment->getIndex();
// 			    char     char_write        = (char)wdata.range( 7, 0);
// 			    bus_error |= !component_tty [num_component_tty]->write(num_tty,char_write);
// 			    break;
// 			  }
// 			case 1 : // STOP
// 			  {
// 			    printf("\n\t***** [ stop    ] Time : %.10d - Address : %.8x - Wdata[31:0] : %.2x%.2x%.2x%.2x         *****\n"
// 				   ,(unsigned int)sc_simulation_time()
// 				   ,(unsigned int)addr
// 				   ,(unsigned int)wdata.range(31,24)
// 				   ,(unsigned int)wdata.range(23,16)
// 				   ,(unsigned int)wdata.range(15, 8)
// 				   ,(unsigned int)wdata.range( 7, 0)
// 				   );

// 			    uint32_t trdid = (uint32_t) DCACHE[i][j].REQ_TRDID.read();
			    
// 			    if (context_stop [trdid] == false)
// 			      {
// 				context_stop [trdid] = true;
// 				nb_context_stop ++;

// 				if (nb_context_stop >= nb_context)
// 				  sc_stop();
// 			      }

// 			    break;
// 			  }
// 			case 2 : // PRINT
// 			  {
// 			    printf("\n\t----- [ print   ] Time : %.10d - Address : %.8x - Wdata[31:0] : %.2x%.2x%.2x%.2x         -----\n"
// 				   ,(unsigned int)sc_simulation_time()
// 				   ,(unsigned int)addr
// 				   ,(unsigned int)wdata.range(31,24)
// 				   ,(unsigned int)wdata.range(23,16)
// 				   ,(unsigned int)wdata.range(15, 8)
// 				   ,(unsigned int)wdata.range( 7, 0)
// 				   );
			    
// 			    break;
// 			  }
// 			default :
// 			  {
// 			    printf("<%s> : [address : %.8x] tty %d, reg %d don't exist\n",NAME,(unsigned int)addr,num_tty,num_print);
// 			    exit(1);
// 			  }
// 			}
		      
// 		      break;
// 		    }
// 		  case TYPE_RAMLOCK :
// 		    {
// 		      // Access is on a byte, else error
// 		      if (nb_bytes != 1)
// 			{
// 			  bus_error = true;
// 			  break;
// 			}
// 		      uint32_t num_ramlock           = (addr - entity.segment->getBase()); // Char access
// 		      uint32_t num_component_ramlock = entity.segment->getIndex();
// 		      bus_error |= !component_ramlock [num_component_ramlock]->test(num_ramlock);
		      
// 		      if (bus_error == true)
// 			break;
		      
// 		      memset (read_dram,0,SIZE_DDATA/8);
			
// 		      if (must_read == true)
// 			read_dram [0] = (char)component_ramlock [num_component_ramlock]->read (num_ramlock);
// 		      if (must_write == true)
// 			read_dram [0] = (char)component_ramlock [num_component_ramlock]->write(num_ramlock);

// 		      /*
// 		      printf("Access ramlock   ( %d )\n" ,(uint32_t)sc_simulation_time());
// 		      printf(" * addr          : %.8x\n" ,(uint32_t)addr);
// 		      printf(" * trdid         : %d\n"   ,(uint32_t)DCACHE[i][j].REQ_TRDID.read());
// 		      printf(" * r/w           : %d/%d\n",must_read,must_write);
// 		      printf(" * val           : %d\n"   ,(uint32_t)read_dram[0]);
// 		      */
// 		      break;
// 		    }
// 		  case TYPE_SIM2OS  :
// 		    {
// 		      // Mapping :
// 		      // [0]  number of service - Wonly - A write in this register lunch the execution of service
// 		      // [1]  result            - Ronly - Content the result of the service
// 		      // [2]  error             - Ronly - Content the code of errno
// 		      // [3+] argument          - Wonly - it's all argument to execute the service

// 		      uint32_t num_reg = (addr - entity.segment->getBase())>>2;
		      
// 		      switch (num_reg)
// 			{
// 			case 0  : // ---> number of service
// 			  {
// 			    if (must_write == false)
// 			      {
// 				cerr << "<" << NAME << "> {ERROR} : SIM2OS[0] is not accessible in Read" << endl;
// 				bus_error = true;
// 			      }
// 			    else
// 			      {
// 				printf("<sim2os> service     : %.8x\n",(uint32_t)wdata);
// 				component_sim2os->execute(int2service((uint32_t)wdata));
// 			      }
// 			  break;
// 			  }
// 			case 1  : // ---> result
// 			  { 
// 			    if (must_read == false)
// 			      {
// 				cerr << "<" << NAME << "> {ERROR} : SIM2OS[1] is not accessible in Write" << endl;
// 				bus_error = true;
// 			      }
// 			    else
// 			      {
// 				// Decomposition en groupe octect
// 				uint32_t result = (uint32_t) component_sim2os->result;
// 				printf("<sim2os> result      : %.8x (%d)\n",result,result);
				
// 				read_dram = itoa(result,read_dram,SIZE_DDATA/8);
// 			      }
// 			    break;
// 			  }
// 			case 2  : // ---> error
// 			  {
// 			    if (must_read == false)
// 			      {
// 				cerr << "<" << NAME << "> {ERROR} : SIM2OS[2] is not accessible in Write" << endl;
// 				bus_error = true;
// 			      }
// 			    else
// 			      {
// 				// Decomposition en groupe octect
// 				uint32_t error = (uint32_t) component_sim2os->error;
// 				printf("<sim2os> error       : %.8x\n",error);
// 				read_dram = itoa(error ,read_dram,SIZE_DDATA/8);
// 			      }
// 			    break;
// 			  }
// 			default : // ---> argument
// 			  { 
// 			    if (must_write == false)
// 			      {
// 				cerr << "<" << NAME << "> {ERROR} : SIM2OS[" << num_reg << "] is not accessible in Write" << endl;
// 				bus_error = true;
// 			      }
// 			    else
// 			      {
// 				uint32_t data = (uint32_t)wdata;
// 				printf("<sim2os> argument[%d] : %.8x\n",num_reg-1,data);
// 				component_sim2os->parameter(num_reg-2,(void *)data);
// 			      }
// 			    break;
// 			  }
// 			}//end switch num_reg
		      
// 		      break;
// 		    }
// 		  default           :
// 		    {
// 		      // Have a bus error
// 		      bus_error = true;
// 		      break;
// 		    }
// 		  }// switch
// 		uncached |= entity.segment->getUncached();
// 		}
// 	      else
// 		uncached = true; // If segment don't exist : it's the system bus that determine if the segment exist


// 	      if ((must_write == true) && (bus_error == false))
// 		{
// 		  // Permutation if problem of endianness
// 		  if (isSameEndianness((uint32_t)DCACHE[i][j].REQ_TRDID.read()) == false) 
// 		    write_dram = swapBytes(write_dram, SIZE_DDATA/8, nb_bytes);
		  
// 		  bus_error |= !component_data->write(addr                   ,
// 						     nb_bytes, // take the good access
// 						     write_dram             );
// 		}
	      

// 	      // Acces at the cache !!!
// 	      Cache_Access cache_type = dreq_type2cache_type (type, uncached);
	      
// 	      uint32_t latence = component_cache->latence(DATA_CACHE                                               ,
// 							  i                                               ,
// 							  j                                                 ,
// 							  (uint32_t)DCACHE [i][j].REQ_ADDR .read() ,
// 							  (uint32_t)DCACHE [i][j].REQ_TRDID.read() ,
// 							  cache_type.type                                          ,
// 							  cache_type.direction                                     );
	      
// 	      // If is a respons -> compute the latence and push in the write_buffer
// 	      if ( must_ack == true)
// 		{
// 		  if (bus_error == true)
// 		    cout << "Dcache : have a bus error" << endl;
// 		  component_buffer_drsp [i]->push(latence,
// 							   Entry((uint32_t)DCACHE [i][j].REQ_TRDID.read() ,
// 								 (uint32_t)DCACHE [i][j].REQ_PKTID.read() ,
// 								 1                                                        ,
// 								 SIZE_DDATA/8                                             ,
// 								 &read_dram                                               ,
// 								 (bus_error==true)?ERR_BUS:ERR_NO                         )
// 							   );			
// 		}
// 	    }// dnb_port
// 	}//i
      

};
