From: Emmanuel Blot <[email protected]>

Signed-off-by: Lex Bailey <[email protected]>
---
 MAINTAINERS                    |  14 +-
 hmp-commands-info.hx           |  12 ++
 hw/riscv/Kconfig               |   3 +
 hw/riscv/ibex_common.c         | 316 ++++++++++++++++++++++++++++++++
 hw/riscv/meson.build           |   1 +
 include/hw/riscv/ibex_common.h | 322 +++++++++++++++++++++++++++++++++
 6 files changed, 666 insertions(+), 2 deletions(-)
 create mode 100644 hw/riscv/ibex_common.c
 create mode 100644 include/hw/riscv/ibex_common.h

diff --git a/MAINTAINERS b/MAINTAINERS
index e0c481e212..8b8bb7b554 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1716,9 +1716,13 @@ M: Alistair Francis <[email protected]>
 L: [email protected]
 S: Supported
 F: hw/riscv/opentitan.c
-F: hw/*/ibex_*.c
+F: hw/ssi/ibex_spi_host.c
+F: hw/timer/ibex_timer.c
+F: hw/char/ibex_uart.c
 F: include/hw/riscv/opentitan.h
-F: include/hw/*/ibex_*.h
+F: include/hw/ssi/ibex_spi_host.h
+F: include/hw/timer/ibex_timer.h
+F: include/hw/char/ibex_uart.h
 
 Microchip PolarFire SoC Icicle Kit
 L: [email protected]
@@ -4450,6 +4454,12 @@ F: docs/devel/ebpf_rss.rst
 F: ebpf/*
 F: tools/ebpf/*
 
+Ibex
+M: lowRISC <[email protected]>
+S: Supported
+F: hw/riscv/ibex_common.c
+F: include/hw/riscv/ibex_common.h
+F: include/hw/riscv/ibex_irq.h
 Build and test automation
 -------------------------
 Build and test automation, general continuous integration
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index 74c741f80e..90f05f7599 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -1010,3 +1010,15 @@ SRST
   ``info firmware-log``
     Show the firmware (ovmf) debug log.
 ERST
+
+    {
+        .name       = "ibex",
+        .args_type  = "",
+        .params     = "",
+        .help       = "Show Ibex vCPU info",
+    },
+
+SRST
+  ``info ibex``
+    Show Ibex vCPU information.
+ERST
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index e6aa32ee8f..7877f0615c 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -7,6 +7,9 @@ config RISCV_NUMA
 config IBEX
     bool
 
+config IBEX_COMMON
+    bool
+
 # RISC-V machines in alphabetical order
 
 config MICROCHIP_PFSOC
diff --git a/hw/riscv/ibex_common.c b/hw/riscv/ibex_common.c
new file mode 100644
index 0000000000..c6056767c7
--- /dev/null
+++ b/hw/riscv/ibex_common.c
@@ -0,0 +1,316 @@
+/*
+ * QEMU RISC-V Helpers for LowRISC Ibex Demo System & OpenTitan EarlGrey
+ *
+ * Copyright (c) 2022-2023 Rivos, Inc.
+ *
+ * Author(s):
+ *  Emmanuel Blot <[email protected]>
+ *  Loïc Lefort <[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/log.h"
+#include "cpu.h"
+#include "disas/disas.h"
+#include "elf.h"
+#include "exec/hwaddr.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "hw/misc/unimp.h"
+#include "hw/qdev-core.h"
+#include "hw/qdev-properties.h"
+#include "hw/riscv/ibex_common.h"
+#include "hw/sysbus.h"
+#include "monitor/monitor.h"
+
+
+static void ibex_mmio_map_device(SysBusDevice *dev, MemoryRegion *mr,
+                                 unsigned nr, hwaddr addr)
+{
+    assert(nr < dev->num_mmio);
+    assert(dev->mmio[nr].addr == (hwaddr)-1);
+    dev->mmio[nr].addr = addr;
+    memory_region_add_subregion(mr, addr, dev->mmio[nr].memory);
+}
+
+DeviceState **ibex_create_devices(const IbexDeviceDef *defs, unsigned count,
+                                  DeviceState *parent)
+{
+    DeviceState **devices = g_new0(DeviceState *, count);
+    unsigned unimp_count = 0;
+    for (unsigned idx = 0; idx < count; idx++) {
+        const IbexDeviceDef *def = &defs[idx];
+        assert(def->type);
+        devices[idx] = qdev_new(def->type);
+
+        char *name;
+        if (!strcmp(def->type, TYPE_UNIMPLEMENTED_DEVICE)) {
+            if (def->name) {
+                name = g_strdup_printf("%s[%u]", def->name, def->instance);
+            } else {
+                name = g_strdup_printf(TYPE_UNIMPLEMENTED_DEVICE "[%u]",
+                                       unimp_count);
+            }
+            unimp_count += 1u;
+        } else {
+            name = g_strdup_printf("%s[%u]", def->type, def->instance);
+        }
+        object_property_add_child(OBJECT(parent), name, OBJECT(devices[idx]));
+        g_free(name);
+    }
+    return devices;
+}
+
+void ibex_link_devices(DeviceState **devices, const IbexDeviceDef *defs,
+                       unsigned count)
+{
+    /* Link devices */
+    for (unsigned idx = 0; idx < count; idx++) {
+        DeviceState *dev = devices[idx];
+        const IbexDeviceLinkDef *link = defs[idx].link;
+        if (link) {
+            while (link->propname) {
+                DeviceState *target = devices[link->index];
+                (void)object_property_set_link(OBJECT(dev), link->propname,
+                                               OBJECT(target), &error_fatal);
+                link++;
+            }
+        }
+    }
+}
+
+void ibex_define_device_props(DeviceState **devices, const IbexDeviceDef *defs,
+                              unsigned count)
+{
+    for (unsigned idx = 0; idx < count; idx++) {
+        DeviceState *dev = devices[idx];
+        const IbexDevicePropDef *prop = defs[idx].prop;
+        if (prop) {
+            while (prop->propname) {
+                switch (prop->type) {
+                case IBEX_PROP_TYPE_BOOL:
+                    object_property_set_bool(OBJECT(dev), prop->propname,
+                                             prop->b, &error_fatal);
+                    break;
+                case IBEX_PROP_TYPE_INT:
+                    object_property_set_int(OBJECT(dev), prop->propname,
+                                            prop->i, &error_fatal);
+                    break;
+                case IBEX_PROP_TYPE_UINT:
+                    object_property_set_int(OBJECT(dev), prop->propname,
+                                            prop->u, &error_fatal);
+                    break;
+                case IBEX_PROP_TYPE_STR:
+                    object_property_set_str(OBJECT(dev), prop->propname,
+                                            prop->s, &error_fatal);
+                    break;
+                default:
+                    g_assert_not_reached();
+                    break;
+                }
+                prop++;
+            }
+        }
+    }
+}
+
+void ibex_realize_system_devices(DeviceState **devices,
+                                 const IbexDeviceDef *defs, unsigned count)
+{
+    BusState *bus = sysbus_get_default();
+
+    ibex_realize_devices(devices, bus, defs, count);
+
+    MemoryRegion *mrs[] = { get_system_memory(), NULL, NULL, NULL };
+
+    ibex_map_devices(devices, mrs, defs, count);
+}
+
+void ibex_realize_devices(DeviceState **devices, BusState *bus,
+                          const IbexDeviceDef *defs, unsigned count)
+{
+    /* Realize devices */
+    for (unsigned idx = 0; idx < count; idx++) {
+        DeviceState *dev = devices[idx];
+        const IbexDeviceDef *def = &defs[idx];
+
+        if (def->cfg) {
+            def->cfg(dev, def, DEVICE(OBJECT(dev)->parent));
+        }
+
+        if (def->memmap) {
+            SysBusDevice *busdev =
+                (SysBusDevice *)object_dynamic_cast(OBJECT(dev),
+                                                    TYPE_SYS_BUS_DEVICE);
+            if (!busdev) {
+                /* non-sysbus devices are not supported for now */
+                g_assert_not_reached();
+            }
+
+            qdev_realize_and_unref(DEVICE(busdev), bus, &error_fatal);
+        } else {
+            /* device is not connected to a bus */
+            qdev_realize_and_unref(dev, NULL, &error_fatal);
+        }
+    }
+}
+
+void ibex_map_devices(DeviceState **devices, MemoryRegion **mrs,
+                      const IbexDeviceDef *defs, unsigned count)
+{
+    for (unsigned idx = 0; idx < count; idx++) {
+        DeviceState *dev = devices[idx];
+        const IbexDeviceDef *def = &defs[idx];
+
+        if (def->memmap) {
+            SysBusDevice *busdev =
+                (SysBusDevice *)object_dynamic_cast(OBJECT(dev),
+                                                    TYPE_SYS_BUS_DEVICE);
+            if (busdev) {
+                const MemMapEntry *memmap = def->memmap;
+                unsigned mem = 0;
+                while (memmap->size) {
+                    unsigned region = IBEX_MEMMAP_GET_REGIDX(memmap->base);
+                    MemoryRegion *mr = mrs[region];
+                    if (mr) {
+                        ibex_mmio_map_device(busdev, mr, mem,
+                                             IBEX_MEMMAP_GET_ADDRESS(
+                                                 memmap->base));
+                    }
+                    mem++;
+                    memmap++;
+                }
+            }
+        }
+    }
+}
+
+void ibex_connect_devices(DeviceState **devices, const IbexDeviceDef *defs,
+                          unsigned count)
+{
+    /* Connect GPIOs (in particular, IRQs) */
+    for (unsigned idx = 0; idx < count; idx++) {
+        DeviceState *dev = devices[idx];
+        const IbexDeviceDef *def = &defs[idx];
+
+        if (def->gpio) {
+            const IbexGpioConnDef *conn = def->gpio;
+            while (conn->out.num >= 0 && conn->in.num >= 0) {
+                qemu_irq in_gpio =
+                    qdev_get_gpio_in_named(devices[conn->in.index],
+                                           conn->in.name, conn->in.num);
+
+                qdev_connect_gpio_out_named(dev, conn->out.name, conn->out.num,
+                                            in_gpio);
+                conn++;
+            }
+        }
+    }
+}
+
+void ibex_configure_devices(DeviceState **devices, BusState *bus,
+                            const IbexDeviceDef *defs, unsigned count)
+{
+    ibex_link_devices(devices, defs, count);
+    ibex_define_device_props(devices, defs, count);
+    ibex_realize_devices(devices, bus, defs, count);
+    ibex_connect_devices(devices, defs, count);
+}
+
+void ibex_unimp_configure(DeviceState *dev, const IbexDeviceDef *def,
+                          DeviceState *parent)
+{
+    if (def->name) {
+        qdev_prop_set_string(dev, "name", def->name);
+    }
+    assert(def->memmap != NULL);
+    assert(def->memmap->size != 0);
+    qdev_prop_set_uint64(dev, "size", def->memmap->size);
+}
+
+void ibex_load_kernel(AddressSpace *as)
+{
+    MachineState *ms = MACHINE(qdev_get_machine());
+
+    /* load kernel if provided */
+    if (ms->kernel_filename) {
+        uint64_t kernel_entry;
+        if (load_elf_ram_sym(ms->kernel_filename, NULL, NULL, NULL,
+                             &kernel_entry, NULL, NULL, NULL, 0, EM_RISCV, 1, 
0,
+                             as, true, NULL) <= 0) {
+            error_report("Cannot load ELF kernel %s", ms->kernel_filename);
+            exit(EXIT_FAILURE);
+        }
+
+        CPUState *cpu;
+        CPU_FOREACH(cpu) {
+            if (!as || cpu->as == as) {
+                CPURISCVState *env = &RISCV_CPU(cpu)->env;
+                env->resetvec = (target_ulong)kernel_entry;
+            }
+        }
+    }
+}
+
+uint64_t ibex_get_current_pc(void)
+{
+    CPUState *cs = current_cpu;
+
+    return cs && cs->cc->get_pc ? cs->cc->get_pc(cs) : 0u;
+}
+
+/* x0 is replaced with PC */
+static const char ibex_ireg_names[32u][4u] = {
+    "pc", "ra", "sp", "gp", "tp",  "t0",  "t1", "t2", "s0", "s1", "a0",
+    "a1", "a2", "a3", "a4", "a5",  "a6",  "a7", "s2", "s3", "s4", "s5",
+    "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6",
+};
+
+void ibex_log_vcpu_registers(uint64_t regbm)
+{
+    CPURISCVState *env = &RISCV_CPU(current_cpu)->env;
+    qemu_log_mask(CPU_LOG_TB_IN_ASM, "\n....\n");
+    if (regbm & 0x1u) {
+        qemu_log_mask(CPU_LOG_TB_IN_ASM, "%4s: 0x" TARGET_FMT_lx "\n",
+                      ibex_ireg_names[0], env->pc);
+    }
+    for (unsigned gix = 1u; gix < 32u; gix++) {
+        uint64_t mask = 1u << gix;
+        if (regbm & mask) {
+            qemu_log_mask(CPU_LOG_TB_IN_ASM, "%4s: 0x" TARGET_FMT_lx "\n",
+                          ibex_ireg_names[gix], env->gpr[gix]);
+        }
+    }
+}
+
+/*
+ * Note: this is not specific to Ibex, and might apply to any vCPU.
+ */
+static void hmp_info_ibex(Monitor *mon, const QDict *qdict)
+{
+    CPUState *cpu;
+
+    CPU_FOREACH(cpu) {
+        vaddr pc;
+        const char *symbol;
+        if (cpu->cc->get_pc) {
+            pc = cpu->cc->get_pc(cpu);
+            symbol = lookup_symbol(pc);
+        } else {
+            pc = -1;
+            symbol = "?";
+        }
+        monitor_printf(mon, "* CPU #%d: 0x%" PRIx64 " in '%s'\n",
+                       cpu->cpu_index, (uint64_t)pc, symbol);
+    }
+}
+
+static void ibex_register_types(void)
+{
+    monitor_register_hmp("ibex", true, &hmp_info_ibex);
+}
+
+type_init(ibex_register_types)
diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
index 533472e22a..70d63f56b5 100644
--- a/hw/riscv/meson.build
+++ b/hw/riscv/meson.build
@@ -3,6 +3,7 @@ riscv_ss.add(files('boot.c'))
 riscv_ss.add(when: 'CONFIG_RISCV_NUMA', if_true: files('numa.c'))
 riscv_ss.add(files('riscv_hart.c'))
 riscv_ss.add(when: 'CONFIG_OPENTITAN', if_true: files('opentitan.c'))
+riscv_ss.add(when: 'CONFIG_IBEX_COMMON', if_true: files('ibex_common.c'))
 riscv_ss.add(when: 'CONFIG_RISCV_VIRT', if_true: files('virt.c'))
 riscv_ss.add(when: 'CONFIG_SHAKTI_C', if_true: files('shakti_c.c'))
 riscv_ss.add(when: 'CONFIG_SIFIVE_E', if_true: files('sifive_e.c'))
diff --git a/include/hw/riscv/ibex_common.h b/include/hw/riscv/ibex_common.h
new file mode 100644
index 0000000000..6c7dae5cbe
--- /dev/null
+++ b/include/hw/riscv/ibex_common.h
@@ -0,0 +1,322 @@
+/*
+ * QEMU RISC-V Helpers for LowRISC OpenTitan EarlGrey and related systems
+ *
+ * Copyright (c) 2022-2023 Rivos, Inc.
+ *
+ * Author(s):
+ *  Emmanuel Blot <[email protected]>
+ *  Loïc Lefort <[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_RISCV_IBEX_COMMON_H
+#define HW_RISCV_IBEX_COMMON_H
+
+#include "qemu/osdep.h"
+#include "qom/object.h"
+#include "exec/hwaddr.h"
+#include "hw/qdev-core.h"
+
+
+/* ------------------------------------------------------------------------ */
+/* Devices & GPIOs */
+/* ------------------------------------------------------------------------ */
+
+#define IBEX_MAX_MMIO_ENTRIES 4u
+#define IBEX_MAX_GPIO_ENTRIES 16u
+
+typedef struct IbexDeviceDef IbexDeviceDef;
+
+typedef void (*ibex_dev_cfg_fn)(DeviceState *dev, const IbexDeviceDef *def,
+                                DeviceState *parent);
+
+/**
+ * Structure defining a GPIO connection (in particular, IRQs) from the current
+ * device to a target device
+ */
+typedef struct {
+    /** Source GPIO */
+    struct {
+        /** Name of source GPIO array or NULL for unnamed */
+        const char *name;
+        /** Index of source output GPIO */
+        int num;
+    } out;
+
+    /** Target GPIO */
+    struct {
+        /** Target device index */
+        int index;
+        /** Name of target input GPIO array or NULL for unnamed */
+        const char *name;
+        /** Index of target input GPIO */
+        int num;
+    } in;
+} IbexGpioConnDef;
+
+typedef struct {
+    /** Name of the property to assign the linked device to */
+    const char *propname;
+    /** Linked device index */
+    int index;
+} IbexDeviceLinkDef;
+
+/** Type of device property */
+typedef enum {
+    IBEX_PROP_TYPE_BOOL,
+    IBEX_PROP_TYPE_INT,
+    IBEX_PROP_TYPE_UINT,
+    IBEX_PROP_TYPE_STR,
+} IbexPropertyType;
+
+typedef struct {
+    /** Name of the property */
+    const char *propname;
+    /** Type of property */
+    IbexPropertyType type;
+    /** Value */
+    union {
+        bool b;
+        int64_t i;
+        uint64_t u;
+        const char *s;
+    };
+} IbexDevicePropDef;
+
+struct IbexDeviceDef {
+    /** Registered type of the device */
+    const char *type;
+    /** Optional name, may be NULL */
+    const char *name;
+    /** Instance number, default to 0 */
+    int instance;
+    /** Optional configuration function */
+    ibex_dev_cfg_fn cfg;
+    /** Array of memory map */
+    const MemMapEntry *memmap;
+    /** Array of GPIO connections */
+    const IbexGpioConnDef *gpio;
+    /** Array of linked devices */
+    const IbexDeviceLinkDef *link;
+    /** Array of properties */
+    const IbexDevicePropDef *prop;
+};
+
+/*
+ * Special memory address marked to flag a special MemMapEntry.
+ * Flagged MemMapEntry are used to select a memory region while mem mapping
+ * devices. There could be up to 4 different regions.
+ */
+#define IBEX_MEMMAP_REGIDX_COUNT 4u
+#define IBEX_MEMMAP_REGIDX_MASK \
+    ((IBEX_MEMMAP_REGIDX_COUNT) - 1u) /* address are always word-aligned */
+#define IBEX_MEMMAP_MAKE_REG(_addr_, _flag_) \
+    ((_addr_) | ((_flag_) & IBEX_MEMMAP_REGIDX_MASK))
+#define IBEX_MEMMAP_GET_REGIDX(_addr_) ((_addr_) & IBEX_MEMMAP_REGIDX_MASK)
+#define IBEX_MEMMAP_GET_ADDRESS(_addr_) ((_addr_) & ~IBEX_MEMMAP_REGIDX_MASK)
+
+/**
+ * Create memory map entries, each arg is MemMapEntry definition
+ */
+#define MEMMAPENTRIES(...) \
+    (const MemMapEntry[]) \
+    { \
+        __VA_ARGS__, \
+        { \
+            .size = 0u \
+        } \
+    }
+
+/**
+ * Create GPIO connection entries, each arg is IbexGpioConnDef definition
+ */
+#define IBEXGPIOCONNDEFS(...) \
+    (const IbexGpioConnDef[]) \
+    { \
+        __VA_ARGS__, \
+        { \
+            .out = {.num = -1 } \
+        } \
+    }
+
+/**
+ * Create device link entries, each arg is IbexDeviceLinkDef definition
+ */
+#define IBEXDEVICELINKDEFS(...) \
+    (const IbexDeviceLinkDef[]) \
+    { \
+        __VA_ARGS__, \
+        { \
+            .propname = NULL \
+        } \
+    }
+
+/**
+ * Create device property entries, each arg is IbexDevicePropDef definition
+ */
+#define IBEXDEVICEPROPDEFS(...) \
+    (const IbexDevicePropDef[]) \
+    { \
+        __VA_ARGS__, \
+        { \
+            .propname = NULL \
+        } \
+    }
+
+/**
+ * Create a IbexGpioConnDef to connect two unnamed GPIOs
+ */
+#define IBEX_GPIO(_irq_, _in_idx_, _num_) \
+    { \
+        .out = { \
+            .num = (_irq_), \
+        }, \
+        .in = { \
+            .index = (_in_idx_), \
+            .num = (_num_), \
+        } \
+    }
+
+/**
+ * Create a IbexGpioConnDef to connect a SysBus IRQ to an unnamed GPIO
+ */
+#define IBEX_GPIO_SYSBUS_IRQ(_irq_, _in_idx_, _num_) \
+    { \
+        .out = { \
+            .name = SYSBUS_DEVICE_GPIO_IRQ, \
+            .num = (_irq_), \
+        }, \
+        .in = { \
+            .index = (_in_idx_), \
+            .num = (_num_), \
+        } \
+    }
+
+/**
+ * Create a IbexLinkDeviceDef to link one device to another
+ */
+#define IBEX_DEVLINK(_pname_, _idx_) \
+    { \
+        .propname = (_pname_), .index = (_idx_), \
+    }
+
+/**
+ * Create a boolean device property
+ */
+#define IBEX_DEV_BOOL_PROP(_pname_, _b_) \
+    { \
+        .propname = (_pname_), .type = IBEX_PROP_TYPE_BOOL, .b = (_b_), \
+    }
+
+/**
+ * Create a signed integer device property
+ */
+#define IBEX_DEV_INT_PROP(_pname_, _i_) \
+    { \
+        .propname = (_pname_), .type = IBEX_PROP_TYPE_INT, .i = (_i_), \
+    }
+
+/**
+ * Create an unsigned integer device property
+ */
+#define IBEX_DEV_UINT_PROP(_pname_, _u_) \
+    { \
+        .propname = (_pname_), .type = IBEX_PROP_TYPE_UINT, .u = (_u_), \
+    }
+
+/**
+ * Create a string device property
+ */
+#define IBEX_DEV_STRING_PROP(_pname_, _s_) \
+    { \
+        .propname = (_pname_), .type = IBEX_PROP_TYPE_STR, .s = (_s_), \
+    }
+
+DeviceState **ibex_create_devices(const IbexDeviceDef *defs, unsigned count,
+                                  DeviceState *parent);
+void ibex_link_devices(DeviceState **devices, const IbexDeviceDef *defs,
+                       unsigned count);
+void ibex_define_device_props(DeviceState **devices, const IbexDeviceDef *defs,
+                              unsigned count);
+void ibex_realize_system_devices(DeviceState **devices,
+                                 const IbexDeviceDef *defs, unsigned count);
+void ibex_realize_devices(DeviceState **devices, BusState *bus,
+                          const IbexDeviceDef *defs, unsigned count);
+void ibex_connect_devices(DeviceState **devices, const IbexDeviceDef *defs,
+                          unsigned count);
+void ibex_map_devices(DeviceState **devices, MemoryRegion **mrs,
+                      const IbexDeviceDef *defs, unsigned count);
+void ibex_configure_devices(DeviceState **devices, BusState *bus,
+                            const IbexDeviceDef *defs, unsigned count);
+
+/**
+ * Utility function to configure unimplemented device.
+ * The Ibex device definition should have one defined memory entry, and an
+ * optional name.
+ */
+void ibex_unimp_configure(DeviceState *dev, const IbexDeviceDef *def,
+                          DeviceState *parent);
+
+/* ------------------------------------------------------------------------ */
+/* CPU */
+/* ------------------------------------------------------------------------ */
+
+/**
+ * Load an ELF application into a CPU address space.
+ * @as the address space to load the application into, maybe NULL to use the
+ * default address space
+ */
+void ibex_load_kernel(AddressSpace *as);
+
+/**
+ * Helper for device debugging: report the current guest PC, if any.
+ *
+ * If a HW access is performed from another device but the CPU, reported PC
+ * is 0.
+ */
+uint64_t ibex_get_current_pc(void);
+
+enum {
+    RV_GPR_PC = (1u << 0u),
+    RV_GPR_RA = (1u << 1u),
+    RV_GPR_SP = (1u << 2u),
+    RV_GPR_GP = (1u << 3u),
+    RV_GPR_TP = (1u << 4u),
+    RV_GPR_T0 = (1u << 5u),
+    RV_GPR_T1 = (1u << 6u),
+    RV_GPR_T2 = (1u << 7u),
+    RV_GPR_S0 = (1u << 8u),
+    RV_GPR_S1 = (1u << 9u),
+    RV_GPR_A0 = (1u << 10u),
+    RV_GPR_A1 = (1u << 11u),
+    RV_GPR_A2 = (1u << 12u),
+    RV_GPR_A3 = (1u << 13u),
+    RV_GPR_A4 = (1u << 14u),
+    RV_GPR_A5 = (1u << 15u),
+    RV_GPR_A6 = (1u << 16u),
+    RV_GPR_A7 = (1u << 17u),
+    RV_GPR_S2 = (1u << 18u),
+    RV_GPR_S3 = (1u << 19u),
+    RV_GPR_S4 = (1u << 20u),
+    RV_GPR_S5 = (1u << 21u),
+    RV_GPR_S6 = (1u << 22u),
+    RV_GPR_S7 = (1u << 23u),
+    RV_GPR_S8 = (1u << 24u),
+    RV_GPR_S9 = (1u << 25u),
+    RV_GPR_S10 = (1u << 26u),
+    RV_GPR_S11 = (1u << 27u),
+    RV_GPR_T3 = (1u << 28u),
+    RV_GPR_T4 = (1u << 29u),
+    RV_GPR_T5 = (1u << 30u),
+    RV_GPR_T6 = (1u << 31u),
+};
+
+/**
+ * Log current vCPU registers.
+ *
+ * @regbm is a bitmap of registers to be dumped [x1..t6], pc replace x0
+ */
+void ibex_log_vcpu_registers(uint64_t regbm);
+
+#endif /* HW_RISCV_IBEX_COMMON_H */
-- 
2.49.1


Reply via email to