mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Merge pull request #4599 from wwylele/bitfield-endian
Common: make BitField endianness-aware
This commit is contained in:
		
						commit
						f78512d6de
					
				
					 11 changed files with 306 additions and 157 deletions
				
			
		|  | @ -126,29 +126,29 @@ struct SourceConfiguration { | |||
|         union { | ||||
|             u32_le dirty_raw; | ||||
| 
 | ||||
|             BitField<0, 1, u32_le> format_dirty; | ||||
|             BitField<1, 1, u32_le> mono_or_stereo_dirty; | ||||
|             BitField<2, 1, u32_le> adpcm_coefficients_dirty; | ||||
|             BitField<0, 1, u32> format_dirty; | ||||
|             BitField<1, 1, u32> mono_or_stereo_dirty; | ||||
|             BitField<2, 1, u32> adpcm_coefficients_dirty; | ||||
|             /// Tends to be set when a looped buffer is queued.
 | ||||
|             BitField<3, 1, u32_le> partial_embedded_buffer_dirty; | ||||
|             BitField<4, 1, u32_le> partial_reset_flag; | ||||
|             BitField<3, 1, u32> partial_embedded_buffer_dirty; | ||||
|             BitField<4, 1, u32> partial_reset_flag; | ||||
| 
 | ||||
|             BitField<16, 1, u32_le> enable_dirty; | ||||
|             BitField<17, 1, u32_le> interpolation_dirty; | ||||
|             BitField<18, 1, u32_le> rate_multiplier_dirty; | ||||
|             BitField<19, 1, u32_le> buffer_queue_dirty; | ||||
|             BitField<20, 1, u32_le> loop_related_dirty; | ||||
|             BitField<16, 1, u32> enable_dirty; | ||||
|             BitField<17, 1, u32> interpolation_dirty; | ||||
|             BitField<18, 1, u32> rate_multiplier_dirty; | ||||
|             BitField<19, 1, u32> buffer_queue_dirty; | ||||
|             BitField<20, 1, u32> loop_related_dirty; | ||||
|             /// Tends to also be set when embedded buffer is updated.
 | ||||
|             BitField<21, 1, u32_le> play_position_dirty; | ||||
|             BitField<22, 1, u32_le> filters_enabled_dirty; | ||||
|             BitField<23, 1, u32_le> simple_filter_dirty; | ||||
|             BitField<24, 1, u32_le> biquad_filter_dirty; | ||||
|             BitField<25, 1, u32_le> gain_0_dirty; | ||||
|             BitField<26, 1, u32_le> gain_1_dirty; | ||||
|             BitField<27, 1, u32_le> gain_2_dirty; | ||||
|             BitField<28, 1, u32_le> sync_dirty; | ||||
|             BitField<29, 1, u32_le> reset_flag; | ||||
|             BitField<30, 1, u32_le> embedded_buffer_dirty; | ||||
|             BitField<21, 1, u32> play_position_dirty; | ||||
|             BitField<22, 1, u32> filters_enabled_dirty; | ||||
|             BitField<23, 1, u32> simple_filter_dirty; | ||||
|             BitField<24, 1, u32> biquad_filter_dirty; | ||||
|             BitField<25, 1, u32> gain_0_dirty; | ||||
|             BitField<26, 1, u32> gain_1_dirty; | ||||
|             BitField<27, 1, u32> gain_2_dirty; | ||||
|             BitField<28, 1, u32> sync_dirty; | ||||
|             BitField<29, 1, u32> reset_flag; | ||||
|             BitField<30, 1, u32> embedded_buffer_dirty; | ||||
|         }; | ||||
| 
 | ||||
|         // Gain control
 | ||||
|  | @ -206,8 +206,8 @@ struct SourceConfiguration { | |||
| 
 | ||||
|         union { | ||||
|             u16_le filters_enabled; | ||||
|             BitField<0, 1, u16_le> simple_filter_enabled; | ||||
|             BitField<1, 1, u16_le> biquad_filter_enabled; | ||||
|             BitField<0, 1, u16> simple_filter_enabled; | ||||
|             BitField<1, 1, u16> biquad_filter_enabled; | ||||
|         }; | ||||
| 
 | ||||
|         SimpleFilter simple_filter; | ||||
|  | @ -227,8 +227,8 @@ struct SourceConfiguration { | |||
|             /// ADPCM Predictor (4 bits) and Scale (4 bits)
 | ||||
|             union { | ||||
|                 u16_le adpcm_ps; | ||||
|                 BitField<0, 4, u16_le> adpcm_scale; | ||||
|                 BitField<4, 4, u16_le> adpcm_predictor; | ||||
|                 BitField<0, 4, u16> adpcm_scale; | ||||
|                 BitField<4, 4, u16> adpcm_predictor; | ||||
|             }; | ||||
| 
 | ||||
|             /// ADPCM Historical Samples (y[n-1] and y[n-2])
 | ||||
|  | @ -285,14 +285,14 @@ struct SourceConfiguration { | |||
|             u16_le flags1_raw; | ||||
|             BitField<0, 2, MonoOrStereo> mono_or_stereo; | ||||
|             BitField<2, 2, Format> format; | ||||
|             BitField<5, 1, u16_le> fade_in; | ||||
|             BitField<5, 1, u16> fade_in; | ||||
|         }; | ||||
| 
 | ||||
|         /// ADPCM Predictor (4 bit) and Scale (4 bit)
 | ||||
|         union { | ||||
|             u16_le adpcm_ps; | ||||
|             BitField<0, 4, u16_le> adpcm_scale; | ||||
|             BitField<4, 4, u16_le> adpcm_predictor; | ||||
|             BitField<0, 4, u16> adpcm_scale; | ||||
|             BitField<4, 4, u16> adpcm_predictor; | ||||
|         }; | ||||
| 
 | ||||
|         /// ADPCM Historical Samples (y[n-1] and y[n-2])
 | ||||
|  | @ -300,8 +300,8 @@ struct SourceConfiguration { | |||
| 
 | ||||
|         union { | ||||
|             u16_le flags2_raw; | ||||
|             BitField<0, 1, u16_le> adpcm_dirty; ///< Has the ADPCM info above been changed?
 | ||||
|             BitField<1, 1, u16_le> is_looping;  ///< Is this a looping buffer?
 | ||||
|             BitField<0, 1, u16> adpcm_dirty; ///< Has the ADPCM info above been changed?
 | ||||
|             BitField<1, 1, u16> is_looping;  ///< Is this a looping buffer?
 | ||||
|         }; | ||||
| 
 | ||||
|         /// Buffer id of embedded buffer (used as a buffer id in SourceStatus to reference this
 | ||||
|  | @ -334,20 +334,20 @@ struct DspConfiguration { | |||
|     union { | ||||
|         u32_le dirty_raw; | ||||
| 
 | ||||
|         BitField<8, 1, u32_le> mixer1_enabled_dirty; | ||||
|         BitField<9, 1, u32_le> mixer2_enabled_dirty; | ||||
|         BitField<10, 1, u32_le> delay_effect_0_dirty; | ||||
|         BitField<11, 1, u32_le> delay_effect_1_dirty; | ||||
|         BitField<12, 1, u32_le> reverb_effect_0_dirty; | ||||
|         BitField<13, 1, u32_le> reverb_effect_1_dirty; | ||||
|         BitField<8, 1, u32> mixer1_enabled_dirty; | ||||
|         BitField<9, 1, u32> mixer2_enabled_dirty; | ||||
|         BitField<10, 1, u32> delay_effect_0_dirty; | ||||
|         BitField<11, 1, u32> delay_effect_1_dirty; | ||||
|         BitField<12, 1, u32> reverb_effect_0_dirty; | ||||
|         BitField<13, 1, u32> reverb_effect_1_dirty; | ||||
| 
 | ||||
|         BitField<16, 1, u32_le> volume_0_dirty; | ||||
|         BitField<16, 1, u32> volume_0_dirty; | ||||
| 
 | ||||
|         BitField<24, 1, u32_le> volume_1_dirty; | ||||
|         BitField<25, 1, u32_le> volume_2_dirty; | ||||
|         BitField<26, 1, u32_le> output_format_dirty; | ||||
|         BitField<27, 1, u32_le> limiter_enabled_dirty; | ||||
|         BitField<28, 1, u32_le> headphones_connected_dirty; | ||||
|         BitField<24, 1, u32> volume_1_dirty; | ||||
|         BitField<25, 1, u32> volume_2_dirty; | ||||
|         BitField<26, 1, u32> output_format_dirty; | ||||
|         BitField<27, 1, u32> limiter_enabled_dirty; | ||||
|         BitField<28, 1, u32> headphones_connected_dirty; | ||||
|     }; | ||||
| 
 | ||||
|     /// The DSP has three intermediate audio mixers. This controls the volume level (0.0-1.0) for
 | ||||
|  | @ -384,9 +384,9 @@ struct DspConfiguration { | |||
|         /// The DSP clears these each audio frame.
 | ||||
|         union { | ||||
|             u16_le dirty_raw; | ||||
|             BitField<0, 1, u16_le> enable_dirty; | ||||
|             BitField<1, 1, u16_le> work_buffer_address_dirty; | ||||
|             BitField<2, 1, u16_le> other_dirty; ///< Set when anything else has been changed
 | ||||
|             BitField<0, 1, u16> enable_dirty; | ||||
|             BitField<1, 1, u16> work_buffer_address_dirty; | ||||
|             BitField<2, 1, u16> other_dirty; ///< Set when anything else has been changed
 | ||||
|         }; | ||||
| 
 | ||||
|         u16_le enable; | ||||
|  |  | |||
|  | @ -34,6 +34,7 @@ | |||
| #include <limits> | ||||
| #include <type_traits> | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/swap.h" | ||||
| 
 | ||||
| /*
 | ||||
|  * Abstract bitfield class | ||||
|  | @ -108,7 +109,7 @@ | |||
|  * symptoms. | ||||
|  */ | ||||
| #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 { | ||||
| private: | ||||
|     // UnderlyingType is T for non-enum types and the underlying type of T if
 | ||||
|  | @ -121,6 +122,8 @@ private: | |||
|     // We store the value as the unsigned type to avoid undefined behaviour on value shifting
 | ||||
|     using StorageType = std::make_unsigned_t<UnderlyingType>; | ||||
| 
 | ||||
|     using StorageTypeWithEndian = typename AddEndian<StorageType, EndianTag>::type; | ||||
| 
 | ||||
| public: | ||||
|     BitField& operator=(const BitField&) = default; | ||||
| 
 | ||||
|  | @ -168,7 +171,7 @@ public: | |||
|     } | ||||
| 
 | ||||
|     FORCE_INLINE void Assign(const T& value) { | ||||
|         storage = (storage & ~mask) | FormatValue(value); | ||||
|         storage = (static_cast<StorageType>(storage) & ~mask) | FormatValue(value); | ||||
|     } | ||||
| 
 | ||||
|     FORCE_INLINE T Value() const { | ||||
|  | @ -180,7 +183,7 @@ public: | |||
|     } | ||||
| 
 | ||||
| private: | ||||
|     StorageType storage; | ||||
|     StorageTypeWithEndian storage; | ||||
| 
 | ||||
|     static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); | ||||
| 
 | ||||
|  | @ -196,3 +199,6 @@ private: | |||
| static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value, | ||||
|               "BitField must be trivially copyable"); | ||||
| #endif | ||||
| 
 | ||||
| template <std::size_t Position, std::size_t Bits, typename T> | ||||
| using BitFieldBE = BitField<Position, Bits, T, BETag>; | ||||
|  |  | |||
|  | @ -172,7 +172,7 @@ struct swap_struct_t { | |||
|     using swapped_t = swap_struct_t; | ||||
| 
 | ||||
| protected: | ||||
|     T value = T(); | ||||
|     T value; | ||||
| 
 | ||||
|     static T swap(T v) { | ||||
|         return F::swap(v); | ||||
|  | @ -645,64 +645,116 @@ protected: | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| 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 | ||||
| using u16_le = u16; | ||||
| using u32_le = u32; | ||||
| using u64_le = u64; | ||||
| 
 | ||||
| using s16_le = s16; | ||||
| using s32_le = s32; | ||||
| using s64_le = s64; | ||||
| using LETag = KeepTag; | ||||
| using BETag = SwapTag; | ||||
| 
 | ||||
| template <typename T> | ||||
| using enum_le = std::enable_if_t<std::is_enum_v<T>, T>; | ||||
| 
 | ||||
| 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>>; | ||||
| 
 | ||||
| template <typename T> | ||||
| using enum_be = swap_enum_t<T>; | ||||
| 
 | ||||
| using float_be = swap_struct_t<float, swap_float_t<float>>; | ||||
| using double_be = swap_struct_t<double, swap_double_t<double>>; | ||||
| #else | ||||
| 
 | ||||
| using u64_le = swap_struct_t<u64, swap_64_t<u64>>; | ||||
| using s64_le = swap_struct_t<s64, swap_64_t<s64>>; | ||||
| 
 | ||||
| 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>>; | ||||
| 
 | ||||
| template <typename T> | ||||
| using enum_le = swap_enum_t<T>; | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
| template <typename T> | ||||
| using enum_be = std::enable_if_t<std::is_enum_v<T>, T>; | ||||
| 
 | ||||
| using float_be = float; | ||||
| using double_be = double; | ||||
| using BETag = KeepTag; | ||||
| using LETag = SwapTag; | ||||
| 
 | ||||
| #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; | ||||
|  |  | |||
|  | @ -129,18 +129,18 @@ struct ExHeader_StorageInfo { | |||
|         u64_le ext_save_data_id; | ||||
|         // When using extended savedata access
 | ||||
|         // Prefer the ID specified in the most significant bits
 | ||||
|         BitField<40, 20, u64_le> extdata_id3; | ||||
|         BitField<20, 20, u64_le> extdata_id4; | ||||
|         BitField<0, 20, u64_le> extdata_id5; | ||||
|         BitField<40, 20, u64> extdata_id3; | ||||
|         BitField<20, 20, u64> extdata_id4; | ||||
|         BitField<0, 20, u64> extdata_id5; | ||||
|     }; | ||||
|     u8 system_save_data_id[8]; | ||||
|     union { | ||||
|         u64_le storage_accessible_unique_ids; | ||||
|         // When using extended savedata access
 | ||||
|         // Prefer the ID specified in the most significant bits
 | ||||
|         BitField<40, 20, u64_le> extdata_id0; | ||||
|         BitField<20, 20, u64_le> extdata_id1; | ||||
|         BitField<0, 20, u64_le> extdata_id2; | ||||
|         BitField<40, 20, u64> extdata_id0; | ||||
|         BitField<20, 20, u64> extdata_id1; | ||||
|         BitField<0, 20, u64> extdata_id2; | ||||
|     }; | ||||
|     u8 access_info[7]; | ||||
|     u8 other_attributes; | ||||
|  |  | |||
|  | @ -19,9 +19,9 @@ namespace Service::IR { | |||
| 
 | ||||
| struct ExtraHIDResponse { | ||||
|     union { | ||||
|         BitField<0, 8, u32_le> header; | ||||
|         BitField<8, 12, u32_le> c_stick_x; | ||||
|         BitField<20, 12, u32_le> c_stick_y; | ||||
|         BitField<0, 8, u32> header; | ||||
|         BitField<8, 12, u32> c_stick_x; | ||||
|         BitField<20, 12, u32> c_stick_y; | ||||
|     } c_stick; | ||||
|     union { | ||||
|         BitField<0, 5, u8> battery_level; | ||||
|  |  | |||
|  | @ -27,13 +27,13 @@ namespace Service::IR { | |||
| union PadState { | ||||
|     u32_le hex{}; | ||||
| 
 | ||||
|     BitField<14, 1, u32_le> zl; | ||||
|     BitField<15, 1, u32_le> zr; | ||||
|     BitField<14, 1, u32> zl; | ||||
|     BitField<15, 1, u32> zr; | ||||
| 
 | ||||
|     BitField<24, 1, u32_le> c_stick_right; | ||||
|     BitField<25, 1, u32_le> c_stick_left; | ||||
|     BitField<26, 1, u32_le> c_stick_up; | ||||
|     BitField<27, 1, u32_le> c_stick_down; | ||||
|     BitField<24, 1, u32> c_stick_right; | ||||
|     BitField<25, 1, u32> c_stick_left; | ||||
|     BitField<26, 1, u32> c_stick_up; | ||||
|     BitField<27, 1, u32> c_stick_down; | ||||
| }; | ||||
| 
 | ||||
| /// Interface to "ir:rst" service
 | ||||
|  |  | |||
|  | @ -231,8 +231,8 @@ private: | |||
|      */ | ||||
|     union SegmentTag { | ||||
|         u32_le raw; | ||||
|         BitField<0, 4, u32_le> segment_index; | ||||
|         BitField<4, 28, u32_le> offset_into_segment; | ||||
|         BitField<0, 4, u32> segment_index; | ||||
|         BitField<4, 28, u32> offset_into_segment; | ||||
| 
 | ||||
|         SegmentTag() = default; | ||||
|         explicit SegmentTag(u32 raw_) : raw(raw_) {} | ||||
|  | @ -270,8 +270,8 @@ private: | |||
|         u16_le test_bit; // bit address into the name to test
 | ||||
|         union Child { | ||||
|             u16_le raw; | ||||
|             BitField<0, 15, u16_le> next_index; | ||||
|             BitField<15, 1, u16_le> is_end; | ||||
|             BitField<0, 15, u16> next_index; | ||||
|             BitField<15, 1, u16> is_end; | ||||
|         } left, right; | ||||
|         u16_le export_table_index; // index of an ExportNamedSymbolEntry
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -45,20 +45,20 @@ struct ControllerState { | |||
|             union { | ||||
|                 u16_le hex; | ||||
| 
 | ||||
|                 BitField<0, 1, u16_le> a; | ||||
|                 BitField<1, 1, u16_le> b; | ||||
|                 BitField<2, 1, u16_le> select; | ||||
|                 BitField<3, 1, u16_le> start; | ||||
|                 BitField<4, 1, u16_le> right; | ||||
|                 BitField<5, 1, u16_le> left; | ||||
|                 BitField<6, 1, u16_le> up; | ||||
|                 BitField<7, 1, u16_le> down; | ||||
|                 BitField<8, 1, u16_le> r; | ||||
|                 BitField<9, 1, u16_le> l; | ||||
|                 BitField<10, 1, u16_le> x; | ||||
|                 BitField<11, 1, u16_le> y; | ||||
|                 BitField<12, 1, u16_le> debug; | ||||
|                 BitField<13, 1, u16_le> gpio14; | ||||
|                 BitField<0, 1, u16> a; | ||||
|                 BitField<1, 1, u16> b; | ||||
|                 BitField<2, 1, u16> select; | ||||
|                 BitField<3, 1, u16> start; | ||||
|                 BitField<4, 1, u16> right; | ||||
|                 BitField<5, 1, u16> left; | ||||
|                 BitField<6, 1, u16> up; | ||||
|                 BitField<7, 1, u16> down; | ||||
|                 BitField<8, 1, u16> r; | ||||
|                 BitField<9, 1, u16> l; | ||||
|                 BitField<10, 1, u16> x; | ||||
|                 BitField<11, 1, u16> y; | ||||
|                 BitField<12, 1, u16> debug; | ||||
|                 BitField<13, 1, u16> gpio14; | ||||
|                 // Bits 14-15 are currently unused
 | ||||
|             }; | ||||
|             s16_le circle_pad_x; | ||||
|  | @ -96,12 +96,12 @@ struct ControllerState { | |||
|             union { | ||||
|                 u32_le hex; | ||||
| 
 | ||||
|                 BitField<0, 5, u32_le> battery_level; | ||||
|                 BitField<5, 1, u32_le> zl_not_held; | ||||
|                 BitField<6, 1, u32_le> zr_not_held; | ||||
|                 BitField<7, 1, u32_le> r_not_held; | ||||
|                 BitField<8, 12, u32_le> c_stick_x; | ||||
|                 BitField<20, 12, u32_le> c_stick_y; | ||||
|                 BitField<0, 5, u32> battery_level; | ||||
|                 BitField<5, 1, u32> zl_not_held; | ||||
|                 BitField<6, 1, u32> zr_not_held; | ||||
|                 BitField<7, 1, u32> r_not_held; | ||||
|                 BitField<8, 12, u32> c_stick_x; | ||||
|                 BitField<20, 12, u32> c_stick_y; | ||||
|             }; | ||||
|         } extra_hid_response; | ||||
|     }; | ||||
|  |  | |||
|  | @ -141,22 +141,22 @@ struct PadData { | |||
|     // The following union isn't trivially copyable but we don't use this input anyway.
 | ||||
|     // union DigitalButton {
 | ||||
|     //     u16_le button;
 | ||||
|     //     BitField<0, 1, u16_le> button_1;   // Share
 | ||||
|     //     BitField<1, 1, u16_le> button_2;   // L3
 | ||||
|     //     BitField<2, 1, u16_le> button_3;   // R3
 | ||||
|     //     BitField<3, 1, u16_le> button_4;   // Options
 | ||||
|     //     BitField<4, 1, u16_le> button_5;   // Up
 | ||||
|     //     BitField<5, 1, u16_le> button_6;   // Right
 | ||||
|     //     BitField<6, 1, u16_le> button_7;   // Down
 | ||||
|     //     BitField<7, 1, u16_le> button_8;   // Left
 | ||||
|     //     BitField<8, 1, u16_le> button_9;   // L2
 | ||||
|     //     BitField<9, 1, u16_le> button_10;  // R2
 | ||||
|     //     BitField<10, 1, u16_le> button_11; // L1
 | ||||
|     //     BitField<11, 1, u16_le> button_12; // R1
 | ||||
|     //     BitField<12, 1, u16_le> button_13; // Triangle
 | ||||
|     //     BitField<13, 1, u16_le> button_14; // Circle
 | ||||
|     //     BitField<14, 1, u16_le> button_15; // Cross
 | ||||
|     //     BitField<15, 1, u16_le> button_16; // Square
 | ||||
|     //     BitField<0, 1, u16> button_1;   // Share
 | ||||
|     //     BitField<1, 1, u16> button_2;   // L3
 | ||||
|     //     BitField<2, 1, u16> button_3;   // R3
 | ||||
|     //     BitField<3, 1, u16> button_4;   // Options
 | ||||
|     //     BitField<4, 1, u16> button_5;   // Up
 | ||||
|     //     BitField<5, 1, u16> button_6;   // Right
 | ||||
|     //     BitField<6, 1, u16> button_7;   // Down
 | ||||
|     //     BitField<7, 1, u16> button_8;   // Left
 | ||||
|     //     BitField<8, 1, u16> button_9;   // L2
 | ||||
|     //     BitField<9, 1, u16> button_10;  // R2
 | ||||
|     //     BitField<10, 1, u16> button_11; // L1
 | ||||
|     //     BitField<11, 1, u16> button_12; // R1
 | ||||
|     //     BitField<12, 1, u16> button_13; // Triangle
 | ||||
|     //     BitField<13, 1, u16> button_14; // Circle
 | ||||
|     //     BitField<14, 1, u16> button_15; // Cross
 | ||||
|     //     BitField<15, 1, u16> button_16; // Square
 | ||||
|     // } digital_button;
 | ||||
| 
 | ||||
|     u8 home; | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| add_executable(tests | ||||
|     common/bit_field.cpp | ||||
|     common/param_package.cpp | ||||
|     core/arm/arm_test_common.cpp | ||||
|     core/arm/arm_test_common.h | ||||
|  |  | |||
							
								
								
									
										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, | ||||
|                    }}); | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue