Mistake on this page?
Report an issue in GitHub or email us
MbedCRC.h
1 /* mbed Microcontroller Library
2  * Copyright (c) 2018 ARM Limited
3  * SPDX-License-Identifier: Apache-2.0
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #ifndef MBED_CRC_API_H
18 #define MBED_CRC_API_H
19 
20 #include "cmsis.h"
21 #include "hal/crc_api.h"
22 #ifdef DEVICE_CRC
23 #include "device.h"
24 #endif
25 #include "platform/mbed_assert.h"
26 
27 #ifdef __cplusplus
28 
29 #include "platform/SingletonPtr.h"
30 #include "platform/PlatformMutex.h"
31 
32 #include <mstd_type_traits>
33 
34 namespace mbed {
35 /** \addtogroup drivers-public-api */
36 /** @{*/
37 /**
38  * \defgroup drivers_MbedCRC MbedCRC class
39  * @{
40  */
41 
42 extern SingletonPtr<PlatformMutex> mbed_crc_mutex;
43 
44 /** CRC mode selection
45  */
46 enum class CrcMode {
47  HARDWARE, /// Use hardware (if available), else table-based computation
48  TABLE, /// Use table-based computation (if table available), else bitwise
49  BITWISE /// Always use bitwise manual computation
50 };
51 
52 #ifndef DOXYGEN_ONLY
53 namespace impl {
54 template<uint32_t polynomial, uint8_t width, CrcMode mode>
55 class MbedCRC;
56 
57 constexpr bool have_crc_table(uint32_t polynomial, uint8_t width)
58 {
59 #if MBED_CRC_TABLE_SIZE > 0
60  return (polynomial == POLY_32BIT_ANSI && width == 32) ||
61  (polynomial == POLY_16BIT_IBM && width == 16) ||
62  (polynomial == POLY_16BIT_CCITT && width == 16) ||
63  (polynomial == POLY_8BIT_CCITT && width == 8) ||
64  (polynomial == POLY_7BIT_SD && width == 7);
65 #else
66  return false;
67 #endif
68 }
69 
70 constexpr CrcMode choose_crc_mode(uint32_t polynomial, uint8_t width, CrcMode mode_limit)
71 {
72  return
73 #if DEVICE_CRC
74  mode_limit == CrcMode::HARDWARE && HAL_CRC_IS_SUPPORTED(polynomial, width) ? CrcMode::HARDWARE :
75 #endif
76  mode_limit <= CrcMode::TABLE && have_crc_table(polynomial, width) ? CrcMode::TABLE :
77  CrcMode::BITWISE;
78 }
79 #endif // DOXYGEN_ONLY
80 
81 } // namespace impl
82 
83 /** CRC object provides CRC generation through hardware or software
84  *
85  * CRC sums can be generated using three different methods: hardware, software ROM tables
86  * and bitwise computation. The mode used is normally selected automatically based on required
87  * polynomial and hardware capabilities. Any polynomial in standard form (`x^3 + x + 1`)
88  * can be used for computation, but custom ones can affect the performance.
89  *
90  * First choice is the hardware mode. The supported polynomials are hardware specific, and
91  * you need to consult your MCU manual to discover them. Next, ROM polynomial tables
92  * are tried (you can find list of supported polynomials here ::crc_polynomial). If the selected
93  * configuration is supported, it will accelerate the software computations. If ROM tables
94  * are not available for the selected polynomial, then CRC is computed at run time bit by bit
95  * for all data input.
96  *
97  * If desired, the mode can be manually limited for a given instance by specifying the mode_limit
98  * template parameter. This might be appropriate to ensure a table is not pulled in for a
99  * non-speed-critical CRC, or to avoid the hardware set-up overhead if you know you will be
100  * calling `compute` with very small data sizes.
101  *
102  * @note Synchronization level: Thread safe
103  *
104  * @tparam polynomial CRC polynomial value in hex
105  * @tparam width CRC polynomial width
106  * @tparam mode_limit Maximum amount of acceleration to use
107  *
108  * Example: Compute CRC data
109  * @code
110  *
111  * #include "mbed.h"
112  *
113  * int main() {
114  * MbedCRC<POLY_32BIT_ANSI, 32> ct;
115  *
116  * char test[] = "123456789";
117  * uint32_t crc = 0;
118  *
119  * printf("\nPolynomial = 0x%lx Width = %d \n", ct.get_polynomial(), ct.get_width());
120  *
121  * ct.compute((void *)test, strlen((const char*)test), &crc);
122  *
123  * printf("The CRC of data \"123456789\" is : 0x%lx\n", crc);
124  * return 0;
125  * }
126  * @endcode
127  * Example: Compute CRC with data available in parts
128  * @code
129  *
130  * #include "mbed.h"
131  * int main() {
132  * MbedCRC<POLY_32BIT_ANSI, 32> ct;
133  *
134  * char test[] = "123456789";
135  * uint32_t crc = 0;
136  *
137  * printf("\nPolynomial = 0x%lx Width = %d \n", ct.get_polynomial(), ct.get_width());
138  * ct.compute_partial_start(&crc);
139  * ct.compute_partial((void *)&test, 4, &crc);
140  * ct.compute_partial((void *)&test[4], 5, &crc);
141  * ct.compute_partial_stop(&crc);
142  * printf("The CRC of data \"123456789\" is : 0x%lx\n", crc);
143  * return 0;
144  * }
145  * @endcode
146  */
147 template <uint32_t polynomial = POLY_32BIT_ANSI, uint8_t width = 32, CrcMode mode_limit = CrcMode::HARDWARE>
148 class MbedCRC {
149  impl::MbedCRC<polynomial, width, impl::choose_crc_mode(polynomial, width, mode_limit)> crc_impl;
150 
151 public:
152  /* Backwards compatibility */
153  enum CrcMode {
154 #if DEVICE_CRC
155  HARDWARE = int(::mbed::CrcMode::HARDWARE),
156 #endif
157  TABLE = int(::mbed::CrcMode::TABLE),
158  BITWISE = int(::mbed::CrcMode::BITWISE)
159  };
160 
161  typedef size_t crc_data_size_t;
162 
163  /** Lifetime of CRC object
164  *
165  * @param initial_xor Initial value/seed to Xor
166  * @param final_xor Final Xor value
167  * @param reflect_data
168  * @param reflect_remainder
169  * @note Default constructor without any arguments is valid only for supported CRC polynomials. :: crc_polynomial_t
170  * MbedCRC <POLY_7BIT_SD, 7> ct; --- Valid POLY_7BIT_SD
171  * MbedCRC <0x1021, 16> ct; --- Valid POLY_16BIT_CCITT
172  * MbedCRC <POLY_16BIT_CCITT, 32> ct; --- Invalid, compilation error
173  * MbedCRC <POLY_16BIT_CCITT, 32> ct (i,f,rd,rr) Constructor can be used for not supported polynomials
174  * MbedCRC<POLY_16BIT_CCITT, 16> sd(0, 0, false, false); Constructor can also be used for supported
175  * polynomials with different initial/final/reflect values
176  *
177  */
178  constexpr
179  MbedCRC(uint32_t initial_xor, uint32_t final_xor, bool reflect_data, bool reflect_remainder) :
180  crc_impl(initial_xor, final_xor, reflect_data, reflect_remainder)
181  {
182  }
183 
184  /* Default values for different types of polynomials
185  */
186  // *INDENT-OFF*
187  template<uint32_t poly = polynomial, std::enable_if_t<poly == POLY_32BIT_ANSI && width == 32, int> = 0>
188  constexpr MbedCRC() : MbedCRC(0xFFFFFFFF, 0xFFFFFFFF, true, true)
189  {
190  }
191 
192  template<uint32_t poly = polynomial, std::enable_if_t<poly == POLY_16BIT_IBM && width == 16, int> = 0>
193  constexpr MbedCRC() : MbedCRC(0, 0, true, true)
194  {
195  }
196 
197  template<uint32_t poly = polynomial, std::enable_if_t<poly == POLY_16BIT_CCITT && width == 16, int> = 0>
198  constexpr MbedCRC() : MbedCRC(0xFFFF, 0, false, false)
199  {
200  }
201 
202  template<uint32_t poly = polynomial, std::enable_if_t<poly == POLY_7BIT_SD && width == 7, int> = 0>
203  constexpr MbedCRC() : MbedCRC(0, 0, false, false)
204  {
205  }
206 
207  template<uint32_t poly = polynomial, std::enable_if_t<poly == POLY_8BIT_CCITT && width == 8, int> = 0>
208  constexpr MbedCRC() : MbedCRC(0, 0, false, false)
209  {
210  }
211  // *INDENT-ON*
212 
213  /** Compute CRC for the data input
214  * Compute CRC performs the initialization, computation and collection of
215  * final CRC.
216  *
217  * @param buffer Data bytes
218  * @param size Size of data
219  * @param crc CRC is the output value
220  * @return 0 on success, negative error code on failure
221  */
222  int32_t compute(const void *buffer, crc_data_size_t size, uint32_t *crc)
223  {
224  return crc_impl.compute(buffer, size, crc);
225  }
226 
227  /** Compute partial CRC for the data input.
228  *
229  * CRC data if not available fully, CRC can be computed in parts with available data.
230  *
231  * In case of hardware, intermediate values and states are saved by hardware. Mutex
232  * locking is used to serialize access to hardware CRC.
233  *
234  * In case of software CRC, previous CRC output should be passed as argument to the
235  * current compute_partial call. Please note the intermediate CRC value is maintained by
236  * application and not the driver.
237  *
238  * @pre: Call `compute_partial_start` to start the partial CRC calculation.
239  * @post: Call `compute_partial_stop` to get the final CRC value.
240  *
241  * @param buffer Data bytes
242  * @param size Size of data
243  * @param crc CRC value is intermediate CRC value filled by API.
244  * @return 0 on success or a negative error code on failure
245  * @note: CRC as output in compute_partial is not final CRC value, call `compute_partial_stop`
246  * to get final correct CRC value.
247  */
248  int32_t compute_partial(const void *buffer, crc_data_size_t size, uint32_t *crc)
249  {
250  return crc_impl.compute_partial(buffer, size, crc);
251  }
252 
253  /** Compute partial start, indicate start of partial computation.
254  *
255  * This API should be called before performing any partial computation
256  * with compute_partial API.
257  *
258  * @param crc Initial CRC value set by the API
259  * @return 0 on success or a negative in case of failure
260  * @note: CRC is an out parameter and must be reused with compute_partial
261  * and `compute_partial_stop` without any modifications in application.
262  */
263  int32_t compute_partial_start(uint32_t *crc)
264  {
265  return crc_impl.compute_partial_start(crc);
266  }
267 
268  /** Get the final CRC value of partial computation.
269  *
270  * CRC value available in partial computation is not correct CRC, as some
271  * algorithms require remainder to be reflected and final value to be XORed
272  * This API is used to perform final computation to get correct CRC value.
273  *
274  * @param crc CRC result
275  * @return 0 on success or a negative in case of failure.
276  */
277  int32_t compute_partial_stop(uint32_t *crc)
278  {
279  return crc_impl.compute_partial_stop(crc);
280  }
281 
282  /** Get the current CRC polynomial.
283  *
284  * @return Polynomial value
285  */
286  static constexpr uint32_t get_polynomial()
287  {
288  return polynomial;
289  }
290 
291  /** Get the current CRC width
292  *
293  * @return CRC width
294  */
295  static constexpr uint8_t get_width()
296  {
297  return width;
298  }
299 };
300 
301 #if !defined(DOXYGEN_ONLY)
302 /* Internal implementation - basically same as public, but actual mode locked in */
303 namespace impl {
304 
305 template <uint32_t polynomial, uint8_t width, CrcMode mode>
306 class MbedCRC {
307 public:
308  typedef size_t crc_data_size_t;
309 
310  constexpr
311  MbedCRC(uint32_t initial_xor, uint32_t final_xor, bool reflect_data, bool reflect_remainder) :
312  _initial_value(adjust_initial_value(initial_xor, reflect_data)),
313  _final_xor(final_xor),
314  _reflect_data(reflect_data),
315  _reflect_remainder(reflect_remainder)
316  {
317  static_assert(width <= 32, "Max 32-bit CRC supported");
318  }
319 
320  /** Compute CRC for the data input
321  * Compute CRC performs the initialization, computation and collection of
322  * final CRC.
323  *
324  * @param buffer Data bytes
325  * @param size Size of data
326  * @param crc CRC is the output value
327  * @return 0 on success, negative error code on failure
328  */
329  int32_t compute(const void *buffer, crc_data_size_t size, uint32_t *crc)
330  {
331  int32_t status;
332 
333  status = compute_partial_start(crc);
334  if (0 != status) {
335  return status;
336  }
337 
338  status = compute_partial(buffer, size, crc);
339  if (0 != status) {
340  return status;
341  }
342 
343  status = compute_partial_stop(crc);
344  return status;
345  }
346 
347  /** Compute partial CRC for the data input.
348  *
349  * CRC data if not available fully, CRC can be computed in parts with available data.
350  *
351  * In case of hardware, intermediate values and states are saved by hardware. Mutex
352  * locking is used to serialize access to hardware CRC.
353  *
354  * In case of software CRC, previous CRC output should be passed as argument to the
355  * current compute_partial call. Please note the intermediate CRC value is maintained by
356  * application and not the driver.
357  *
358  * @pre: Call `compute_partial_start` to start the partial CRC calculation.
359  * @post: Call `compute_partial_stop` to get the final CRC value.
360  *
361  * @param buffer Data bytes
362  * @param size Size of data
363  * @param crc CRC value is intermediate CRC value filled by API.
364  * @return 0 on success or a negative error code on failure
365  * @note: CRC as output in compute_partial is not final CRC value, call `compute_partial_stop`
366  * to get final correct CRC value.
367  */
368  int32_t compute_partial(const void *buffer, crc_data_size_t size, uint32_t *crc)
369  {
370  const uint8_t *data = static_cast<const uint8_t *>(buffer);
371  return do_compute_partial(data, size, crc);
372  }
373 
374  /** Compute partial start, indicate start of partial computation.
375  *
376  * This API should be called before performing any partial computation
377  * with compute_partial API.
378  *
379  * @param crc Initial CRC value set by the API
380  * @return 0 on success or a negative in case of failure
381  * @note: CRC is an out parameter and must be reused with compute_partial
382  * and `compute_partial_stop` without any modifications in application.
383  */
384  int32_t compute_partial_start(uint32_t *crc)
385  {
386 #if DEVICE_CRC
387  if (mode == CrcMode::HARDWARE) {
388  lock();
389  crc_mbed_config_t config;
390  config.polynomial = polynomial;
391  config.width = width;
392  config.initial_xor = _initial_value;
393  config.final_xor = _final_xor;
394  config.reflect_in = _reflect_data;
395  config.reflect_out = _reflect_remainder;
396 
398  }
399 #endif
400 
401  *crc = _initial_value;
402  return 0;
403  }
404 
405  /** Get the final CRC value of partial computation.
406  *
407  * CRC value available in partial computation is not correct CRC, as some
408  * algorithms require remainder to be reflected and final value to be XORed
409  * This API is used to perform final computation to get correct CRC value.
410  *
411  * @param crc CRC result
412  * @return 0 on success or a negative in case of failure.
413  */
414  int32_t compute_partial_stop(uint32_t *crc)
415  {
416 #if DEVICE_CRC
417  if (mode == CrcMode::HARDWARE) {
418  *crc = hal_crc_get_result();
419  unlock();
420  return 0;
421  }
422 #endif
423  uint_fast32_t p_crc = *crc;
424  if (mode == CrcMode::BITWISE) {
425  if (_reflect_data) {
426  /* CRC has MSB in bottom bit of register */
427  if (!_reflect_remainder) {
428  p_crc = reflect_crc(p_crc);
429  }
430  } else {
431  /* CRC has MSB in top bit of register */
432  p_crc = _reflect_remainder ? reflect(p_crc) : shift_right(p_crc);
433  }
434  } else { // TABLE
435  /* CRC has MSB in bottom bit of register */
436  if (!_reflect_remainder) {
437  p_crc = reflect_crc(p_crc);
438  }
439  }
440 
441  p_crc ^= _final_xor;
442  p_crc &= get_crc_mask();
443  *crc = p_crc;
444 
445  return 0;
446  }
447 
448 private:
449  /** Guaranteed constexpr reflection (all toolchains)
450  *
451  * @note This should never be run-time evaluated - very inefficient
452  * @param Register value to be reflected (full 32-bit value)
453  * @return Reflected value (full 32-bit value)
454  */
455  static constexpr uint32_t reflect_constant(uint32_t data)
456  {
457  /* Doing this hard way to keep it C++11 constexpr and hence ARM C 5 compatible */
458  return ((data & 0x00000001) << 31) |
459  ((data & 0x00000002) << 29) |
460  ((data & 0x00000004) << 27) |
461  ((data & 0x00000008) << 25) |
462  ((data & 0x00000010) << 23) |
463  ((data & 0x00000020) << 21) |
464  ((data & 0x00000040) << 19) |
465  ((data & 0x00000080) << 17) |
466  ((data & 0x00000100) << 15) |
467  ((data & 0x00000200) << 13) |
468  ((data & 0x00000400) << 11) |
469  ((data & 0x00000800) << 9) |
470  ((data & 0x00001000) << 7) |
471  ((data & 0x00002000) << 5) |
472  ((data & 0x00004000) << 3) |
473  ((data & 0x00008000) << 1) |
474  ((data & 0x00010000) >> 1) |
475  ((data & 0x00020000) >> 3) |
476  ((data & 0x00040000) >> 5) |
477  ((data & 0x00080000) >> 7) |
478  ((data & 0x00100000) >> 9) |
479  ((data & 0x00200000) >> 11) |
480  ((data & 0x00400000) >> 13) |
481  ((data & 0x00800000) >> 15) |
482  ((data & 0x01000000) >> 17) |
483  ((data & 0x02000000) >> 19) |
484  ((data & 0x04000000) >> 21) |
485  ((data & 0x08000000) >> 23) |
486  ((data & 0x10000000) >> 25) |
487  ((data & 0x20000000) >> 27) |
488  ((data & 0x40000000) >> 29) |
489  ((data & 0x80000000) >> 31);
490  }
491 
492  /** General reflection
493  *
494  * @note This is used when we may need to perform run-time computation, so
495  * we need the possibility to produce the optimal run-time RBIT instruction. But
496  * if the compiler doesn't treat RBIT as a built-in, it's useful to have a C fallback
497  * for the constant case, avoiding runtime RBIT(0) computations. This is an
498  * optimization only available for some toolchains; others will always use runtime
499  * RBIT. If we require a constant expression, use reflect_constant instead.
500  *
501  * @param Register value to be reflected (full 32-bit value)
502  * @return Reflected value (full 32-bit value)
503  */
504 #ifdef MSTD_HAS_IS_CONSTANT_EVALUATED
505  static constexpr uint32_t reflect(uint32_t data)
506  {
507  return mstd::is_constant_evaluated() ? reflect_constant(data) : __RBIT(data);
508  }
509 #else
510  static uint32_t reflect(uint32_t data)
511  {
512  return __RBIT(data);
513  }
514 #endif
515 
516  /** Data bytes may need to be reflected.
517  *
518  * @param data value to be reflected (bottom 8 bits)
519  * @return Reflected value (bottom 8 bits)
520  */
521  static MSTD_CONSTEXPR_IF_HAS_IS_CONSTANT_EVALUATED
522  uint_fast32_t reflect_byte(uint_fast32_t data)
523  {
524  return reflect(data) >> 24;
525  }
526 
527  /** Get the current CRC polynomial, reflected at bottom of register.
528  *
529  * @return Reflected polynomial value (so x^width term would be at bit -1)
530  */
531  static constexpr uint32_t get_reflected_polynomial()
532  {
533  return shift_right(reflect_constant(polynomial));
534  }
535 
536  /** Get the current CRC polynomial, at top of register.
537  *
538  * @return Shifted polynomial value (so x^width term would be at bit 32)
539  */
540  static constexpr uint32_t get_top_polynomial()
541  {
542  return shift_left(polynomial);
543  }
544 
545  const uint32_t _initial_value;
546  const uint32_t _final_xor;
547  const bool _reflect_data;
548  const bool _reflect_remainder;
549 
550  // *INDENT-OFF*
551  using crc_table_t = std::conditional_t<width <= 8, uint8_t,
552  std::conditional_t<width <= 16, uint16_t,
553  uint32_t
554  >>;
555  // *INDENT-ON*
556 
557 #if MBED_CRC_TABLE_SIZE > 0
558  /* Tables only actually defined for mode == TABLE, and certain polynomials - see below */
559  static const crc_table_t _crc_table[MBED_CRC_TABLE_SIZE];
560 #endif
561 
562  static constexpr uint32_t adjust_initial_value(uint32_t initial_xor, bool reflect_data)
563  {
564  if (mode == CrcMode::BITWISE) {
565  /* For bitwise calculation, CRC register is reflected if data is, to match input.
566  * (MSB at bottom of register). If not reflected, it is at the top of the register
567  * (MSB at top of register).
568  */
569  return reflect_data ? reflect_crc(initial_xor) : shift_left(initial_xor);
570  } else if (mode == CrcMode::TABLE) {
571  /* For table calculation, CRC value is reflected, to match tables.
572  * (MSB at bottom of register). */
573  return reflect_crc(initial_xor);
574  } else { // CrcMode::HARDWARE
575  return initial_xor;
576  }
577  }
578 
579  /** Acquire exclusive access to CRC hardware/software.
580  */
581  static void lock()
582  {
583 #if DEVICE_CRC
584  if (mode == CrcMode::HARDWARE) {
585  mbed_crc_mutex->lock();
586  }
587 #endif
588  }
589 
590  /** Release exclusive access to CRC hardware/software.
591  */
592  static void unlock()
593  {
594 #if DEVICE_CRC
595  if (mode == CrcMode::HARDWARE) {
596  mbed_crc_mutex->unlock();
597  }
598 #endif
599  }
600 
601  /** Get the CRC data mask.
602  *
603  * @return CRC data mask is generated based on current CRC width
604  */
605  static constexpr uint32_t get_crc_mask()
606  {
607  return (uint32_t)((uint32_t)2U << (width - 1)) - 1U;
608  }
609 
610  /** CRC values may need to be reflected.
611  *
612  * @param CRC value to be reflected (width bits at bottom of 32-bit word)
613  * @return Reflected value (still at bottom of 32-bit word)
614  */
615  static MSTD_CONSTEXPR_IF_HAS_IS_CONSTANT_EVALUATED
616  uint32_t reflect_crc(uint32_t data)
617  {
618  return reflect(data) >> (32 - width);
619  }
620 
621  /** Register values may need to be shifted left.
622  *
623  * @param Register value to be shifted up (in bottom width bits)
624  * @return Shifted value (in top width bits)
625  */
626  static constexpr uint32_t shift_left(uint32_t data)
627  {
628  return data << (32 - width);
629  }
630 
631  /** Register values may need to be shifted right.
632  *
633  * @param Register value to be shifted right (in top width bits)
634  * @return Shifted value (in bottom width bits)
635  */
636  static constexpr uint32_t shift_right(uint32_t data)
637  {
638  return data >> (32 - width);
639  }
640 
641  /* Check to see if we can do assembler optimizations */
642 #if (defined __GNUC__ || defined __clang__) && \
643  (defined __arm__ || defined __ARM_ARCH)
644 #if (__ARM_ARCH_7M__ == 1U) || \
645  (__ARM_ARCH_7EM__ == 1U) || \
646  (__ARM_ARCH_8M_MAIN__ == 1U) || \
647  (__ARM_ARCH_8_1M_MAIN__ == 1U) || \
648  (__ARM_ARCH_7A__ == 1U)
649  /* ARM that has Thumb-2 - same unified assembly is good for either ARM or Thumb state (LSRS; IT CS; EORCS reg/imm) */
650 #define MBED_CRC_ARM_THUMB2 1
651 #define MBED_CRC_THUMB1 0
652 #elif (__ARM_ARCH_6M__ == 1U) || \
653  (__ARM_ARCH_8M_BASE__ == 1U)
654  /* Thumb-1-only ARM-M device - use Thumb-1 compatible assembly with branch (LSRS; BCC; EORS reg) */
655 #define MBED_CRC_ARM_THUMB2 0
656 #define MBED_CRC_THUMB1 1
657 #else // __ARM_ARCH_xxx
658 #error "Unknown ARM architecture for CRC optimization"
659 #endif // __ARM_ARCH_xxx
660 #else // __arm__ || defined __ICC_ARM__ || defined __ARM_ARCH
661  /* Seem to be compiling for non-ARM, or an unsupported toolchain, so stick with C implementations */
662 #define MBED_CRC_ARM_THUMB2 0
663 #define MBED_CRC_THUMB1 0
664 #endif
665 
666  // *INDENT-OFF*
667  /** Process 1 bit of non-reflected CRC
668  *
669  * Shift the p_crc register left 1 bit - if a one is shifted
670  * out, exclusive-or with the polynomial mask.
671  *
672  * Assembler optimizations can be applied here, to make
673  * use of the CPU's carry output from shifts.
674  *
675  * @param p_crc input register value
676  * @return updated register value
677  */
678  static uint_fast32_t do_1_bit_normal(uint_fast32_t p_crc)
679  {
680 #if MBED_CRC_ARM_THUMB2
681  __asm(".syntax unified\n\t"
682  "LSLS" "\t%[p_crc], %[p_crc], #1\n\t"
683  "IT" "\tCS\n\t"
684  "EORCS" "\t%[p_crc], %[poly]"
685  : [p_crc] "+&r" (p_crc)
686  : [poly] "rI" (get_top_polynomial())
687  : "cc");
688 #elif MBED_CRC_THUMB1
689  __asm(".syntax unified\n\t"
690  "LSLS" "\t%[p_crc], %[p_crc], #1\n\t"
691  "BCC" "\t%=f\n\t"
692  "EORS" "\t%[p_crc], %[poly]\n"
693  "%=:"
694  : [p_crc] "+&l" (p_crc)
695  : [poly] "l" (get_top_polynomial())
696  : "cc");
697 #else
698  if (p_crc & 0x80000000) {
699  p_crc = (p_crc << 1) ^ get_top_polynomial();
700  } else {
701  p_crc = (p_crc << 1);
702  }
703 #endif
704  return p_crc;
705  }
706 
707  /** Process 1 bit of reflected CRC
708  *
709  * Shift the p_crc register right 1 bit - if a one is shifted
710  * out, exclusive-or with the polynomial mask.
711  *
712  * Assembler optimizations can be applied here, to make
713  * use of the CPU's carry output from shifts.
714  *
715  * @param p_crc input register value
716  * @return updated register value
717  */
718  static uint_fast32_t do_1_bit_reflected(uint_fast32_t p_crc)
719  {
720 #if MBED_CRC_ARM_THUMB2
721  __asm(".syntax unified\n\t"
722  "LSRS" "\t%[p_crc], %[p_crc], #1\n\t"
723  "IT" "\tCS\n\t"
724  "EORCS" "\t%[p_crc], %[poly]"
725  : [p_crc] "+&r" (p_crc)
726  : [poly] "rI" (get_reflected_polynomial())
727  : "cc");
728 #elif MBED_CRC_THUMB1
729  __asm(".syntax unified\n\t"
730  "LSRS" "\t%[p_crc], %[p_crc], #1\n\t"
731  "BCC" "\t%=f\n\t"
732  "EORS" "\t%[p_crc], %[poly]\n"
733  "%=:"
734  : [p_crc] "+&l" (p_crc)
735  : [poly] "l" (get_reflected_polynomial())
736  : "cc");
737 #else
738  if (p_crc & 1) {
739  p_crc = (p_crc >> 1) ^ get_reflected_polynomial();
740  } else {
741  p_crc = (p_crc >> 1);
742  }
743 #endif
744  return p_crc;
745  }
746  // *INDENT-ON*
747 
748  /** Bitwise CRC computation.
749  *
750  * @param buffer data buffer
751  * @param size size of the data
752  * @param crc CRC value is filled in, but the value is not the final
753  * @return 0 on success or a negative error code on failure
754  */
755  template<CrcMode mode_ = mode>
756  std::enable_if_t<mode_ == CrcMode::BITWISE, int32_t>
757  do_compute_partial(const uint8_t *data, crc_data_size_t size, uint32_t *crc) const
758  {
759  uint_fast32_t p_crc = *crc;
760 
761  if (_reflect_data) {
762  /* Everything is reflected to match data - MSB of polynomial at bottom of 32-bit register */
763  for (crc_data_size_t byte = 0; byte < size; byte++) {
764  p_crc ^= data[byte];
765 
766  // Perform modulo-2 division, a bit at a time
767  for (unsigned int bit = 8; bit > 0; --bit) {
768  p_crc = do_1_bit_reflected(p_crc);
769  }
770  }
771  } else {
772  /* Polynomial is shifted to put MSB of polynomial at top of 32-bit register */
773  for (crc_data_size_t byte = 0; byte < size; byte++) {
774  p_crc ^= (uint_fast32_t) data[byte] << 24;
775 
776  // Perform modulo-2 division, a bit at a time
777  for (unsigned int bit = 8; bit > 0; --bit) {
778  p_crc = do_1_bit_normal(p_crc);
779  }
780  }
781  }
782 
783  *crc = p_crc;
784 
785  return 0;
786  }
787 
788 #if MBED_CRC_TABLE_SIZE > 0
789  /** CRC computation using ROM tables.
790  *
791  * @param buffer data buffer
792  * @param size size of the data
793  * @param crc CRC value is filled in, but the value is not the final
794  * @return 0 on success or a negative error code on failure
795  */
796  template<CrcMode mode_ = mode>
797  std::enable_if_t<mode_ == CrcMode::TABLE, int32_t>
798  do_compute_partial(const uint8_t *data, crc_data_size_t size, uint32_t *crc) const
799  {
800  uint_fast32_t p_crc = *crc;
801  // GCC has been observed to not hoist the load of _reflect_data out of the loop
802  // Note the inversion because table and CRC are reflected - data must be
803  bool reflect = !_reflect_data;
804 
805  for (crc_data_size_t byte = 0; byte < size; byte++) {
806  uint_fast32_t data_byte = data[byte];
807  if (reflect) {
808  data_byte = reflect_byte(data_byte);
809  }
810 #if MBED_CRC_TABLE_SIZE == 16
811  p_crc = _crc_table[(data_byte ^ p_crc) & 0xF] ^ (p_crc >> 4);
812  data_byte >>= 4;
813  p_crc = _crc_table[(data_byte ^ p_crc) & 0xF] ^ (p_crc >> 4);
814 #else
815  p_crc = _crc_table[(data_byte ^ p_crc) & 0xFF] ^ (p_crc >> 8);
816 #endif
817  }
818  *crc = p_crc;
819  return 0;
820  }
821 #endif
822 
823 #ifdef DEVICE_CRC
824  /** Hardware CRC computation.
825  *
826  * @param buffer data buffer
827  * @param size size of the data
828  * @return 0 on success or a negative error code on failure
829  */
830  template<CrcMode mode_ = mode>
831  std::enable_if_t<mode_ == CrcMode::HARDWARE, int32_t>
832  do_compute_partial(const uint8_t *data, crc_data_size_t size, uint32_t *) const
833  {
834  hal_crc_compute_partial(data, size);
835  return 0;
836  }
837 #endif
838 
839 };
840 
841 #if MBED_CRC_TABLE_SIZE > 0
842 /* Declarations of the tables we provide. (Not strictly needed, but compilers
843  * can warn if they see us using the template without a generic definition, so
844  * let it know we have provided these specialisations.)
845  */
846 template<>
847 const uint8_t MbedCRC<POLY_7BIT_SD, 7, CrcMode::TABLE>::_crc_table[MBED_CRC_TABLE_SIZE];
848 
849 template<>
850 const uint8_t MbedCRC<POLY_8BIT_CCITT, 8, CrcMode::TABLE>::_crc_table[MBED_CRC_TABLE_SIZE];
851 
852 template<>
853 const uint16_t MbedCRC<POLY_16BIT_CCITT, 16, CrcMode::TABLE>::_crc_table[MBED_CRC_TABLE_SIZE];
854 
855 template<>
856 const uint16_t MbedCRC<POLY_16BIT_IBM, 16, CrcMode::TABLE>::_crc_table[MBED_CRC_TABLE_SIZE];
857 
858 template<>
859 const uint32_t MbedCRC<POLY_32BIT_ANSI, 32, CrcMode::TABLE>::_crc_table[MBED_CRC_TABLE_SIZE];
860 
861 #endif // MBED_CRC_TABLE_SIZE > 0
862 
863 } // namespace impl
864 
865 #endif // !defined(DOXYGEN_ONLY)
866 
867 /** @}*/
868 /** @}*/
869 
870 } // namespace mbed
871 
872 #endif // __cplusplus
873 
874 /* Internal helper for mbed_error.c crash recovery */
875 #ifdef __cplusplus
876 extern "C"
877 #endif
878 uint32_t mbed_tiny_compute_crc32(const void *data, int datalen);
879 
880 #endif
x16+x15+x2+1
Definition: crc_api.h:34
x7+x3+1
Definition: crc_api.h:31
uint32_t final_xor
Final xor value for the computation.
Definition: crc_api.h:46
void hal_crc_compute_partial_start(const crc_mbed_config_t *config)
Initialize the hardware CRC module with the given polynomial.
uint32_t width
CRC Bit Width.
Definition: crc_api.h:42
void unlock()
Unlock a PlatformMutex that the same thread has previously locked.
Definition: PlatformMutex.h:81
x16+x12+x5+1
Definition: crc_api.h:33
void lock()
Wait until a PlatformMutex becomes available.
Definition: PlatformMutex.h:71
x8+x2+x+1
Definition: crc_api.h:32
void hal_crc_compute_partial(const uint8_t *data, const size_t size)
Writes data to the current CRC module.
bool reflect_out
Reflect bits in final result before returning.
Definition: crc_api.h:50
uint32_t polynomial
CRC Polynomial.
Definition: crc_api.h:40
x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1
Definition: crc_api.h:35
bool reflect_in
Reflect bits on input.
Definition: crc_api.h:48
Definition: ATHandler.h:46
uint32_t initial_xor
Initial seed value for the computation.
Definition: crc_api.h:44
Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.