M5Utility 0.0.8 git rev:f3e2efe
Loading...
Searching...
No Matches
lfsr.hpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
3 *
4 * SPDX-License-Identifier: MIT
5 */
10#ifndef M5_UTILITY_LFSR_HPP
11#define M5_UTILITY_LFSR_HPP
12
13#include <bitset>
14#include <climits>
15#include "misc.hpp"
16
17namespace m5 {
18namespace utility {
19
27template <uint32_t N, uint32_t... Taps>
29 static_assert(N >= 1, "N must be >= 1");
30 static_assert(N <= 64, "N must be <= 64");
31 static_assert(sizeof...(Taps) >= 1, "At least one tap required");
32
33 // Tap boundary check: 1..N-1
34 template <uint32_t...>
35 struct all_valid : std::true_type {
36 //
37 };
38 template <uint32_t A, uint32_t... Rest>
39 struct all_valid<A, Rest...> : std::integral_constant<bool, (A >= 1 && A <= N) && all_valid<Rest...>::value> {
40 //
41 };
42 static_assert(all_valid<Taps...>::value, "Taps out of range");
43
44protected:
45 // XOR of taps; bit index is N - Ts (Ts is exponent)
46 template <uint32_t... Ts>
47 static bool taps_xor(const std::bitset<N>& s)
48 {
49 bool r{};
50 using swallow = int[];
51 (void)swallow{0, (r ^= s.test(N - Ts), 0)...}; // Swallow idiom
52 return r;
53 }
54
55public:
56 using storage_t = typename uint_least_for_bits<N>::type;
57 using state_type_t = std::bitset<N>;
58
61 explicit FibonacciLFSR_Right(const storage_t seed) noexcept : _state{seed}
62 {
63 }
65
67 inline const state_type_t& state() const noexcept
68 {
69 return _state;
70 }
71
73 template <typename UL = unsigned long,
74 typename std::enable_if<(sizeof(UL) * CHAR_BIT >= 64), std::nullptr_t>::type = nullptr>
75 inline storage_t value() const
76 {
77 return static_cast<storage_t>(_state.to_ulong());
78 }
79 template <typename UL = unsigned long,
80 typename std::enable_if<(sizeof(UL) * CHAR_BIT < 64), std::nullptr_t>::type = nullptr>
81 inline storage_t value() const
82 {
83 return static_cast<storage_t>(_state.to_ullong());
84 }
85
87 bool step() noexcept
88 {
89 // x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31;
90 const bool out = _state.test(0); // LSB (output)
91 const bool fb = taps_xor<Taps...>(_state); // feedback
92 _state >>= 1; // Shift to right
93 _state.set(N - 1, fb); // Insert feedback into MSB
94 return out;
95 }
96
98 uint64_t step(const uint32_t nbits) noexcept
99 {
100 uint64_t v{};
101 for (uint32_t i = 0; i < nbits; ++i) {
102 v |= (uint64_t(step()) << i);
103 }
104 return v;
105 }
106
110 inline uint16_t next16() noexcept
111 {
112 return (uint16_t)step(16);
113 }
115 inline uint32_t next32() noexcept
116 {
117 return (uint32_t)step(32);
118 }
120 inline uint64_t next64() noexcept
121 {
122 return step(64);
123 }
125
126protected:
127 static inline bool taps_xor_all(const state_type_t& s)
128 {
129 return taps_xor<Taps...>(s);
130 }
131
132 state_type_t _state;
133};
134
142template <uint32_t N, uint32_t... Taps>
144 static_assert(N >= 1, "N must be >= 1");
145 static_assert(N <= 64, "N must be <= 64");
146 static_assert(sizeof...(Taps) >= 1, "At least one tap required");
147
148 // Tap boundary check: 1..N-1
149 template <uint32_t...>
150 struct all_valid : std::true_type {
151 //
152 };
153 template <uint32_t A, uint32_t... Rest>
154 struct all_valid<A, Rest...> : std::integral_constant<bool, (A >= 1 && A <= N) && all_valid<Rest...>::value> {
155 //
156 };
157 static_assert(all_valid<Taps...>::value, "Taps out of range");
158
159protected:
160 template <uint32_t... Ts>
161 static bool taps_xor(const std::bitset<N>& s)
162 {
163 bool r{};
164 using swallow = int[];
165 (void)swallow{0, (r ^= s.test(Ts - 1), 0)...}; // Swallow idiom
166 return r;
167 }
168
169public:
170 using storage_t = typename uint_least_for_bits<N>::type;
171 using state_type_t = std::bitset<N>;
172
175 explicit FibonacciLFSR_Left(const uint64_t seed) noexcept : _state{seed}
176 {
177 }
179
181 inline const state_type_t& state() const noexcept
182 {
183 return _state;
184 }
185
187 template <typename UL = unsigned long,
188 typename std::enable_if<(sizeof(UL) * CHAR_BIT >= 64), std::nullptr_t>::type = nullptr>
189 inline storage_t value() const
190 {
191 return static_cast<storage_t>(_state.to_ulong());
192 }
193 template <typename UL = unsigned long,
194 typename std::enable_if<(sizeof(UL) * CHAR_BIT < 64), std::nullptr_t>::type = nullptr>
195 inline storage_t value() const
196 {
197 return static_cast<storage_t>(_state.to_ullong());
198 }
199
201 bool step() noexcept
202 {
203 const bool out = _state.test(N - 1); // MSB (output)
204 const bool fb = taps_xor<Taps...>(_state); // feedback
205 _state <<= 1; // shift to left
206 _state.set(0, fb); // insert feedback into LSB
207 return out;
208 }
209
211 uint64_t step(const uint32_t nbits) noexcept
212 {
213 uint64_t v{};
214 for (uint32_t i = 0; i < nbits; ++i) {
215 v |= (uint64_t(step()) << i); // i-th output placed at bit i
216 }
217 return v;
218 }
219
222 inline uint16_t next16() noexcept
223 {
224 return (uint16_t)step(16);
225 }
226 inline uint32_t next32() noexcept
227 {
228 return (uint32_t)step(32);
229 }
230 inline uint64_t next64() noexcept
231 {
232 return step(64);
233 }
235
236protected:
237 static inline bool taps_xor_all(const state_type_t& s)
238 {
239 return taps_xor<Taps...>(s);
240 }
241 state_type_t _state;
242};
243
244} // namespace utility
245} // namespace m5
246#endif
Fibonacci LFSR (left-shift version)
Definition lfsr.hpp:143
bool step() noexcept
Shift 1 step (Left). Returns output bit (MSB before shift)
Definition lfsr.hpp:201
std::bitset< N > state_type_t
State type.
Definition lfsr.hpp:171
uint64_t step(const uint32_t nbits) noexcept
Shift nbits steps and pack outputs LSB-first.
Definition lfsr.hpp:211
typename uint_least_for_bits< N >::type storage_t
uint8/16/32/64_t
Definition lfsr.hpp:170
const state_type_t & state() const noexcept
Gets the state.
Definition lfsr.hpp:181
storage_t value() const
Gets the state value.
Definition lfsr.hpp:189
Fibonacci LFSRs (right-shift version)
Definition lfsr.hpp:28
typename uint_least_for_bits< N >::type storage_t
uint8/16/32/64_t
Definition lfsr.hpp:56
uint16_t next16() noexcept
Shift 16 bits and get.
Definition lfsr.hpp:110
std::bitset< N > state_type_t
State type.
Definition lfsr.hpp:57
storage_t value() const
Gets the state value.
Definition lfsr.hpp:75
uint64_t next64() noexcept
Shift 64 bits and get.
Definition lfsr.hpp:120
uint32_t next32() noexcept
Shift 32 bits and get.
Definition lfsr.hpp:115
uint64_t step(const uint32_t nbits) noexcept
Shift nbit steps and gets.
Definition lfsr.hpp:98
const state_type_t & state() const noexcept
Gets the state.
Definition lfsr.hpp:67
bool step() noexcept
Shift 1 step (Right). Returns output bit (LSB before shift)
Definition lfsr.hpp:87
Miscellaneous features.
Top level namespace of M5.
Definition bit_segment.hpp:17
For utilities.