@@ -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;
new file mode 100644
@@ -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 */
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