/gme/blargg_endian.h

http://game-music-emu.googlecode.com/ · C Header · 184 lines · 149 code · 26 blank · 9 comment · 25 complexity · fe47377c85c78dc96b2fc18b7393ff02 MD5 · raw file

  1. // CPU Byte Order Utilities
  2. #ifndef BLARGG_ENDIAN
  3. #define BLARGG_ENDIAN
  4. #include "blargg_common.h"
  5. // BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16)
  6. #if defined (__i386__) || defined (__x86_64__) || defined (_M_IX86) || defined (_M_X64)
  7. #define BLARGG_CPU_X86 1
  8. #define BLARGG_CPU_CISC 1
  9. #endif
  10. #if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__) || \
  11. defined (__POWERPC__) || defined (__powerc)
  12. #define BLARGG_CPU_POWERPC 1
  13. #define BLARGG_CPU_RISC 1
  14. #endif
  15. // BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only
  16. // one may be #defined to 1. Only needed if something actually depends on byte order.
  17. #if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN)
  18. #ifdef __GLIBC__
  19. // GCC handles this for us
  20. #include <endian.h>
  21. #if __BYTE_ORDER == __LITTLE_ENDIAN
  22. #define BLARGG_LITTLE_ENDIAN 1
  23. #elif __BYTE_ORDER == __BIG_ENDIAN
  24. #define BLARGG_BIG_ENDIAN 1
  25. #endif
  26. #else
  27. #if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \
  28. (defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234)
  29. #define BLARGG_LITTLE_ENDIAN 1
  30. #endif
  31. #if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \
  32. defined (__sparc__) || BLARGG_CPU_POWERPC || \
  33. (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321)
  34. #define BLARGG_BIG_ENDIAN 1
  35. #elif !defined (__mips__)
  36. // No endian specified; assume little-endian, since it's most common
  37. #define BLARGG_LITTLE_ENDIAN 1
  38. #endif
  39. #endif
  40. #endif
  41. #if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN
  42. #undef BLARGG_LITTLE_ENDIAN
  43. #undef BLARGG_BIG_ENDIAN
  44. #endif
  45. inline void blargg_verify_byte_order()
  46. {
  47. #ifndef NDEBUG
  48. #if BLARGG_BIG_ENDIAN
  49. volatile int i = 1;
  50. assert( *(volatile char*) &i == 0 );
  51. #elif BLARGG_LITTLE_ENDIAN
  52. volatile int i = 1;
  53. assert( *(volatile char*) &i != 0 );
  54. #endif
  55. #endif
  56. }
  57. inline unsigned get_le16( void const* p )
  58. {
  59. return (unsigned) ((unsigned char const*) p) [1] << 8 |
  60. (unsigned) ((unsigned char const*) p) [0];
  61. }
  62. inline unsigned get_be16( void const* p )
  63. {
  64. return (unsigned) ((unsigned char const*) p) [0] << 8 |
  65. (unsigned) ((unsigned char const*) p) [1];
  66. }
  67. inline blargg_ulong get_le32( void const* p )
  68. {
  69. return (blargg_ulong) ((unsigned char const*) p) [3] << 24 |
  70. (blargg_ulong) ((unsigned char const*) p) [2] << 16 |
  71. (blargg_ulong) ((unsigned char const*) p) [1] << 8 |
  72. (blargg_ulong) ((unsigned char const*) p) [0];
  73. }
  74. inline blargg_ulong get_be32( void const* p )
  75. {
  76. return (blargg_ulong) ((unsigned char const*) p) [0] << 24 |
  77. (blargg_ulong) ((unsigned char const*) p) [1] << 16 |
  78. (blargg_ulong) ((unsigned char const*) p) [2] << 8 |
  79. (blargg_ulong) ((unsigned char const*) p) [3];
  80. }
  81. inline void set_le16( void* p, unsigned n )
  82. {
  83. ((unsigned char*) p) [1] = (unsigned char) (n >> 8);
  84. ((unsigned char*) p) [0] = (unsigned char) n;
  85. }
  86. inline void set_be16( void* p, unsigned n )
  87. {
  88. ((unsigned char*) p) [0] = (unsigned char) (n >> 8);
  89. ((unsigned char*) p) [1] = (unsigned char) n;
  90. }
  91. inline void set_le32( void* p, blargg_ulong n )
  92. {
  93. ((unsigned char*) p) [0] = (unsigned char) n;
  94. ((unsigned char*) p) [1] = (unsigned char) (n >> 8);
  95. ((unsigned char*) p) [2] = (unsigned char) (n >> 16);
  96. ((unsigned char*) p) [3] = (unsigned char) (n >> 24);
  97. }
  98. inline void set_be32( void* p, blargg_ulong n )
  99. {
  100. ((unsigned char*) p) [3] = (unsigned char) n;
  101. ((unsigned char*) p) [2] = (unsigned char) (n >> 8);
  102. ((unsigned char*) p) [1] = (unsigned char) (n >> 16);
  103. ((unsigned char*) p) [0] = (unsigned char) (n >> 24);
  104. }
  105. #if BLARGG_NONPORTABLE
  106. // Optimized implementation if byte order is known
  107. #if BLARGG_LITTLE_ENDIAN
  108. #define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr))
  109. #define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr))
  110. #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
  111. #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
  112. #elif BLARGG_BIG_ENDIAN
  113. #define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr))
  114. #define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr))
  115. #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
  116. #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
  117. #if BLARGG_CPU_POWERPC
  118. // PowerPC has special byte-reversed instructions
  119. #if defined (__MWERKS__)
  120. #define GET_LE16( addr ) (__lhbrx( addr, 0 ))
  121. #define GET_LE32( addr ) (__lwbrx( addr, 0 ))
  122. #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 ))
  123. #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 ))
  124. #elif defined (__GNUC__)
  125. #define GET_LE16( addr ) ({unsigned short ppc_lhbrx_; __asm__ volatile( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr) : "memory" ); ppc_lhbrx_;})
  126. #define GET_LE32( addr ) ({unsigned short ppc_lwbrx_; __asm__ volatile( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr) : "memory" ); ppc_lwbrx_;})
  127. #define SET_LE16( addr, in ) ({__asm__ volatile( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) : "memory" );})
  128. #define SET_LE32( addr, in ) ({__asm__ volatile( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) : "memory" );})
  129. #endif
  130. #endif
  131. #endif
  132. #endif
  133. #ifndef GET_LE16
  134. #define GET_LE16( addr ) get_le16( addr )
  135. #define SET_LE16( addr, data ) set_le16( addr, data )
  136. #endif
  137. #ifndef GET_LE32
  138. #define GET_LE32( addr ) get_le32( addr )
  139. #define SET_LE32( addr, data ) set_le32( addr, data )
  140. #endif
  141. #ifndef GET_BE16
  142. #define GET_BE16( addr ) get_be16( addr )
  143. #define SET_BE16( addr, data ) set_be16( addr, data )
  144. #endif
  145. #ifndef GET_BE32
  146. #define GET_BE32( addr ) get_be32( addr )
  147. #define SET_BE32( addr, data ) set_be32( addr, data )
  148. #endif
  149. // auto-selecting versions
  150. inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); }
  151. inline void set_le( BOOST::uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); }
  152. inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); }
  153. inline void set_be( BOOST::uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); }
  154. inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); }
  155. inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); }
  156. inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); }
  157. inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); }
  158. #endif