summary refs log tree commit diff stats
path: root/hw/riscv
diff options
context:
space:
mode:
Diffstat (limited to 'hw/riscv')
-rw-r--r--hw/riscv/Kconfig70
-rw-r--r--hw/riscv/meson.build12
-rw-r--r--hw/riscv/microchip_pfsoc.c437
-rw-r--r--hw/riscv/opentitan.c1
-rw-r--r--hw/riscv/riscv_hart.c3
-rw-r--r--hw/riscv/riscv_htif.c261
-rw-r--r--hw/riscv/sifive_clint.c262
-rw-r--r--hw/riscv/sifive_e.c12
-rw-r--r--hw/riscv/sifive_e_prci.c125
-rw-r--r--hw/riscv/sifive_gpio.c397
-rw-r--r--hw/riscv/sifive_plic.c524
-rw-r--r--hw/riscv/sifive_test.c100
-rw-r--r--hw/riscv/sifive_u.c41
-rw-r--r--hw/riscv/sifive_u_otp.c191
-rw-r--r--hw/riscv/sifive_u_prci.c169
-rw-r--r--hw/riscv/sifive_uart.c194
-rw-r--r--hw/riscv/spike.c7
-rw-r--r--hw/riscv/trace-events7
-rw-r--r--hw/riscv/trace.h1
-rw-r--r--hw/riscv/virt.c9
20 files changed, 537 insertions, 2286 deletions
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index 28947ef3e0..2df978fe8d 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -1,50 +1,62 @@
-config HTIF
+config IBEX
     bool
 
-config HART
+config MICROCHIP_PFSOC
     bool
+    select CADENCE_SDHCI
+    select MCHP_PFSOC_MMUART
+    select MSI_NONBROKEN
+    select SIFIVE_CLINT
+    select SIFIVE_PDMA
+    select SIFIVE_PLIC
+    select UNIMP
 
-config IBEX
+config OPENTITAN
     bool
+    select IBEX
+    select UNIMP
 
-config SIFIVE
+config RISCV_VIRT
     bool
+    imply PCI_DEVICES
+    imply TEST_DEVICES
+    select GOLDFISH_RTC
     select MSI_NONBROKEN
+    select PCI
+    select PCI_EXPRESS_GENERIC_BRIDGE
+    select PFLASH_CFI01
+    select SERIAL
+    select SIFIVE_CLINT
+    select SIFIVE_PLIC
+    select SIFIVE_TEST
+    select VIRTIO_MMIO
 
 config SIFIVE_E
     bool
-    select HART
-    select SIFIVE
+    select MSI_NONBROKEN
+    select SIFIVE_CLINT
+    select SIFIVE_GPIO
+    select SIFIVE_PLIC
+    select SIFIVE_UART
+    select SIFIVE_E_PRCI
     select UNIMP
 
 config SIFIVE_U
     bool
     select CADENCE
-    select HART
-    select SIFIVE
+    select MSI_NONBROKEN
+    select SIFIVE_CLINT
+    select SIFIVE_GPIO
+    select SIFIVE_PDMA
+    select SIFIVE_PLIC
+    select SIFIVE_UART
+    select SIFIVE_U_OTP
+    select SIFIVE_U_PRCI
     select UNIMP
 
 config SPIKE
     bool
-    select HART
     select HTIF
-    select SIFIVE
-
-config OPENTITAN
-    bool
-    select IBEX
-    select HART
-    select UNIMP
-
-config RISCV_VIRT
-    bool
-    imply PCI_DEVICES
-    imply TEST_DEVICES
-    select PCI
-    select HART
-    select SERIAL
-    select GOLDFISH_RTC
-    select VIRTIO_MMIO
-    select PCI_EXPRESS_GENERIC_BRIDGE
-    select PFLASH_CFI01
-    select SIFIVE
+    select MSI_NONBROKEN
+    select SIFIVE_CLINT
+    select SIFIVE_PLIC
diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
index fe2ea75f65..275c0f7eb7 100644
--- a/hw/riscv/meson.build
+++ b/hw/riscv/meson.build
@@ -1,20 +1,12 @@
 riscv_ss = ss.source_set()
 riscv_ss.add(files('boot.c'), fdt)
 riscv_ss.add(files('numa.c'))
-riscv_ss.add(when: 'CONFIG_HART', if_true: files('riscv_hart.c'))
+riscv_ss.add(files('riscv_hart.c'))
 riscv_ss.add(when: 'CONFIG_OPENTITAN', if_true: files('opentitan.c'))
 riscv_ss.add(when: 'CONFIG_RISCV_VIRT', if_true: files('virt.c'))
-riscv_ss.add(when: 'CONFIG_SIFIVE', if_true: files('sifive_clint.c'))
-riscv_ss.add(when: 'CONFIG_SIFIVE', if_true: files('sifive_gpio.c'))
-riscv_ss.add(when: 'CONFIG_SIFIVE', if_true: files('sifive_plic.c'))
-riscv_ss.add(when: 'CONFIG_SIFIVE', if_true: files('sifive_test.c'))
-riscv_ss.add(when: 'CONFIG_SIFIVE', if_true: files('sifive_uart.c'))
 riscv_ss.add(when: 'CONFIG_SIFIVE_E', if_true: files('sifive_e.c'))
-riscv_ss.add(when: 'CONFIG_SIFIVE_E', if_true: files('sifive_e_prci.c'))
 riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u.c'))
-riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u_otp.c'))
-riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u_prci.c'))
-riscv_ss.add(when: 'CONFIG_SPIKE', if_true: files('riscv_htif.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'))
 
 hw_arch += {'riscv': riscv_ss}
diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
new file mode 100644
index 0000000000..4627179cd3
--- /dev/null
+++ b/hw/riscv/microchip_pfsoc.c
@@ -0,0 +1,437 @@
+/*
+ * QEMU RISC-V Board Compatible with Microchip PolarFire SoC Icicle Kit
+ *
+ * Copyright (c) 2020 Wind River Systems, Inc.
+ *
+ * Author:
+ *   Bin Meng <bin.meng@windriver.com>
+ *
+ * Provides a board compatible with the Microchip PolarFire SoC Icicle Kit
+ *
+ * 0) CLINT (Core Level Interruptor)
+ * 1) PLIC (Platform Level Interrupt Controller)
+ * 2) eNVM (Embedded Non-Volatile Memory)
+ * 3) MMUARTs (Multi-Mode UART)
+ * 4) Cadence eMMC/SDHC controller and an SD card connected to it
+ * 5) SiFive Platform DMA (Direct Memory Access Controller)
+ * 6) GEM (Gigabit Ethernet MAC Controller)
+ *
+ * This board currently generates devicetree dynamically that indicates at least
+ * two harts and up to five harts.
+ *
+ * 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 "qemu/error-report.h"
+#include "qemu/log.h"
+#include "qemu/units.h"
+#include "qemu/cutils.h"
+#include "qapi/error.h"
+#include "hw/boards.h"
+#include "hw/irq.h"
+#include "hw/loader.h"
+#include "hw/sysbus.h"
+#include "chardev/char.h"
+#include "hw/cpu/cluster.h"
+#include "target/riscv/cpu.h"
+#include "hw/misc/unimp.h"
+#include "hw/riscv/boot.h"
+#include "hw/riscv/riscv_hart.h"
+#include "hw/riscv/microchip_pfsoc.h"
+#include "hw/intc/sifive_clint.h"
+#include "hw/intc/sifive_plic.h"
+#include "sysemu/sysemu.h"
+
+/*
+ * The BIOS image used by this machine is called Hart Software Services (HSS).
+ * See https://github.com/polarfire-soc/hart-software-services
+ */
+#define BIOS_FILENAME   "hss.bin"
+#define RESET_VECTOR    0x20220000
+
+/* CLINT timebase frequency */
+#define CLINT_TIMEBASE_FREQ 1000000
+
+/* GEM version */
+#define GEM_REVISION    0x0107010c
+
+static const struct MemmapEntry {
+    hwaddr base;
+    hwaddr size;
+} microchip_pfsoc_memmap[] = {
+    [MICROCHIP_PFSOC_DEBUG] =           {        0x0,     0x1000 },
+    [MICROCHIP_PFSOC_E51_DTIM] =        {  0x1000000,     0x2000 },
+    [MICROCHIP_PFSOC_BUSERR_UNIT0] =    {  0x1700000,     0x1000 },
+    [MICROCHIP_PFSOC_BUSERR_UNIT1] =    {  0x1701000,     0x1000 },
+    [MICROCHIP_PFSOC_BUSERR_UNIT2] =    {  0x1702000,     0x1000 },
+    [MICROCHIP_PFSOC_BUSERR_UNIT3] =    {  0x1703000,     0x1000 },
+    [MICROCHIP_PFSOC_BUSERR_UNIT4] =    {  0x1704000,     0x1000 },
+    [MICROCHIP_PFSOC_CLINT] =           {  0x2000000,    0x10000 },
+    [MICROCHIP_PFSOC_L2CC] =            {  0x2010000,     0x1000 },
+    [MICROCHIP_PFSOC_DMA] =             {  0x3000000,   0x100000 },
+    [MICROCHIP_PFSOC_L2LIM] =           {  0x8000000,  0x2000000 },
+    [MICROCHIP_PFSOC_PLIC] =            {  0xc000000,  0x4000000 },
+    [MICROCHIP_PFSOC_MMUART0] =         { 0x20000000,     0x1000 },
+    [MICROCHIP_PFSOC_SYSREG] =          { 0x20002000,     0x2000 },
+    [MICROCHIP_PFSOC_MPUCFG] =          { 0x20005000,     0x1000 },
+    [MICROCHIP_PFSOC_EMMC_SD] =         { 0x20008000,     0x1000 },
+    [MICROCHIP_PFSOC_MMUART1] =         { 0x20100000,     0x1000 },
+    [MICROCHIP_PFSOC_MMUART2] =         { 0x20102000,     0x1000 },
+    [MICROCHIP_PFSOC_MMUART3] =         { 0x20104000,     0x1000 },
+    [MICROCHIP_PFSOC_MMUART4] =         { 0x20106000,     0x1000 },
+    [MICROCHIP_PFSOC_GEM0] =            { 0x20110000,     0x2000 },
+    [MICROCHIP_PFSOC_GEM1] =            { 0x20112000,     0x2000 },
+    [MICROCHIP_PFSOC_GPIO0] =           { 0x20120000,     0x1000 },
+    [MICROCHIP_PFSOC_GPIO1] =           { 0x20121000,     0x1000 },
+    [MICROCHIP_PFSOC_GPIO2] =           { 0x20122000,     0x1000 },
+    [MICROCHIP_PFSOC_ENVM_CFG] =        { 0x20200000,     0x1000 },
+    [MICROCHIP_PFSOC_ENVM_DATA] =       { 0x20220000,    0x20000 },
+    [MICROCHIP_PFSOC_IOSCB_CFG] =       { 0x37080000,     0x1000 },
+    [MICROCHIP_PFSOC_DRAM] =            { 0x80000000,        0x0 },
+};
+
+static void microchip_pfsoc_soc_instance_init(Object *obj)
+{
+    MachineState *ms = MACHINE(qdev_get_machine());
+    MicrochipPFSoCState *s = MICROCHIP_PFSOC(obj);
+
+    object_initialize_child(obj, "e-cluster", &s->e_cluster, TYPE_CPU_CLUSTER);
+    qdev_prop_set_uint32(DEVICE(&s->e_cluster), "cluster-id", 0);
+
+    object_initialize_child(OBJECT(&s->e_cluster), "e-cpus", &s->e_cpus,
+                            TYPE_RISCV_HART_ARRAY);
+    qdev_prop_set_uint32(DEVICE(&s->e_cpus), "num-harts", 1);
+    qdev_prop_set_uint32(DEVICE(&s->e_cpus), "hartid-base", 0);
+    qdev_prop_set_string(DEVICE(&s->e_cpus), "cpu-type",
+                         TYPE_RISCV_CPU_SIFIVE_E51);
+    qdev_prop_set_uint64(DEVICE(&s->e_cpus), "resetvec", RESET_VECTOR);
+
+    object_initialize_child(obj, "u-cluster", &s->u_cluster, TYPE_CPU_CLUSTER);
+    qdev_prop_set_uint32(DEVICE(&s->u_cluster), "cluster-id", 1);
+
+    object_initialize_child(OBJECT(&s->u_cluster), "u-cpus", &s->u_cpus,
+                            TYPE_RISCV_HART_ARRAY);
+    qdev_prop_set_uint32(DEVICE(&s->u_cpus), "num-harts", ms->smp.cpus - 1);
+    qdev_prop_set_uint32(DEVICE(&s->u_cpus), "hartid-base", 1);
+    qdev_prop_set_string(DEVICE(&s->u_cpus), "cpu-type",
+                         TYPE_RISCV_CPU_SIFIVE_U54);
+    qdev_prop_set_uint64(DEVICE(&s->u_cpus), "resetvec", RESET_VECTOR);
+
+    object_initialize_child(obj, "dma-controller", &s->dma,
+                            TYPE_SIFIVE_PDMA);
+
+    object_initialize_child(obj, "gem0", &s->gem0, TYPE_CADENCE_GEM);
+    object_initialize_child(obj, "gem1", &s->gem1, TYPE_CADENCE_GEM);
+
+    object_initialize_child(obj, "sd-controller", &s->sdhci,
+                            TYPE_CADENCE_SDHCI);
+}
+
+static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
+{
+    MachineState *ms = MACHINE(qdev_get_machine());
+    MicrochipPFSoCState *s = MICROCHIP_PFSOC(dev);
+    const struct MemmapEntry *memmap = microchip_pfsoc_memmap;
+    MemoryRegion *system_memory = get_system_memory();
+    MemoryRegion *e51_dtim_mem = g_new(MemoryRegion, 1);
+    MemoryRegion *l2lim_mem = g_new(MemoryRegion, 1);
+    MemoryRegion *envm_data = g_new(MemoryRegion, 1);
+    char *plic_hart_config;
+    size_t plic_hart_config_len;
+    NICInfo *nd;
+    int i;
+
+    sysbus_realize(SYS_BUS_DEVICE(&s->e_cpus), &error_abort);
+    sysbus_realize(SYS_BUS_DEVICE(&s->u_cpus), &error_abort);
+    /*
+     * The cluster must be realized after the RISC-V hart array container,
+     * as the container's CPU object is only created on realize, and the
+     * CPU must exist and have been parented into the cluster before the
+     * cluster is realized.
+     */
+    qdev_realize(DEVICE(&s->e_cluster), NULL, &error_abort);
+    qdev_realize(DEVICE(&s->u_cluster), NULL, &error_abort);
+
+    /* E51 DTIM */
+    memory_region_init_ram(e51_dtim_mem, NULL, "microchip.pfsoc.e51_dtim_mem",
+                           memmap[MICROCHIP_PFSOC_E51_DTIM].size, &error_fatal);
+    memory_region_add_subregion(system_memory,
+                                memmap[MICROCHIP_PFSOC_E51_DTIM].base,
+                                e51_dtim_mem);
+
+    /* Bus Error Units */
+    create_unimplemented_device("microchip.pfsoc.buserr_unit0_mem",
+        memmap[MICROCHIP_PFSOC_BUSERR_UNIT0].base,
+        memmap[MICROCHIP_PFSOC_BUSERR_UNIT0].size);
+    create_unimplemented_device("microchip.pfsoc.buserr_unit1_mem",
+        memmap[MICROCHIP_PFSOC_BUSERR_UNIT1].base,
+        memmap[MICROCHIP_PFSOC_BUSERR_UNIT1].size);
+    create_unimplemented_device("microchip.pfsoc.buserr_unit2_mem",
+        memmap[MICROCHIP_PFSOC_BUSERR_UNIT2].base,
+        memmap[MICROCHIP_PFSOC_BUSERR_UNIT2].size);
+    create_unimplemented_device("microchip.pfsoc.buserr_unit3_mem",
+        memmap[MICROCHIP_PFSOC_BUSERR_UNIT3].base,
+        memmap[MICROCHIP_PFSOC_BUSERR_UNIT3].size);
+    create_unimplemented_device("microchip.pfsoc.buserr_unit4_mem",
+        memmap[MICROCHIP_PFSOC_BUSERR_UNIT4].base,
+        memmap[MICROCHIP_PFSOC_BUSERR_UNIT4].size);
+
+    /* CLINT */
+    sifive_clint_create(memmap[MICROCHIP_PFSOC_CLINT].base,
+        memmap[MICROCHIP_PFSOC_CLINT].size, 0, ms->smp.cpus,
+        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
+        CLINT_TIMEBASE_FREQ, false);
+
+    /* L2 cache controller */
+    create_unimplemented_device("microchip.pfsoc.l2cc",
+        memmap[MICROCHIP_PFSOC_L2CC].base, memmap[MICROCHIP_PFSOC_L2CC].size);
+
+    /*
+     * Add L2-LIM at reset size.
+     * This should be reduced in size as the L2 Cache Controller WayEnable
+     * register is incremented. Unfortunately I don't see a nice (or any) way
+     * to handle reducing or blocking out the L2 LIM while still allowing it
+     * be re returned to all enabled after a reset. For the time being, just
+     * leave it enabled all the time. This won't break anything, but will be
+     * too generous to misbehaving guests.
+     */
+    memory_region_init_ram(l2lim_mem, NULL, "microchip.pfsoc.l2lim",
+                           memmap[MICROCHIP_PFSOC_L2LIM].size, &error_fatal);
+    memory_region_add_subregion(system_memory,
+                                memmap[MICROCHIP_PFSOC_L2LIM].base,
+                                l2lim_mem);
+
+    /* create PLIC hart topology configuration string */
+    plic_hart_config_len = (strlen(MICROCHIP_PFSOC_PLIC_HART_CONFIG) + 1) *
+                           ms->smp.cpus;
+    plic_hart_config = g_malloc0(plic_hart_config_len);
+    for (i = 0; i < ms->smp.cpus; i++) {
+        if (i != 0) {
+            strncat(plic_hart_config, "," MICROCHIP_PFSOC_PLIC_HART_CONFIG,
+                    plic_hart_config_len);
+        } else {
+            strncat(plic_hart_config, "M", plic_hart_config_len);
+        }
+        plic_hart_config_len -= (strlen(MICROCHIP_PFSOC_PLIC_HART_CONFIG) + 1);
+    }
+
+    /* PLIC */
+    s->plic = sifive_plic_create(memmap[MICROCHIP_PFSOC_PLIC].base,
+        plic_hart_config, 0,
+        MICROCHIP_PFSOC_PLIC_NUM_SOURCES,
+        MICROCHIP_PFSOC_PLIC_NUM_PRIORITIES,
+        MICROCHIP_PFSOC_PLIC_PRIORITY_BASE,
+        MICROCHIP_PFSOC_PLIC_PENDING_BASE,
+        MICROCHIP_PFSOC_PLIC_ENABLE_BASE,
+        MICROCHIP_PFSOC_PLIC_ENABLE_STRIDE,
+        MICROCHIP_PFSOC_PLIC_CONTEXT_BASE,
+        MICROCHIP_PFSOC_PLIC_CONTEXT_STRIDE,
+        memmap[MICROCHIP_PFSOC_PLIC].size);
+    g_free(plic_hart_config);
+
+    /* DMA */
+    sysbus_realize(SYS_BUS_DEVICE(&s->dma), errp);
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->dma), 0,
+                    memmap[MICROCHIP_PFSOC_DMA].base);
+    for (i = 0; i < SIFIVE_PDMA_IRQS; i++) {
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), i,
+                           qdev_get_gpio_in(DEVICE(s->plic),
+                                            MICROCHIP_PFSOC_DMA_IRQ0 + i));
+    }
+
+    /* SYSREG */
+    create_unimplemented_device("microchip.pfsoc.sysreg",
+        memmap[MICROCHIP_PFSOC_SYSREG].base,
+        memmap[MICROCHIP_PFSOC_SYSREG].size);
+
+    /* MPUCFG */
+    create_unimplemented_device("microchip.pfsoc.mpucfg",
+        memmap[MICROCHIP_PFSOC_MPUCFG].base,
+        memmap[MICROCHIP_PFSOC_MPUCFG].size);
+
+    /* SDHCI */
+    sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), errp);
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci), 0,
+                    memmap[MICROCHIP_PFSOC_EMMC_SD].base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0,
+        qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_EMMC_SD_IRQ));
+
+    /* MMUARTs */
+    s->serial0 = mchp_pfsoc_mmuart_create(system_memory,
+        memmap[MICROCHIP_PFSOC_MMUART0].base,
+        qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART0_IRQ),
+        serial_hd(0));
+    s->serial1 = mchp_pfsoc_mmuart_create(system_memory,
+        memmap[MICROCHIP_PFSOC_MMUART1].base,
+        qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART1_IRQ),
+        serial_hd(1));
+    s->serial2 = mchp_pfsoc_mmuart_create(system_memory,
+        memmap[MICROCHIP_PFSOC_MMUART2].base,
+        qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART2_IRQ),
+        serial_hd(2));
+    s->serial3 = mchp_pfsoc_mmuart_create(system_memory,
+        memmap[MICROCHIP_PFSOC_MMUART3].base,
+        qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART3_IRQ),
+        serial_hd(3));
+    s->serial4 = mchp_pfsoc_mmuart_create(system_memory,
+        memmap[MICROCHIP_PFSOC_MMUART4].base,
+        qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART4_IRQ),
+        serial_hd(4));
+
+    /* GEMs */
+
+    nd = &nd_table[0];
+    if (nd->used) {
+        qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
+        qdev_set_nic_properties(DEVICE(&s->gem0), nd);
+    }
+    nd = &nd_table[1];
+    if (nd->used) {
+        qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
+        qdev_set_nic_properties(DEVICE(&s->gem1), nd);
+    }
+
+    object_property_set_int(OBJECT(&s->gem0), "revision", GEM_REVISION, errp);
+    object_property_set_int(OBJECT(&s->gem0), "phy-addr", 8, errp);
+    sysbus_realize(SYS_BUS_DEVICE(&s->gem0), errp);
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem0), 0,
+                    memmap[MICROCHIP_PFSOC_GEM0].base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem0), 0,
+        qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_GEM0_IRQ));
+
+    object_property_set_int(OBJECT(&s->gem1), "revision", GEM_REVISION, errp);
+    object_property_set_int(OBJECT(&s->gem1), "phy-addr", 9, errp);
+    sysbus_realize(SYS_BUS_DEVICE(&s->gem1), errp);
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem1), 0,
+                    memmap[MICROCHIP_PFSOC_GEM1].base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem1), 0,
+        qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_GEM1_IRQ));
+
+    /* GPIOs */
+    create_unimplemented_device("microchip.pfsoc.gpio0",
+        memmap[MICROCHIP_PFSOC_GPIO0].base,
+        memmap[MICROCHIP_PFSOC_GPIO0].size);
+    create_unimplemented_device("microchip.pfsoc.gpio1",
+        memmap[MICROCHIP_PFSOC_GPIO1].base,
+        memmap[MICROCHIP_PFSOC_GPIO1].size);
+    create_unimplemented_device("microchip.pfsoc.gpio2",
+        memmap[MICROCHIP_PFSOC_GPIO2].base,
+        memmap[MICROCHIP_PFSOC_GPIO2].size);
+
+    /* eNVM */
+    memory_region_init_rom(envm_data, OBJECT(dev), "microchip.pfsoc.envm.data",
+                           memmap[MICROCHIP_PFSOC_ENVM_DATA].size,
+                           &error_fatal);
+    memory_region_add_subregion(system_memory,
+                                memmap[MICROCHIP_PFSOC_ENVM_DATA].base,
+                                envm_data);
+
+    /* IOSCBCFG */
+    create_unimplemented_device("microchip.pfsoc.ioscb.cfg",
+        memmap[MICROCHIP_PFSOC_IOSCB_CFG].base,
+        memmap[MICROCHIP_PFSOC_IOSCB_CFG].size);
+}
+
+static void microchip_pfsoc_soc_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = microchip_pfsoc_soc_realize;
+    /* Reason: Uses serial_hds in realize function, thus can't be used twice */
+    dc->user_creatable = false;
+}
+
+static const TypeInfo microchip_pfsoc_soc_type_info = {
+    .name = TYPE_MICROCHIP_PFSOC,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(MicrochipPFSoCState),
+    .instance_init = microchip_pfsoc_soc_instance_init,
+    .class_init = microchip_pfsoc_soc_class_init,
+};
+
+static void microchip_pfsoc_soc_register_types(void)
+{
+    type_register_static(&microchip_pfsoc_soc_type_info);
+}
+
+type_init(microchip_pfsoc_soc_register_types)
+
+static void microchip_icicle_kit_machine_init(MachineState *machine)
+{
+    MachineClass *mc = MACHINE_GET_CLASS(machine);
+    const struct MemmapEntry *memmap = microchip_pfsoc_memmap;
+    MicrochipIcicleKitState *s = MICROCHIP_ICICLE_KIT_MACHINE(machine);
+    MemoryRegion *system_memory = get_system_memory();
+    MemoryRegion *main_mem = g_new(MemoryRegion, 1);
+    DriveInfo *dinfo = drive_get_next(IF_SD);
+
+    /* Sanity check on RAM size */
+    if (machine->ram_size < mc->default_ram_size) {
+        char *sz = size_to_str(mc->default_ram_size);
+        error_report("Invalid RAM size, should be bigger than %s", sz);
+        g_free(sz);
+        exit(EXIT_FAILURE);
+    }
+
+    /* Initialize SoC */
+    object_initialize_child(OBJECT(machine), "soc", &s->soc,
+                            TYPE_MICROCHIP_PFSOC);
+    qdev_realize(DEVICE(&s->soc), NULL, &error_abort);
+
+    /* Register RAM */
+    memory_region_init_ram(main_mem, NULL, "microchip.icicle.kit.ram",
+                           machine->ram_size, &error_fatal);
+    memory_region_add_subregion(system_memory,
+                                memmap[MICROCHIP_PFSOC_DRAM].base, main_mem);
+
+    /* Load the firmware */
+    riscv_find_and_load_firmware(machine, BIOS_FILENAME, RESET_VECTOR, NULL);
+
+    /* Attach an SD card */
+    if (dinfo) {
+        CadenceSDHCIState *sdhci = &(s->soc.sdhci);
+        DeviceState *card = qdev_new(TYPE_SD_CARD);
+
+        qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo),
+                                &error_fatal);
+        qdev_realize_and_unref(card, sdhci->bus, &error_fatal);
+    }
+}
+
+static void microchip_icicle_kit_machine_class_init(ObjectClass *oc, void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->desc = "Microchip PolarFire SoC Icicle Kit";
+    mc->init = microchip_icicle_kit_machine_init;
+    mc->max_cpus = MICROCHIP_PFSOC_MANAGEMENT_CPU_COUNT +
+                   MICROCHIP_PFSOC_COMPUTE_CPU_COUNT;
+    mc->min_cpus = MICROCHIP_PFSOC_MANAGEMENT_CPU_COUNT + 1;
+    mc->default_cpus = mc->min_cpus;
+    mc->default_ram_size = 1 * GiB;
+}
+
+static const TypeInfo microchip_icicle_kit_machine_typeinfo = {
+    .name       = MACHINE_TYPE_NAME("microchip-icicle-kit"),
+    .parent     = TYPE_MACHINE,
+    .class_init = microchip_icicle_kit_machine_class_init,
+    .instance_size = sizeof(MicrochipIcicleKitState),
+};
+
+static void microchip_icicle_kit_machine_init_register_types(void)
+{
+    type_register_static(&microchip_icicle_kit_machine_typeinfo);
+}
+
+type_init(microchip_icicle_kit_machine_init_register_types)
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
index 23ba3b4bfc..0531bd879b 100644
--- a/hw/riscv/opentitan.c
+++ b/hw/riscv/opentitan.c
@@ -111,6 +111,7 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
                             &error_abort);
     object_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus,
                             &error_abort);
+    object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x8090, &error_abort);
     sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_abort);
 
     /* Boot ROM */
diff --git a/hw/riscv/riscv_hart.c b/hw/riscv/riscv_hart.c
index f59fe52f0f..613ea2aaa0 100644
--- a/hw/riscv/riscv_hart.c
+++ b/hw/riscv/riscv_hart.c
@@ -31,6 +31,8 @@ static Property riscv_harts_props[] = {
     DEFINE_PROP_UINT32("num-harts", RISCVHartArrayState, num_harts, 1),
     DEFINE_PROP_UINT32("hartid-base", RISCVHartArrayState, hartid_base, 0),
     DEFINE_PROP_STRING("cpu-type", RISCVHartArrayState, cpu_type),
+    DEFINE_PROP_UINT64("resetvec", RISCVHartArrayState, resetvec,
+                       DEFAULT_RSTVEC),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -44,6 +46,7 @@ static bool riscv_hart_realize(RISCVHartArrayState *s, int idx,
                                char *cpu_type, Error **errp)
 {
     object_initialize_child(OBJECT(s), "harts[*]", &s->harts[idx], cpu_type);
+    qdev_prop_set_uint64(DEVICE(&s->harts[idx]), "resetvec", s->resetvec);
     s->harts[idx].env.mhartid = s->hartid_base + idx;
     qemu_register_reset(riscv_harts_cpu_reset, &s->harts[idx]);
     return qdev_realize(DEVICE(&s->harts[idx]), NULL, errp);
diff --git a/hw/riscv/riscv_htif.c b/hw/riscv/riscv_htif.c
deleted file mode 100644
index ca87a5cf9f..0000000000
--- a/hw/riscv/riscv_htif.c
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * QEMU RISC-V Host Target Interface (HTIF) Emulation
- *
- * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
- * Copyright (c) 2017-2018 SiFive, Inc.
- *
- * This provides HTIF device emulation for QEMU. At the moment this allows
- * for identical copies of bbl/linux to run on both spike and QEMU.
- *
- * 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 "qemu/log.h"
-#include "hw/sysbus.h"
-#include "hw/char/serial.h"
-#include "chardev/char.h"
-#include "chardev/char-fe.h"
-#include "hw/riscv/riscv_htif.h"
-#include "qemu/timer.h"
-#include "qemu/error-report.h"
-
-#define RISCV_DEBUG_HTIF 0
-#define HTIF_DEBUG(fmt, ...)                                                   \
-    do {                                                                       \
-        if (RISCV_DEBUG_HTIF) {                                                \
-            qemu_log_mask(LOG_TRACE, "%s: " fmt "\n", __func__, ##__VA_ARGS__);\
-        }                                                                      \
-    } while (0)
-
-static uint64_t fromhost_addr, tohost_addr;
-static int address_symbol_set;
-
-void htif_symbol_callback(const char *st_name, int st_info, uint64_t st_value,
-                          uint64_t st_size)
-{
-    if (strcmp("fromhost", st_name) == 0) {
-        address_symbol_set |= 1;
-        fromhost_addr = st_value;
-        if (st_size != 8) {
-            error_report("HTIF fromhost must be 8 bytes");
-            exit(1);
-        }
-    } else if (strcmp("tohost", st_name) == 0) {
-        address_symbol_set |= 2;
-        tohost_addr = st_value;
-        if (st_size != 8) {
-            error_report("HTIF tohost must be 8 bytes");
-            exit(1);
-        }
-    }
-}
-
-/*
- * Called by the char dev to see if HTIF is ready to accept input.
- */
-static int htif_can_recv(void *opaque)
-{
-    return 1;
-}
-
-/*
- * Called by the char dev to supply input to HTIF console.
- * We assume that we will receive one character at a time.
- */
-static void htif_recv(void *opaque, const uint8_t *buf, int size)
-{
-    HTIFState *htifstate = opaque;
-
-    if (size != 1) {
-        return;
-    }
-
-    /* TODO - we need to check whether mfromhost is zero which indicates
-              the device is ready to receive. The current implementation
-              will drop characters */
-
-    uint64_t val_written = htifstate->pending_read;
-    uint64_t resp = 0x100 | *buf;
-
-    htifstate->env->mfromhost = (val_written >> 48 << 48) | (resp << 16 >> 16);
-}
-
-/*
- * Called by the char dev to supply special events to the HTIF console.
- * Not used for HTIF.
- */
-static void htif_event(void *opaque, QEMUChrEvent event)
-{
-
-}
-
-static int htif_be_change(void *opaque)
-{
-    HTIFState *s = opaque;
-
-    qemu_chr_fe_set_handlers(&s->chr, htif_can_recv, htif_recv, htif_event,
-        htif_be_change, s, NULL, true);
-
-    return 0;
-}
-
-static void htif_handle_tohost_write(HTIFState *htifstate, uint64_t val_written)
-{
-    uint8_t device = val_written >> 56;
-    uint8_t cmd = val_written >> 48;
-    uint64_t payload = val_written & 0xFFFFFFFFFFFFULL;
-    int resp = 0;
-
-    HTIF_DEBUG("mtohost write: device: %d cmd: %d what: %02" PRIx64
-        " -payload: %016" PRIx64 "\n", device, cmd, payload & 0xFF, payload);
-
-    /*
-     * Currently, there is a fixed mapping of devices:
-     * 0: riscv-tests Pass/Fail Reporting Only (no syscall proxy)
-     * 1: Console
-     */
-    if (unlikely(device == 0x0)) {
-        /* frontend syscall handler, shutdown and exit code support */
-        if (cmd == 0x0) {
-            if (payload & 0x1) {
-                /* exit code */
-                int exit_code = payload >> 1;
-                exit(exit_code);
-            } else {
-                qemu_log_mask(LOG_UNIMP, "pk syscall proxy not supported\n");
-            }
-        } else {
-            qemu_log("HTIF device %d: unknown command\n", device);
-        }
-    } else if (likely(device == 0x1)) {
-        /* HTIF Console */
-        if (cmd == 0x0) {
-            /* this should be a queue, but not yet implemented as such */
-            htifstate->pending_read = val_written;
-            htifstate->env->mtohost = 0; /* clear to indicate we read */
-            return;
-        } else if (cmd == 0x1) {
-            qemu_chr_fe_write(&htifstate->chr, (uint8_t *)&payload, 1);
-            resp = 0x100 | (uint8_t)payload;
-        } else {
-            qemu_log("HTIF device %d: unknown command\n", device);
-        }
-    } else {
-        qemu_log("HTIF unknown device or command\n");
-        HTIF_DEBUG("device: %d cmd: %d what: %02" PRIx64
-            " payload: %016" PRIx64, device, cmd, payload & 0xFF, payload);
-    }
-    /*
-     * - latest bbl does not set fromhost to 0 if there is a value in tohost
-     * - with this code enabled, qemu hangs waiting for fromhost to go to 0
-     * - with this code disabled, qemu works with bbl priv v1.9.1 and v1.10
-     * - HTIF needs protocol documentation and a more complete state machine
-
-        while (!htifstate->fromhost_inprogress &&
-            htifstate->env->mfromhost != 0x0) {
-        }
-    */
-    htifstate->env->mfromhost = (val_written >> 48 << 48) | (resp << 16 >> 16);
-    htifstate->env->mtohost = 0; /* clear to indicate we read */
-}
-
-#define TOHOST_OFFSET1 (htifstate->tohost_offset)
-#define TOHOST_OFFSET2 (htifstate->tohost_offset + 4)
-#define FROMHOST_OFFSET1 (htifstate->fromhost_offset)
-#define FROMHOST_OFFSET2 (htifstate->fromhost_offset + 4)
-
-/* CPU wants to read an HTIF register */
-static uint64_t htif_mm_read(void *opaque, hwaddr addr, unsigned size)
-{
-    HTIFState *htifstate = opaque;
-    if (addr == TOHOST_OFFSET1) {
-        return htifstate->env->mtohost & 0xFFFFFFFF;
-    } else if (addr == TOHOST_OFFSET2) {
-        return (htifstate->env->mtohost >> 32) & 0xFFFFFFFF;
-    } else if (addr == FROMHOST_OFFSET1) {
-        return htifstate->env->mfromhost & 0xFFFFFFFF;
-    } else if (addr == FROMHOST_OFFSET2) {
-        return (htifstate->env->mfromhost >> 32) & 0xFFFFFFFF;
-    } else {
-        qemu_log("Invalid htif read: address %016" PRIx64 "\n",
-            (uint64_t)addr);
-        return 0;
-    }
-}
-
-/* CPU wrote to an HTIF register */
-static void htif_mm_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    HTIFState *htifstate = opaque;
-    if (addr == TOHOST_OFFSET1) {
-        if (htifstate->env->mtohost == 0x0) {
-            htifstate->allow_tohost = 1;
-            htifstate->env->mtohost = value & 0xFFFFFFFF;
-        } else {
-            htifstate->allow_tohost = 0;
-        }
-    } else if (addr == TOHOST_OFFSET2) {
-        if (htifstate->allow_tohost) {
-            htifstate->env->mtohost |= value << 32;
-            htif_handle_tohost_write(htifstate, htifstate->env->mtohost);
-        }
-    } else if (addr == FROMHOST_OFFSET1) {
-        htifstate->fromhost_inprogress = 1;
-        htifstate->env->mfromhost = value & 0xFFFFFFFF;
-    } else if (addr == FROMHOST_OFFSET2) {
-        htifstate->env->mfromhost |= value << 32;
-        htifstate->fromhost_inprogress = 0;
-    } else {
-        qemu_log("Invalid htif write: address %016" PRIx64 "\n",
-            (uint64_t)addr);
-    }
-}
-
-static const MemoryRegionOps htif_mm_ops = {
-    .read = htif_mm_read,
-    .write = htif_mm_write,
-};
-
-HTIFState *htif_mm_init(MemoryRegion *address_space, MemoryRegion *main_mem,
-    CPURISCVState *env, Chardev *chr)
-{
-    uint64_t base = MIN(tohost_addr, fromhost_addr);
-    uint64_t size = MAX(tohost_addr + 8, fromhost_addr + 8) - base;
-    uint64_t tohost_offset = tohost_addr - base;
-    uint64_t fromhost_offset = fromhost_addr - base;
-
-    HTIFState *s = g_malloc0(sizeof(HTIFState));
-    s->address_space = address_space;
-    s->main_mem = main_mem;
-    s->main_mem_ram_ptr = memory_region_get_ram_ptr(main_mem);
-    s->env = env;
-    s->tohost_offset = tohost_offset;
-    s->fromhost_offset = fromhost_offset;
-    s->pending_read = 0;
-    s->allow_tohost = 0;
-    s->fromhost_inprogress = 0;
-    qemu_chr_fe_init(&s->chr, chr, &error_abort);
-    qemu_chr_fe_set_handlers(&s->chr, htif_can_recv, htif_recv, htif_event,
-        htif_be_change, s, NULL, true);
-    if (address_symbol_set == 3) {
-        memory_region_init_io(&s->mmio, NULL, &htif_mm_ops, s,
-                              TYPE_HTIF_UART, size);
-        memory_region_add_subregion_overlap(address_space, base,
-                                            &s->mmio, 1);
-    }
-
-    return s;
-}
diff --git a/hw/riscv/sifive_clint.c b/hw/riscv/sifive_clint.c
deleted file mode 100644
index 15e13d5f7a..0000000000
--- a/hw/riscv/sifive_clint.c
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * SiFive CLINT (Core Local Interruptor)
- *
- * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
- * Copyright (c) 2017 SiFive, Inc.
- *
- * This provides real-time clock, timer and interprocessor interrupts.
- *
- * 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 "qemu/error-report.h"
-#include "qemu/module.h"
-#include "hw/sysbus.h"
-#include "target/riscv/cpu.h"
-#include "hw/qdev-properties.h"
-#include "hw/riscv/sifive_clint.h"
-#include "qemu/timer.h"
-
-static uint64_t cpu_riscv_read_rtc(void)
-{
-    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
-        SIFIVE_CLINT_TIMEBASE_FREQ, NANOSECONDS_PER_SECOND);
-}
-
-/*
- * Called when timecmp is written to update the QEMU timer or immediately
- * trigger timer interrupt if mtimecmp <= current timer value.
- */
-static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value)
-{
-    uint64_t next;
-    uint64_t diff;
-
-    uint64_t rtc_r = cpu_riscv_read_rtc();
-
-    cpu->env.timecmp = value;
-    if (cpu->env.timecmp <= rtc_r) {
-        /* if we're setting an MTIMECMP value in the "past",
-           immediately raise the timer interrupt */
-        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
-        return;
-    }
-
-    /* otherwise, set up the future timer interrupt */
-    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
-    diff = cpu->env.timecmp - rtc_r;
-    /* back to ns (note args switched in muldiv64) */
-    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
-        muldiv64(diff, NANOSECONDS_PER_SECOND, SIFIVE_CLINT_TIMEBASE_FREQ);
-    timer_mod(cpu->env.timer, next);
-}
-
-/*
- * Callback used when the timer set using timer_mod expires.
- * Should raise the timer interrupt line
- */
-static void sifive_clint_timer_cb(void *opaque)
-{
-    RISCVCPU *cpu = opaque;
-    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
-}
-
-/* CPU wants to read rtc or timecmp register */
-static uint64_t sifive_clint_read(void *opaque, hwaddr addr, unsigned size)
-{
-    SiFiveCLINTState *clint = opaque;
-    if (addr >= clint->sip_base &&
-        addr < clint->sip_base + (clint->num_harts << 2)) {
-        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
-        CPUState *cpu = qemu_get_cpu(hartid);
-        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
-        if (!env) {
-            error_report("clint: invalid timecmp hartid: %zu", hartid);
-        } else if ((addr & 0x3) == 0) {
-            return (env->mip & MIP_MSIP) > 0;
-        } else {
-            error_report("clint: invalid read: %08x", (uint32_t)addr);
-            return 0;
-        }
-    } else if (addr >= clint->timecmp_base &&
-        addr < clint->timecmp_base + (clint->num_harts << 3)) {
-        size_t hartid = clint->hartid_base +
-            ((addr - clint->timecmp_base) >> 3);
-        CPUState *cpu = qemu_get_cpu(hartid);
-        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
-        if (!env) {
-            error_report("clint: invalid timecmp hartid: %zu", hartid);
-        } else if ((addr & 0x7) == 0) {
-            /* timecmp_lo */
-            uint64_t timecmp = env->timecmp;
-            return timecmp & 0xFFFFFFFF;
-        } else if ((addr & 0x7) == 4) {
-            /* timecmp_hi */
-            uint64_t timecmp = env->timecmp;
-            return (timecmp >> 32) & 0xFFFFFFFF;
-        } else {
-            error_report("clint: invalid read: %08x", (uint32_t)addr);
-            return 0;
-        }
-    } else if (addr == clint->time_base) {
-        /* time_lo */
-        return cpu_riscv_read_rtc() & 0xFFFFFFFF;
-    } else if (addr == clint->time_base + 4) {
-        /* time_hi */
-        return (cpu_riscv_read_rtc() >> 32) & 0xFFFFFFFF;
-    }
-
-    error_report("clint: invalid read: %08x", (uint32_t)addr);
-    return 0;
-}
-
-/* CPU wrote to rtc or timecmp register */
-static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
-        unsigned size)
-{
-    SiFiveCLINTState *clint = opaque;
-
-    if (addr >= clint->sip_base &&
-        addr < clint->sip_base + (clint->num_harts << 2)) {
-        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
-        CPUState *cpu = qemu_get_cpu(hartid);
-        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
-        if (!env) {
-            error_report("clint: invalid timecmp hartid: %zu", hartid);
-        } else if ((addr & 0x3) == 0) {
-            riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MSIP, BOOL_TO_MASK(value));
-        } else {
-            error_report("clint: invalid sip write: %08x", (uint32_t)addr);
-        }
-        return;
-    } else if (addr >= clint->timecmp_base &&
-        addr < clint->timecmp_base + (clint->num_harts << 3)) {
-        size_t hartid = clint->hartid_base +
-            ((addr - clint->timecmp_base) >> 3);
-        CPUState *cpu = qemu_get_cpu(hartid);
-        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
-        if (!env) {
-            error_report("clint: invalid timecmp hartid: %zu", hartid);
-        } else if ((addr & 0x7) == 0) {
-            /* timecmp_lo */
-            uint64_t timecmp_hi = env->timecmp >> 32;
-            sifive_clint_write_timecmp(RISCV_CPU(cpu),
-                timecmp_hi << 32 | (value & 0xFFFFFFFF));
-            return;
-        } else if ((addr & 0x7) == 4) {
-            /* timecmp_hi */
-            uint64_t timecmp_lo = env->timecmp;
-            sifive_clint_write_timecmp(RISCV_CPU(cpu),
-                value << 32 | (timecmp_lo & 0xFFFFFFFF));
-        } else {
-            error_report("clint: invalid timecmp write: %08x", (uint32_t)addr);
-        }
-        return;
-    } else if (addr == clint->time_base) {
-        /* time_lo */
-        error_report("clint: time_lo write not implemented");
-        return;
-    } else if (addr == clint->time_base + 4) {
-        /* time_hi */
-        error_report("clint: time_hi write not implemented");
-        return;
-    }
-
-    error_report("clint: invalid write: %08x", (uint32_t)addr);
-}
-
-static const MemoryRegionOps sifive_clint_ops = {
-    .read = sifive_clint_read,
-    .write = sifive_clint_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 8
-    }
-};
-
-static Property sifive_clint_properties[] = {
-    DEFINE_PROP_UINT32("hartid-base", SiFiveCLINTState, hartid_base, 0),
-    DEFINE_PROP_UINT32("num-harts", SiFiveCLINTState, num_harts, 0),
-    DEFINE_PROP_UINT32("sip-base", SiFiveCLINTState, sip_base, 0),
-    DEFINE_PROP_UINT32("timecmp-base", SiFiveCLINTState, timecmp_base, 0),
-    DEFINE_PROP_UINT32("time-base", SiFiveCLINTState, time_base, 0),
-    DEFINE_PROP_UINT32("aperture-size", SiFiveCLINTState, aperture_size, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sifive_clint_realize(DeviceState *dev, Error **errp)
-{
-    SiFiveCLINTState *s = SIFIVE_CLINT(dev);
-    memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_clint_ops, s,
-                          TYPE_SIFIVE_CLINT, s->aperture_size);
-    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
-}
-
-static void sifive_clint_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    dc->realize = sifive_clint_realize;
-    device_class_set_props(dc, sifive_clint_properties);
-}
-
-static const TypeInfo sifive_clint_info = {
-    .name          = TYPE_SIFIVE_CLINT,
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SiFiveCLINTState),
-    .class_init    = sifive_clint_class_init,
-};
-
-static void sifive_clint_register_types(void)
-{
-    type_register_static(&sifive_clint_info);
-}
-
-type_init(sifive_clint_register_types)
-
-
-/*
- * Create CLINT device.
- */
-DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
-    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
-    uint32_t timecmp_base, uint32_t time_base, bool provide_rdtime)
-{
-    int i;
-    for (i = 0; i < num_harts; i++) {
-        CPUState *cpu = qemu_get_cpu(hartid_base + i);
-        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
-        if (!env) {
-            continue;
-        }
-        if (provide_rdtime) {
-            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc);
-        }
-        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
-                                  &sifive_clint_timer_cb, cpu);
-        env->timecmp = 0;
-    }
-
-    DeviceState *dev = qdev_new(TYPE_SIFIVE_CLINT);
-    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
-    qdev_prop_set_uint32(dev, "num-harts", num_harts);
-    qdev_prop_set_uint32(dev, "sip-base", sip_base);
-    qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base);
-    qdev_prop_set_uint32(dev, "time-base", time_base);
-    qdev_prop_set_uint32(dev, "aperture-size", size);
-    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
-    return dev;
-}
diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
index ca55cc438a..40bbf530d4 100644
--- a/hw/riscv/sifive_e.c
+++ b/hw/riscv/sifive_e.c
@@ -39,12 +39,12 @@
 #include "hw/misc/unimp.h"
 #include "target/riscv/cpu.h"
 #include "hw/riscv/riscv_hart.h"
-#include "hw/riscv/sifive_plic.h"
-#include "hw/riscv/sifive_clint.h"
-#include "hw/riscv/sifive_uart.h"
 #include "hw/riscv/sifive_e.h"
-#include "hw/riscv/sifive_e_prci.h"
 #include "hw/riscv/boot.h"
+#include "hw/char/sifive_uart.h"
+#include "hw/intc/sifive_clint.h"
+#include "hw/intc/sifive_plic.h"
+#include "hw/misc/sifive_e_prci.h"
 #include "chardev/char.h"
 #include "sysemu/arch_init.h"
 #include "sysemu/sysemu.h"
@@ -177,6 +177,7 @@ static void sifive_e_soc_init(Object *obj)
     object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY);
     object_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus,
                             &error_abort);
+    object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x1004, &error_abort);
     object_initialize_child(obj, "riscv.sifive.e.gpio0", &s->gpio,
                             TYPE_SIFIVE_GPIO);
 }
@@ -212,7 +213,8 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
         memmap[SIFIVE_E_PLIC].size);
     sifive_clint_create(memmap[SIFIVE_E_CLINT].base,
         memmap[SIFIVE_E_CLINT].size, 0, ms->smp.cpus,
-        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, false);
+        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
+        SIFIVE_CLINT_TIMEBASE_FREQ, false);
     create_unimplemented_device("riscv.sifive.e.aon",
         memmap[SIFIVE_E_AON].base, memmap[SIFIVE_E_AON].size);
     sifive_e_prci_create(memmap[SIFIVE_E_PRCI].base);
diff --git a/hw/riscv/sifive_e_prci.c b/hw/riscv/sifive_e_prci.c
deleted file mode 100644
index 17dfa74715..0000000000
--- a/hw/riscv/sifive_e_prci.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * QEMU SiFive E PRCI (Power, Reset, Clock, Interrupt)
- *
- * Copyright (c) 2017 SiFive, Inc.
- *
- * Simple model of the PRCI to emulate register reads made by the SDK BSP
- *
- * 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 "hw/sysbus.h"
-#include "qapi/error.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "hw/hw.h"
-#include "hw/riscv/sifive_e_prci.h"
-
-static uint64_t sifive_e_prci_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    SiFiveEPRCIState *s = opaque;
-    switch (addr) {
-    case SIFIVE_E_PRCI_HFROSCCFG:
-        return s->hfrosccfg;
-    case SIFIVE_E_PRCI_HFXOSCCFG:
-        return s->hfxosccfg;
-    case SIFIVE_E_PRCI_PLLCFG:
-        return s->pllcfg;
-    case SIFIVE_E_PRCI_PLLOUTDIV:
-        return s->plloutdiv;
-    }
-    qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%x\n",
-                  __func__, (int)addr);
-    return 0;
-}
-
-static void sifive_e_prci_write(void *opaque, hwaddr addr,
-                                uint64_t val64, unsigned int size)
-{
-    SiFiveEPRCIState *s = opaque;
-    switch (addr) {
-    case SIFIVE_E_PRCI_HFROSCCFG:
-        s->hfrosccfg = (uint32_t) val64;
-        /* OSC stays ready */
-        s->hfrosccfg |= SIFIVE_E_PRCI_HFROSCCFG_RDY;
-        break;
-    case SIFIVE_E_PRCI_HFXOSCCFG:
-        s->hfxosccfg = (uint32_t) val64;
-        /* OSC stays ready */
-        s->hfxosccfg |= SIFIVE_E_PRCI_HFXOSCCFG_RDY;
-        break;
-    case SIFIVE_E_PRCI_PLLCFG:
-        s->pllcfg = (uint32_t) val64;
-        /* PLL stays locked */
-        s->pllcfg |= SIFIVE_E_PRCI_PLLCFG_LOCK;
-        break;
-    case SIFIVE_E_PRCI_PLLOUTDIV:
-        s->plloutdiv = (uint32_t) val64;
-        break;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%x v=0x%x\n",
-                      __func__, (int)addr, (int)val64);
-    }
-}
-
-static const MemoryRegionOps sifive_e_prci_ops = {
-    .read = sifive_e_prci_read,
-    .write = sifive_e_prci_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static void sifive_e_prci_init(Object *obj)
-{
-    SiFiveEPRCIState *s = SIFIVE_E_PRCI(obj);
-
-    memory_region_init_io(&s->mmio, obj, &sifive_e_prci_ops, s,
-                          TYPE_SIFIVE_E_PRCI, SIFIVE_E_PRCI_REG_SIZE);
-    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
-
-    s->hfrosccfg = (SIFIVE_E_PRCI_HFROSCCFG_RDY | SIFIVE_E_PRCI_HFROSCCFG_EN);
-    s->hfxosccfg = (SIFIVE_E_PRCI_HFXOSCCFG_RDY | SIFIVE_E_PRCI_HFXOSCCFG_EN);
-    s->pllcfg = (SIFIVE_E_PRCI_PLLCFG_REFSEL | SIFIVE_E_PRCI_PLLCFG_BYPASS |
-                 SIFIVE_E_PRCI_PLLCFG_LOCK);
-    s->plloutdiv = SIFIVE_E_PRCI_PLLOUTDIV_DIV1;
-}
-
-static const TypeInfo sifive_e_prci_info = {
-    .name          = TYPE_SIFIVE_E_PRCI,
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SiFiveEPRCIState),
-    .instance_init = sifive_e_prci_init,
-};
-
-static void sifive_e_prci_register_types(void)
-{
-    type_register_static(&sifive_e_prci_info);
-}
-
-type_init(sifive_e_prci_register_types)
-
-
-/*
- * Create PRCI device.
- */
-DeviceState *sifive_e_prci_create(hwaddr addr)
-{
-    DeviceState *dev = qdev_new(TYPE_SIFIVE_E_PRCI);
-    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
-    return dev;
-}
diff --git a/hw/riscv/sifive_gpio.c b/hw/riscv/sifive_gpio.c
deleted file mode 100644
index aac6b44cac..0000000000
--- a/hw/riscv/sifive_gpio.c
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * SiFive System-on-Chip general purpose input/output register definition
- *
- * Copyright 2019 AdaCore
- *
- * Base on nrf51_gpio.c:
- *
- * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
- *
- * This code is licensed under the GPL version 2 or later.  See
- * the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/log.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "hw/riscv/sifive_gpio.h"
-#include "migration/vmstate.h"
-#include "trace.h"
-
-static void update_output_irq(SIFIVEGPIOState *s)
-{
-    uint32_t pending;
-    uint32_t pin;
-
-    pending = s->high_ip & s->high_ie;
-    pending |= s->low_ip & s->low_ie;
-    pending |= s->rise_ip & s->rise_ie;
-    pending |= s->fall_ip & s->fall_ie;
-
-    for (int i = 0; i < s->ngpio; i++) {
-        pin = 1 << i;
-        qemu_set_irq(s->irq[i], (pending & pin) != 0);
-        trace_sifive_gpio_update_output_irq(i, (pending & pin) != 0);
-    }
-}
-
-static void update_state(SIFIVEGPIOState *s)
-{
-    size_t i;
-    bool prev_ival, in, in_mask, port, out_xor, pull, output_en, input_en,
-        rise_ip, fall_ip, low_ip, high_ip, oval, actual_value, ival;
-
-    for (i = 0; i < s->ngpio; i++) {
-
-        prev_ival = extract32(s->value, i, 1);
-        in        = extract32(s->in, i, 1);
-        in_mask   = extract32(s->in_mask, i, 1);
-        port      = extract32(s->port, i, 1);
-        out_xor   = extract32(s->out_xor, i, 1);
-        pull      = extract32(s->pue, i, 1);
-        output_en = extract32(s->output_en, i, 1);
-        input_en  = extract32(s->input_en, i, 1);
-        rise_ip   = extract32(s->rise_ip, i, 1);
-        fall_ip   = extract32(s->fall_ip, i, 1);
-        low_ip    = extract32(s->low_ip, i, 1);
-        high_ip   = extract32(s->high_ip, i, 1);
-
-        /* Output value (IOF not supported) */
-        oval = output_en && (port ^ out_xor);
-
-        /* Pin both driven externally and internally */
-        if (output_en && in_mask) {
-            qemu_log_mask(LOG_GUEST_ERROR, "GPIO pin %zu short circuited\n", i);
-        }
-
-        if (in_mask) {
-            /* The pin is driven by external device */
-            actual_value = in;
-        } else if (output_en) {
-            /* The pin is driven by internal circuit */
-            actual_value = oval;
-        } else {
-            /* Floating? Apply pull-up resistor */
-            actual_value = pull;
-        }
-
-        if (output_en) {
-            qemu_set_irq(s->output[i], actual_value);
-        }
-
-        /* Input value */
-        ival = input_en && actual_value;
-
-        /* Interrupts */
-        high_ip = high_ip || ival;
-        s->high_ip = deposit32(s->high_ip, i, 1, high_ip);
-
-        low_ip = low_ip || !ival;
-        s->low_ip = deposit32(s->low_ip,  i, 1, low_ip);
-
-        rise_ip = rise_ip || (ival && !prev_ival);
-        s->rise_ip = deposit32(s->rise_ip, i, 1, rise_ip);
-
-        fall_ip = fall_ip || (!ival && prev_ival);
-        s->fall_ip = deposit32(s->fall_ip, i, 1, fall_ip);
-
-        /* Update value */
-        s->value = deposit32(s->value, i, 1, ival);
-    }
-    update_output_irq(s);
-}
-
-static uint64_t sifive_gpio_read(void *opaque, hwaddr offset, unsigned int size)
-{
-    SIFIVEGPIOState *s = SIFIVE_GPIO(opaque);
-    uint64_t r = 0;
-
-    switch (offset) {
-    case SIFIVE_GPIO_REG_VALUE:
-        r = s->value;
-        break;
-
-    case SIFIVE_GPIO_REG_INPUT_EN:
-        r = s->input_en;
-        break;
-
-    case SIFIVE_GPIO_REG_OUTPUT_EN:
-        r = s->output_en;
-        break;
-
-    case SIFIVE_GPIO_REG_PORT:
-        r = s->port;
-        break;
-
-    case SIFIVE_GPIO_REG_PUE:
-        r = s->pue;
-        break;
-
-    case SIFIVE_GPIO_REG_DS:
-        r = s->ds;
-        break;
-
-    case SIFIVE_GPIO_REG_RISE_IE:
-        r = s->rise_ie;
-        break;
-
-    case SIFIVE_GPIO_REG_RISE_IP:
-        r = s->rise_ip;
-        break;
-
-    case SIFIVE_GPIO_REG_FALL_IE:
-        r = s->fall_ie;
-        break;
-
-    case SIFIVE_GPIO_REG_FALL_IP:
-        r = s->fall_ip;
-        break;
-
-    case SIFIVE_GPIO_REG_HIGH_IE:
-        r = s->high_ie;
-        break;
-
-    case SIFIVE_GPIO_REG_HIGH_IP:
-        r = s->high_ip;
-        break;
-
-    case SIFIVE_GPIO_REG_LOW_IE:
-        r = s->low_ie;
-        break;
-
-    case SIFIVE_GPIO_REG_LOW_IP:
-        r = s->low_ip;
-        break;
-
-    case SIFIVE_GPIO_REG_IOF_EN:
-        r = s->iof_en;
-        break;
-
-    case SIFIVE_GPIO_REG_IOF_SEL:
-        r = s->iof_sel;
-        break;
-
-    case SIFIVE_GPIO_REG_OUT_XOR:
-        r = s->out_xor;
-        break;
-
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                "%s: bad read offset 0x%" HWADDR_PRIx "\n",
-                      __func__, offset);
-    }
-
-    trace_sifive_gpio_read(offset, r);
-
-    return r;
-}
-
-static void sifive_gpio_write(void *opaque, hwaddr offset,
-                              uint64_t value, unsigned int size)
-{
-    SIFIVEGPIOState *s = SIFIVE_GPIO(opaque);
-
-    trace_sifive_gpio_write(offset, value);
-
-    switch (offset) {
-
-    case SIFIVE_GPIO_REG_INPUT_EN:
-        s->input_en = value;
-        break;
-
-    case SIFIVE_GPIO_REG_OUTPUT_EN:
-        s->output_en = value;
-        break;
-
-    case SIFIVE_GPIO_REG_PORT:
-        s->port = value;
-        break;
-
-    case SIFIVE_GPIO_REG_PUE:
-        s->pue = value;
-        break;
-
-    case SIFIVE_GPIO_REG_DS:
-        s->ds = value;
-        break;
-
-    case SIFIVE_GPIO_REG_RISE_IE:
-        s->rise_ie = value;
-        break;
-
-    case SIFIVE_GPIO_REG_RISE_IP:
-         /* Write 1 to clear */
-        s->rise_ip &= ~value;
-        break;
-
-    case SIFIVE_GPIO_REG_FALL_IE:
-        s->fall_ie = value;
-        break;
-
-    case SIFIVE_GPIO_REG_FALL_IP:
-         /* Write 1 to clear */
-        s->fall_ip &= ~value;
-        break;
-
-    case SIFIVE_GPIO_REG_HIGH_IE:
-        s->high_ie = value;
-        break;
-
-    case SIFIVE_GPIO_REG_HIGH_IP:
-         /* Write 1 to clear */
-        s->high_ip &= ~value;
-        break;
-
-    case SIFIVE_GPIO_REG_LOW_IE:
-        s->low_ie = value;
-        break;
-
-    case SIFIVE_GPIO_REG_LOW_IP:
-         /* Write 1 to clear */
-        s->low_ip &= ~value;
-        break;
-
-    case SIFIVE_GPIO_REG_IOF_EN:
-        s->iof_en = value;
-        break;
-
-    case SIFIVE_GPIO_REG_IOF_SEL:
-        s->iof_sel = value;
-        break;
-
-    case SIFIVE_GPIO_REG_OUT_XOR:
-        s->out_xor = value;
-        break;
-
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "%s: bad write offset 0x%" HWADDR_PRIx "\n",
-                      __func__, offset);
-    }
-
-    update_state(s);
-}
-
-static const MemoryRegionOps gpio_ops = {
-    .read =  sifive_gpio_read,
-    .write = sifive_gpio_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl.min_access_size = 4,
-    .impl.max_access_size = 4,
-};
-
-static void sifive_gpio_set(void *opaque, int line, int value)
-{
-    SIFIVEGPIOState *s = SIFIVE_GPIO(opaque);
-
-    trace_sifive_gpio_set(line, value);
-
-    assert(line >= 0 && line < SIFIVE_GPIO_PINS);
-
-    s->in_mask = deposit32(s->in_mask, line, 1, value >= 0);
-    if (value >= 0) {
-        s->in = deposit32(s->in, line, 1, value != 0);
-    }
-
-    update_state(s);
-}
-
-static void sifive_gpio_reset(DeviceState *dev)
-{
-    SIFIVEGPIOState *s = SIFIVE_GPIO(dev);
-
-    s->value = 0;
-    s->input_en = 0;
-    s->output_en = 0;
-    s->port = 0;
-    s->pue = 0;
-    s->ds = 0;
-    s->rise_ie = 0;
-    s->rise_ip = 0;
-    s->fall_ie = 0;
-    s->fall_ip = 0;
-    s->high_ie = 0;
-    s->high_ip = 0;
-    s->low_ie = 0;
-    s->low_ip = 0;
-    s->iof_en = 0;
-    s->iof_sel = 0;
-    s->out_xor = 0;
-    s->in = 0;
-    s->in_mask = 0;
-}
-
-static const VMStateDescription vmstate_sifive_gpio = {
-    .name = TYPE_SIFIVE_GPIO,
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(value,     SIFIVEGPIOState),
-        VMSTATE_UINT32(input_en,  SIFIVEGPIOState),
-        VMSTATE_UINT32(output_en, SIFIVEGPIOState),
-        VMSTATE_UINT32(port,      SIFIVEGPIOState),
-        VMSTATE_UINT32(pue,       SIFIVEGPIOState),
-        VMSTATE_UINT32(rise_ie,   SIFIVEGPIOState),
-        VMSTATE_UINT32(rise_ip,   SIFIVEGPIOState),
-        VMSTATE_UINT32(fall_ie,   SIFIVEGPIOState),
-        VMSTATE_UINT32(fall_ip,   SIFIVEGPIOState),
-        VMSTATE_UINT32(high_ie,   SIFIVEGPIOState),
-        VMSTATE_UINT32(high_ip,   SIFIVEGPIOState),
-        VMSTATE_UINT32(low_ie,    SIFIVEGPIOState),
-        VMSTATE_UINT32(low_ip,    SIFIVEGPIOState),
-        VMSTATE_UINT32(iof_en,    SIFIVEGPIOState),
-        VMSTATE_UINT32(iof_sel,   SIFIVEGPIOState),
-        VMSTATE_UINT32(out_xor,   SIFIVEGPIOState),
-        VMSTATE_UINT32(in,        SIFIVEGPIOState),
-        VMSTATE_UINT32(in_mask,   SIFIVEGPIOState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property sifive_gpio_properties[] = {
-    DEFINE_PROP_UINT32("ngpio", SIFIVEGPIOState, ngpio, SIFIVE_GPIO_PINS),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sifive_gpio_realize(DeviceState *dev, Error **errp)
-{
-    SIFIVEGPIOState *s = SIFIVE_GPIO(dev);
-
-    memory_region_init_io(&s->mmio, OBJECT(dev), &gpio_ops, s,
-            TYPE_SIFIVE_GPIO, SIFIVE_GPIO_SIZE);
-
-    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
-
-    for (int i = 0; i < s->ngpio; i++) {
-        sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
-    }
-
-    qdev_init_gpio_in(DEVICE(s), sifive_gpio_set, s->ngpio);
-    qdev_init_gpio_out(DEVICE(s), s->output, s->ngpio);
-}
-
-static void sifive_gpio_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    device_class_set_props(dc, sifive_gpio_properties);
-    dc->vmsd = &vmstate_sifive_gpio;
-    dc->realize = sifive_gpio_realize;
-    dc->reset = sifive_gpio_reset;
-    dc->desc = "SiFive GPIO";
-}
-
-static const TypeInfo sifive_gpio_info = {
-    .name = TYPE_SIFIVE_GPIO,
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SIFIVEGPIOState),
-    .class_init = sifive_gpio_class_init
-};
-
-static void sifive_gpio_register_types(void)
-{
-    type_register_static(&sifive_gpio_info);
-}
-
-type_init(sifive_gpio_register_types)
diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c
deleted file mode 100644
index 11ef147606..0000000000
--- a/hw/riscv/sifive_plic.c
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * SiFive PLIC (Platform Level Interrupt Controller)
- *
- * Copyright (c) 2017 SiFive, Inc.
- *
- * This provides a parameterizable interrupt controller based on SiFive's PLIC.
- *
- * 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 "qemu/log.h"
-#include "qemu/module.h"
-#include "qemu/error-report.h"
-#include "hw/sysbus.h"
-#include "hw/pci/msi.h"
-#include "hw/boards.h"
-#include "hw/qdev-properties.h"
-#include "target/riscv/cpu.h"
-#include "sysemu/sysemu.h"
-#include "hw/riscv/sifive_plic.h"
-
-#define RISCV_DEBUG_PLIC 0
-
-static PLICMode char_to_mode(char c)
-{
-    switch (c) {
-    case 'U': return PLICMode_U;
-    case 'S': return PLICMode_S;
-    case 'H': return PLICMode_H;
-    case 'M': return PLICMode_M;
-    default:
-        error_report("plic: invalid mode '%c'", c);
-        exit(1);
-    }
-}
-
-static char mode_to_char(PLICMode m)
-{
-    switch (m) {
-    case PLICMode_U: return 'U';
-    case PLICMode_S: return 'S';
-    case PLICMode_H: return 'H';
-    case PLICMode_M: return 'M';
-    default: return '?';
-    }
-}
-
-static void sifive_plic_print_state(SiFivePLICState *plic)
-{
-    int i;
-    int addrid;
-
-    /* pending */
-    qemu_log("pending       : ");
-    for (i = plic->bitfield_words - 1; i >= 0; i--) {
-        qemu_log("%08x", plic->pending[i]);
-    }
-    qemu_log("\n");
-
-    /* pending */
-    qemu_log("claimed       : ");
-    for (i = plic->bitfield_words - 1; i >= 0; i--) {
-        qemu_log("%08x", plic->claimed[i]);
-    }
-    qemu_log("\n");
-
-    for (addrid = 0; addrid < plic->num_addrs; addrid++) {
-        qemu_log("hart%d-%c enable: ",
-            plic->addr_config[addrid].hartid,
-            mode_to_char(plic->addr_config[addrid].mode));
-        for (i = plic->bitfield_words - 1; i >= 0; i--) {
-            qemu_log("%08x", plic->enable[addrid * plic->bitfield_words + i]);
-        }
-        qemu_log("\n");
-    }
-}
-
-static uint32_t atomic_set_masked(uint32_t *a, uint32_t mask, uint32_t value)
-{
-    uint32_t old, new, cmp = atomic_read(a);
-
-    do {
-        old = cmp;
-        new = (old & ~mask) | (value & mask);
-        cmp = atomic_cmpxchg(a, old, new);
-    } while (old != cmp);
-
-    return old;
-}
-
-static void sifive_plic_set_pending(SiFivePLICState *plic, int irq, bool level)
-{
-    atomic_set_masked(&plic->pending[irq >> 5], 1 << (irq & 31), -!!level);
-}
-
-static void sifive_plic_set_claimed(SiFivePLICState *plic, int irq, bool level)
-{
-    atomic_set_masked(&plic->claimed[irq >> 5], 1 << (irq & 31), -!!level);
-}
-
-static int sifive_plic_irqs_pending(SiFivePLICState *plic, uint32_t addrid)
-{
-    int i, j;
-    for (i = 0; i < plic->bitfield_words; i++) {
-        uint32_t pending_enabled_not_claimed =
-            (plic->pending[i] & ~plic->claimed[i]) &
-            plic->enable[addrid * plic->bitfield_words + i];
-        if (!pending_enabled_not_claimed) {
-            continue;
-        }
-        for (j = 0; j < 32; j++) {
-            int irq = (i << 5) + j;
-            uint32_t prio = plic->source_priority[irq];
-            int enabled = pending_enabled_not_claimed & (1 << j);
-            if (enabled && prio > plic->target_priority[addrid]) {
-                return 1;
-            }
-        }
-    }
-    return 0;
-}
-
-static void sifive_plic_update(SiFivePLICState *plic)
-{
-    int addrid;
-
-    /* raise irq on harts where this irq is enabled */
-    for (addrid = 0; addrid < plic->num_addrs; addrid++) {
-        uint32_t hartid = plic->addr_config[addrid].hartid;
-        PLICMode mode = plic->addr_config[addrid].mode;
-        CPUState *cpu = qemu_get_cpu(hartid);
-        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
-        if (!env) {
-            continue;
-        }
-        int level = sifive_plic_irqs_pending(plic, addrid);
-        switch (mode) {
-        case PLICMode_M:
-            riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MEIP, BOOL_TO_MASK(level));
-            break;
-        case PLICMode_S:
-            riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_SEIP, BOOL_TO_MASK(level));
-            break;
-        default:
-            break;
-        }
-    }
-
-    if (RISCV_DEBUG_PLIC) {
-        sifive_plic_print_state(plic);
-    }
-}
-
-static uint32_t sifive_plic_claim(SiFivePLICState *plic, uint32_t addrid)
-{
-    int i, j;
-    uint32_t max_irq = 0;
-    uint32_t max_prio = plic->target_priority[addrid];
-
-    for (i = 0; i < plic->bitfield_words; i++) {
-        uint32_t pending_enabled_not_claimed =
-            (plic->pending[i] & ~plic->claimed[i]) &
-            plic->enable[addrid * plic->bitfield_words + i];
-        if (!pending_enabled_not_claimed) {
-            continue;
-        }
-        for (j = 0; j < 32; j++) {
-            int irq = (i << 5) + j;
-            uint32_t prio = plic->source_priority[irq];
-            int enabled = pending_enabled_not_claimed & (1 << j);
-            if (enabled && prio > max_prio) {
-                max_irq = irq;
-                max_prio = prio;
-            }
-        }
-    }
-
-    if (max_irq) {
-        sifive_plic_set_pending(plic, max_irq, false);
-        sifive_plic_set_claimed(plic, max_irq, true);
-    }
-    return max_irq;
-}
-
-static uint64_t sifive_plic_read(void *opaque, hwaddr addr, unsigned size)
-{
-    SiFivePLICState *plic = opaque;
-
-    /* writes must be 4 byte words */
-    if ((addr & 0x3) != 0) {
-        goto err;
-    }
-
-    if (addr >= plic->priority_base && /* 4 bytes per source */
-        addr < plic->priority_base + (plic->num_sources << 2))
-    {
-        uint32_t irq = ((addr - plic->priority_base) >> 2) + 1;
-        if (RISCV_DEBUG_PLIC) {
-            qemu_log("plic: read priority: irq=%d priority=%d\n",
-                irq, plic->source_priority[irq]);
-        }
-        return plic->source_priority[irq];
-    } else if (addr >= plic->pending_base && /* 1 bit per source */
-               addr < plic->pending_base + (plic->num_sources >> 3))
-    {
-        uint32_t word = (addr - plic->pending_base) >> 2;
-        if (RISCV_DEBUG_PLIC) {
-            qemu_log("plic: read pending: word=%d value=%d\n",
-                word, plic->pending[word]);
-        }
-        return plic->pending[word];
-    } else if (addr >= plic->enable_base && /* 1 bit per source */
-             addr < plic->enable_base + plic->num_addrs * plic->enable_stride)
-    {
-        uint32_t addrid = (addr - plic->enable_base) / plic->enable_stride;
-        uint32_t wordid = (addr & (plic->enable_stride - 1)) >> 2;
-        if (wordid < plic->bitfield_words) {
-            if (RISCV_DEBUG_PLIC) {
-                qemu_log("plic: read enable: hart%d-%c word=%d value=%x\n",
-                    plic->addr_config[addrid].hartid,
-                    mode_to_char(plic->addr_config[addrid].mode), wordid,
-                    plic->enable[addrid * plic->bitfield_words + wordid]);
-            }
-            return plic->enable[addrid * plic->bitfield_words + wordid];
-        }
-    } else if (addr >= plic->context_base && /* 1 bit per source */
-             addr < plic->context_base + plic->num_addrs * plic->context_stride)
-    {
-        uint32_t addrid = (addr - plic->context_base) / plic->context_stride;
-        uint32_t contextid = (addr & (plic->context_stride - 1));
-        if (contextid == 0) {
-            if (RISCV_DEBUG_PLIC) {
-                qemu_log("plic: read priority: hart%d-%c priority=%x\n",
-                    plic->addr_config[addrid].hartid,
-                    mode_to_char(plic->addr_config[addrid].mode),
-                    plic->target_priority[addrid]);
-            }
-            return plic->target_priority[addrid];
-        } else if (contextid == 4) {
-            uint32_t value = sifive_plic_claim(plic, addrid);
-            if (RISCV_DEBUG_PLIC) {
-                qemu_log("plic: read claim: hart%d-%c irq=%x\n",
-                    plic->addr_config[addrid].hartid,
-                    mode_to_char(plic->addr_config[addrid].mode),
-                    value);
-            }
-            sifive_plic_update(plic);
-            return value;
-        }
-    }
-
-err:
-    qemu_log_mask(LOG_GUEST_ERROR,
-                  "%s: Invalid register read 0x%" HWADDR_PRIx "\n",
-                  __func__, addr);
-    return 0;
-}
-
-static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value,
-        unsigned size)
-{
-    SiFivePLICState *plic = opaque;
-
-    /* writes must be 4 byte words */
-    if ((addr & 0x3) != 0) {
-        goto err;
-    }
-
-    if (addr >= plic->priority_base && /* 4 bytes per source */
-        addr < plic->priority_base + (plic->num_sources << 2))
-    {
-        uint32_t irq = ((addr - plic->priority_base) >> 2) + 1;
-        plic->source_priority[irq] = value & 7;
-        if (RISCV_DEBUG_PLIC) {
-            qemu_log("plic: write priority: irq=%d priority=%d\n",
-                irq, plic->source_priority[irq]);
-        }
-        sifive_plic_update(plic);
-        return;
-    } else if (addr >= plic->pending_base && /* 1 bit per source */
-               addr < plic->pending_base + (plic->num_sources >> 3))
-    {
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "%s: invalid pending write: 0x%" HWADDR_PRIx "",
-                      __func__, addr);
-        return;
-    } else if (addr >= plic->enable_base && /* 1 bit per source */
-        addr < plic->enable_base + plic->num_addrs * plic->enable_stride)
-    {
-        uint32_t addrid = (addr - plic->enable_base) / plic->enable_stride;
-        uint32_t wordid = (addr & (plic->enable_stride - 1)) >> 2;
-        if (wordid < plic->bitfield_words) {
-            plic->enable[addrid * plic->bitfield_words + wordid] = value;
-            if (RISCV_DEBUG_PLIC) {
-                qemu_log("plic: write enable: hart%d-%c word=%d value=%x\n",
-                    plic->addr_config[addrid].hartid,
-                    mode_to_char(plic->addr_config[addrid].mode), wordid,
-                    plic->enable[addrid * plic->bitfield_words + wordid]);
-            }
-            return;
-        }
-    } else if (addr >= plic->context_base && /* 4 bytes per reg */
-        addr < plic->context_base + plic->num_addrs * plic->context_stride)
-    {
-        uint32_t addrid = (addr - plic->context_base) / plic->context_stride;
-        uint32_t contextid = (addr & (plic->context_stride - 1));
-        if (contextid == 0) {
-            if (RISCV_DEBUG_PLIC) {
-                qemu_log("plic: write priority: hart%d-%c priority=%x\n",
-                    plic->addr_config[addrid].hartid,
-                    mode_to_char(plic->addr_config[addrid].mode),
-                    plic->target_priority[addrid]);
-            }
-            if (value <= plic->num_priorities) {
-                plic->target_priority[addrid] = value;
-                sifive_plic_update(plic);
-            }
-            return;
-        } else if (contextid == 4) {
-            if (RISCV_DEBUG_PLIC) {
-                qemu_log("plic: write claim: hart%d-%c irq=%x\n",
-                    plic->addr_config[addrid].hartid,
-                    mode_to_char(plic->addr_config[addrid].mode),
-                    (uint32_t)value);
-            }
-            if (value < plic->num_sources) {
-                sifive_plic_set_claimed(plic, value, false);
-                sifive_plic_update(plic);
-            }
-            return;
-        }
-    }
-
-err:
-    qemu_log_mask(LOG_GUEST_ERROR,
-                  "%s: Invalid register write 0x%" HWADDR_PRIx "\n",
-                  __func__, addr);
-}
-
-static const MemoryRegionOps sifive_plic_ops = {
-    .read = sifive_plic_read,
-    .write = sifive_plic_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static Property sifive_plic_properties[] = {
-    DEFINE_PROP_STRING("hart-config", SiFivePLICState, hart_config),
-    DEFINE_PROP_UINT32("hartid-base", SiFivePLICState, hartid_base, 0),
-    DEFINE_PROP_UINT32("num-sources", SiFivePLICState, num_sources, 0),
-    DEFINE_PROP_UINT32("num-priorities", SiFivePLICState, num_priorities, 0),
-    DEFINE_PROP_UINT32("priority-base", SiFivePLICState, priority_base, 0),
-    DEFINE_PROP_UINT32("pending-base", SiFivePLICState, pending_base, 0),
-    DEFINE_PROP_UINT32("enable-base", SiFivePLICState, enable_base, 0),
-    DEFINE_PROP_UINT32("enable-stride", SiFivePLICState, enable_stride, 0),
-    DEFINE_PROP_UINT32("context-base", SiFivePLICState, context_base, 0),
-    DEFINE_PROP_UINT32("context-stride", SiFivePLICState, context_stride, 0),
-    DEFINE_PROP_UINT32("aperture-size", SiFivePLICState, aperture_size, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-/*
- * parse PLIC hart/mode address offset config
- *
- * "M"              1 hart with M mode
- * "MS,MS"          2 harts, 0-1 with M and S mode
- * "M,MS,MS,MS,MS"  5 harts, 0 with M mode, 1-5 with M and S mode
- */
-static void parse_hart_config(SiFivePLICState *plic)
-{
-    int addrid, hartid, modes;
-    const char *p;
-    char c;
-
-    /* count and validate hart/mode combinations */
-    addrid = 0, hartid = 0, modes = 0;
-    p = plic->hart_config;
-    while ((c = *p++)) {
-        if (c == ',') {
-            addrid += ctpop8(modes);
-            modes = 0;
-            hartid++;
-        } else {
-            int m = 1 << char_to_mode(c);
-            if (modes == (modes | m)) {
-                error_report("plic: duplicate mode '%c' in config: %s",
-                             c, plic->hart_config);
-                exit(1);
-            }
-            modes |= m;
-        }
-    }
-    if (modes) {
-        addrid += ctpop8(modes);
-    }
-    hartid++;
-
-    plic->num_addrs = addrid;
-    plic->num_harts = hartid;
-
-    /* store hart/mode combinations */
-    plic->addr_config = g_new(PLICAddr, plic->num_addrs);
-    addrid = 0, hartid = plic->hartid_base;
-    p = plic->hart_config;
-    while ((c = *p++)) {
-        if (c == ',') {
-            hartid++;
-        } else {
-            plic->addr_config[addrid].addrid = addrid;
-            plic->addr_config[addrid].hartid = hartid;
-            plic->addr_config[addrid].mode = char_to_mode(c);
-            addrid++;
-        }
-    }
-}
-
-static void sifive_plic_irq_request(void *opaque, int irq, int level)
-{
-    SiFivePLICState *plic = opaque;
-    if (RISCV_DEBUG_PLIC) {
-        qemu_log("sifive_plic_irq_request: irq=%d level=%d\n", irq, level);
-    }
-    sifive_plic_set_pending(plic, irq, level > 0);
-    sifive_plic_update(plic);
-}
-
-static void sifive_plic_realize(DeviceState *dev, Error **errp)
-{
-    SiFivePLICState *plic = SIFIVE_PLIC(dev);
-    int i;
-
-    memory_region_init_io(&plic->mmio, OBJECT(dev), &sifive_plic_ops, plic,
-                          TYPE_SIFIVE_PLIC, plic->aperture_size);
-    parse_hart_config(plic);
-    plic->bitfield_words = (plic->num_sources + 31) >> 5;
-    plic->source_priority = g_new0(uint32_t, plic->num_sources);
-    plic->target_priority = g_new(uint32_t, plic->num_addrs);
-    plic->pending = g_new0(uint32_t, plic->bitfield_words);
-    plic->claimed = g_new0(uint32_t, plic->bitfield_words);
-    plic->enable = g_new0(uint32_t, plic->bitfield_words * plic->num_addrs);
-    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &plic->mmio);
-    qdev_init_gpio_in(dev, sifive_plic_irq_request, plic->num_sources);
-
-    /* We can't allow the supervisor to control SEIP as this would allow the
-     * supervisor to clear a pending external interrupt which will result in
-     * lost a interrupt in the case a PLIC is attached. The SEIP bit must be
-     * hardware controlled when a PLIC is attached.
-     */
-    for (i = 0; i < plic->num_harts; i++) {
-        RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(plic->hartid_base + i));
-        if (riscv_cpu_claim_interrupts(cpu, MIP_SEIP) < 0) {
-            error_report("SEIP already claimed");
-            exit(1);
-        }
-    }
-
-    msi_nonbroken = true;
-}
-
-static void sifive_plic_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    device_class_set_props(dc, sifive_plic_properties);
-    dc->realize = sifive_plic_realize;
-}
-
-static const TypeInfo sifive_plic_info = {
-    .name          = TYPE_SIFIVE_PLIC,
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SiFivePLICState),
-    .class_init    = sifive_plic_class_init,
-};
-
-static void sifive_plic_register_types(void)
-{
-    type_register_static(&sifive_plic_info);
-}
-
-type_init(sifive_plic_register_types)
-
-/*
- * Create PLIC device.
- */
-DeviceState *sifive_plic_create(hwaddr addr, char *hart_config,
-    uint32_t hartid_base, uint32_t num_sources,
-    uint32_t num_priorities, uint32_t priority_base,
-    uint32_t pending_base, uint32_t enable_base,
-    uint32_t enable_stride, uint32_t context_base,
-    uint32_t context_stride, uint32_t aperture_size)
-{
-    DeviceState *dev = qdev_new(TYPE_SIFIVE_PLIC);
-    assert(enable_stride == (enable_stride & -enable_stride));
-    assert(context_stride == (context_stride & -context_stride));
-    qdev_prop_set_string(dev, "hart-config", hart_config);
-    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
-    qdev_prop_set_uint32(dev, "num-sources", num_sources);
-    qdev_prop_set_uint32(dev, "num-priorities", num_priorities);
-    qdev_prop_set_uint32(dev, "priority-base", priority_base);
-    qdev_prop_set_uint32(dev, "pending-base", pending_base);
-    qdev_prop_set_uint32(dev, "enable-base", enable_base);
-    qdev_prop_set_uint32(dev, "enable-stride", enable_stride);
-    qdev_prop_set_uint32(dev, "context-base", context_base);
-    qdev_prop_set_uint32(dev, "context-stride", context_stride);
-    qdev_prop_set_uint32(dev, "aperture-size", aperture_size);
-    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
-    return dev;
-}
diff --git a/hw/riscv/sifive_test.c b/hw/riscv/sifive_test.c
deleted file mode 100644
index 0c78fb2c93..0000000000
--- a/hw/riscv/sifive_test.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * QEMU SiFive Test Finisher
- *
- * Copyright (c) 2018 SiFive, Inc.
- *
- * Test finisher memory mapped device used to exit simulation
- *
- * 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 "hw/sysbus.h"
-#include "qapi/error.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "sysemu/runstate.h"
-#include "hw/hw.h"
-#include "hw/riscv/sifive_test.h"
-
-static uint64_t sifive_test_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    return 0;
-}
-
-static void sifive_test_write(void *opaque, hwaddr addr,
-           uint64_t val64, unsigned int size)
-{
-    if (addr == 0) {
-        int status = val64 & 0xffff;
-        int code = (val64 >> 16) & 0xffff;
-        switch (status) {
-        case FINISHER_FAIL:
-            exit(code);
-        case FINISHER_PASS:
-            exit(0);
-        case FINISHER_RESET:
-            qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
-            return;
-        default:
-            break;
-        }
-    }
-    qemu_log_mask(LOG_GUEST_ERROR, "%s: write: addr=0x%x val=0x%016" PRIx64 "\n",
-                  __func__, (int)addr, val64);
-}
-
-static const MemoryRegionOps sifive_test_ops = {
-    .read = sifive_test_read,
-    .write = sifive_test_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static void sifive_test_init(Object *obj)
-{
-    SiFiveTestState *s = SIFIVE_TEST(obj);
-
-    memory_region_init_io(&s->mmio, obj, &sifive_test_ops, s,
-                          TYPE_SIFIVE_TEST, 0x1000);
-    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
-}
-
-static const TypeInfo sifive_test_info = {
-    .name          = TYPE_SIFIVE_TEST,
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SiFiveTestState),
-    .instance_init = sifive_test_init,
-};
-
-static void sifive_test_register_types(void)
-{
-    type_register_static(&sifive_test_info);
-}
-
-type_init(sifive_test_register_types)
-
-
-/*
- * Create Test device.
- */
-DeviceState *sifive_test_create(hwaddr addr)
-{
-    DeviceState *dev = qdev_new(TYPE_SIFIVE_TEST);
-    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
-    return dev;
-}
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index a48046c6a0..4f12a93188 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -14,6 +14,7 @@
  * 4) GPIO (General Purpose Input/Output Controller)
  * 5) OTP (One-Time Programmable) memory with stored serial number
  * 6) GEM (Gigabit Ethernet Controller) and management block
+ * 7) DMA (Direct Memory Access Controller)
  *
  * This board currently generates devicetree dynamically that indicates at least
  * two harts and up to five harts.
@@ -45,11 +46,11 @@
 #include "hw/misc/unimp.h"
 #include "target/riscv/cpu.h"
 #include "hw/riscv/riscv_hart.h"
-#include "hw/riscv/sifive_plic.h"
-#include "hw/riscv/sifive_clint.h"
-#include "hw/riscv/sifive_uart.h"
 #include "hw/riscv/sifive_u.h"
 #include "hw/riscv/boot.h"
+#include "hw/char/sifive_uart.h"
+#include "hw/intc/sifive_clint.h"
+#include "hw/intc/sifive_plic.h"
 #include "chardev/char.h"
 #include "net/eth.h"
 #include "sysemu/arch_init.h"
@@ -73,6 +74,7 @@ static const struct MemmapEntry {
     [SIFIVE_U_MROM] =     {     0x1000,     0xf000 },
     [SIFIVE_U_CLINT] =    {  0x2000000,    0x10000 },
     [SIFIVE_U_L2CC] =     {  0x2010000,     0x1000 },
+    [SIFIVE_U_PDMA] =     {  0x3000000,   0x100000 },
     [SIFIVE_U_L2LIM] =    {  0x8000000,  0x2000000 },
     [SIFIVE_U_PLIC] =     {  0xc000000,  0x4000000 },
     [SIFIVE_U_PRCI] =     { 0x10000000,     0x1000 },
@@ -303,6 +305,22 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
     qemu_fdt_setprop_string(fdt, nodename, "compatible", "gpio-restart");
     g_free(nodename);
 
+    nodename = g_strdup_printf("/soc/dma@%lx",
+        (long)memmap[SIFIVE_U_PDMA].base);
+    qemu_fdt_add_subnode(fdt, nodename);
+    qemu_fdt_setprop_cell(fdt, nodename, "#dma-cells", 1);
+    qemu_fdt_setprop_cells(fdt, nodename, "interrupts",
+        SIFIVE_U_PDMA_IRQ0, SIFIVE_U_PDMA_IRQ1, SIFIVE_U_PDMA_IRQ2,
+        SIFIVE_U_PDMA_IRQ3, SIFIVE_U_PDMA_IRQ4, SIFIVE_U_PDMA_IRQ5,
+        SIFIVE_U_PDMA_IRQ6, SIFIVE_U_PDMA_IRQ7);
+    qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
+    qemu_fdt_setprop_cells(fdt, nodename, "reg",
+        0x0, memmap[SIFIVE_U_PDMA].base,
+        0x0, memmap[SIFIVE_U_PDMA].size);
+    qemu_fdt_setprop_string(fdt, nodename, "compatible",
+                            "sifive,fu540-c000-pdma");
+    g_free(nodename);
+
     nodename = g_strdup_printf("/soc/cache-controller@%lx",
         (long)memmap[SIFIVE_U_L2CC].base);
     qemu_fdt_add_subnode(fdt, nodename);
@@ -611,6 +629,7 @@ static void sifive_u_soc_instance_init(Object *obj)
     qdev_prop_set_uint32(DEVICE(&s->e_cpus), "num-harts", 1);
     qdev_prop_set_uint32(DEVICE(&s->e_cpus), "hartid-base", 0);
     qdev_prop_set_string(DEVICE(&s->e_cpus), "cpu-type", SIFIVE_E_CPU);
+    qdev_prop_set_uint64(DEVICE(&s->e_cpus), "resetvec", 0x1004);
 
     object_initialize_child(obj, "u-cluster", &s->u_cluster, TYPE_CPU_CLUSTER);
     qdev_prop_set_uint32(DEVICE(&s->u_cluster), "cluster-id", 1);
@@ -620,11 +639,13 @@ static void sifive_u_soc_instance_init(Object *obj)
     qdev_prop_set_uint32(DEVICE(&s->u_cpus), "num-harts", ms->smp.cpus - 1);
     qdev_prop_set_uint32(DEVICE(&s->u_cpus), "hartid-base", 1);
     qdev_prop_set_string(DEVICE(&s->u_cpus), "cpu-type", SIFIVE_U_CPU);
+    qdev_prop_set_uint64(DEVICE(&s->u_cpus), "resetvec", 0x1004);
 
     object_initialize_child(obj, "prci", &s->prci, TYPE_SIFIVE_U_PRCI);
     object_initialize_child(obj, "otp", &s->otp, TYPE_SIFIVE_U_OTP);
     object_initialize_child(obj, "gem", &s->gem, TYPE_CADENCE_GEM);
     object_initialize_child(obj, "gpio", &s->gpio, TYPE_SIFIVE_GPIO);
+    object_initialize_child(obj, "pdma", &s->dma, TYPE_SIFIVE_PDMA);
 }
 
 static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
@@ -704,7 +725,8 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
         serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
     sifive_clint_create(memmap[SIFIVE_U_CLINT].base,
         memmap[SIFIVE_U_CLINT].size, 0, ms->smp.cpus,
-        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, false);
+        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
+        SIFIVE_CLINT_TIMEBASE_FREQ, false);
 
     if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) {
         return;
@@ -727,6 +749,17 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
                                             SIFIVE_U_GPIO_IRQ0 + i));
     }
 
+    /* PDMA */
+    sysbus_realize(SYS_BUS_DEVICE(&s->dma), errp);
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->dma), 0, memmap[SIFIVE_U_PDMA].base);
+
+    /* Connect PDMA interrupts to the PLIC */
+    for (i = 0; i < SIFIVE_PDMA_IRQS; i++) {
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), i,
+                           qdev_get_gpio_in(DEVICE(s->plic),
+                                            SIFIVE_U_PDMA_IRQ0 + i));
+    }
+
     qdev_prop_set_uint32(DEVICE(&s->otp), "serial", s->serial);
     if (!sysbus_realize(SYS_BUS_DEVICE(&s->otp), errp)) {
         return;
diff --git a/hw/riscv/sifive_u_otp.c b/hw/riscv/sifive_u_otp.c
deleted file mode 100644
index f6ecbaa2ca..0000000000
--- a/hw/riscv/sifive_u_otp.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * QEMU SiFive U OTP (One-Time Programmable) Memory interface
- *
- * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
- *
- * Simple model of the OTP to emulate register reads made by the SDK BSP
- *
- * 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 "hw/qdev-properties.h"
-#include "hw/sysbus.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "hw/riscv/sifive_u_otp.h"
-
-static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    SiFiveUOTPState *s = opaque;
-
-    switch (addr) {
-    case SIFIVE_U_OTP_PA:
-        return s->pa;
-    case SIFIVE_U_OTP_PAIO:
-        return s->paio;
-    case SIFIVE_U_OTP_PAS:
-        return s->pas;
-    case SIFIVE_U_OTP_PCE:
-        return s->pce;
-    case SIFIVE_U_OTP_PCLK:
-        return s->pclk;
-    case SIFIVE_U_OTP_PDIN:
-        return s->pdin;
-    case SIFIVE_U_OTP_PDOUT:
-        if ((s->pce & SIFIVE_U_OTP_PCE_EN) &&
-            (s->pdstb & SIFIVE_U_OTP_PDSTB_EN) &&
-            (s->ptrim & SIFIVE_U_OTP_PTRIM_EN)) {
-            return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK];
-        } else {
-            return 0xff;
-        }
-    case SIFIVE_U_OTP_PDSTB:
-        return s->pdstb;
-    case SIFIVE_U_OTP_PPROG:
-        return s->pprog;
-    case SIFIVE_U_OTP_PTC:
-        return s->ptc;
-    case SIFIVE_U_OTP_PTM:
-        return s->ptm;
-    case SIFIVE_U_OTP_PTM_REP:
-        return s->ptm_rep;
-    case SIFIVE_U_OTP_PTR:
-        return s->ptr;
-    case SIFIVE_U_OTP_PTRIM:
-        return s->ptrim;
-    case SIFIVE_U_OTP_PWE:
-        return s->pwe;
-    }
-
-    qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n",
-                  __func__, addr);
-    return 0;
-}
-
-static void sifive_u_otp_write(void *opaque, hwaddr addr,
-                               uint64_t val64, unsigned int size)
-{
-    SiFiveUOTPState *s = opaque;
-    uint32_t val32 = (uint32_t)val64;
-
-    switch (addr) {
-    case SIFIVE_U_OTP_PA:
-        s->pa = val32 & SIFIVE_U_OTP_PA_MASK;
-        break;
-    case SIFIVE_U_OTP_PAIO:
-        s->paio = val32;
-        break;
-    case SIFIVE_U_OTP_PAS:
-        s->pas = val32;
-        break;
-    case SIFIVE_U_OTP_PCE:
-        s->pce = val32;
-        break;
-    case SIFIVE_U_OTP_PCLK:
-        s->pclk = val32;
-        break;
-    case SIFIVE_U_OTP_PDIN:
-        s->pdin = val32;
-        break;
-    case SIFIVE_U_OTP_PDOUT:
-        /* read-only */
-        break;
-    case SIFIVE_U_OTP_PDSTB:
-        s->pdstb = val32;
-        break;
-    case SIFIVE_U_OTP_PPROG:
-        s->pprog = val32;
-        break;
-    case SIFIVE_U_OTP_PTC:
-        s->ptc = val32;
-        break;
-    case SIFIVE_U_OTP_PTM:
-        s->ptm = val32;
-        break;
-    case SIFIVE_U_OTP_PTM_REP:
-        s->ptm_rep = val32;
-        break;
-    case SIFIVE_U_OTP_PTR:
-        s->ptr = val32;
-        break;
-    case SIFIVE_U_OTP_PTRIM:
-        s->ptrim = val32;
-        break;
-    case SIFIVE_U_OTP_PWE:
-        s->pwe = val32;
-        break;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx
-                      " v=0x%x\n", __func__, addr, val32);
-    }
-}
-
-static const MemoryRegionOps sifive_u_otp_ops = {
-    .read = sifive_u_otp_read,
-    .write = sifive_u_otp_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static Property sifive_u_otp_properties[] = {
-    DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sifive_u_otp_realize(DeviceState *dev, Error **errp)
-{
-    SiFiveUOTPState *s = SIFIVE_U_OTP(dev);
-
-    memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_otp_ops, s,
-                          TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE);
-    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
-}
-
-static void sifive_u_otp_reset(DeviceState *dev)
-{
-    SiFiveUOTPState *s = SIFIVE_U_OTP(dev);
-
-    /* Initialize all fuses' initial value to 0xFFs */
-    memset(s->fuse, 0xff, sizeof(s->fuse));
-
-    /* Make a valid content of serial number */
-    s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial;
-    s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(s->serial);
-}
-
-static void sifive_u_otp_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    device_class_set_props(dc, sifive_u_otp_properties);
-    dc->realize = sifive_u_otp_realize;
-    dc->reset = sifive_u_otp_reset;
-}
-
-static const TypeInfo sifive_u_otp_info = {
-    .name          = TYPE_SIFIVE_U_OTP,
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SiFiveUOTPState),
-    .class_init    = sifive_u_otp_class_init,
-};
-
-static void sifive_u_otp_register_types(void)
-{
-    type_register_static(&sifive_u_otp_info);
-}
-
-type_init(sifive_u_otp_register_types)
diff --git a/hw/riscv/sifive_u_prci.c b/hw/riscv/sifive_u_prci.c
deleted file mode 100644
index 4fa590c064..0000000000
--- a/hw/riscv/sifive_u_prci.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * QEMU SiFive U PRCI (Power, Reset, Clock, Interrupt)
- *
- * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
- *
- * Simple model of the PRCI to emulate register reads made by the SDK BSP
- *
- * 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 "hw/sysbus.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "hw/riscv/sifive_u_prci.h"
-
-static uint64_t sifive_u_prci_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    SiFiveUPRCIState *s = opaque;
-
-    switch (addr) {
-    case SIFIVE_U_PRCI_HFXOSCCFG:
-        return s->hfxosccfg;
-    case SIFIVE_U_PRCI_COREPLLCFG0:
-        return s->corepllcfg0;
-    case SIFIVE_U_PRCI_DDRPLLCFG0:
-        return s->ddrpllcfg0;
-    case SIFIVE_U_PRCI_DDRPLLCFG1:
-        return s->ddrpllcfg1;
-    case SIFIVE_U_PRCI_GEMGXLPLLCFG0:
-        return s->gemgxlpllcfg0;
-    case SIFIVE_U_PRCI_GEMGXLPLLCFG1:
-        return s->gemgxlpllcfg1;
-    case SIFIVE_U_PRCI_CORECLKSEL:
-        return s->coreclksel;
-    case SIFIVE_U_PRCI_DEVICESRESET:
-        return s->devicesreset;
-    case SIFIVE_U_PRCI_CLKMUXSTATUS:
-        return s->clkmuxstatus;
-    }
-
-    qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n",
-                  __func__, addr);
-
-    return 0;
-}
-
-static void sifive_u_prci_write(void *opaque, hwaddr addr,
-                                uint64_t val64, unsigned int size)
-{
-    SiFiveUPRCIState *s = opaque;
-    uint32_t val32 = (uint32_t)val64;
-
-    switch (addr) {
-    case SIFIVE_U_PRCI_HFXOSCCFG:
-        s->hfxosccfg = val32;
-        /* OSC stays ready */
-        s->hfxosccfg |= SIFIVE_U_PRCI_HFXOSCCFG_RDY;
-        break;
-    case SIFIVE_U_PRCI_COREPLLCFG0:
-        s->corepllcfg0 = val32;
-        /* internal feedback */
-        s->corepllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE;
-        /* PLL stays locked */
-        s->corepllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK;
-        break;
-    case SIFIVE_U_PRCI_DDRPLLCFG0:
-        s->ddrpllcfg0 = val32;
-        /* internal feedback */
-        s->ddrpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE;
-        /* PLL stays locked */
-        s->ddrpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK;
-        break;
-    case SIFIVE_U_PRCI_DDRPLLCFG1:
-        s->ddrpllcfg1 = val32;
-        break;
-    case SIFIVE_U_PRCI_GEMGXLPLLCFG0:
-        s->gemgxlpllcfg0 = val32;
-        /* internal feedback */
-        s->gemgxlpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE;
-        /* PLL stays locked */
-        s->gemgxlpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK;
-        break;
-    case SIFIVE_U_PRCI_GEMGXLPLLCFG1:
-        s->gemgxlpllcfg1 = val32;
-        break;
-    case SIFIVE_U_PRCI_CORECLKSEL:
-        s->coreclksel = val32;
-        break;
-    case SIFIVE_U_PRCI_DEVICESRESET:
-        s->devicesreset = val32;
-        break;
-    case SIFIVE_U_PRCI_CLKMUXSTATUS:
-        s->clkmuxstatus = val32;
-        break;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx
-                      " v=0x%x\n", __func__, addr, val32);
-    }
-}
-
-static const MemoryRegionOps sifive_u_prci_ops = {
-    .read = sifive_u_prci_read,
-    .write = sifive_u_prci_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static void sifive_u_prci_realize(DeviceState *dev, Error **errp)
-{
-    SiFiveUPRCIState *s = SIFIVE_U_PRCI(dev);
-
-    memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_prci_ops, s,
-                          TYPE_SIFIVE_U_PRCI, SIFIVE_U_PRCI_REG_SIZE);
-    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
-}
-
-static void sifive_u_prci_reset(DeviceState *dev)
-{
-    SiFiveUPRCIState *s = SIFIVE_U_PRCI(dev);
-
-    /* Initialize register to power-on-reset values */
-    s->hfxosccfg = SIFIVE_U_PRCI_HFXOSCCFG_RDY | SIFIVE_U_PRCI_HFXOSCCFG_EN;
-    s->corepllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF |
-                     SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE |
-                     SIFIVE_U_PRCI_PLLCFG0_LOCK;
-    s->ddrpllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF |
-                    SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE |
-                    SIFIVE_U_PRCI_PLLCFG0_LOCK;
-    s->gemgxlpllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF |
-                       SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE |
-                       SIFIVE_U_PRCI_PLLCFG0_LOCK;
-    s->coreclksel = SIFIVE_U_PRCI_CORECLKSEL_HFCLK;
-}
-
-static void sifive_u_prci_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    dc->realize = sifive_u_prci_realize;
-    dc->reset = sifive_u_prci_reset;
-}
-
-static const TypeInfo sifive_u_prci_info = {
-    .name          = TYPE_SIFIVE_U_PRCI,
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SiFiveUPRCIState),
-    .class_init    = sifive_u_prci_class_init,
-};
-
-static void sifive_u_prci_register_types(void)
-{
-    type_register_static(&sifive_u_prci_info);
-}
-
-type_init(sifive_u_prci_register_types)
diff --git a/hw/riscv/sifive_uart.c b/hw/riscv/sifive_uart.c
deleted file mode 100644
index 9350482662..0000000000
--- a/hw/riscv/sifive_uart.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * QEMU model of the UART on the SiFive E300 and U500 series SOCs.
- *
- * Copyright (c) 2016 Stefan O'Rear
- *
- * 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 "qemu/log.h"
-#include "hw/sysbus.h"
-#include "chardev/char.h"
-#include "chardev/char-fe.h"
-#include "hw/hw.h"
-#include "hw/irq.h"
-#include "hw/riscv/sifive_uart.h"
-
-/*
- * Not yet implemented:
- *
- * Transmit FIFO using "qemu/fifo8.h"
- */
-
-/* Returns the state of the IP (interrupt pending) register */
-static uint64_t uart_ip(SiFiveUARTState *s)
-{
-    uint64_t ret = 0;
-
-    uint64_t txcnt = SIFIVE_UART_GET_TXCNT(s->txctrl);
-    uint64_t rxcnt = SIFIVE_UART_GET_RXCNT(s->rxctrl);
-
-    if (txcnt != 0) {
-        ret |= SIFIVE_UART_IP_TXWM;
-    }
-    if (s->rx_fifo_len > rxcnt) {
-        ret |= SIFIVE_UART_IP_RXWM;
-    }
-
-    return ret;
-}
-
-static void update_irq(SiFiveUARTState *s)
-{
-    int cond = 0;
-    if ((s->ie & SIFIVE_UART_IE_TXWM) ||
-        ((s->ie & SIFIVE_UART_IE_RXWM) && s->rx_fifo_len)) {
-        cond = 1;
-    }
-    if (cond) {
-        qemu_irq_raise(s->irq);
-    } else {
-        qemu_irq_lower(s->irq);
-    }
-}
-
-static uint64_t
-uart_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    SiFiveUARTState *s = opaque;
-    unsigned char r;
-    switch (addr) {
-    case SIFIVE_UART_RXFIFO:
-        if (s->rx_fifo_len) {
-            r = s->rx_fifo[0];
-            memmove(s->rx_fifo, s->rx_fifo + 1, s->rx_fifo_len - 1);
-            s->rx_fifo_len--;
-            qemu_chr_fe_accept_input(&s->chr);
-            update_irq(s);
-            return r;
-        }
-        return 0x80000000;
-
-    case SIFIVE_UART_TXFIFO:
-        return 0; /* Should check tx fifo */
-    case SIFIVE_UART_IE:
-        return s->ie;
-    case SIFIVE_UART_IP:
-        return uart_ip(s);
-    case SIFIVE_UART_TXCTRL:
-        return s->txctrl;
-    case SIFIVE_UART_RXCTRL:
-        return s->rxctrl;
-    case SIFIVE_UART_DIV:
-        return s->div;
-    }
-
-    qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read: addr=0x%x\n",
-                  __func__, (int)addr);
-    return 0;
-}
-
-static void
-uart_write(void *opaque, hwaddr addr,
-           uint64_t val64, unsigned int size)
-{
-    SiFiveUARTState *s = opaque;
-    uint32_t value = val64;
-    unsigned char ch = value;
-
-    switch (addr) {
-    case SIFIVE_UART_TXFIFO:
-        qemu_chr_fe_write(&s->chr, &ch, 1);
-        update_irq(s);
-        return;
-    case SIFIVE_UART_IE:
-        s->ie = val64;
-        update_irq(s);
-        return;
-    case SIFIVE_UART_TXCTRL:
-        s->txctrl = val64;
-        return;
-    case SIFIVE_UART_RXCTRL:
-        s->rxctrl = val64;
-        return;
-    case SIFIVE_UART_DIV:
-        s->div = val64;
-        return;
-    }
-    qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%x v=0x%x\n",
-                  __func__, (int)addr, (int)value);
-}
-
-static const MemoryRegionOps uart_ops = {
-    .read = uart_read,
-    .write = uart_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static void uart_rx(void *opaque, const uint8_t *buf, int size)
-{
-    SiFiveUARTState *s = opaque;
-
-    /* Got a byte.  */
-    if (s->rx_fifo_len >= sizeof(s->rx_fifo)) {
-        printf("WARNING: UART dropped char.\n");
-        return;
-    }
-    s->rx_fifo[s->rx_fifo_len++] = *buf;
-
-    update_irq(s);
-}
-
-static int uart_can_rx(void *opaque)
-{
-    SiFiveUARTState *s = opaque;
-
-    return s->rx_fifo_len < sizeof(s->rx_fifo);
-}
-
-static void uart_event(void *opaque, QEMUChrEvent event)
-{
-}
-
-static int uart_be_change(void *opaque)
-{
-    SiFiveUARTState *s = opaque;
-
-    qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, uart_event,
-        uart_be_change, s, NULL, true);
-
-    return 0;
-}
-
-/*
- * Create UART device.
- */
-SiFiveUARTState *sifive_uart_create(MemoryRegion *address_space, hwaddr base,
-    Chardev *chr, qemu_irq irq)
-{
-    SiFiveUARTState *s = g_malloc0(sizeof(SiFiveUARTState));
-    s->irq = irq;
-    qemu_chr_fe_init(&s->chr, chr, &error_abort);
-    qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, uart_event,
-        uart_be_change, s, NULL, true);
-    memory_region_init_io(&s->mmio, NULL, &uart_ops, s,
-                          TYPE_SIFIVE_UART, SIFIVE_UART_MAX);
-    memory_region_add_subregion(address_space, base, &s->mmio);
-    return s;
-}
diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index 56f5fe73c7..3fd152a035 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -31,12 +31,12 @@
 #include "hw/loader.h"
 #include "hw/sysbus.h"
 #include "target/riscv/cpu.h"
-#include "hw/riscv/riscv_htif.h"
 #include "hw/riscv/riscv_hart.h"
-#include "hw/riscv/sifive_clint.h"
 #include "hw/riscv/spike.h"
 #include "hw/riscv/boot.h"
 #include "hw/riscv/numa.h"
+#include "hw/char/riscv_htif.h"
+#include "hw/intc/sifive_clint.h"
 #include "chardev/char.h"
 #include "sysemu/arch_init.h"
 #include "sysemu/device_tree.h"
@@ -242,7 +242,8 @@ static void spike_board_init(MachineState *machine)
         sifive_clint_create(
             memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size,
             memmap[SPIKE_CLINT].size, base_hartid, hart_count,
-            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, false);
+            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
+            SIFIVE_CLINT_TIMEBASE_FREQ, false);
     }
 
     /* register system main memory (actual RAM) */
diff --git a/hw/riscv/trace-events b/hw/riscv/trace-events
deleted file mode 100644
index b819878963..0000000000
--- a/hw/riscv/trace-events
+++ /dev/null
@@ -1,7 +0,0 @@
-# See docs/devel/tracing.txt for syntax documentation.
-
-# sifive_gpio.c
-sifive_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64
-sifive_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64
-sifive_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
-sifive_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
diff --git a/hw/riscv/trace.h b/hw/riscv/trace.h
deleted file mode 100644
index 8c0e3ca1f3..0000000000
--- a/hw/riscv/trace.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "trace/trace-hw_riscv.h"
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 6fca513ec9..41bd2f38ba 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -30,12 +30,12 @@
 #include "hw/char/serial.h"
 #include "target/riscv/cpu.h"
 #include "hw/riscv/riscv_hart.h"
-#include "hw/riscv/sifive_plic.h"
-#include "hw/riscv/sifive_clint.h"
-#include "hw/riscv/sifive_test.h"
 #include "hw/riscv/virt.h"
 #include "hw/riscv/boot.h"
 #include "hw/riscv/numa.h"
+#include "hw/intc/sifive_clint.h"
+#include "hw/intc/sifive_plic.h"
+#include "hw/misc/sifive_test.h"
 #include "chardev/char.h"
 #include "sysemu/arch_init.h"
 #include "sysemu/device_tree.h"
@@ -541,7 +541,8 @@ static void virt_machine_init(MachineState *machine)
         sifive_clint_create(
             memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size,
             memmap[VIRT_CLINT].size, base_hartid, hart_count,
-            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, true);
+            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
+            SIFIVE_CLINT_TIMEBASE_FREQ, true);
 
         /* Per-socket PLIC hart topology configuration string */
         plic_hart_config_len =