aboutsummaryrefslogtreecommitdiff
path: root/fesvr/byteorder.h
diff options
context:
space:
mode:
Diffstat (limited to 'fesvr/byteorder.h')
-rw-r--r--fesvr/byteorder.h94
1 files changed, 94 insertions, 0 deletions
diff --git a/fesvr/byteorder.h b/fesvr/byteorder.h
new file mode 100644
index 0000000..2b1dbf9
--- /dev/null
+++ b/fesvr/byteorder.h
@@ -0,0 +1,94 @@
+// See LICENSE for license details.
+
+#ifndef _RISCV_BYTEORDER_H
+#define _RISCV_BYTEORDER_H
+
+#include "config.h"
+#include <stdint.h>
+
+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 WORDS_BIGENDIAN
+template<typename T> static inline T from_be(T n) { return n; }
+template<typename T> static inline T to_be(T n) { return n; }
+template<typename T> static inline T from_le(T n) { return swap(n); }
+template<typename T> static inline T to_le(T n) { return swap(n); }
+#else
+template<typename T> static inline T from_le(T n) { return n; }
+template<typename T> static inline T to_le(T n) { return n; }
+template<typename T> static inline T from_be(T n) { return swap(n); }
+template<typename T> static inline T to_be(T n) { return swap(n); }
+#endif
+
+// Wrapper to mark a value as target endian, to guide conversion code
+
+template<typename T> 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<typename T> class target_endian : public base_endian<T> {
+ protected:
+ target_endian(T n) : base_endian<T>(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<typename T> const target_endian<T> target_endian<T>::zero = target_endian(T(0));
+template<typename T> const target_endian<T> target_endian<T>::all_ones = target_endian(~T(0));
+
+
+// Specializations with implicit conversions (no swap information needed)
+
+template<> class target_endian<uint8_t> : public base_endian<uint8_t> {
+ public:
+ target_endian() {}
+ target_endian(uint8_t n) : base_endian<uint8_t>(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<int8_t> : public base_endian<int8_t> {
+ public:
+ target_endian() {}
+ target_endian(int8_t n) : base_endian<int8_t>(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