This patch provides an implementation of Nuclei FPGA Evaluation Kit Board as MCU mode. The Machine based on Nuclei's specification which has Customized register. The following machine is implemented:
-"Nuclei 100T": SYSTIMER, ECLIC, UART ... Signed-off-by: Wang Junqiang <wangjunqi...@iscas.ac.cn> --- default-configs/devices/riscv32-softmmu.mak | 1 + default-configs/devices/riscv64-softmmu.mak | 1 + hw/riscv/Kconfig | 9 + hw/riscv/meson.build | 1 + hw/riscv/nuclei_n.c | 276 ++++++++++++++++++++ include/hw/riscv/nuclei_n.h | 136 ++++++++++ 6 files changed, 424 insertions(+) create mode 100644 hw/riscv/nuclei_n.c create mode 100644 include/hw/riscv/nuclei_n.h diff --git a/default-configs/devices/riscv32-softmmu.mak b/default-configs/devices/riscv32-softmmu.mak index d847bd5692..52fb26ef01 100644 --- a/default-configs/devices/riscv32-softmmu.mak +++ b/default-configs/devices/riscv32-softmmu.mak @@ -13,3 +13,4 @@ CONFIG_SIFIVE_E=y CONFIG_SIFIVE_U=y CONFIG_RISCV_VIRT=y CONFIG_OPENTITAN=y +CONFIG_NUCLEI_N=y \ No newline at end of file diff --git a/default-configs/devices/riscv64-softmmu.mak b/default-configs/devices/riscv64-softmmu.mak index d5eec75f05..ff688bbbc6 100644 --- a/default-configs/devices/riscv64-softmmu.mak +++ b/default-configs/devices/riscv64-softmmu.mak @@ -13,3 +13,4 @@ CONFIG_SIFIVE_E=y CONFIG_SIFIVE_U=y CONFIG_RISCV_VIRT=y CONFIG_MICROCHIP_PFSOC=y +CONFIG_NUCLEI_N=y \ No newline at end of file diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 1de18cdcf1..427ed3afd3 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -67,3 +67,12 @@ config SPIKE select MSI_NONBROKEN select SIFIVE_CLINT select SIFIVE_PLIC + +config NUCLEI_N + bool + select MSI_NONBROKEN + select NUCLEI_SYSTIMER + select NUCLEI_ECLIC + select SIFIVE_GPIO + select NUCLEI_UART + select UNIMP \ No newline at end of file diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index 275c0f7eb7..840c2852e2 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -8,5 +8,6 @@ riscv_ss.add(when: 'CONFIG_SIFIVE_E', if_true: files('sifive_e.c')) riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u.c')) riscv_ss.add(when: 'CONFIG_SPIKE', if_true: files('spike.c')) riscv_ss.add(when: 'CONFIG_MICROCHIP_PFSOC', if_true: files('microchip_pfsoc.c')) +riscv_ss.add(when: 'CONFIG_NUCLEI_N', if_true: files('nuclei_n.c')) hw_arch += {'riscv': riscv_ss} diff --git a/hw/riscv/nuclei_n.c b/hw/riscv/nuclei_n.c new file mode 100644 index 0000000000..a95b8a7d29 --- /dev/null +++ b/hw/riscv/nuclei_n.c @@ -0,0 +1,276 @@ +/* + * Nuclei N series SOC machine interface + * + * Copyright (c) 2020 Gao ZhiYuan <alaph...@gmail.com> + * Copyright (c) 2020-2021 PLCT Lab.All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "qapi/visitor.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "hw/sysbus.h" +#include "target/riscv/cpu.h" +#include "hw/misc/unimp.h" +#include "hw/char/riscv_htif.h" +#include "hw/riscv/riscv_hart.h" +#include "hw/intc/nuclei_eclic.h" +#include "hw/char/nuclei_uart.h" +#include "hw/riscv/nuclei_n.h" +#include "hw/riscv/boot.h" +#include "chardev/char.h" +#include "sysemu/arch_init.h" +#include "sysemu/device_tree.h" +#include "sysemu/qtest.h" +#include "sysemu/sysemu.h" +#include "exec/address-spaces.h" + +#include <libfdt.h> + +static const struct MemmapEntry { + hwaddr base; + hwaddr size; +} nuclei_memmap[] = { + [HBIRD_DEBUG] = {0x0, 0x1000}, + [HBIRD_ROM] = {0x1000, 0x1000}, + [HBIRD_TIMER] = {0x2000000, 0x1000}, + [HBIRD_ECLIC] = {0xc000000, 0x10000}, + [HBIRD_GPIO] = {0x10012000, 0x1000}, + [HBIRD_UART0] = {0x10013000, 0x1000}, + [HBIRD_QSPI0] = {0x10014000, 0x1000}, + [HBIRD_PWM0] = {0x10015000, 0x1000}, + [HBIRD_UART1] = {0x10023000, 0x1000}, + [HBIRD_QSPI1] = {0x10024000, 0x1000}, + [HBIRD_PWM1] = {0x10025000, 0x1000}, + [HBIRD_QSPI2] = {0x10034000, 0x1000}, + [HBIRD_PWM2] = {0x10035000, 0x1000}, + [HBIRD_XIP] = {0x20000000, 0x10000000}, + [HBIRD_DRAM] = {0xa0000000, 0x0}, + [HBIRD_ILM] = {0x80000000, 0x20000}, + [HBIRD_DLM] = {0x90000000, 0x20000}, +}; + +static void nuclei_machine_get_uint32_prop(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + visit_type_uint32(v, name, (uint32_t *)opaque, errp); +} + +static void nuclei_machine_set_uint32_prop(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + visit_type_uint32(v, name, (uint32_t *)opaque, errp); +} + +static void nuclei_board_init(MachineState *machine) +{ + const struct MemmapEntry *memmap = nuclei_memmap; + NucleiHBState *s = HBIRD_FPGA_MACHINE(machine); + MemoryRegion *system_memory = get_system_memory(); + MemoryRegion *main_mem = g_new(MemoryRegion, 1); + MemoryRegion *flash = g_new(MemoryRegion, 1); + target_ulong start_addr = memmap[HBIRD_ILM].base; + int i; + + /* TODO: Add qtest support */ + /* Initialize SOC */ + object_initialize_child(OBJECT(machine), "soc", + &s->soc, TYPE_NUCLEI_HBIRD_SOC); + qdev_realize(DEVICE(&s->soc), NULL, &error_abort); + + memory_region_init_ram(&s->soc.ilm, NULL, "riscv.nuclei.ram.ilm", + memmap[HBIRD_ILM].size, &error_fatal); + memory_region_add_subregion(system_memory, + memmap[HBIRD_ILM].base, &s->soc.ilm); + + memory_region_init_ram(&s->soc.dlm, NULL, "riscv.nuclei.ram.dlm", + memmap[HBIRD_DLM].size, &error_fatal); + memory_region_add_subregion(system_memory, + memmap[HBIRD_DLM].base, &s->soc.dlm); + + /* register DRAM */ + memory_region_init_ram(main_mem, NULL, "riscv.nuclei.dram", + machine->ram_size, &error_fatal); + memory_region_add_subregion(system_memory, memmap[HBIRD_DRAM].base, + main_mem); + + /* Flash memory */ + memory_region_init_ram(flash, NULL, "riscv.nuclei.xip", + memmap[HBIRD_XIP].size, &error_fatal); + memory_region_add_subregion(system_memory, memmap[HBIRD_XIP].base, + flash); + + switch (s->msel) { + case MSEL_ILM: + start_addr = memmap[HBIRD_ILM].base; + break; + case MSEL_FLASH: + start_addr = memmap[HBIRD_XIP].base; + break; + case MSEL_FLASHXIP: + start_addr = memmap[HBIRD_XIP].base; + break; + case MSEL_DDR: + start_addr = memmap[HBIRD_DRAM].base; + break; + default: + start_addr = memmap[HBIRD_ILM].base; + break; + } + + /* reset vector */ + uint32_t reset_vec[8] = { + 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */ + 0x02028593, /* addi a1, t0, %pcrel_lo(1b) */ + 0xf1402573, /* csrr a0, mhartid */ +#if defined(TARGET_RISCV32) + 0x0182a283, /* lw t0, 24(t0) */ +#elif defined(TARGET_RISCV64) + 0x0182b283, /* ld t0, 24(t0) */ +#endif + 0x00028067, /* jr t0 */ + 0x00000000, + start_addr, /* start: .dword DRAM_BASE */ + 0x00000000, + }; + + for (i = 0; i < sizeof(reset_vec) >> 2; i++) { + reset_vec[i] = cpu_to_le32(reset_vec[i]); + } + rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec), + memmap[HBIRD_ROM].base, &address_space_memory); + + /* boot rom */ + if (machine->kernel_filename) { + riscv_load_kernel(machine->kernel_filename, start_addr, NULL); + } +} + +static void nuclei_soc_init(Object *obj) +{ + NucleiHBSoCState *s = RISCV_NUCLEI_HBIRD_SOC(obj); + + object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY); + + object_initialize_child(obj, "riscv.nuclei.gpio", + &s->gpio, TYPE_SIFIVE_GPIO); +} + +static void nuclei_soc_realize(DeviceState *dev, Error **errp) +{ + const struct MemmapEntry *memmap = nuclei_memmap; + MachineState *ms = MACHINE(qdev_get_machine()); + NucleiHBSoCState *s = RISCV_NUCLEI_HBIRD_SOC(dev); + MemoryRegion *sys_mem = get_system_memory(); + Error *err = NULL; + + object_property_set_str(OBJECT(&s->cpus), "cpu-type", ms->cpu_type, + &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_abort); + + /* Mask ROM */ + memory_region_init_rom(&s->internal_rom, OBJECT(dev), "riscv.nuclei.irom", + memmap[HBIRD_ROM].size, &error_fatal); + memory_region_add_subregion(sys_mem, + memmap[HBIRD_ROM].base, &s->internal_rom); + + s->eclic = nuclei_eclic_create(memmap[HBIRD_ECLIC].base, + memmap[HBIRD_ECLIC].size, HBIRD_SOC_INT_MAX); + + s->timer = nuclei_systimer_create(memmap[HBIRD_TIMER].base, + memmap[HBIRD_TIMER].size, + s->eclic, + NUCLEI_HBIRD_TIMEBASE_FREQ); + + /* GPIO */ + sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err); + if (err) { + error_propagate(errp, err); + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, memmap[HBIRD_GPIO].base); + + nuclei_uart_create(sys_mem, + memmap[HBIRD_UART0].base, + memmap[HBIRD_UART0].size, + serial_hd(0), + nuclei_eclic_get_irq(DEVICE(s->eclic), + HBIRD_SOC_INT22_IRQn)); +} + +static void nuclei_machine_instance_init(Object *obj) +{ + NucleiHBState *s = HBIRD_FPGA_MACHINE(obj); + + s->msel = 0; + object_property_add(obj, "msel", "uint32", + nuclei_machine_get_uint32_prop, + nuclei_machine_set_uint32_prop, NULL, &s->msel); + object_property_set_description(obj, "msel", + "Mode Select Startup"); +} + +static void nuclei_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Nuclei HummingBird Evaluation Kit"; + mc->init = nuclei_board_init; + mc->max_cpus = 1; + mc->default_cpu_type = NUCLEI_N_CPU; +} + +static const TypeInfo nuclei_machine_typeinfo = { + .name = MACHINE_TYPE_NAME("hbird_fpga"), + .parent = TYPE_MACHINE, + .class_init = nuclei_machine_class_init, + .instance_init = nuclei_machine_instance_init, + .instance_size = sizeof(NucleiHBState), +}; + +static void nuclei_machine_init_register_types(void) +{ + type_register_static(&nuclei_machine_typeinfo); +} + +type_init(nuclei_machine_init_register_types) + + static void nuclei_soc_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + dc->realize = nuclei_soc_realize; + dc->user_creatable = false; +} + +static const TypeInfo nuclei_soc_type_info = { + .name = TYPE_NUCLEI_HBIRD_SOC, + .parent = TYPE_DEVICE, + .instance_size = sizeof(NucleiHBSoCState), + .instance_init = nuclei_soc_init, + .class_init = nuclei_soc_class_init, +}; + +static void nuclei_soc_register_types(void) +{ + type_register_static(&nuclei_soc_type_info); +} + +type_init(nuclei_soc_register_types) diff --git a/include/hw/riscv/nuclei_n.h b/include/hw/riscv/nuclei_n.h new file mode 100644 index 0000000000..83776c5c22 --- /dev/null +++ b/include/hw/riscv/nuclei_n.h @@ -0,0 +1,136 @@ +/* + * Nuclei U series SOC machine interface + * + * Copyright (c) 2020 Gao ZhiYuan <alaph...@gmail.com> + * Copyright (c) 2020-2021 PLCT Lab.All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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/>. + */ +#ifndef HW_RISCV_NUCLEI_HBIRD_H +#define HW_RISCV_NUCLEI_HBIRD_H + +#include "hw/char/nuclei_uart.h" +#include "hw/gpio/sifive_gpio.h" +#include "hw/intc/nuclei_eclic.h" +#include "hw/intc/nuclei_systimer.h" +#include "hw/riscv/riscv_hart.h" +#include "hw/sysbus.h" + +#define TYPE_NUCLEI_HBIRD_SOC "riscv.nuclei.hbird.soc" +#define RISCV_NUCLEI_HBIRD_SOC(obj) \ + OBJECT_CHECK(NucleiHBSoCState, (obj), TYPE_NUCLEI_HBIRD_SOC) + +typedef struct NucleiHBSoCState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + RISCVHartArrayState cpus; + + DeviceState *eclic; + MemoryRegion ilm; + MemoryRegion dlm; + MemoryRegion internal_rom; + MemoryRegion xip_mem; + + DeviceState *timer; + NucLeiUARTState uart; + SIFIVEGPIOState gpio; + +} NucleiHBSoCState; + +#define TYPE_HBIRD_FPGA_MACHINE MACHINE_TYPE_NAME("hbird_fpga") +#define HBIRD_FPGA_MACHINE(obj) \ + OBJECT_CHECK(NucleiHBState, (obj), TYPE_HBIRD_FPGA_MACHINE) + +typedef struct NucleiHBState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + NucleiHBSoCState soc; + + uint32_t msel; +} NucleiHBState; + +enum { + MSEL_ILM = 1, + MSEL_FLASH = 2, + MSEL_FLASHXIP = 3, + MSEL_DDR = 4 +}; + +enum { + HBIRD_DEBUG, + HBIRD_ROM, + HBIRD_TIMER, + HBIRD_ECLIC, + HBIRD_GPIO, + HBIRD_UART0, + HBIRD_QSPI0, + HBIRD_PWM0, + HBIRD_UART1, + HBIRD_QSPI1, + HBIRD_PWM1, + HBIRD_QSPI2, + HBIRD_PWM2, + HBIRD_XIP, + HBIRD_DRAM, + HBIRD_ILM, + HBIRD_DLM +}; + +enum { + HBIRD_SOC_INT19_IRQn = 19, /*!< Device Interrupt */ + HBIRD_SOC_INT20_IRQn = 20, /*!< Device Interrupt */ + HBIRD_SOC_INT21_IRQn = 21, /*!< Device Interrupt */ + HBIRD_SOC_INT22_IRQn = 22, /*!< Device Interrupt */ + HBIRD_SOC_INT23_IRQn = 23, /*!< Device Interrupt */ + HBIRD_SOC_INT24_IRQn = 24, /*!< Device Interrupt */ + HBIRD_SOC_INT25_IRQn = 25, /*!< Device Interrupt */ + HBIRD_SOC_INT26_IRQn = 26, /*!< Device Interrupt */ + HBIRD_SOC_INT27_IRQn = 27, /*!< Device Interrupt */ + HBIRD_SOC_INT28_IRQn = 28, /*!< Device Interrupt */ + HBIRD_SOC_INT29_IRQn = 29, /*!< Device Interrupt */ + HBIRD_SOC_INT30_IRQn = 30, /*!< Device Interrupt */ + HBIRD_SOC_INT31_IRQn = 31, /*!< Device Interrupt */ + HBIRD_SOC_INT32_IRQn = 32, /*!< Device Interrupt */ + HBIRD_SOC_INT33_IRQn = 33, /*!< Device Interrupt */ + HBIRD_SOC_INT34_IRQn = 34, /*!< Device Interrupt */ + HBIRD_SOC_INT35_IRQn = 35, /*!< Device Interrupt */ + HBIRD_SOC_INT36_IRQn = 36, /*!< Device Interrupt */ + HBIRD_SOC_INT37_IRQn = 37, /*!< Device Interrupt */ + HBIRD_SOC_INT38_IRQn = 38, /*!< Device Interrupt */ + HBIRD_SOC_INT39_IRQn = 39, /*!< Device Interrupt */ + HBIRD_SOC_INT40_IRQn = 40, /*!< Device Interrupt */ + HBIRD_SOC_INT41_IRQn = 41, /*!< Device Interrupt */ + HBIRD_SOC_INT42_IRQn = 42, /*!< Device Interrupt */ + HBIRD_SOC_INT43_IRQn = 43, /*!< Device Interrupt */ + HBIRD_SOC_INT44_IRQn = 44, /*!< Device Interrupt */ + HBIRD_SOC_INT45_IRQn = 45, /*!< Device Interrupt */ + HBIRD_SOC_INT46_IRQn = 46, /*!< Device Interrupt */ + HBIRD_SOC_INT47_IRQn = 47, /*!< Device Interrupt */ + HBIRD_SOC_INT48_IRQn = 48, /*!< Device Interrupt */ + HBIRD_SOC_INT49_IRQn = 49, /*!< Device Interrupt */ + HBIRD_SOC_INT50_IRQn = 50, /*!< Device Interrupt */ + HBIRD_SOC_INT_MAX, +}; + +#if defined(TARGET_RISCV32) +#define NUCLEI_N_CPU TYPE_RISCV_CPU_NUCLEI_N307FD +#elif defined(TARGET_RISCV64) +#define NUCLEI_N_CPU TYPE_RISCV_CPU_NUCLEI_NX600FD +#endif + +#endif -- 2.17.1