// See LICENSE for license details. #ifndef _RISCV_BYTEORDER_H #define _RISCV_BYTEORDER_H #include "config.h" #include static inline uint8_t swap(uint8_t n) { return n; } static inline uint16_t swap(uint16_t n) { return (n >> 8) | (n << 8); } static inline uint32_t swap(uint32_t n) { return (swap(uint16_t(n)) << 16) | swap(uint16_t(n >> 16)); } static inline uint64_t swap(uint64_t n) { return (uint64_t(swap(uint32_t(n))) << 32) | swap(uint32_t(n >> 32)); } static inline int8_t swap(int8_t n) { return n; } static inline int16_t swap(int16_t n) { return int16_t(swap(uint16_t(n))); } static inline int32_t swap(int32_t n) { return int32_t(swap(uint32_t(n))); } static inline int64_t swap(int64_t n) { return int64_t(swap(uint64_t(n))); } #ifdef HAVE_INT128 typedef __int128 int128_t; typedef unsigned __int128 uint128_t; static inline uint128_t swap(uint128_t n) { return (uint128_t(swap(uint64_t(n))) << 64) | swap(uint64_t(n >> 64)); } static inline int128_t swap(int128_t n) { return int128_t(swap(uint128_t(n))); } #endif #ifdef WORDS_BIGENDIAN template static inline T from_be(T n) { return n; } template static inline T to_be(T n) { return n; } template static inline T from_le(T n) { return swap(n); } template static inline T to_le(T n) { return swap(n); } #else template static inline T from_le(T n) { return n; } template static inline T to_le(T n) { return n; } template static inline T from_be(T n) { return swap(n); } template static inline T to_be(T n) { return swap(n); } #endif // Wrapper to mark a value as target endian, to guide conversion code template class base_endian { protected: T value; base_endian(T n) : value(n) {} public: // Setting to and testing against zero never needs swapping base_endian() : value(0) {} bool operator!() { return !value; } // Bitwise logic operations can be performed without swapping base_endian& operator|=(const base_endian& rhs) { value |= rhs.value; return *this; } base_endian& operator&=(const base_endian& rhs) { value &= rhs.value; return *this; } base_endian& operator^=(const base_endian& rhs) { value ^= rhs.value; return *this; } inline T from_be() { return ::from_be(value); } inline T from_le() { return ::from_le(value); } }; template class target_endian : public base_endian { protected: target_endian(T n) : base_endian(n) {} public: target_endian() {} static inline target_endian to_be(T n) { return target_endian(::to_be(n)); } static inline target_endian to_le(T n) { return target_endian(::to_le(n)); } // Useful values over which swapping is identity static const target_endian zero; static const target_endian all_ones; }; template const target_endian target_endian::zero = target_endian(T(0)); template const target_endian target_endian::all_ones = target_endian(~T(0)); // Specializations with implicit conversions (no swap information needed) template<> class target_endian : public base_endian { public: target_endian() {} target_endian(uint8_t n) : base_endian(n) {} operator uint8_t() { return value; } static inline target_endian to_be(uint8_t n) { return target_endian(n); } static inline target_endian to_le(uint8_t n) { return target_endian(n); } }; template<> class target_endian : public base_endian { public: target_endian() {} target_endian(int8_t n) : base_endian(n) {} operator int8_t() { return value; } static inline target_endian to_be(int8_t n) { return target_endian(n); } static inline target_endian to_le(int8_t n) { return target_endian(n); } }; #endif