#ifndef _ENDIANNESS_H
#define _ENDIANNESS_H
//=====[ endianness ]==========================================================

/* 
 * file              : endianness.h
 * date (yyyy/mm/dd) : 2006/05/02
 * authors           : Rosiere Mathieu
 */

#include <byteswap.h>

#define LittleEndian false
#define BigEndian    true

union TestEndian 
{
  unsigned long total;
  struct 
  {
    unsigned char octet1;
    unsigned char octet2;
    unsigned char octet3;
    unsigned char octet4;
  } octets;
};

//-----[ hostEndianness ]------------------------------------------------------
/*
 * false : LitteEndian
 * true  : BigEndian
 */
inline bool hostEndianness()
{
  union TestEndian test_endian;
  test_endian.total = 0xFF;
  
  return (test_endian.octets.octet1 == 0xFF)?LittleEndian:BigEndian;
}

//-----[ cpuEndianness ]-------------------------------------------------------
/*
 * false : LitteEndian
 * true  : BigEndian
 */
inline bool cpuEndianness(unsigned int cpu_id)
{
  return(BigEndian);

  /*
   * Comment connaitre l'endianness ?
   * static    : table generee dans le top level
   * dynamique : table generee par un l'equivalent de hostEndianness et ecrivant dans un segment precis de la ram
   */
}

//-----[ isSameEndianness ]----------------------------------------------------

/*
 * The host machine and the simulate processeur have the same endianness
 */
inline bool isSameEndianness(unsigned int cpu_id)
{
  return ((hostEndianness() ^ cpuEndianness(cpu_id)) == false);
}

//-----[ swapBytes ]-----------------------------------------------------------
/*
 * swapBytes -> change the endiannes
 * exemple for 16 and size_access = 4, [0123456789abcdef] -> [32107654ba98fedc]
 */
inline char * swapBytes (char * string_src , unsigned int size_string, unsigned int size_access)
{
  char string_tmp [size_string];

  if (size_access == 1)
    return string_src;

  if (size_string % size_access != 0)
    {
      cerr << "<swapBytes> : Size of string must be a multiple of size_access." << endl;
      exit(1);
    }

  // size_access :
  // 1 -> bytes
  // 2 -> half
  // 4 -> word
  // 8 -> doubleword

  memcpy (string_tmp,string_src,size_string);

  // Loop to reorganize the string
  for (unsigned int it_size_string = 0 ; it_size_string < size_string; it_size_string += size_access)
    {
      // Permutation
//       for (unsigned int it_size_access = 0 ; it_size_access < size_access; it_size_access ++)
// 	string_src [it_size_string+it_size_access] = string_tmp [it_size_string + (size_access-1) - it_size_access];
      switch (size_access)
	{
	case 2  : 
	  {
	    string_src[it_size_string+0] = string_tmp[it_size_string+1];
	    string_src[it_size_string+1] = string_tmp[it_size_string+0];
	    break;
	  }
	case 4  :
	  {
	    string_src[it_size_string+0] = string_tmp[it_size_string+3];
	    string_src[it_size_string+1] = string_tmp[it_size_string+2];
	    string_src[it_size_string+2] = string_tmp[it_size_string+1];
	    string_src[it_size_string+3] = string_tmp[it_size_string+0];
	    break;
	  }
	case 8  :
	  {
	    string_src[it_size_string+0] = string_tmp[it_size_string+7];
	    string_src[it_size_string+1] = string_tmp[it_size_string+6];
	    string_src[it_size_string+2] = string_tmp[it_size_string+5];
	    string_src[it_size_string+3] = string_tmp[it_size_string+4];
	    string_src[it_size_string+4] = string_tmp[it_size_string+3];
	    string_src[it_size_string+5] = string_tmp[it_size_string+2];
	    string_src[it_size_string+6] = string_tmp[it_size_string+1];
	    string_src[it_size_string+7] = string_tmp[it_size_string+0];
	    break;
	  }
	default :  
	  {
	    cerr << "<swapBytes> : Illegal size of access (size_access = " << size_access << ")" << endl;
	    exit(1);
	    break;
	  }
	}//end switch(size_access)
    }//end it_size_string
  

//   cout << "size_access : " << size_access << endl;
//   cout << "size_string : " << size_string << endl;

//   for (unsigned int it_size_string = 0 ; it_size_string < size_string; it_size_string ++)
//     printf("%.2x",(unsigned int)string_src[it_size_string]);
//   printf("\n");

//   // Loop to reorganize the string
//   for (unsigned int it_size_string = 0 ; it_size_string < size_string; it_size_string += size_access)
//     {
//       switch (size_access)
// 	{
// 	case 2  : string_src[it_size_string] = bswap_16((unsigned short)   string_src[it_size_string]); break;
// 	case 4  : string_src[it_size_string] = bswap_32((unsigned int  )   string_src[it_size_string]); break;
// 	case 8  : string_src[it_size_string] = bswap_64((unsigned long int)string_src[it_size_string]); break;
// 	default :  
// 	  {
// 	    cerr << "<swapBytes> : Illegal size of access (size_access = " << size_access << ")" << endl;
// 	    exit(1);
// 	    break;
// 	  }
// 	}//end switch(size_access)

//   for (unsigned int it_size_string = 0 ; it_size_string < size_string; it_size_string ++)
//     printf("%.2x",(unsigned int)string_src[it_size_string]);
//   printf("\n");

  return string_src;
}
#endif //_ENDIANNESS_H
