Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
MbedCRC.h
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2018 ARM Limited 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 #ifndef MBED_CRC_API_H 00018 #define MBED_CRC_API_H 00019 00020 #include "cmsis.h" 00021 #include "hal/crc_api.h" 00022 #ifdef DEVICE_CRC 00023 #include "device.h" 00024 #endif 00025 #include "platform/mbed_assert.h" 00026 00027 #ifdef __cplusplus 00028 00029 #include "platform/SingletonPtr.h" 00030 #include "platform/PlatformMutex.h" 00031 00032 #include <type_traits> 00033 00034 namespace mbed { 00035 /** \addtogroup drivers-public-api */ 00036 /** @{*/ 00037 /** 00038 * \defgroup drivers_MbedCRC MbedCRC class 00039 * @{ 00040 */ 00041 00042 extern SingletonPtr<PlatformMutex> mbed_crc_mutex; 00043 00044 /** CRC mode selection 00045 */ 00046 enum class CrcMode { 00047 HARDWARE, /// Use hardware (if available), else table-based computation 00048 TABLE, /// Use table-based computation (if table available), else bitwise 00049 BITWISE /// Always use bitwise manual computation 00050 }; 00051 00052 #ifndef DOXYGEN_ONLY 00053 namespace impl { 00054 template<uint32_t polynomial, uint8_t width, CrcMode mode> 00055 class MbedCRC; 00056 00057 constexpr bool have_crc_table(uint32_t polynomial, uint8_t width) 00058 { 00059 #if MBED_CRC_TABLE_SIZE > 0 00060 return (polynomial == POLY_32BIT_ANSI && width == 32) || 00061 (polynomial == POLY_16BIT_IBM && width == 16) || 00062 (polynomial == POLY_16BIT_CCITT && width == 16) || 00063 (polynomial == POLY_8BIT_CCITT && width == 8) || 00064 (polynomial == POLY_7BIT_SD && width == 7); 00065 #else 00066 return false; 00067 #endif 00068 } 00069 00070 constexpr CrcMode choose_crc_mode(uint32_t polynomial, uint8_t width, CrcMode mode_limit) 00071 { 00072 return 00073 #if DEVICE_CRC 00074 mode_limit == CrcMode::HARDWARE && HAL_CRC_IS_SUPPORTED(polynomial, width) ? CrcMode::HARDWARE : 00075 #endif 00076 mode_limit <= CrcMode::TABLE && have_crc_table(polynomial, width) ? CrcMode::TABLE : 00077 CrcMode::BITWISE; 00078 } 00079 #endif // DOXYGEN_ONLY 00080 00081 } // namespace impl 00082 00083 /** CRC object provides CRC generation through hardware or software 00084 * 00085 * CRC sums can be generated using three different methods: hardware, software ROM tables 00086 * and bitwise computation. The mode used is normally selected automatically based on required 00087 * polynomial and hardware capabilities. Any polynomial in standard form (`x^3 + x + 1`) 00088 * can be used for computation, but custom ones can affect the performance. 00089 * 00090 * First choice is the hardware mode. The supported polynomials are hardware specific, and 00091 * you need to consult your MCU manual to discover them. Next, ROM polynomial tables 00092 * are tried (you can find list of supported polynomials here ::crc_polynomial). If the selected 00093 * configuration is supported, it will accelerate the software computations. If ROM tables 00094 * are not available for the selected polynomial, then CRC is computed at run time bit by bit 00095 * for all data input. 00096 * 00097 * If desired, the mode can be manually limited for a given instance by specifying the mode_limit 00098 * template parameter. This might be appropriate to ensure a table is not pulled in for a 00099 * non-speed-critical CRC, or to avoid the hardware set-up overhead if you know you will be 00100 * calling `compute` with very small data sizes. 00101 * 00102 * @note Synchronization level: Thread safe 00103 * 00104 * @tparam polynomial CRC polynomial value in hex 00105 * @tparam width CRC polynomial width 00106 * @tparam mode_limit Maximum amount of acceleration to use 00107 * 00108 * Example: Compute CRC data 00109 * @code 00110 * 00111 * #include "mbed.h" 00112 * 00113 * int main() { 00114 * MbedCRC<POLY_32BIT_ANSI, 32> ct; 00115 * 00116 * char test[] = "123456789"; 00117 * uint32_t crc = 0; 00118 * 00119 * printf("\nPolynomial = 0x%lx Width = %d \n", ct.get_polynomial(), ct.get_width()); 00120 * 00121 * ct.compute((void *)test, strlen((const char*)test), &crc); 00122 * 00123 * printf("The CRC of data \"123456789\" is : 0x%lx\n", crc); 00124 * return 0; 00125 * } 00126 * @endcode 00127 * Example: Compute CRC with data available in parts 00128 * @code 00129 * 00130 * #include "mbed.h" 00131 * int main() { 00132 * MbedCRC<POLY_32BIT_ANSI, 32> ct; 00133 * 00134 * char test[] = "123456789"; 00135 * uint32_t crc = 0; 00136 * 00137 * printf("\nPolynomial = 0x%lx Width = %d \n", ct.get_polynomial(), ct.get_width()); 00138 * ct.compute_partial_start(&crc); 00139 * ct.compute_partial((void *)&test, 4, &crc); 00140 * ct.compute_partial((void *)&test[4], 5, &crc); 00141 * ct.compute_partial_stop(&crc); 00142 * printf("The CRC of data \"123456789\" is : 0x%lx\n", crc); 00143 * return 0; 00144 * } 00145 * @endcode 00146 */ 00147 template <uint32_t polynomial = POLY_32BIT_ANSI, uint8_t width = 32, CrcMode mode_limit = CrcMode::HARDWARE> 00148 class MbedCRC { 00149 impl::MbedCRC<polynomial, width, impl::choose_crc_mode(polynomial, width, mode_limit)> crc_impl; 00150 00151 public: 00152 /* Backwards compatibility */ 00153 enum CrcMode { 00154 #if DEVICE_CRC 00155 HARDWARE = int(::mbed::CrcMode::HARDWARE), 00156 #endif 00157 TABLE = int(::mbed::CrcMode::TABLE), 00158 BITWISE = int(::mbed::CrcMode::BITWISE) 00159 }; 00160 00161 typedef size_t crc_data_size_t; 00162 00163 /** Lifetime of CRC object 00164 * 00165 * @param initial_xor Initial value/seed to Xor 00166 * @param final_xor Final Xor value 00167 * @param reflect_data 00168 * @param reflect_remainder 00169 * @note Default constructor without any arguments is valid only for supported CRC polynomials. :: crc_polynomial_t 00170 * MbedCRC <POLY_7BIT_SD, 7> ct; --- Valid POLY_7BIT_SD 00171 * MbedCRC <0x1021, 16> ct; --- Valid POLY_16BIT_CCITT 00172 * MbedCRC <POLY_16BIT_CCITT, 32> ct; --- Invalid, compilation error 00173 * MbedCRC <POLY_16BIT_CCITT, 32> ct (i,f,rd,rr) Constructor can be used for not supported polynomials 00174 * MbedCRC<POLY_16BIT_CCITT, 16> sd(0, 0, false, false); Constructor can also be used for supported 00175 * polynomials with different initial/final/reflect values 00176 * 00177 */ 00178 MbedCRC(uint32_t initial_xor, uint32_t final_xor, bool reflect_data, bool reflect_remainder) : 00179 crc_impl(initial_xor, final_xor, reflect_data, reflect_remainder) 00180 { 00181 } 00182 00183 MbedCRC(); 00184 00185 /** Compute CRC for the data input 00186 * Compute CRC performs the initialization, computation and collection of 00187 * final CRC. 00188 * 00189 * @param buffer Data bytes 00190 * @param size Size of data 00191 * @param crc CRC is the output value 00192 * @return 0 on success, negative error code on failure 00193 */ 00194 int32_t compute(const void *buffer, crc_data_size_t size, uint32_t *crc) 00195 { 00196 return crc_impl.compute(buffer, size, crc); 00197 } 00198 00199 /** Compute partial CRC for the data input. 00200 * 00201 * CRC data if not available fully, CRC can be computed in parts with available data. 00202 * 00203 * In case of hardware, intermediate values and states are saved by hardware. Mutex 00204 * locking is used to serialize access to hardware CRC. 00205 * 00206 * In case of software CRC, previous CRC output should be passed as argument to the 00207 * current compute_partial call. Please note the intermediate CRC value is maintained by 00208 * application and not the driver. 00209 * 00210 * @pre: Call `compute_partial_start` to start the partial CRC calculation. 00211 * @post: Call `compute_partial_stop` to get the final CRC value. 00212 * 00213 * @param buffer Data bytes 00214 * @param size Size of data 00215 * @param crc CRC value is intermediate CRC value filled by API. 00216 * @return 0 on success or a negative error code on failure 00217 * @note: CRC as output in compute_partial is not final CRC value, call `compute_partial_stop` 00218 * to get final correct CRC value. 00219 */ 00220 int32_t compute_partial(const void *buffer, crc_data_size_t size, uint32_t *crc) 00221 { 00222 return crc_impl.compute_partial(buffer, size, crc); 00223 } 00224 00225 /** Compute partial start, indicate start of partial computation. 00226 * 00227 * This API should be called before performing any partial computation 00228 * with compute_partial API. 00229 * 00230 * @param crc Initial CRC value set by the API 00231 * @return 0 on success or a negative in case of failure 00232 * @note: CRC is an out parameter and must be reused with compute_partial 00233 * and `compute_partial_stop` without any modifications in application. 00234 */ 00235 int32_t compute_partial_start(uint32_t *crc) 00236 { 00237 return crc_impl.compute_partial_start(crc); 00238 } 00239 00240 /** Get the final CRC value of partial computation. 00241 * 00242 * CRC value available in partial computation is not correct CRC, as some 00243 * algorithms require remainder to be reflected and final value to be XORed 00244 * This API is used to perform final computation to get correct CRC value. 00245 * 00246 * @param crc CRC result 00247 * @return 0 on success or a negative in case of failure. 00248 */ 00249 int32_t compute_partial_stop(uint32_t *crc) 00250 { 00251 return crc_impl.compute_partial_stop(crc); 00252 } 00253 00254 /** Get the current CRC polynomial. 00255 * 00256 * @return Polynomial value 00257 */ 00258 static constexpr uint32_t get_polynomial() 00259 { 00260 return polynomial; 00261 } 00262 00263 /** Get the current CRC width 00264 * 00265 * @return CRC width 00266 */ 00267 static constexpr uint8_t get_width() 00268 { 00269 return width; 00270 } 00271 }; 00272 00273 #if !defined(DOXYGEN_ONLY) 00274 /* Internal implementation - basically same as public, but actual mode locked in */ 00275 namespace impl { 00276 00277 template <uint32_t polynomial, uint8_t width, CrcMode mode> 00278 class MbedCRC { 00279 public: 00280 typedef size_t crc_data_size_t; 00281 00282 MbedCRC(uint32_t initial_xor, uint32_t final_xor, bool reflect_data, bool reflect_remainder) : 00283 _initial_value(adjust_initial_value(initial_xor, reflect_data)), 00284 _final_xor(final_xor), 00285 _reflect_data(reflect_data), 00286 _reflect_remainder(reflect_remainder) 00287 { 00288 static_assert(width <= 32, "Max 32-bit CRC supported"); 00289 } 00290 00291 /** Compute CRC for the data input 00292 * Compute CRC performs the initialization, computation and collection of 00293 * final CRC. 00294 * 00295 * @param buffer Data bytes 00296 * @param size Size of data 00297 * @param crc CRC is the output value 00298 * @return 0 on success, negative error code on failure 00299 */ 00300 int32_t compute(const void *buffer, crc_data_size_t size, uint32_t *crc) 00301 { 00302 int32_t status; 00303 00304 status = compute_partial_start(crc); 00305 if (0 != status) { 00306 return status; 00307 } 00308 00309 status = compute_partial(buffer, size, crc); 00310 if (0 != status) { 00311 return status; 00312 } 00313 00314 status = compute_partial_stop(crc); 00315 return status; 00316 } 00317 00318 /** Compute partial CRC for the data input. 00319 * 00320 * CRC data if not available fully, CRC can be computed in parts with available data. 00321 * 00322 * In case of hardware, intermediate values and states are saved by hardware. Mutex 00323 * locking is used to serialize access to hardware CRC. 00324 * 00325 * In case of software CRC, previous CRC output should be passed as argument to the 00326 * current compute_partial call. Please note the intermediate CRC value is maintained by 00327 * application and not the driver. 00328 * 00329 * @pre: Call `compute_partial_start` to start the partial CRC calculation. 00330 * @post: Call `compute_partial_stop` to get the final CRC value. 00331 * 00332 * @param buffer Data bytes 00333 * @param size Size of data 00334 * @param crc CRC value is intermediate CRC value filled by API. 00335 * @return 0 on success or a negative error code on failure 00336 * @note: CRC as output in compute_partial is not final CRC value, call `compute_partial_stop` 00337 * to get final correct CRC value. 00338 */ 00339 int32_t compute_partial(const void *buffer, crc_data_size_t size, uint32_t *crc) 00340 { 00341 const uint8_t *data = static_cast<const uint8_t *>(buffer); 00342 return do_compute_partial(data, size, crc); 00343 } 00344 00345 /** Compute partial start, indicate start of partial computation. 00346 * 00347 * This API should be called before performing any partial computation 00348 * with compute_partial API. 00349 * 00350 * @param crc Initial CRC value set by the API 00351 * @return 0 on success or a negative in case of failure 00352 * @note: CRC is an out parameter and must be reused with compute_partial 00353 * and `compute_partial_stop` without any modifications in application. 00354 */ 00355 int32_t compute_partial_start(uint32_t *crc) 00356 { 00357 #if DEVICE_CRC 00358 if (mode == CrcMode::HARDWARE) { 00359 lock(); 00360 crc_mbed_config_t config; 00361 config.polynomial = polynomial; 00362 config.width = width; 00363 config.initial_xor = _initial_value; 00364 config.final_xor = _final_xor; 00365 config.reflect_in = _reflect_data; 00366 config.reflect_out = _reflect_remainder; 00367 00368 hal_crc_compute_partial_start(&config); 00369 } 00370 #endif 00371 00372 *crc = _initial_value; 00373 return 0; 00374 } 00375 00376 /** Get the final CRC value of partial computation. 00377 * 00378 * CRC value available in partial computation is not correct CRC, as some 00379 * algorithms require remainder to be reflected and final value to be XORed 00380 * This API is used to perform final computation to get correct CRC value. 00381 * 00382 * @param crc CRC result 00383 * @return 0 on success or a negative in case of failure. 00384 */ 00385 int32_t compute_partial_stop(uint32_t *crc) 00386 { 00387 #if DEVICE_CRC 00388 if (mode == CrcMode::HARDWARE) { 00389 *crc = hal_crc_get_result(); 00390 unlock(); 00391 return 0; 00392 } 00393 #endif 00394 uint_fast32_t p_crc = *crc; 00395 if (mode == CrcMode::BITWISE) { 00396 if (_reflect_data) { 00397 /* CRC has MSB in bottom bit of register */ 00398 if (!_reflect_remainder) { 00399 p_crc = reflect_crc(p_crc); 00400 } 00401 } else { 00402 /* CRC has MSB in top bit of register */ 00403 p_crc = _reflect_remainder ? reflect_register(p_crc) : shift_right(p_crc); 00404 } 00405 } else { // TABLE 00406 /* CRC has MSB in bottom bit of register */ 00407 if (!_reflect_remainder) { 00408 p_crc = reflect_crc(p_crc); 00409 } 00410 } 00411 00412 p_crc ^= _final_xor; 00413 p_crc &= get_crc_mask(); 00414 *crc = p_crc; 00415 00416 return 0; 00417 } 00418 00419 private: 00420 /** Get the current CRC polynomial, reflected at bottom of register. 00421 * 00422 * @return Reflected polynomial value (so x^width term would be at bit -1) 00423 */ 00424 static constexpr uint32_t get_reflected_polynomial() 00425 { 00426 /* Doing this hard way to keep it C++11 constexpr and hence ARM C 5 compatible */ 00427 return shift_right(((polynomial & 0x00000001) << 31) | 00428 ((polynomial & 0x00000002) << 29) | 00429 ((polynomial & 0x00000004) << 27) | 00430 ((polynomial & 0x00000008) << 25) | 00431 ((polynomial & 0x00000010) << 23) | 00432 ((polynomial & 0x00000020) << 21) | 00433 ((polynomial & 0x00000040) << 19) | 00434 ((polynomial & 0x00000080) << 17) | 00435 ((polynomial & 0x00000100) << 15) | 00436 ((polynomial & 0x00000200) << 13) | 00437 ((polynomial & 0x00000400) << 11) | 00438 ((polynomial & 0x00000800) << 9) | 00439 ((polynomial & 0x00001000) << 7) | 00440 ((polynomial & 0x00002000) << 5) | 00441 ((polynomial & 0x00004000) << 3) | 00442 ((polynomial & 0x00008000) << 1) | 00443 ((polynomial & 0x00010000) >> 1) | 00444 ((polynomial & 0x00020000) >> 3) | 00445 ((polynomial & 0x00040000) >> 5) | 00446 ((polynomial & 0x00080000) >> 7) | 00447 ((polynomial & 0x00100000) >> 9) | 00448 ((polynomial & 0x00200000) >> 11) | 00449 ((polynomial & 0x00400000) >> 13) | 00450 ((polynomial & 0x00800000) >> 15) | 00451 ((polynomial & 0x01000000) >> 17) | 00452 ((polynomial & 0x02000000) >> 19) | 00453 ((polynomial & 0x04000000) >> 21) | 00454 ((polynomial & 0x08000000) >> 23) | 00455 ((polynomial & 0x10000000) >> 25) | 00456 ((polynomial & 0x20000000) >> 27) | 00457 ((polynomial & 0x40000000) >> 29) | 00458 ((polynomial & 0x80000000) >> 31)); 00459 } 00460 00461 /** Get the current CRC polynomial, at top of register. 00462 * 00463 * @return Shifted polynomial value (so x^width term would be at bit 32) 00464 */ 00465 static constexpr uint32_t get_top_polynomial() 00466 { 00467 return shift_left(polynomial); 00468 } 00469 00470 const uint32_t _initial_value; 00471 const uint32_t _final_xor; 00472 const bool _reflect_data; 00473 const bool _reflect_remainder; 00474 00475 // *INDENT-OFF* 00476 using crc_table_t = std::conditional_t<width <= 8, uint8_t, 00477 std::conditional_t<width <= 16, uint16_t, 00478 uint32_t 00479 >>; 00480 // *INDENT-ON* 00481 00482 /* Not [MBED_CRC_TABLE_SIZE] as that could be [0], which is illegal. 00483 * We do need the declaration to always exist so that do_compute_partial<TABLE> is always well-formed, 00484 * but we never actually use it MBED_CRC_TABLE_SIZE is 0. 00485 */ 00486 static const crc_table_t _crc_table[]; 00487 00488 static uint32_t adjust_initial_value(uint32_t initial_xor, bool reflect_data) 00489 { 00490 /* As initial_xor is almost certain to be constant all zeros or ones, try to 00491 * process that a constant, avoiding an RBIT instruction (or worse). 00492 */ 00493 if (initial_xor == 0 || initial_xor == (get_crc_mask() & -1U)) { 00494 /* Only possible adjustment is shifting to top for bitwise */ 00495 if (mode == CrcMode::BITWISE && !reflect_data) { 00496 return shift_left(initial_xor); 00497 } else { 00498 return initial_xor; 00499 } 00500 } 00501 00502 /* Weird or non-constant initial value - need to think about reflection */ 00503 if (mode == CrcMode::BITWISE) { 00504 /* For bitwise calculation, CRC register is reflected if data is, to match input. 00505 * (MSB at bottom of register). If not reflected, it is at the top of the register 00506 * (MSB at top of register). 00507 */ 00508 return reflect_data ? reflect_crc(initial_xor) : shift_left(initial_xor); 00509 } else if (mode == CrcMode::TABLE) { 00510 /* For table calculation, CRC value is reflected, to match tables. 00511 * (MSB at bottom of register). */ 00512 return reflect_crc(initial_xor); 00513 } else { // CrcMode::HARDWARE 00514 return initial_xor; 00515 } 00516 } 00517 00518 /** Acquire exclusive access to CRC hardware/software. 00519 */ 00520 static void lock() 00521 { 00522 #if DEVICE_CRC 00523 if (mode == CrcMode::HARDWARE) { 00524 mbed_crc_mutex->lock(); 00525 } 00526 #endif 00527 } 00528 00529 /** Release exclusive access to CRC hardware/software. 00530 */ 00531 static void unlock() 00532 { 00533 #if DEVICE_CRC 00534 if (mode == CrcMode::HARDWARE) { 00535 mbed_crc_mutex->unlock(); 00536 } 00537 #endif 00538 } 00539 00540 /** Get the CRC data mask. 00541 * 00542 * @return CRC data mask is generated based on current CRC width 00543 */ 00544 static constexpr uint32_t get_crc_mask() 00545 { 00546 return (uint32_t)((uint32_t)2U << (width - 1)) - 1U; 00547 } 00548 00549 /** Data bytes may need to be reflected. 00550 * 00551 * @param data value to be reflected (bottom 8 bits) 00552 * @return Reflected value (bottom 8 bits) 00553 */ 00554 static uint_fast32_t reflect_byte(uint_fast32_t data) 00555 { 00556 return __RBIT(data) >> 24; 00557 } 00558 00559 /** CRC values may need to be reflected. 00560 * 00561 * @param CRC value to be reflected (width bits at bottom of 32-bit word) 00562 * @return Reflected value (still at bottom of 32-bit word) 00563 */ 00564 static uint32_t reflect_crc(uint32_t data) 00565 { 00566 return __RBIT(data) >> (32 - width); 00567 } 00568 00569 /** Register values may need to be reflected. 00570 * 00571 * @param Register value to be reflected (full 32-bit value) 00572 * @return Reflected value (full 32-bit value) 00573 */ 00574 static uint32_t reflect_register(uint32_t data) 00575 { 00576 return __RBIT(data); 00577 } 00578 00579 /** Register values may need to be shifted left. 00580 * 00581 * @param Register value to be shifted up (in bottom width bits) 00582 * @return Shifted value (in top width bits) 00583 */ 00584 static constexpr uint32_t shift_left(uint32_t data) 00585 { 00586 return data << (32 - width); 00587 } 00588 00589 /** Register values may need to be shifted right. 00590 * 00591 * @param Register value to be shifted right (in top width bits) 00592 * @return Shifted value (in bottom width bits) 00593 */ 00594 static constexpr uint32_t shift_right(uint32_t data) 00595 { 00596 return data >> (32 - width); 00597 } 00598 00599 /* Check to see if we can do assembler optimizations */ 00600 #if ((defined __GNUC__ || defined __clang__) && !defined __CC_ARM) && \ 00601 (defined __arm__ || defined __ARM_ARCH) 00602 #if (__ARM_ARCH_7M__ == 1U) || \ 00603 (__ARM_ARCH_7EM__ == 1U) || \ 00604 (__ARM_ARCH_8M_MAIN__ == 1U) || \ 00605 (__ARM_ARCH_7A__ == 1U) 00606 /* ARM that has Thumb-2 - same unified assembly is good for either ARM or Thumb state (LSRS; IT CS; EORCS reg/imm) */ 00607 #define MBED_CRC_ARM_THUMB2 1 00608 #define MBED_CRC_THUMB1 0 00609 #elif (__ARM_ARCH_6M__ == 1U) || \ 00610 (__ARM_ARCH_8M_BASE__ == 1U) 00611 /* Thumb-1-only ARM-M device - use Thumb-1 compatible assembly with branch (LSRS; BCC; EORS reg) */ 00612 #define MBED_CRC_ARM_THUMB2 0 00613 #define MBED_CRC_THUMB1 1 00614 #else // __ARM_ARCH_xxx 00615 #error "Unknown ARM architecture for CRC optimization" 00616 #endif // __ARM_ARCH_xxx 00617 #else // __arm__ || defined __ICC_ARM__ || defined __ARM_ARCH 00618 /* Seem to be compiling for non-ARM, or an unsupported toolchain, so stick with C implementations */ 00619 #define MBED_CRC_ARM_THUMB2 0 00620 #define MBED_CRC_THUMB1 0 00621 #endif 00622 00623 // *INDENT-OFF* 00624 /** Process 1 bit of non-reflected CRC 00625 * 00626 * Shift the p_crc register left 1 bit - if a one is shifted 00627 * out, exclusive-or with the polynomial mask. 00628 * 00629 * Assembler optimizations can be applied here, to make 00630 * use of the CPU's carry output from shifts. 00631 * 00632 * @param p_crc input register value 00633 * @return updated register value 00634 */ 00635 static uint_fast32_t do_1_bit_normal(uint_fast32_t p_crc) 00636 { 00637 #if MBED_CRC_ARM_THUMB2 00638 __asm(".syntax unified\n\t" 00639 "LSLS" "\t%[p_crc], %[p_crc], #1\n\t" 00640 "IT" "\tCS\n\t" 00641 "EORCS" "\t%[p_crc], %[poly]" 00642 : [p_crc] "+&r" (p_crc) 00643 : [poly] "rI" (get_top_polynomial()) 00644 : "cc"); 00645 #elif MBED_CRC_THUMB1 00646 __asm(".syntax unified\n\t" 00647 "LSLS" "\t%[p_crc], %[p_crc], #1\n\t" 00648 "BCC" "\t%=f\n\t" 00649 "EORS" "\t%[p_crc], %[poly]\n" 00650 "%=:" 00651 : [p_crc] "+&l" (p_crc) 00652 : [poly] "l" (get_top_polynomial()) 00653 : "cc"); 00654 #else 00655 if (p_crc & 0x80000000) { 00656 p_crc = (p_crc << 1) ^ get_top_polynomial(); 00657 } else { 00658 p_crc = (p_crc << 1); 00659 } 00660 #endif 00661 return p_crc; 00662 } 00663 00664 /** Process 1 bit of reflected CRC 00665 * 00666 * Shift the p_crc register right 1 bit - if a one is shifted 00667 * out, exclusive-or with the polynomial mask. 00668 * 00669 * Assembler optimizations can be applied here, to make 00670 * use of the CPU's carry output from shifts. 00671 * 00672 * @param p_crc input register value 00673 * @return updated register value 00674 */ 00675 static uint_fast32_t do_1_bit_reflected(uint_fast32_t p_crc) 00676 { 00677 #if MBED_CRC_ARM_THUMB2 00678 __asm(".syntax unified\n\t" 00679 "LSRS" "\t%[p_crc], %[p_crc], #1\n\t" 00680 "IT" "\tCS\n\t" 00681 "EORCS" "\t%[p_crc], %[poly]" 00682 : [p_crc] "+&r" (p_crc) 00683 : [poly] "rI" (get_reflected_polynomial()) 00684 : "cc"); 00685 #elif MBED_CRC_THUMB1 00686 __asm(".syntax unified\n\t" 00687 "LSRS" "\t%[p_crc], %[p_crc], #1\n\t" 00688 "BCC" "\t%=f\n\t" 00689 "EORS" "\t%[p_crc], %[poly]\n" 00690 "%=:" 00691 : [p_crc] "+&l" (p_crc) 00692 : [poly] "l" (get_reflected_polynomial()) 00693 : "cc"); 00694 #else 00695 if (p_crc & 1) { 00696 p_crc = (p_crc >> 1) ^ get_reflected_polynomial(); 00697 } else { 00698 p_crc = (p_crc >> 1); 00699 } 00700 #endif 00701 return p_crc; 00702 } 00703 // *INDENT-ON* 00704 00705 /** Bitwise CRC computation. 00706 * 00707 * @param buffer data buffer 00708 * @param size size of the data 00709 * @param crc CRC value is filled in, but the value is not the final 00710 * @return 0 on success or a negative error code on failure 00711 */ 00712 template<CrcMode mode_ = mode> 00713 std::enable_if_t<mode_ == CrcMode::BITWISE, int32_t> 00714 do_compute_partial(const uint8_t *data, crc_data_size_t size, uint32_t *crc) const 00715 { 00716 uint_fast32_t p_crc = *crc; 00717 00718 if (_reflect_data) { 00719 /* Everything is reflected to match data - MSB of polynomial at bottom of 32-bit register */ 00720 for (crc_data_size_t byte = 0; byte < size; byte++) { 00721 p_crc ^= data[byte]; 00722 00723 // Perform modulo-2 division, a bit at a time 00724 for (unsigned int bit = 8; bit > 0; --bit) { 00725 p_crc = do_1_bit_reflected(p_crc); 00726 } 00727 } 00728 } else { 00729 /* Polynomial is shifted to put MSB of polynomial at top of 32-bit register */ 00730 for (crc_data_size_t byte = 0; byte < size; byte++) { 00731 p_crc ^= (uint_fast32_t) data[byte] << 24; 00732 00733 // Perform modulo-2 division, a bit at a time 00734 for (unsigned int bit = 8; bit > 0; --bit) { 00735 p_crc = do_1_bit_normal(p_crc); 00736 } 00737 } 00738 } 00739 00740 *crc = p_crc; 00741 00742 return 0; 00743 } 00744 00745 /** CRC computation using ROM tables. 00746 * 00747 * @param buffer data buffer 00748 * @param size size of the data 00749 * @param crc CRC value is filled in, but the value is not the final 00750 * @return 0 on success or a negative error code on failure 00751 */ 00752 template<CrcMode mode_ = mode> 00753 std::enable_if_t<mode_ == CrcMode::TABLE, int32_t> 00754 do_compute_partial(const uint8_t *data, crc_data_size_t size, uint32_t *crc) const 00755 { 00756 uint_fast32_t p_crc = *crc; 00757 // GCC has been observed to not hoist the load of _reflect_data out of the loop 00758 // Note the inversion because table and CRC are reflected - data must be 00759 bool reflect = !_reflect_data; 00760 00761 for (crc_data_size_t byte = 0; byte < size; byte++) { 00762 uint_fast32_t data_byte = data[byte]; 00763 if (reflect) { 00764 data_byte = reflect_byte(data_byte); 00765 } 00766 #if MBED_CRC_TABLE_SIZE == 16 00767 p_crc = _crc_table[(data_byte ^ p_crc) & 0xF] ^ (p_crc >> 4); 00768 data_byte >>= 4; 00769 p_crc = _crc_table[(data_byte ^ p_crc) & 0xF] ^ (p_crc >> 4); 00770 #else 00771 p_crc = _crc_table[(data_byte ^ p_crc) & 0xFF] ^ (p_crc >> 8); 00772 #endif 00773 } 00774 *crc = p_crc; 00775 return 0; 00776 } 00777 00778 #ifdef DEVICE_CRC 00779 /** Hardware CRC computation. 00780 * 00781 * @param buffer data buffer 00782 * @param size size of the data 00783 * @return 0 on success or a negative error code on failure 00784 */ 00785 template<CrcMode mode_ = mode> 00786 std::enable_if_t<mode_ == CrcMode::HARDWARE, int32_t> 00787 do_compute_partial(const uint8_t *data, crc_data_size_t size, uint32_t *) const 00788 { 00789 hal_crc_compute_partial(data, size); 00790 return 0; 00791 } 00792 #endif 00793 00794 }; 00795 00796 } // namespace impl 00797 00798 #endif // !defined(DOXYGEN_ONLY) 00799 00800 /* Default values for different types of polynomials 00801 */ 00802 template<> 00803 inline MbedCRC<POLY_32BIT_ANSI, 32>::MbedCRC() : MbedCRC(0xFFFFFFFF, 0xFFFFFFFF, true, true) 00804 { 00805 } 00806 00807 template<> 00808 inline MbedCRC<POLY_16BIT_IBM, 16>::MbedCRC() : MbedCRC(0, 0, true, true) 00809 { 00810 } 00811 00812 template<> 00813 inline MbedCRC<POLY_16BIT_CCITT, 16>::MbedCRC() : MbedCRC(0xFFFF, 0, false, false) 00814 { 00815 } 00816 00817 template<> 00818 inline MbedCRC<POLY_7BIT_SD, 7>::MbedCRC(): MbedCRC(0, 0, false, false) 00819 { 00820 } 00821 00822 template<> 00823 inline MbedCRC<POLY_8BIT_CCITT, 8>::MbedCRC(): MbedCRC(0, 0, false, false) 00824 { 00825 } 00826 00827 /** @}*/ 00828 /** @}*/ 00829 00830 } // namespace mbed 00831 00832 #endif // __cplusplus 00833 00834 /* Internal helper for mbed_error.c crash recovery */ 00835 #ifdef __cplusplus 00836 extern "C" 00837 #endif 00838 uint32_t mbed_tiny_compute_crc32(const void *data, int datalen); 00839 00840 #endif
Generated on Tue Jul 12 2022 13:54:34 by
