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 <ta...@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 --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 */ -- 2.46.0.rc2.264.g509ed76dc8-goog