rlm@0: // CPU Byte Order Utilities rlm@0: rlm@0: // snes_spc 0.9.0 rlm@0: #ifndef BLARGG_ENDIAN rlm@0: #define BLARGG_ENDIAN rlm@0: rlm@0: #include "blargg_common.h" rlm@0: rlm@0: // BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16) rlm@0: #if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ rlm@0: defined (__x86_64__) || defined (__ia64__) || defined (__i386__) rlm@0: #define BLARGG_CPU_X86 1 rlm@0: #define BLARGG_CPU_CISC 1 rlm@0: #endif rlm@0: rlm@0: #if defined (__powerpc__) || defined (__ppc__) || defined (__POWERPC__) || defined (__powerc) rlm@0: #define BLARGG_CPU_POWERPC 1 rlm@0: #define BLARGG_CPU_RISC 1 rlm@0: #endif rlm@0: rlm@0: // BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only rlm@0: // one may be #defined to 1. Only needed if something actually depends on byte order. rlm@0: #if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN) rlm@0: #ifdef __GLIBC__ rlm@0: // GCC handles this for us rlm@0: #include rlm@0: #if __BYTE_ORDER == __LITTLE_ENDIAN rlm@0: #define BLARGG_LITTLE_ENDIAN 1 rlm@0: #elif __BYTE_ORDER == __BIG_ENDIAN rlm@0: #define BLARGG_BIG_ENDIAN 1 rlm@0: #endif rlm@0: #else rlm@0: rlm@0: #if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \ rlm@0: (defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234) rlm@0: #define BLARGG_LITTLE_ENDIAN 1 rlm@0: #endif rlm@0: rlm@0: #if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \ rlm@0: defined (__sparc__) || BLARGG_CPU_POWERPC || \ rlm@0: (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321) rlm@0: #define BLARGG_BIG_ENDIAN 1 rlm@0: #elif !defined (__mips__) rlm@0: // No endian specified; assume little-endian, since it's most common rlm@0: #define BLARGG_LITTLE_ENDIAN 1 rlm@0: #endif rlm@0: #endif rlm@0: #endif rlm@0: rlm@0: #if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN rlm@0: #undef BLARGG_LITTLE_ENDIAN rlm@0: #undef BLARGG_BIG_ENDIAN rlm@0: #endif rlm@0: rlm@0: inline void blargg_verify_byte_order() rlm@0: { rlm@0: #ifndef NDEBUG rlm@0: #if BLARGG_BIG_ENDIAN rlm@0: volatile int i = 1; rlm@0: assert( *(volatile char*) &i == 0 ); rlm@0: #elif BLARGG_LITTLE_ENDIAN rlm@0: volatile int i = 1; rlm@0: assert( *(volatile char*) &i != 0 ); rlm@0: #endif rlm@0: #endif rlm@0: } rlm@0: rlm@0: inline unsigned get_le16( void const* p ) rlm@0: { rlm@0: return (unsigned) ((unsigned char const*) p) [1] << 8 | rlm@0: (unsigned) ((unsigned char const*) p) [0]; rlm@0: } rlm@0: rlm@0: inline unsigned get_be16( void const* p ) rlm@0: { rlm@0: return (unsigned) ((unsigned char const*) p) [0] << 8 | rlm@0: (unsigned) ((unsigned char const*) p) [1]; rlm@0: } rlm@0: rlm@0: inline blargg_ulong get_le32( void const* p ) rlm@0: { rlm@0: return (blargg_ulong) ((unsigned char const*) p) [3] << 24 | rlm@0: (blargg_ulong) ((unsigned char const*) p) [2] << 16 | rlm@0: (blargg_ulong) ((unsigned char const*) p) [1] << 8 | rlm@0: (blargg_ulong) ((unsigned char const*) p) [0]; rlm@0: } rlm@0: rlm@0: inline blargg_ulong get_be32( void const* p ) rlm@0: { rlm@0: return (blargg_ulong) ((unsigned char const*) p) [0] << 24 | rlm@0: (blargg_ulong) ((unsigned char const*) p) [1] << 16 | rlm@0: (blargg_ulong) ((unsigned char const*) p) [2] << 8 | rlm@0: (blargg_ulong) ((unsigned char const*) p) [3]; rlm@0: } rlm@0: rlm@0: inline void set_le16( void* p, unsigned n ) rlm@0: { rlm@0: ((unsigned char*) p) [1] = (unsigned char) (n >> 8); rlm@0: ((unsigned char*) p) [0] = (unsigned char) n; rlm@0: } rlm@0: rlm@0: inline void set_be16( void* p, unsigned n ) rlm@0: { rlm@0: ((unsigned char*) p) [0] = (unsigned char) (n >> 8); rlm@0: ((unsigned char*) p) [1] = (unsigned char) n; rlm@0: } rlm@0: rlm@0: inline void set_le32( void* p, blargg_ulong n ) rlm@0: { rlm@0: ((unsigned char*) p) [0] = (unsigned char) n; rlm@0: ((unsigned char*) p) [1] = (unsigned char) (n >> 8); rlm@0: ((unsigned char*) p) [2] = (unsigned char) (n >> 16); rlm@0: ((unsigned char*) p) [3] = (unsigned char) (n >> 24); rlm@0: } rlm@0: rlm@0: inline void set_be32( void* p, blargg_ulong n ) rlm@0: { rlm@0: ((unsigned char*) p) [3] = (unsigned char) n; rlm@0: ((unsigned char*) p) [2] = (unsigned char) (n >> 8); rlm@0: ((unsigned char*) p) [1] = (unsigned char) (n >> 16); rlm@0: ((unsigned char*) p) [0] = (unsigned char) (n >> 24); rlm@0: } rlm@0: rlm@0: #if BLARGG_NONPORTABLE rlm@0: // Optimized implementation if byte order is known rlm@0: #if BLARGG_LITTLE_ENDIAN rlm@0: #define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr)) rlm@0: #define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr)) rlm@0: #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) rlm@0: #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) rlm@0: #elif BLARGG_BIG_ENDIAN rlm@0: #define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr)) rlm@0: #define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr)) rlm@0: #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) rlm@0: #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) rlm@0: rlm@0: #if BLARGG_CPU_POWERPC rlm@0: // PowerPC has special byte-reversed instructions rlm@0: #if defined (__MWERKS__) rlm@0: #define GET_LE16( addr ) (__lhbrx( addr, 0 )) rlm@0: #define GET_LE32( addr ) (__lwbrx( addr, 0 )) rlm@0: #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 )) rlm@0: #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 )) rlm@0: #elif defined (__GNUC__) rlm@0: #define GET_LE16( addr ) ({unsigned ppc_lhbrx_; asm( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr), "0" (ppc_lhbrx_) ); ppc_lhbrx_;}) rlm@0: #define GET_LE32( addr ) ({unsigned ppc_lwbrx_; asm( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr), "0" (ppc_lwbrx_) ); ppc_lwbrx_;}) rlm@0: #define SET_LE16( addr, in ) ({asm( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) );}) rlm@0: #define SET_LE32( addr, in ) ({asm( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) );}) rlm@0: #endif rlm@0: #endif rlm@0: #endif rlm@0: #endif rlm@0: rlm@0: #ifndef GET_LE16 rlm@0: #define GET_LE16( addr ) get_le16( addr ) rlm@0: #define SET_LE16( addr, data ) set_le16( addr, data ) rlm@0: #endif rlm@0: rlm@0: #ifndef GET_LE32 rlm@0: #define GET_LE32( addr ) get_le32( addr ) rlm@0: #define SET_LE32( addr, data ) set_le32( addr, data ) rlm@0: #endif rlm@0: rlm@0: #ifndef GET_BE16 rlm@0: #define GET_BE16( addr ) get_be16( addr ) rlm@0: #define SET_BE16( addr, data ) set_be16( addr, data ) rlm@0: #endif rlm@0: rlm@0: #ifndef GET_BE32 rlm@0: #define GET_BE32( addr ) get_be32( addr ) rlm@0: #define SET_BE32( addr, data ) set_be32( addr, data ) rlm@0: #endif rlm@0: rlm@0: // auto-selecting versions rlm@0: rlm@0: inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); } rlm@0: inline void set_le( BOOST::uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); } rlm@0: inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); } rlm@0: inline void set_be( BOOST::uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); } rlm@0: inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); } rlm@0: inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); } rlm@0: inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); } rlm@0: inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); } rlm@0: rlm@0: #endif