• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lfs utility functions
3  *
4  * Copyright (c) 2017, Arm Limited. All rights reserved.
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 #ifndef LFS_UTIL_H
8 #define LFS_UTIL_H
9 
10 // Users can override lfs_util.h with their own configuration by defining
11 // LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h).
12 //
13 // If LFS_CONFIG is used, none of the default utils will be emitted and must be
14 // provided by the config file. To start, I would suggest copying lfs_util.h
15 // and modifying as needed.
16 #ifdef LFS_CONFIG
17 #define LFS_STRINGIZE(x) LFS_STRINGIZE2(x)
18 #define LFS_STRINGIZE2(x) #x
19 #include LFS_STRINGIZE(LFS_CONFIG)
20 #else
21 
22 // System includes
23 #include <stdint.h>
24 #include <stdbool.h>
25 #include <string.h>
26 #include <inttypes.h>
27 
28 #ifndef LFS_NO_MALLOC
29 #include <stdlib.h>
30 #endif
31 #ifndef LFS_NO_ASSERT
32 #include <assert.h>
33 #endif
34 #if !defined(LFS_NO_DEBUG) || \
35         !defined(LFS_NO_WARN) || \
36         !defined(LFS_NO_ERROR) || \
37         defined(LFS_YES_TRACE)
38 #include <stdio.h>
39 #endif
40 
41 #ifdef __cplusplus
42 extern "C"
43 {
44 #endif
45 
46 
47 // Macros, may be replaced by system specific wrappers. Arguments to these
48 // macros must not have side-effects as the macros can be removed for a smaller
49 // code footprint
50 
51 // Logging functions
52 #ifndef LFS_TRACE
53 #ifdef LFS_YES_TRACE
54 #define LFS_TRACE_(fmt, ...) \
55     printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
56 #define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "")
57 #else
58 #define LFS_TRACE(...)
59 #endif
60 #endif
61 
62 #ifndef LFS_DEBUG
63 #ifndef LFS_NO_DEBUG
64 #define LFS_DEBUG_(fmt, ...) \
65     printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
66 #define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "")
67 #else
68 #define LFS_DEBUG(...)
69 #endif
70 #endif
71 
72 #ifndef LFS_WARN
73 #ifndef LFS_NO_WARN
74 #define LFS_WARN_(fmt, ...) \
75     printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
76 #define LFS_WARN(...) LFS_WARN_(__VA_ARGS__, "")
77 #else
78 #define LFS_WARN(...)
79 #endif
80 #endif
81 
82 #ifndef LFS_ERROR
83 #ifndef LFS_NO_ERROR
84 #define LFS_ERROR_(fmt, ...) \
85     printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
86 #define LFS_ERROR(...) LFS_ERROR_(__VA_ARGS__, "")
87 #else
88 #define LFS_ERROR(...)
89 #endif
90 #endif
91 
92 // Runtime assertions
93 #ifndef LFS_ASSERT
94 #ifndef LFS_NO_ASSERT
95 #define LFS_ASSERT(test) assert(test)
96 #else
97 #define LFS_ASSERT(test)
98 #endif
99 #endif
100 
101 
102 // Builtin functions, these may be replaced by more efficient
103 // toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more
104 // expensive basic C implementation for debugging purposes
105 
106 // Min/max functions for unsigned 32-bit numbers
lfs_max(uint32_t a,uint32_t b)107 static inline uint32_t lfs_max(uint32_t a, uint32_t b) {
108     return (a > b) ? a : b;
109 }
110 
lfs_min(uint32_t a,uint32_t b)111 static inline uint32_t lfs_min(uint32_t a, uint32_t b) {
112     return (a < b) ? a : b;
113 }
114 
115 // Align to nearest multiple of a size
lfs_aligndown(uint32_t a,uint32_t alignment)116 static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) {
117     return a - (a % alignment);
118 }
119 
lfs_alignup(uint32_t a,uint32_t alignment)120 static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) {
121     return lfs_aligndown(a + alignment-1, alignment);
122 }
123 
124 // Find the smallest power of 2 greater than or equal to a
lfs_npw2(uint32_t a)125 static inline uint32_t lfs_npw2(uint32_t a) {
126 #if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
127     return 32 - __builtin_clz(a-1);
128 #else
129     uint32_t r = 0;
130     uint32_t s;
131     a -= 1;
132     s = (a > 0xffff) << 4; a >>= s; r |= s;
133     s = (a > 0xff  ) << 3; a >>= s; r |= s;
134     s = (a > 0xf   ) << 2; a >>= s; r |= s;
135     s = (a > 0x3   ) << 1; a >>= s; r |= s;
136     return (r | (a >> 1)) + 1;
137 #endif
138 }
139 
140 // Count the number of trailing binary zeros in a
141 // lfs_ctz(0) may be undefined
lfs_ctz(uint32_t a)142 static inline uint32_t lfs_ctz(uint32_t a) {
143 #if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__)
144     return __builtin_ctz(a);
145 #else
146     return lfs_npw2((a & -a) + 1) - 1;
147 #endif
148 }
149 
150 // Count the number of binary ones in a
lfs_popc(uint32_t a)151 static inline uint32_t lfs_popc(uint32_t a) {
152 #if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
153     return __builtin_popcount(a);
154 #else
155     a = a - ((a >> 1) & 0x55555555);
156     a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
157     return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
158 #endif
159 }
160 
161 // Find the sequence comparison of a and b, this is the distance
162 // between a and b ignoring overflow
lfs_scmp(uint32_t a,uint32_t b)163 static inline int lfs_scmp(uint32_t a, uint32_t b) {
164     return (int)(unsigned)(a - b);
165 }
166 
167 // Convert between 32-bit little-endian and native order
lfs_fromle32(uint32_t a)168 static inline uint32_t lfs_fromle32(uint32_t a) {
169 #if !defined(LFS_NO_INTRINSICS) && ( \
170     (defined(  BYTE_ORDER  ) && defined(  ORDER_LITTLE_ENDIAN  ) &&   BYTE_ORDER   ==   ORDER_LITTLE_ENDIAN  ) || \
171     (defined(__BYTE_ORDER  ) && defined(__ORDER_LITTLE_ENDIAN  ) && __BYTE_ORDER   == __ORDER_LITTLE_ENDIAN  ) || \
172     (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
173     return a;
174 #elif !defined(LFS_NO_INTRINSICS) && ( \
175     (defined(  BYTE_ORDER  ) && defined(  ORDER_BIG_ENDIAN  ) &&   BYTE_ORDER   ==   ORDER_BIG_ENDIAN  ) || \
176     (defined(__BYTE_ORDER  ) && defined(__ORDER_BIG_ENDIAN  ) && __BYTE_ORDER   == __ORDER_BIG_ENDIAN  ) || \
177     (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
178     return __builtin_bswap32(a);
179 #else
180     return (((uint8_t*)&a)[0] <<  0) |
181            (((uint8_t*)&a)[1] <<  8) |
182            (((uint8_t*)&a)[2] << 16) |
183            (((uint8_t*)&a)[3] << 24);
184 #endif
185 }
186 
lfs_tole32(uint32_t a)187 static inline uint32_t lfs_tole32(uint32_t a) {
188     return lfs_fromle32(a);
189 }
190 
191 // Convert between 32-bit big-endian and native order
lfs_frombe32(uint32_t a)192 static inline uint32_t lfs_frombe32(uint32_t a) {
193 #if !defined(LFS_NO_INTRINSICS) && ( \
194     (defined(  BYTE_ORDER  ) && defined(  ORDER_LITTLE_ENDIAN  ) &&   BYTE_ORDER   ==   ORDER_LITTLE_ENDIAN  ) || \
195     (defined(__BYTE_ORDER  ) && defined(__ORDER_LITTLE_ENDIAN  ) && __BYTE_ORDER   == __ORDER_LITTLE_ENDIAN  ) || \
196     (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
197     return __builtin_bswap32(a);
198 #elif !defined(LFS_NO_INTRINSICS) && ( \
199     (defined(  BYTE_ORDER  ) && defined(  ORDER_BIG_ENDIAN  ) &&   BYTE_ORDER   ==   ORDER_BIG_ENDIAN  ) || \
200     (defined(__BYTE_ORDER  ) && defined(__ORDER_BIG_ENDIAN  ) && __BYTE_ORDER   == __ORDER_BIG_ENDIAN  ) || \
201     (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
202     return a;
203 #else
204     return (((uint8_t*)&a)[0] << 24) |
205            (((uint8_t*)&a)[1] << 16) |
206            (((uint8_t*)&a)[2] <<  8) |
207            (((uint8_t*)&a)[3] <<  0);
208 #endif
209 }
210 
lfs_tobe32(uint32_t a)211 static inline uint32_t lfs_tobe32(uint32_t a) {
212     return lfs_frombe32(a);
213 }
214 
215 // Calculate CRC-32 with polynomial = 0x04c11db7
216 uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size);
217 
218 // Allocate memory, only used if buffers are not provided to littlefs
219 // Note, memory must be 64-bit aligned
lfs_malloc(size_t size)220 static inline void *lfs_malloc(size_t size) {
221 #ifndef LFS_NO_MALLOC
222     return malloc(size);
223 #else
224     (void)size;
225     return NULL;
226 #endif
227 }
228 
229 // Deallocate memory, only used if buffers are not provided to littlefs
lfs_free(void * p)230 static inline void lfs_free(void *p) {
231 #ifndef LFS_NO_MALLOC
232     free(p);
233 #else
234     (void)p;
235 #endif
236 }
237 
238 
239 #ifdef __cplusplus
240 } /* extern "C" */
241 #endif
242 
243 #endif
244 #endif
245