hw/riscv: Initial support for BOSC's Xiangshan Kunminghu FPGA prototype

This implementation provides emulation for the Xiangshan Kunminghu
FPGA prototype platform, including support for UART, CLINT, IMSIC,
and APLIC devices. More details can be found at
https://github.com/OpenXiangShan/XiangShan

Signed-off-by: qinshaoqing <qinshaoqing@bosc.ac.cn>
Signed-off-by: Yang Wang <wangyang@bosc.ac.cn>
Signed-off-by: Yu Hu <819258943@qq.com>
Signed-off-by: Ran Wang <wangran@bosc.ac.cn>
Signed-off-by: Borong Huang <3543977024@qq.com>
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Message-ID: <20250617074222.17618-1-wangran@bosc.ac.cn>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
Huang Borong 2025-06-17 15:42:22 +08:00 committed by Alistair Francis
parent 60aab7ad11
commit 29abd3d112
8 changed files with 346 additions and 0 deletions

View file

@ -1697,6 +1697,13 @@ S: Maintained
F: hw/riscv/microblaze-v-generic.c
F: docs/system/riscv/microblaze-v-generic.rst
Xiangshan Kunminghu
M: Ran Wang <wangran@bosc.ac.cn>
S: Maintained
F: docs/system/riscv/xiangshan-kunminghu.rst
F: hw/riscv/xiangshan_kmh.c
F: include/hw/riscv/xiangshan_kmh.h
RX Machines
-----------
rx-gdbsim

View file

@ -11,3 +11,4 @@
# CONFIG_RISCV_VIRT=n
# CONFIG_MICROCHIP_PFSOC=n
# CONFIG_SHAKTI_C=n
# CONFIG_XIANGSHAN_KUNMINGHU=n

View file

@ -0,0 +1,39 @@
BOSC Xiangshan Kunminghu FPGA prototype platform (``xiangshan-kunminghu``)
==========================================================================
The ``xiangshan-kunminghu`` machine is compatible with our FPGA prototype
platform.
XiangShan is an open-source high-performance RISC-V processor project.
The third generation processor is called Kunminghu. Kunminghu is a 64-bit
RV64GCBSUHV processor core. More information can be found in our Github
repository:
https://github.com/OpenXiangShan/XiangShan
Supported devices
-----------------
The ``xiangshan-kunminghu`` machine supports the following devices:
* Up to 16 xiangshan-kunminghu cores
* Core Local Interruptor (CLINT)
* Incoming MSI Controller (IMSIC)
* Advanced Platform-Level Interrupt Controller (APLIC)
* 1 UART
Boot options
------------
The ``xiangshan-kunminghu`` machine can start using the standard ``-bios``
functionality for loading the boot image. You need to compile and link
the firmware, kernel, and Device Tree (FDT) into a single binary file,
such as ``fw_payload.bin``.
Running
-------
Below is an example command line for running the ``xiangshan-kunminghu``
machine:
.. code-block:: bash
$ qemu-system-riscv64 -machine xiangshan-kunminghu \
-smp 16 -m 16G \
-bios path/to/opensbi/platform/generic/firmware/fw_payload.bin \
-nographic

View file

@ -71,6 +71,7 @@ undocumented; you can get a complete list by running
riscv/shakti-c
riscv/sifive_u
riscv/virt
riscv/xiangshan-kunminghu
RISC-V CPU firmware
-------------------

View file

@ -119,3 +119,12 @@ config SPIKE
select HTIF
select RISCV_ACLINT
select SIFIVE_PLIC
config XIANGSHAN_KUNMINGHU
bool
default y
depends on RISCV64
select RISCV_ACLINT
select RISCV_APLIC
select RISCV_IMSIC
select SERIAL_MM

View file

@ -13,5 +13,6 @@ riscv_ss.add(when: 'CONFIG_ACPI', if_true: files('virt-acpi-build.c'))
riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files(
'riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c', 'riscv-iommu-hpm.c'))
riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c'))
riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true: files('xiangshan_kmh.c'))
hw_arch += {'riscv': riscv_ss}

220
hw/riscv/xiangshan_kmh.c Normal file
View file

@ -0,0 +1,220 @@
/*
* QEMU RISC-V Board Compatible with the Xiangshan Kunminghu
* FPGA prototype platform
*
* Copyright (c) 2025 Beijing Institute of Open Source Chip (BOSC)
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Provides a board compatible with the Xiangshan Kunminghu
* FPGA prototype platform:
*
* 0) UART (16550A)
* 1) CLINT (Core-Local Interruptor)
* 2) IMSIC (Incoming MSI Controller)
* 3) APLIC (Advanced Platform-Level Interrupt Controller)
*
* More information can be found in our Github repository:
* https://github.com/OpenXiangShan/XiangShan
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "system/address-spaces.h"
#include "hw/boards.h"
#include "hw/char/serial-mm.h"
#include "hw/intc/riscv_aclint.h"
#include "hw/intc/riscv_aplic.h"
#include "hw/intc/riscv_imsic.h"
#include "hw/qdev-properties.h"
#include "hw/riscv/boot.h"
#include "hw/riscv/xiangshan_kmh.h"
#include "hw/riscv/riscv_hart.h"
#include "system/system.h"
static const MemMapEntry xiangshan_kmh_memmap[] = {
[XIANGSHAN_KMH_ROM] = { 0x1000, 0xF000 },
[XIANGSHAN_KMH_UART0] = { 0x310B0000, 0x10000 },
[XIANGSHAN_KMH_CLINT] = { 0x38000000, 0x10000 },
[XIANGSHAN_KMH_APLIC_M] = { 0x31100000, 0x4000 },
[XIANGSHAN_KMH_APLIC_S] = { 0x31120000, 0x4000 },
[XIANGSHAN_KMH_IMSIC_M] = { 0x3A800000, 0x10000 },
[XIANGSHAN_KMH_IMSIC_S] = { 0x3B000000, 0x80000 },
[XIANGSHAN_KMH_DRAM] = { 0x80000000, 0x0 },
};
static DeviceState *xiangshan_kmh_create_aia(uint32_t num_harts)
{
int i;
const MemMapEntry *memmap = xiangshan_kmh_memmap;
hwaddr addr = 0;
DeviceState *aplic_m = NULL;
/* M-level IMSICs */
addr = memmap[XIANGSHAN_KMH_IMSIC_M].base;
for (i = 0; i < num_harts; i++) {
riscv_imsic_create(addr + i * IMSIC_HART_SIZE(0), i, true,
1, XIANGSHAN_KMH_IMSIC_NUM_IDS);
}
/* S-level IMSICs */
addr = memmap[XIANGSHAN_KMH_IMSIC_S].base;
for (i = 0; i < num_harts; i++) {
riscv_imsic_create(addr +
i * IMSIC_HART_SIZE(XIANGSHAN_KMH_IMSIC_GUEST_BITS),
i, false, 1 + XIANGSHAN_KMH_IMSIC_GUEST_BITS,
XIANGSHAN_KMH_IMSIC_NUM_IDS);
}
/* M-level APLIC */
aplic_m = riscv_aplic_create(memmap[XIANGSHAN_KMH_APLIC_M].base,
memmap[XIANGSHAN_KMH_APLIC_M].size,
0, 0, XIANGSHAN_KMH_APLIC_NUM_SOURCES,
1, true, true, NULL);
/* S-level APLIC */
riscv_aplic_create(memmap[XIANGSHAN_KMH_APLIC_S].base,
memmap[XIANGSHAN_KMH_APLIC_S].size,
0, 0, XIANGSHAN_KMH_APLIC_NUM_SOURCES,
1, true, false, aplic_m);
return aplic_m;
}
static void xiangshan_kmh_soc_realize(DeviceState *dev, Error **errp)
{
MachineState *ms = MACHINE(qdev_get_machine());
XiangshanKmhSoCState *s = XIANGSHAN_KMH_SOC(dev);
const MemMapEntry *memmap = xiangshan_kmh_memmap;
MemoryRegion *system_memory = get_system_memory();
uint32_t num_harts = ms->smp.cpus;
qdev_prop_set_uint32(DEVICE(&s->cpus), "num-harts", num_harts);
qdev_prop_set_uint32(DEVICE(&s->cpus), "hartid-base", 0);
qdev_prop_set_string(DEVICE(&s->cpus), "cpu-type",
TYPE_RISCV_CPU_XIANGSHAN_KMH);
sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_fatal);
/* AIA */
s->irqchip = xiangshan_kmh_create_aia(num_harts);
/* UART */
serial_mm_init(system_memory, memmap[XIANGSHAN_KMH_UART0].base, 2,
qdev_get_gpio_in(s->irqchip, XIANGSHAN_KMH_UART0_IRQ),
115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
/* CLINT */
riscv_aclint_swi_create(memmap[XIANGSHAN_KMH_CLINT].base,
0, num_harts, false);
riscv_aclint_mtimer_create(memmap[XIANGSHAN_KMH_CLINT].base +
RISCV_ACLINT_SWI_SIZE,
RISCV_ACLINT_DEFAULT_MTIMER_SIZE,
0, num_harts, RISCV_ACLINT_DEFAULT_MTIMECMP,
RISCV_ACLINT_DEFAULT_MTIME,
XIANGSHAN_KMH_CLINT_TIMEBASE_FREQ, true);
/* ROM */
memory_region_init_rom(&s->rom, OBJECT(dev), "xiangshan.kunminghu.rom",
memmap[XIANGSHAN_KMH_ROM].size, &error_fatal);
memory_region_add_subregion(system_memory,
memmap[XIANGSHAN_KMH_ROM].base, &s->rom);
}
static void xiangshan_kmh_soc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = xiangshan_kmh_soc_realize;
dc->user_creatable = false;
}
static void xiangshan_kmh_soc_instance_init(Object *obj)
{
XiangshanKmhSoCState *s = XIANGSHAN_KMH_SOC(obj);
object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY);
}
static const TypeInfo xiangshan_kmh_soc_info = {
.name = TYPE_XIANGSHAN_KMH_SOC,
.parent = TYPE_DEVICE,
.instance_size = sizeof(XiangshanKmhSoCState),
.instance_init = xiangshan_kmh_soc_instance_init,
.class_init = xiangshan_kmh_soc_class_init,
};
static void xiangshan_kmh_soc_register_types(void)
{
type_register_static(&xiangshan_kmh_soc_info);
}
type_init(xiangshan_kmh_soc_register_types)
static void xiangshan_kmh_machine_init(MachineState *machine)
{
XiangshanKmhState *s = XIANGSHAN_KMH_MACHINE(machine);
const MemMapEntry *memmap = xiangshan_kmh_memmap;
MemoryRegion *system_memory = get_system_memory();
hwaddr start_addr = memmap[XIANGSHAN_KMH_DRAM].base;
/* Initialize SoC */
object_initialize_child(OBJECT(machine), "soc", &s->soc,
TYPE_XIANGSHAN_KMH_SOC);
qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
/* Register RAM */
memory_region_add_subregion(system_memory,
memmap[XIANGSHAN_KMH_DRAM].base,
machine->ram);
/* ROM reset vector */
riscv_setup_rom_reset_vec(machine, &s->soc.cpus,
start_addr,
memmap[XIANGSHAN_KMH_ROM].base,
memmap[XIANGSHAN_KMH_ROM].size, 0, 0);
if (machine->firmware) {
riscv_load_firmware(machine->firmware, &start_addr, NULL);
}
/* Note: dtb has been integrated into firmware(OpenSBI) when compiling */
}
static void xiangshan_kmh_machine_class_init(ObjectClass *klass, const void *data)
{
MachineClass *mc = MACHINE_CLASS(klass);
static const char *const valid_cpu_types[] = {
TYPE_RISCV_CPU_XIANGSHAN_KMH,
NULL
};
mc->desc = "RISC-V Board compatible with the Xiangshan " \
"Kunminghu FPGA prototype platform";
mc->init = xiangshan_kmh_machine_init;
mc->max_cpus = XIANGSHAN_KMH_MAX_CPUS;
mc->default_cpu_type = TYPE_RISCV_CPU_XIANGSHAN_KMH;
mc->valid_cpu_types = valid_cpu_types;
mc->default_ram_id = "xiangshan.kunminghu.ram";
}
static const TypeInfo xiangshan_kmh_machine_info = {
.name = TYPE_XIANGSHAN_KMH_MACHINE,
.parent = TYPE_MACHINE,
.instance_size = sizeof(XiangshanKmhState),
.class_init = xiangshan_kmh_machine_class_init,
};
static void xiangshan_kmh_machine_register_types(void)
{
type_register_static(&xiangshan_kmh_machine_info);
}
type_init(xiangshan_kmh_machine_register_types)

View file

@ -0,0 +1,68 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* QEMU RISC-V Board Compatible with the Xiangshan Kunminghu
* FPGA prototype platform
*
* Copyright (c) 2025 Beijing Institute of Open Source Chip (BOSC)
*
*/
#ifndef HW_XIANGSHAN_KMH_H
#define HW_XIANGSHAN_KMH_H
#include "hw/boards.h"
#include "hw/riscv/riscv_hart.h"
#define XIANGSHAN_KMH_MAX_CPUS 16
typedef struct XiangshanKmhSoCState {
/*< private >*/
DeviceState parent_obj;
/*< public >*/
RISCVHartArrayState cpus;
DeviceState *irqchip;
MemoryRegion rom;
} XiangshanKmhSoCState;
#define TYPE_XIANGSHAN_KMH_SOC "xiangshan.kunminghu.soc"
DECLARE_INSTANCE_CHECKER(XiangshanKmhSoCState, XIANGSHAN_KMH_SOC,
TYPE_XIANGSHAN_KMH_SOC)
typedef struct XiangshanKmhState {
/*< private >*/
MachineState parent_obj;
/*< public >*/
XiangshanKmhSoCState soc;
} XiangshanKmhState;
#define TYPE_XIANGSHAN_KMH_MACHINE MACHINE_TYPE_NAME("xiangshan-kunminghu")
DECLARE_INSTANCE_CHECKER(XiangshanKmhState, XIANGSHAN_KMH_MACHINE,
TYPE_XIANGSHAN_KMH_MACHINE)
enum {
XIANGSHAN_KMH_ROM,
XIANGSHAN_KMH_UART0,
XIANGSHAN_KMH_CLINT,
XIANGSHAN_KMH_APLIC_M,
XIANGSHAN_KMH_APLIC_S,
XIANGSHAN_KMH_IMSIC_M,
XIANGSHAN_KMH_IMSIC_S,
XIANGSHAN_KMH_DRAM,
};
enum {
XIANGSHAN_KMH_UART0_IRQ = 10,
};
/* Indicating Timebase-freq (1MHZ) */
#define XIANGSHAN_KMH_CLINT_TIMEBASE_FREQ 1000000
#define XIANGSHAN_KMH_IMSIC_NUM_IDS 255
#define XIANGSHAN_KMH_IMSIC_NUM_GUESTS 7
#define XIANGSHAN_KMH_IMSIC_GUEST_BITS 3
#define XIANGSHAN_KMH_APLIC_NUM_SOURCES 96
#endif