first submission

This commit is contained in:
qiyongshuang
2023-02-01 14:19:13 +08:00
parent d534aad004
commit b79c6ac80d
3711 changed files with 745432 additions and 2 deletions
@@ -0,0 +1,243 @@
/*
* Copyright (c) 1997-2015, Wind River Systems, Inc.
* Copyright (c) 2021 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_SYS_ATOMIC_H_
#define ZEPHYR_INCLUDE_SYS_ATOMIC_H_
#include <stdbool.h>
#include <toolchain.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef int atomic_t;
typedef atomic_t atomic_val_t;
typedef void *atomic_ptr_t;
typedef atomic_ptr_t atomic_ptr_val_t;
/* Low-level primitives come in several styles: */
#if defined(CONFIG_ATOMIC_OPERATIONS_C)
/* Generic-but-slow implementation based on kernel locking and syscalls */
#include <sys/atomic_c.h>
#elif defined(CONFIG_ATOMIC_OPERATIONS_ARCH)
/* Some architectures need their own implementation */
# ifdef CONFIG_XTENSA
/* Not all Xtensa toolchains support GCC-style atomic intrinsics */
# include <arch/xtensa/atomic_xtensa.h>
# else
/* Other arch specific implementation */
# include <sys/atomic_arch.h>
# endif /* CONFIG_XTENSA */
#else
/* Default. See this file for the Doxygen reference: */
#include <sys/atomic_builtin.h>
#endif
/* Portable higher-level utilities: */
/**
* @defgroup atomic_apis Atomic Services APIs
* @ingroup kernel_apis
* @{
*/
/**
* @brief Initialize an atomic variable.
*
* This macro can be used to initialize an atomic variable. For example,
* @code atomic_t my_var = ATOMIC_INIT(75); @endcode
*
* @param i Value to assign to atomic variable.
*/
#define ATOMIC_INIT(i) (i)
/**
* @brief Initialize an atomic pointer variable.
*
* This macro can be used to initialize an atomic pointer variable. For
* example,
* @code atomic_ptr_t my_ptr = ATOMIC_PTR_INIT(&data); @endcode
*
* @param p Pointer value to assign to atomic pointer variable.
*/
#define ATOMIC_PTR_INIT(p) (p)
/**
* @cond INTERNAL_HIDDEN
*/
#define ATOMIC_BITS (sizeof(atomic_val_t) * 8)
#define ATOMIC_MASK(bit) (1U << ((uint32_t)(bit) & (ATOMIC_BITS - 1U)))
#define ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / ATOMIC_BITS))
/**
* INTERNAL_HIDDEN @endcond
*/
/**
* @brief This macro computes the number of atomic variables necessary to
* represent a bitmap with @a num_bits.
*
* @param num_bits Number of bits.
*/
#define ATOMIC_BITMAP_SIZE(num_bits) (1 + ((num_bits) - 1) / ATOMIC_BITS)
/**
* @brief Define an array of atomic variables.
*
* This macro defines an array of atomic variables containing at least
* @a num_bits bits.
*
* @note
* If used from file scope, the bits of the array are initialized to zero;
* if used from within a function, the bits are left uninitialized.
*
* @cond INTERNAL_HIDDEN
* @note
* This macro should be replicated in the PREDEFINED field of the documentation
* Doxyfile.
* @endcond
*
* @param name Name of array of atomic variables.
* @param num_bits Number of bits needed.
*/
#define ATOMIC_DEFINE(name, num_bits) \
atomic_t name[ATOMIC_BITMAP_SIZE(num_bits)]
/**
* @brief Atomically test a bit.
*
* This routine tests whether bit number @a bit of @a target is set or not.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return true if the bit was set, false if it wasn't.
*/
static inline bool atomic_test_bit(const atomic_t *target, int bit)
{
atomic_val_t val = atomic_get(ATOMIC_ELEM(target, bit));
return (1 & (val >> (bit & (ATOMIC_BITS - 1)))) != 0;
}
/**
* @brief Atomically test and clear a bit.
*
* Atomically clear bit number @a bit of @a target and return its old value.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return true if the bit was set, false if it wasn't.
*/
static inline bool atomic_test_and_clear_bit(atomic_t *target, int bit)
{
atomic_val_t mask = ATOMIC_MASK(bit);
atomic_val_t old;
old = atomic_and(ATOMIC_ELEM(target, bit), ~mask);
return (old & mask) != 0;
}
/**
* @brief Atomically set a bit.
*
* Atomically set bit number @a bit of @a target and return its old value.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return true if the bit was set, false if it wasn't.
*/
static inline bool atomic_test_and_set_bit(atomic_t *target, int bit)
{
atomic_val_t mask = ATOMIC_MASK(bit);
atomic_val_t old;
old = atomic_or(ATOMIC_ELEM(target, bit), mask);
return (old & mask) != 0;
}
/**
* @brief Atomically clear a bit.
*
* Atomically clear bit number @a bit of @a target.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return N/A
*/
static inline void atomic_clear_bit(atomic_t *target, int bit)
{
atomic_val_t mask = ATOMIC_MASK(bit);
(void)atomic_and(ATOMIC_ELEM(target, bit), ~mask);
}
/**
* @brief Atomically set a bit.
*
* Atomically set bit number @a bit of @a target.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return N/A
*/
static inline void atomic_set_bit(atomic_t *target, int bit)
{
atomic_val_t mask = ATOMIC_MASK(bit);
(void)atomic_or(ATOMIC_ELEM(target, bit), mask);
}
/**
* @brief Atomically set a bit to a given value.
*
* Atomically set bit number @a bit of @a target to value @a val.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
* @param val true for 1, false for 0.
*
* @return N/A
*/
static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val)
{
atomic_val_t mask = ATOMIC_MASK(bit);
if (val) {
(void)atomic_or(ATOMIC_ELEM(target, bit), mask);
} else {
(void)atomic_and(ATOMIC_ELEM(target, bit), ~mask);
}
}
/**
* @}
*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ZEPHYR_INCLUDE_SYS_ATOMIC_H_ */
@@ -0,0 +1,303 @@
/* atomic operations */
/*
* Copyright (c) 1997-2015, Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_SYS_ATOMIC_BUILTIN_H_
#define ZEPHYR_INCLUDE_SYS_ATOMIC_BUILTIN_H_
#ifdef __cplusplus
extern "C" {
#endif
/* Included from <atomic.h> */
/**
* @addtogroup atomic_apis Atomic Services APIs
* @ingroup kernel_apis
* @{
*/
/**
* @brief Atomic compare-and-set.
*
* This routine performs an atomic compare-and-set on @a target. If the current
* value of @a target equals @a old_value, @a target is set to @a new_value.
* If the current value of @a target does not equal @a old_value, @a target
* is left unchanged.
*
* @param target Address of atomic variable.
* @param old_value Original value to compare against.
* @param new_value New value to store.
* @return true if @a new_value is written, false otherwise.
*/
static inline bool atomic_cas(atomic_t *target, atomic_val_t old_value,
atomic_val_t new_value)
{
return __atomic_compare_exchange_n(target, &old_value, new_value,
0, __ATOMIC_SEQ_CST,
__ATOMIC_SEQ_CST);
}
/**
* @brief Atomic compare-and-set with pointer values
*
* This routine performs an atomic compare-and-set on @a target. If the current
* value of @a target equals @a old_value, @a target is set to @a new_value.
* If the current value of @a target does not equal @a old_value, @a target
* is left unchanged.
*
* @param target Address of atomic variable.
* @param old_value Original value to compare against.
* @param new_value New value to store.
* @return true if @a new_value is written, false otherwise.
*/
static inline bool atomic_ptr_cas(atomic_ptr_t *target, atomic_ptr_val_t old_value,
atomic_ptr_val_t new_value)
{
return __atomic_compare_exchange_n(target, &old_value, new_value,
0, __ATOMIC_SEQ_CST,
__ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic addition.
*
* This routine performs an atomic addition on @a target.
*
* @param target Address of atomic variable.
* @param value Value to add.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_add(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_add(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic subtraction.
*
* This routine performs an atomic subtraction on @a target.
*
* @param target Address of atomic variable.
* @param value Value to subtract.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_sub(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic increment.
*
* This routine performs an atomic increment by 1 on @a target.
*
* @param target Address of atomic variable.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_inc(atomic_t *target)
{
return atomic_add(target, 1);
}
/**
*
* @brief Atomic decrement.
*
* This routine performs an atomic decrement by 1 on @a target.
*
* @param target Address of atomic variable.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_dec(atomic_t *target)
{
return atomic_sub(target, 1);
}
/**
*
* @brief Atomic get.
*
* This routine performs an atomic read on @a target.
*
* @param target Address of atomic variable.
*
* @return Value of @a target.
*/
static inline atomic_val_t atomic_get(const atomic_t *target)
{
return __atomic_load_n(target, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic get a pointer value
*
* This routine performs an atomic read on @a target.
*
* @param target Address of pointer variable.
*
* @return Value of @a target.
*/
static inline atomic_ptr_val_t atomic_ptr_get(const atomic_ptr_t *target)
{
return __atomic_load_n(target, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic get-and-set.
*
* This routine atomically sets @a target to @a value and returns
* the previous value of @a target.
*
* @param target Address of atomic variable.
* @param value Value to write to @a target.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_set(atomic_t *target, atomic_val_t value)
{
/* This builtin, as described by Intel, is not a traditional
* test-and-set operation, but rather an atomic exchange operation. It
* writes value into *ptr, and returns the previous contents of *ptr.
*/
return __atomic_exchange_n(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic get-and-set for pointer values
*
* This routine atomically sets @a target to @a value and returns
* the previous value of @a target.
*
* @param target Address of atomic variable.
* @param value Value to write to @a target.
*
* @return Previous value of @a target.
*/
static inline atomic_ptr_val_t atomic_ptr_set(atomic_ptr_t *target, atomic_ptr_val_t value)
{
return __atomic_exchange_n(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic clear.
*
* This routine atomically sets @a target to zero and returns its previous
* value. (Hence, it is equivalent to atomic_set(target, 0).)
*
* @param target Address of atomic variable.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_clear(atomic_t *target)
{
return atomic_set(target, 0);
}
/**
*
* @brief Atomic clear of a pointer value
*
* This routine atomically sets @a target to zero and returns its previous
* value. (Hence, it is equivalent to atomic_set(target, 0).)
*
* @param target Address of atomic variable.
*
* @return Previous value of @a target.
*/
static inline atomic_ptr_val_t atomic_ptr_clear(atomic_ptr_t *target)
{
return atomic_ptr_set(target, NULL);
}
/**
*
* @brief Atomic bitwise inclusive OR.
*
* This routine atomically sets @a target to the bitwise inclusive OR of
* @a target and @a value.
*
* @param target Address of atomic variable.
* @param value Value to OR.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_or(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_or(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic bitwise exclusive OR (XOR).
*
* This routine atomically sets @a target to the bitwise exclusive OR (XOR) of
* @a target and @a value.
*
* @param target Address of atomic variable.
* @param value Value to XOR
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_xor(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic bitwise AND.
*
* This routine atomically sets @a target to the bitwise AND of @a target
* and @a value.
*
* @param target Address of atomic variable.
* @param value Value to AND.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_and(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_and(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic bitwise NAND.
*
* This routine atomically sets @a target to the bitwise NAND of @a target
* and @a value. (This operation is equivalent to target = ~(target & value).)
*
* @param target Address of atomic variable.
* @param value Value to NAND.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_nand(target, value, __ATOMIC_SEQ_CST);
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_SYS_ATOMIC_BUILTIN_H_ */
@@ -0,0 +1,568 @@
/** @file
* @brief Byte order helpers.
*/
/*
* Copyright (c) 2015-2016, Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_SYS_BYTEORDER_H_
#define ZEPHYR_INCLUDE_SYS_BYTEORDER_H_
#include <zephyr/types.h>
#include <stddef.h>
// #include <sys/__assert.h>
#include <toolchain.h>
/* Internal helpers only used by the sys_* APIs further below */
#define __bswap_16(x) ((uint16_t) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)))
#define __bswap_24(x) ((uint32_t) ((((x) >> 16) & 0xff) | \
(((x)) & 0xff00) | \
(((x) & 0xff) << 16)))
#define __bswap_32(x) ((uint32_t) ((((x) >> 24) & 0xff) | \
(((x) >> 8) & 0xff00) | \
(((x) & 0xff00) << 8) | \
(((x) & 0xff) << 24)))
#define __bswap_48(x) ((uint64_t) ((((x) >> 40) & 0xff) | \
(((x) >> 24) & 0xff00) | \
(((x) >> 8) & 0xff0000) | \
(((x) & 0xff0000) << 8) | \
(((x) & 0xff00) << 24) | \
(((x) & 0xff) << 40)))
#define __bswap_64(x) ((uint64_t) ((((x) >> 56) & 0xff) | \
(((x) >> 40) & 0xff00) | \
(((x) >> 24) & 0xff0000) | \
(((x) >> 8) & 0xff000000) | \
(((x) & 0xff000000) << 8) | \
(((x) & 0xff0000) << 24) | \
(((x) & 0xff00) << 40) | \
(((x) & 0xff) << 56)))
/** @def sys_le16_to_cpu
* @brief Convert 16-bit integer from little-endian to host endianness.
*
* @param val 16-bit integer in little-endian format.
*
* @return 16-bit integer in host endianness.
*/
/** @def sys_cpu_to_le16
* @brief Convert 16-bit integer from host endianness to little-endian.
*
* @param val 16-bit integer in host endianness.
*
* @return 16-bit integer in little-endian format.
*/
/** @def sys_le24_to_cpu
* @brief Convert 24-bit integer from little-endian to host endianness.
*
* @param val 24-bit integer in little-endian format.
*
* @return 24-bit integer in host endianness.
*/
/** @def sys_cpu_to_le24
* @brief Convert 24-bit integer from host endianness to little-endian.
*
* @param val 24-bit integer in host endianness.
*
* @return 24-bit integer in little-endian format.
*/
/** @def sys_le32_to_cpu
* @brief Convert 32-bit integer from little-endian to host endianness.
*
* @param val 32-bit integer in little-endian format.
*
* @return 32-bit integer in host endianness.
*/
/** @def sys_cpu_to_le32
* @brief Convert 32-bit integer from host endianness to little-endian.
*
* @param val 32-bit integer in host endianness.
*
* @return 32-bit integer in little-endian format.
*/
/** @def sys_le48_to_cpu
* @brief Convert 48-bit integer from little-endian to host endianness.
*
* @param val 48-bit integer in little-endian format.
*
* @return 48-bit integer in host endianness.
*/
/** @def sys_cpu_to_le48
* @brief Convert 48-bit integer from host endianness to little-endian.
*
* @param val 48-bit integer in host endianness.
*
* @return 48-bit integer in little-endian format.
*/
/** @def sys_be16_to_cpu
* @brief Convert 16-bit integer from big-endian to host endianness.
*
* @param val 16-bit integer in big-endian format.
*
* @return 16-bit integer in host endianness.
*/
/** @def sys_cpu_to_be16
* @brief Convert 16-bit integer from host endianness to big-endian.
*
* @param val 16-bit integer in host endianness.
*
* @return 16-bit integer in big-endian format.
*/
/** @def sys_be24_to_cpu
* @brief Convert 24-bit integer from big-endian to host endianness.
*
* @param val 24-bit integer in big-endian format.
*
* @return 24-bit integer in host endianness.
*/
/** @def sys_cpu_to_be24
* @brief Convert 24-bit integer from host endianness to big-endian.
*
* @param val 24-bit integer in host endianness.
*
* @return 24-bit integer in big-endian format.
*/
/** @def sys_be32_to_cpu
* @brief Convert 32-bit integer from big-endian to host endianness.
*
* @param val 32-bit integer in big-endian format.
*
* @return 32-bit integer in host endianness.
*/
/** @def sys_cpu_to_be32
* @brief Convert 32-bit integer from host endianness to big-endian.
*
* @param val 32-bit integer in host endianness.
*
* @return 32-bit integer in big-endian format.
*/
/** @def sys_be48_to_cpu
* @brief Convert 48-bit integer from big-endian to host endianness.
*
* @param val 48-bit integer in big-endian format.
*
* @return 48-bit integer in host endianness.
*/
/** @def sys_cpu_to_be48
* @brief Convert 48-bit integer from host endianness to big-endian.
*
* @param val 48-bit integer in host endianness.
*
* @return 48-bit integer in big-endian format.
*/
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define sys_le16_to_cpu(val) (val)
#define sys_cpu_to_le16(val) (val)
#define sys_le24_to_cpu(val) (val)
#define sys_cpu_to_le24(val) (val)
#define sys_le32_to_cpu(val) (val)
#define sys_cpu_to_le32(val) (val)
#define sys_le48_to_cpu(val) (val)
#define sys_cpu_to_le48(val) (val)
#define sys_le64_to_cpu(val) (val)
#define sys_cpu_to_le64(val) (val)
#define sys_be16_to_cpu(val) __bswap_16(val)
#define sys_cpu_to_be16(val) __bswap_16(val)
#define sys_be24_to_cpu(val) __bswap_24(val)
#define sys_cpu_to_be24(val) __bswap_24(val)
#define sys_be32_to_cpu(val) __bswap_32(val)
#define sys_cpu_to_be32(val) __bswap_32(val)
#define sys_be48_to_cpu(val) __bswap_48(val)
#define sys_cpu_to_be48(val) __bswap_48(val)
#define sys_be64_to_cpu(val) __bswap_64(val)
#define sys_cpu_to_be64(val) __bswap_64(val)
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define sys_le16_to_cpu(val) __bswap_16(val)
#define sys_cpu_to_le16(val) __bswap_16(val)
#define sys_le24_to_cpu(val) __bswap_24(val)
#define sys_cpu_to_le24(val) __bswap_24(val)
#define sys_le32_to_cpu(val) __bswap_32(val)
#define sys_cpu_to_le32(val) __bswap_32(val)
#define sys_le48_to_cpu(val) __bswap_48(val)
#define sys_cpu_to_le48(val) __bswap_48(val)
#define sys_le64_to_cpu(val) __bswap_64(val)
#define sys_cpu_to_le64(val) __bswap_64(val)
#define sys_be16_to_cpu(val) (val)
#define sys_cpu_to_be16(val) (val)
#define sys_be24_to_cpu(val) (val)
#define sys_cpu_to_be24(val) (val)
#define sys_be32_to_cpu(val) (val)
#define sys_cpu_to_be32(val) (val)
#define sys_be48_to_cpu(val) (val)
#define sys_cpu_to_be48(val) (val)
#define sys_be64_to_cpu(val) (val)
#define sys_cpu_to_be64(val) (val)
#else
#error "Unknown byte order"
#endif
/**
* @brief Put a 16-bit integer as big-endian to arbitrary location.
*
* Put a 16-bit integer, originally in host endianness, to a
* potentially unaligned memory location in big-endian format.
*
* @param val 16-bit integer in host endianness.
* @param dst Destination memory address to store the result.
*/
static inline void sys_put_be16(uint16_t val, uint8_t dst[2])
{
dst[0] = val >> 8;
dst[1] = val;
}
/**
* @brief Put a 24-bit integer as big-endian to arbitrary location.
*
* Put a 24-bit integer, originally in host endianness, to a
* potentially unaligned memory location in big-endian format.
*
* @param val 24-bit integer in host endianness.
* @param dst Destination memory address to store the result.
*/
static inline void sys_put_be24(uint32_t val, uint8_t dst[3])
{
dst[0] = val >> 16;
sys_put_be16(val, &dst[1]);
}
/**
* @brief Put a 32-bit integer as big-endian to arbitrary location.
*
* Put a 32-bit integer, originally in host endianness, to a
* potentially unaligned memory location in big-endian format.
*
* @param val 32-bit integer in host endianness.
* @param dst Destination memory address to store the result.
*/
static inline void sys_put_be32(uint32_t val, uint8_t dst[4])
{
sys_put_be16(val >> 16, dst);
sys_put_be16(val, &dst[2]);
}
/**
* @brief Put a 48-bit integer as big-endian to arbitrary location.
*
* Put a 48-bit integer, originally in host endianness, to a
* potentially unaligned memory location in big-endian format.
*
* @param val 48-bit integer in host endianness.
* @param dst Destination memory address to store the result.
*/
static inline void sys_put_be48(uint64_t val, uint8_t dst[6])
{
sys_put_be16(val >> 32, dst);
sys_put_be32(val, &dst[2]);
}
/**
* @brief Put a 64-bit integer as big-endian to arbitrary location.
*
* Put a 64-bit integer, originally in host endianness, to a
* potentially unaligned memory location in big-endian format.
*
* @param val 64-bit integer in host endianness.
* @param dst Destination memory address to store the result.
*/
static inline void sys_put_be64(uint64_t val, uint8_t dst[8])
{
sys_put_be32(val >> 32, dst);
sys_put_be32(val, &dst[4]);
}
/**
* @brief Put a 16-bit integer as little-endian to arbitrary location.
*
* Put a 16-bit integer, originally in host endianness, to a
* potentially unaligned memory location in little-endian format.
*
* @param val 16-bit integer in host endianness.
* @param dst Destination memory address to store the result.
*/
static inline void sys_put_le16(uint16_t val, uint8_t dst[2])
{
dst[0] = val;
dst[1] = val >> 8;
}
/**
* @brief Put a 24-bit integer as little-endian to arbitrary location.
*
* Put a 24-bit integer, originally in host endianness, to a
* potentially unaligned memory location in littel-endian format.
*
* @param val 24-bit integer in host endianness.
* @param dst Destination memory address to store the result.
*/
static inline void sys_put_le24(uint32_t val, uint8_t dst[3])
{
sys_put_le16(val, dst);
dst[2] = val >> 16;
}
/**
* @brief Put a 32-bit integer as little-endian to arbitrary location.
*
* Put a 32-bit integer, originally in host endianness, to a
* potentially unaligned memory location in little-endian format.
*
* @param val 32-bit integer in host endianness.
* @param dst Destination memory address to store the result.
*/
static inline void sys_put_le32(uint32_t val, uint8_t dst[4])
{
sys_put_le16(val, dst);
sys_put_le16(val >> 16, &dst[2]);
}
/**
* @brief Put a 48-bit integer as little-endian to arbitrary location.
*
* Put a 48-bit integer, originally in host endianness, to a
* potentially unaligned memory location in little-endian format.
*
* @param val 48-bit integer in host endianness.
* @param dst Destination memory address to store the result.
*/
static inline void sys_put_le48(uint64_t val, uint8_t dst[6])
{
sys_put_le32(val, dst);
sys_put_le16(val >> 32, &dst[4]);
}
/**
* @brief Put a 64-bit integer as little-endian to arbitrary location.
*
* Put a 64-bit integer, originally in host endianness, to a
* potentially unaligned memory location in little-endian format.
*
* @param val 64-bit integer in host endianness.
* @param dst Destination memory address to store the result.
*/
static inline void sys_put_le64(uint64_t val, uint8_t dst[8])
{
sys_put_le32(val, dst);
sys_put_le32(val >> 32, &dst[4]);
}
/**
* @brief Get a 16-bit integer stored in big-endian format.
*
* Get a 16-bit integer, stored in big-endian format in a potentially
* unaligned memory location, and convert it to the host endianness.
*
* @param src Location of the big-endian 16-bit integer to get.
*
* @return 16-bit integer in host endianness.
*/
static inline uint16_t sys_get_be16(const uint8_t src[2])
{
return ((uint16_t)src[0] << 8) | src[1];
}
/**
* @brief Get a 24-bit integer stored in big-endian format.
*
* Get a 24-bit integer, stored in big-endian format in a potentially
* unaligned memory location, and convert it to the host endianness.
*
* @param src Location of the big-endian 24-bit integer to get.
*
* @return 24-bit integer in host endianness.
*/
static inline uint32_t sys_get_be24(const uint8_t src[3])
{
return ((uint32_t)src[0] << 16) | sys_get_be16(&src[1]);
}
/**
* @brief Get a 32-bit integer stored in big-endian format.
*
* Get a 32-bit integer, stored in big-endian format in a potentially
* unaligned memory location, and convert it to the host endianness.
*
* @param src Location of the big-endian 32-bit integer to get.
*
* @return 32-bit integer in host endianness.
*/
static inline uint32_t sys_get_be32(const uint8_t src[4])
{
return ((uint32_t)sys_get_be16(&src[0]) << 16) | sys_get_be16(&src[2]);
}
/**
* @brief Get a 48-bit integer stored in big-endian format.
*
* Get a 48-bit integer, stored in big-endian format in a potentially
* unaligned memory location, and convert it to the host endianness.
*
* @param src Location of the big-endian 48-bit integer to get.
*
* @return 48-bit integer in host endianness.
*/
static inline uint64_t sys_get_be48(const uint8_t src[6])
{
return ((uint64_t)sys_get_be32(&src[0]) << 16) | sys_get_be16(&src[4]);
}
/**
* @brief Get a 64-bit integer stored in big-endian format.
*
* Get a 64-bit integer, stored in big-endian format in a potentially
* unaligned memory location, and convert it to the host endianness.
*
* @param src Location of the big-endian 64-bit integer to get.
*
* @return 64-bit integer in host endianness.
*/
static inline uint64_t sys_get_be64(const uint8_t src[8])
{
return ((uint64_t)sys_get_be32(&src[0]) << 32) | sys_get_be32(&src[4]);
}
/**
* @brief Get a 16-bit integer stored in little-endian format.
*
* Get a 16-bit integer, stored in little-endian format in a potentially
* unaligned memory location, and convert it to the host endianness.
*
* @param src Location of the little-endian 16-bit integer to get.
*
* @return 16-bit integer in host endianness.
*/
static inline uint16_t sys_get_le16(const uint8_t src[2])
{
return ((uint16_t)src[1] << 8) | src[0];
}
/**
* @brief Get a 24-bit integer stored in big-endian format.
*
* Get a 24-bit integer, stored in big-endian format in a potentially
* unaligned memory location, and convert it to the host endianness.
*
* @param src Location of the big-endian 24-bit integer to get.
*
* @return 24-bit integer in host endianness.
*/
static inline uint32_t sys_get_le24(const uint8_t src[3])
{
return ((uint32_t)src[2] << 16) | sys_get_le16(&src[0]);
}
/**
* @brief Get a 32-bit integer stored in little-endian format.
*
* Get a 32-bit integer, stored in little-endian format in a potentially
* unaligned memory location, and convert it to the host endianness.
*
* @param src Location of the little-endian 32-bit integer to get.
*
* @return 32-bit integer in host endianness.
*/
static inline uint32_t sys_get_le32(const uint8_t src[4])
{
return ((uint32_t)sys_get_le16(&src[2]) << 16) | sys_get_le16(&src[0]);
}
/**
* @brief Get a 48-bit integer stored in little-endian format.
*
* Get a 48-bit integer, stored in little-endian format in a potentially
* unaligned memory location, and convert it to the host endianness.
*
* @param src Location of the little-endian 48-bit integer to get.
*
* @return 48-bit integer in host endianness.
*/
static inline uint64_t sys_get_le48(const uint8_t src[6])
{
return ((uint64_t)sys_get_le32(&src[2]) << 16) | sys_get_le16(&src[0]);
}
/**
* @brief Get a 64-bit integer stored in little-endian format.
*
* Get a 64-bit integer, stored in little-endian format in a potentially
* unaligned memory location, and convert it to the host endianness.
*
* @param src Location of the little-endian 64-bit integer to get.
*
* @return 64-bit integer in host endianness.
*/
static inline uint64_t sys_get_le64(const uint8_t src[8])
{
return ((uint64_t)sys_get_le32(&src[4]) << 32) | sys_get_le32(&src[0]);
}
/**
* @brief Swap one buffer content into another
*
* Copy the content of src buffer into dst buffer in reversed order,
* i.e.: src[n] will be put in dst[end-n]
* Where n is an index and 'end' the last index in both arrays.
* The 2 memory pointers must be pointing to different areas, and have
* a minimum size of given length.
*
* @param dst A valid pointer on a memory area where to copy the data in
* @param src A valid pointer on a memory area where to copy the data from
* @param length Size of both dst and src memory areas
*/
static inline void sys_memcpy_swap(void *dst, const void *src, size_t length)
{
uint8_t *pdst = (uint8_t *)dst;
const uint8_t *psrc = (const uint8_t *)src;
// __ASSERT(((psrc < pdst && (psrc + length) <= pdst) ||
// (psrc > pdst && (pdst + length) <= psrc)),
// "Source and destination buffers must not overlap");
psrc += length - 1;
for (; length > 0; length--) {
*pdst++ = *psrc--;
}
}
/**
* @brief Swap buffer content
*
* In-place memory swap, where final content will be reversed.
* I.e.: buf[n] will be put in buf[end-n]
* Where n is an index and 'end' the last index of buf.
*
* @param buf A valid pointer on a memory area to swap
* @param length Size of buf memory area
*/
static inline void sys_mem_swap(void *buf, size_t length)
{
size_t i;
for (i = 0; i < (length/2); i++) {
uint8_t tmp = ((uint8_t *)buf)[i];
((uint8_t *)buf)[i] = ((uint8_t *)buf)[length - 1 - i];
((uint8_t *)buf)[length - 1 - i] = tmp;
}
}
#endif /* ZEPHYR_INCLUDE_SYS_BYTEORDER_H_ */
@@ -0,0 +1,433 @@
/*
* Copyright (c) 2011-2014, Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Misc utilities
*
* Misc utilities usable by the kernel and application code.
*/
#ifndef ZEPHYR_INCLUDE_SYS_UTIL_H_
#define ZEPHYR_INCLUDE_SYS_UTIL_H_
#include <sys/util_macro.h>
/* needs to be outside _ASMLANGUAGE so 'true' and 'false' can turn
* into '1' and '0' for asm or linker scripts
*/
#include <stdbool.h>
#ifndef _ASMLANGUAGE
#include <zephyr/types.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup sys-util Utility Functions
* @{
*/
/** @brief Cast @p x, a pointer, to an unsigned integer. */
#define POINTER_TO_UINT(x) ((uintptr_t) (x))
/** @brief Cast @p x, an unsigned integer, to a <tt>void*</tt>. */
#define UINT_TO_POINTER(x) ((void *) (uintptr_t) (x))
/** @brief Cast @p x, a pointer, to a signed integer. */
#define POINTER_TO_INT(x) ((intptr_t) (x))
/** @brief Cast @p x, a signed integer, to a <tt>void*</tt>. */
#define INT_TO_POINTER(x) ((void *) (intptr_t) (x))
#if !(defined(__CHAR_BIT__) && defined(__SIZEOF_LONG__))
# error Missing required predefined macros for BITS_PER_LONG calculation
#endif
/** Number of bits in a long int. */
#define BITS_PER_LONG (__CHAR_BIT__ * __SIZEOF_LONG__)
/**
* @brief Create a contiguous bitmask starting at bit position @p l
* and ending at position @p h.
*/
#define GENMASK(h, l) \
(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
/** @brief Extract the Least Significant Bit from @p value. */
#define LSB_GET(value) ((value) & -(value))
/**
* @brief Extract a bitfield element from @p value corresponding to
* the field mask @p mask.
*/
#define FIELD_GET(mask, value) (((value) & (mask)) / LSB_GET(mask))
/**
* @brief Prepare a bitfield element using @p value with @p mask representing
* its field position and width. The result should be combined
* with other fields using a logical OR.
*/
#define FIELD_PREP(mask, value) (((value) * LSB_GET(mask)) & (mask))
/** @brief 0 if @p cond is true-ish; causes a compile error otherwise. */
#define ZERO_OR_COMPILE_ERROR(cond) ((int) sizeof(char[1 - 2 * !(cond)]) - 1)
#if defined(__cplusplus)
/* The built-in function used below for type checking in C is not
* supported by GNU C++.
*/
#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
#else /* __cplusplus */
/**
* @brief Zero if @p array has an array type, a compile error otherwise
*
* This macro is available only from C, not C++.
*/
#define IS_ARRAY(array) \
ZERO_OR_COMPILE_ERROR( \
!__builtin_types_compatible_p(__typeof__(array), \
__typeof__(&(array)[0])))
/**
* @brief Number of elements in the given @p array
*
* In C++, due to language limitations, this will accept as @p array
* any type that implements <tt>operator[]</tt>. The results may not be
* particulary meaningful in this case.
*
* In C, passing a pointer as @p array causes a compile error.
*/
#define ARRAY_SIZE(array) \
((long) (IS_ARRAY(array) + (sizeof(array) / sizeof((array)[0]))))
#endif /* __cplusplus */
/**
* @brief Check if a pointer @p ptr lies within @p array.
*
* In C but not C++, this causes a compile error if @p array is not an array
* (e.g. if @p ptr and @p array are mixed up).
*
* @param ptr a pointer
* @param array an array
* @return 1 if @p ptr is part of @p array, 0 otherwise
*/
#define PART_OF_ARRAY(array, ptr) \
((ptr) && ((ptr) >= &array[0] && (ptr) < &array[ARRAY_SIZE(array)]))
/**
* @brief Get a pointer to a structure containing the element
*
* Example:
*
* struct foo {
* int bar;
* };
*
* struct foo my_foo;
* int *ptr = &my_foo.bar;
*
* struct foo *container = CONTAINER_OF(ptr, struct foo, bar);
*
* Above, @p container points at @p my_foo.
*
* @param ptr pointer to a structure element
* @param type name of the type that @p ptr is an element of
* @param field the name of the field within the struct @p ptr points to
* @return a pointer to the structure that contains @p ptr
*/
#define CONTAINER_OF(ptr, type, field) \
((type *)(((char *)(ptr)) - offsetof(type, field)))
/**
* @brief Value of @p x rounded up to the next multiple of @p align,
* which must be a power of 2.
*/
#define ROUND_UP(x, align) \
(((unsigned long)(x) + ((unsigned long)(align) - 1)) & \
~((unsigned long)(align) - 1))
/**
* @brief Value of @p x rounded down to the previous multiple of @p
* align, which must be a power of 2.
*/
#define ROUND_DOWN(x, align) \
((unsigned long)(x) & ~((unsigned long)(align) - 1))
/** @brief Value of @p x rounded up to the next word boundary. */
#define WB_UP(x) ROUND_UP(x, sizeof(void *))
/** @brief Value of @p x rounded down to the previous word boundary. */
#define WB_DN(x) ROUND_DOWN(x, sizeof(void *))
/**
* @brief Ceiling function applied to @p numerator / @p divider as a fraction.
*/
#define ceiling_fraction(numerator, divider) \
(((numerator) + ((divider) - 1)) / (divider))
/**
* @def MAX
* @brief The larger value between @p a and @p b.
* @note Arguments are evaluated twice.
*/
#ifndef MAX
/* Use Z_MAX for a GCC-only, single evaluation version */
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
/**
* @def MIN
* @brief The smaller value between @p a and @p b.
* @note Arguments are evaluated twice.
*/
#ifndef MIN
/* Use Z_MIN for a GCC-only, single evaluation version */
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
/**
* @def CLAMP
* @brief Clamp a value to a given range.
* @note Arguments are evaluated multiple times.
*/
#ifndef CLAMP
/* Use Z_CLAMP for a GCC-only, single evaluation version */
#define CLAMP(val, low, high) (((val) <= (low)) ? (low) : MIN(val, high))
#endif
/**
* @brief Is @p x a power of two?
* @param x value to check
* @return true if @p x is a power of two, false otherwise
*/
static inline bool is_power_of_two(unsigned int x)
{
return (x != 0U) && ((x & (x - 1U)) == 0U);
}
/**
* @brief Arithmetic shift right
* @param value value to shift
* @param shift number of bits to shift
* @return @p value shifted right by @p shift; opened bit positions are
* filled with the sign bit
*/
static inline int64_t arithmetic_shift_right(int64_t value, uint8_t shift)
{
int64_t sign_ext;
if (shift == 0U) {
return value;
}
/* extract sign bit */
sign_ext = (value >> 63) & 1;
/* make all bits of sign_ext be the same as the value's sign bit */
sign_ext = -sign_ext;
/* shift value and fill opened bit positions with sign bit */
return (value >> shift) | (sign_ext << (64 - shift));
}
/**
* @brief byte by byte memcpy.
*
* Copy `size` bytes of `src` into `dest`. This is guaranteed to be done byte by byte.
*
* @param dst Pointer to the destination memory.
* @param src Pointer to the source of the data.
* @param size The number of bytes to copy.
*/
static inline void bytecpy(void *dst, const void *src, size_t size)
{
size_t i;
for (i = 0; i < size; ++i) {
((volatile uint8_t *)dst)[i] = ((volatile const uint8_t *)src)[i];
}
}
/**
* @brief byte by byte swap.
*
* Swap @a size bytes between memory regions @a a and @a b. This is
* guaranteed to be done byte by byte.
*
* @param a Pointer to the the first memory region.
* @param b Pointer to the the second memory region.
* @param size The number of bytes to swap.
*/
static inline void byteswp(void *a, void *b, size_t size)
{
uint8_t t;
uint8_t *aa = (uint8_t *)a;
uint8_t *bb = (uint8_t *)b;
for (; size > 0; --size) {
t = *aa;
*aa++ = *bb;
*bb++ = t;
}
}
/**
* @brief Convert a single character into a hexadecimal nibble.
*
* @param c The character to convert
* @param x The address of storage for the converted number.
*
* @return Zero on success or (negative) error code otherwise.
*/
int char2hex(char c, uint8_t *x);
/**
* @brief Convert a single hexadecimal nibble into a character.
*
* @param c The number to convert
* @param x The address of storage for the converted character.
*
* @return Zero on success or (negative) error code otherwise.
*/
int hex2char(uint8_t x, char *c);
/**
* @brief Convert a binary array into string representation.
*
* @param buf The binary array to convert
* @param buflen The length of the binary array to convert
* @param hex Address of where to store the string representation.
* @param hexlen Size of the storage area for string representation.
*
* @return The length of the converted string, or 0 if an error occurred.
*/
size_t bin2hex(const uint8_t *buf, size_t buflen, char *hex, size_t hexlen);
/**
* @brief Convert a hexadecimal string into a binary array.
*
* @param hex The hexadecimal string to convert
* @param hexlen The length of the hexadecimal string to convert.
* @param buf Address of where to store the binary data
* @param buflen Size of the storage area for binary data
*
* @return The length of the binary array, or 0 if an error occurred.
*/
size_t hex2bin(const char *hex, size_t hexlen, uint8_t *buf, size_t buflen);
/**
* @brief Convert a binary coded decimal (BCD 8421) value to binary.
*
* @param bcd BCD 8421 value to convert.
*
* @return Binary representation of input value.
*/
static inline uint8_t bcd2bin(uint8_t bcd)
{
return ((10 * (bcd >> 4)) + (bcd & 0x0F));
}
/**
* @brief Convert a binary value to binary coded decimal (BCD 8421).
*
* @param bin Binary value to convert.
*
* @return BCD 8421 representation of input value.
*/
static inline uint8_t bin2bcd(uint8_t bin)
{
return (((bin / 10) << 4) | (bin % 10));
}
/**
* @brief Convert a uint8_t into a decimal string representation.
*
* Convert a uint8_t value into its ASCII decimal string representation.
* The string is terminated if there is enough space in buf.
*
* @param buf Address of where to store the string representation.
* @param buflen Size of the storage area for string representation.
* @param value The value to convert to decimal string
*
* @return The length of the converted string (excluding terminator if
* any), or 0 if an error occurred.
*/
uint8_t u8_to_dec(char *buf, uint8_t buflen, uint8_t value);
/**
* @brief Properly truncate a NULL-terminated UTF-8 string
*
* Take a NULL-terminated UTF-8 string and ensure that if the string has been
* truncated (by setting the NULL terminator) earlier by other means, that
* the string ends with a properly formatted UTF-8 character (1-4 bytes).
*
* @htmlonly
* Example:
* char test_str[] = "€€€";
* char trunc_utf8[8];
*
* printf("Original : %s\n", test_str); // €€€
* strncpy(trunc_utf8, test_str, sizeof(trunc_utf8));
* trunc_utf8[sizeof(trunc_utf8) - 1] = '\0';
* printf("Bad : %s\n", trunc_utf8); // €€�
* utf8_trunc(trunc_utf8);
* printf("Truncated: %s\n", trunc_utf8); // €€
* @endhtmlonly
*
* @param utf8_str NULL-terminated string
*
* @return Pointer to the @p utf8_str
*/
char *utf8_trunc(char *utf8_str);
/**
* @brief Copies a UTF-8 encoded string from @p src to @p dst
*
* The resulting @p dst will always be NULL terminated, and the @p dst string
* will always be properly UTF-8 truncated.
*
* @param dst The destination of the UTF-8 string.
* @param src The source string
* @param n The size of the @p dst buffer. Shall not be 0.
*
* return Pointer to the @p dst
*/
char *utf8_lcpy(char *dst, const char *src, size_t n);
#ifdef __cplusplus
}
#endif
#endif /* !_ASMLANGUAGE */
/** @brief Number of bytes in @p x kibibytes */
#ifdef _LINKER
/* This is used in linker scripts so need to avoid type casting there */
#define KB(x) ((x) << 10)
#else
#define KB(x) (((size_t)x) << 10)
#endif
/** @brief Number of bytes in @p x mebibytes */
#define MB(x) (KB(x) << 10)
/** @brief Number of bytes in @p x gibibytes */
#define GB(x) (MB(x) << 10)
/** @brief Number of Hz in @p x kHz */
#define KHZ(x) ((x) * 1000)
/** @brief Number of Hz in @p x MHz */
#define MHZ(x) (KHZ(x) * 1000)
/**
* @}
*/
#endif /* ZEPHYR_INCLUDE_SYS_UTIL_H_ */
@@ -0,0 +1,146 @@
/*
* Copyright (c) 2011-2014, Wind River Systems, Inc.
* Copyright (c) 2020, Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Misc utilities
*
* Repetitive or obscure helper macros needed by sys/util.h.
*/
#ifndef ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_H_
#define ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_H_
#include "util_loops.h"
/* IS_ENABLED() helpers */
/* This is called from IS_ENABLED(), and sticks on a "_XXXX" prefix,
* it will now be "_XXXX1" if config_macro is "1", or just "_XXXX" if it's
* undefined.
* ENABLED: Z_IS_ENABLED2(_XXXX1)
* DISABLED Z_IS_ENABLED2(_XXXX)
*/
#define Z_IS_ENABLED1(config_macro) Z_IS_ENABLED2(_XXXX##config_macro)
/* Here's the core trick, we map "_XXXX1" to "_YYYY," (i.e. a string
* with a trailing comma), so it has the effect of making this a
* two-argument tuple to the preprocessor only in the case where the
* value is defined to "1"
* ENABLED: _YYYY, <--- note comma!
* DISABLED: _XXXX
*/
#define _XXXX1 _YYYY,
/* Then we append an extra argument to fool the gcc preprocessor into
* accepting it as a varargs macro.
* arg1 arg2 arg3
* ENABLED: Z_IS_ENABLED3(_YYYY, 1, 0)
* DISABLED Z_IS_ENABLED3(_XXXX 1, 0)
*/
#define Z_IS_ENABLED2(one_or_two_args) Z_IS_ENABLED3(one_or_two_args 1, 0)
/* And our second argument is thus now cooked to be 1 in the case
* where the value is defined to 1, and 0 if not:
*/
#define Z_IS_ENABLED3(ignore_this, val, ...) val
/* Used internally by COND_CODE_1 and COND_CODE_0. */
#define Z_COND_CODE_1(_flag, _if_1_code, _else_code) \
__COND_CODE(_XXXX##_flag, _if_1_code, _else_code)
#define Z_COND_CODE_0(_flag, _if_0_code, _else_code) \
__COND_CODE(_ZZZZ##_flag, _if_0_code, _else_code)
#define _ZZZZ0 _YYYY,
#define __COND_CODE(one_or_two_args, _if_code, _else_code) \
__GET_ARG2_DEBRACKET(one_or_two_args _if_code, _else_code)
/* Gets second argument and removes brackets around that argument. It
* is expected that the parameter is provided in brackets/parentheses.
*/
#define __GET_ARG2_DEBRACKET(ignore_this, val, ...) __DEBRACKET val
/* Used to remove brackets from around a single argument. */
#define __DEBRACKET(...) __VA_ARGS__
/* Used by IS_EMPTY() */
/* reference: https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ */
#define Z_HAS_COMMA(...) \
NUM_VA_ARGS_LESS_1_IMPL(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
#define Z_TRIGGER_PARENTHESIS_(...) ,
#define Z_IS_EMPTY_(...) \
Z_IS_EMPTY__( \
Z_HAS_COMMA(__VA_ARGS__), \
Z_HAS_COMMA(Z_TRIGGER_PARENTHESIS_ __VA_ARGS__), \
Z_HAS_COMMA(__VA_ARGS__ (/*empty*/)), \
Z_HAS_COMMA(Z_TRIGGER_PARENTHESIS_ __VA_ARGS__ (/*empty*/)))
#define Z_CAT5(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4
#define Z_IS_EMPTY__(_0, _1, _2, _3) \
Z_HAS_COMMA(Z_CAT5(Z_IS_EMPTY_CASE_, _0, _1, _2, _3))
#define Z_IS_EMPTY_CASE_0001 ,
/* Used by LIST_DROP_EMPTY() */
/* Adding ',' after each element would add empty element at the end of
* list, which is hard to remove, so instead precede each element with ',',
* this way first element is empty, and this one is easy to drop.
*/
#define Z_LIST_ADD_ELEM(e) EMPTY, e
#define Z_LIST_DROP_FIRST(...) GET_ARGS_LESS_N(1, __VA_ARGS__)
#define Z_LIST_NO_EMPTIES(e) \
COND_CODE_1(IS_EMPTY(e), (), (Z_LIST_ADD_ELEM(e)))
#define UTIL_CAT(a, ...) UTIL_PRIMITIVE_CAT(a, __VA_ARGS__)
#define UTIL_PRIMITIVE_CAT(a, ...) a##__VA_ARGS__
#define UTIL_CHECK_N(x, n, ...) n
#define UTIL_CHECK(...) UTIL_CHECK_N(__VA_ARGS__, 0,)
#define UTIL_NOT(x) UTIL_CHECK(UTIL_PRIMITIVE_CAT(UTIL_NOT_, x))
#define UTIL_NOT_0 ~, 1,
#define UTIL_COMPL(b) UTIL_PRIMITIVE_CAT(UTIL_COMPL_, b)
#define UTIL_COMPL_0 1
#define UTIL_COMPL_1 0
#define UTIL_BOOL(x) UTIL_COMPL(UTIL_NOT(x))
#define UTIL_EVAL(...) __VA_ARGS__
#define UTIL_EXPAND(...) __VA_ARGS__
#define UTIL_REPEAT(...) UTIL_LISTIFY(__VA_ARGS__)
/* Implementation details for NUM_VA_ARGS_LESS_1 */
#define NUM_VA_ARGS_LESS_1_IMPL( \
_ignored, \
_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
_11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
_21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
_31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
_41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
_51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \
_61, _62, N, ...) N
/* Used by MACRO_MAP_CAT */
#define MACRO_MAP_CAT_(...) \
/* To make sure it works also for 2 arguments in total */ \
MACRO_MAP_CAT_N(NUM_VA_ARGS_LESS_1(__VA_ARGS__), __VA_ARGS__)
#define MACRO_MAP_CAT_N_(N, ...) UTIL_CAT(MACRO_MC_, N)(__VA_ARGS__,)
#define MACRO_MC_0(...)
#define MACRO_MC_1(m, a, ...) m(a)
#define MACRO_MC_2(m, a, ...) UTIL_CAT(m(a), MACRO_MC_1(m, __VA_ARGS__,))
#define MACRO_MC_3(m, a, ...) UTIL_CAT(m(a), MACRO_MC_2(m, __VA_ARGS__,))
#define MACRO_MC_4(m, a, ...) UTIL_CAT(m(a), MACRO_MC_3(m, __VA_ARGS__,))
#define MACRO_MC_5(m, a, ...) UTIL_CAT(m(a), MACRO_MC_4(m, __VA_ARGS__,))
#define MACRO_MC_6(m, a, ...) UTIL_CAT(m(a), MACRO_MC_5(m, __VA_ARGS__,))
#define MACRO_MC_7(m, a, ...) UTIL_CAT(m(a), MACRO_MC_6(m, __VA_ARGS__,))
#define MACRO_MC_8(m, a, ...) UTIL_CAT(m(a), MACRO_MC_7(m, __VA_ARGS__,))
#define MACRO_MC_9(m, a, ...) UTIL_CAT(m(a), MACRO_MC_8(m, __VA_ARGS__,))
#define MACRO_MC_10(m, a, ...) UTIL_CAT(m(a), MACRO_MC_9(m, __VA_ARGS__,))
#define MACRO_MC_11(m, a, ...) UTIL_CAT(m(a), MACRO_MC_10(m, __VA_ARGS__,))
#define MACRO_MC_12(m, a, ...) UTIL_CAT(m(a), MACRO_MC_11(m, __VA_ARGS__,))
#define MACRO_MC_13(m, a, ...) UTIL_CAT(m(a), MACRO_MC_12(m, __VA_ARGS__,))
#define MACRO_MC_14(m, a, ...) UTIL_CAT(m(a), MACRO_MC_13(m, __VA_ARGS__,))
#define MACRO_MC_15(m, a, ...) UTIL_CAT(m(a), MACRO_MC_14(m, __VA_ARGS__,))
#endif /* ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_H_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,601 @@
/*
* Copyright (c) 2011-2014, Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Macro utilities
*
* Macro utilities are the public interface for C/C++ code and device tree
* related implementation. In general, C/C++ will include <sys/util.h>
* instead this file directly. For device tree implementation, this file
* should be include instead <sys/util_internal.h>
*/
#ifndef ZEPHYR_INCLUDE_SYS_UTIL_MACROS_H_
#define ZEPHYR_INCLUDE_SYS_UTIL_MACROS_H_
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup sys-util
* @{
*/
/*
* Most of the eldritch implementation details for all the macrobatics
* below (APIs like IS_ENABLED(), COND_CODE_1(), etc.) are hidden away
* in this file.
*/
#include <sys/util_internal.h>
#ifndef BIT
#if defined(_ASMLANGUAGE)
#define BIT(n) (1 << (n))
#else
/**
* @brief Unsigned integer with bit position @p n set (signed in
* assembly language).
*/
#define BIT(n) (1UL << (n))
#endif
#endif
/** @brief 64-bit unsigned integer with bit position @p _n set. */
#define BIT64(_n) (1ULL << (_n))
/**
* @brief Set or clear a bit depending on a boolean value
*
* The argument @p var is a variable whose value is written to as a
* side effect.
*
* @param var Variable to be altered
* @param bit Bit number
* @param set if 0, clears @p bit in @p var; any other value sets @p bit
*/
#define WRITE_BIT(var, bit, set) \
((var) = (set) ? ((var) | BIT(bit)) : ((var) & ~BIT(bit)))
/**
* @brief Bit mask with bits 0 through <tt>n-1</tt> (inclusive) set,
* or 0 if @p n is 0.
*/
#define BIT_MASK(n) (BIT(n) - 1UL)
/**
* @brief 64-bit bit mask with bits 0 through <tt>n-1</tt> (inclusive) set,
* or 0 if @p n is 0.
*/
#define BIT64_MASK(n) (BIT64(n) - 1ULL)
/**
* @brief Check for macro definition in compiler-visible expressions
*
* This trick was pioneered in Linux as the config_enabled() macro. It
* has the effect of taking a macro value that may be defined to "1"
* or may not be defined at all and turning it into a literal
* expression that can be handled by the C compiler instead of just
* the preprocessor. It is often used with a @p CONFIG_FOO macro which
* may be defined to 1 via Kconfig, or left undefined.
*
* That is, it works similarly to <tt>\#if defined(CONFIG_FOO)</tt>
* except that its expansion is a C expression. Thus, much <tt>\#ifdef</tt>
* usage can be replaced with equivalents like:
*
* if (IS_ENABLED(CONFIG_FOO)) {
* do_something_with_foo
* }
*
* This is cleaner since the compiler can generate errors and warnings
* for @p do_something_with_foo even when @p CONFIG_FOO is undefined.
*
* @param config_macro Macro to check
* @return 1 if @p config_macro is defined to 1, 0 otherwise (including
* if @p config_macro is not defined)
*/
#define IS_ENABLED(config_macro) Z_IS_ENABLED1(config_macro)
/* INTERNAL: the first pass above is just to expand any existing
* macros, we need the macro value to be e.g. a literal "1" at
* expansion time in the next macro, not "(1)", etc... Standard
* recursive expansion does not work.
*/
/**
* @brief Insert code depending on whether @p _flag expands to 1 or not.
*
* This relies on similar tricks as IS_ENABLED(), but as the result of
* @p _flag expansion, results in either @p _if_1_code or @p
* _else_code is expanded.
*
* To prevent the preprocessor from treating commas as argument
* separators, the @p _if_1_code and @p _else_code expressions must be
* inside brackets/parentheses: <tt>()</tt>. These are stripped away
* during macro expansion.
*
* Example:
*
* COND_CODE_1(CONFIG_FLAG, (uint32_t x;), (there_is_no_flag();))
*
* If @p CONFIG_FLAG is defined to 1, this expands to:
*
* uint32_t x;
*
* It expands to <tt>there_is_no_flag();</tt> otherwise.
*
* This could be used as an alternative to:
*
* #if defined(CONFIG_FLAG) && (CONFIG_FLAG == 1)
* #define MAYBE_DECLARE(x) uint32_t x
* #else
* #define MAYBE_DECLARE(x) there_is_no_flag()
* #endif
*
* MAYBE_DECLARE(x);
*
* However, the advantage of COND_CODE_1() is that code is resolved in
* place where it is used, while the @p \#if method defines @p
* MAYBE_DECLARE on two lines and requires it to be invoked again on a
* separate line. This makes COND_CODE_1() more concise and also
* sometimes more useful when used within another macro's expansion.
*
* @note @p _flag can be the result of preprocessor expansion, e.g.
* an expression involving <tt>NUM_VA_ARGS_LESS_1(...)</tt>.
* However, @p _if_1_code is only expanded if @p _flag expands
* to the integer literal 1. Integer expressions that evaluate
* to 1, e.g. after doing some arithmetic, will not work.
*
* @param _flag evaluated flag
* @param _if_1_code result if @p _flag expands to 1; must be in parentheses
* @param _else_code result otherwise; must be in parentheses
*/
#define COND_CODE_1(_flag, _if_1_code, _else_code) \
Z_COND_CODE_1(_flag, _if_1_code, _else_code)
/**
* @brief Like COND_CODE_1() except tests if @p _flag is 0.
*
* This is like COND_CODE_1(), except that it tests whether @p _flag
* expands to the integer literal 0. It expands to @p _if_0_code if
* so, and @p _else_code otherwise; both of these must be enclosed in
* parentheses.
*
* @param _flag evaluated flag
* @param _if_0_code result if @p _flag expands to 0; must be in parentheses
* @param _else_code result otherwise; must be in parentheses
* @see COND_CODE_1()
*/
#define COND_CODE_0(_flag, _if_0_code, _else_code) \
Z_COND_CODE_0(_flag, _if_0_code, _else_code)
/**
* @brief Insert code if @p _flag is defined and equals 1.
*
* Like COND_CODE_1(), this expands to @p _code if @p _flag is defined to 1;
* it expands to nothing otherwise.
*
* Example:
*
* IF_ENABLED(CONFIG_FLAG, (uint32_t foo;))
*
* If @p CONFIG_FLAG is defined to 1, this expands to:
*
* uint32_t foo;
*
* and to nothing otherwise.
*
* It can be considered as a more compact alternative to:
*
* #if defined(CONFIG_FLAG) && (CONFIG_FLAG == 1)
* uint32_t foo;
* #endif
*
* @param _flag evaluated flag
* @param _code result if @p _flag expands to 1; must be in parentheses
*/
#define IF_ENABLED(_flag, _code) \
COND_CODE_1(_flag, _code, ())
/**
* @brief Check if a macro has a replacement expression
*
* If @p a is a macro defined to a nonempty value, this will return
* true, otherwise it will return false. It only works with defined
* macros, so an additional @p \#ifdef test may be needed in some cases.
*
* This macro may be used with COND_CODE_1() and COND_CODE_0() while
* processing <tt>__VA_ARGS__</tt> to avoid processing empty arguments.
*
* Example:
*
* #define EMPTY
* #define NON_EMPTY 1
* #undef UNDEFINED
* IS_EMPTY(EMPTY)
* IS_EMPTY(NON_EMPTY)
* IS_EMPTY(UNDEFINED)
* #if defined(EMPTY) && IS_EMPTY(EMPTY) == true
* some_conditional_code
* #endif
*
* In above examples, the invocations of IS_EMPTY(...) return @p true,
* @p false, and @p true; @p some_conditional_code is included.
*
* @param ... macro to check for emptiness (may be <tt>__VA_ARGS__</tt>)
*/
#define IS_EMPTY(...) Z_IS_EMPTY_(__VA_ARGS__)
/**
* @brief Remove empty arguments from list.
*
* During macro expansion, <tt>__VA_ARGS__</tt> and other preprocessor
* generated lists may contain empty elements, e.g.:
*
* #define LIST ,a,b,,d,
*
* Using EMPTY to show each empty element, LIST contains:
*
* EMPTY, a, b, EMPTY, d
*
* When processing such lists, e.g. using FOR_EACH(), all empty elements
* will be processed, and may require filtering out.
* To make that process easier, it is enough to invoke LIST_DROP_EMPTY
* which will remove all empty elements.
*
* Example:
*
* LIST_DROP_EMPTY(LIST)
*
* expands to:
*
* a, b, d
*
* @param ... list to be processed
*/
#define LIST_DROP_EMPTY(...) \
Z_LIST_DROP_FIRST(FOR_EACH(Z_LIST_NO_EMPTIES, (), __VA_ARGS__))
/**
* @brief Macro with an empty expansion
*
* This trivial definition is provided for readability when a macro
* should expand to an empty result, which e.g. is sometimes needed to
* silence checkpatch.
*
* Example:
*
* #define LIST_ITEM(n) , item##n
*
* The above would cause checkpatch to complain, but:
*
* #define LIST_ITEM(n) EMPTY, item##n
*
* would not.
*/
#define EMPTY
/**
* @brief Macro that expands to its argument
*
* This is useful in macros like @c FOR_EACH() when there is no
* transformation required on the list elements.
*
* @param V any value
*/
#define IDENTITY(V) V
/**
* @brief Get nth argument from argument list.
*
* @param N Argument index to fetch. Counter from 1.
* @param ... Variable list of argments from which one argument is returned.
*
* @return Nth argument.
*/
#define GET_ARG_N(N, ...) Z_GET_ARG_##N(__VA_ARGS__)
/**
* @brief Strips n first arguments from the argument list.
*
* @param N Number of arguments to discard.
* @param ... Variable list of argments.
*
* @return argument list without N first arguments.
*/
#define GET_ARGS_LESS_N(N, ...) Z_GET_ARGS_LESS_##N(__VA_ARGS__)
/**
* @brief Like <tt>a || b</tt>, but does evaluation and
* short-circuiting at C preprocessor time.
*
* This is not the same as the binary @p || operator; in particular,
* @p a should expand to an integer literal 0 or 1. However, @p b
* can be any value.
*
* This can be useful when @p b is an expression that would cause a
* build error when @p a is 1.
*/
#define UTIL_OR(a, b) COND_CODE_1(UTIL_BOOL(a), (a), (b))
/**
* @brief Like <tt>a && b</tt>, but does evaluation and
* short-circuiting at C preprocessor time.
*
* This is not the same as the binary @p &&, however; in particular,
* @p a should expand to an integer literal 0 or 1. However, @p b
* can be any value.
*
* This can be useful when @p b is an expression that would cause a
* build error when @p a is 0.
*/
#define UTIL_AND(a, b) COND_CODE_1(UTIL_BOOL(a), (b), (0))
/**
* @brief Generates a sequence of code.
*
* Example:
*
* #define FOO(i, _) MY_PWM ## i ,
* { UTIL_LISTIFY(PWM_COUNT, FOO) }
*
* The above two lines expand to:
*
* { MY_PWM0 , MY_PWM1 , }
*
* @param LEN The length of the sequence. Must be an integer literal less
* than 255.
* @param F A macro function that accepts at least two arguments:
* <tt>F(i, ...)</tt>. @p F is called repeatedly in the expansion.
* Its first argument @p i is the index in the sequence, and
* the variable list of arguments passed to UTIL_LISTIFY are passed
* through to @p F.
*
* @note Calling UTIL_LISTIFY with undefined arguments has undefined
* behavior.
*/
#define UTIL_LISTIFY(LEN, F, ...) UTIL_CAT(Z_UTIL_LISTIFY_, LEN)(F, __VA_ARGS__)
/**
* @brief Call a macro @p F on each provided argument with a given
* separator between each call.
*
* Example:
*
* #define F(x) int a##x
* FOR_EACH(F, (;), 4, 5, 6);
*
* This expands to:
*
* int a4;
* int a5;
* int a6;
*
* @param F Macro to invoke
* @param sep Separator (e.g. comma or semicolon). Must be in parentheses;
* this is required to enable providing a comma as separator.
* @param ... Variable argument list. The macro @p F is invoked as
* <tt>F(element)</tt> for each element in the list.
*/
#define FOR_EACH(F, sep, ...) \
Z_FOR_EACH(F, sep, REVERSE_ARGS(__VA_ARGS__))
/**
* @brief Like FOR_EACH(), but with a terminator instead of a separator,
* and drops empty elements from the argument list
*
* The @p sep argument to <tt>FOR_EACH(F, (sep), a, b)</tt> is a
* separator which is placed between calls to @p F, like this:
*
* FOR_EACH(F, (sep), a, b) // F(a) sep F(b)
* // ^^^ no sep here!
*
* By contrast, the @p term argument to <tt>FOR_EACH_NONEMPTY_TERM(F, (term),
* a, b)</tt> is added after each time @p F appears in the expansion:
*
* FOR_EACH_NONEMPTY_TERM(F, (term), a, b) // F(a) term F(b) term
* // ^^^^
*
* Further, any empty elements are dropped:
*
* FOR_EACH_NONEMPTY_TERM(F, (term), a, EMPTY, b) // F(a) term F(b) term
*
* This is more convenient in some cases, because FOR_EACH_NONEMPTY_TERM()
* expands to nothing when given an empty argument list, and it's
* often cumbersome to write a macro @p F that does the right thing
* even when given an empty argument.
*
* One example is when <tt>__VA_ARGS__</tt> may or may not be empty,
* and the results are embedded in a larger initializer:
*
* #define SQUARE(x) ((x)*(x))
*
* int my_array[] = {
* FOR_EACH_NONEMPTY_TERM(SQUARE, (,), FOO(...))
* FOR_EACH_NONEMPTY_TERM(SQUARE, (,), BAR(...))
* FOR_EACH_NONEMPTY_TERM(SQUARE, (,), BAZ(...))
* };
*
* This is more convenient than:
*
* 1. figuring out whether the @p FOO, @p BAR, and @p BAZ expansions
* are empty and adding a comma manually (or not) between FOR_EACH()
* calls
* 2. rewriting SQUARE so it reacts appropriately when "x" is empty
* (which would be necessary if e.g. @p FOO expands to nothing)
*
* @param F Macro to invoke on each nonempty element of the variable
* arguments
* @param term Terminator (e.g. comma or semicolon) placed after each
* invocation of F. Must be in parentheses; this is required
* to enable providing a comma as separator.
* @param ... Variable argument list. The macro @p F is invoked as
* <tt>F(element)</tt> for each nonempty element in the list.
*/
#define FOR_EACH_NONEMPTY_TERM(F, term, ...) \
COND_CODE_0( \
/* are there zero non-empty arguments ? */ \
NUM_VA_ARGS_LESS_1(LIST_DROP_EMPTY(__VA_ARGS__, _)), \
/* if so, expand to nothing */ \
(), \
/* otherwise, expand to: */ \
(/* FOR_EACH() on nonempty elements, */ \
FOR_EACH(F, term, LIST_DROP_EMPTY(__VA_ARGS__)) \
/* plus a final terminator */ \
__DEBRACKET term \
))
/**
* @brief Call macro @p F on each provided argument, with the argument's index
* as an additional parameter.
*
* This is like FOR_EACH(), except @p F should be a macro which takes two
* arguments: <tt>F(index, variable_arg)</tt>.
*
* Example:
*
* #define F(idx, x) int a##idx = x
* FOR_EACH_IDX(F, (;), 4, 5, 6);
*
* This expands to:
*
* int a0 = 4;
* int a1 = 5;
* int a2 = 6;
*
* @param F Macro to invoke
* @param sep Separator (e.g. comma or semicolon). Must be in parentheses;
* this is required to enable providing a comma as separator.
* @param ... Variable argument list. The macro @p F is invoked as
* <tt>F(index, element)</tt> for each element in the list.
*/
#define FOR_EACH_IDX(F, sep, ...) \
Z_FOR_EACH_IDX(F, sep, REVERSE_ARGS(__VA_ARGS__))
/**
* @brief Call macro @p F on each provided argument, with an additional fixed
* argument as a parameter.
*
* This is like FOR_EACH(), except @p F should be a macro which takes two
* arguments: <tt>F(variable_arg, fixed_arg)</tt>.
*
* Example:
*
* static void func(int val, void *dev);
* FOR_EACH_FIXED_ARG(func, (;), dev, 4, 5, 6);
*
* This expands to:
*
* func(4, dev);
* func(5, dev);
* func(6, dev);
*
* @param F Macro to invoke
* @param sep Separator (e.g. comma or semicolon). Must be in parentheses;
* this is required to enable providing a comma as separator.
* @param fixed_arg Fixed argument passed to @p F as the second macro parameter.
* @param ... Variable argument list. The macro @p F is invoked as
* <tt>F(element, fixed_arg)</tt> for each element in the list.
*/
#define FOR_EACH_FIXED_ARG(F, sep, fixed_arg, ...) \
Z_FOR_EACH_FIXED_ARG(F, sep, fixed_arg, REVERSE_ARGS(__VA_ARGS__))
/**
* @brief Calls macro @p F for each variable argument with an index and fixed
* argument
*
* This is like the combination of FOR_EACH_IDX() with FOR_EACH_FIXED_ARG().
*
* Example:
*
* #define F(idx, x, fixed_arg) int fixed_arg##idx = x
* FOR_EACH_IDX_FIXED_ARG(F, (;), a, 4, 5, 6);
*
* This expands to:
*
* int a0 = 4;
* int a1 = 5;
* int a2 = 6;
*
* @param F Macro to invoke
* @param sep Separator (e.g. comma or semicolon). Must be in parentheses;
* This is required to enable providing a comma as separator.
* @param fixed_arg Fixed argument passed to @p F as the third macro parameter.
* @param ... Variable list of arguments. The macro @p F is invoked as
* <tt>F(index, element, fixed_arg)</tt> for each element in
* the list.
*/
#define FOR_EACH_IDX_FIXED_ARG(F, sep, fixed_arg, ...) \
Z_FOR_EACH_IDX_FIXED_ARG(F, sep, fixed_arg, REVERSE_ARGS(__VA_ARGS__))
/** @brief Reverse arguments order.
*
* @param ... Variable argument list.
*/
#define REVERSE_ARGS(...) \
Z_FOR_EACH_ENGINE(Z_FOR_EACH_EXEC, (,), Z_BYPASS, _, __VA_ARGS__)
/**
* @brief Number of arguments in the variable arguments list minus one.
*
* @param ... List of arguments
* @return Number of variadic arguments in the argument list, minus one
*/
#define NUM_VA_ARGS_LESS_1(...) \
NUM_VA_ARGS_LESS_1_IMPL(__VA_ARGS__, 63, 62, 61, \
60, 59, 58, 57, 56, 55, 54, 53, 52, 51, \
50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \
40, 39, 38, 37, 36, 35, 34, 33, 32, 31, \
30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \
20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, ~)
/**
* @brief Mapping macro that pastes results together
*
* This is similar to FOR_EACH() in that it invokes a macro repeatedly
* on each element of <tt>__VA_ARGS__</tt>. However, unlike FOR_EACH(),
* MACRO_MAP_CAT() pastes the results together into a single token.
*
* For example, with this macro FOO:
*
* #define FOO(x) item_##x##_
*
* <tt>MACRO_MAP_CAT(FOO, a, b, c),</tt> expands to the token:
*
* item_a_item_b_item_c_
*
* @param ... Macro to expand on each argument, followed by its
* arguments. (The macro should take exactly one argument.)
* @return The results of expanding the macro on each argument, all pasted
* together
*/
#define MACRO_MAP_CAT(...) MACRO_MAP_CAT_(__VA_ARGS__)
/**
* @brief Mapping macro that pastes a fixed number of results together
*
* Similar to @ref MACRO_MAP_CAT(), but expects a fixed number of
* arguments. If more arguments are given than are expected, the rest
* are ignored.
*
* @param N Number of arguments to map
* @param ... Macro to expand on each argument, followed by its
* arguments. (The macro should take exactly one argument.)
* @return The results of expanding the macro on each argument, all pasted
* together
*/
#define MACRO_MAP_CAT_N(N, ...) MACRO_MAP_CAT_N_(N, __VA_ARGS__)
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_SYS_UTIL_MACROS_H_ */
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2010-2014, Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Macros to abstract toolchain specific capabilities
*
* This file contains various macros to abstract compiler capabilities that
* utilize toolchain specific attributes and/or pragmas.
*/
#ifndef ZEPHYR_INCLUDE_TOOLCHAIN_H_
#define ZEPHYR_INCLUDE_TOOLCHAIN_H_
/**
* @def HAS_BUILTIN(x)
* @brief Check if the compiler supports the built-in function \a x.
*
* This macro is for use with conditional compilation to enable code using a
* builtin function that may not be available in every compiler.
*/
#ifdef __has_builtin
#define HAS_BUILTIN(x) __has_builtin(x)
#else
/*
* The compiler doesn't provide the __has_builtin() macro, so instead we depend
* on the toolchain-specific headers to define HAS_BUILTIN_x for the builtins
* supported.
*/
#define HAS_BUILTIN(x) HAS_BUILTIN_##x
#endif
#if defined(__XCC__)
#include <toolchain/xcc.h>
#elif defined(__CCAC__)
#include <toolchain/mwdt.h>
#elif defined(__llvm__)
#include <toolchain/llvm.h>
#elif defined(__GNUC__) || (defined(_LINKER) && defined(__GCC_LINKER_CMD__))
#include <toolchain/gcc.h>
#else
/* This include line exists for off-tree definitions of compilers,
* and therefore this header is not meant to exist in-tree
*/
#include <toolchain/other.h>
#endif
/*
* Ensure that __BYTE_ORDER__ and related preprocessor definitions are defined,
* as these are often used without checking for definition and doing so can
* cause unexpected behaviours.
*/
#ifndef _LINKER
#if !defined(__BYTE_ORDER__) || !defined(__ORDER_BIG_ENDIAN__) || \
!defined(__ORDER_LITTLE_ENDIAN__)
#error "__BYTE_ORDER__ is not defined"
#endif
#endif /* !_LINKER */
#endif /* ZEPHYR_INCLUDE_TOOLCHAIN_H_ */
@@ -0,0 +1,222 @@
/*
* Copyright (c) 2010-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_TOOLCHAIN_COMMON_H_
#define ZEPHYR_INCLUDE_TOOLCHAIN_COMMON_H_
/**
* @file
* @brief Common toolchain abstraction
*
* Macros to abstract compiler capabilities (common to all toolchains).
*/
/* Abstract use of extern keyword for compatibility between C and C++ */
#ifdef __cplusplus
#define EXTERN_C extern "C"
#else
#define EXTERN_C extern
#endif
/* Use TASK_ENTRY_CPP to tag task entry points defined in C++ files. */
#ifdef __cplusplus
#define TASK_ENTRY_CPP extern "C"
#endif
/*
* Generate a reference to an external symbol.
* The reference indicates to the linker that the symbol is required
* by the module containing the reference and should be included
* in the image if the module is in the image.
*
* The assembler directive ".set" is used to define a local symbol.
* No memory is allocated, and the local symbol does not appear in
* the symbol table.
*/
#ifdef _ASMLANGUAGE
#define REQUIRES(sym) .set sym ## _Requires, sym
#else
#define REQUIRES(sym) __asm__ (".set " # sym "_Requires, " # sym "\n\t");
#endif
#ifdef _ASMLANGUAGE
#define SECTION .section
#endif
/*
* If the project is being built for speed (i.e. not for minimum size) then
* align functions and branches in executable sections to improve performance.
*/
#ifdef _ASMLANGUAGE
#if defined(CONFIG_X86)
#ifdef PERF_OPT
#define PERFOPT_ALIGN .balign 16
#else
#define PERFOPT_ALIGN .balign 1
#endif
#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
#define PERFOPT_ALIGN .balign 4
#elif defined(CONFIG_ARC)
/* .align assembler directive is supposed by all ARC toolchains and it is
* implemented in a same way across ARC toolchains.
*/
#define PERFOPT_ALIGN .align 4
#elif defined(CONFIG_NIOS2) || defined(CONFIG_RISCV) || \
defined(CONFIG_XTENSA)
#define PERFOPT_ALIGN .balign 4
#elif defined(CONFIG_ARCH_POSIX)
#elif defined(CONFIG_SPARC)
#define PERFOPT_ALIGN .align 4
#else
#error Architecture unsupported
#endif
#define GC_SECTION(sym) SECTION .text.##sym, "ax"
#endif /* _ASMLANGUAGE */
/* force inlining a function */
#if !defined(_ASMLANGUAGE)
#ifdef CONFIG_COVERAGE
/*
* The always_inline attribute forces a function to be inlined,
* even ignoring -fno-inline. So for code coverage, do not
* force inlining of these functions to keep their bodies around
* so their number of executions can be counted.
*
* Note that "inline" is kept here for kobject_hash.c and
* priv_stacks_hash.c. These are built without compiler flags
* used for coverage. ALWAYS_INLINE cannot be empty as compiler
* would complain about unused functions. Attaching unused
* attribute would result in their text sections balloon more than
* 10 times in size, as those functions are kept in text section.
* So just keep "inline" here.
*/
#define ALWAYS_INLINE inline
#else
#define ALWAYS_INLINE inline __attribute__((always_inline))
#endif
#endif
#define Z_STRINGIFY(x) #x
#define STRINGIFY(s) Z_STRINGIFY(s)
/* concatenate the values of the arguments into one */
#define _DO_CONCAT(x, y) x ## y
#define _CONCAT(x, y) _DO_CONCAT(x, y)
/* Additionally used as a sentinel by gen_syscalls.py to identify what
* functions are system calls
*
* Note POSIX unit tests don't still generate the system call stubs, so
* until https://github.com/zephyrproject-rtos/zephyr/issues/5006 is
* fixed via possibly #4174, we introduce this hack -- which will
* disallow us to test system calls in POSIX unit testing (currently
* not used).
*/
#ifndef ZTEST_UNITTEST
#define __syscall static inline
#else
#define __syscall
#endif /* ZTEST_UNITTEST */
/* Definitions for struct declaration tags. These are sentinel values used by
* parse_syscalls.py to gather a list of names of struct declarations that
* have these tags applied for them.
*/
/* Indicates this is a driver subsystem */
#define __subsystem
/* Indicates this is a network socket object */
#define __net_socket
#ifndef BUILD_ASSERT
/* Compile-time assertion that makes the build to fail.
* Common implementation swallows the message.
*/
#define BUILD_ASSERT(EXPR, MSG...) \
enum _CONCAT(__build_assert_enum, __COUNTER__) { \
_CONCAT(__build_assert, __COUNTER__) = 1 / !!(EXPR) \
}
#endif
#ifndef BUILD_ASSERT_MSG
#define BUILD_ASSERT_MSG(EXPR, MSG) __DEPRECATED_MACRO BUILD_ASSERT(EXPR, MSG)
#endif
/*
* This is meant to be used in conjunction with __in_section() and similar
* where scattered structure instances are concatenated together by the linker
* and walked by the code at run time just like a contiguous array of such
* structures.
*
* Assemblers and linkers may insert alignment padding by default whose
* size is larger than the natural alignment for those structures when
* gathering various section segments together, messing up the array walk.
* To prevent this, we need to provide an explicit alignment not to rely
* on the default that might just work by luck.
*
* Alignment statements in linker scripts are not sufficient as
* the assembler may add padding by itself to each segment when switching
* between sections within the same file even if it merges many such segments
* into a single section in the end.
*/
#define Z_DECL_ALIGN(type) __aligned(__alignof(type)) type
/*
* Convenience helper combining __in_section() and Z_DECL_ALIGN().
* The section name is the struct type prepended with an underscore.
* The subsection is "static" and the subsubsection is the variable name.
*
* In the linker script, create output sections for these using
* Z_ITERABLE_SECTION_ROM or Z_ITERABLE_SECTION_RAM.
*/
#define Z_STRUCT_SECTION_ITERABLE(struct_type, name) \
Z_DECL_ALIGN(struct struct_type) name \
__in_section(_##struct_type, static, name) __used
/* Special variant of Z_STRUCT_SECTION_ITERABLE, for placing alternate
* data types within the iterable section of a specific data type. The
* data type sizes and semantics must be equivalent!
*/
#define Z_STRUCT_SECTION_ITERABLE_ALTERNATE(out_type, struct_type, name) \
Z_DECL_ALIGN(struct struct_type) name \
__in_section(_##out_type, static, name) __used
/*
* Iterator for structure instances gathered by Z_STRUCT_SECTION_ITERABLE().
* The linker must provide a _<struct_type>_list_start symbol and a
* _<struct_type>_list_end symbol to mark the start and the end of the
* list of struct objects to iterate over.
*/
#define Z_STRUCT_SECTION_FOREACH(struct_type, iterator) \
extern struct struct_type _CONCAT(_##struct_type, _list_start)[]; \
extern struct struct_type _CONCAT(_##struct_type, _list_end)[]; \
for (struct struct_type *iterator = \
_CONCAT(_##struct_type, _list_start); \
({ __ASSERT(iterator <= _CONCAT(_##struct_type, _list_end), \
"unexpected list end location"); \
iterator < _CONCAT(_##struct_type, _list_end); }); \
iterator++)
#endif /* ZEPHYR_INCLUDE_TOOLCHAIN_COMMON_H_ */
@@ -0,0 +1,573 @@
/*
* Copyright (c) 2010-2014,2017 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_TOOLCHAIN_GCC_H_
#define ZEPHYR_INCLUDE_TOOLCHAIN_GCC_H_
/**
* @file
* @brief GCC toolchain abstraction
*
* Macros to abstract compiler capabilities for GCC toolchain.
*/
/*
* Older versions of GCC do not define __BYTE_ORDER__, so it must be manually
* detected and defined using arch-specific definitions.
*/
#ifndef _LINKER
#ifndef __ORDER_BIG_ENDIAN__
#define __ORDER_BIG_ENDIAN__ (1)
#endif
#ifndef __ORDER_LITTLE_ENDIAN__
#define __ORDER_LITTLE_ENDIAN__ (2)
#endif
#ifndef __BYTE_ORDER__
#if defined(__BIG_ENDIAN__) || defined(__ARMEB__) || \
defined(__THUMBEB__) || defined(__AARCH64EB__) || \
defined(__MIPSEB__) || defined(__TC32EB__)
#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
#elif defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || \
defined(__THUMBEL__) || defined(__AARCH64EL__) || \
defined(__MIPSEL__) || defined(__TC32EL__)
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
#else
#error "__BYTE_ORDER__ is not defined and cannot be automatically resolved"
#endif
#endif
/* C++11 has static_assert built in */
#ifdef __cplusplus
#define BUILD_ASSERT(EXPR, MSG...) static_assert(EXPR, "" MSG)
#define BUILD_ASSERT_MSG(EXPR, MSG) __DEPRECATED_MACRO BUILD_ASSERT(EXPR, MSG)
/*
* GCC 4.6 and higher have the C11 _Static_assert built in, and its
* output is easier to understand than the common BUILD_ASSERT macros.
*/
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) || \
(__STDC_VERSION__) >= 201100
#define BUILD_ASSERT(EXPR, MSG...) _Static_assert(EXPR, "" MSG)
#define BUILD_ASSERT_MSG(EXPR, MSG) __DEPRECATED_MACRO BUILD_ASSERT(EXPR, MSG)
#else
#define BUILD_ASSERT(EXPR, MSG...)
#define BUILD_ASSERT_MSG(EXPR, MSG)
#endif
#include <toolchain/common.h>
#include <stdbool.h>
#define ALIAS_OF(of) __attribute__((alias(#of)))
#define FUNC_ALIAS(real_func, new_alias, return_type) \
return_type new_alias() ALIAS_OF(real_func)
#if defined(CONFIG_ARCH_POSIX)
#include <arch/posix/posix_trace.h>
/*let's not segfault if this were to happen for some reason*/
#define CODE_UNREACHABLE \
{\
posix_print_error_and_exit("CODE_UNREACHABLE reached from %s:%d\n",\
__FILE__, __LINE__);\
__builtin_unreachable(); \
}
#else
#define CODE_UNREACHABLE __builtin_unreachable()
#endif
#define FUNC_NORETURN __attribute__((__noreturn__))
/* The GNU assembler for Cortex-M3 uses # for immediate values, not
* comments, so the @nobits# trick does not work.
*/
#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
#define _NODATA_SECTION(segment) __attribute__((section(#segment)))
#else
#define _NODATA_SECTION(segment) \
__attribute__((section(#segment ",\"wa\",@nobits#")))
#endif
/* Unaligned access */
#define UNALIGNED_GET(p) \
__extension__ ({ \
struct __attribute__((__packed__)) { \
__typeof__(*(p)) __v; \
} *__p = (__typeof__(__p)) (p); \
__p->__v; \
})
#if __GNUC__ >= 7 && (defined(CONFIG_ARM) || defined(CONFIG_ARM64))
/* Version of UNALIGNED_PUT() which issues a compiler_barrier() after
* the store. It is required to workaround an apparent optimization
* bug in GCC for ARM Cortex-M3 and higher targets, when multiple
* byte, half-word and word stores (strb, strh, str instructions),
* which support unaligned access, can be coalesced into store double
* (strd) instruction, which doesn't support unaligned access (the
* compilers in question do this optimization ignoring __packed__
* attribute).
*/
#define UNALIGNED_PUT(v, p) \
do { \
struct __attribute__((__packed__)) { \
__typeof__(*p) __v; \
} *__p = (__typeof__(__p)) (p); \
__p->__v = (v); \
compiler_barrier(); \
} while (false)
#else
#define UNALIGNED_PUT(v, p) \
do { \
struct __attribute__((__packed__)) { \
__typeof__(*p) __v; \
} *__p = (__typeof__(__p)) (p); \
__p->__v = (v); \
} while (false)
#endif
/* Double indirection to ensure section names are expanded before
* stringification
*/
#define __GENERIC_SECTION(segment) __attribute__((section(STRINGIFY(segment))))
#define Z_GENERIC_SECTION(segment) __GENERIC_SECTION(segment)
#define __GENERIC_DOT_SECTION(segment) \
__attribute__((section("." STRINGIFY(segment))))
#define Z_GENERIC_DOT_SECTION(segment) __GENERIC_DOT_SECTION(segment)
#define ___in_section(a, b, c) \
__attribute__((section("." Z_STRINGIFY(a) \
"." Z_STRINGIFY(b) \
"." Z_STRINGIFY(c))))
#define __in_section(a, b, c) ___in_section(a, b, c)
#define __in_section_unique(seg) ___in_section(seg, __FILE__, __COUNTER__)
/* When using XIP, using '__ramfunc' places a function into RAM instead
* of FLASH. Make sure '__ramfunc' is defined only when
* CONFIG_ARCH_HAS_RAMFUNC_SUPPORT is defined, so that the compiler can
* report an error if '__ramfunc' is used but the architecture does not
* support it.
*/
#if !defined(CONFIG_XIP)
#define __ramfunc
#elif defined(CONFIG_ARCH_HAS_RAMFUNC_SUPPORT)
#define __ramfunc __attribute__((noinline)) \
__attribute__((long_call, section(".ramfunc")))
#endif /* !CONFIG_XIP */
#ifndef __fallthrough
#if __GNUC__ >= 7
#define __fallthrough __attribute__((fallthrough))
#else
#define __fallthrough
#endif /* __GNUC__ >= 7 */
#endif
#ifndef __packed
#define __packed __attribute__((__packed__))
#endif
#ifndef __aligned
#define __aligned(x) __attribute__((__aligned__(x)))
#endif
#define __may_alias __attribute__((__may_alias__))
#ifndef __printf_like
#define __printf_like(f, a) __attribute__((format (printf, f, a)))
#endif
#define __used __attribute__((__used__))
#ifndef __deprecated
#define __deprecated __attribute__((deprecated))
#endif
#ifndef __attribute_const__
#define __attribute_const__ __attribute__((__const__))
#endif
#define ARG_UNUSED(x) (void)(x)
#define likely(x) __builtin_expect((bool)!!(x), true)
#define unlikely(x) __builtin_expect((bool)!!(x), false)
#define popcount(x) __builtin_popcount(x)
#ifndef __no_optimization
#define __no_optimization __attribute__((optimize("-O0")))
#endif
#ifndef __weak
#define __weak __attribute__((__weak__))
#endif
#define __unused __attribute__((__unused__))
/* Builtins with availability that depend on the compiler version. */
#if __GNUC__ >= 5
#define HAS_BUILTIN___builtin_add_overflow 1
#define HAS_BUILTIN___builtin_sub_overflow 1
#define HAS_BUILTIN___builtin_mul_overflow 1
#define HAS_BUILTIN___builtin_div_overflow 1
#endif
#if __GNUC__ >= 4
#define HAS_BUILTIN___builtin_clz 1
#define HAS_BUILTIN___builtin_clzl 1
#define HAS_BUILTIN___builtin_clzll 1
#define HAS_BUILTIN___builtin_ctz 1
#define HAS_BUILTIN___builtin_ctzl 1
#define HAS_BUILTIN___builtin_ctzll 1
#endif
/*
* Be *very* careful with these. You cannot filter out __DEPRECATED_MACRO with
* -wno-deprecated, which has implications for -Werror.
*/
/*
* Expands to nothing and generates a warning. Used like
*
* #define FOO __WARN("Please use BAR instead") ...
*
* The warning points to the location where the macro is expanded.
*/
#define __WARN(msg) __WARN1(GCC warning msg)
#define __WARN1(s) _Pragma(#s)
/* Generic message */
#ifndef __DEPRECATED_MACRO
#define __DEPRECATED_MACRO __WARN("Macro is deprecated")
#endif
/* These macros allow having ARM asm functions callable from thumb */
#if defined(_ASMLANGUAGE)
#if defined(CONFIG_ARM)
#if defined(CONFIG_ASSEMBLER_ISA_THUMB2)
#define FUNC_CODE() .thumb;
#define FUNC_INSTR(a)
#else
#define FUNC_CODE() .code 32
#define FUNC_INSTR(a)
#endif /* CONFIG_ASSEMBLER_ISA_THUMB2 */
#else
#define FUNC_CODE()
#define FUNC_INSTR(a)
#endif /* CONFIG_ARM */
#endif /* _ASMLANGUAGE */
/*
* These macros are used to declare assembly language symbols that need
* to be typed properly(func or data) to be visible to the OMF tool.
* So that the build tool could mark them as an entry point to be linked
* correctly. This is an elfism. Use #if 0 for a.out.
*/
#if defined(_ASMLANGUAGE)
#if defined(CONFIG_ARM) || defined(CONFIG_NIOS2) || defined(CONFIG_RISCV) \
|| defined(CONFIG_XTENSA) || defined(CONFIG_ARM64)
#define GTEXT(sym) .global sym; .type sym, %function
#define GDATA(sym) .global sym; .type sym, %object
#define WTEXT(sym) .weak sym; .type sym, %function
#define WDATA(sym) .weak sym; .type sym, %object
#elif defined(CONFIG_ARC)
/*
* Need to use assembly macros because ';' is interpreted as the start of
* a single line comment in the ARC assembler.
*/
.macro glbl_text symbol
.globl \symbol
.type \symbol, %function
.endm
.macro glbl_data symbol
.globl \symbol
.type \symbol, %object
.endm
.macro weak_data symbol
.weak \symbol
.type \symbol, %object
.endm
#define GTEXT(sym) glbl_text sym
#define GDATA(sym) glbl_data sym
#define WDATA(sym) weak_data sym
#else /* !CONFIG_ARM && !CONFIG_ARC */
#define GTEXT(sym) .globl sym; .type sym, @function
#define GDATA(sym) .globl sym; .type sym, @object
#endif
/*
* These macros specify the section in which a given function or variable
* resides.
*
* - SECTION_FUNC allows only one function to reside in a sub-section
* - SECTION_SUBSEC_FUNC allows multiple functions to reside in a sub-section
* This ensures that garbage collection only discards the section
* if all functions in the sub-section are not referenced.
*/
#if defined(CONFIG_ARC)
/*
* Need to use assembly macros because ';' is interpreted as the start of
* a single line comment in the ARC assembler.
*
* Also, '\()' is needed in the .section directive of these macros for
* correct substitution of the 'section' variable.
*/
.macro section_var section, symbol
.section .\section\().\symbol
\symbol :
.endm
.macro section_func section, symbol
.section .\section\().\symbol, "ax"
FUNC_CODE()
PERFOPT_ALIGN
\symbol :
FUNC_INSTR(\symbol)
.endm
.macro section_subsec_func section, subsection, symbol
.section .\section\().\subsection, "ax"
PERFOPT_ALIGN
\symbol :
.endm
#define SECTION_VAR(sect, sym) section_var sect, sym
#define SECTION_FUNC(sect, sym) section_func sect, sym
#define SECTION_SUBSEC_FUNC(sect, subsec, sym) \
section_subsec_func sect, subsec, sym
#else /* !CONFIG_ARC */
#define SECTION_VAR(sect, sym) .section .sect.sym; sym:
#define SECTION_FUNC(sect, sym) \
.section .sect.sym, "ax"; \
FUNC_CODE() \
PERFOPT_ALIGN; sym : \
FUNC_INSTR(sym)
#define SECTION_SUBSEC_FUNC(sect, subsec, sym) \
.section .sect.subsec, "ax"; PERFOPT_ALIGN; sym :
#endif /* CONFIG_ARC */
#endif /* _ASMLANGUAGE */
#if defined(_ASMLANGUAGE)
#if defined(CONFIG_ARM)
#if defined(CONFIG_ASSEMBLER_ISA_THUMB2)
/* '.syntax unified' is a gcc-ism used in thumb-2 asm files */
#define _ASM_FILE_PROLOGUE .text; .syntax unified; .thumb
#else
#define _ASM_FILE_PROLOGUE .text; .code 32
#endif /* CONFIG_ASSEMBLER_ISA_THUMB2 */
#elif defined(CONFIG_ARM64)
#define _ASM_FILE_PROLOGUE .text
#endif /* CONFIG_ARM64 || CONFIG_ARM */
#endif /* _ASMLANGUAGE */
/*
* These macros generate absolute symbols for GCC
*/
/* create an extern reference to the absolute symbol */
#define GEN_OFFSET_EXTERN(name) extern const char name[]
#define GEN_ABS_SYM_BEGIN(name) \
EXTERN_C void name(void); \
void name(void) \
{
#define GEN_ABS_SYM_END }
/*
* Note that GEN_ABSOLUTE_SYM(), depending on the architecture
* and toolchain, may restrict the range of values permitted
* for assignment to the named symbol.
*
* For example, on x86, "value" is interpreated as signed
* 32-bit integer. Passing in an unsigned 32-bit integer
* with MSB set would result in a negative integer.
* Moreover, GCC would error out if an integer larger
* than 2^32-1 is passed as "value".
*/
/*
* GEN_ABSOLUTE_SYM_KCONFIG() is outputted by the build system
* to generate named symbol/value pairs for kconfigs.
*/
#if defined(CONFIG_ARM)
/*
* GNU/ARM backend does not have a proper operand modifier which does not
* produces prefix # followed by value, such as %0 for PowerPC, Intel, and
* MIPS. The workaround performed here is using %B0 which converts
* the value to ~(value). Thus "n"(~(value)) is set in operand constraint
* to output (value) in the ARM specific GEN_OFFSET macro.
*/
#define GEN_ABSOLUTE_SYM(name, value) \
__asm__(".globl\t" #name "\n\t.equ\t" #name \
",%B0" \
"\n\t.type\t" #name ",%%object" : : "n"(~(value)))
#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \
__asm__(".globl\t" #name \
"\n\t.equ\t" #name "," #value \
"\n\t.type\t" #name ",%object")
#elif defined(CONFIG_X86)
#define GEN_ABSOLUTE_SYM(name, value) \
__asm__(".globl\t" #name "\n\t.equ\t" #name \
",%c0" \
"\n\t.type\t" #name ",@object" : : "n"(value))
#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \
__asm__(".globl\t" #name \
"\n\t.equ\t" #name "," #value \
"\n\t.type\t" #name ",@object")
#elif defined(CONFIG_ARC) || defined(CONFIG_ARM64)
#define GEN_ABSOLUTE_SYM(name, value) \
__asm__(".globl\t" #name "\n\t.equ\t" #name \
",%c0" \
"\n\t.type\t" #name ",@object" : : "n"(value))
#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \
__asm__(".globl\t" #name \
"\n\t.equ\t" #name "," #value \
"\n\t.type\t" #name ",@object")
#elif defined(CONFIG_NIOS2) || defined(CONFIG_RISCV) || defined(CONFIG_XTENSA)
/* No special prefixes necessary for constants in this arch AFAICT */
#define GEN_ABSOLUTE_SYM(name, value) \
__asm__(".globl\t" #name "\n\t.equ\t" #name \
",%0" \
"\n\t.type\t" #name ",%%object" : : "n"(value))
#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \
__asm__(".globl\t" #name \
"\n\t.equ\t" #name "," #value \
"\n\t.type\t" #name ",%object")
#elif defined(CONFIG_ARCH_POSIX)
#define GEN_ABSOLUTE_SYM(name, value) \
__asm__(".globl\t" #name "\n\t.equ\t" #name \
",%c0" \
"\n\t.type\t" #name ",@object" : : "n"(value))
#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \
__asm__(".globl\t" #name \
"\n\t.equ\t" #name "," #value \
"\n\t.type\t" #name ",@object")
#elif defined(CONFIG_SPARC)
#define GEN_ABSOLUTE_SYM(name, value) \
__asm__(".global\t" #name "\n\t.equ\t" #name \
",%0" \
"\n\t.type\t" #name ",#object" : : "n"(value))
#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \
__asm__(".globl\t" #name \
"\n\t.equ\t" #name "," #value \
"\n\t.type\t" #name ",#object")
#else
#error processor architecture not supported
#endif
#define compiler_barrier() do { \
__asm__ __volatile__ ("" ::: "memory"); \
} while (false)
/** @brief Return larger value of two provided expressions.
*
* Macro ensures that expressions are evaluated only once.
*
* @note Macro has limited usage compared to the standard macro as it cannot be
* used:
* - to generate constant integer, e.g. __aligned(Z_MAX(4,5))
* - static variable, e.g. array like static uint8_t array[Z_MAX(...)];
*/
#define Z_MAX(a, b) ({ \
/* random suffix to avoid naming conflict */ \
__typeof__(a) _value_a_ = (a); \
__typeof__(b) _value_b_ = (b); \
_value_a_ > _value_b_ ? _value_a_ : _value_b_; \
})
/** @brief Return smaller value of two provided expressions.
*
* Macro ensures that expressions are evaluated only once. See @ref Z_MAX for
* macro limitations.
*/
#define Z_MIN(a, b) ({ \
/* random suffix to avoid naming conflict */ \
__typeof__(a) _value_a_ = (a); \
__typeof__(b) _value_b_ = (b); \
_value_a_ < _value_b_ ? _value_a_ : _value_b_; \
})
/** @brief Return a value clamped to a given range.
*
* Macro ensures that expressions are evaluated only once. See @ref Z_MAX for
* macro limitations.
*/
#define Z_CLAMP(val, low, high) ({ \
/* random suffix to avoid naming conflict */ \
__typeof__(val) _value_val_ = (val); \
__typeof__(low) _value_low_ = (low); \
__typeof__(high) _value_high_ = (high); \
(_value_val_ < _value_low_) ? _value_low_ : \
(_value_val_ > _value_high_) ? _value_high_ : \
_value_val_; \
})
/**
* @brief Calculate power of two ceiling for some nonzero value
*
* @param x Nonzero unsigned long value
* @return X rounded up to the next power of two
*/
#ifdef CONFIG_64BIT
#define Z_POW2_CEIL(x) ((1UL << (63U - __builtin_clzl(x))) < x ? \
1UL << (63U - __builtin_clzl(x) + 1U) : \
1UL << (63U - __builtin_clzl(x)))
#else
#define Z_POW2_CEIL(x) ((1UL << (31U - __builtin_clzl(x))) < x ? \
1UL << (31U - __builtin_clzl(x) + 1U) : \
1UL << (31U - __builtin_clzl(x)))
#endif
#endif /* !_LINKER */
#endif /* ZEPHYR_INCLUDE_TOOLCHAIN_GCC_H_ */
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2017 Linaro Limited
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_ZEPHYR_TYPES_H_
#define ZEPHYR_INCLUDE_ZEPHYR_TYPES_H_
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* 32 bits on ILP32 builds, 64 bits on LP64 builts */
typedef unsigned long ulong_t;
/*
* A type with strong alignment requiremnts, similar to C11 max_align_t. It can
* be used to force alignment of data structures allocated on the stack or as
* return * type for heap allocators.
*/
typedef union {
long long thelonglong;
long double thelongdouble;
uintmax_t theuintmax_t;
size_t thesize_t;
uintptr_t theuintptr_t;
void *thepvoid;
void (*thepfunc)(void);
} z_max_align_t;
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_ZEPHYR_TYPES_H_ */