diff options
Diffstat (limited to 'common/endian.h')
-rw-r--r-- | common/endian.h | 219 |
1 files changed, 210 insertions, 9 deletions
diff --git a/common/endian.h b/common/endian.h index 6d6563f802..7278265961 100644 --- a/common/endian.h +++ b/common/endian.h @@ -49,6 +49,18 @@ # error No endianness defined #endif +#ifdef HAVE_INT64 +#define SWAP_CONSTANT_64(a) \ + ((uint64)((((a) >> 56) & 0x000000FF) | \ + (((a) >> 40) & 0x0000FF00) | \ + (((a) >> 24) & 0x00FF0000) | \ + (((a) >> 8) & 0xFF000000) | \ + (((a) & 0xFF000000) << 8) | \ + (((a) & 0x00FF0000) << 24) | \ + (((a) & 0x0000FF00) << 40) | \ + (((a) & 0x000000FF) << 56) )) +#endif + #define SWAP_CONSTANT_32(a) \ ((uint32)((((a) >> 24) & 0x00FF) | \ (((a) >> 8) & 0xFF00) | \ @@ -59,6 +71,36 @@ ((uint16)((((a) >> 8) & 0x00FF) | \ (((a) << 8) & 0xFF00) )) + + +/** + * Swap the bytes in a 16 bit word in order to convert LE encoded data to BE + * and vice versa. + */ + +// compilerspecific variants come first, fallback last + +// Test for GCC and if the target has the MIPS rel.2 instructions (we know the psp does) +#if defined(__GNUC__) && (defined(__psp__) || defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)) + + FORCEINLINE uint16 SWAP_BYTES_16(const uint16 a) { + if (__builtin_constant_p(a)) { + return SWAP_CONSTANT_16(a); + } else { + uint16 result; + __asm__ ("wsbh %0,%1" : "=r" (result) : "r" (a)); + return result; + } + } +#else + + inline uint16 SWAP_BYTES_16(const uint16 a) { + return (a >> 8) | (a << 8); + } +#endif + + + /** * Swap the bytes in a 32 bit word in order to convert LE encoded data to BE * and vice versa. @@ -108,32 +150,60 @@ } #endif +#ifdef HAVE_INT64 /** - * Swap the bytes in a 16 bit word in order to convert LE encoded data to BE + * Swap the bytes in a 64 bit word in order to convert LE encoded data to BE * and vice versa. */ -// compilerspecific variants come first, fallback last +// machine/compiler-specific variants come first, fallback last // Test for GCC and if the target has the MIPS rel.2 instructions (we know the psp does) +// #if defined(__GNUC__) && (defined(__psp__) || defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)) - FORCEINLINE uint16 SWAP_BYTES_16(const uint16 a) { + FORCEINLINE uint64 SWAP_BYTES_64(const uint64 a) { if (__builtin_constant_p(a)) { - return SWAP_CONSTANT_16(a); + return SWAP_CONSTANT_64(a); } else { - uint16 result; - __asm__ ("wsbh %0,%1" : "=r" (result) : "r" (a)); - return result; + uint32 low = (uint32)a, high = (uint32)(a >> 32); + low = SWAP_BYTES_32(low); + high = SWAP_BYTES_32(high); + + return (((uint64)low) << 32) | high; } } + +// Test for GCC >= 4.3.0 as this version added the bswap builtin +#elif GCC_ATLEAST(4, 3) + + FORCEINLINE uint64 SWAP_BYTES_64(uint64 a) { + return __builtin_bswap64(a); + } + +#elif defined(_MSC_VER) + + FORCEINLINE uint64 SWAP_BYTES_64(uint64 a) { + return _byteswap_uint64(a); + } + +// generic fallback #else - inline uint16 SWAP_BYTES_16(const uint16 a) { - return (a >> 8) | (a << 8); + inline uint64 SWAP_BYTES_64(uint64 a) { + uint32 low = (uint32)a, high = (uint32)(a >> 32); + uint16 lowLow = (uint16)low, lowHigh = (uint16)(low >> 16), + highLow = (uint16)high, highHigh = (uint16)(high >> 16); + + return ((uint64)(((uint32)(uint16)((lowLow >> 8) | (lowLow << 8)) << 16) | + (uint16)((lowHigh >> 8) | (lowHigh << 8))) << 32) | + (((uint32)(uint16)((highLow >> 8) | (highLow << 8)) << 16) | + (uint16)((highHigh >> 8) | (highHigh << 8))); } #endif +#endif // HAVE_INT64 + /** * A wrapper macro used around four character constants, like 'DATA', to @@ -183,6 +253,18 @@ ((Unaligned32 *)ptr)->val = value; } +#ifdef HAVE_INT64 + FORCEINLINE uint64 READ_UINT64(const void *ptr) { + struct Unaligned64 { uint64 val; } __attribute__ ((__packed__, __may_alias__)); + return ((const Unaligned64 *)ptr)->val; + } + + FORCEINLINE void WRITE_UINT64(void *ptr, uint64 value) { + struct Unaligned64 { uint64 val; } __attribute__((__packed__, __may_alias__)); + ((Unaligned64 *)ptr)->val = value; + } +#endif + #elif !defined(SCUMM_NEED_ALIGNMENT) FORCEINLINE uint16 READ_UINT16(const void *ptr) { @@ -201,6 +283,16 @@ *(uint32 *)(ptr) = value; } +#ifdef HAVE_INT64 + FORCEINLINE uint64 READ_UINT64(const void *ptr) { + return *(const uint64 *)(ptr); + } + + FORCEINLINE void WRITE_UINT64(void *ptr, uint64 value) { + *(uint64 *)(ptr) = value; + } +#endif + // use software fallback by loading each byte explicitely #else @@ -227,6 +319,23 @@ b[2] = (uint8)(value >> 16); b[3] = (uint8)(value >> 24); } +#ifdef HAVE_INT64 + inline uint64 READ_UINT64(const void *ptr) { + const uint8 *b = (const uint8 *)ptr; + return ((uint64)b[7] << 56) | ((uint64)b[6] << 48) | ((uint64)b[5] << 40) | ((uint64)b[4] << 32) | ((uint64)b[3] << 24) | ((uint64)b[2] << 16) | ((uint64)b[1] << 8) | ((uint64)b[0]); + } + inline void WRITE_UINT64(void *ptr, uint64 value) { + uint8 *b = (uint8 *)ptr; + b[0] = (uint8)(value >> 0); + b[1] = (uint8)(value >> 8); + b[2] = (uint8)(value >> 16); + b[3] = (uint8)(value >> 24); + b[4] = (uint8)(value >> 32); + b[5] = (uint8)(value >> 40); + b[6] = (uint8)(value >> 48); + b[7] = (uint8)(value >> 56); + } +#endif # elif defined(SCUMM_BIG_ENDIAN) @@ -250,6 +359,23 @@ b[2] = (uint8)(value >> 8); b[3] = (uint8)(value >> 0); } +#ifdef HAVE_INT64 + inline uint64 READ_UINT64(const void *ptr) { + const uint8 *b = (const uint8 *)ptr; + return ((uint64)b[0] << 56) | ((uint64)b[1] << 48) | ((uint64)b[2] << 40) | ((uint64)b[3] << 32) | ((uint64)b[4] << 24) | ((uint64)b[5] << 16) | ((uint64)b[6] << 8) | ((uint64)b[7]); + } + inline void WRITE_UINT64(void *ptr, uint64 value) { + uint8 *b = (uint8 *)ptr; + b[0] = (uint8)(value >> 56); + b[1] = (uint8)(value >> 48); + b[2] = (uint8)(value >> 40); + b[3] = (uint8)(value >> 32); + b[4] = (uint8)(value >> 24); + b[5] = (uint8)(value >> 16); + b[6] = (uint8)(value >> 8); + b[7] = (uint8)(value >> 0); + } +#endif # endif @@ -283,6 +409,17 @@ #define CONSTANT_BE_32(a) SWAP_CONSTANT_32(a) #define CONSTANT_BE_16(a) SWAP_CONSTANT_16(a) +#ifdef HAVE_INT64 + #define READ_LE_UINT64(a) READ_UINT64(a) + #define WRITE_LE_UINT64(a, v) WRITE_UINT64(a, v) + #define FROM_LE_64(a) ((uint64)(a)) + #define FROM_BE_64(a) SWAP_BYTES_64(a) + #define TO_LE_64(a) ((uint64)(a)) + #define TO_BE_64(a) SWAP_BYTES_64(a) + #define CONSTANT_LE_64(a) ((uint64)(a)) + #define CONSTANT_BE_64(a) SWAP_CONSTANT_64(a) +#endif + // if the unaligned load and the byteswap take alot instructions its better to directly read and invert # if defined(SCUMM_NEED_ALIGNMENT) && !defined(__mips__) @@ -306,6 +443,24 @@ b[2] = (uint8)(value >> 8); b[3] = (uint8)(value >> 0); } +#ifdef HAVE_INT64 + inline uint64 READ_BE_UINT64(const void *ptr) { + const uint8 *b = (const uint8 *)ptr; + return ((uint64)b[0] << 56) | ((uint64)b[1] << 48) | ((uint64)b[2] << 40) | ((uint64)b[3] << 32) | ((uint64)b[4] << 24) | ((uint64)b[5] << 16) | ((uint64)b[6] << 8) | ((uint64)b[7]); + } + inline void WRITE_BE_UINT64(void *ptr, uint64 value) { + uint8 *b = (uint8 *)ptr; + b[0] = (uint8)(value >> 56); + b[1] = (uint8)(value >> 48); + b[2] = (uint8)(value >> 40); + b[3] = (uint8)(value >> 32); + b[4] = (uint8)(value >> 24); + b[5] = (uint8)(value >> 16); + b[6] = (uint8)(value >> 8); + b[7] = (uint8)(value >> 0); + } +#endif + # else inline uint16 READ_BE_UINT16(const void *ptr) { @@ -320,6 +475,14 @@ inline void WRITE_BE_UINT32(void *ptr, uint32 value) { WRITE_UINT32(ptr, SWAP_BYTES_32(value)); } +#ifdef HAVE_INT64 + inline uint64 READ_BE_UINT64(const void *ptr) { + return SWAP_BYTES_64(READ_UINT64(ptr)); + } + inline void WRITE_BE_UINT64(void *ptr, uint64 value) { + WRITE_UINT64(ptr, SWAP_BYTES_64(value)); + } +#endif # endif // if defined(SCUMM_NEED_ALIGNMENT) @@ -349,6 +512,17 @@ #define CONSTANT_BE_32(a) ((uint32)(a)) #define CONSTANT_BE_16(a) ((uint16)(a)) +#ifdef HAVE_INT64 + #define READ_BE_UINT64(a) READ_UINT64(a) + #define WRITE_BE_UINT64(a, v) WRITE_UINT64(a, v) + #define FROM_LE_64(a) SWAP_BYTES_64(a) + #define FROM_BE_64(a) ((uint64)(a)) + #define TO_LE_64(a) SWAP_BYTES_64(a) + #define TO_BE_64(a) ((uint64)(a)) + #define CONSTANT_LE_64(a) SWAP_CONSTANT_64(a) + #define CONSTANT_BE_64(a) ((uint64)(a)) +#endif + // if the unaligned load and the byteswap take alot instructions its better to directly read and invert # if defined(SCUMM_NEED_ALIGNMENT) && !defined(__mips__) @@ -372,6 +546,25 @@ b[2] = (uint8)(value >> 16); b[3] = (uint8)(value >> 24); } + +#ifdef HAVE_INT64 + inline uint64 READ_LE_UINT64(const void *ptr) { + const uint8 *b = (const uint8 *)ptr; + return ((uint64)b[7] << 56) | ((uint64)b[6] << 48) | ((uint64)b[5] << 40) | ((uint64)b[4] << 32) | ((uint64)b[3] << 24) | ((uint64)b[2] << 16) | ((uint64)b[1] << 8) | ((uint64)b[0]); + } + inline void WRITE_LE_UINT64(void *ptr, uint64 value) { + uint8 *b = (uint8 *)ptr; + b[0] = (uint8)(value >> 0); + b[1] = (uint8)(value >> 8); + b[2] = (uint8)(value >> 16); + b[3] = (uint8)(value >> 24); + b[4] = (uint8)(value >> 32); + b[5] = (uint8)(value >> 40); + b[6] = (uint8)(value >> 48); + b[7] = (uint8)(value >> 56); + } +#endif + # else inline uint16 READ_LE_UINT16(const void *ptr) { @@ -386,6 +579,14 @@ inline void WRITE_LE_UINT32(void *ptr, uint32 value) { WRITE_UINT32(ptr, SWAP_BYTES_32(value)); } +#ifdef HAVE_INT64 + inline uint64 READ_LE_UINT64(const void *ptr) { + return SWAP_BYTES_64(READ_UINT64(ptr)); + } + inline void WRITE_LE_UINT64(void *ptr, uint64 value) { + WRITE_UINT64(ptr, SWAP_BYTES_64(value)); + } +#endif # endif // if defined(SCUMM_NEED_ALIGNMENT) |