#ifndef __MDFN_ENDIAN_H #define __MDFN_ENDIAN_H #pragma warning(once : 4519) static INLINE uint32 BitsExtract(const uint8* ptr, const size_t bit_offset, const size_t bit_count) { uint32 ret = 0; for(size_t x = 0; x < bit_count; x++) { size_t co = bit_offset + x; bool b = (ptr[co >> 3] >> (co & 7)) & 1; ret |= (uint64)b << x; } return ret; } static INLINE void BitsIntract(uint8* ptr, const size_t bit_offset, const size_t bit_count, uint32 value) { for(size_t x = 0; x < bit_count; x++) { size_t co = bit_offset + x; bool b = (value >> x) & 1; uint8 tmp = ptr[co >> 3]; tmp &= ~(1 << (co & 7)); tmp |= b << (co & 7); ptr[co >> 3] = tmp; } } /* Regarding safety of calling MDFN_*sb on dynamically-allocated memory with new uint8[], see C++ standard 3.7.3.1(i.e. it should be safe provided the offsets into the memory are aligned/multiples of the MDFN_*sb access type). malloc()'d and calloc()'d memory should be safe as well. Statically-allocated arrays/memory should be unioned with a big POD type or C++11 "alignas"'d. (May need to audit code to ensure this is being done). */ void Endian_A16_Swap(void *src, uint32 nelements); void Endian_A32_Swap(void *src, uint32 nelements); void Endian_A64_Swap(void *src, uint32 nelements); void Endian_A16_NE_LE(void *src, uint32 nelements); void Endian_A32_NE_LE(void *src, uint32 nelements); void Endian_A64_NE_LE(void *src, uint32 nelements); void Endian_A16_NE_BE(void *src, uint32 nelements); void Endian_A32_NE_BE(void *src, uint32 nelements); void Endian_A64_NE_BE(void *src, uint32 nelements); void Endian_V_NE_LE(void *src, uint32 bytesize); void Endian_V_NE_BE(void *src, uint32 bytesize); static INLINE uint16 MDFN_bswap16(uint16 v) { return (v << 8) | (v >> 8); } static INLINE uint32 MDFN_bswap32(uint32 v) { return (v << 24) | ((v & 0xFF00) << 8) | ((v >> 8) & 0xFF00) | (v >> 24); } static INLINE uint64 MDFN_bswap64(uint64 v) { //octoshock edit //return (v << 56) | (v >> 56) | ((v & 0xFF00) << 40) | ((v >> 40) & 0xFF00) | ((uint64)MDFN_bswap32(v >> 16) << 16); return (v << 56) | (v >> 56) | ((v & 0xFF00) << 40) | ((v >> 40) & 0xFF00) | ((uint64)MDFN_bswap32(((uint32)v) >> 16) << 16); } #ifdef LSB_FIRST #define MDFN_ENDIANH_IS_BIGENDIAN 0 #else #define MDFN_ENDIANH_IS_BIGENDIAN 1 #endif // // X endian. // template static INLINE T MDFN_deXsb(const void* ptr) { T tmp; memcpy(&tmp, MDFN_ASSUME_ALIGNED(ptr, (aligned ? sizeof(T) : 1)), sizeof(T)); if(isbigendian != -1 && isbigendian != MDFN_ENDIANH_IS_BIGENDIAN) { static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "Gummy penguins."); if(sizeof(T) == 8) return (T)MDFN_bswap64(tmp); else if(sizeof(T) == 4) return (T)MDFN_bswap32(tmp); else if(sizeof(T) == 2) return (T)MDFN_bswap16(tmp); } return tmp; } // // Native endian. // template static INLINE T MDFN_densb(const void* ptr) { return MDFN_deXsb<-1, T, aligned>(ptr); } // // Little endian. // template static INLINE T MDFN_delsb(const void* ptr) { return MDFN_deXsb<0, T, aligned>(ptr); } template static INLINE uint16 MDFN_de16lsb(const void* ptr) { return MDFN_delsb(ptr); } static INLINE uint32 MDFN_de24lsb(const void* ptr) { const uint8* morp = (const uint8*)ptr; return(morp[0]|(morp[1]<<8)|(morp[2]<<16)); } template static INLINE uint32 MDFN_de32lsb(const void* ptr) { return MDFN_delsb(ptr); } template static INLINE uint64 MDFN_de64lsb(const void* ptr) { return MDFN_delsb(ptr); } // // Big endian. // template static INLINE T MDFN_demsb(const void* ptr) { return MDFN_deXsb<1, T, aligned>(ptr); } template static INLINE uint16 MDFN_de16msb(const void* ptr) { return MDFN_demsb(ptr); } static INLINE uint32 MDFN_de24msb(const void* ptr) { const uint8* morp = (const uint8*)ptr; return((morp[2]<<0)|(morp[1]<<8)|(morp[0]<<16)); } template static INLINE uint32 MDFN_de32msb(const void* ptr) { return MDFN_demsb(ptr); } template static INLINE uint64 MDFN_de64msb(const void* ptr) { return MDFN_demsb(ptr); } // // // // // // // // // // X endian. // template static INLINE void MDFN_enXsb(void* ptr, T value) { T tmp = value; if(isbigendian != -1 && isbigendian != MDFN_ENDIANH_IS_BIGENDIAN) { static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "Gummy penguins."); if(sizeof(T) == 8) tmp = (T)MDFN_bswap64(value); else if(sizeof(T) == 4) tmp = (T)MDFN_bswap32(value); else if(sizeof(T) == 2) tmp = (T)MDFN_bswap16(value); } memcpy(MDFN_ASSUME_ALIGNED(ptr, (aligned ? sizeof(T) : 1)), &tmp, sizeof(T)); } // // Native endian. // template static INLINE void MDFN_ennsb(void* ptr, T value) { MDFN_enXsb<-1, T, aligned>(ptr, value); } // // Little endian. // template static INLINE void MDFN_enlsb(void* ptr, T value) { MDFN_enXsb<0, T, aligned>(ptr, value); } template static INLINE void MDFN_en16lsb(void* ptr, uint16 value) { MDFN_enlsb(ptr, value); } static INLINE void MDFN_en24lsb(void* ptr, uint32 value) { uint8* morp = (uint8*)ptr; morp[0] = value; morp[1] = value >> 8; morp[2] = value >> 16; } template static INLINE void MDFN_en32lsb(void* ptr, uint32 value) { MDFN_enlsb(ptr, value); } template static INLINE void MDFN_en64lsb(void* ptr, uint64 value) { MDFN_enlsb(ptr, value); } // // Big endian. // template static INLINE void MDFN_enmsb(void* ptr, T value) { MDFN_enXsb<1, T, aligned>(ptr, value); } template static INLINE void MDFN_en16msb(void* ptr, uint16 value) { MDFN_enmsb(ptr, value); } static INLINE void MDFN_en24msb(void* ptr, uint32 value) { uint8* morp = (uint8*)ptr; morp[0] = value; morp[1] = value >> 8; morp[2] = value >> 16; } template static INLINE void MDFN_en32msb(void* ptr, uint32 value) { MDFN_enmsb(ptr, value); } template static INLINE void MDFN_en64msb(void* ptr, uint64 value) { MDFN_enmsb(ptr, value); } #endif