mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	common/bitfield: make it endianness-aware
This commit is contained in:
		
							parent
							
								
									fa9d6b79f9
								
							
						
					
					
						commit
						055b9513a3
					
				
					 3 changed files with 100 additions and 3 deletions
				
			
		|  | @ -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>; | ||||||
|  |  | ||||||
|  | @ -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