diff mbox series

[RFC,5/5] Nuclei FPGA Evaluation Kit MCU Machine

Message ID 20210507081654.11056-6-wangjunqiang@iscas.ac.cn
State New
Headers show
Series RISC-V:support Nuclei FPGA Evaluation Kit | expand

Commit Message

Wang Junqiang May 7, 2021, 8:16 a.m. UTC
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 <wangjunqiang@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 mbox series

Patch

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 <alapha23@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 <alapha23@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