1/*=============================================================================
2|
3| NAME
4|
5| shiftRegister.cpp
6|
7| DESCRIPTION
8|
9| Binary linear feedback shift register class implementation.
10|
11| AUTHOR
12|
13| Sean O'Connor
14|
15| LEGAL
16|
17| CRCDemo Version 2.1 - A Program for generating and checking CRC codes.
18| Copyright (C) 1999-2025 by Sean Erik O'Connor. All Rights Reserved.
19|
20| This program is free software: you can redistribute it and/or modify
21| it under the terms of the GNU General Public License as published by
22| the Free Software Foundation, either version 3 of the License, or
23| (at your option) any later version.
24|
25| This program is distributed in the hope that it will be useful,
26| but WITHOUT ANY WARRANTY; without even the implied warranty of
27| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28| GNU General Public License for more details.
29|
30| You should have received a copy of the GNU General Public License
31| along with this program. If not, see <http://www.gnu.org/licenses/>.
32|
33| The author's address is seanerikoconnor!AT!gmail!DOT!com
34| with !DOT! replaced by . and the !AT! replaced by @
35|
36+============================================================================*/
37
38#include <string>
39using namespace std ;
40
41#include "dataTypes.hpp"
42#include "shiftRegister.hpp" // class Shift_register()
43
44
45
46/*=============================================================================
47|
48| NAME
49|
50| ShiftRegister
51|
52| DESCRIPTION
53|
54| Contructor for ShiftRegister class. Initializes shift register contents
55| to zero, and sets up the given generator polynomial.
56|
57| PARAMETERS
58|
59| generatorPoly (Input) Generator polynomial (yields shift register feedback
60| connections). Input in the form of a string. e.g.
61| ShiftRegister sr( "x ^ 16 + x ^ 15 + x ^ 2 + 1" ) ;
62| RETURNS
63|
64| EXCEPTIONS
65|
66| If there is an error, the degree of the generator polynomial
67| is zero.
68|
69| SIDE EFFECTS
70|
71| METHOD
72|
73| Read the polynomial string backwards, from lowest to highest degree
74| coefficients. Handle the constant term and x term as special cases.
75| Pack the coefficients into the generator polynomial in reverse bit order,
76| dropping the highest degree term.
77|
78| For example, if g( x ) = x ^ 16 + x ^ 15 + x ^ 2 + 1
79| we represent g( x ) as A001 (hexadecimal). This is the scheme:
80|
81| Coefficients: 1 1000 0000 0000 0101
82| Reversed: 1010 0000 0000 0001 1
83| x ^ 16 term dropped: 1010 0000 0000 0001
84| Hexadecimal: A 0 0 1
85|
86| Another example is CRC-32Q which has generator polynomial,
87| g( x ) = x^32+x^31+x^24+x^22+x^16+x^14+x^8+x^7+x^5+x^3+x+1
88|
89| Coefficients: 1 1000 0001 0100 0001 0100 0001 1010 1011
90| Reversed: 1101 0101 1000 0010 1000 0010 1000 0001 1
91| x ^ 16 term dropped: 1101 0101 1000 0010 1000 0010 1000 0001
92| Hexadecimal: D 5 8 2 8 2 8 1
93|
94| BUGS
95|
96| Assumes the polynomial has a constant term.
97| For 32 bit CRC, the leading bit in the generator
98| polynomial is trashed to zero.
99|
100| AUTHOR
101|
102| Sean E. O'Connor 2 February 2000
103|
104+============================================================================*/
105
106ShiftRegister::ShiftRegister( const string & g )
107 : contents_( 0 ) // Initial shift register contents is zero.
108 , generatorPoly_( 0 ) // Polynomial is also initially zero.
109 , degreeGeneratorPoly_( 0 ) // Zero degree, i.e. constant.
110{
111 int i ; // Index of current character in polynomial string.
112 int powerOfX = 0 ;
113 int lastPowerOfX = 0 ;
114
115 // The polynomial string must have at least one character in it.
116 if (g.empty())
117 return ;
118
119 // Point to the last character in the string.
120 i = g.length() - 1 ;
121
122 // Skip trailing blanks at the end of the string.
123 while (g[ i ] == ' ')
124 --i ;
125
126 // Read the polynomial's constant term, if any,
127 // and add it as a 1 bit to the end of the buffer.
128 if (g[ i ] == '1')
129 {
130 generatorPoly_ |= 1 ;
131 --i ;
132 }
133 else // No constant term --- error.
134 return ;
135
136 // Parse the remaining x ^ n terms, assuming there is at
137 // least one of them.
138
139 while (i > 0)
140 {
141 while (g[ i ] == ' ') // Skip any blanks.
142 --i ;
143
144 if (g[ i ] == '+') // Eat the '+'.
145 --i ;
146 else // No plus means bad syntax.
147 return ;
148
149 while (g[ i ] == ' ') // Skip any blanks.
150 --i ;
151
152 // Parse the "x" term, if any, shift left, and add a
153 // 1 bit to the end of the buffer.
154 if (g[ i ] == 'X' || g[ i ] == 'x')
155 {
156 powerOfX = 1 ;
157 --i ;
158 }
159 else // Parse the exponent "n" in the term "x ^ n".
160 {
161 int powerOf10 = 1 ;
162
163 // Read digits from back to front.
164 for (powerOfX = 0 ;
165 i > 0 && ('0' <= g[ i ] && g[ i ] <= '9') ;
166 --i, powerOf10 *= 10)
167 {
168 powerOfX += powerOf10 * (g[ i ] - (int)'0') ;
169 }
170 }
171
172 while (g[ i ] == ' ') // Skip blanks yet again.
173 --i ;
174
175 // Parse the "x ^" part of the term "x ^ n".
176 // If we just parsed "x", we can skip this part.
177 if (powerOfX > 1)
178 {
179 // Parse the exponentiation '^' symbol.
180 if (g[ i ] == '^')
181 --i ;
182 else
183 return ;
184
185 while (g[ i ] == ' ') // Skip blanks.
186 --i ;
187
188 // Parse the "x" symbol.
189 if (g[ i ] == 'X' || g[ i ] == 'x')
190 --i ;
191 else
192 return ;
193
194 } // end parse x ^ n.
195
196
197 // Check that powers of x are increasing.
198 if (powerOfX <= lastPowerOfX)
199 return ;
200
201
202 // Shift the coefficient "x ^ n" into place within
203 // the generator polynomial, in bit reversed order.
204 // If we get the term x^N, where N = number of bits
205 // in the generatorPoly buffer, which is the highest
206 // possible term, shift by one less, since we'll
207 // chop it off below anyway.
208 int shiftLeftAmount = powerOfX - lastPowerOfX ;
209
210 if (powerOfX == (8 * sizeof( generatorPoly_ )))
211 --shiftLeftAmount ;
212
213 for (int j = 0 ; j < shiftLeftAmount ; ++j )
214 generatorPoly_ <<= 1 ;
215
216 generatorPoly_ |= 1 ;
217
218 lastPowerOfX = powerOfX ;
219
220 } // end while i > 0
221
222 // Chop off the leading power of x, unless we've already
223 // handled the x^N case above.
224 if (powerOfX != (8 * sizeof( generatorPoly_ )))
225 generatorPoly_ >>= 1 ;
226
227 // Record the generator polynomial degree.
228 degreeGeneratorPoly_ = lastPowerOfX ;
229
230} // --------------------------< end ShiftRegister >----------------------------
231
232
233
234/*=============================================================================
235|
236| NAME
237|
238| shiftInBit
239|
240| DESCRIPTION
241|
242| Shift one bit into the shift register.
243|
244| PARAMETERS
245|
246| dataBit (Input) Bit to shift into the shift register. Must be 1 or 0 only.
247|
248| RETURNS
249|
250| EXCEPTIONS
251|
252| SIDE EFFECTS
253|
254| METHOD
255|
256| BUGS
257|
258| AUTHOR
259|
260| Sean E. O'Connor 2 February 2000
261|
262+============================================================================*/
263
264void ShiftRegister::shiftInBit( int dataBit )
265{
266 syndrome_t feedback = 0 ;
267
268 // To compute the feedback, add incoming data bit and leading bit of
269 // shift register modulo 2. This is an XOR operation in computer talk.
270 // Recall that we've reversed the order of the shift register circuit.
271 if (dataBit ^ (contents_ & 1))
272 feedback = generatorPoly_ ;
273 else
274 feedback = 0 ;
275
276 // Shift.
277 contents_ >>= 1 ;
278
279 // Now were ready to add in the generator polynomial coefficients modulo 2
280 // (or XOR if you prefer).
281 contents_ ^= feedback ;
282
283} // --------------------------< end shiftInBit >----------------------------
284
285
286
287ShiftRegister::~ShiftRegister( void )
288{
289
290}
291
292
293/*=============================================================================
294|
295| NAME
296|
297| shiftInByte
298|
299| DESCRIPTION
300|
301| Shift one byte into the shift register.
302|
303| PARAMETERS
304|
305| dataByte (Input) Byte to shift into the shift register.
306|
307| RETURNS
308|
309| EXCEPTIONS
310|
311| SIDE EFFECTS
312|
313| METHOD
314|
315| BUGS
316|
317| AUTHOR
318|
319| Sean E. O'Connor 2 February 2000
320|
321+============================================================================*/
322
323void ShiftRegister::shiftInByte( unsigned char dataByte )
324{
325 int i = 0 ;
326 unsigned int mask = 0x80 ;
327
328 // Shift in the 8 bits in the byte in left to right order.
329 for (i = 0, mask = 0x80 ; i < 8 ; ++i, mask >>= 1)
330 shiftInBit( ((mask & (unsigned int) dataByte) == 0 ? 0 : 1) ) ;
331
332} // --------------------------< end shiftInByte >----------------------------
333
334
335
336/*=============================================================================
337|
338| NAME
339|
340| shiftRegContents
341|
342| DESCRIPTION
343|
344| Return the contents of the shift register.
345|
346| RETURNS
347|
348| The GF( 2 ) coefficients of the polynomial,
349| n-k
350| i( x ) x mod g( x )
351|
352| packed into a syndrome_t integer. The least significant
353| bit is the constant term of the polynomial.
354|
355| EXCEPTIONS
356|
357| SIDE EFFECTS
358|
359| METHOD
360|
361| BUGS
362|
363| AUTHOR
364|
365| Sean E. O'Connor 2 February 2000
366|
367+============================================================================*/
368
369syndrome_t ShiftRegister::shiftRegContents( void )
370{
371 // in_mask points to the least significant bit in contents.
372 // out_mask points to the most significant bit in the output.
373 syndrome_t in_mask = 1 ;
374 syndrome_t out_mask = (syndrome_t) 1 <<
375 (8 * sizeof( syndrome_t ) - 1) ;
376 syndrome_t reversed = 0 ;
377
378 // Reverse the bit order.
379 for (int i = 0 ; i < 8 * sizeof( syndrome_t ) ; ++i)
380 {
381 if (in_mask & contents_)
382 reversed |= out_mask ;
383
384 out_mask >>= 1 ;
385 in_mask <<= 1 ;
386 }
387
388 return( reversed ) ;
389
390} // --------------------------< end shiftInByte >----------------------------
391
392
393void ShiftRegister::clear( syndrome_t presetValue )
394{
395 contents_ = presetValue ;
396}
397
398// Get the degree of the generator polynomial.
399int ShiftRegister::getDegreeOfGeneratorPoly( void ) const
400{
401 return degreeGeneratorPoly_ ;
402}