29
29
#include " platform/SingletonPtr.h"
30
30
#include " platform/PlatformMutex.h"
31
31
32
+ #ifdef UNITTEST
32
33
#include < type_traits>
34
+ #define MSTD_CONSTEXPR_IF_HAS_IS_CONSTANT_EVALUATED
35
+ #else
36
+ #include < mstd_type_traits>
37
+ #endif
33
38
34
39
namespace mbed {
35
40
/* * \addtogroup drivers-public-api */
@@ -175,11 +180,13 @@ class MbedCRC {
175
180
* polynomials with different initial/final/reflect values
176
181
*
177
182
*/
183
+ constexpr
178
184
MbedCRC (uint32_t initial_xor, uint32_t final_xor, bool reflect_data, bool reflect_remainder) :
179
185
crc_impl (initial_xor, final_xor, reflect_data, reflect_remainder)
180
186
{
181
187
}
182
188
189
+ constexpr
183
190
MbedCRC ();
184
191
185
192
/* * Compute CRC for the data input
@@ -279,6 +286,7 @@ class MbedCRC {
279
286
public:
280
287
typedef size_t crc_data_size_t ;
281
288
289
+ constexpr
282
290
MbedCRC (uint32_t initial_xor, uint32_t final_xor, bool reflect_data, bool reflect_remainder) :
283
291
_initial_value (adjust_initial_value(initial_xor, reflect_data)),
284
292
_final_xor (final_xor),
@@ -400,7 +408,7 @@ class MbedCRC {
400
408
}
401
409
} else {
402
410
/* CRC has MSB in top bit of register */
403
- p_crc = _reflect_remainder ? reflect_register (p_crc) : shift_right (p_crc);
411
+ p_crc = _reflect_remainder ? reflect (p_crc) : shift_right (p_crc);
404
412
}
405
413
} else { // TABLE
406
414
/* CRC has MSB in bottom bit of register */
@@ -417,45 +425,91 @@ class MbedCRC {
417
425
}
418
426
419
427
private:
428
+ /* * Guaranteed constexpr reflection (all toolchains)
429
+ *
430
+ * @note This should never be run-time evaluated - very inefficient
431
+ * @param Register value to be reflected (full 32-bit value)
432
+ * @return Reflected value (full 32-bit value)
433
+ */
434
+ static constexpr uint32_t reflect_constant (uint32_t data)
435
+ {
436
+ /* Doing this hard way to keep it C++11 constexpr and hence ARM C 5 compatible */
437
+ return ((data & 0x00000001 ) << 31 ) |
438
+ ((data & 0x00000002 ) << 29 ) |
439
+ ((data & 0x00000004 ) << 27 ) |
440
+ ((data & 0x00000008 ) << 25 ) |
441
+ ((data & 0x00000010 ) << 23 ) |
442
+ ((data & 0x00000020 ) << 21 ) |
443
+ ((data & 0x00000040 ) << 19 ) |
444
+ ((data & 0x00000080 ) << 17 ) |
445
+ ((data & 0x00000100 ) << 15 ) |
446
+ ((data & 0x00000200 ) << 13 ) |
447
+ ((data & 0x00000400 ) << 11 ) |
448
+ ((data & 0x00000800 ) << 9 ) |
449
+ ((data & 0x00001000 ) << 7 ) |
450
+ ((data & 0x00002000 ) << 5 ) |
451
+ ((data & 0x00004000 ) << 3 ) |
452
+ ((data & 0x00008000 ) << 1 ) |
453
+ ((data & 0x00010000 ) >> 1 ) |
454
+ ((data & 0x00020000 ) >> 3 ) |
455
+ ((data & 0x00040000 ) >> 5 ) |
456
+ ((data & 0x00080000 ) >> 7 ) |
457
+ ((data & 0x00100000 ) >> 9 ) |
458
+ ((data & 0x00200000 ) >> 11 ) |
459
+ ((data & 0x00400000 ) >> 13 ) |
460
+ ((data & 0x00800000 ) >> 15 ) |
461
+ ((data & 0x01000000 ) >> 17 ) |
462
+ ((data & 0x02000000 ) >> 19 ) |
463
+ ((data & 0x04000000 ) >> 21 ) |
464
+ ((data & 0x08000000 ) >> 23 ) |
465
+ ((data & 0x10000000 ) >> 25 ) |
466
+ ((data & 0x20000000 ) >> 27 ) |
467
+ ((data & 0x40000000 ) >> 29 ) |
468
+ ((data & 0x80000000 ) >> 31 );
469
+ }
470
+
471
+ /* * General reflection
472
+ *
473
+ * @note This is used when we may need to perform run-time computation, so
474
+ * we need the possibility to produce the optimal run-time RBIT instruction. But
475
+ * if the compiler doesn't treat RBIT as a built-in, it's useful to have a C fallback
476
+ * for the constant case, avoiding runtime RBIT(0) computations. This is an
477
+ * optimization only available for some toolchains; others will always use runtime
478
+ * RBIT. If we require a constant expression, use reflect_constant instead.
479
+ *
480
+ * @param Register value to be reflected (full 32-bit value)
481
+ * @return Reflected value (full 32-bit value)
482
+ */
483
+ #ifdef MSTD_HAS_IS_CONSTANT_EVALUATED
484
+ static constexpr uint32_t reflect (uint32_t data)
485
+ {
486
+ return mstd::is_constant_evaluated () ? reflect_constant (data) : __RBIT (data);
487
+ }
488
+ #else
489
+ static uint32_t reflect (uint32_t data)
490
+ {
491
+ return __RBIT (data);
492
+ }
493
+ #endif
494
+
495
+ /* * Data bytes may need to be reflected.
496
+ *
497
+ * @param data value to be reflected (bottom 8 bits)
498
+ * @return Reflected value (bottom 8 bits)
499
+ */
500
+ static MSTD_CONSTEXPR_IF_HAS_IS_CONSTANT_EVALUATED
501
+ uint_fast32_t reflect_byte (uint_fast32_t data)
502
+ {
503
+ return reflect (data) >> 24 ;
504
+ }
505
+
420
506
/* * Get the current CRC polynomial, reflected at bottom of register.
421
507
*
422
508
* @return Reflected polynomial value (so x^width term would be at bit -1)
423
509
*/
424
510
static constexpr uint32_t get_reflected_polynomial ()
425
511
{
426
- /* Doing this hard way to keep it C++11 constexpr and hence ARM C 5 compatible */
427
- return shift_right (((polynomial & 0x00000001 ) << 31 ) |
428
- ((polynomial & 0x00000002 ) << 29 ) |
429
- ((polynomial & 0x00000004 ) << 27 ) |
430
- ((polynomial & 0x00000008 ) << 25 ) |
431
- ((polynomial & 0x00000010 ) << 23 ) |
432
- ((polynomial & 0x00000020 ) << 21 ) |
433
- ((polynomial & 0x00000040 ) << 19 ) |
434
- ((polynomial & 0x00000080 ) << 17 ) |
435
- ((polynomial & 0x00000100 ) << 15 ) |
436
- ((polynomial & 0x00000200 ) << 13 ) |
437
- ((polynomial & 0x00000400 ) << 11 ) |
438
- ((polynomial & 0x00000800 ) << 9 ) |
439
- ((polynomial & 0x00001000 ) << 7 ) |
440
- ((polynomial & 0x00002000 ) << 5 ) |
441
- ((polynomial & 0x00004000 ) << 3 ) |
442
- ((polynomial & 0x00008000 ) << 1 ) |
443
- ((polynomial & 0x00010000 ) >> 1 ) |
444
- ((polynomial & 0x00020000 ) >> 3 ) |
445
- ((polynomial & 0x00040000 ) >> 5 ) |
446
- ((polynomial & 0x00080000 ) >> 7 ) |
447
- ((polynomial & 0x00100000 ) >> 9 ) |
448
- ((polynomial & 0x00200000 ) >> 11 ) |
449
- ((polynomial & 0x00400000 ) >> 13 ) |
450
- ((polynomial & 0x00800000 ) >> 15 ) |
451
- ((polynomial & 0x01000000 ) >> 17 ) |
452
- ((polynomial & 0x02000000 ) >> 19 ) |
453
- ((polynomial & 0x04000000 ) >> 21 ) |
454
- ((polynomial & 0x08000000 ) >> 23 ) |
455
- ((polynomial & 0x10000000 ) >> 25 ) |
456
- ((polynomial & 0x20000000 ) >> 27 ) |
457
- ((polynomial & 0x40000000 ) >> 29 ) |
458
- ((polynomial & 0x80000000 ) >> 31 ));
512
+ return shift_right (reflect_constant (polynomial));
459
513
}
460
514
461
515
/* * Get the current CRC polynomial, at top of register.
@@ -484,21 +538,8 @@ class MbedCRC {
484
538
static const crc_table_t _crc_table[MBED_CRC_TABLE_SIZE];
485
539
#endif
486
540
487
- static uint32_t adjust_initial_value (uint32_t initial_xor, bool reflect_data)
541
+ static constexpr uint32_t adjust_initial_value (uint32_t initial_xor, bool reflect_data)
488
542
{
489
- /* As initial_xor is almost certain to be constant all zeros or ones, try to
490
- * process that a constant, avoiding an RBIT instruction (or worse).
491
- */
492
- if (initial_xor == 0 || initial_xor == (get_crc_mask () & -1U )) {
493
- /* Only possible adjustment is shifting to top for bitwise */
494
- if (mode == CrcMode::BITWISE && !reflect_data) {
495
- return shift_left (initial_xor);
496
- } else {
497
- return initial_xor;
498
- }
499
- }
500
-
501
- /* Weird or non-constant initial value - need to think about reflection */
502
543
if (mode == CrcMode::BITWISE) {
503
544
/* For bitwise calculation, CRC register is reflected if data is, to match input.
504
545
* (MSB at bottom of register). If not reflected, it is at the top of the register
@@ -545,34 +586,15 @@ class MbedCRC {
545
586
return (uint32_t )((uint32_t )2U << (width - 1 )) - 1U ;
546
587
}
547
588
548
- /* * Data bytes may need to be reflected.
549
- *
550
- * @param data value to be reflected (bottom 8 bits)
551
- * @return Reflected value (bottom 8 bits)
552
- */
553
- static uint_fast32_t reflect_byte (uint_fast32_t data)
554
- {
555
- return __RBIT (data) >> 24 ;
556
- }
557
-
558
589
/* * CRC values may need to be reflected.
559
590
*
560
591
* @param CRC value to be reflected (width bits at bottom of 32-bit word)
561
592
* @return Reflected value (still at bottom of 32-bit word)
562
593
*/
563
- static uint32_t reflect_crc (uint32_t data)
594
+ static MSTD_CONSTEXPR_IF_HAS_IS_CONSTANT_EVALUATED
595
+ uint32_t reflect_crc (uint32_t data)
564
596
{
565
- return __RBIT (data) >> (32 - width);
566
- }
567
-
568
- /* * Register values may need to be reflected.
569
- *
570
- * @param Register value to be reflected (full 32-bit value)
571
- * @return Reflected value (full 32-bit value)
572
- */
573
- static uint32_t reflect_register (uint32_t data)
574
- {
575
- return __RBIT (data);
597
+ return reflect (data) >> (32 - width);
576
598
}
577
599
578
600
/* * Register values may need to be shifted left.
@@ -823,27 +845,32 @@ const uint32_t MbedCRC<POLY_32BIT_ANSI, 32, CrcMode::TABLE>::_crc_table[MBED_CRC
823
845
/* Default values for different types of polynomials
824
846
*/
825
847
template <>
826
- inline MbedCRC<POLY_32BIT_ANSI, 32 >::MbedCRC() : MbedCRC(0xFFFFFFFF , 0xFFFFFFFF , true , true )
848
+ inline MSTD_CONSTEXPR_FN_14
849
+ MbedCRC<POLY_32BIT_ANSI, 32 >::MbedCRC() : MbedCRC(0xFFFFFFFF , 0xFFFFFFFF , true , true )
827
850
{
828
851
}
829
852
830
853
template <>
831
- inline MbedCRC<POLY_16BIT_IBM, 16 >::MbedCRC() : MbedCRC(0 , 0 , true , true )
854
+ inline MSTD_CONSTEXPR_FN_14
855
+ MbedCRC<POLY_16BIT_IBM, 16 >::MbedCRC() : MbedCRC(0 , 0 , true , true )
832
856
{
833
857
}
834
858
835
859
template <>
836
- inline MbedCRC<POLY_16BIT_CCITT, 16 >::MbedCRC() : MbedCRC(0xFFFF , 0 , false , false )
860
+ inline MSTD_CONSTEXPR_FN_14
861
+ MbedCRC<POLY_16BIT_CCITT, 16 >::MbedCRC() : MbedCRC(0xFFFF , 0 , false , false )
837
862
{
838
863
}
839
864
840
865
template <>
841
- inline MbedCRC<POLY_7BIT_SD, 7 >::MbedCRC(): MbedCRC(0 , 0 , false , false )
866
+ inline MSTD_CONSTEXPR_FN_14
867
+ MbedCRC<POLY_7BIT_SD, 7 >::MbedCRC(): MbedCRC(0 , 0 , false , false )
842
868
{
843
869
}
844
870
845
871
template <>
846
- inline MbedCRC<POLY_8BIT_CCITT, 8 >::MbedCRC(): MbedCRC(0 , 0 , false , false )
872
+ inline MSTD_CONSTEXPR_FN_14
873
+ MbedCRC<POLY_8BIT_CCITT, 8 >::MbedCRC(): MbedCRC(0 , 0 , false , false )
847
874
{
848
875
}
849
876
0 commit comments