Merge pull request #2090 from FearlessTobi/port-4599
Port citra-emu/citra#4244 and citra-emu/citra#4599: Changes to BitField
This commit is contained in:
		| @@ -34,6 +34,7 @@ | |||||||
| #include <limits> | #include <limits> | ||||||
| #include <type_traits> | #include <type_traits> | ||||||
| #include "common/common_funcs.h" | #include "common/common_funcs.h" | ||||||
|  | #include "common/swap.h" | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Abstract bitfield class |  * Abstract bitfield class | ||||||
| @@ -108,7 +109,7 @@ | |||||||
|  * symptoms. |  * symptoms. | ||||||
|  */ |  */ | ||||||
| #pragma pack(1) | #pragma pack(1) | ||||||
| template <std::size_t Position, std::size_t Bits, typename T> | template <std::size_t Position, std::size_t Bits, typename T, typename EndianTag = LETag> | ||||||
| struct BitField { | struct BitField { | ||||||
| private: | private: | ||||||
|     // UnderlyingType is T for non-enum types and the underlying type of T if |     // UnderlyingType is T for non-enum types and the underlying type of T if | ||||||
| @@ -121,7 +122,11 @@ private: | |||||||
|     // We store the value as the unsigned type to avoid undefined behaviour on value shifting |     // We store the value as the unsigned type to avoid undefined behaviour on value shifting | ||||||
|     using StorageType = std::make_unsigned_t<UnderlyingType>; |     using StorageType = std::make_unsigned_t<UnderlyingType>; | ||||||
|  |  | ||||||
|  |     using StorageTypeWithEndian = typename AddEndian<StorageType, EndianTag>::type; | ||||||
|  |  | ||||||
| public: | public: | ||||||
|  |     BitField& operator=(const BitField&) = default; | ||||||
|  |  | ||||||
|     /// Constants to allow limited introspection of fields if needed |     /// Constants to allow limited introspection of fields if needed | ||||||
|     static constexpr std::size_t position = Position; |     static constexpr std::size_t position = Position; | ||||||
|     static constexpr std::size_t bits = Bits; |     static constexpr std::size_t bits = Bits; | ||||||
| @@ -170,7 +175,7 @@ public: | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     constexpr FORCE_INLINE void Assign(const T& value) { |     constexpr FORCE_INLINE void Assign(const T& value) { | ||||||
|         storage = (storage & ~mask) | FormatValue(value); |         storage = (static_cast<StorageType>(storage) & ~mask) | FormatValue(value); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     constexpr T Value() const { |     constexpr T Value() const { | ||||||
| @@ -182,7 +187,7 @@ public: | |||||||
|     } |     } | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     StorageType storage; |     StorageTypeWithEndian storage; | ||||||
|  |  | ||||||
|     static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); |     static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); | ||||||
|  |  | ||||||
| @@ -193,3 +198,6 @@ private: | |||||||
|     static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable in a BitField"); |     static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable in a BitField"); | ||||||
| }; | }; | ||||||
| #pragma pack() | #pragma pack() | ||||||
|  |  | ||||||
|  | template <std::size_t Position, std::size_t Bits, typename T> | ||||||
|  | using BitFieldBE = BitField<Position, Bits, T, BETag>; | ||||||
|   | |||||||
| @@ -17,6 +17,8 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
|  | #include <type_traits> | ||||||
|  |  | ||||||
| #if defined(_MSC_VER) | #if defined(_MSC_VER) | ||||||
| #include <cstdlib> | #include <cstdlib> | ||||||
| #elif defined(__linux__) | #elif defined(__linux__) | ||||||
| @@ -170,7 +172,7 @@ struct swap_struct_t { | |||||||
|     using swapped_t = swap_struct_t; |     using swapped_t = swap_struct_t; | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
|     T value = T(); |     T value; | ||||||
|  |  | ||||||
|     static T swap(T v) { |     static T swap(T v) { | ||||||
|         return F::swap(v); |         return F::swap(v); | ||||||
| @@ -605,52 +607,154 @@ struct swap_double_t { | |||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | template <typename T> | ||||||
|  | struct swap_enum_t { | ||||||
|  |     static_assert(std::is_enum_v<T>); | ||||||
|  |     using base = std::underlying_type_t<T>; | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |     swap_enum_t() = default; | ||||||
|  |     swap_enum_t(const T& v) : value(swap(v)) {} | ||||||
|  |  | ||||||
|  |     swap_enum_t& operator=(const T& v) { | ||||||
|  |         value = swap(v); | ||||||
|  |         return *this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     operator T() const { | ||||||
|  |         return swap(value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     explicit operator base() const { | ||||||
|  |         return static_cast<base>(swap(value)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |     T value{}; | ||||||
|  |     // clang-format off | ||||||
|  |     using swap_t = std::conditional_t< | ||||||
|  |         std::is_same_v<base, u16>, swap_16_t<u16>, std::conditional_t< | ||||||
|  |         std::is_same_v<base, s16>, swap_16_t<s16>, std::conditional_t< | ||||||
|  |         std::is_same_v<base, u32>, swap_32_t<u32>, std::conditional_t< | ||||||
|  |         std::is_same_v<base, s32>, swap_32_t<s32>, std::conditional_t< | ||||||
|  |         std::is_same_v<base, u64>, swap_64_t<u64>, std::conditional_t< | ||||||
|  |         std::is_same_v<base, s64>, swap_64_t<s64>, void>>>>>>; | ||||||
|  |     // clang-format on | ||||||
|  |     static T swap(T x) { | ||||||
|  |         return static_cast<T>(swap_t::swap(static_cast<base>(x))); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct SwapTag {}; // Use the different endianness from the system | ||||||
|  | struct KeepTag {}; // Use the same endianness as the system | ||||||
|  |  | ||||||
|  | template <typename T, typename Tag> | ||||||
|  | struct AddEndian; | ||||||
|  |  | ||||||
|  | // KeepTag specializations | ||||||
|  |  | ||||||
|  | template <typename T> | ||||||
|  | struct AddEndian<T, KeepTag> { | ||||||
|  |     using type = T; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // SwapTag specializations | ||||||
|  |  | ||||||
|  | template <> | ||||||
|  | struct AddEndian<u8, SwapTag> { | ||||||
|  |     using type = u8; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <> | ||||||
|  | struct AddEndian<u16, SwapTag> { | ||||||
|  |     using type = swap_struct_t<u16, swap_16_t<u16>>; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <> | ||||||
|  | struct AddEndian<u32, SwapTag> { | ||||||
|  |     using type = swap_struct_t<u32, swap_32_t<u32>>; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <> | ||||||
|  | struct AddEndian<u64, SwapTag> { | ||||||
|  |     using type = swap_struct_t<u64, swap_64_t<u64>>; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <> | ||||||
|  | struct AddEndian<s8, SwapTag> { | ||||||
|  |     using type = s8; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <> | ||||||
|  | struct AddEndian<s16, SwapTag> { | ||||||
|  |     using type = swap_struct_t<s16, swap_16_t<s16>>; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <> | ||||||
|  | struct AddEndian<s32, SwapTag> { | ||||||
|  |     using type = swap_struct_t<s32, swap_32_t<s32>>; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <> | ||||||
|  | struct AddEndian<s64, SwapTag> { | ||||||
|  |     using type = swap_struct_t<s64, swap_64_t<s64>>; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <> | ||||||
|  | struct AddEndian<float, SwapTag> { | ||||||
|  |     using type = swap_struct_t<float, swap_float_t<float>>; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <> | ||||||
|  | struct AddEndian<double, SwapTag> { | ||||||
|  |     using type = swap_struct_t<double, swap_double_t<double>>; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <typename T> | ||||||
|  | struct AddEndian<T, SwapTag> { | ||||||
|  |     static_assert(std::is_enum_v<T>); | ||||||
|  |     using type = swap_enum_t<T>; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // Alias LETag/BETag as KeepTag/SwapTag depending on the system | ||||||
| #if COMMON_LITTLE_ENDIAN | #if COMMON_LITTLE_ENDIAN | ||||||
| using u16_le = u16; |  | ||||||
| using u32_le = u32; |  | ||||||
| using u64_le = u64; |  | ||||||
|  |  | ||||||
| using s16_le = s16; | using LETag = KeepTag; | ||||||
| using s32_le = s32; | using BETag = SwapTag; | ||||||
| using s64_le = s64; |  | ||||||
|  |  | ||||||
| using float_le = float; |  | ||||||
| using double_le = double; |  | ||||||
|  |  | ||||||
| using u64_be = swap_struct_t<u64, swap_64_t<u64>>; |  | ||||||
| using s64_be = swap_struct_t<s64, swap_64_t<s64>>; |  | ||||||
|  |  | ||||||
| using u32_be = swap_struct_t<u32, swap_32_t<u32>>; |  | ||||||
| using s32_be = swap_struct_t<s32, swap_32_t<s32>>; |  | ||||||
|  |  | ||||||
| using u16_be = swap_struct_t<u16, swap_16_t<u16>>; |  | ||||||
| using s16_be = swap_struct_t<s16, swap_16_t<s16>>; |  | ||||||
|  |  | ||||||
| using float_be = swap_struct_t<float, swap_float_t<float>>; |  | ||||||
| using double_be = swap_struct_t<double, swap_double_t<double>>; |  | ||||||
| #else | #else | ||||||
|  |  | ||||||
| using u64_le = swap_struct_t<u64, swap_64_t<u64>>; | using BETag = KeepTag; | ||||||
| using s64_le = swap_struct_t<s64, swap_64_t<s64>>; | using LETag = SwapTag; | ||||||
|  |  | ||||||
| using u32_le = swap_struct_t<u32, swap_32_t<u32>>; |  | ||||||
| using s32_le = swap_struct_t<s32, swap_32_t<s32>>; |  | ||||||
|  |  | ||||||
| using u16_le = swap_struct_t<u16, swap_16_t<u16>>; |  | ||||||
| using s16_le = swap_struct_t<s16, swap_16_t<s16>>; |  | ||||||
|  |  | ||||||
| using float_le = swap_struct_t<float, swap_float_t<float>>; |  | ||||||
| using double_le = swap_struct_t<double, swap_double_t<double>>; |  | ||||||
|  |  | ||||||
| using u16_be = u16; |  | ||||||
| using u32_be = u32; |  | ||||||
| using u64_be = u64; |  | ||||||
|  |  | ||||||
| using s16_be = s16; |  | ||||||
| using s32_be = s32; |  | ||||||
| using s64_be = s64; |  | ||||||
|  |  | ||||||
| using float_be = float; |  | ||||||
| using double_be = double; |  | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | // Aliases for LE types | ||||||
|  | using u16_le = AddEndian<u16, LETag>::type; | ||||||
|  | using u32_le = AddEndian<u32, LETag>::type; | ||||||
|  | using u64_le = AddEndian<u64, LETag>::type; | ||||||
|  |  | ||||||
|  | using s16_le = AddEndian<s16, LETag>::type; | ||||||
|  | using s32_le = AddEndian<s32, LETag>::type; | ||||||
|  | using s64_le = AddEndian<s64, LETag>::type; | ||||||
|  |  | ||||||
|  | template <typename T> | ||||||
|  | using enum_le = std::enable_if_t<std::is_enum_v<T>, typename AddEndian<T, LETag>::type>; | ||||||
|  |  | ||||||
|  | using float_le = AddEndian<float, LETag>::type; | ||||||
|  | using double_le = AddEndian<double, LETag>::type; | ||||||
|  |  | ||||||
|  | // Aliases for BE types | ||||||
|  | using u16_be = AddEndian<u16, BETag>::type; | ||||||
|  | using u32_be = AddEndian<u32, BETag>::type; | ||||||
|  | using u64_be = AddEndian<u64, BETag>::type; | ||||||
|  |  | ||||||
|  | using s16_be = AddEndian<s16, BETag>::type; | ||||||
|  | using s32_be = AddEndian<s32, BETag>::type; | ||||||
|  | using s64_be = AddEndian<s64, BETag>::type; | ||||||
|  |  | ||||||
|  | template <typename T> | ||||||
|  | using enum_be = std::enable_if_t<std::is_enum_v<T>, typename AddEndian<T, BETag>::type>; | ||||||
|  |  | ||||||
|  | using float_be = AddEndian<float, BETag>::type; | ||||||
|  | using double_be = AddEndian<double, BETag>::type; | ||||||
|   | |||||||
| @@ -39,10 +39,10 @@ struct CommandHeader { | |||||||
|     union { |     union { | ||||||
|         u32_le raw_low; |         u32_le raw_low; | ||||||
|         BitField<0, 16, CommandType> type; |         BitField<0, 16, CommandType> type; | ||||||
|         BitField<16, 4, u32_le> num_buf_x_descriptors; |         BitField<16, 4, u32> num_buf_x_descriptors; | ||||||
|         BitField<20, 4, u32_le> num_buf_a_descriptors; |         BitField<20, 4, u32> num_buf_a_descriptors; | ||||||
|         BitField<24, 4, u32_le> num_buf_b_descriptors; |         BitField<24, 4, u32> num_buf_b_descriptors; | ||||||
|         BitField<28, 4, u32_le> num_buf_w_descriptors; |         BitField<28, 4, u32> num_buf_w_descriptors; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     enum class BufferDescriptorCFlag : u32 { |     enum class BufferDescriptorCFlag : u32 { | ||||||
| @@ -53,28 +53,28 @@ struct CommandHeader { | |||||||
|  |  | ||||||
|     union { |     union { | ||||||
|         u32_le raw_high; |         u32_le raw_high; | ||||||
|         BitField<0, 10, u32_le> data_size; |         BitField<0, 10, u32> data_size; | ||||||
|         BitField<10, 4, BufferDescriptorCFlag> buf_c_descriptor_flags; |         BitField<10, 4, BufferDescriptorCFlag> buf_c_descriptor_flags; | ||||||
|         BitField<31, 1, u32_le> enable_handle_descriptor; |         BitField<31, 1, u32> enable_handle_descriptor; | ||||||
|     }; |     }; | ||||||
| }; | }; | ||||||
| static_assert(sizeof(CommandHeader) == 8, "CommandHeader size is incorrect"); | static_assert(sizeof(CommandHeader) == 8, "CommandHeader size is incorrect"); | ||||||
|  |  | ||||||
| union HandleDescriptorHeader { | union HandleDescriptorHeader { | ||||||
|     u32_le raw_high; |     u32_le raw_high; | ||||||
|     BitField<0, 1, u32_le> send_current_pid; |     BitField<0, 1, u32> send_current_pid; | ||||||
|     BitField<1, 4, u32_le> num_handles_to_copy; |     BitField<1, 4, u32> num_handles_to_copy; | ||||||
|     BitField<5, 4, u32_le> num_handles_to_move; |     BitField<5, 4, u32> num_handles_to_move; | ||||||
| }; | }; | ||||||
| static_assert(sizeof(HandleDescriptorHeader) == 4, "HandleDescriptorHeader size is incorrect"); | static_assert(sizeof(HandleDescriptorHeader) == 4, "HandleDescriptorHeader size is incorrect"); | ||||||
|  |  | ||||||
| struct BufferDescriptorX { | struct BufferDescriptorX { | ||||||
|     union { |     union { | ||||||
|         BitField<0, 6, u32_le> counter_bits_0_5; |         BitField<0, 6, u32> counter_bits_0_5; | ||||||
|         BitField<6, 3, u32_le> address_bits_36_38; |         BitField<6, 3, u32> address_bits_36_38; | ||||||
|         BitField<9, 3, u32_le> counter_bits_9_11; |         BitField<9, 3, u32> counter_bits_9_11; | ||||||
|         BitField<12, 4, u32_le> address_bits_32_35; |         BitField<12, 4, u32> address_bits_32_35; | ||||||
|         BitField<16, 16, u32_le> size; |         BitField<16, 16, u32> size; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     u32_le address_bits_0_31; |     u32_le address_bits_0_31; | ||||||
| @@ -103,10 +103,10 @@ struct BufferDescriptorABW { | |||||||
|     u32_le address_bits_0_31; |     u32_le address_bits_0_31; | ||||||
|  |  | ||||||
|     union { |     union { | ||||||
|         BitField<0, 2, u32_le> flags; |         BitField<0, 2, u32> flags; | ||||||
|         BitField<2, 3, u32_le> address_bits_36_38; |         BitField<2, 3, u32> address_bits_36_38; | ||||||
|         BitField<24, 4, u32_le> size_bits_32_35; |         BitField<24, 4, u32> size_bits_32_35; | ||||||
|         BitField<28, 4, u32_le> address_bits_32_35; |         BitField<28, 4, u32> address_bits_32_35; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     VAddr Address() const { |     VAddr Address() const { | ||||||
| @@ -128,8 +128,8 @@ struct BufferDescriptorC { | |||||||
|     u32_le address_bits_0_31; |     u32_le address_bits_0_31; | ||||||
|  |  | ||||||
|     union { |     union { | ||||||
|         BitField<0, 16, u32_le> address_bits_32_47; |         BitField<0, 16, u32> address_bits_32_47; | ||||||
|         BitField<16, 16, u32_le> size; |         BitField<16, 16, u32> size; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     VAddr Address() const { |     VAddr Address() const { | ||||||
| @@ -167,8 +167,8 @@ struct DomainMessageHeader { | |||||||
|         struct { |         struct { | ||||||
|             union { |             union { | ||||||
|                 BitField<0, 8, CommandType> command; |                 BitField<0, 8, CommandType> command; | ||||||
|                 BitField<8, 8, u32_le> input_object_count; |                 BitField<8, 8, u32> input_object_count; | ||||||
|                 BitField<16, 16, u32_le> size; |                 BitField<16, 16, u32> size; | ||||||
|             }; |             }; | ||||||
|             u32_le object_id; |             u32_le object_id; | ||||||
|             INSERT_PADDING_WORDS(2); |             INSERT_PADDING_WORDS(2); | ||||||
|   | |||||||
| @@ -41,20 +41,20 @@ private: | |||||||
|     struct PadState { |     struct PadState { | ||||||
|         union { |         union { | ||||||
|             u32_le raw{}; |             u32_le raw{}; | ||||||
|             BitField<0, 1, u32_le> a; |             BitField<0, 1, u32> a; | ||||||
|             BitField<1, 1, u32_le> b; |             BitField<1, 1, u32> b; | ||||||
|             BitField<2, 1, u32_le> x; |             BitField<2, 1, u32> x; | ||||||
|             BitField<3, 1, u32_le> y; |             BitField<3, 1, u32> y; | ||||||
|             BitField<4, 1, u32_le> l; |             BitField<4, 1, u32> l; | ||||||
|             BitField<5, 1, u32_le> r; |             BitField<5, 1, u32> r; | ||||||
|             BitField<6, 1, u32_le> zl; |             BitField<6, 1, u32> zl; | ||||||
|             BitField<7, 1, u32_le> zr; |             BitField<7, 1, u32> zr; | ||||||
|             BitField<8, 1, u32_le> plus; |             BitField<8, 1, u32> plus; | ||||||
|             BitField<9, 1, u32_le> minus; |             BitField<9, 1, u32> minus; | ||||||
|             BitField<10, 1, u32_le> d_left; |             BitField<10, 1, u32> d_left; | ||||||
|             BitField<11, 1, u32_le> d_up; |             BitField<11, 1, u32> d_up; | ||||||
|             BitField<12, 1, u32_le> d_right; |             BitField<12, 1, u32> d_right; | ||||||
|             BitField<13, 1, u32_le> d_down; |             BitField<13, 1, u32> d_down; | ||||||
|         }; |         }; | ||||||
|     }; |     }; | ||||||
|     static_assert(sizeof(PadState) == 0x4, "PadState is an invalid size"); |     static_assert(sizeof(PadState) == 0x4, "PadState is an invalid size"); | ||||||
| @@ -62,7 +62,7 @@ private: | |||||||
|     struct Attributes { |     struct Attributes { | ||||||
|         union { |         union { | ||||||
|             u32_le raw{}; |             u32_le raw{}; | ||||||
|             BitField<0, 1, u32_le> connected; |             BitField<0, 1, u32> connected; | ||||||
|         }; |         }; | ||||||
|     }; |     }; | ||||||
|     static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); |     static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); | ||||||
|   | |||||||
| @@ -39,13 +39,13 @@ public: | |||||||
|         union { |         union { | ||||||
|             u32_le raw{}; |             u32_le raw{}; | ||||||
|  |  | ||||||
|             BitField<0, 1, u32_le> pro_controller; |             BitField<0, 1, u32> pro_controller; | ||||||
|             BitField<1, 1, u32_le> handheld; |             BitField<1, 1, u32> handheld; | ||||||
|             BitField<2, 1, u32_le> joycon_dual; |             BitField<2, 1, u32> joycon_dual; | ||||||
|             BitField<3, 1, u32_le> joycon_left; |             BitField<3, 1, u32> joycon_left; | ||||||
|             BitField<4, 1, u32_le> joycon_right; |             BitField<4, 1, u32> joycon_right; | ||||||
|  |  | ||||||
|             BitField<6, 1, u32_le> pokeball; // TODO(ogniK): Confirm when possible |             BitField<6, 1, u32> pokeball; // TODO(ogniK): Confirm when possible | ||||||
|         }; |         }; | ||||||
|     }; |     }; | ||||||
|     static_assert(sizeof(NPadType) == 4, "NPadType is an invalid size"); |     static_assert(sizeof(NPadType) == 4, "NPadType is an invalid size"); | ||||||
| @@ -150,43 +150,43 @@ private: | |||||||
|         union { |         union { | ||||||
|             u64_le raw{}; |             u64_le raw{}; | ||||||
|             // Button states |             // Button states | ||||||
|             BitField<0, 1, u64_le> a; |             BitField<0, 1, u64> a; | ||||||
|             BitField<1, 1, u64_le> b; |             BitField<1, 1, u64> b; | ||||||
|             BitField<2, 1, u64_le> x; |             BitField<2, 1, u64> x; | ||||||
|             BitField<3, 1, u64_le> y; |             BitField<3, 1, u64> y; | ||||||
|             BitField<4, 1, u64_le> l_stick; |             BitField<4, 1, u64> l_stick; | ||||||
|             BitField<5, 1, u64_le> r_stick; |             BitField<5, 1, u64> r_stick; | ||||||
|             BitField<6, 1, u64_le> l; |             BitField<6, 1, u64> l; | ||||||
|             BitField<7, 1, u64_le> r; |             BitField<7, 1, u64> r; | ||||||
|             BitField<8, 1, u64_le> zl; |             BitField<8, 1, u64> zl; | ||||||
|             BitField<9, 1, u64_le> zr; |             BitField<9, 1, u64> zr; | ||||||
|             BitField<10, 1, u64_le> plus; |             BitField<10, 1, u64> plus; | ||||||
|             BitField<11, 1, u64_le> minus; |             BitField<11, 1, u64> minus; | ||||||
|  |  | ||||||
|             // D-Pad |             // D-Pad | ||||||
|             BitField<12, 1, u64_le> d_left; |             BitField<12, 1, u64> d_left; | ||||||
|             BitField<13, 1, u64_le> d_up; |             BitField<13, 1, u64> d_up; | ||||||
|             BitField<14, 1, u64_le> d_right; |             BitField<14, 1, u64> d_right; | ||||||
|             BitField<15, 1, u64_le> d_down; |             BitField<15, 1, u64> d_down; | ||||||
|  |  | ||||||
|             // Left JoyStick |             // Left JoyStick | ||||||
|             BitField<16, 1, u64_le> l_stick_left; |             BitField<16, 1, u64> l_stick_left; | ||||||
|             BitField<17, 1, u64_le> l_stick_up; |             BitField<17, 1, u64> l_stick_up; | ||||||
|             BitField<18, 1, u64_le> l_stick_right; |             BitField<18, 1, u64> l_stick_right; | ||||||
|             BitField<19, 1, u64_le> l_stick_down; |             BitField<19, 1, u64> l_stick_down; | ||||||
|  |  | ||||||
|             // Right JoyStick |             // Right JoyStick | ||||||
|             BitField<20, 1, u64_le> r_stick_left; |             BitField<20, 1, u64> r_stick_left; | ||||||
|             BitField<21, 1, u64_le> r_stick_up; |             BitField<21, 1, u64> r_stick_up; | ||||||
|             BitField<22, 1, u64_le> r_stick_right; |             BitField<22, 1, u64> r_stick_right; | ||||||
|             BitField<23, 1, u64_le> r_stick_down; |             BitField<23, 1, u64> r_stick_down; | ||||||
|  |  | ||||||
|             // Not always active? |             // Not always active? | ||||||
|             BitField<24, 1, u64_le> left_sl; |             BitField<24, 1, u64> left_sl; | ||||||
|             BitField<25, 1, u64_le> left_sr; |             BitField<25, 1, u64> left_sr; | ||||||
|  |  | ||||||
|             BitField<26, 1, u64_le> right_sl; |             BitField<26, 1, u64> right_sl; | ||||||
|             BitField<27, 1, u64_le> right_sr; |             BitField<27, 1, u64> right_sr; | ||||||
|         }; |         }; | ||||||
|     }; |     }; | ||||||
|     static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size"); |     static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size"); | ||||||
| @@ -200,12 +200,12 @@ private: | |||||||
|     struct ConnectionState { |     struct ConnectionState { | ||||||
|         union { |         union { | ||||||
|             u32_le raw{}; |             u32_le raw{}; | ||||||
|             BitField<0, 1, u32_le> IsConnected; |             BitField<0, 1, u32> IsConnected; | ||||||
|             BitField<1, 1, u32_le> IsWired; |             BitField<1, 1, u32> IsWired; | ||||||
|             BitField<2, 1, u32_le> IsLeftJoyConnected; |             BitField<2, 1, u32> IsLeftJoyConnected; | ||||||
|             BitField<3, 1, u32_le> IsLeftJoyWired; |             BitField<3, 1, u32> IsLeftJoyWired; | ||||||
|             BitField<4, 1, u32_le> IsRightJoyConnected; |             BitField<4, 1, u32> IsRightJoyConnected; | ||||||
|             BitField<5, 1, u32_le> IsRightJoyWired; |             BitField<5, 1, u32> IsRightJoyWired; | ||||||
|         }; |         }; | ||||||
|     }; |     }; | ||||||
|     static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size"); |     static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size"); | ||||||
| @@ -240,23 +240,23 @@ private: | |||||||
|     struct NPadProperties { |     struct NPadProperties { | ||||||
|         union { |         union { | ||||||
|             s64_le raw{}; |             s64_le raw{}; | ||||||
|             BitField<11, 1, s64_le> is_vertical; |             BitField<11, 1, s64> is_vertical; | ||||||
|             BitField<12, 1, s64_le> is_horizontal; |             BitField<12, 1, s64> is_horizontal; | ||||||
|             BitField<13, 1, s64_le> use_plus; |             BitField<13, 1, s64> use_plus; | ||||||
|             BitField<14, 1, s64_le> use_minus; |             BitField<14, 1, s64> use_minus; | ||||||
|         }; |         }; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     struct NPadDevice { |     struct NPadDevice { | ||||||
|         union { |         union { | ||||||
|             u32_le raw{}; |             u32_le raw{}; | ||||||
|             BitField<0, 1, s32_le> pro_controller; |             BitField<0, 1, s32> pro_controller; | ||||||
|             BitField<1, 1, s32_le> handheld; |             BitField<1, 1, s32> handheld; | ||||||
|             BitField<2, 1, s32_le> handheld_left; |             BitField<2, 1, s32> handheld_left; | ||||||
|             BitField<3, 1, s32_le> handheld_right; |             BitField<3, 1, s32> handheld_right; | ||||||
|             BitField<4, 1, s32_le> joycon_left; |             BitField<4, 1, s32> joycon_left; | ||||||
|             BitField<5, 1, s32_le> joycon_right; |             BitField<5, 1, s32> joycon_right; | ||||||
|             BitField<6, 1, s32_le> pokeball; |             BitField<6, 1, s32> pokeball; | ||||||
|         }; |         }; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -33,8 +33,8 @@ private: | |||||||
|     struct Attributes { |     struct Attributes { | ||||||
|         union { |         union { | ||||||
|             u32 raw{}; |             u32 raw{}; | ||||||
|             BitField<0, 1, u32_le> start_touch; |             BitField<0, 1, u32> start_touch; | ||||||
|             BitField<1, 1, u32_le> end_touch; |             BitField<1, 1, u32> end_touch; | ||||||
|         }; |         }; | ||||||
|     }; |     }; | ||||||
|     static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); |     static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); | ||||||
|   | |||||||
| @@ -42,7 +42,7 @@ private: | |||||||
|         union { |         union { | ||||||
|             BitField<0, 16, Flags> flags; |             BitField<0, 16, Flags> flags; | ||||||
|             BitField<16, 8, Severity> severity; |             BitField<16, 8, Severity> severity; | ||||||
|             BitField<24, 8, u32_le> verbosity; |             BitField<24, 8, u32> verbosity; | ||||||
|         }; |         }; | ||||||
|         u32_le payload_size; |         u32_le payload_size; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,11 +19,11 @@ public: | |||||||
|     virtual ~nvdevice() = default; |     virtual ~nvdevice() = default; | ||||||
|     union Ioctl { |     union Ioctl { | ||||||
|         u32_le raw; |         u32_le raw; | ||||||
|         BitField<0, 8, u32_le> cmd; |         BitField<0, 8, u32> cmd; | ||||||
|         BitField<8, 8, u32_le> group; |         BitField<8, 8, u32> group; | ||||||
|         BitField<16, 14, u32_le> length; |         BitField<16, 14, u32> length; | ||||||
|         BitField<30, 1, u32_le> is_in; |         BitField<30, 1, u32> is_in; | ||||||
|         BitField<31, 1, u32_le> is_out; |         BitField<31, 1, u32> is_out; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| add_executable(tests | add_executable(tests | ||||||
|  |     common/bit_field.cpp | ||||||
|     common/param_package.cpp |     common/param_package.cpp | ||||||
|     common/ring_buffer.cpp |     common/ring_buffer.cpp | ||||||
|     core/arm/arm_test_common.cpp |     core/arm/arm_test_common.cpp | ||||||
|   | |||||||
							
								
								
									
										90
									
								
								src/tests/common/bit_field.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/tests/common/bit_field.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | |||||||
|  | // Copyright 2019 Citra Emulator Project | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #include <array> | ||||||
|  | #include <cstring> | ||||||
|  | #include <type_traits> | ||||||
|  | #include <catch2/catch.hpp> | ||||||
|  | #include "common/bit_field.h" | ||||||
|  |  | ||||||
|  | TEST_CASE("BitField", "[common]") { | ||||||
|  |     enum class TestEnum : u32 { | ||||||
|  |         A = 0b10111101, | ||||||
|  |         B = 0b10101110, | ||||||
|  |         C = 0b00001111, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     union LEBitField { | ||||||
|  |         u32_le raw; | ||||||
|  |         BitField<0, 6, u32> a; | ||||||
|  |         BitField<6, 4, s32> b; | ||||||
|  |         BitField<10, 8, TestEnum> c; | ||||||
|  |         BitField<18, 14, u32> d; | ||||||
|  |     } le_bitfield; | ||||||
|  |  | ||||||
|  |     union BEBitField { | ||||||
|  |         u32_be raw; | ||||||
|  |         BitFieldBE<0, 6, u32> a; | ||||||
|  |         BitFieldBE<6, 4, s32> b; | ||||||
|  |         BitFieldBE<10, 8, TestEnum> c; | ||||||
|  |         BitFieldBE<18, 14, u32> d; | ||||||
|  |     } be_bitfield; | ||||||
|  |  | ||||||
|  |     static_assert(sizeof(LEBitField) == sizeof(u32)); | ||||||
|  |     static_assert(sizeof(BEBitField) == sizeof(u32)); | ||||||
|  |     static_assert(std::is_trivially_copyable_v<LEBitField>); | ||||||
|  |     static_assert(std::is_trivially_copyable_v<BEBitField>); | ||||||
|  |  | ||||||
|  |     std::array<u8, 4> raw{{ | ||||||
|  |         0b01101100, | ||||||
|  |         0b11110110, | ||||||
|  |         0b10111010, | ||||||
|  |         0b11101100, | ||||||
|  |     }}; | ||||||
|  |  | ||||||
|  |     std::memcpy(&le_bitfield, &raw, sizeof(raw)); | ||||||
|  |     std::memcpy(&be_bitfield, &raw, sizeof(raw)); | ||||||
|  |  | ||||||
|  |     // bit fields: 11101100101110'10111101'1001'101100 | ||||||
|  |     REQUIRE(le_bitfield.raw == 0b11101100'10111010'11110110'01101100); | ||||||
|  |     REQUIRE(le_bitfield.a == 0b101100); | ||||||
|  |     REQUIRE(le_bitfield.b == -7); // 1001 as two's complement | ||||||
|  |     REQUIRE(le_bitfield.c == TestEnum::A); | ||||||
|  |     REQUIRE(le_bitfield.d == 0b11101100101110); | ||||||
|  |  | ||||||
|  |     le_bitfield.a.Assign(0b000111); | ||||||
|  |     le_bitfield.b.Assign(-1); | ||||||
|  |     le_bitfield.c.Assign(TestEnum::C); | ||||||
|  |     le_bitfield.d.Assign(0b01010101010101); | ||||||
|  |     std::memcpy(&raw, &le_bitfield, sizeof(raw)); | ||||||
|  |     // bit fields: 01010101010101'00001111'1111'000111 | ||||||
|  |     REQUIRE(le_bitfield.raw == 0b01010101'01010100'00111111'11000111); | ||||||
|  |     REQUIRE(raw == std::array<u8, 4>{{ | ||||||
|  |                        0b11000111, | ||||||
|  |                        0b00111111, | ||||||
|  |                        0b01010100, | ||||||
|  |                        0b01010101, | ||||||
|  |                    }}); | ||||||
|  |  | ||||||
|  |     // bit fields: 01101100111101'10101110'1011'101100 | ||||||
|  |     REQUIRE(be_bitfield.raw == 0b01101100'11110110'10111010'11101100); | ||||||
|  |     REQUIRE(be_bitfield.a == 0b101100); | ||||||
|  |     REQUIRE(be_bitfield.b == -5); // 1011 as two's complement | ||||||
|  |     REQUIRE(be_bitfield.c == TestEnum::B); | ||||||
|  |     REQUIRE(be_bitfield.d == 0b01101100111101); | ||||||
|  |  | ||||||
|  |     be_bitfield.a.Assign(0b000111); | ||||||
|  |     be_bitfield.b.Assign(-1); | ||||||
|  |     be_bitfield.c.Assign(TestEnum::C); | ||||||
|  |     be_bitfield.d.Assign(0b01010101010101); | ||||||
|  |     std::memcpy(&raw, &be_bitfield, sizeof(raw)); | ||||||
|  |     // bit fields: 01010101010101'00001111'1111'000111 | ||||||
|  |     REQUIRE(be_bitfield.raw == 0b01010101'01010100'00111111'11000111); | ||||||
|  |     REQUIRE(raw == std::array<u8, 4>{{ | ||||||
|  |                        0b01010101, | ||||||
|  |                        0b01010100, | ||||||
|  |                        0b00111111, | ||||||
|  |                        0b11000111, | ||||||
|  |                    }}); | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user