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_7A__ == 1U)
653  /* ARM that has Thumb-2 - same unified assembly is good for either ARM or Thumb state (LSRS; IT CS; EORCS reg/imm) */
654 #define MBED_CRC_ARM_THUMB2 1
655 #define MBED_CRC_THUMB1 0
656 #elif (__ARM_ARCH_6M__ == 1U) || \
657  (__ARM_ARCH_8M_BASE__ == 1U)
658  /* Thumb-1-only ARM-M device - use Thumb-1 compatible assembly with branch (LSRS; BCC; EORS reg) */
659 #define MBED_CRC_ARM_THUMB2 0
660 #define MBED_CRC_THUMB1 1
661 #else // __ARM_ARCH_xxx
662 #error "Unknown ARM architecture for CRC optimization"
663 #endif // __ARM_ARCH_xxx
664 #else // __arm__ || defined __ICC_ARM__ || defined __ARM_ARCH
665  /* Seem to be compiling for non-ARM, or an unsupported toolchain, so stick with C implementations */
666 #define MBED_CRC_ARM_THUMB2 0
667 #define MBED_CRC_THUMB1 0
668 #endif
669 
670  // *INDENT-OFF*
671  /** Process 1 bit of non-reflected CRC
672  *
673  * Shift the p_crc register left 1 bit - if a one is shifted
674  * out, exclusive-or with the polynomial mask.
675  *
676  * Assembler optimizations can be applied here, to make
677  * use of the CPU's carry output from shifts.
678  *
679  * @param p_crc input register value
680  * @return updated register value
681  */
682  static uint_fast32_t do_1_bit_normal(uint_fast32_t p_crc)
683  {
684 #if MBED_CRC_ARM_THUMB2
685  __asm(".syntax unified\n\t"
686  "LSLS" "\t%[p_crc], %[p_crc], #1\n\t"
687  "IT" "\tCS\n\t"
688  "EORCS" "\t%[p_crc], %[poly]"
689  : [p_crc] "+&r" (p_crc)
690  : [poly] "rI" (get_top_polynomial())
691  : "cc");
692 #elif MBED_CRC_THUMB1
693  __asm(".syntax unified\n\t"
694  "LSLS" "\t%[p_crc], %[p_crc], #1\n\t"
695  "BCC" "\t%=f\n\t"
696  "EORS" "\t%[p_crc], %[poly]\n"
697  "%=:"
698  : [p_crc] "+&l" (p_crc)
699  : [poly] "l" (get_top_polynomial())
700  : "cc");
701 #else
702  if (p_crc & 0x80000000) {
703  p_crc = (p_crc << 1) ^ get_top_polynomial();
704  } else {
705  p_crc = (p_crc << 1);
706  }
707 #endif
708  return p_crc;
709  }
710 
711  /** Process 1 bit of reflected CRC
712  *
713  * Shift the p_crc register right 1 bit - if a one is shifted
714  * out, exclusive-or with the polynomial mask.
715  *
716  * Assembler optimizations can be applied here, to make
717  * use of the CPU's carry output from shifts.
718  *
719  * @param p_crc input register value
720  * @return updated register value
721  */
722  static uint_fast32_t do_1_bit_reflected(uint_fast32_t p_crc)
723  {
724 #if MBED_CRC_ARM_THUMB2
725  __asm(".syntax unified\n\t"
726  "LSRS" "\t%[p_crc], %[p_crc], #1\n\t"
727  "IT" "\tCS\n\t"
728  "EORCS" "\t%[p_crc], %[poly]"
729  : [p_crc] "+&r" (p_crc)
730  : [poly] "rI" (get_reflected_polynomial())
731  : "cc");
732 #elif MBED_CRC_THUMB1
733  __asm(".syntax unified\n\t"
734  "LSRS" "\t%[p_crc], %[p_crc], #1\n\t"
735  "BCC" "\t%=f\n\t"
736  "EORS" "\t%[p_crc], %[poly]\n"
737  "%=:"
738  : [p_crc] "+&l" (p_crc)
739  : [poly] "l" (get_reflected_polynomial())
740  : "cc");
741 #else
742  if (p_crc & 1) {
743  p_crc = (p_crc >> 1) ^ get_reflected_polynomial();
744  } else {
745  p_crc = (p_crc >> 1);
746  }
747 #endif
748  return p_crc;
749  }
750  // *INDENT-ON*
751 
752  /** Bitwise CRC computation.
753  *
754  * @param buffer data buffer
755  * @param size size of the data
756  * @param crc CRC value is filled in, but the value is not the final
757  * @return 0 on success or a negative error code on failure
758  */
759  template<CrcMode mode_ = mode>
760  std::enable_if_t<mode_ == CrcMode::BITWISE, int32_t>
761  do_compute_partial(const uint8_t *data, crc_data_size_t size, uint32_t *crc) const
762  {
763  uint_fast32_t p_crc = *crc;
764 
765  if (_reflect_data) {
766  /* Everything is reflected to match data - MSB of polynomial at bottom of 32-bit register */
767  for (crc_data_size_t byte = 0; byte < size; byte++) {
768  p_crc ^= data[byte];
769 
770  // Perform modulo-2 division, a bit at a time
771  for (unsigned int bit = 8; bit > 0; --bit) {
772  p_crc = do_1_bit_reflected(p_crc);
773  }
774  }
775  } else {
776  /* Polynomial is shifted to put MSB of polynomial at top of 32-bit register */
777  for (crc_data_size_t byte = 0; byte < size; byte++) {
778  p_crc ^= (uint_fast32_t) data[byte] << 24;
779 
780  // Perform modulo-2 division, a bit at a time
781  for (unsigned int bit = 8; bit > 0; --bit) {
782  p_crc = do_1_bit_normal(p_crc);
783  }
784  }
785  }
786 
787  *crc = p_crc;
788 
789  return 0;
790  }
791 
792 #if MBED_CRC_TABLE_SIZE > 0
793  /** CRC computation using ROM tables.
794  *
795  * @param buffer data buffer
796  * @param size size of the data
797  * @param crc CRC value is filled in, but the value is not the final
798  * @return 0 on success or a negative error code on failure
799  */
800  template<CrcMode mode_ = mode>
801  std::enable_if_t<mode_ == CrcMode::TABLE, int32_t>
802  do_compute_partial(const uint8_t *data, crc_data_size_t size, uint32_t *crc) const
803  {
804  uint_fast32_t p_crc = *crc;
805  // GCC has been observed to not hoist the load of _reflect_data out of the loop
806  // Note the inversion because table and CRC are reflected - data must be
807  bool reflect = !_reflect_data;
808 
809  for (crc_data_size_t byte = 0; byte < size; byte++) {
810  uint_fast32_t data_byte = data[byte];
811  if (reflect) {
812  data_byte = reflect_byte(data_byte);
813  }
814 #if MBED_CRC_TABLE_SIZE == 16
815  p_crc = _crc_table[(data_byte ^ p_crc) & 0xF] ^ (p_crc >> 4);
816  data_byte >>= 4;
817  p_crc = _crc_table[(data_byte ^ p_crc) & 0xF] ^ (p_crc >> 4);
818 #else
819  p_crc = _crc_table[(data_byte ^ p_crc) & 0xFF] ^ (p_crc >> 8);
820 #endif
821  }
822  *crc = p_crc;
823  return 0;
824  }
825 #endif
826 
827 #ifdef DEVICE_CRC
828  /** Hardware CRC computation.
829  *
830  * @param buffer data buffer
831  * @param size size of the data
832  * @return 0 on success or a negative error code on failure
833  */
834  template<CrcMode mode_ = mode>
835  std::enable_if_t<mode_ == CrcMode::HARDWARE, int32_t>
836  do_compute_partial(const uint8_t *data, crc_data_size_t size, uint32_t *) const
837  {
838  hal_crc_compute_partial(data, size);
839  return 0;
840  }
841 #endif
842 
843 };
844 
845 #if MBED_CRC_TABLE_SIZE > 0
846 /* Declarations of the tables we provide. (Not strictly needed, but compilers
847  * can warn if they see us using the template without a generic definition, so
848  * let it know we have provided these specialisations.)
849  */
850 template<>
851 const uint8_t MbedCRC<POLY_7BIT_SD, 7, CrcMode::TABLE>::_crc_table[MBED_CRC_TABLE_SIZE];
852 
853 template<>
854 const uint8_t MbedCRC<POLY_8BIT_CCITT, 8, CrcMode::TABLE>::_crc_table[MBED_CRC_TABLE_SIZE];
855 
856 template<>
857 const uint16_t MbedCRC<POLY_16BIT_CCITT, 16, CrcMode::TABLE>::_crc_table[MBED_CRC_TABLE_SIZE];
858 
859 template<>
860 const uint16_t MbedCRC<POLY_16BIT_IBM, 16, CrcMode::TABLE>::_crc_table[MBED_CRC_TABLE_SIZE];
861 
862 template<>
863 const uint32_t MbedCRC<POLY_32BIT_ANSI, 32, CrcMode::TABLE>::_crc_table[MBED_CRC_TABLE_SIZE];
864 
865 #endif // MBED_CRC_TABLE_SIZE > 0
866 
867 } // namespace impl
868 
869 #endif // !defined(DOXYGEN_ONLY)
870 
871 /** @}*/
872 /** @}*/
873 
874 } // namespace mbed
875 
876 #endif // __cplusplus
877 
878 /* Internal helper for mbed_error.c crash recovery */
879 #ifdef __cplusplus
880 extern "C"
881 #endif
882 uint32_t mbed_tiny_compute_crc32(const void *data, int datalen);
883 
884 #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.