diff mbox series

[RFC,08/23] test/unit: add register access macros and functions

Message ID 20240805201719.2345596-9-tavip@google.com
State New
Headers show
Series NXP i.MX RT595, ARM SVD and device model unit tests | expand

Commit Message

Octavian Purdila Aug. 5, 2024, 8:17 p.m. UTC
Add register access macros for devices models that use SVD generated
registers. This allows accessing register or register bit fields in
unit tests, e.g.:

  REG32_WRITE(f->dev, FLEXCOMM, PSELID, persel);
  g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM, PSELID, PERSEL) == persel);

Also add support for accessing 32bit registers with memory transaction
state, e.g.:

  /* no register access until a function is selected  */
  g_assert(reg32_addr_read_raw(f->dev, FLEXCOMM_BASE, &tmp, 4) == MEMTX_ERROR);

Signed-off-by: Octavian Purdila <tavip@google.com>
---
 include/hw/regs.h      |   2 +-
 tests/unit/reg-utils.h | 103 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 104 insertions(+), 1 deletion(-)
 create mode 100644 tests/unit/reg-utils.h
diff mbox series

Patch

diff --git a/include/hw/regs.h b/include/hw/regs.h
index 8d0da0629d..fd6576ba2b 100644
--- a/include/hw/regs.h
+++ b/include/hw/regs.h
@@ -59,7 +59,7 @@  static inline bool reg32_aligned_access(hwaddr addr, unsigned size)
  * // backstore is updated to 0x78
  * reg32_write(&backstore, REG2_ADDR, 0x12345678, wr_bits_array);
  */
-static inline uint32_t reg32_write(void *base, uint32_t off, uint32_t val,
+static inline uint32_t reg32_write(void *base, uint32_t addr, uint32_t val,
                                    const uint32_t *rw_bits_array)
 {
     uint32_t *ptr = base + addr;
diff --git a/tests/unit/reg-utils.h b/tests/unit/reg-utils.h
new file mode 100644
index 0000000000..f18ee07d20
--- /dev/null
+++ b/tests/unit/reg-utils.h
@@ -0,0 +1,103 @@ 
+/*
+ * Register access utilities for peripheral device tests.
+ *
+ * Copyright (C) 2024 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef _REG_UTILS_H
+#define _REG_UTILS_H
+
+#ifdef DEBUG_REG
+#define debug(fmt, args...) fprintf(stderr, fmt, ## args)
+#else
+#define debug(fmt, args...)
+#endif
+
+#define _REG_OFF(mod, field) (offsetof(mod##_Type, field))
+
+#define REG32_READ(dev, mod, reg)                                       \
+    ({                                                                  \
+        uint32_t value;                                                 \
+        value = sysbus_mmio_read_addr(dev, mod##_BASE + _REG_OFF(mod, reg), \
+                                      sizeof(uint32_t));                \
+        debug("[%s] -> %08x\n", #reg, value);                           \
+        value;                                                          \
+    })
+
+#define REG32_WRITE(dev, mod, reg, value)                               \
+    do {                                                                \
+        debug("[%s] <- %08x\n", #reg, value);                           \
+        sysbus_mmio_write_addr(dev, mod##_BASE + _REG_OFF(mod, reg), value, \
+                               sizeof(uint32_t));                       \
+    } while (0)
+
+#define REG_FIELD_VAL(v, mod, reg, field)                               \
+    ((v & mod##_##reg##_##field##_Msk) >> mod##_##reg##_##field##_Pos)
+
+#define REG32_READ_FIELD(dev, mod, reg, field)                  \
+    REG_FIELD_VAL(REG32_READ(dev, mod, reg), mod, reg, field)
+
+#define REG32_WRITE_FIELD(dev, mod, reg, field, val)                    \
+    do {                                                                \
+        uint32_t _tmp = REG32_READ(dev, mod, reg);                      \
+                                                                        \
+        _tmp &= ~mod##_##reg##_##field##_Msk;                           \
+        _tmp |= (val << mod##_##reg##_##field##_Pos) &                  \
+            mod##_##reg##_##field##_Msk;                                \
+        REG32_WRITE(dev, mod, reg, _tmp);                               \
+    } while (0)
+
+#define REG32_WRITE_FIELD_NOUPDATE(dev, mod, reg, field, val)           \
+    do {                                                                \
+        uint32_t _tmp;                                                  \
+                                                                        \
+        _tmp = (val << mod##_##reg##_##field##_Pos) &                   \
+            mod##_##reg##_##field##_Msk;                                \
+        REG32_WRITE(dev, mod, reg, _tmp);                               \
+    } while (0)
+
+#define WAIT_REG32_FIELD(ms, dev, mod, reg, field, val)         \
+    {                                                           \
+        int remaining = ms;                                     \
+                                                                \
+        while (remaining) {                                     \
+            if (REG32_READ_FIELD(dev, mod, reg, field) == val) {    \
+                break;                                          \
+            }                                                   \
+            main_loop_wait(false);                              \
+            usleep(1000);                                       \
+            remaining--;                                        \
+        }                                                       \
+                                                                \
+        g_assert(remaining);                                    \
+    }
+
+static inline MemTxResult reg32_addr_read_raw(DeviceState *dev, uint32_t addr,
+                                              uint32_t *value, uint32_t size)
+{
+    MemTxResult res;
+    uint64_t tmp;
+
+    res = sysbus_mmio_read_addr_raw(dev, addr, &tmp, size);
+    if (res == MEMTX_OK) {
+        *value = tmp;
+    }
+    debug("%d: [%x] -[%d]-> %08x\n", res, addr, size, *value);
+    return res;
+}
+
+static inline MemTxResult reg32_addr_write_raw(DeviceState *dev, uint32_t addr,
+                                               uint32_t value, uint32_t size)
+{
+    MemTxResult res;
+
+    res = sysbus_mmio_write_addr_raw(dev, addr, value, size);
+    debug("%d: [%x] <-[%d]- %08x\n", res, addr, size, value);
+    return res;
+}
+
+#endif /* _REG_UTILS_H */