diff options
author | Clyne Sullivan <clyne@bitgloo.com> | 2022-08-07 19:23:07 -0400 |
---|---|---|
committer | Clyne Sullivan <clyne@bitgloo.com> | 2022-08-07 19:23:07 -0400 |
commit | 0a3a9188e70ca435f600dc1cceee614895468572 (patch) | |
tree | b0f1c263052c93b41514f5f74155da11109d17ab | |
parent | 30fd7bb79fe88aad8740543dd29a56b8f7b55a01 (diff) |
draft; make reg access generic
-rw-r--r-- | funreg.hpp | 152 |
1 files changed, 95 insertions, 57 deletions
@@ -11,7 +11,7 @@ namespace fr { -// A utility to measure a bit-mask's offset from bit zero. +// A utility to measure a bit-mask's offset from bit zero. template<auto Mask, unsigned int N = 0> constexpr auto BitOffset = []() constexpr { if constexpr (Mask & 1) @@ -20,6 +20,40 @@ constexpr auto BitOffset = []() constexpr { return BitOffset<(Mask >> 1), (N + 1)>; }(); +template<typename T, uintptr_t Addr> +struct MemoryIO { + constexpr static auto addr = Addr; + + /** + * Gets a pointer to the register. + */ + constexpr static T read() { + return *reinterpret_cast<volatile T*>(Addr); + } + + /** + * Overwrites the register's value. + */ + constexpr static void write(const T& value) { + *reinterpret_cast<volatile T*>(Addr) = value; + } +}; + +template<typename T, uintptr_t Addr> +struct ExternalIO { + constexpr static auto addr = Addr; + + /** + * Gets a pointer to the register. + */ + static T (*read)(); + + /** + * Overwrites the register's value. + */ + static void (*write)(const T& value); +}; + /** * @struct Register * @brief Defines a memory-mapped register, given bit-size and address. @@ -31,13 +65,22 @@ constexpr auto BitOffset = []() constexpr { * * Use only as a type, e.g. "using GPIO_OUT = Register<uint32_t, 0xA0004120>" */ -template<typename T, uintptr_t Addr> +template<typename T, typename RegAccess> struct Register { + constexpr static auto Addr = RegAccess::addr; + /** * Gets a pointer to the register. */ - constexpr static auto get() { - return reinterpret_cast<volatile T*>(Addr); + constexpr static T read() { + return RegAccess::read(); + } + + /** + * Overwrites the register's value. + */ + constexpr static void write(const T& value) { + RegAccess::write(value); } /** @@ -45,14 +88,14 @@ struct Register { */ template<typename... Masks> static void set() { - apply<Masks...>([](auto r, auto m) { *r = *r | m; }); + apply<Masks...>([](auto r, auto m) { return r | m; }); } /** * Sets register bits to '1' according to the given mask. */ static void set(const T& mask) { - *get() = *get() | mask; + write(read() | mask); } /** @@ -60,14 +103,14 @@ struct Register { */ template<typename... Masks> static void clear() { - apply<Masks...>([](auto r, auto m) { *r = *r & ~m; }); + apply<Masks...>([](auto r, auto m) { return r & ~m; }); } /** * Clears register bits to '0' according to the given mask. */ static void clear(const T& mask) { - *get() = *get() & ~mask; + write(read() & ~mask); } /** @@ -75,14 +118,14 @@ struct Register { */ template<typename... Masks> static void toggle() { - apply<Masks...>([](auto r, auto m) { *r = *r ^ m; }); + apply<Masks...>([](auto r, auto m) { return r ^m; }); } /** * Toggles bits in the register according to the given mask. */ static void toggle(const T& mask) { - *get() = *get() ^ mask; + write(read() ^ mask); } /** @@ -92,26 +135,10 @@ struct Register { */ template<typename... Masks> static auto read() { - if constexpr (sizeof...(Masks) > 0) { - if (((Addr == Masks::reg::addr) | ...)) { - auto mask = - ([] { - return Addr == Masks::reg::addr ? Masks::mask : 0; - }() | ...); - return *get() & mask; - } else { - return 0; - } - } else { - return *get(); - } - } - - /** - * Overwrites the entire register with the given value. - */ - static void write(const T& value) { - *get() = value; + if constexpr (sizeof...(Masks) > 0) + return read() & mergeMasks<Masks...>(); + else + return read(); } /** @@ -121,17 +148,10 @@ struct Register { template<typename... Masks> static bool test() { if constexpr (sizeof...(Masks) > 0) { - if (((Addr == Masks::reg::addr) | ...)) { - auto mask = - ([] { - return Addr == Masks::reg::addr ? Masks::mask : 0; - }() | ...); - return (*get() & mask) == mask; - } else { - return 0; - } + auto mask = mergeMasks<Masks...>(); + return (read() & mask) == mask; } else { - return *get() != 0; + return read() != 0; } } @@ -145,16 +165,16 @@ struct Register { template<typename... Ops> static void modify() { if (((Addr == Ops::reg::addr) | ...)) { - auto mask = *get(); + auto mask = read(); ([&mask] { if (Addr == Ops::reg::addr) mask = Ops(mask); }(), ...); - *get() = mask; + write(mask); } } - // Below is meant for internal use only. + // Below is meant for internal use only. // Applies bit-masks to the register through the provided function. // The provided function receives a pointer to the register's data and a @@ -163,14 +183,28 @@ struct Register { template<typename... Masks> static void apply(auto fn) { if constexpr (sizeof...(Masks) > 0) { - auto mask = + auto mask = mergeMasks<Masks...>(); + if (mask) + write(fn(read(), mask)); + } else { + write(fn(read(), T(0) - 1)); + } + } + + template<typename... Masks> + static auto mergeMasks() { + if constexpr (sizeof...(Masks) > 0) { + if (((Addr == Masks::reg::addr) | ...)) { + auto mask = ([] { return Addr == Masks::reg::addr ? Masks::mask : 0; }() | ...); - if (mask) - fn(get(), mask); + return mask; + } else { + return 0; + } } else { - fn(get(), T(0) - 1); + return 0; } } @@ -203,7 +237,7 @@ struct RegisterMask */ struct set { constexpr set() { - *Reg::get() = *Reg::get() | Mask; + Reg::write(Reg::read() | Mask); } // For internal use. @@ -219,7 +253,7 @@ struct RegisterMask */ struct clear { constexpr clear() { - *Reg::get() = *Reg::get() & ~Mask; + Reg::write(Reg::read() & ~Mask); } // For internal use. @@ -235,7 +269,7 @@ struct RegisterMask */ struct toggle { constexpr toggle() { - *Reg::get() = *Reg::get() ^ Mask; + Reg::write(Reg::read() ^ Mask); } // For internal use. @@ -249,7 +283,7 @@ struct RegisterMask * Reads from the paired register, applying the bit-mask. */ static auto read() { - return *Reg::get() & Mask; + return Reg::read() & Mask; } /** @@ -272,10 +306,10 @@ struct RegisterMask template<T value> struct write { constexpr write() { - auto r = *Reg::get(); + auto r = Reg::read(); r &= ~Mask; r |= value << BitOffset<Mask>; - *Reg::get() = r; + Reg::write(r); } // For internal use. @@ -352,11 +386,11 @@ public: /** * Sets bits throughout this group's registers according to the given masks. * Bit-masks for the same register will be merged so that each register is - * only written once. + * only written once. */ template<typename... Masks> static void set() { - apply<Masks...>([](auto r, auto m) { *r = *r | m; }); + apply<Masks...>([](auto r, auto m) { return r | m; }); } /** @@ -366,7 +400,7 @@ public: */ template<typename... Masks> static void clear() { - apply<Masks...>([](auto r, auto m) { *r = *r & ~m; }); + apply<Masks...>([](auto r, auto m) { return r & ~m; }); } /** @@ -376,7 +410,7 @@ public: */ template<typename... Masks> static void toggle() { - apply<Masks...>([](auto r, auto m) { *r = *r ^ m; }); + apply<Masks...>([](auto r, auto m) { return r ^ m; }); } /** @@ -407,6 +441,10 @@ private: template<typename... RegMasks> constexpr auto Masks = (RegMasks::mask | ...); +template<typename T, uintptr_t Addr> +using MemRegister = Register<T, MemoryIO<T, Addr>>; + } // namespace fr #endif // FUNCTIONAL_REGISTER_IO_H + |