diff --git a/configs/devices/riscv32-softmmu/default.mak b/configs/devices/riscv32-softmmu/default.mak index d847bd5692ec5364e4f6608c58073f75cf615bfe..65c65cc2cc69b1575a1e0b9098e5f62e5756607f 100644 --- a/configs/devices/riscv32-softmmu/default.mak +++ b/configs/devices/riscv32-softmmu/default.mak @@ -13,3 +13,4 @@ CONFIG_SIFIVE_E=y CONFIG_SIFIVE_U=y CONFIG_RISCV_VIRT=y CONFIG_OPENTITAN=y +CONFIG_ESP32_C3=y diff --git a/docs/system/riscv/esp32-c3.rst b/docs/system/riscv/esp32-c3.rst new file mode 100644 index 0000000000000000000000000000000000000000..6376d77b5f86d0d906faa6bc6793ab5c2622d39c --- /dev/null +++ b/docs/system/riscv/esp32-c3.rst @@ -0,0 +1,2 @@ +esp32/c3 Reference Platform (``esp32/c3``) +========================================== diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst index 89a866e4f4f192242efc11bece2478c6f0850ab6..f1c024efed7c6340218265ba69b13f4edf80ec92 100644 --- a/docs/system/target-riscv.rst +++ b/docs/system/target-riscv.rst @@ -66,6 +66,7 @@ undocumented; you can get a complete list by running .. toctree:: :maxdepth: 1 + riscv/esp32-c3 riscv/microchip-icicle-kit riscv/shakti-c riscv/sifive_u diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 6528ebfa3a3bbd7408a46b485f606a30e295c172..1e25b075169f1d798f42c36d503b69c654b4be28 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -6,6 +6,9 @@ config IBEX # RISC-V machines in alphabetical order +config ESP32_C3 + bool + config MICROCHIP_PFSOC bool select CADENCE_SDHCI diff --git a/hw/riscv/esp32_c3.c b/hw/riscv/esp32_c3.c new file mode 100644 index 0000000000000000000000000000000000000000..a5f1d43aaea08489497f845c35220e66ca28226b --- /dev/null +++ b/hw/riscv/esp32_c3.c @@ -0,0 +1,166 @@ +/* + * ESP32-C3-class SoC emulation + * + * Copyright (c) 2023 + * Davids Paskevics (davip00@zedat.fu-berlin.de) + * Nicolas Patzelt (nicolas.patzelt@fu-berlin.de) + * Jakob Knitter (jakok07@zedat.fu-berlin.de) + * + * 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.The 0x00001000 address is mapped to ROM with a trampoline code to 0x80000000. AUIPC instruction moves its immediate value 12 bits to the left and adds to the current PC , so t0 = 0(x7ffff<<12)+ 0x1000 = 0x80000000ww.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "hw/boards.h" +#include "hw/riscv/esp32_c3.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "hw/intc/sifive_plic.h" +#include "hw/intc/riscv_aclint.h" +#include "sysemu/sysemu.h" +#include "hw/qdev-properties.h" +#include "exec/address-spaces.h" +#include "hw/riscv/boot.h" + + +static const struct MemmapEntry { + hwaddr base; + hwaddr size; +} esp32_c3_memmap[] = { + [ESP32_C3_DROM] = { 0x3FF00000, 0x1FFFF }, + [ESP32_C3_IROM] = { 0x40000000, 0x5FFFF }, + [ESP32_C3_IRAM] = { 0x4037C000, 0x63FFF }, + [ESP32_C3_DRAM] = { 0x3FC80000, 0x5FFFF }, + [ESP32_C3_DM] = { 0x20000000, 0x7FFFFFF } +}; + +static void esp32_c3_machine_state_init(MachineState *mstate) +{ + Esp32C3MachineState *sms = RISCV_ESP32_MACHINE(mstate); + MemoryRegion *system_memory = get_system_memory(); + + /* Allow only ESP32 C3 CPU for this platform */ + if (strcmp(mstate->cpu_type, TYPE_RISCV_CPU_ESP32_C3) != 0) { + error_report("This board can only be used with ESP32 C3 CPU"); + exit(1); + } + + /* Initialize SoC */ + object_initialize_child(OBJECT(mstate), "soc", &sms->soc, + TYPE_RISCV_ESP32_SOC); + qdev_realize(DEVICE(&sms->soc), NULL, &error_abort); + + /* register RAM */ + // TODO: Deal with IRAM vs DRAM + memory_region_add_subregion(system_memory, + esp32_c3_memmap[ESP32_C3_IRAM].base, + mstate->ram); + + /* ROM reset vector */ + // TODO: Check if this is correct + // TODO: Does this make sense for our board? Code runs from ROM directly. + riscv_setup_rom_reset_vec(mstate, &sms->soc.cpus, + esp32_c3_memmap[ESP32_C3_IRAM].base, + esp32_c3_memmap[ESP32_C3_IROM].base, + esp32_c3_memmap[ESP32_C3_IROM].size, 0x0400, 0); + if (mstate->firmware) { + // We don't have any (separate) firmware to load, as this is an MCU + error_report("This board can't load firmware"); + exit(1); + } +} + +static void esp32_c3_machine_instance_init(Object *obj) +{ +} + +static void esp32_c3_machine_class_init(ObjectClass *klass, void *data) +{ + MachineClass *mc = MACHINE_CLASS(klass); + mc->desc = "RISC-V Board compatible with ES32-C3 SDK"; + mc->init = esp32_c3_machine_state_init; + mc->default_cpu_type = TYPE_RISCV_CPU_ESP32_C3; + mc->default_ram_id = "riscv.esp32.c.ram"; +} + +static const TypeInfo esp32_c3_machine_type_info = { + .name = TYPE_RISCV_ESP32_MACHINE, + .parent = TYPE_MACHINE, + .class_init = esp32_c3_machine_class_init, + .instance_init = esp32_c3_machine_instance_init, + .instance_size = sizeof(Esp32C3MachineState), +}; + +static void esp32_c3_machine_type_info_register(void) +{ + type_register_static(&esp32_c3_machine_type_info); +} +type_init(esp32_c3_machine_type_info_register) + +static void esp32_c3_soc_state_realize(DeviceState *dev, Error **errp) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + (void)ms; + Esp32C3SoCState *sss = RISCV_ESP32_SOC(dev); + MemoryRegion *system_memory = get_system_memory(); + + sysbus_realize(SYS_BUS_DEVICE(&sss->cpus), &error_abort); + + /* ROM */ + // TODO: Deal with IROM vs DROM + memory_region_init_rom(&sss->rom, OBJECT(dev), "riscv.esp32.c.rom", + esp32_c3_memmap[ESP32_C3_IROM].size, &error_fatal); + memory_region_add_subregion(system_memory, + esp32_c3_memmap[ESP32_C3_IROM].base, &sss->rom); +} + +static void esp32_c3_soc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->realize = esp32_c3_soc_state_realize; + /* + * Reasons: + * - Creates CPUS in riscv_hart_realize(), and can create unintended + * CPUs + * - Uses serial_hds in realize function, thus can't be used twice + */ + dc->user_creatable = false; +} + +static void esp32_c3_soc_instance_init(Object *obj) +{ + Esp32C3SoCState *sss = RISCV_ESP32_SOC(obj); + + object_initialize_child(obj, "cpus", &sss->cpus, TYPE_RISCV_HART_ARRAY); + + /* + * CPU type is fixed and we are not supporting passing from commandline yet. + * So let it be in instance_init. When supported should use ms->cpu_type + * instead of TYPE_RISCV_CPU_ESP32_C3 + */ + object_property_set_str(OBJECT(&sss->cpus), "cpu-type", + TYPE_RISCV_CPU_ESP32_C3, &error_abort); + object_property_set_int(OBJECT(&sss->cpus), "num-harts", 1, + &error_abort); +} + +static const TypeInfo esp32_c3_type_info = { + .name = TYPE_RISCV_ESP32_SOC, + .parent = TYPE_DEVICE, + .class_init = esp32_c3_soc_class_init, + .instance_init = esp32_c3_soc_instance_init, + .instance_size = sizeof(Esp32C3SoCState), +}; + +static void esp32_c3_type_info_register(void) +{ + type_register_static(&esp32_c3_type_info); +} + +type_init(esp32_c3_type_info_register) diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index 2f7ee81be3ca916185c00d9ae5a19e45928f871e..2bdcc914eb9885b93d7f16b2565f569a2a3f5f9d 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -8,6 +8,7 @@ riscv_ss.add(when: 'CONFIG_SHAKTI_C', if_true: files('shakti_c.c')) 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_ESP32_C3', if_true: files('esp32_c3.c')) riscv_ss.add(when: 'CONFIG_MICROCHIP_PFSOC', if_true: files('microchip_pfsoc.c')) riscv_ss.add(when: 'CONFIG_ACPI', if_true: files('virt-acpi-build.c')) diff --git a/include/hw/riscv/esp32_c3.h b/include/hw/riscv/esp32_c3.h new file mode 100644 index 0000000000000000000000000000000000000000..8ef80b3f758055ec57ffa11ea21a3179ed854dba --- /dev/null +++ b/include/hw/riscv/esp32_c3.h @@ -0,0 +1,64 @@ +/* + * ESP32-C3-class SoC emulation + * + * Copyright (c) 2023 + * Davids Paskevics (davip00@zedat.fu-berlin.de) + * Nicolas Patzelt (nicolas.patzelt@fu-berlin.de) + * Jakob Knitter (jakok07@zedat.fu-berlin.de) + * + * 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/>. + */ + +#ifndef HW_ESP32_C3_H +#define HW_ESP32_C3_H + +#include "hw/riscv/riscv_hart.h" +#include "hw/boards.h" + + + +#define TYPE_RISCV_ESP32_SOC "riscv.esp32.cclass.soc" +#define RISCV_ESP32_SOC(obj) \ + OBJECT_CHECK(Esp32C3SoCState, (obj), TYPE_RISCV_ESP32_SOC) + +typedef struct Esp32C3SoCState { + /*< private >*/ + DeviceState parent_obj; + + /*< public >*/ + RISCVHartArrayState cpus; + DeviceState *plic; + MemoryRegion rom; + +} Esp32C3SoCState; + +#define TYPE_RISCV_ESP32_MACHINE MACHINE_TYPE_NAME("esp32_c3") +#define RISCV_ESP32_MACHINE(obj) \ + OBJECT_CHECK(Esp32C3MachineState, (obj), TYPE_RISCV_ESP32_MACHINE) +typedef struct Esp32C3MachineState { + /*< private >*/ + MachineState parent_obj; + + /*< public >*/ + Esp32C3SoCState soc; +} Esp32C3MachineState; + +enum { + ESP32_C3_DROM, + ESP32_C3_IROM, + ESP32_C3_IRAM, + ESP32_C3_DRAM, + ESP32_C3_DM +}; + +#endif diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h index 04af50983e61ebdd66ca647dbe3ba6e0f83a7f3f..af05762b7126a01410d5ce0ef55b942100692d7a 100644 --- a/target/riscv/cpu-qom.h +++ b/target/riscv/cpu-qom.h @@ -35,6 +35,7 @@ #define TYPE_RISCV_CPU_BASE128 RISCV_CPU_TYPE_NAME("x-rv128") #define TYPE_RISCV_CPU_IBEX RISCV_CPU_TYPE_NAME("lowrisc-ibex") #define TYPE_RISCV_CPU_SHAKTI_C RISCV_CPU_TYPE_NAME("shakti-c") +#define TYPE_RISCV_CPU_ESP32_C3 RISCV_CPU_TYPE_NAME("esp32-c3") #define TYPE_RISCV_CPU_SIFIVE_E31 RISCV_CPU_TYPE_NAME("sifive-e31") #define TYPE_RISCV_CPU_SIFIVE_E34 RISCV_CPU_TYPE_NAME("sifive-e34") #define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51") diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 881bddf393f9fe00d50156311be09ce48d5f50c4..d04b5c88f98279079e883b86c7081423033c0798 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -520,6 +520,15 @@ static void rv32_sifive_u_cpu_init(Object *obj) cpu->cfg.pmp = true; } +static void rv32_esp32_c3_cpu_init(Object *obj) +{ + CPURISCVState *env = &RISCV_CPU(obj)->env; + set_misa(env, MXL_RV32, RVI | RVM | RVC); +#ifndef CONFIG_USER_ONLY + set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV32); +#endif +} + static void rv32_sifive_e_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; @@ -1938,6 +1947,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32_sifive_e_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32_imafcu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32_sifive_u_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_ESP32_C3, rv32_esp32_c3_cpu_init), #elif defined(TARGET_RISCV64) DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE64, rv64_base_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64_sifive_e_cpu_init),