1 // See LICENSE for license details.
2 
3 #ifndef _RISCV_BYTEORDER_H
4 #define _RISCV_BYTEORDER_H
5 
6 #include "config.h"
7 #include <stdint.h>
8 
swap(uint8_t n)9 static inline uint8_t swap(uint8_t n) { return n; }
swap(uint16_t n)10 static inline uint16_t swap(uint16_t n) { return (n >> 8) | (n << 8); }
swap(uint32_t n)11 static inline uint32_t swap(uint32_t n) { return (swap(uint16_t(n)) << 16) | swap(uint16_t(n >> 16)); }
swap(uint64_t n)12 static inline uint64_t swap(uint64_t n) { return (uint64_t(swap(uint32_t(n))) << 32) | swap(uint32_t(n >> 32)); }
swap(int8_t n)13 static inline int8_t swap(int8_t n) { return n; }
swap(int16_t n)14 static inline int16_t swap(int16_t n) { return int16_t(swap(uint16_t(n))); }
swap(int32_t n)15 static inline int32_t swap(int32_t n) { return int32_t(swap(uint32_t(n))); }
swap(int64_t n)16 static inline int64_t swap(int64_t n) { return int64_t(swap(uint64_t(n))); }
17 
18 #ifdef WORDS_BIGENDIAN
from_be(T n)19 template<typename T> static inline T from_be(T n) { return n; }
to_be(T n)20 template<typename T> static inline T to_be(T n) { return n; }
from_le(T n)21 template<typename T> static inline T from_le(T n) { return swap(n); }
to_le(T n)22 template<typename T> static inline T to_le(T n) { return swap(n); }
23 #else
from_le(T n)24 template<typename T> static inline T from_le(T n) { return n; }
to_le(T n)25 template<typename T> static inline T to_le(T n) { return n; }
from_be(T n)26 template<typename T> static inline T from_be(T n) { return swap(n); }
to_be(T n)27 template<typename T> static inline T to_be(T n) { return swap(n); }
28 #endif
29 
30 // Wrapper to mark a value as target endian, to guide conversion code
31 
32 template<typename T> class base_endian {
33 
34  protected:
35   T value;
36 
base_endian(T n)37   base_endian(T n) : value(n) {}
38 
39  public:
40   // Setting to and testing against zero never needs swapping
base_endian()41   base_endian() : value(0) {}
42   bool operator!() { return !value; }
43 
44   // Bitwise logic operations can be performed without swapping
45   base_endian& operator|=(const base_endian& rhs) { value |= rhs.value; return *this; }
46   base_endian& operator&=(const base_endian& rhs) { value &= rhs.value; return *this; }
47   base_endian& operator^=(const base_endian& rhs) { value ^= rhs.value; return *this; }
48 
from_be()49   inline T from_be() { return ::from_be(value); }
from_le()50   inline T from_le() { return ::from_le(value); }
51 };
52 
53 template<typename T> class target_endian : public base_endian<T> {
54  protected:
target_endian(T n)55   target_endian(T n) : base_endian<T>(n) {}
56 
57  public:
target_endian()58   target_endian() {}
59 
to_be(T n)60   static inline target_endian to_be(T n) { return target_endian(::to_be(n)); }
to_le(T n)61   static inline target_endian to_le(T n) { return target_endian(::to_le(n)); }
62 
63   // Useful values over which swapping is identity
64   static const target_endian zero;
65   static const target_endian all_ones;
66 };
67 
68 template<typename T> const target_endian<T> target_endian<T>::zero = target_endian(T(0));
69 template<typename T> const target_endian<T> target_endian<T>::all_ones = target_endian(~T(0));
70 
71 
72 // Specializations with implicit conversions (no swap information needed)
73 
74 template<> class target_endian<uint8_t> : public base_endian<uint8_t> {
75  public:
target_endian()76   target_endian() {}
target_endian(uint8_t n)77   target_endian(uint8_t n) : base_endian<uint8_t>(n) {}
uint8_t()78   operator uint8_t() { return value; }
79 
to_be(uint8_t n)80   static inline target_endian to_be(uint8_t n) { return target_endian(n); }
to_le(uint8_t n)81   static inline target_endian to_le(uint8_t n) { return target_endian(n); }
82 };
83 
84 template<> class target_endian<int8_t> : public base_endian<int8_t> {
85  public:
target_endian()86   target_endian() {}
target_endian(int8_t n)87   target_endian(int8_t n) : base_endian<int8_t>(n) {}
int8_t()88   operator int8_t() { return value; }
89 
to_be(int8_t n)90   static inline target_endian to_be(int8_t n) { return target_endian(n); }
to_le(int8_t n)91   static inline target_endian to_le(int8_t n) { return target_endian(n); }
92 };
93 
94 #endif
95