#ifndef _UTIL_HH_ #define _UTIL_HH_ #include #include // Functions to access hardware registers. GCC will generate memory access instructions of the correct width. // Usage: "_reg8(base, ofs) = 0xf0;" to set // "uint8_t foo = _reg8(base, ofs);" to get // Read/modify/write like "_reg8(base, ofs) |= (1<<7);" also works as expected. constexpr inline uint8_t volatile& _reg8(uintptr_t const& base, size_t const& ofs) noexcept __attribute__((const)); constexpr inline uint8_t volatile& _reg8(uintptr_t const& base, size_t const& ofs) noexcept { return *reinterpret_cast(base+ofs); } constexpr inline uint16_t volatile& _reg16(uintptr_t const& base, size_t const& ofs) noexcept __attribute__((const)); constexpr inline uint16_t volatile& _reg16(uintptr_t const& base, size_t const& ofs) noexcept { return *reinterpret_cast(base+ofs); } constexpr inline uint32_t volatile& _reg32(uintptr_t const& base, size_t const& ofs) noexcept __attribute__((const)); constexpr inline uint32_t volatile& _reg32(uintptr_t const& base, size_t const& ofs) noexcept { return *reinterpret_cast(base+ofs); } // log2(n) inline unsigned _ln2(unsigned n) noexcept __attribute__((const)); inline unsigned _ln2(unsigned n) noexcept { uint32_t reg; asm ("clz %[dst], %[src]" : [dst] "=r"(reg) : [src] "r"(n)); reg = 31-reg; if(n & ~(1<