libmicroemu 0.2.0
ARM Microcontroller Emulator Library
Loading...
Searching...
No Matches
bit_manip.h
1#pragma once
2#include "libmicroemu/internal/utils/traits.h"
3#include "libmicroemu/types.h"
4#include <cassert>
5#include <cstddef>
6#include <cstdint>
7#include <type_traits>
8
9namespace libmicroemu::internal {
10
11template <typename T> class BitManip {
12 // clang-format off
13 static_assert(
14 std::is_same<T, u64>::value ||
15 std::is_same<T, u32>::value ||
16 std::is_same<T, u16>::value ||
17 std::is_same<T, u8>::value,
18 "BitManip only works for u32, u16 and u8");
19 // clang-format on
20public:
35 template <T alignment> static constexpr T AlignDown(const T &address) {
36 if (alignment == 0U)
37 return address;
38 return address & ~(alignment - 1U);
39 }
40
55 template <T alignment> static constexpr T AlignUp(const T &address) {
56 if (alignment == 0U) {
57 return address;
58 }
59 return (address + (alignment - 1U)) & ~(alignment - 1U);
60 }
61
67 template <unsigned bit> static constexpr T GenerateBitMask() {
68 return static_cast<T>(static_cast<T>(1U) << bit);
69 }
70
77 template <unsigned last_bit, unsigned first_bit> static constexpr T GenerateBitMask() {
78
79 if constexpr (last_bit == sizeof(T) * 8U - 1U) {
80 T constexpr msk = ~static_cast<T>(0U);
81 return static_cast<T>(msk << first_bit);
82 } else {
83 auto constexpr shift_range = last_bit - first_bit + 1U;
84 T constexpr one = static_cast<T>(1U);
85 T constexpr msk = (one << shift_range) - one;
86 return static_cast<T>(msk << first_bit);
87 }
88 }
89
96 static constexpr T GenerateBitMask(unsigned last_bit, unsigned first_bit) {
97 if (last_bit == sizeof(T) * 8U - 1U) {
98 T constexpr msk = ~static_cast<T>(0U);
99 return static_cast<T>(msk << first_bit);
100 } else {
101 auto shift_range = last_bit - first_bit + 1U;
102 T constexpr one = static_cast<T>(1U);
103 T msk = (one << shift_range) - one;
104 return static_cast<T>(msk << first_bit);
105 }
106 }
107
114 template <unsigned bit> static constexpr T IsolateBit(const T &value) {
115 return (value & (static_cast<T>(1U) << bit)) >> bit;
116 }
117
124 template <unsigned bit> static constexpr bool IsBitSet(const T &value) {
125 return (value & (static_cast<T>(1U) << bit)) != 0;
126 }
127
135 template <unsigned last_bit, unsigned first_bit>
136 static constexpr T ExtractBits1R(const T &value) {
137 return (value & GenerateBitMask<last_bit, first_bit>()) >> first_bit;
138 }
139
152 template <typename U> static U ExtractType(T value, u32 start_byte) {
153 assert(start_byte >= 0U && start_byte <= (sizeof(T) - 1U));
154 auto bitpos = start_byte * 8U;
155 auto constexpr bitmask = GenerateBitMask<sizeof(U) * 8U - 1U, 0U>() - 1U;
156 return static_cast<U>((value >> bitpos) & bitmask);
157 }
158
167 template <typename U> static T InsertType(T value, u32 start_byte, U insert_val) {
168 assert(start_byte >= 0U && start_byte <= (sizeof(T) - 1U));
169 auto start_pos = start_byte * 8U;
170 auto end_pos = start_pos + sizeof(U) * 8 - 1U;
171
172 auto mask = GenerateBitMask(end_pos, start_pos);
173 auto shifted_bits = static_cast<T>(insert_val) << start_pos;
174 return (value & (~mask)) | (shifted_bits & mask);
175 }
176
186 template <unsigned r2_last_bit, unsigned r2_first_bit, unsigned r1_last_bit,
187 unsigned r1_first_bit>
188 static constexpr T ExtractBits2R(const T &value) {
189 return ((value & GenerateBitMask<r2_last_bit, r2_first_bit>()) >>
190 (r2_first_bit - r1_last_bit + r1_first_bit - 1U)) +
191 ((value & GenerateBitMask<r1_last_bit, r1_first_bit>()) >> (r1_first_bit));
192 }
193
200 template <typename U> static inline U ZeroExtend(const T &value) {
201 static_assert(std::is_same<U, u32>::value || std::is_same<U, u16>::value ||
202 std::is_same<U, u8>::value,
203 "ZeroExtend only works for u32, u16 and u8");
204 return static_cast<U>(value);
205 }
206
214 template <typename U, unsigned top_bit> static inline U SignExtend(const T &value) {
215 static_assert(std::is_same<U, u32>::value || std::is_same<U, u16>::value ||
216 std::is_same<U, u8>::value,
217 "ZeroExtend only works for u32, u16 and u8");
218 T s = (value >> top_bit) & 0x1U;
219 U bitmask = BitManip<U>::template GenerateBitMask<no_of_bits<U>::N, top_bit>();
220 U value_u = static_cast<U>(value);
221 if (s) {
222 value_u = value_u | bitmask;
223 } else {
224 value_u = value_u & ~bitmask;
225 }
226 return value_u;
227 }
228
234 static T IsZeroBit(const T &value) {
235 return value == static_cast<T>(0U) ? static_cast<T>(1U) : static_cast<T>(0U);
236 }
237
243 static T BitCount(const T &value) {
244 T v{value};
245 T c{0U}; // c accumulates the total bits set in v
246 for (; v; c++) {
247 v &= v - 1U; // clear the least significant bit set
248 }
249 return c;
250 }
251
257 static T LowestBitSet(const T &value) {
258 T x{value};
259 if (x == 0)
260 return no_of_bits<T>::N;
261
262 T result = 0;
263 while ((x & 1) == 0) {
264 x >>= 1;
265 result++;
266 }
267
268 return result;
269 }
270 static T CountLeadingZeros(const T &value) {
271 int n{32U};
272 u32 y{0U};
273 u32 x{value};
274
275 y = x >> 16U;
276 if (y != 0U) {
277 n = n - 16U;
278 x = y;
279 }
280 y = x >> 8U;
281 if (y != 0U) {
282 n = n - 8U;
283 x = y;
284 }
285 y = x >> 4U;
286 if (y != 0U) {
287 n = n - 4U;
288 x = y;
289 }
290 y = x >> 2U;
291 if (y != 0U) {
292 n = n - 2U;
293 x = y;
294 }
295 y = x >> 1U;
296 if (y != 0U) {
297 return n - 2U;
298 }
299
300 return n - x;
301 }
302
303private:
307 BitManip() = delete;
308
312 ~BitManip() = delete;
313
318 BitManip(const BitManip &r_src) = delete;
319
324 BitManip &operator=(const BitManip &r_src) = delete;
325
330 BitManip(BitManip &&r_src) = delete;
331
336 BitManip &operator=(BitManip &&r_src) = delete;
337};
338
339using Bm8 = BitManip<u8>;
340using Bm16 = BitManip<u16>;
341using Bm32 = BitManip<u32>;
342
343} // namespace libmicroemu::internal
Definition bit_manip.h:11
static U ZeroExtend(const T &value)
Takes a value of type T and converts it to type U by extending the missing bits with 0.
Definition bit_manip.h:200
static T LowestBitSet(const T &value)
Finds the position of the lowest bit set in the given value.
Definition bit_manip.h:257
static constexpr T GenerateBitMask()
Generates a mask for the bit 'bit'.
Definition bit_manip.h:67
static constexpr T ExtractBits2R(const T &value)
Extracts bits from value in 2 bit regions and concatenates them.
Definition bit_manip.h:188
static constexpr bool IsBitSet(const T &value)
Checks if the given bit "bit" is set in the value.
Definition bit_manip.h:124
static U SignExtend(const T &value)
Takes a value of type T and converts it to type U by extending the given top bit.
Definition bit_manip.h:214
static constexpr T AlignUp(const T &address)
Aligns the given address up to the nearest multiple of the specified alignment.
Definition bit_manip.h:55
static constexpr T ExtractBits1R(const T &value)
Extracts bits from value in the region [last_bit:first_bit].
Definition bit_manip.h:136
static U ExtractType(T value, u32 start_byte)
Extracts bits from an value and returns the result as the specified type.
Definition bit_manip.h:152
static T IsZeroBit(const T &value)
Checks if the given value is zero.
Definition bit_manip.h:234
static constexpr T AlignDown(const T &address)
Aligns the given address down to the nearest multiple of the specified alignment.
Definition bit_manip.h:35
static constexpr T GenerateBitMask()
Generates a mask of 1 bits in the region [last_bit:first_bit].
Definition bit_manip.h:77
static T BitCount(const T &value)
Counts the number of bits set in the given value.
Definition bit_manip.h:243
static constexpr T GenerateBitMask(unsigned last_bit, unsigned first_bit)
Generates a mask of 1 bits in the region [last_bit:first_bit].
Definition bit_manip.h:96
static T InsertType(T value, u32 start_byte, U insert_val)
Inserts bits of a shorter type into a value at the specified byte position.
Definition bit_manip.h:167
static constexpr T IsolateBit(const T &value)
Isolates the given bit "bit" in the value.
Definition bit_manip.h:114
The libmicroemu::internal namespace contains all classes and functions of libmicroemu which are priva...
Definition bkpt_flags.h:6
Definition traits.h:31