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