openMSX
CRC16.hh
Go to the documentation of this file.
1 #ifndef CRC16_HH
2 #define CRC16_HH
3 
4 #include "openmsx.hh"
5 #include <cstring> // for size_t
6 
7 namespace openmsx {
8 
13 class CRC16
14 {
15 public:
18  explicit CRC16(word initialCRC = 0xFFFF)
19  {
20  init(initialCRC);
21  }
22 
25  void init(word initialCRC)
26  {
27  crc = initialCRC;
28  }
29 
33  template<byte V1> void init()
34  {
35  static const word T0 = 0xffff;
36  static const word T1 = CT_CRC16<T0, V1>::value;
37  init(T1);
38  }
39  template<byte V1, byte V2> void init()
40  {
41  static const word T0 = 0xffff;
42  static const word T1 = CT_CRC16<T0, V1>::value;
43  static const word T2 = CT_CRC16<T1, V2>::value;
44  init(T2);
45  }
46  template<byte V1, byte V2, byte V3> void init()
47  {
48  static const word T0 = 0xffff;
49  static const word T1 = CT_CRC16<T0, V1>::value;
50  static const word T2 = CT_CRC16<T1, V2>::value;
51  static const word T3 = CT_CRC16<T2, V3>::value;
52  init(T3);
53  }
54  template<byte V1, byte V2, byte V3, byte V4> void init()
55  {
56  static const word T0 = 0xffff;
57  static const word T1 = CT_CRC16<T0, V1>::value;
58  static const word T2 = CT_CRC16<T1, V2>::value;
59  static const word T3 = CT_CRC16<T2, V3>::value;
60  static const word T4 = CT_CRC16<T3, V4>::value;
61  init(T4);
62  }
63 
66  void update(byte value)
67  {
68  // Classical byte-at-a-time algorithm by Dilip V. Sarwate
69  crc = (crc << 8) ^ tab[0][(crc >> 8) ^ value];
70  }
71 
75  void update(const byte* data, size_t size)
76  {
77  // Based on:
78  // Slicing-by-4 and slicing-by-8 algorithms by Michael E.
79  // Kounavis and Frank L. Berry from Intel Corp.
80  // http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
81  // and the implementation by Peter Kankowski found on:
82  // http://www.strchr.com/crc32_popcnt
83  // I transformed the code from CRC32 to CRC16 (this was not
84  // trivial because both CRCs use a different convention about
85  // bit order). I also made the code also work on bigendian
86  // hosts.
87 
88  unsigned c = crc; // 32-bit are faster than 16-bit calculations
89  // on x86 and many other modern architectures
90  // calculate the bulk of the data 8 bytes at a time
91  for (auto n = size / 8; n; --n) {
92  c = tab[7][data[0] ^ (c >> 8)] ^
93  tab[6][data[1] ^ (c & 255)] ^
94  tab[5][data[2]] ^
95  tab[4][data[3]] ^
96  tab[3][data[4]] ^
97  tab[2][data[5]] ^
98  tab[1][data[6]] ^
99  tab[0][data[7]];
100  data += 8;
101  }
102  // calculate the remaining bytes in the usual way
103  for (size &= 7; size; --size) {
104  c = word(c << 8) ^ tab[0][(c >> 8) ^ *data++];
105  }
106  crc = c; // store back in a 16-bit result
107  }
108 
111  word getValue() const
112  {
113  return crc;
114  }
115 
116 private:
117  word crc;
118  static const word tab[8][256];
119 
120  // The Stuff below is template magic to perform the following
121  // computation at compile-time:
122  // for (int i = 8; i < 16; ++i) {
123  // crc = (crc << 1) ^ ((((crc ^ (data << i)) & 0x8000) ? 0x1021 : 0));
124  // }
125  template<word C, word V, int B> struct CT_H {
126  static const word D = word(C << 1) ^ (((C ^ V) & 0x8000) ? 0x1021 : 0);
127  static const word value = CT_H<D, word(V << 1), B - 1>::value;
128  };
129  template<word C, word V> struct CT_H<C, V, 0> {
130  static const word value = C;
131  };
132  template<word IN, byte VAL> struct CT_CRC16 : CT_H<IN, VAL << 8, 8> {};
133 };
134 
135 } // namespace openmsx
136 
137 #endif