1 /**************************************************************************//**
2 *
3 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Change Logs:
8 * Date Author Notes
9 * 2020-2-7 Wayne First version
10 *
11 ******************************************************************************/
12 #ifndef __NU_BITUTIL_H__
13 #define __NU_BITUTIL_H__
14
15 #if defined(__ICCARM__)
16 #include <arm_math.h>
17 #elif defined (__ARMCC_VERSION)
18 #ifdef __has_include
19 #if __has_include("cmsis_compiler.h")
20 #include "cmsis_compiler.h"
21 #endif
22 #endif
23
24 #if !defined(__CLZ)
25 #define __CLZ __clz
26 #endif
27 #endif
28
29 #include <stdint.h>
30
31 #if !defined(__STATIC_INLINE)
32 #define __STATIC_INLINE static inline
33 #endif
34
35 #ifdef __cplusplus
36 extern "C" {
37 #endif
38
39 /* ----------------------------------------------
40 * Count Leading Zeros Count Trailing Zeros
41 * (MSB)00000000000000001000000000001000(LSB)
42 * ################| |!!!
43 * Find Highest Set Find First Set
44 * ----------------------------------------------
45 *
46 * ----------------------------------------------
47 * Count Leading Ones Count Trailing Ones
48 * (MSB)11111111111111110111111111110111(LSB)
49 * ^^^^^^^^^^^^^^^^| |@@@
50 * Find Highest Zero Find First Zero
51 * ----------------------------------------------
52 */
53
54 /* Count Leading Zeros in word - Find Highest Set
55 EX: x=(MSB)00000000000000001000000000001000(LSB)
56 ################|
57 Find Highest Set
58 nu_clz will start zero-counting from MSB and return the number.
59 */
60
nu_clz(uint32_t x)61 __STATIC_INLINE int nu_clz(uint32_t x)
62 {
63 return x ? __CLZ(x) : 32;
64 }
65
66 /* Count Leading Ones in word - Find Highest Zero
67 EX: x=(MSB)11111111111111110111111111110111(LSB)
68 ^^^^^^^^^^^^^^^^|
69 Find Highest Zero
70 nu_clo will start one-counting from MSB and return the number.
71 */
nu_clo(uint32_t x)72 __STATIC_INLINE int nu_clo(uint32_t x)
73 {
74 return nu_clz(~x);
75 }
76
77 /* Count Trailing Zero in word - Find First Set
78 EX: x=(MSB)00000000000000001000000000001000(LSB)
79 |!!!
80 Find First Set
81 nu_ctz will start zero-counting from LSB and return the number.
82 */
nu_ctz(uint32_t x)83 __STATIC_INLINE int nu_ctz(uint32_t x)
84 {
85 int c = 32;
86 if (x)
87 c = __CLZ(x & -x);
88 return x ? 31 - c : c;
89 }
90
91 /* Count Trailing Ones in word - Find First Zero
92 EX: x=(MSB)11111111111111110111111111110111(LSB)
93 |@@@
94 Find First Zero
95 nu_cto will start one-counting from LSB and return the number.
96 */
nu_cto(uint32_t x)97 __STATIC_INLINE int nu_cto(uint32_t x)
98 {
99 return nu_ctz(~x);
100 }
101
102 /* Get 16-bit from a byte-array in little-endian */
nu_get16_le(const uint8_t * pos)103 __STATIC_INLINE uint16_t nu_get16_le(const uint8_t *pos)
104 {
105 uint16_t val;
106
107 val = *pos ++;
108 val += (*pos << 8);
109
110 return val;
111 }
112
113 /* Set 16-bit to a byte-array in little-endian */
nu_set16_le(uint8_t * pos,uint16_t val)114 __STATIC_INLINE void nu_set16_le(uint8_t *pos, uint16_t val)
115 {
116 *pos ++ = val & 0xFF;
117 *pos = val >> 8;
118 }
119
120 /* Get 32-bit from a byte-array in little-endian */
nu_get32_le(const uint8_t * pos)121 __STATIC_INLINE uint32_t nu_get32_le(const uint8_t *pos)
122 {
123 uint32_t val;
124
125 val = *pos ++;
126 val += (*pos ++ << 8);
127 val += (*pos ++ << 16);
128 val += (*pos ++ << 24);
129
130 return val;
131 }
132
133 /* Get 24-bit from a byte-array in little-endian */
nu_get24_le(const uint8_t * pos)134 __STATIC_INLINE uint32_t nu_get24_le(const uint8_t *pos)
135 {
136 uint32_t val;
137
138 val = *pos ++;
139 val += (*pos ++ << 8);
140 val += (*pos ++ << 16);
141
142 return val;
143 }
144
145 /* Set 24-bit to a byte-array in little-endian */
nu_set24_le(uint8_t * pos,uint32_t val)146 __STATIC_INLINE void nu_set24_le(uint8_t *pos, uint32_t val)
147 {
148 *pos ++ = val & 0xFF;
149 *pos ++ = (val >> 8) & 0xFF;
150 *pos ++ = (val >> 16) & 0xFF;
151 }
152
153 /* Set 32-bit to a byte-array in little-endian */
nu_set32_le(uint8_t * pos,uint32_t val)154 __STATIC_INLINE void nu_set32_le(uint8_t *pos, uint32_t val)
155 {
156 *pos ++ = val & 0xFF;
157 *pos ++ = (val >> 8) & 0xFF;
158 *pos ++ = (val >> 16) & 0xFF;
159 *pos = (val >> 24) & 0xFF;
160 }
161
162 /* Get 16-bit from a byte-array in big-endian */
nu_get16_be(const uint8_t * pos)163 __STATIC_INLINE uint16_t nu_get16_be(const uint8_t *pos)
164 {
165 uint16_t val;
166
167 val = *pos ++;
168 val <<= 8;
169 val += *pos;
170
171 return val;
172 }
173
174 /* Set 16-bit to a byte-array in big-endian */
nu_set16_be(uint8_t * pos,uint16_t val)175 __STATIC_INLINE void nu_set16_be(uint8_t *pos, uint16_t val)
176 {
177 *pos ++ = val >> 8;
178 *pos = (val & 0xFF);
179 }
180
181 /* Get 24-bit from a byte-array in big-endian */
nu_get24_be(const uint8_t * pos)182 __STATIC_INLINE uint32_t nu_get24_be(const uint8_t *pos)
183 {
184 uint32_t val;
185
186 val = *pos ++;
187 val <<= 8;
188 val += *pos ++;
189 val <<= 8;
190 val += *pos ++;
191
192 return val;
193 }
194
195 /* Set 24-bit to a byte-array in big-endian */
nu_set24_be(uint8_t * pos,uint32_t val)196 __STATIC_INLINE void nu_set24_be(uint8_t *pos, uint32_t val)
197 {
198 *pos ++ = val >> 16;
199 *pos ++ = val >> 8;
200 *pos ++ = (val & 0xFF);
201 }
202
203 /* Get 32-bit from a byte-array in big-endian */
nu_get32_be(const uint8_t * pos)204 __STATIC_INLINE uint32_t nu_get32_be(const uint8_t *pos)
205 {
206 uint32_t val;
207
208 val = *pos ++;
209 val <<= 8;
210 val += *pos ++;
211 val <<= 8;
212 val += *pos ++;
213 val <<= 8;
214 val += *pos;
215
216 return val;
217 }
218
219 /* Set 32-bit to a byte-array in big-endian */
nu_set32_be(uint8_t * pos,uint32_t val)220 __STATIC_INLINE void nu_set32_be(uint8_t *pos, uint32_t val)
221 {
222 *pos ++ = val >> 24;
223 *pos ++ = val >> 16;
224 *pos ++ = val >> 8;
225 *pos ++ = (val & 0xFF);
226 }
227
228 #ifdef __cplusplus
229 }
230 #endif
231
232 #endif //__NU_BITUTIL_H__
233