| 
									
										
										
										
											2014-12-16 21:38:14 -08:00
										 |  |  | // Licensed under GPLv2 or any later version
 | 
					
						
							| 
									
										
										
										
											2014-05-07 18:14:42 -04:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Copyright 2014 Tony Wasserka
 | 
					
						
							|  |  |  | // All rights reserved.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Redistribution and use in source and binary forms, with or without
 | 
					
						
							|  |  |  | // modification, are permitted provided that the following conditions are met:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //     * Redistributions of source code must retain the above copyright
 | 
					
						
							|  |  |  | //       notice, this list of conditions and the following disclaimer.
 | 
					
						
							|  |  |  | //     * Redistributions in binary form must reproduce the above copyright
 | 
					
						
							|  |  |  | //       notice, this list of conditions and the following disclaimer in the
 | 
					
						
							|  |  |  | //       documentation and/or other materials provided with the distribution.
 | 
					
						
							|  |  |  | //     * Neither the name of the owner nor the names of its contributors may
 | 
					
						
							|  |  |  | //       be used to endorse or promote products derived from this software
 | 
					
						
							|  |  |  | //       without specific prior written permission.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
					
						
							|  |  |  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
					
						
							|  |  |  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
					
						
							|  |  |  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
					
						
							|  |  |  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
					
						
							|  |  |  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
					
						
							|  |  |  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
					
						
							|  |  |  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
					
						
							|  |  |  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
					
						
							|  |  |  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
					
						
							|  |  |  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-21 13:40:28 +01:00
										 |  |  | #include <cstddef>
 | 
					
						
							| 
									
										
										
										
											2014-05-07 18:14:42 -04:00
										 |  |  | #include <limits>
 | 
					
						
							|  |  |  | #include <type_traits>
 | 
					
						
							| 
									
										
										
										
											2015-05-06 04:06:12 -03:00
										 |  |  | #include "common/common_funcs.h"
 | 
					
						
							| 
									
										
										
										
											2014-05-07 18:14:42 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Abstract bitfield class | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Allows endianness-independent access to individual bitfields within some raw | 
					
						
							|  |  |  |  * integer value. The assembly generated by this class is identical to the | 
					
						
							|  |  |  |  * usage of raw bitfields, so it's a perfectly fine replacement. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * For BitField<X,Y,Z>, X is the distance of the bitfield to the LSB of the | 
					
						
							|  |  |  |  * raw value, Y is the length in bits of the bitfield. Z is an integer type | 
					
						
							|  |  |  |  * which determines the sign of the bitfield. Z must have the same size as the | 
					
						
							|  |  |  |  * raw integer. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * General usage: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Create a new union with the raw integer value as a member. | 
					
						
							|  |  |  |  * Then for each bitfield you want to expose, add a BitField member | 
					
						
							|  |  |  |  * in the union. The template parameters are the bit offset and the number | 
					
						
							|  |  |  |  * of desired bits. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Changes in the bitfield members will then get reflected in the raw integer | 
					
						
							|  |  |  |  * value and vice-versa. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Sample usage: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * union SomeRegister | 
					
						
							|  |  |  |  * { | 
					
						
							|  |  |  |  *     u32 hex; | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     BitField<0,7,u32> first_seven_bits;     // unsigned
 | 
					
						
							| 
									
										
										
										
											2014-10-25 15:12:24 -04:00
										 |  |  |  *     BitField<7,8,u32> next_eight_bits;      // unsigned
 | 
					
						
							| 
									
										
										
										
											2014-05-07 18:14:42 -04:00
										 |  |  |  *     BitField<3,15,s32> some_signed_fields;  // signed
 | 
					
						
							|  |  |  |  * }; | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This is equivalent to the little-endian specific code: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * union SomeRegister | 
					
						
							|  |  |  |  * { | 
					
						
							|  |  |  |  *     u32 hex; | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     struct | 
					
						
							|  |  |  |  *     { | 
					
						
							|  |  |  |  *         u32 first_seven_bits : 7; | 
					
						
							|  |  |  |  *         u32 next_eight_bits : 8; | 
					
						
							|  |  |  |  *     }; | 
					
						
							|  |  |  |  *     struct | 
					
						
							|  |  |  |  *     { | 
					
						
							|  |  |  |  *         u32 : 3; // padding
 | 
					
						
							|  |  |  |  *         s32 some_signed_fields : 15; | 
					
						
							|  |  |  |  *     }; | 
					
						
							|  |  |  |  * }; | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Caveats: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 1) | 
					
						
							|  |  |  |  * BitField provides automatic casting from and to the storage type where | 
					
						
							|  |  |  |  * appropriate. However, when using non-typesafe functions like printf, an | 
					
						
							|  |  |  |  * explicit cast must be performed on the BitField object to make sure it gets | 
					
						
							|  |  |  |  * passed correctly, e.g.: | 
					
						
							|  |  |  |  * printf("Value: %d", (s32)some_register.some_signed_fields); | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 2) | 
					
						
							|  |  |  |  * Not really a caveat, but potentially irritating: This class is used in some | 
					
						
							|  |  |  |  * packed structures that do not guarantee proper alignment. Therefore we have | 
					
						
							|  |  |  |  * to use #pragma pack here not to pack the members of the class, but instead | 
					
						
							|  |  |  |  * to break GCC's assumption that the members of the class are aligned on | 
					
						
							|  |  |  |  * sizeof(StorageType). | 
					
						
							|  |  |  |  * TODO(neobrain): Confirm that this is a proper fix and not just masking | 
					
						
							|  |  |  |  * symptoms. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #pragma pack(1)
 | 
					
						
							| 
									
										
										
										
											2017-05-20 20:40:13 -07:00
										 |  |  | template <std::size_t Position, std::size_t Bits, typename T> | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  | struct BitField { | 
					
						
							| 
									
										
										
										
											2014-05-07 18:14:42 -04:00
										 |  |  | private: | 
					
						
							| 
									
										
										
										
											2018-11-10 23:41:30 -05:00
										 |  |  |     // UnderlyingType is T for non-enum types and the underlying type of T if
 | 
					
						
							| 
									
										
										
										
											2017-05-20 20:40:13 -07:00
										 |  |  |     // T is an enumeration. Note that T is wrapped within an enable_if in the
 | 
					
						
							|  |  |  |     // former case to workaround compile errors which arise when using
 | 
					
						
							|  |  |  |     // std::underlying_type<T>::type directly.
 | 
					
						
							| 
									
										
										
										
											2018-11-10 23:41:30 -05:00
										 |  |  |     using UnderlyingType = typename std::conditional_t<std::is_enum_v<T>, std::underlying_type<T>, | 
					
						
							|  |  |  |                                                        std::enable_if<true, T>>::type; | 
					
						
							| 
									
										
										
										
											2017-05-20 20:40:13 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-10 23:41:30 -05:00
										 |  |  |     // We store the value as the unsigned type to avoid undefined behaviour on value shifting
 | 
					
						
							|  |  |  |     using StorageType = std::make_unsigned_t<UnderlyingType>; | 
					
						
							| 
									
										
										
										
											2017-05-20 20:40:13 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-07 18:14:42 -04:00
										 |  |  | public: | 
					
						
							| 
									
										
										
										
											2017-05-20 20:40:13 -07:00
										 |  |  |     /// Constants to allow limited introspection of fields if needed
 | 
					
						
							| 
									
										
										
										
											2018-09-15 15:21:06 +02:00
										 |  |  |     static constexpr std::size_t position = Position; | 
					
						
							|  |  |  |     static constexpr std::size_t bits = Bits; | 
					
						
							| 
									
										
										
										
											2018-11-10 23:41:30 -05:00
										 |  |  |     static constexpr StorageType mask = (((StorageType)~0) >> (8 * sizeof(T) - bits)) << position; | 
					
						
							| 
									
										
										
										
											2017-05-20 20:40:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Formats a value by masking and shifting it according to the field parameters. A value | 
					
						
							|  |  |  |      * containing several bitfields can be assembled by formatting each of their values and ORing | 
					
						
							|  |  |  |      * the results together. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     static constexpr FORCE_INLINE StorageType FormatValue(const T& value) { | 
					
						
							|  |  |  |         return ((StorageType)value << position) & mask; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Extracts a value from the passed storage. In most situations prefer use the member functions | 
					
						
							|  |  |  |      * (such as Value() or operator T), but this can be used to extract a value from a bitfield | 
					
						
							|  |  |  |      * union in a constexpr context. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     static constexpr FORCE_INLINE T ExtractValue(const StorageType& storage) { | 
					
						
							| 
									
										
										
										
											2018-11-10 23:41:30 -05:00
										 |  |  |         if constexpr (std::numeric_limits<UnderlyingType>::is_signed) { | 
					
						
							| 
									
										
										
										
											2017-05-20 20:40:13 -07:00
										 |  |  |             std::size_t shift = 8 * sizeof(T) - bits; | 
					
						
							| 
									
										
										
										
											2018-11-10 23:41:30 -05:00
										 |  |  |             return static_cast<T>(static_cast<UnderlyingType>(storage << (shift - position)) >> | 
					
						
							|  |  |  |                                   shift); | 
					
						
							| 
									
										
										
										
											2017-05-20 20:40:13 -07:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2018-11-10 23:41:30 -05:00
										 |  |  |             return static_cast<T>((storage & mask) >> position); | 
					
						
							| 
									
										
										
										
											2017-05-20 20:40:13 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-11 17:41:15 +00:00
										 |  |  |     // This constructor and assignment operator might be considered ambiguous:
 | 
					
						
							|  |  |  |     // Would they initialize the storage or just the bitfield?
 | 
					
						
							|  |  |  |     // Hence, delete them. Use the Assign method to set bitfield values!
 | 
					
						
							|  |  |  |     BitField(T val) = delete; | 
					
						
							|  |  |  |     BitField& operator=(T val) = delete; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-07 16:32:10 -05:00
										 |  |  |     constexpr BitField() noexcept = default; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     constexpr BitField(const BitField&) noexcept = default; | 
					
						
							|  |  |  |     constexpr BitField& operator=(const BitField&) noexcept = default; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     constexpr BitField(BitField&&) noexcept = default; | 
					
						
							|  |  |  |     constexpr BitField& operator=(BitField&&) noexcept = default; | 
					
						
							| 
									
										
										
										
											2014-05-07 18:14:42 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-05 21:44:22 -04:00
										 |  |  |     constexpr FORCE_INLINE operator T() const { | 
					
						
							| 
									
										
										
										
											2014-05-29 22:54:34 +02:00
										 |  |  |         return Value(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-05 21:44:22 -04:00
										 |  |  |     constexpr FORCE_INLINE void Assign(const T& value) { | 
					
						
							| 
									
										
										
										
											2017-05-20 20:40:13 -07:00
										 |  |  |         storage = (storage & ~mask) | FormatValue(value); | 
					
						
							| 
									
										
										
										
											2014-12-16 01:18:56 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-05 21:44:22 -04:00
										 |  |  |     constexpr T Value() const { | 
					
						
							| 
									
										
										
										
											2017-05-20 20:40:13 -07:00
										 |  |  |         return ExtractValue(storage); | 
					
						
							| 
									
										
										
										
											2014-05-07 18:14:42 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-21 06:39:42 -04:00
										 |  |  |     constexpr explicit operator bool() const { | 
					
						
							| 
									
										
										
										
											2014-12-20 18:28:17 -05:00
										 |  |  |         return Value() != 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-07 18:14:42 -04:00
										 |  |  | private: | 
					
						
							|  |  |  |     StorageType storage; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // And, you know, just in case people specify something stupid like bits=position=0x80000000
 | 
					
						
							|  |  |  |     static_assert(position < 8 * sizeof(T), "Invalid position"); | 
					
						
							|  |  |  |     static_assert(bits <= 8 * sizeof(T), "Invalid number of bits"); | 
					
						
							|  |  |  |     static_assert(bits > 0, "Invalid number of bits"); | 
					
						
							| 
									
										
										
										
											2018-04-17 18:00:18 -04:00
										 |  |  |     static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable in a BitField"); | 
					
						
							| 
									
										
										
										
											2014-05-07 18:14:42 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | #pragma pack()
 |