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