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