From: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
To: Ben Dooks <ben.dooks@codethink.co.uk>,
nazar.kazakov@codethink.co.uk, joseph.baker@codethink.co.uk,
fran.redondo@codethink.co.uk, lawrence.hunter@codethink.co.uk,
liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com,
qemu-riscv@nongnu.org
Cc: qemu-devel@nongnu.org
Subject: Re: [PATCH v2 1/3] hw/riscv: add CVA6 machine
Date: Mon, 9 Jun 2025 08:24:00 -0300 [thread overview]
Message-ID: <ca6cc5a3-029a-4e6c-8dfb-076b910bfbb5@ventanamicro.com> (raw)
In-Reply-To: <20250527112437.291445-2-ben.dooks@codethink.co.uk>
On 5/27/25 8:24 AM, Ben Dooks wrote:
> Add a (currently Genesy2 based) CVA6 machine.
>
> Has SPI and UART, the GPIO and Ethernet are currently black-holed
> as there is no hardware model for them (lowRISC ethernet and Xilinx
> GPIO)
>
> Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
> ---
> v2:
> - whitespace fixes
> - use g_autofree on plic
> v1:
> - squashed in fixes for sd-card and new qemu init
> - move to spdx for cva6 machine
> - code cleanups missed in first review
> ---
> hw/riscv/Kconfig | 10 ++
> hw/riscv/cva6.c | 229 ++++++++++++++++++++++++++++++++++++++++
> hw/riscv/meson.build | 1 +
> include/hw/riscv/cva6.h | 85 +++++++++++++++
> 4 files changed, 325 insertions(+)
> create mode 100644 hw/riscv/cva6.c
> create mode 100644 include/hw/riscv/cva6.h
>
> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> index e6a0ac1fa1..b96f6fa014 100644
> --- a/hw/riscv/Kconfig
> +++ b/hw/riscv/Kconfig
> @@ -9,6 +9,16 @@ config IBEX
>
> # RISC-V machines in alphabetical order
>
> +config CVA6
> + bool
> + default y
> + depends on RISCV32 || RISCV64
> + select DEVICE_TREE
> + select SIFIVE_PLIC
> + select XILINX_SPI
> + select RISCV_ACLINT
> + select UNIMP
> +
> config MICROCHIP_PFSOC
> bool
> default y
> diff --git a/hw/riscv/cva6.c b/hw/riscv/cva6.c
> new file mode 100644
> index 0000000000..3adfa8b5cc
> --- /dev/null
> +++ b/hw/riscv/cva6.c
> @@ -0,0 +1,229 @@
> +/*
> + * QEMU RISC-V Board for OpenHW CVA6 SoC
> + *
> + * Copyright (c) 2025 Codethink Ltd
> + * Ben Dooks <ben.dooks@codethink.co.uk>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/error-report.h"
> +#include "qemu/units.h"
> +#include "qapi/error.h"
> +#include "qapi/visitor.h"
> +#include "hw/boards.h"
> +#include "hw/irq.h"
> +#include "hw/loader.h"
> +#include "hw/sysbus.h"
> +#include "hw/misc/unimp.h"
> +
> +#include "hw/sd/sd.h"
> +#include "hw/ssi/ssi.h"
> +
> +#include "hw/riscv/cva6.h"
> +#include "hw/riscv/boot.h"
> +#include "hw/intc/riscv_aclint.h"
> +
> +#include "system/system.h"
> +
> +#include <libfdt.h>
> +
> +#define CVA6_ROM_BASE 0x10000
> +
> +static const MemMapEntry cva6_memmap[] = {
> + [CVA6_DEBUG] = { 0x0000000, 0x1000 },
> + [CVA6_ROM] = { CVA6_ROM_BASE, 0x10000 },
> + [CVA6_CLINT] = { 0x2000000, 0xC0000 },
> + [CVA6_PLIC] = { 0xC000000, 0x4000000 },
> + [CVA6_UART] = { 0x10000000, 0x1000 },
> + [CVA6_TIMER] = { 0x18000000, 0x10000 },
> + [CVA6_SPI] = { 0x20000000, 0x800000 },
> + [CVA6_ETHERNET] = { 0x30000000, 0x10000 },
> + [CVA6_GPIO] = { 0x40000000, 0x1000 },
> + [CVA6_DRAM] = { 0x80000000, 0x40000000 },
> +};
> +
> +static void cva6_machine_init(MachineState *machine)
> +{
> + MachineClass *mc = MACHINE_GET_CLASS(machine);
> + MemoryRegion *sys_mem = get_system_memory();
> + hwaddr dram_addr = cva6_memmap[CVA6_DRAM].base;
> + CVA6State *s = CVA6_MACHINE(machine);
> + RISCVBootInfo boot_info;
> +
> + object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_CVA6);
> + qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
> +
> + if (machine->ram_size > mc->default_ram_size) {
> + error_report("RAM size is too big for DRAM area");
> + exit(EXIT_FAILURE);
> + }
> +
> + memory_region_add_subregion(sys_mem, dram_addr, machine->ram);
> + riscv_boot_info_init(&boot_info, &s->soc.cpus);
> +
> + if (machine->firmware) {
> + hwaddr firmware_load_addr = cva6_memmap[CVA6_ROM].base;
> + riscv_load_firmware(machine->firmware, &firmware_load_addr, NULL);
> + }
> +
> + if (machine->kernel_filename) {
> + /* note - we've not tested just loading the kernel w/o uboot */
> + riscv_load_kernel(machine, &boot_info, dram_addr, false, NULL);
> + }
> +
> +}
> +
> +static void cva6_machine_class_init(ObjectClass *oc, const void *data)
> +{
> + MachineClass *mc = MACHINE_CLASS(oc);
> +
> + mc->desc = "RISC-V board for CVA6";
> + mc->init = cva6_machine_init;
> + mc->max_cpus = 1;
> + mc->default_ram_id = "cva6.ram";
> + /* start with "max" cpu type until we sort out CVA6 type */
> + mc->default_cpu_type = TYPE_RISCV_CPU_MAX;
> + mc->default_ram_size = cva6_memmap[CVA6_DRAM].size;
> +};
> +
> +static void cva6_soc_init(Object *obj)
> +{
> + CVA6SoCState *s = RISCV_CVA6(obj);
> +
> + object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY);
> +}
> +
> +static void cva6_add_spi(CVA6SoCState *s, const MemMapEntry *map)
> +{
> + DriveInfo *dinfo;
> + BlockBackend *blk;
> + DeviceState *card_dev;
> + qemu_irq sd_cs;
> + DeviceState *sddev;
> + SysBusDevice *busdev;
> + DeviceState *spi_dev;
> + SSIBus *spi;
> +
> + spi_dev = qdev_new("xlnx.xps-spi");
> + qdev_prop_set_uint8(spi_dev, "num-ss-bits", 1);
> + qdev_prop_set_string(spi_dev, "endianness", "little");
> +
> + busdev = SYS_BUS_DEVICE(spi_dev);
> + sysbus_realize_and_unref(busdev, &error_fatal);
> + sysbus_mmio_map(busdev, 0, map->base);
> + sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(DEVICE(s->plic), CVA6_SPI_IRQ));
> +
> + spi = (SSIBus *)qdev_get_child_bus(spi_dev, "spi");
> +
> + sddev = ssi_create_peripheral(spi, "ssi-sd");
> + sd_cs = qdev_get_gpio_in_named(sddev, SSI_GPIO_CS, 0);
> + sysbus_connect_irq(busdev, 1, sd_cs);
> +
> + dinfo = drive_get(IF_SD, 0, 0);
> + blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
> + card_dev = qdev_new(TYPE_SD_CARD_SPI);
> + qdev_prop_set_drive_err(card_dev, "drive", blk, &error_fatal);
> +
> + qdev_realize_and_unref(card_dev, qdev_get_child_bus(sddev, "sd-bus"), &error_fatal);
> +}
> +
> +static void not_implemented(const char *name, const MemMapEntry *map)
> +{
> + create_unimplemented_device(name, map->base, map->size);
> +}
> +
> +static void cva6_soc_realize(DeviceState *dev_soc, Error **errp)
> +{
> + MemoryRegion *system_memory = get_system_memory();
> + MachineState *ms = MACHINE(qdev_get_machine());
> + CVA6SoCState *s = RISCV_CVA6(dev_soc);
> + const MemMapEntry *memmap = cva6_memmap;
> + MemoryRegion *rom = g_new(MemoryRegion, 1);
> + g_autofree char *plic_hart_config;
> +
> + object_property_set_str(OBJECT(&s->cpus), "cpu-type", ms->cpu_type,
> + &error_abort);
> + object_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus,
> + &error_abort);
> + object_property_set_int(OBJECT(&s->cpus), "resetvec", CVA6_ROM_BASE,
> + &error_abort);
> + sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_fatal);
> +
> + /* boot rom */
> + memory_region_init_rom(rom, OBJECT(dev_soc), "riscv.cva6.bootrom",
> + memmap[CVA6_ROM].size, &error_fatal);
> + memory_region_add_subregion(system_memory, memmap[CVA6_ROM].base,
> + rom);
> +
> + /* create PLIC hart topology configuration string */
> + plic_hart_config = riscv_plic_hart_config_string(ms->smp.cpus);
> +
> + /* MMIO */
> + s->plic = sifive_plic_create(memmap[CVA6_PLIC].base,
> + plic_hart_config, ms->smp.cpus, 0,
> + CVA6_PLIC_NUM_SOURCES,
> + CVA6_PLIC_NUM_PRIORITIES,
> + CVA6_PLIC_PRIORITY_BASE,
> + CVA6_PLIC_PENDING_BASE,
> + CVA6_PLIC_ENABLE_BASE,
> + CVA6_PLIC_ENABLE_STRIDE,
> + CVA6_PLIC_CONTEXT_BASE,
> + CVA6_PLIC_CONTEXT_STRIDE,
> + memmap[CVA6_PLIC].size);
> +
> + riscv_aclint_swi_create(memmap[CVA6_CLINT].base, 0,
> + ms->smp.cpus, false);
> +
> + riscv_aclint_mtimer_create(
> + memmap[CVA6_CLINT].base + RISCV_ACLINT_SWI_SIZE,
> + RISCV_ACLINT_DEFAULT_MTIMER_SIZE, 0, ms->smp.cpus,
> + RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME,
> + CLINT_TIMEBASE_FREQ, true);
> +
> + /* something in cva6-sdk uboot seems to prod the debug
> + * unit by accident, so make it not implemented */
> + not_implemented("debug", &memmap[CVA6_DEBUG]);
> +
> + /* 16550 uart, one 32bit register per 32bit word */
> +
> + serial_mm_init(system_memory, memmap[CVA6_UART].base, 2,
> + qdev_get_gpio_in(DEVICE(s->plic), CVA6_UART_IRQ),
> + 50*1000*10000,
> + serial_hd(0), DEVICE_LITTLE_ENDIAN);
> +
> + /* just unimplement the timers, network and gpio here for now.
> + * no-one seems to be using the apb timer block anyway*/
> + not_implemented("net", &memmap[CVA6_ETHERNET]);
> + not_implemented("gpio", &memmap[CVA6_GPIO]);
> + not_implemented("timer", &memmap[CVA6_TIMER]);
> +
> + /* connect xilinx spi block here */
> + cva6_add_spi(s, &memmap[CVA6_SPI]);
> +}
> +
> +static void cva6_soc_class_init(ObjectClass *oc, const void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(oc);
> +
> + dc->realize = cva6_soc_realize;
> + dc->user_creatable = false;
> +};
> +
> +static const TypeInfo cva6_types[] = {
> + {
> + .name = TYPE_RISCV_CVA6,
> + .parent = TYPE_DEVICE,
> + .instance_size = sizeof(CVA6SoCState),
> + .instance_init = cva6_soc_init,
> + .class_init = cva6_soc_class_init,
> + }, {
> + .name = TYPE_CVA6_MACHINE,
> + .parent = TYPE_MACHINE,
> + .instance_size = sizeof(CVA6State),
> + .class_init = cva6_machine_class_init,
> + }
> +};
> +
> +DEFINE_TYPES(cva6_types)
> diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
> index c22f3a7216..a32fffab63 100644
> --- a/hw/riscv/meson.build
> +++ b/hw/riscv/meson.build
> @@ -2,6 +2,7 @@ riscv_ss = ss.source_set()
> 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_CVA6', if_true: files('cva6.c'))
> riscv_ss.add(when: 'CONFIG_OPENTITAN', if_true: files('opentitan.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'))
> diff --git a/include/hw/riscv/cva6.h b/include/hw/riscv/cva6.h
> new file mode 100644
> index 0000000000..8f6172e8b8
> --- /dev/null
> +++ b/include/hw/riscv/cva6.h
> @@ -0,0 +1,85 @@
> +/*
> + * QEMU RISC-V Board for OpenHW CVA6 SoC
> + * https://github.com/openhwgroup/cva6/tree/master/corev_apu
> + *
> + * Copyright (c) 2025 Codethink Ltd
> + * Ben Dooks <ben.dooks@codethink.co.uk>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef HW_CVA6_H
> +#define HW_CVA6_H
> +
> +#include "hw/riscv/riscv_hart.h"
> +#include "hw/intc/sifive_plic.h"
> +#include "hw/char/serial-mm.h"
> +
> +#include "hw/boards.h"
> +#include "hw/sysbus.h"
> +#include "qom/object.h"
> +
> +#define TYPE_RISCV_CVA6 "riscv.cva6.soc"
> +OBJECT_DECLARE_SIMPLE_TYPE(CVA6SoCState, RISCV_CVA6)
> +
> +typedef struct CVA6SoCState {
> + /*< private >*/
> + DeviceState parent_obj;
> +
> + /*< public >*/
> + RISCVHartArrayState cpus;
> + DeviceState *plic;
> + MemoryRegion rom;
> +
> + uint32_t resetvec;
> +} CVA6SoCState;
> +
> +#define TYPE_CVA6_MACHINE MACHINE_TYPE_NAME("cva6")
> +OBJECT_DECLARE_SIMPLE_TYPE(CVA6State, CVA6_MACHINE)
> +
> +typedef struct CVA6State {
> + /*< private >*/
> + MachineState parent_obj;
> +
> + /*< public >*/
> + CVA6SoCState soc;
> +}
> +CVA6State;
> +
> +enum {
> + CVA6_DEBUG,
> + CVA6_ROM,
> + CVA6_CLINT,
> + CVA6_PLIC,
> + CVA6_UART,
> + CVA6_TIMER,
> + CVA6_SPI,
> + CVA6_ETHERNET,
> + CVA6_GPIO,
> + CVA6_DRAM,
> +};
> +
> +enum {
> + CVA6_UART_IRQ = 1,
> + CVA6_SPI_IRQ = 2,
> + CVA6_ETH_IRQ = 3,
> + CVA6_TIMER0_OVF_IRQ = 4,
> + CVA6_TIMER0_CMP_IRQ = 5,
> + CVA6_TIMER1_OVF_IRQ = 6,
> + CVA6_TIMER1_CMP_IRQ = 7,
> +};
> +
> +#define CLINT_TIMEBASE_FREQ 25000000
> +
> +/* plic register interface in corev_apu/rv_plic/rtl/plic_regmap.sv */
> +
I believe you've missed my comment in v1:
"Where is this file? It's not on QEMU or Linux.
I'm assuming that you're referring to plic_regmap.sv from this repo:
https://github.com/openhwgroup/cva6/tree/master/corev_apu
If that's the case we need to point to this repo in the comment. The commit
msg also works."
Please add the github link in the comment. Thanks,
Daniel
> +#define CVA6_PLIC_NUM_SOURCES 32
> +#define CVA6_PLIC_NUM_PRIORITIES 7
> +#define CVA6_PLIC_PRIORITY_BASE 0x0000
> +#define CVA6_PLIC_PENDING_BASE 0x1000
> +#define CVA6_PLIC_ENABLE_BASE 0x2000
> +#define CVA6_PLIC_ENABLE_STRIDE 0x80
> +#define CVA6_PLIC_CONTEXT_BASE 0x200000
> +#define CVA6_PLIC_CONTEXT_STRIDE 0x1000
> +
> +#endif /* HW_CVA6_H */
next prev parent reply other threads:[~2025-06-09 12:31 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-05-27 11:24 Add initial CVA6 implementaiton Ben Dooks
2025-05-27 11:24 ` [PATCH v2 1/3] hw/riscv: add CVA6 machine Ben Dooks
2025-06-09 11:24 ` Daniel Henrique Barboza [this message]
2025-06-09 11:32 ` Ben Dooks
2025-06-09 12:03 ` Daniel Henrique Barboza
2025-05-27 11:24 ` [PATCH v2 2/3] target/riscv: add cva6 core type Ben Dooks
2025-06-07 20:17 ` Daniel Henrique Barboza
2025-06-09 10:40 ` Ben Dooks
2025-06-09 11:30 ` Daniel Henrique Barboza
2025-06-09 11:47 ` Ben Dooks
2025-06-09 12:28 ` Daniel Henrique Barboza
2025-06-09 11:59 ` Ben Dooks
2025-06-09 12:30 ` Daniel Henrique Barboza
2025-05-27 11:24 ` [PATCH v2 3/3] hw/riscv: set cva6 to use TYPE_RISCV_CPU_CVA6 Ben Dooks
2025-06-07 20:22 ` Add initial CVA6 implementaiton Daniel Henrique Barboza
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ca6cc5a3-029a-4e6c-8dfb-076b910bfbb5@ventanamicro.com \
--to=dbarboza@ventanamicro.com \
--cc=ben.dooks@codethink.co.uk \
--cc=fran.redondo@codethink.co.uk \
--cc=joseph.baker@codethink.co.uk \
--cc=lawrence.hunter@codethink.co.uk \
--cc=liwei1518@gmail.com \
--cc=nazar.kazakov@codethink.co.uk \
--cc=qemu-devel@nongnu.org \
--cc=qemu-riscv@nongnu.org \
--cc=zhiwei_liu@linux.alibaba.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.