1 /**
2 * \file
3 *
4 * \brief 32-bit CRC implementation.
5 *
6 * Copyright (C) 2014-2015 Atmel Corporation. All rights reserved.
7 *
8 * \asf_license_start
9 *
10 * \page License
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 *
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 *
22 * 3. The name of Atmel may not be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * 4. This software may only be redistributed and used in connection with an
26 * Atmel microcontroller product.
27 *
28 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 *
40 * \asf_license_stop
41 *
42 */
43 /*
44 * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45 */
46
47 #include "crc32.h"
48 #include <status_codes.h>
49
50
51 /**
52 * Convenience typedef for words.
53 *
54 * \note This type has an architecture dependent size, and is used to optimize
55 * the CRC algorithm with regards to the number of databus accesses.
56 */
57 typedef unsigned int word_t;
58
59 /** Polynomial for 32-bit CRC in IEEE 802.3. */
60 #define CRC32_POLYNOMIAL 0xEDB88320UL
61
62 /** Convenience macro for inverting the CRC. */
63 #define COMPLEMENT_CRC(c) ((c) ^ 0xffffffffUL)
64
65 /** Convenience macro for size of a word. */
66 #define WORD_SIZE (sizeof(word_t))
67
68 /** Bitmask for word-aligning an address. */
69 #define WORD_ALIGNMENT_MASK ~((uintptr_t)WORD_SIZE - 1)
70
71
72 /**
73 * \internal
74 * \brief Recalculate 32-bit CRC for bytes within a word
75 *
76 * \param[in] data Data to recalculate for.
77 * \param[in] crc Initial/current CRC value.
78 * \param[in] bytes Number of data bytes in word.
79 *
80 * \return New CRC value.
81 *
82 * \attention This implementation assumes a little-endian architecture.
83 */
_crc32_recalculate_bytes_helper(word_t data,crc32_t crc,uint_fast8_t bytes)84 static inline crc32_t _crc32_recalculate_bytes_helper(word_t data,
85 crc32_t crc, uint_fast8_t bytes)
86 {
87 uint_fast8_t bit;
88
89 crc ^= data;
90
91 for (bit = 8 * bytes; bit > 0; bit--) {
92 if (crc & 1) {
93 crc = (crc >> 1) ^ CRC32_POLYNOMIAL;
94 } else {
95 crc >>= 1;
96 }
97 }
98
99 return crc;
100 }
101
102 /**
103 * \brief Recalculate 32-bit CRC for another block
104 *
105 * This function recalculates the CRC according to the polynomial
106 * \ref CRC32_POLYNOMIAL for the specified data block and initial CRC value.
107 *
108 * To reduce the number of databus accesses and thus speed up the calculation,
109 * the algorithm is tuned to work with words as much as possible.
110 *
111 * \param[in] data Address of data.
112 * \param[in] length Length of data.
113 * \param[in,out] crc Address of variable containing current CRC, and to store
114 * recalculated CRC in.
115 *
116 * \return Status of calculation.
117 * \retval STATUS_OK if calculation succeeded.
118 * \retval <other> if calculation failed or could not be started.
119 *
120 * \note To calculate the CRC of multiple blocks, use \ref crc32_calculate()
121 * first, then this function for the following blocks.
122 *
123 * \attention This implementation assumes a little-endian architecture.
124 */
crc32_recalculate(const void * data,size_t length,crc32_t * crc)125 enum status_code crc32_recalculate(const void *data, size_t length, crc32_t *crc)
126 {
127 const word_t *word_ptr =
128 (word_t *)((uintptr_t)data & WORD_ALIGNMENT_MASK);
129 size_t temp_length;
130 crc32_t temp_crc = COMPLEMENT_CRC(*crc);
131 word_t word;
132
133 // Calculate for initial bytes to get word-aligned
134 if (length < WORD_SIZE) {
135 temp_length = length;
136 } else {
137 temp_length = ~WORD_ALIGNMENT_MASK & (WORD_SIZE - (uintptr_t)data);
138 }
139
140 if (temp_length) {
141 length -= temp_length;
142
143 word = *(word_ptr++);
144 word >>= 8 * (WORD_SIZE - temp_length);
145 temp_crc = _crc32_recalculate_bytes_helper(word, temp_crc, temp_length);
146 }
147
148 // Calculate for whole words, if any
149 temp_length = length & WORD_ALIGNMENT_MASK;
150
151 if (temp_length) {
152 length -= temp_length;
153 temp_length /= WORD_SIZE;
154
155 while (temp_length--) {
156 word = *(word_ptr++);
157 temp_crc = _crc32_recalculate_bytes_helper(word, temp_crc, WORD_SIZE);
158 }
159 }
160
161 // Calculate for tailing bytes
162 if (length) {
163 word = *word_ptr;
164 word &= 0xffffffffUL >> (8 * (WORD_SIZE - length));
165 temp_crc = _crc32_recalculate_bytes_helper(word, temp_crc, length);
166 }
167
168 *crc = COMPLEMENT_CRC(temp_crc);
169
170 return STATUS_OK;
171 }