Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MbedCRC.h Source File

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