mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +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 { |         union { | ||||||
|             u32_le dirty_raw; |             u32_le dirty_raw; | ||||||
| 
 | 
 | ||||||
|             BitField<0, 1, u32_le> format_dirty; |             BitField<0, 1, u32> format_dirty; | ||||||
|             BitField<1, 1, u32_le> mono_or_stereo_dirty; |             BitField<1, 1, u32> mono_or_stereo_dirty; | ||||||
|             BitField<2, 1, u32_le> adpcm_coefficients_dirty; |             BitField<2, 1, u32> adpcm_coefficients_dirty; | ||||||
|             /// Tends to be set when a looped buffer is queued.
 |             /// Tends to be set when a looped buffer is queued.
 | ||||||
|             BitField<3, 1, u32_le> partial_embedded_buffer_dirty; |             BitField<3, 1, u32> partial_embedded_buffer_dirty; | ||||||
|             BitField<4, 1, u32_le> partial_reset_flag; |             BitField<4, 1, u32> partial_reset_flag; | ||||||
| 
 | 
 | ||||||
|             BitField<16, 1, u32_le> enable_dirty; |             BitField<16, 1, u32> enable_dirty; | ||||||
|             BitField<17, 1, u32_le> interpolation_dirty; |             BitField<17, 1, u32> interpolation_dirty; | ||||||
|             BitField<18, 1, u32_le> rate_multiplier_dirty; |             BitField<18, 1, u32> rate_multiplier_dirty; | ||||||
|             BitField<19, 1, u32_le> buffer_queue_dirty; |             BitField<19, 1, u32> buffer_queue_dirty; | ||||||
|             BitField<20, 1, u32_le> loop_related_dirty; |             BitField<20, 1, u32> loop_related_dirty; | ||||||
|             /// Tends to also be set when embedded buffer is updated.
 |             /// Tends to also be set when embedded buffer is updated.
 | ||||||
|             BitField<21, 1, u32_le> play_position_dirty; |             BitField<21, 1, u32> play_position_dirty; | ||||||
|             BitField<22, 1, u32_le> filters_enabled_dirty; |             BitField<22, 1, u32> filters_enabled_dirty; | ||||||
|             BitField<23, 1, u32_le> simple_filter_dirty; |             BitField<23, 1, u32> simple_filter_dirty; | ||||||
|             BitField<24, 1, u32_le> biquad_filter_dirty; |             BitField<24, 1, u32> biquad_filter_dirty; | ||||||
|             BitField<25, 1, u32_le> gain_0_dirty; |             BitField<25, 1, u32> gain_0_dirty; | ||||||
|             BitField<26, 1, u32_le> gain_1_dirty; |             BitField<26, 1, u32> gain_1_dirty; | ||||||
|             BitField<27, 1, u32_le> gain_2_dirty; |             BitField<27, 1, u32> gain_2_dirty; | ||||||
|             BitField<28, 1, u32_le> sync_dirty; |             BitField<28, 1, u32> sync_dirty; | ||||||
|             BitField<29, 1, u32_le> reset_flag; |             BitField<29, 1, u32> reset_flag; | ||||||
|             BitField<30, 1, u32_le> embedded_buffer_dirty; |             BitField<30, 1, u32> embedded_buffer_dirty; | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         // Gain control
 |         // Gain control
 | ||||||
|  | @ -206,8 +206,8 @@ struct SourceConfiguration { | ||||||
| 
 | 
 | ||||||
|         union { |         union { | ||||||
|             u16_le filters_enabled; |             u16_le filters_enabled; | ||||||
|             BitField<0, 1, u16_le> simple_filter_enabled; |             BitField<0, 1, u16> simple_filter_enabled; | ||||||
|             BitField<1, 1, u16_le> biquad_filter_enabled; |             BitField<1, 1, u16> biquad_filter_enabled; | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         SimpleFilter simple_filter; |         SimpleFilter simple_filter; | ||||||
|  | @ -227,8 +227,8 @@ struct SourceConfiguration { | ||||||
|             /// ADPCM Predictor (4 bits) and Scale (4 bits)
 |             /// ADPCM Predictor (4 bits) and Scale (4 bits)
 | ||||||
|             union { |             union { | ||||||
|                 u16_le adpcm_ps; |                 u16_le adpcm_ps; | ||||||
|                 BitField<0, 4, u16_le> adpcm_scale; |                 BitField<0, 4, u16> adpcm_scale; | ||||||
|                 BitField<4, 4, u16_le> adpcm_predictor; |                 BitField<4, 4, u16> adpcm_predictor; | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|             /// ADPCM Historical Samples (y[n-1] and y[n-2])
 |             /// ADPCM Historical Samples (y[n-1] and y[n-2])
 | ||||||
|  | @ -285,14 +285,14 @@ struct SourceConfiguration { | ||||||
|             u16_le flags1_raw; |             u16_le flags1_raw; | ||||||
|             BitField<0, 2, MonoOrStereo> mono_or_stereo; |             BitField<0, 2, MonoOrStereo> mono_or_stereo; | ||||||
|             BitField<2, 2, Format> format; |             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)
 |         /// ADPCM Predictor (4 bit) and Scale (4 bit)
 | ||||||
|         union { |         union { | ||||||
|             u16_le adpcm_ps; |             u16_le adpcm_ps; | ||||||
|             BitField<0, 4, u16_le> adpcm_scale; |             BitField<0, 4, u16> adpcm_scale; | ||||||
|             BitField<4, 4, u16_le> adpcm_predictor; |             BitField<4, 4, u16> adpcm_predictor; | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         /// ADPCM Historical Samples (y[n-1] and y[n-2])
 |         /// ADPCM Historical Samples (y[n-1] and y[n-2])
 | ||||||
|  | @ -300,8 +300,8 @@ struct SourceConfiguration { | ||||||
| 
 | 
 | ||||||
|         union { |         union { | ||||||
|             u16_le flags2_raw; |             u16_le flags2_raw; | ||||||
|             BitField<0, 1, u16_le> adpcm_dirty; ///< Has the ADPCM info above been changed?
 |             BitField<0, 1, u16> adpcm_dirty; ///< Has the ADPCM info above been changed?
 | ||||||
|             BitField<1, 1, u16_le> is_looping;  ///< Is this a looping buffer?
 |             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
 |         /// Buffer id of embedded buffer (used as a buffer id in SourceStatus to reference this
 | ||||||
|  | @ -334,20 +334,20 @@ struct DspConfiguration { | ||||||
|     union { |     union { | ||||||
|         u32_le dirty_raw; |         u32_le dirty_raw; | ||||||
| 
 | 
 | ||||||
|         BitField<8, 1, u32_le> mixer1_enabled_dirty; |         BitField<8, 1, u32> mixer1_enabled_dirty; | ||||||
|         BitField<9, 1, u32_le> mixer2_enabled_dirty; |         BitField<9, 1, u32> mixer2_enabled_dirty; | ||||||
|         BitField<10, 1, u32_le> delay_effect_0_dirty; |         BitField<10, 1, u32> delay_effect_0_dirty; | ||||||
|         BitField<11, 1, u32_le> delay_effect_1_dirty; |         BitField<11, 1, u32> delay_effect_1_dirty; | ||||||
|         BitField<12, 1, u32_le> reverb_effect_0_dirty; |         BitField<12, 1, u32> reverb_effect_0_dirty; | ||||||
|         BitField<13, 1, u32_le> reverb_effect_1_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<24, 1, u32> volume_1_dirty; | ||||||
|         BitField<25, 1, u32_le> volume_2_dirty; |         BitField<25, 1, u32> volume_2_dirty; | ||||||
|         BitField<26, 1, u32_le> output_format_dirty; |         BitField<26, 1, u32> output_format_dirty; | ||||||
|         BitField<27, 1, u32_le> limiter_enabled_dirty; |         BitField<27, 1, u32> limiter_enabled_dirty; | ||||||
|         BitField<28, 1, u32_le> headphones_connected_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
 |     /// 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.
 |         /// The DSP clears these each audio frame.
 | ||||||
|         union { |         union { | ||||||
|             u16_le dirty_raw; |             u16_le dirty_raw; | ||||||
|             BitField<0, 1, u16_le> enable_dirty; |             BitField<0, 1, u16> enable_dirty; | ||||||
|             BitField<1, 1, u16_le> work_buffer_address_dirty; |             BitField<1, 1, u16> work_buffer_address_dirty; | ||||||
|             BitField<2, 1, u16_le> other_dirty; ///< Set when anything else has been changed
 |             BitField<2, 1, u16> other_dirty; ///< Set when anything else has been changed
 | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         u16_le enable; |         u16_le enable; | ||||||
|  |  | ||||||
|  | @ -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,6 +122,8 @@ 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; |     BitField& operator=(const BitField&) = default; | ||||||
| 
 | 
 | ||||||
|  | @ -168,7 +171,7 @@ public: | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     FORCE_INLINE void Assign(const T& value) { |     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 { |     FORCE_INLINE T Value() const { | ||||||
|  | @ -180,7 +183,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"); | ||||||
| 
 | 
 | ||||||
|  | @ -196,3 +199,6 @@ private: | ||||||
| static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value, | static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value, | ||||||
|               "BitField must be trivially copyable"); |               "BitField must be trivially copyable"); | ||||||
| #endif | #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; |     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); | ||||||
|  | @ -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 | #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; |  | ||||||
| 
 | 
 | ||||||
| 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 | #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>>; |  | ||||||
| 
 |  | ||||||
| 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; |  | ||||||
| 
 | 
 | ||||||
| #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; | ||||||
|  |  | ||||||
|  | @ -129,18 +129,18 @@ struct ExHeader_StorageInfo { | ||||||
|         u64_le ext_save_data_id; |         u64_le ext_save_data_id; | ||||||
|         // When using extended savedata access
 |         // When using extended savedata access
 | ||||||
|         // Prefer the ID specified in the most significant bits
 |         // Prefer the ID specified in the most significant bits
 | ||||||
|         BitField<40, 20, u64_le> extdata_id3; |         BitField<40, 20, u64> extdata_id3; | ||||||
|         BitField<20, 20, u64_le> extdata_id4; |         BitField<20, 20, u64> extdata_id4; | ||||||
|         BitField<0, 20, u64_le> extdata_id5; |         BitField<0, 20, u64> extdata_id5; | ||||||
|     }; |     }; | ||||||
|     u8 system_save_data_id[8]; |     u8 system_save_data_id[8]; | ||||||
|     union { |     union { | ||||||
|         u64_le storage_accessible_unique_ids; |         u64_le storage_accessible_unique_ids; | ||||||
|         // When using extended savedata access
 |         // When using extended savedata access
 | ||||||
|         // Prefer the ID specified in the most significant bits
 |         // Prefer the ID specified in the most significant bits
 | ||||||
|         BitField<40, 20, u64_le> extdata_id0; |         BitField<40, 20, u64> extdata_id0; | ||||||
|         BitField<20, 20, u64_le> extdata_id1; |         BitField<20, 20, u64> extdata_id1; | ||||||
|         BitField<0, 20, u64_le> extdata_id2; |         BitField<0, 20, u64> extdata_id2; | ||||||
|     }; |     }; | ||||||
|     u8 access_info[7]; |     u8 access_info[7]; | ||||||
|     u8 other_attributes; |     u8 other_attributes; | ||||||
|  |  | ||||||
|  | @ -19,9 +19,9 @@ namespace Service::IR { | ||||||
| 
 | 
 | ||||||
| struct ExtraHIDResponse { | struct ExtraHIDResponse { | ||||||
|     union { |     union { | ||||||
|         BitField<0, 8, u32_le> header; |         BitField<0, 8, u32> header; | ||||||
|         BitField<8, 12, u32_le> c_stick_x; |         BitField<8, 12, u32> c_stick_x; | ||||||
|         BitField<20, 12, u32_le> c_stick_y; |         BitField<20, 12, u32> c_stick_y; | ||||||
|     } c_stick; |     } c_stick; | ||||||
|     union { |     union { | ||||||
|         BitField<0, 5, u8> battery_level; |         BitField<0, 5, u8> battery_level; | ||||||
|  |  | ||||||
|  | @ -27,13 +27,13 @@ namespace Service::IR { | ||||||
| union PadState { | union PadState { | ||||||
|     u32_le hex{}; |     u32_le hex{}; | ||||||
| 
 | 
 | ||||||
|     BitField<14, 1, u32_le> zl; |     BitField<14, 1, u32> zl; | ||||||
|     BitField<15, 1, u32_le> zr; |     BitField<15, 1, u32> zr; | ||||||
| 
 | 
 | ||||||
|     BitField<24, 1, u32_le> c_stick_right; |     BitField<24, 1, u32> c_stick_right; | ||||||
|     BitField<25, 1, u32_le> c_stick_left; |     BitField<25, 1, u32> c_stick_left; | ||||||
|     BitField<26, 1, u32_le> c_stick_up; |     BitField<26, 1, u32> c_stick_up; | ||||||
|     BitField<27, 1, u32_le> c_stick_down; |     BitField<27, 1, u32> c_stick_down; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Interface to "ir:rst" service
 | /// Interface to "ir:rst" service
 | ||||||
|  |  | ||||||
|  | @ -231,8 +231,8 @@ private: | ||||||
|      */ |      */ | ||||||
|     union SegmentTag { |     union SegmentTag { | ||||||
|         u32_le raw; |         u32_le raw; | ||||||
|         BitField<0, 4, u32_le> segment_index; |         BitField<0, 4, u32> segment_index; | ||||||
|         BitField<4, 28, u32_le> offset_into_segment; |         BitField<4, 28, u32> offset_into_segment; | ||||||
| 
 | 
 | ||||||
|         SegmentTag() = default; |         SegmentTag() = default; | ||||||
|         explicit SegmentTag(u32 raw_) : raw(raw_) {} |         explicit SegmentTag(u32 raw_) : raw(raw_) {} | ||||||
|  | @ -270,8 +270,8 @@ private: | ||||||
|         u16_le test_bit; // bit address into the name to test
 |         u16_le test_bit; // bit address into the name to test
 | ||||||
|         union Child { |         union Child { | ||||||
|             u16_le raw; |             u16_le raw; | ||||||
|             BitField<0, 15, u16_le> next_index; |             BitField<0, 15, u16> next_index; | ||||||
|             BitField<15, 1, u16_le> is_end; |             BitField<15, 1, u16> is_end; | ||||||
|         } left, right; |         } left, right; | ||||||
|         u16_le export_table_index; // index of an ExportNamedSymbolEntry
 |         u16_le export_table_index; // index of an ExportNamedSymbolEntry
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -45,20 +45,20 @@ struct ControllerState { | ||||||
|             union { |             union { | ||||||
|                 u16_le hex; |                 u16_le hex; | ||||||
| 
 | 
 | ||||||
|                 BitField<0, 1, u16_le> a; |                 BitField<0, 1, u16> a; | ||||||
|                 BitField<1, 1, u16_le> b; |                 BitField<1, 1, u16> b; | ||||||
|                 BitField<2, 1, u16_le> select; |                 BitField<2, 1, u16> select; | ||||||
|                 BitField<3, 1, u16_le> start; |                 BitField<3, 1, u16> start; | ||||||
|                 BitField<4, 1, u16_le> right; |                 BitField<4, 1, u16> right; | ||||||
|                 BitField<5, 1, u16_le> left; |                 BitField<5, 1, u16> left; | ||||||
|                 BitField<6, 1, u16_le> up; |                 BitField<6, 1, u16> up; | ||||||
|                 BitField<7, 1, u16_le> down; |                 BitField<7, 1, u16> down; | ||||||
|                 BitField<8, 1, u16_le> r; |                 BitField<8, 1, u16> r; | ||||||
|                 BitField<9, 1, u16_le> l; |                 BitField<9, 1, u16> l; | ||||||
|                 BitField<10, 1, u16_le> x; |                 BitField<10, 1, u16> x; | ||||||
|                 BitField<11, 1, u16_le> y; |                 BitField<11, 1, u16> y; | ||||||
|                 BitField<12, 1, u16_le> debug; |                 BitField<12, 1, u16> debug; | ||||||
|                 BitField<13, 1, u16_le> gpio14; |                 BitField<13, 1, u16> gpio14; | ||||||
|                 // Bits 14-15 are currently unused
 |                 // Bits 14-15 are currently unused
 | ||||||
|             }; |             }; | ||||||
|             s16_le circle_pad_x; |             s16_le circle_pad_x; | ||||||
|  | @ -96,12 +96,12 @@ struct ControllerState { | ||||||
|             union { |             union { | ||||||
|                 u32_le hex; |                 u32_le hex; | ||||||
| 
 | 
 | ||||||
|                 BitField<0, 5, u32_le> battery_level; |                 BitField<0, 5, u32> battery_level; | ||||||
|                 BitField<5, 1, u32_le> zl_not_held; |                 BitField<5, 1, u32> zl_not_held; | ||||||
|                 BitField<6, 1, u32_le> zr_not_held; |                 BitField<6, 1, u32> zr_not_held; | ||||||
|                 BitField<7, 1, u32_le> r_not_held; |                 BitField<7, 1, u32> r_not_held; | ||||||
|                 BitField<8, 12, u32_le> c_stick_x; |                 BitField<8, 12, u32> c_stick_x; | ||||||
|                 BitField<20, 12, u32_le> c_stick_y; |                 BitField<20, 12, u32> c_stick_y; | ||||||
|             }; |             }; | ||||||
|         } extra_hid_response; |         } extra_hid_response; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  | @ -141,22 +141,22 @@ struct PadData { | ||||||
|     // The following union isn't trivially copyable but we don't use this input anyway.
 |     // The following union isn't trivially copyable but we don't use this input anyway.
 | ||||||
|     // union DigitalButton {
 |     // union DigitalButton {
 | ||||||
|     //     u16_le button;
 |     //     u16_le button;
 | ||||||
|     //     BitField<0, 1, u16_le> button_1;   // Share
 |     //     BitField<0, 1, u16> button_1;   // Share
 | ||||||
|     //     BitField<1, 1, u16_le> button_2;   // L3
 |     //     BitField<1, 1, u16> button_2;   // L3
 | ||||||
|     //     BitField<2, 1, u16_le> button_3;   // R3
 |     //     BitField<2, 1, u16> button_3;   // R3
 | ||||||
|     //     BitField<3, 1, u16_le> button_4;   // Options
 |     //     BitField<3, 1, u16> button_4;   // Options
 | ||||||
|     //     BitField<4, 1, u16_le> button_5;   // Up
 |     //     BitField<4, 1, u16> button_5;   // Up
 | ||||||
|     //     BitField<5, 1, u16_le> button_6;   // Right
 |     //     BitField<5, 1, u16> button_6;   // Right
 | ||||||
|     //     BitField<6, 1, u16_le> button_7;   // Down
 |     //     BitField<6, 1, u16> button_7;   // Down
 | ||||||
|     //     BitField<7, 1, u16_le> button_8;   // Left
 |     //     BitField<7, 1, u16> button_8;   // Left
 | ||||||
|     //     BitField<8, 1, u16_le> button_9;   // L2
 |     //     BitField<8, 1, u16> button_9;   // L2
 | ||||||
|     //     BitField<9, 1, u16_le> button_10;  // R2
 |     //     BitField<9, 1, u16> button_10;  // R2
 | ||||||
|     //     BitField<10, 1, u16_le> button_11; // L1
 |     //     BitField<10, 1, u16> button_11; // L1
 | ||||||
|     //     BitField<11, 1, u16_le> button_12; // R1
 |     //     BitField<11, 1, u16> button_12; // R1
 | ||||||
|     //     BitField<12, 1, u16_le> button_13; // Triangle
 |     //     BitField<12, 1, u16> button_13; // Triangle
 | ||||||
|     //     BitField<13, 1, u16_le> button_14; // Circle
 |     //     BitField<13, 1, u16> button_14; // Circle
 | ||||||
|     //     BitField<14, 1, u16_le> button_15; // Cross
 |     //     BitField<14, 1, u16> button_15; // Cross
 | ||||||
|     //     BitField<15, 1, u16_le> button_16; // Square
 |     //     BitField<15, 1, u16> button_16; // Square
 | ||||||
|     // } digital_button;
 |     // } digital_button;
 | ||||||
| 
 | 
 | ||||||
|     u8 home; |     u8 home; | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| add_executable(tests | add_executable(tests | ||||||
|  |     common/bit_field.cpp | ||||||
|     common/param_package.cpp |     common/param_package.cpp | ||||||
|     core/arm/arm_test_common.cpp |     core/arm/arm_test_common.cpp | ||||||
|     core/arm/arm_test_common.h |     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