/*****************************************************************************/ /** * \file * \brief bit manipulation functions * \ingroup l4util_bitops * * \date 07/03/2001 * \author Lars Reuther */ /* * (c) 2000-2009 Author(s) * economic rights: Technische Universität Dresden (Germany) * This file is part of TUD:OS and distributed under the terms of the * GNU Lesser General Public License 2.1. * Please see the COPYING-LGPL-2.1 file for details. */ /*****************************************************************************/ #ifndef __L4UTIL__INCLUDE__BITOPS_H__ #define __L4UTIL__INCLUDE__BITOPS_H__ /* L4 includes */ #include #include /** define some more usual names */ #define l4util_test_and_clear_bit(b, dest) l4util_btr(b, dest) #define l4util_test_and_set_bit(b, dest) l4util_bts(b, dest) #define l4util_test_and_change_bit(b, dest) l4util_btc(b, dest) #define l4util_log2(word) l4util_bsr(word) /***************************************************************************** *** Prototypes *****************************************************************************/ EXTERN_C_BEGIN /** * \defgroup l4util_bitops Bit Manipulation * \ingroup l4util_api */ /** * \brief Set bit in memory * \ingroup l4util_bitops * * \param b bit position * \param dest destination operand */ L4_INLINE void l4util_set_bit(int b, volatile l4_umword_t * dest); L4_INLINE void l4util_set_bit32(int b, volatile l4_uint32_t * dest); #if L4_MWORD_BITS >= 64 L4_INLINE void l4util_set_bit64(int b, volatile l4_uint64_t * dest); #endif /** * \brief Clear bit in memory * \ingroup l4util_bitops * * \param b bit position * \param dest destination operand */ L4_INLINE void l4util_clear_bit(int b, volatile l4_umword_t * dest); L4_INLINE void l4util_clear_bit32(int b, volatile l4_uint32_t * dest); #if L4_MWORD_BITS >= 64 L4_INLINE void l4util_clear_bit64(int b, volatile l4_uint64_t * dest); #endif /** * \brief Complement bit in memory * \ingroup l4util_bitops * * \param b bit position * \param dest destination operand */ L4_INLINE void l4util_complement_bit(int b, volatile l4_umword_t * dest); /** * \brief Test bit (return value of bit) * \ingroup l4util_bitops * * \param b bit position * \param dest destination operand * * \return Value of bit \em b. */ L4_INLINE int l4util_test_bit(int b, const volatile l4_umword_t * dest); L4_INLINE int l4util_test_bit32(int b, const volatile l4_uint32_t * dest); #if L4_MWORD_BITS >= 64 L4_INLINE int l4util_test_bit64(int b, const volatile l4_uint64_t * dest); #endif /** * \brief Bit test and set * \ingroup l4util_bitops * * \param b bit position * \param dest destination operand * * \return Old value of bit \em b. * * Set the \em b bit of \em dest to 1 and return the old value. */ L4_INLINE int l4util_bts(int b, volatile l4_umword_t * dest); /** * \brief Bit test and reset * \ingroup l4util_bitops * * \param b bit position * \param dest destination operand * * \return Old value of bit \em b. * * Reset bit \em b and return old value. */ L4_INLINE int l4util_btr(int b, volatile l4_umword_t * dest); /** * \brief Bit test and complement * \ingroup l4util_bitops * * \param b bit position * \param dest destination operand * * \return Old value of bit \em b. * * Complement bit \em b and return old value. */ L4_INLINE int l4util_btc(int b, volatile l4_umword_t * dest); /** * \brief Bit scan reverse * \ingroup l4util_bitops * * \param word value (machine size) * * \return index of most significant set bit in word, * -1 if no bit is set (word == 0) * * "bit scan reverse", find most significant set bit in word (-> LOG2(word)) */ L4_INLINE int l4util_bsr(l4_umword_t word); /** * \brief Bit scan forward * \ingroup l4util_bitops * * \param word value (machine size) * * \return index of least significant bit set in word, * -1 if no bit is set (word == 0) * * "bit scan forward", find least significant bit set in word. */ L4_INLINE int l4util_bsf(l4_umword_t word); /** * \brief Find the first set bit in a memory region * \ingroup l4util_bitops * * \param dest bit string * \param size size of string in bits (must be a multiple of 32!) * * \return number of the first set bit, * >= size if no bit is set */ L4_INLINE int l4util_find_first_set_bit(const void * dest, l4_size_t size); /** * \brief Find the first zero bit in a memory region * \ingroup l4util_bitops * * \param dest bit string * \param size size of string in bits (must be a multiple of 32!) * * \return number of the first zero bit, * >= size if no bit is set */ L4_INLINE int l4util_find_first_zero_bit(const void * dest, l4_size_t size); /** * \brief Find the next power of 2 for a given number. * \ingroup l4util_bitops * * \param val initial value * * \return next-highest power of 2 */ L4_INLINE int l4util_next_power2(const unsigned long val); EXTERN_C_END /***************************************************************************** *** Implementation of specific version *****************************************************************************/ #include /***************************************************************************** *** Generic implementations *****************************************************************************/ #ifndef __L4UTIL_BITOPS_HAVE_ARCH_SET_BIT #include L4_INLINE void l4util_set_bit(int b, volatile l4_umword_t * dest) { l4_umword_t oldval, newval; dest += b / (sizeof(*dest) * 8); /* advance dest to the proper element */ b &= sizeof(*dest) * 8 - 1; /* modulo; cut off all upper bits */ do { oldval = *dest; newval = oldval | (1 << b); } while (!l4util_cmpxchg(dest, oldval, newval)); } #endif #ifndef __L4UTIL_BITOPS_HAVE_ARCH_CLEAR_BIT #include L4_INLINE void l4util_clear_bit(int b, volatile l4_umword_t * dest) { l4_umword_t oldval, newval; dest += b / (sizeof(*dest) * 8); b &= sizeof(*dest) * 8 - 1; do { oldval = *dest; newval = oldval & ~(1 << b); } while (!l4util_cmpxchg(dest, oldval, newval)); } #endif #ifndef __L4UTIL_BITOPS_HAVE_ARCH_TEST_BIT L4_INLINE int l4util_test_bit(int b, const volatile l4_umword_t * dest) { dest += b / (sizeof(*dest) * 8); b &= sizeof(*dest) * 8 - 1; return (*dest >> b) & 1; } #endif #ifndef __L4UTIL_BITOPS_HAVE_ARCH_TEST_BIT32 L4_INLINE int l4util_test_bit32(int b, const volatile l4_uint32_t * dest) { dest += b / (sizeof(*dest) * 8); b &= sizeof(*dest) * 8 - 1; return (*dest >> b) & 1; } #endif #ifndef __L4UTIL_BITOPS_HAVE_ARCH_BIT_TEST_AND_SET #include L4_INLINE int l4util_bts(int b, volatile l4_umword_t * dest) { l4_umword_t oldval, newval; dest += b / (sizeof(*dest) * 8); b &= sizeof(*dest) * 8 - 1; do { oldval = *dest; newval = oldval | (1 << b); } while (!l4util_cmpxchg(dest, oldval, newval)); /* Return old bit */ return (oldval >> b) & 1; } #endif #ifndef __L4UTIL_BITOPS_HAVE_ARCH_BIT_TEST_AND_RESET #include L4_INLINE int l4util_btr(int b, volatile l4_umword_t * dest) { l4_umword_t oldval, newval; dest += b / (sizeof(*dest) * 8); b &= sizeof(*dest) * 8 - 1; do { oldval = *dest; newval = oldval & ~(1 << b); } while (!l4util_cmpxchg(dest, oldval, newval)); /* Return old bit */ return (oldval >> b) & 1; } #endif #ifndef __L4UTIL_BITOPS_HAVE_ARCH_BIT_SCAN_REVERSE L4_INLINE int l4util_bsr(l4_umword_t word) { int i; if (!word) return -1; for (i = 8 * sizeof(word) - 1; i >= 0; i--) if ((1 << i) & word) return i; return -1; } #endif #ifndef __L4UTIL_BITOPS_HAVE_ARCH_BIT_SCAN_FORWARD L4_INLINE int l4util_bsf(l4_umword_t word) { unsigned int i; if (!word) return -1; for (i = 0; i < sizeof(word) * 8; i++) if ((1 << i) & word) return i; return -1; } #endif #ifndef __L4UTIL_BITOPS_HAVE_ARCH_FIND_FIRST_ZERO_BIT L4_INLINE int l4util_find_first_zero_bit(const void * dest, l4_size_t size) { l4_size_t i, j; unsigned long *v = (unsigned long*)dest; if (!size) return 0; size = (size + 31) & ~0x1f; /* Grmbl: adapt to x86 implementation... */ for (i = j = 0; i < size; i++, j++) { if (j >= sizeof(*v) * 8) { j = 0; v++; } if (!((1 << j) & *v)) return i; } return size + 1; } #endif #ifndef __L4UTIL_BITOPS_HAVE_ARCH_COMPLEMENT_BIT L4_INLINE void l4util_complement_bit(int b, volatile l4_umword_t * dest) { dest += b / (sizeof(*dest) * 8); b &= sizeof(*dest) * 8 - 1; *dest ^= 1UL << b; } #endif /* * Adapted from: * http://en.wikipedia.org/wiki/Power_of_two#Algorithm_to_find_the_next-highest_power_of_two */ L4_INLINE int l4util_next_power2(unsigned long val) { unsigned i; if (val == 0) return 1; val--; for (i=1; i < sizeof(unsigned long)*8; i<<=1) val = val | val >> i; return val+1; } /* Non-implemented version, catch with a linker warning */ extern int __this_l4util_bitops_function_is_not_implemented_for_this_arch__sorry(void); #ifndef __L4UTIL_BITOPS_HAVE_ARCH_CLEAR_BIT32 L4_INLINE void l4util_clear_bit32(int b, volatile l4_uint32_t * dest) { (void)b; (void)dest; __this_l4util_bitops_function_is_not_implemented_for_this_arch__sorry(); } #endif #ifndef __L4UTIL_BITOPS_HAVE_ARCH_BIT_TEST_AND_COMPLEMENT L4_INLINE int l4util_btc(int b, volatile l4_umword_t * dest) { (void)b; (void)dest; __this_l4util_bitops_function_is_not_implemented_for_this_arch__sorry(); return 0; } #endif #ifndef __L4UTIL_BITOPS_HAVE_ARCH_FIND_FIRST_SET_BIT L4_INLINE int l4util_find_first_set_bit(const void * dest, l4_size_t size) { (void)dest; (void)size; __this_l4util_bitops_function_is_not_implemented_for_this_arch__sorry(); return 0; } #endif #endif /* ! __L4UTIL__INCLUDE__BITOPS_H__ */