GNU Radio Manual and C++ API Reference  3.10.9.1
The Free & Open Software Radio Ecosystem
lfsr.h
Go to the documentation of this file.
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2008,2010,2012 Free Software Foundation, Inc.
4  *
5  * This file is part of GNU Radio
6  *
7  * SPDX-License-Identifier: GPL-3.0-or-later
8  *
9  */
10 
11 #ifndef INCLUDED_DIGITAL_LFSR_H
12 #define INCLUDED_DIGITAL_LFSR_H
13 
14 #include <gnuradio/digital/api.h>
15 #ifndef HAVE_BUILTIN_PARITYL
16 #include <volk/volk.h>
17 #endif
18 #include <stdint.h>
19 #include <cstdint>
20 #include <stdexcept>
21 
22 namespace gr {
23 namespace digital {
24 
25 /*!
26  * \brief Fibonacci Linear Feedback Shift Register using specified
27  * polynomial mask
28  * \ingroup misc
29  *
30  * \details
31  * Generates a maximal length pseudo-random sequence of length
32  * 2^degree-1, if supplied with a primitive polynomial.
33  *
34  * Constructor: digital::lfsr(int mask, int seed, int reg_len);
35  *
36  * \param mask - polynomial coefficients representing the
37  * locations of feedback taps from a shift register
38  * which are xor'ed together to form the new high
39  * order bit.
40  *
41  * Some common masks might be:
42  * x^4 + x^3 + x^0 = 0x19, K=3
43  * x^5 + x^3 + x^0 = 0x29, K=4
44  * x^6 + x^5 + x^0 = 0x61, K=5
45  *
46  * \param seed - the initialization vector placed into the
47  * register during initialization. Low order bit
48  * corresponds to x^0 coefficient -- the first to be
49  * shifted as output.
50  *
51  * \param reg_len - specifies the length of the feedback shift
52  * register to be used. During each iteration, the
53  * register is rightshifted one and the new bit is
54  * placed in bit reg_len. reg_len should generally be
55  * at least order(mask) + 1
56  *
57  *
58  * see http://en.wikipedia.org/wiki/Linear_feedback_shift_register
59  * for more explanation.
60  *
61  * next_bit() - Standard LFSR operation
62  *
63  * Perform one cycle of the LFSR. The output bit is taken from
64  * the shift register LSB. The shift register MSB is assigned from
65  * the modulo 2 sum of the masked shift register.
66  *
67  * next_bit_scramble(unsigned char input) - Scramble an input stream
68  *
69  * Perform one cycle of the LFSR. The output bit is taken from
70  * the shift register LSB. The shift register MSB is assigned from
71  * the modulo 2 sum of the masked shift register and the input LSB.
72  *
73  * next_bit_descramble(unsigned char input) - Descramble an input stream
74  *
75  * Perform one cycle of the LFSR. The output bit is taken from
76  * the modulo 2 sum of the masked shift register and the input LSB.
77  * The shift register MSB is assigned from the LSB of the input.
78  *
79  * See http://en.wikipedia.org/wiki/Scrambler for operation of these
80  * last two functions (see multiplicative scrambler.)
81  */
82 class lfsr
83 {
84 private:
85  uint64_t d_shift_register;
86  uint64_t d_mask;
87  uint64_t d_seed;
88  uint8_t d_shift_register_length; // less than 64
89 
90 public:
91  lfsr(uint64_t mask, uint64_t seed, uint8_t reg_len)
92  : d_shift_register(seed),
93  d_mask(mask),
94  d_seed(seed),
95  d_shift_register_length(reg_len)
96  {
97  if (reg_len > 63)
98  throw std::invalid_argument("reg_len must be <= 63");
99  }
100 
101  unsigned char next_bit()
102  {
103  unsigned char output = d_shift_register & 1;
104  uint64_t newbit;
105 #ifdef HAVE_BUILTIN_PARITYL
106  newbit = __builtin_parityl(d_shift_register & d_mask);
107 #else
108  volk_64u_popcnt(&newbit, d_shift_register & d_mask);
109  newbit %= 2;
110 #endif
111 
112  d_shift_register =
113  ((d_shift_register >> 1) | (newbit << d_shift_register_length));
114  return output;
115  }
116 
117  unsigned char next_bit_scramble(unsigned char input)
118  {
119  unsigned char output = d_shift_register & 1;
120  uint64_t newbit;
121 #ifdef HAVE_BUILTIN_PARITYL
122  newbit = __builtin_parityl(d_shift_register & d_mask) ^ (input & 1);
123 #else
124  volk_64u_popcnt(&newbit, d_shift_register & d_mask);
125  newbit = (newbit ^ input) & 1;
126 #endif
127  d_shift_register =
128  ((d_shift_register >> 1) | (newbit << d_shift_register_length));
129  return output;
130  }
131 
132  unsigned char next_bit_descramble(unsigned char input)
133  {
134  unsigned char output;
135 #ifdef HAVE_BUILTIN_PARITYL
136  output = __builtin_parityl(d_shift_register & d_mask) ^ (input & 1);
137 #else
138  uint64_t _tmp;
139  volk_64u_popcnt(&_tmp, d_shift_register & d_mask);
140  output = (_tmp ^ input) & 1;
141 #endif
142  uint64_t newbit = input & 1;
143  d_shift_register =
144  ((d_shift_register >> 1) | (newbit << d_shift_register_length));
145  return output;
146  }
147 
148  /*!
149  * Reset shift register to initial seed value
150  */
151  void reset() { d_shift_register = d_seed; }
152 
153  /*!
154  * Rotate the register through x number of bits
155  * where we are just throwing away the results to get queued up correctly
156  */
157  void pre_shift(int num)
158  {
159  for (int i = 0; i < num; i++) {
160  next_bit();
161  }
162  }
163 
164  uint64_t mask() const { return d_mask; }
165 };
166 
167 } /* namespace digital */
168 } /* namespace gr */
169 
170 #endif /* INCLUDED_DIGITAL_LFSR_H */
Fibonacci Linear Feedback Shift Register using specified polynomial mask.
Definition: lfsr.h:83
void pre_shift(int num)
Definition: lfsr.h:157
void reset()
Definition: lfsr.h:151
unsigned char next_bit_descramble(unsigned char input)
Definition: lfsr.h:132
unsigned char next_bit()
Definition: lfsr.h:101
lfsr(uint64_t mask, uint64_t seed, uint8_t reg_len)
Definition: lfsr.h:91
uint64_t mask() const
Definition: lfsr.h:164
unsigned char next_bit_scramble(unsigned char input)
Definition: lfsr.h:117
GNU Radio logging wrapper.
Definition: basic_block.h:29