1*29abd3d1SHuang Borong /* 2*29abd3d1SHuang Borong * QEMU RISC-V Board Compatible with the Xiangshan Kunminghu 3*29abd3d1SHuang Borong * FPGA prototype platform 4*29abd3d1SHuang Borong * 5*29abd3d1SHuang Borong * Copyright (c) 2025 Beijing Institute of Open Source Chip (BOSC) 6*29abd3d1SHuang Borong * SPDX-License-Identifier: GPL-2.0-or-later 7*29abd3d1SHuang Borong * 8*29abd3d1SHuang Borong * Provides a board compatible with the Xiangshan Kunminghu 9*29abd3d1SHuang Borong * FPGA prototype platform: 10*29abd3d1SHuang Borong * 11*29abd3d1SHuang Borong * 0) UART (16550A) 12*29abd3d1SHuang Borong * 1) CLINT (Core-Local Interruptor) 13*29abd3d1SHuang Borong * 2) IMSIC (Incoming MSI Controller) 14*29abd3d1SHuang Borong * 3) APLIC (Advanced Platform-Level Interrupt Controller) 15*29abd3d1SHuang Borong * 16*29abd3d1SHuang Borong * More information can be found in our Github repository: 17*29abd3d1SHuang Borong * https://github.com/OpenXiangShan/XiangShan 18*29abd3d1SHuang Borong * 19*29abd3d1SHuang Borong * This program is free software; you can redistribute it and/or modify it 20*29abd3d1SHuang Borong * under the terms and conditions of the GNU General Public License, 21*29abd3d1SHuang Borong * version 2 or later, as published by the Free Software Foundation. 22*29abd3d1SHuang Borong * 23*29abd3d1SHuang Borong * This program is distributed in the hope it will be useful, but WITHOUT 24*29abd3d1SHuang Borong * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 25*29abd3d1SHuang Borong * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 26*29abd3d1SHuang Borong * more details. 27*29abd3d1SHuang Borong * 28*29abd3d1SHuang Borong * You should have received a copy of the GNU General Public License along with 29*29abd3d1SHuang Borong * this program. If not, see <http://www.gnu.org/licenses/>. 30*29abd3d1SHuang Borong */ 31*29abd3d1SHuang Borong 32*29abd3d1SHuang Borong #include "qemu/osdep.h" 33*29abd3d1SHuang Borong #include "qapi/error.h" 34*29abd3d1SHuang Borong #include "system/address-spaces.h" 35*29abd3d1SHuang Borong #include "hw/boards.h" 36*29abd3d1SHuang Borong #include "hw/char/serial-mm.h" 37*29abd3d1SHuang Borong #include "hw/intc/riscv_aclint.h" 38*29abd3d1SHuang Borong #include "hw/intc/riscv_aplic.h" 39*29abd3d1SHuang Borong #include "hw/intc/riscv_imsic.h" 40*29abd3d1SHuang Borong #include "hw/qdev-properties.h" 41*29abd3d1SHuang Borong #include "hw/riscv/boot.h" 42*29abd3d1SHuang Borong #include "hw/riscv/xiangshan_kmh.h" 43*29abd3d1SHuang Borong #include "hw/riscv/riscv_hart.h" 44*29abd3d1SHuang Borong #include "system/system.h" 45*29abd3d1SHuang Borong 46*29abd3d1SHuang Borong static const MemMapEntry xiangshan_kmh_memmap[] = { 47*29abd3d1SHuang Borong [XIANGSHAN_KMH_ROM] = { 0x1000, 0xF000 }, 48*29abd3d1SHuang Borong [XIANGSHAN_KMH_UART0] = { 0x310B0000, 0x10000 }, 49*29abd3d1SHuang Borong [XIANGSHAN_KMH_CLINT] = { 0x38000000, 0x10000 }, 50*29abd3d1SHuang Borong [XIANGSHAN_KMH_APLIC_M] = { 0x31100000, 0x4000 }, 51*29abd3d1SHuang Borong [XIANGSHAN_KMH_APLIC_S] = { 0x31120000, 0x4000 }, 52*29abd3d1SHuang Borong [XIANGSHAN_KMH_IMSIC_M] = { 0x3A800000, 0x10000 }, 53*29abd3d1SHuang Borong [XIANGSHAN_KMH_IMSIC_S] = { 0x3B000000, 0x80000 }, 54*29abd3d1SHuang Borong [XIANGSHAN_KMH_DRAM] = { 0x80000000, 0x0 }, 55*29abd3d1SHuang Borong }; 56*29abd3d1SHuang Borong 57*29abd3d1SHuang Borong static DeviceState *xiangshan_kmh_create_aia(uint32_t num_harts) 58*29abd3d1SHuang Borong { 59*29abd3d1SHuang Borong int i; 60*29abd3d1SHuang Borong const MemMapEntry *memmap = xiangshan_kmh_memmap; 61*29abd3d1SHuang Borong hwaddr addr = 0; 62*29abd3d1SHuang Borong DeviceState *aplic_m = NULL; 63*29abd3d1SHuang Borong 64*29abd3d1SHuang Borong /* M-level IMSICs */ 65*29abd3d1SHuang Borong addr = memmap[XIANGSHAN_KMH_IMSIC_M].base; 66*29abd3d1SHuang Borong for (i = 0; i < num_harts; i++) { 67*29abd3d1SHuang Borong riscv_imsic_create(addr + i * IMSIC_HART_SIZE(0), i, true, 68*29abd3d1SHuang Borong 1, XIANGSHAN_KMH_IMSIC_NUM_IDS); 69*29abd3d1SHuang Borong } 70*29abd3d1SHuang Borong 71*29abd3d1SHuang Borong /* S-level IMSICs */ 72*29abd3d1SHuang Borong addr = memmap[XIANGSHAN_KMH_IMSIC_S].base; 73*29abd3d1SHuang Borong for (i = 0; i < num_harts; i++) { 74*29abd3d1SHuang Borong riscv_imsic_create(addr + 75*29abd3d1SHuang Borong i * IMSIC_HART_SIZE(XIANGSHAN_KMH_IMSIC_GUEST_BITS), 76*29abd3d1SHuang Borong i, false, 1 + XIANGSHAN_KMH_IMSIC_GUEST_BITS, 77*29abd3d1SHuang Borong XIANGSHAN_KMH_IMSIC_NUM_IDS); 78*29abd3d1SHuang Borong } 79*29abd3d1SHuang Borong 80*29abd3d1SHuang Borong /* M-level APLIC */ 81*29abd3d1SHuang Borong aplic_m = riscv_aplic_create(memmap[XIANGSHAN_KMH_APLIC_M].base, 82*29abd3d1SHuang Borong memmap[XIANGSHAN_KMH_APLIC_M].size, 83*29abd3d1SHuang Borong 0, 0, XIANGSHAN_KMH_APLIC_NUM_SOURCES, 84*29abd3d1SHuang Borong 1, true, true, NULL); 85*29abd3d1SHuang Borong 86*29abd3d1SHuang Borong /* S-level APLIC */ 87*29abd3d1SHuang Borong riscv_aplic_create(memmap[XIANGSHAN_KMH_APLIC_S].base, 88*29abd3d1SHuang Borong memmap[XIANGSHAN_KMH_APLIC_S].size, 89*29abd3d1SHuang Borong 0, 0, XIANGSHAN_KMH_APLIC_NUM_SOURCES, 90*29abd3d1SHuang Borong 1, true, false, aplic_m); 91*29abd3d1SHuang Borong 92*29abd3d1SHuang Borong return aplic_m; 93*29abd3d1SHuang Borong } 94*29abd3d1SHuang Borong 95*29abd3d1SHuang Borong static void xiangshan_kmh_soc_realize(DeviceState *dev, Error **errp) 96*29abd3d1SHuang Borong { 97*29abd3d1SHuang Borong MachineState *ms = MACHINE(qdev_get_machine()); 98*29abd3d1SHuang Borong XiangshanKmhSoCState *s = XIANGSHAN_KMH_SOC(dev); 99*29abd3d1SHuang Borong const MemMapEntry *memmap = xiangshan_kmh_memmap; 100*29abd3d1SHuang Borong MemoryRegion *system_memory = get_system_memory(); 101*29abd3d1SHuang Borong uint32_t num_harts = ms->smp.cpus; 102*29abd3d1SHuang Borong 103*29abd3d1SHuang Borong qdev_prop_set_uint32(DEVICE(&s->cpus), "num-harts", num_harts); 104*29abd3d1SHuang Borong qdev_prop_set_uint32(DEVICE(&s->cpus), "hartid-base", 0); 105*29abd3d1SHuang Borong qdev_prop_set_string(DEVICE(&s->cpus), "cpu-type", 106*29abd3d1SHuang Borong TYPE_RISCV_CPU_XIANGSHAN_KMH); 107*29abd3d1SHuang Borong sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_fatal); 108*29abd3d1SHuang Borong 109*29abd3d1SHuang Borong /* AIA */ 110*29abd3d1SHuang Borong s->irqchip = xiangshan_kmh_create_aia(num_harts); 111*29abd3d1SHuang Borong 112*29abd3d1SHuang Borong /* UART */ 113*29abd3d1SHuang Borong serial_mm_init(system_memory, memmap[XIANGSHAN_KMH_UART0].base, 2, 114*29abd3d1SHuang Borong qdev_get_gpio_in(s->irqchip, XIANGSHAN_KMH_UART0_IRQ), 115*29abd3d1SHuang Borong 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN); 116*29abd3d1SHuang Borong 117*29abd3d1SHuang Borong /* CLINT */ 118*29abd3d1SHuang Borong riscv_aclint_swi_create(memmap[XIANGSHAN_KMH_CLINT].base, 119*29abd3d1SHuang Borong 0, num_harts, false); 120*29abd3d1SHuang Borong riscv_aclint_mtimer_create(memmap[XIANGSHAN_KMH_CLINT].base + 121*29abd3d1SHuang Borong RISCV_ACLINT_SWI_SIZE, 122*29abd3d1SHuang Borong RISCV_ACLINT_DEFAULT_MTIMER_SIZE, 123*29abd3d1SHuang Borong 0, num_harts, RISCV_ACLINT_DEFAULT_MTIMECMP, 124*29abd3d1SHuang Borong RISCV_ACLINT_DEFAULT_MTIME, 125*29abd3d1SHuang Borong XIANGSHAN_KMH_CLINT_TIMEBASE_FREQ, true); 126*29abd3d1SHuang Borong 127*29abd3d1SHuang Borong /* ROM */ 128*29abd3d1SHuang Borong memory_region_init_rom(&s->rom, OBJECT(dev), "xiangshan.kunminghu.rom", 129*29abd3d1SHuang Borong memmap[XIANGSHAN_KMH_ROM].size, &error_fatal); 130*29abd3d1SHuang Borong memory_region_add_subregion(system_memory, 131*29abd3d1SHuang Borong memmap[XIANGSHAN_KMH_ROM].base, &s->rom); 132*29abd3d1SHuang Borong } 133*29abd3d1SHuang Borong 134*29abd3d1SHuang Borong static void xiangshan_kmh_soc_class_init(ObjectClass *klass, const void *data) 135*29abd3d1SHuang Borong { 136*29abd3d1SHuang Borong DeviceClass *dc = DEVICE_CLASS(klass); 137*29abd3d1SHuang Borong 138*29abd3d1SHuang Borong dc->realize = xiangshan_kmh_soc_realize; 139*29abd3d1SHuang Borong dc->user_creatable = false; 140*29abd3d1SHuang Borong } 141*29abd3d1SHuang Borong 142*29abd3d1SHuang Borong static void xiangshan_kmh_soc_instance_init(Object *obj) 143*29abd3d1SHuang Borong { 144*29abd3d1SHuang Borong XiangshanKmhSoCState *s = XIANGSHAN_KMH_SOC(obj); 145*29abd3d1SHuang Borong 146*29abd3d1SHuang Borong object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY); 147*29abd3d1SHuang Borong } 148*29abd3d1SHuang Borong 149*29abd3d1SHuang Borong static const TypeInfo xiangshan_kmh_soc_info = { 150*29abd3d1SHuang Borong .name = TYPE_XIANGSHAN_KMH_SOC, 151*29abd3d1SHuang Borong .parent = TYPE_DEVICE, 152*29abd3d1SHuang Borong .instance_size = sizeof(XiangshanKmhSoCState), 153*29abd3d1SHuang Borong .instance_init = xiangshan_kmh_soc_instance_init, 154*29abd3d1SHuang Borong .class_init = xiangshan_kmh_soc_class_init, 155*29abd3d1SHuang Borong }; 156*29abd3d1SHuang Borong 157*29abd3d1SHuang Borong static void xiangshan_kmh_soc_register_types(void) 158*29abd3d1SHuang Borong { 159*29abd3d1SHuang Borong type_register_static(&xiangshan_kmh_soc_info); 160*29abd3d1SHuang Borong } 161*29abd3d1SHuang Borong type_init(xiangshan_kmh_soc_register_types) 162*29abd3d1SHuang Borong 163*29abd3d1SHuang Borong static void xiangshan_kmh_machine_init(MachineState *machine) 164*29abd3d1SHuang Borong { 165*29abd3d1SHuang Borong XiangshanKmhState *s = XIANGSHAN_KMH_MACHINE(machine); 166*29abd3d1SHuang Borong const MemMapEntry *memmap = xiangshan_kmh_memmap; 167*29abd3d1SHuang Borong MemoryRegion *system_memory = get_system_memory(); 168*29abd3d1SHuang Borong hwaddr start_addr = memmap[XIANGSHAN_KMH_DRAM].base; 169*29abd3d1SHuang Borong 170*29abd3d1SHuang Borong /* Initialize SoC */ 171*29abd3d1SHuang Borong object_initialize_child(OBJECT(machine), "soc", &s->soc, 172*29abd3d1SHuang Borong TYPE_XIANGSHAN_KMH_SOC); 173*29abd3d1SHuang Borong qdev_realize(DEVICE(&s->soc), NULL, &error_fatal); 174*29abd3d1SHuang Borong 175*29abd3d1SHuang Borong /* Register RAM */ 176*29abd3d1SHuang Borong memory_region_add_subregion(system_memory, 177*29abd3d1SHuang Borong memmap[XIANGSHAN_KMH_DRAM].base, 178*29abd3d1SHuang Borong machine->ram); 179*29abd3d1SHuang Borong 180*29abd3d1SHuang Borong /* ROM reset vector */ 181*29abd3d1SHuang Borong riscv_setup_rom_reset_vec(machine, &s->soc.cpus, 182*29abd3d1SHuang Borong start_addr, 183*29abd3d1SHuang Borong memmap[XIANGSHAN_KMH_ROM].base, 184*29abd3d1SHuang Borong memmap[XIANGSHAN_KMH_ROM].size, 0, 0); 185*29abd3d1SHuang Borong if (machine->firmware) { 186*29abd3d1SHuang Borong riscv_load_firmware(machine->firmware, &start_addr, NULL); 187*29abd3d1SHuang Borong } 188*29abd3d1SHuang Borong 189*29abd3d1SHuang Borong /* Note: dtb has been integrated into firmware(OpenSBI) when compiling */ 190*29abd3d1SHuang Borong } 191*29abd3d1SHuang Borong 192*29abd3d1SHuang Borong static void xiangshan_kmh_machine_class_init(ObjectClass *klass, const void *data) 193*29abd3d1SHuang Borong { 194*29abd3d1SHuang Borong MachineClass *mc = MACHINE_CLASS(klass); 195*29abd3d1SHuang Borong static const char *const valid_cpu_types[] = { 196*29abd3d1SHuang Borong TYPE_RISCV_CPU_XIANGSHAN_KMH, 197*29abd3d1SHuang Borong NULL 198*29abd3d1SHuang Borong }; 199*29abd3d1SHuang Borong 200*29abd3d1SHuang Borong mc->desc = "RISC-V Board compatible with the Xiangshan " \ 201*29abd3d1SHuang Borong "Kunminghu FPGA prototype platform"; 202*29abd3d1SHuang Borong mc->init = xiangshan_kmh_machine_init; 203*29abd3d1SHuang Borong mc->max_cpus = XIANGSHAN_KMH_MAX_CPUS; 204*29abd3d1SHuang Borong mc->default_cpu_type = TYPE_RISCV_CPU_XIANGSHAN_KMH; 205*29abd3d1SHuang Borong mc->valid_cpu_types = valid_cpu_types; 206*29abd3d1SHuang Borong mc->default_ram_id = "xiangshan.kunminghu.ram"; 207*29abd3d1SHuang Borong } 208*29abd3d1SHuang Borong 209*29abd3d1SHuang Borong static const TypeInfo xiangshan_kmh_machine_info = { 210*29abd3d1SHuang Borong .name = TYPE_XIANGSHAN_KMH_MACHINE, 211*29abd3d1SHuang Borong .parent = TYPE_MACHINE, 212*29abd3d1SHuang Borong .instance_size = sizeof(XiangshanKmhState), 213*29abd3d1SHuang Borong .class_init = xiangshan_kmh_machine_class_init, 214*29abd3d1SHuang Borong }; 215*29abd3d1SHuang Borong 216*29abd3d1SHuang Borong static void xiangshan_kmh_machine_register_types(void) 217*29abd3d1SHuang Borong { 218*29abd3d1SHuang Borong type_register_static(&xiangshan_kmh_machine_info); 219*29abd3d1SHuang Borong } 220*29abd3d1SHuang Borong type_init(xiangshan_kmh_machine_register_types) 221