diff options
| -rw-r--r-- | src/common/bit_field.h | 173 | ||||
| -rw-r--r-- | src/common/common.vcxproj | 1 | ||||
| -rw-r--r-- | src/common/common.vcxproj.filters | 1 |
3 files changed, 175 insertions, 0 deletions
diff --git a/src/common/bit_field.h b/src/common/bit_field.h new file mode 100644 index 000000000..f5322b25b --- /dev/null +++ b/src/common/bit_field.h | |||
| @@ -0,0 +1,173 @@ | |||
| 1 | // Copyright 2014 Dolphin Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | |||
| 6 | // Copyright 2014 Tony Wasserka | ||
| 7 | // All rights reserved. | ||
| 8 | // | ||
| 9 | // Redistribution and use in source and binary forms, with or without | ||
| 10 | // modification, are permitted provided that the following conditions are met: | ||
| 11 | // | ||
| 12 | // * Redistributions of source code must retain the above copyright | ||
| 13 | // notice, this list of conditions and the following disclaimer. | ||
| 14 | // * Redistributions in binary form must reproduce the above copyright | ||
| 15 | // notice, this list of conditions and the following disclaimer in the | ||
| 16 | // documentation and/or other materials provided with the distribution. | ||
| 17 | // * Neither the name of the owner nor the names of its contributors may | ||
| 18 | // be used to endorse or promote products derived from this software | ||
| 19 | // without specific prior written permission. | ||
| 20 | // | ||
| 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 22 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 23 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| 24 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| 25 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| 26 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| 27 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| 28 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| 29 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| 30 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| 31 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 32 | |||
| 33 | |||
| 34 | #pragma once | ||
| 35 | |||
| 36 | #include <limits> | ||
| 37 | #include <type_traits> | ||
| 38 | |||
| 39 | #include "Common.h" | ||
| 40 | |||
| 41 | /* | ||
| 42 | * Abstract bitfield class | ||
| 43 | * | ||
| 44 | * Allows endianness-independent access to individual bitfields within some raw | ||
| 45 | * integer value. The assembly generated by this class is identical to the | ||
| 46 | * usage of raw bitfields, so it's a perfectly fine replacement. | ||
| 47 | * | ||
| 48 | * For BitField<X,Y,Z>, X is the distance of the bitfield to the LSB of the | ||
| 49 | * raw value, Y is the length in bits of the bitfield. Z is an integer type | ||
| 50 | * which determines the sign of the bitfield. Z must have the same size as the | ||
| 51 | * raw integer. | ||
| 52 | * | ||
| 53 | * | ||
| 54 | * General usage: | ||
| 55 | * | ||
| 56 | * Create a new union with the raw integer value as a member. | ||
| 57 | * Then for each bitfield you want to expose, add a BitField member | ||
| 58 | * in the union. The template parameters are the bit offset and the number | ||
| 59 | * of desired bits. | ||
| 60 | * | ||
| 61 | * Changes in the bitfield members will then get reflected in the raw integer | ||
| 62 | * value and vice-versa. | ||
| 63 | * | ||
| 64 | * | ||
| 65 | * Sample usage: | ||
| 66 | * | ||
| 67 | * union SomeRegister | ||
| 68 | * { | ||
| 69 | * u32 hex; | ||
| 70 | * | ||
| 71 | * BitField<0,7,u32> first_seven_bits; // unsigned | ||
| 72 | * BitField<7,8,32> next_eight_bits; // unsigned | ||
| 73 | * BitField<3,15,s32> some_signed_fields; // signed | ||
| 74 | * }; | ||
| 75 | * | ||
| 76 | * This is equivalent to the little-endian specific code: | ||
| 77 | * | ||
| 78 | * union SomeRegister | ||
| 79 | * { | ||
| 80 | * u32 hex; | ||
| 81 | * | ||
| 82 | * struct | ||
| 83 | * { | ||
| 84 | * u32 first_seven_bits : 7; | ||
| 85 | * u32 next_eight_bits : 8; | ||
| 86 | * }; | ||
| 87 | * struct | ||
| 88 | * { | ||
| 89 | * u32 : 3; // padding | ||
| 90 | * s32 some_signed_fields : 15; | ||
| 91 | * }; | ||
| 92 | * }; | ||
| 93 | * | ||
| 94 | * | ||
| 95 | * Caveats: | ||
| 96 | * | ||
| 97 | * 1) | ||
| 98 | * BitField provides automatic casting from and to the storage type where | ||
| 99 | * appropriate. However, when using non-typesafe functions like printf, an | ||
| 100 | * explicit cast must be performed on the BitField object to make sure it gets | ||
| 101 | * passed correctly, e.g.: | ||
| 102 | * printf("Value: %d", (s32)some_register.some_signed_fields); | ||
| 103 | * | ||
| 104 | * 2) | ||
| 105 | * Not really a caveat, but potentially irritating: This class is used in some | ||
| 106 | * packed structures that do not guarantee proper alignment. Therefore we have | ||
| 107 | * to use #pragma pack here not to pack the members of the class, but instead | ||
| 108 | * to break GCC's assumption that the members of the class are aligned on | ||
| 109 | * sizeof(StorageType). | ||
| 110 | * TODO(neobrain): Confirm that this is a proper fix and not just masking | ||
| 111 | * symptoms. | ||
| 112 | */ | ||
| 113 | #pragma pack(1) | ||
| 114 | template<std::size_t position, std::size_t bits, typename T> | ||
| 115 | struct BitField | ||
| 116 | { | ||
| 117 | private: | ||
| 118 | // This constructor might be considered ambiguous: | ||
| 119 | // Would it initialize the storage or just the bitfield? | ||
| 120 | // Hence, delete it. Use the assignment operator to set bitfield values! | ||
| 121 | BitField(T val) = delete; | ||
| 122 | |||
| 123 | public: | ||
| 124 | // Force default constructor to be created | ||
| 125 | // so that we can use this within unions | ||
| 126 | BitField() = default; | ||
| 127 | |||
| 128 | __forceinline BitField& operator=(T val) | ||
| 129 | { | ||
| 130 | storage = (storage & ~GetMask()) | ((val << position) & GetMask()); | ||
| 131 | return *this; | ||
| 132 | } | ||
| 133 | |||
| 134 | __forceinline operator T() const | ||
| 135 | { | ||
| 136 | if (std::numeric_limits<T>::is_signed) | ||
| 137 | { | ||
| 138 | std::size_t shift = 8 * sizeof(T)-bits; | ||
| 139 | return (T)(((storage & GetMask()) << (shift - position)) >> shift); | ||
| 140 | } | ||
| 141 | else | ||
| 142 | { | ||
| 143 | return (T)((storage & GetMask()) >> position); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | private: | ||
| 148 | // StorageType is T for non-enum types and the underlying type of T if | ||
| 149 | // T is an enumeration. Note that T is wrapped within an enable_if in the | ||
| 150 | // former case to workaround compile errors which arise when using | ||
| 151 | // std::underlying_type<T>::type directly. | ||
| 152 | typedef typename std::conditional < std::is_enum<T>::value, | ||
| 153 | std::underlying_type<T>, | ||
| 154 | std::enable_if < true, T >> ::type::type StorageType; | ||
| 155 | |||
| 156 | // Unsigned version of StorageType | ||
| 157 | typedef typename std::make_unsigned<StorageType>::type StorageTypeU; | ||
| 158 | |||
| 159 | __forceinline StorageType GetMask() const | ||
| 160 | { | ||
| 161 | return ((~(StorageTypeU)0) >> (8 * sizeof(T)-bits)) << position; | ||
| 162 | } | ||
| 163 | |||
| 164 | StorageType storage; | ||
| 165 | |||
| 166 | static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); | ||
| 167 | |||
| 168 | // And, you know, just in case people specify something stupid like bits=position=0x80000000 | ||
| 169 | static_assert(position < 8 * sizeof(T), "Invalid position"); | ||
| 170 | static_assert(bits <= 8 * sizeof(T), "Invalid number of bits"); | ||
| 171 | static_assert(bits > 0, "Invalid number of bits"); | ||
| 172 | }; | ||
| 173 | #pragma pack() | ||
diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index 5048bebff..5dc6ff790 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj | |||
| @@ -157,6 +157,7 @@ | |||
| 157 | <ClInclude Include="atomic.h" /> | 157 | <ClInclude Include="atomic.h" /> |
| 158 | <ClInclude Include="atomic_gcc.h" /> | 158 | <ClInclude Include="atomic_gcc.h" /> |
| 159 | <ClInclude Include="atomic_win32.h" /> | 159 | <ClInclude Include="atomic_win32.h" /> |
| 160 | <ClInclude Include="bit_field.h" /> | ||
| 160 | <ClInclude Include="break_points.h" /> | 161 | <ClInclude Include="break_points.h" /> |
| 161 | <ClInclude Include="chunk_file.h" /> | 162 | <ClInclude Include="chunk_file.h" /> |
| 162 | <ClInclude Include="common.h" /> | 163 | <ClInclude Include="common.h" /> |
diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index e9ea40022..268730228 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters | |||
| @@ -39,6 +39,7 @@ | |||
| 39 | <ClInclude Include="utf8.h" /> | 39 | <ClInclude Include="utf8.h" /> |
| 40 | <ClInclude Include="symbols.h" /> | 40 | <ClInclude Include="symbols.h" /> |
| 41 | <ClInclude Include="scm_rev.h" /> | 41 | <ClInclude Include="scm_rev.h" /> |
| 42 | <ClInclude Include="bit_field.h" /> | ||
| 42 | </ItemGroup> | 43 | </ItemGroup> |
| 43 | <ItemGroup> | 44 | <ItemGroup> |
| 44 | <ClCompile Include="break_points.cpp" /> | 45 | <ClCompile Include="break_points.cpp" /> |