]> code.bitgloo.com Git - clyne/funreg.git/commitdiff
draft; make reg access generic
authorClyne Sullivan <clyne@bitgloo.com>
Sun, 7 Aug 2022 23:23:07 +0000 (19:23 -0400)
committerClyne Sullivan <clyne@bitgloo.com>
Sun, 7 Aug 2022 23:23:07 +0000 (19:23 -0400)
funreg.hpp

index 156b6cf688c9ed327b9269528c4e0d80329ef8bd..24a34feb948152775927570620f0a806f4883cc0 100644 (file)
@@ -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
+