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