/*=============================================================================
|
| NAME
|
|      shiftRegister.h
|
| DESCRIPTION
|
|     Class definition for a binary linear feedback shift register.
|
| AUTHOR
|
|      Sean O'Connor
|    
| LEGAL
|
|     CRCDemo Version 2.1 - A Program for generating and checking CRC codes.
|     Copyright (C) 1999-2017 by Sean Erik O'Connor.  All Rights Reserved.
|
|     This program is free software: you can redistribute it and/or modify
|     it under the terms of the GNU General Public License as published by
|     the Free Software Foundation, either version 3 of the License, or
|     (at your option) any later version.
|
|     This program is distributed in the hope that it will be useful,
|     but WITHOUT ANY WARRANTY; without even the implied warranty of
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
|     GNU General Public License for more details.
|
|     You should have received a copy of the GNU General Public License
|     along with this program.  If not, see <http://www.gnu.org/licenses/>.
|     
|     The author's address is artificer!AT!seanerikoconnor!DOT!freeservers!DOT!com
|     with !DOT! replaced by . and the !AT! replaced by @
|
+============================================================================*/

#ifndef __SHIFT_REGISTER_H__
#define __SHIFT_REGISTER_H__

#include "dataTypes.h"

#include <string>
using namespace std ;


/*=============================================================================
|
| NAME
|  
|     ShiftRegister
|
| DESCRIPTION
|  
|     Simulation of a binary linear feedback shift register, used to 
|     generate or check a CRC code.
|
| NOTES|
|                                     n-k
|     This circuit computes [ i( x ) x    ] mod g( x ) where
|
|                   n-k            n-k-1
|         g( x ) = x     + g      x      + ... + g x  +  g
|                           n-k-1                 1       0
|
|                       k-1
|         i( x ) = a   x     + ... + a x  +  a
|                   k-1               1       0
|
|     Polynomial coefficients are in the field GF( 2 ), i.e. 
|     modulo 2 arithmetic.
|
|       +---------------------+-----------------------+--------------+
|       |                     |                       |              |
|       |                     v                       |              v
|       |                 +-------+                +-----+        +-----+
|       |                 | g     |                | g   |        | g   |
|     +---+               |  n-k-1|                |  1  |        |  0  |
|     | -1|               +-------+                +-----+        +-----+
|     +---+                   |                       |              |
|       ^        +--------+   |             +-----+   |  +------+    |
|       |        |  (k)   |   v             |  (k)|   v  |  (k) |    |
|       +<-------| a      |<--+--- ... -----| a   |<--+--| a    |<---+
|       |        |  n-k-1 |                 |  1  |      |  0   |
|       |        +--------+                 +-----+      +------+
|       |
|    { a   ... a  }
|       k-1     0
|
|                                            (0)
|     Shift register contents is initially  a        = ... = a = 0
|                                            n-k-1            0
|            
|     The bits a  are shifted in at the left.
|               i
|
|     After k shifts the shift register contents is
|
|                  n-k
|         i( x ) x     mod g( x ) = 
|
|              (k)   n-k-1          (k)        (k)
|             a     x      + ... + a    x  +  a
|              n-k-1                1          0
|
|     The shift register contents is encoded in reverse order from 
|     the above diagram:  The least significant bit in the contents
|     is the coefficient
|
|        (k)                    (k)
|      a      and the msb is  a     
|        n-k-1                  0
|
|     Advantages:
|         (1) We are independent of the computer hardware's word size.
|         (2) It is easier to compute feedback, which we can do by
|             accessing the least significant bit, also in a machine
|             independent way.
|
|     Disadvantages:
|         We must reverse the bits when we print out the result.
|
|     We store the coefficients of g( x ) in a packed binary format. 
|     For example, if g( x ) = x ^ 16  +  x ^ 15  +  x ^ 2  +  1
|     we represent g( x ) as A001 (hexadecimal).  This is the scheme:
|
|     Coefficients:           1 1000 0000 0000 0101
|     x ^ 16 term dropped:    1000 0000 0000 0101
|     Reversed:               1010 0000 0000 0001
|     Hexadecimal:              A    0    0    1
|
|  Example
|
|                             16    15    2             16
|         CRC-16 is g( x ) = x  +  x  +  x  +  1,  n = 2  - 1, n - k = 16.
|
|                       8
|         Let i( x ) = x  +  x.   Coefficients of i are 
|         0001 0000 0010 [binary] = 0102 [hex] = ^A ^B [ascii]
|
|                        n-k
|         Then [ i( x ) x   ] mod g( x ) = 
|
|          24     17      16    15    2        10    9     3     2
|         x    + x   mod x  +  x  +  x + 1  = x  +  x  +  x  +  x
|
|         Coefficients are 0000 0110 0000 1100 [binary] = 060C [hex].
|
| References:
|
|     "Generating CRCs with software", Robert Grappel, EDN Magazine,
|      October 31, 1984, pg. 205.
|
|      Fairchild Advanced Schottky TTL Databook,
|      54/74F401 CRC Generator/Checker.
| BUGS
|
+============================================================================*/

class ShiftRegister
{
    public:
        // Initialize shift register with a given polynomial g( x ).
        ShiftRegister( const string & g ) ;

        // Destructor.
       ~ShiftRegister( void ) ;

        // Shift one bit into the shift register.
        void shiftInBit( int dataBit ) ;

        // Shift one 8-bit byte into the shift register
        void shiftInByte( unsigned char dataByte ) ;

        // Return the contents of the shift register 
        // (coefficients of the polynomial in binary format).
        syndrome_t shiftRegContents( void ) ;

        // Clear the shift register.
        void clear( syndrome_t presetValue = 0L ) ;

        // Get the degree of the generator polynomial.
        int getDegreeOfGeneratorPoly( void ) const ;

    private:
        // Shift register contents, packed binary coefficients of
        // the polynomial
        syndrome_t
            contents_ ;

        // Generator polynomial in bit-packed format
        // and its degree.
        int degreeGeneratorPoly_ ;

        syndrome_t
            generatorPoly_ ;

        // Disallow default copy constructor.
        ShiftRegister( const ShiftRegister & shiftRegister ) ;

        // Disallow default assignment operator.
        ShiftRegister & operator=( const ShiftRegister & shiftRegister ) ;
} ;

#endif //__SHIFT_REGISTER_H__