mirror of https://gitee.com/openkylin/qemu.git
RISC-V: QEMU 2.13 Privileged ISA emulation updates
Several code cleanups, minor specification conformance changes, fixes to make ROM read-only and add device-tree size checks. * Honour privileged ISA v1.10 counter enable CSRs. * Implements WARL behavior for CSRs that don't support writes * Past behavior of raising traps was non-conformant with the RISC-V Privileged ISA Specification v1.10. * Allow S-mode access to sstatus.MXR when priv ISA >= v1.10 * Sets mtval/stval to zero on exceptions without addresses * Past behavior of leaving the last value was non-conformant with the RISC-V Privileged ISA Specition v1.10. mtval/stval must be set on all exceptions; to zero if not supported. * Make ROMs read-only and implement device-tree size checks * Uses memory_region_init_rom and rom_add_blob_fixed_as * Adds hexidecimal instruction bytes to disassembly output. * Fixes missing break statement for rv128 disassembly. * Several code cleanups * Replacing hard-coded constants with enums * Dead-code elimination This is an incremental pull that contains 20 reviewed changes out of 38 changes currently queued in the qemu-2.13-for-upstream branch. -----BEGIN PGP SIGNATURE----- iF0EABECAB0WIQR8mZMOsXzYugc9Xvpr8dezV+8+TwUCWu496QAKCRBr8dezV+8+ T1ZEAJ4wQRHZtn4suN5yMEHQMA2FkX1iNACgiYWLtcNcgoa88eaTcJJJu4QZryY= =I2wf -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/riscv/tags/riscv-qemu-2.13-pull-20180506' into staging RISC-V: QEMU 2.13 Privileged ISA emulation updates Several code cleanups, minor specification conformance changes, fixes to make ROM read-only and add device-tree size checks. * Honour privileged ISA v1.10 counter enable CSRs. * Implements WARL behavior for CSRs that don't support writes * Past behavior of raising traps was non-conformant with the RISC-V Privileged ISA Specification v1.10. * Allow S-mode access to sstatus.MXR when priv ISA >= v1.10 * Sets mtval/stval to zero on exceptions without addresses * Past behavior of leaving the last value was non-conformant with the RISC-V Privileged ISA Specition v1.10. mtval/stval must be set on all exceptions; to zero if not supported. * Make ROMs read-only and implement device-tree size checks * Uses memory_region_init_rom and rom_add_blob_fixed_as * Adds hexidecimal instruction bytes to disassembly output. * Fixes missing break statement for rv128 disassembly. * Several code cleanups * Replacing hard-coded constants with enums * Dead-code elimination This is an incremental pull that contains 20 reviewed changes out of 38 changes currently queued in the qemu-2.13-for-upstream branch. # gpg: Signature made Sun 06 May 2018 00:27:37 BST # gpg: using DSA key 6BF1D7B357EF3E4F # gpg: Good signature from "Michael Clark <michaeljclark@mac.com>" # gpg: aka "Michael Clark <mjc@sifive.com>" # gpg: aka "Michael Clark <michael@metaparadigm.com>" # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 7C99 930E B17C D8BA 073D 5EFA 6BF1 D7B3 57EF 3E4F * remotes/riscv/tags/riscv-qemu-2.13-pull-20180506: RISC-V: Mark ROM read-only after copying in code RISC-V: No traps on writes to misa,minstret,mcycle RISC-V: Make mtvec/stvec ignore vectored traps RISC-V: Add mcycle/minstret support for -icount auto RISC-V: Use [ms]counteren CSRs when priv ISA >= v1.10 RISC-V: Allow S-mode mxr access when priv ISA >= v1.10 RISC-V: Clear mtval/stval on exceptions without info RISC-V: Hardwire satp to 0 for no-mmu case RISC-V: Update E and I extension order RISC-V: Remove erroneous comment from translate.c RISC-V: Remove EM_RISCV ELF_MACHINE indirection RISC-V: Make virt header comment title consistent RISC-V: Make some header guards more specific RISC-V: Fix missing break statement in disassembler RISC-V: Include instruction hex in disassembly RISC-V: Remove unused class definitions RISC-V: Remove identity_translate from load_elf RISC-V: Use ROM base address and size from memmap RISC-V: Make virt board description match spike RISC-V: Replace hardcoded constants with enum values Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
3add3f7edc
|
@ -1470,8 +1470,9 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
||||||
if (isa == rv128) {
|
if (isa == rv128) {
|
||||||
op = rv_op_c_sqsp;
|
op = rv_op_c_sqsp;
|
||||||
} else {
|
} else {
|
||||||
op = rv_op_c_fsdsp; break;
|
op = rv_op_c_fsdsp;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 6: op = rv_op_c_swsp; break;
|
case 6: op = rv_op_c_swsp; break;
|
||||||
case 7:
|
case 7:
|
||||||
if (isa == rv32) {
|
if (isa == rv32) {
|
||||||
|
@ -2769,25 +2770,6 @@ static void format_inst(char *buf, size_t buflen, size_t tab, rv_decode *dec)
|
||||||
char tmp[64];
|
char tmp[64];
|
||||||
const char *fmt;
|
const char *fmt;
|
||||||
|
|
||||||
if (dec->op == rv_op_illegal) {
|
|
||||||
size_t len = inst_length(dec->inst);
|
|
||||||
switch (len) {
|
|
||||||
case 2:
|
|
||||||
snprintf(buf, buflen, "(0x%04" PRIx64 ")", dec->inst);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
snprintf(buf, buflen, "(0x%08" PRIx64 ")", dec->inst);
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
snprintf(buf, buflen, "(0x%012" PRIx64 ")", dec->inst);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
snprintf(buf, buflen, "(0x%016" PRIx64 ")", dec->inst);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt = opcode_data[dec->op].format;
|
fmt = opcode_data[dec->op].format;
|
||||||
while (*fmt) {
|
while (*fmt) {
|
||||||
switch (*fmt) {
|
switch (*fmt) {
|
||||||
|
@ -3004,6 +2986,11 @@ disasm_inst(char *buf, size_t buflen, rv_isa isa, uint64_t pc, rv_inst inst)
|
||||||
format_inst(buf, buflen, 16, &dec);
|
format_inst(buf, buflen, 16, &dec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define INST_FMT_2 "%04" PRIx64 " "
|
||||||
|
#define INST_FMT_4 "%08" PRIx64 " "
|
||||||
|
#define INST_FMT_6 "%012" PRIx64 " "
|
||||||
|
#define INST_FMT_8 "%016" PRIx64 " "
|
||||||
|
|
||||||
static int
|
static int
|
||||||
print_insn_riscv(bfd_vma memaddr, struct disassemble_info *info, rv_isa isa)
|
print_insn_riscv(bfd_vma memaddr, struct disassemble_info *info, rv_isa isa)
|
||||||
{
|
{
|
||||||
|
@ -3031,6 +3018,21 @@ print_insn_riscv(bfd_vma memaddr, struct disassemble_info *info, rv_isa isa)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (len) {
|
||||||
|
case 2:
|
||||||
|
(*info->fprintf_func)(info->stream, INST_FMT_2, inst);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
(*info->fprintf_func)(info->stream, INST_FMT_4, inst);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
(*info->fprintf_func)(info->stream, INST_FMT_6, inst);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
(*info->fprintf_func)(info->stream, INST_FMT_8, inst);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
disasm_inst(buf, sizeof(buf), isa, memaddr, inst);
|
disasm_inst(buf, sizeof(buf), isa, memaddr, inst);
|
||||||
(*info->fprintf_func)(info->stream, "%s", buf);
|
(*info->fprintf_func)(info->stream, "%s", buf);
|
||||||
|
|
||||||
|
|
|
@ -68,16 +68,10 @@ static void riscv_harts_class_init(ObjectClass *klass, void *data)
|
||||||
dc->realize = riscv_harts_realize;
|
dc->realize = riscv_harts_realize;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void riscv_harts_init(Object *obj)
|
|
||||||
{
|
|
||||||
/* RISCVHartArrayState *s = SIFIVE_COREPLEX(obj); */
|
|
||||||
}
|
|
||||||
|
|
||||||
static const TypeInfo riscv_harts_info = {
|
static const TypeInfo riscv_harts_info = {
|
||||||
.name = TYPE_RISCV_HART_ARRAY,
|
.name = TYPE_RISCV_HART_ARRAY,
|
||||||
.parent = TYPE_SYS_BUS_DEVICE,
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
.instance_size = sizeof(RISCVHartArrayState),
|
.instance_size = sizeof(RISCVHartArrayState),
|
||||||
.instance_init = riscv_harts_init,
|
|
||||||
.class_init = riscv_harts_class_init,
|
.class_init = riscv_harts_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,13 +26,10 @@
|
||||||
#include "hw/riscv/sifive_clint.h"
|
#include "hw/riscv/sifive_clint.h"
|
||||||
#include "qemu/timer.h"
|
#include "qemu/timer.h"
|
||||||
|
|
||||||
/* See: riscv-pk/machine/sbi_entry.S and arch/riscv/kernel/time.c */
|
|
||||||
#define TIMER_FREQ (10 * 1000 * 1000)
|
|
||||||
|
|
||||||
static uint64_t cpu_riscv_read_rtc(void)
|
static uint64_t cpu_riscv_read_rtc(void)
|
||||||
{
|
{
|
||||||
return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), TIMER_FREQ,
|
return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
|
||||||
NANOSECONDS_PER_SECOND);
|
SIFIVE_CLINT_TIMEBASE_FREQ, NANOSECONDS_PER_SECOND);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -59,7 +56,7 @@ static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value)
|
||||||
diff = cpu->env.timecmp - rtc_r;
|
diff = cpu->env.timecmp - rtc_r;
|
||||||
/* back to ns (note args switched in muldiv64) */
|
/* back to ns (note args switched in muldiv64) */
|
||||||
next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
|
next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
|
||||||
muldiv64(diff, NANOSECONDS_PER_SECOND, TIMER_FREQ);
|
muldiv64(diff, NANOSECONDS_PER_SECOND, SIFIVE_CLINT_TIMEBASE_FREQ);
|
||||||
timer_mod(cpu->env.timer, next);
|
timer_mod(cpu->env.timer, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,26 +74,13 @@ static const struct MemmapEntry {
|
||||||
[SIFIVE_E_DTIM] = { 0x80000000, 0x4000 }
|
[SIFIVE_E_DTIM] = { 0x80000000, 0x4000 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static void copy_le32_to_phys(hwaddr pa, uint32_t *rom, size_t len)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < (len >> 2); i++) {
|
|
||||||
stl_phys(&address_space_memory, pa + (i << 2), rom[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t identity_translate(void *opaque, uint64_t addr)
|
|
||||||
{
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t load_kernel(const char *kernel_filename)
|
static uint64_t load_kernel(const char *kernel_filename)
|
||||||
{
|
{
|
||||||
uint64_t kernel_entry, kernel_high;
|
uint64_t kernel_entry, kernel_high;
|
||||||
|
|
||||||
if (load_elf(kernel_filename, identity_translate, NULL,
|
if (load_elf(kernel_filename, NULL, NULL,
|
||||||
&kernel_entry, NULL, &kernel_high,
|
&kernel_entry, NULL, &kernel_high,
|
||||||
0, ELF_MACHINE, 1, 0) < 0) {
|
0, EM_RISCV, 1, 0) < 0) {
|
||||||
error_report("qemu: could not load kernel '%s'", kernel_filename);
|
error_report("qemu: could not load kernel '%s'", kernel_filename);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -117,6 +104,7 @@ static void riscv_sifive_e_init(MachineState *machine)
|
||||||
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
|
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
|
||||||
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
|
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
|
||||||
MemoryRegion *xip_mem = g_new(MemoryRegion, 1);
|
MemoryRegion *xip_mem = g_new(MemoryRegion, 1);
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Initialize SOC */
|
/* Initialize SOC */
|
||||||
object_initialize(&s->soc, sizeof(s->soc), TYPE_RISCV_HART_ARRAY);
|
object_initialize(&s->soc, sizeof(s->soc), TYPE_RISCV_HART_ARRAY);
|
||||||
|
@ -136,7 +124,7 @@ static void riscv_sifive_e_init(MachineState *machine)
|
||||||
memmap[SIFIVE_E_DTIM].base, main_mem);
|
memmap[SIFIVE_E_DTIM].base, main_mem);
|
||||||
|
|
||||||
/* Mask ROM */
|
/* Mask ROM */
|
||||||
memory_region_init_ram(mask_rom, NULL, "riscv.sifive.e.mrom",
|
memory_region_init_rom(mask_rom, NULL, "riscv.sifive.e.mrom",
|
||||||
memmap[SIFIVE_E_MROM].size, &error_fatal);
|
memmap[SIFIVE_E_MROM].size, &error_fatal);
|
||||||
memory_region_add_subregion(sys_mem,
|
memory_region_add_subregion(sys_mem,
|
||||||
memmap[SIFIVE_E_MROM].base, mask_rom);
|
memmap[SIFIVE_E_MROM].base, mask_rom);
|
||||||
|
@ -190,33 +178,18 @@ static void riscv_sifive_e_init(MachineState *machine)
|
||||||
0x00028067, /* 0x1004: jr t0 */
|
0x00028067, /* 0x1004: jr t0 */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* copy in the reset vector */
|
/* copy in the reset vector in little_endian byte order */
|
||||||
copy_le32_to_phys(memmap[SIFIVE_E_MROM].base, reset_vec, sizeof(reset_vec));
|
for (i = 0; i < sizeof(reset_vec) >> 2; i++) {
|
||||||
memory_region_set_readonly(mask_rom, true);
|
reset_vec[i] = cpu_to_le32(reset_vec[i]);
|
||||||
|
}
|
||||||
|
rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
|
||||||
|
memmap[SIFIVE_E_MROM].base, &address_space_memory);
|
||||||
|
|
||||||
if (machine->kernel_filename) {
|
if (machine->kernel_filename) {
|
||||||
load_kernel(machine->kernel_filename);
|
load_kernel(machine->kernel_filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv_sifive_e_sysbus_device_init(SysBusDevice *sysbusdev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void riscv_sifive_e_class_init(ObjectClass *klass, void *data)
|
|
||||||
{
|
|
||||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
|
||||||
k->init = riscv_sifive_e_sysbus_device_init;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const TypeInfo riscv_sifive_e_device = {
|
|
||||||
.name = TYPE_SIFIVE_E,
|
|
||||||
.parent = TYPE_SYS_BUS_DEVICE,
|
|
||||||
.instance_size = sizeof(SiFiveEState),
|
|
||||||
.class_init = riscv_sifive_e_class_init,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void riscv_sifive_e_machine_init(MachineClass *mc)
|
static void riscv_sifive_e_machine_init(MachineClass *mc)
|
||||||
{
|
{
|
||||||
mc->desc = "RISC-V Board compatible with SiFive E SDK";
|
mc->desc = "RISC-V Board compatible with SiFive E SDK";
|
||||||
|
@ -225,10 +198,3 @@ static void riscv_sifive_e_machine_init(MachineClass *mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_MACHINE("sifive_e", riscv_sifive_e_machine_init)
|
DEFINE_MACHINE("sifive_e", riscv_sifive_e_machine_init)
|
||||||
|
|
||||||
static void riscv_sifive_e_register_types(void)
|
|
||||||
{
|
|
||||||
type_register_static(&riscv_sifive_e_device);
|
|
||||||
}
|
|
||||||
|
|
||||||
type_init(riscv_sifive_e_register_types);
|
|
||||||
|
|
|
@ -47,12 +47,14 @@
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
static const struct MemmapEntry {
|
static const struct MemmapEntry {
|
||||||
hwaddr base;
|
hwaddr base;
|
||||||
hwaddr size;
|
hwaddr size;
|
||||||
} sifive_u_memmap[] = {
|
} sifive_u_memmap[] = {
|
||||||
[SIFIVE_U_DEBUG] = { 0x0, 0x100 },
|
[SIFIVE_U_DEBUG] = { 0x0, 0x100 },
|
||||||
[SIFIVE_U_MROM] = { 0x1000, 0x2000 },
|
[SIFIVE_U_MROM] = { 0x1000, 0x11000 },
|
||||||
[SIFIVE_U_CLINT] = { 0x2000000, 0x10000 },
|
[SIFIVE_U_CLINT] = { 0x2000000, 0x10000 },
|
||||||
[SIFIVE_U_PLIC] = { 0xc000000, 0x4000000 },
|
[SIFIVE_U_PLIC] = { 0xc000000, 0x4000000 },
|
||||||
[SIFIVE_U_UART0] = { 0x10013000, 0x1000 },
|
[SIFIVE_U_UART0] = { 0x10013000, 0x1000 },
|
||||||
|
@ -60,26 +62,13 @@ static const struct MemmapEntry {
|
||||||
[SIFIVE_U_DRAM] = { 0x80000000, 0x0 },
|
[SIFIVE_U_DRAM] = { 0x80000000, 0x0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void copy_le32_to_phys(hwaddr pa, uint32_t *rom, size_t len)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < (len >> 2); i++) {
|
|
||||||
stl_phys(&address_space_memory, pa + (i << 2), rom[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t identity_translate(void *opaque, uint64_t addr)
|
|
||||||
{
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t load_kernel(const char *kernel_filename)
|
static uint64_t load_kernel(const char *kernel_filename)
|
||||||
{
|
{
|
||||||
uint64_t kernel_entry, kernel_high;
|
uint64_t kernel_entry, kernel_high;
|
||||||
|
|
||||||
if (load_elf(kernel_filename, identity_translate, NULL,
|
if (load_elf(kernel_filename, NULL, NULL,
|
||||||
&kernel_entry, NULL, &kernel_high,
|
&kernel_entry, NULL, &kernel_high,
|
||||||
0, ELF_MACHINE, 1, 0) < 0) {
|
0, EM_RISCV, 1, 0) < 0) {
|
||||||
error_report("qemu: could not load kernel '%s'", kernel_filename);
|
error_report("qemu: could not load kernel '%s'", kernel_filename);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -122,7 +111,8 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
||||||
g_free(nodename);
|
g_free(nodename);
|
||||||
|
|
||||||
qemu_fdt_add_subnode(fdt, "/cpus");
|
qemu_fdt_add_subnode(fdt, "/cpus");
|
||||||
qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency", 10000000);
|
qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
|
||||||
|
SIFIVE_CLINT_TIMEBASE_FREQ);
|
||||||
qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
|
qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
|
||||||
qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
|
qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
|
||||||
|
|
||||||
|
@ -131,7 +121,8 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
||||||
char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
|
char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
|
||||||
char *isa = riscv_isa_string(&s->soc.harts[cpu]);
|
char *isa = riscv_isa_string(&s->soc.harts[cpu]);
|
||||||
qemu_fdt_add_subnode(fdt, nodename);
|
qemu_fdt_add_subnode(fdt, nodename);
|
||||||
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", 1000000000);
|
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
|
||||||
|
SIFIVE_U_CLOCK_FREQ);
|
||||||
qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48");
|
qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48");
|
||||||
qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", isa);
|
qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", isa);
|
||||||
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv");
|
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv");
|
||||||
|
@ -224,9 +215,10 @@ static void riscv_sifive_u_init(MachineState *machine)
|
||||||
const struct MemmapEntry *memmap = sifive_u_memmap;
|
const struct MemmapEntry *memmap = sifive_u_memmap;
|
||||||
|
|
||||||
SiFiveUState *s = g_new0(SiFiveUState, 1);
|
SiFiveUState *s = g_new0(SiFiveUState, 1);
|
||||||
MemoryRegion *sys_memory = get_system_memory();
|
MemoryRegion *system_memory = get_system_memory();
|
||||||
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
|
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
|
||||||
MemoryRegion *boot_rom = g_new(MemoryRegion, 1);
|
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Initialize SOC */
|
/* Initialize SOC */
|
||||||
object_initialize(&s->soc, sizeof(s->soc), TYPE_RISCV_HART_ARRAY);
|
object_initialize(&s->soc, sizeof(s->soc), TYPE_RISCV_HART_ARRAY);
|
||||||
|
@ -242,17 +234,17 @@ static void riscv_sifive_u_init(MachineState *machine)
|
||||||
/* register RAM */
|
/* register RAM */
|
||||||
memory_region_init_ram(main_mem, NULL, "riscv.sifive.u.ram",
|
memory_region_init_ram(main_mem, NULL, "riscv.sifive.u.ram",
|
||||||
machine->ram_size, &error_fatal);
|
machine->ram_size, &error_fatal);
|
||||||
memory_region_add_subregion(sys_memory, memmap[SIFIVE_U_DRAM].base,
|
memory_region_add_subregion(system_memory, memmap[SIFIVE_U_DRAM].base,
|
||||||
main_mem);
|
main_mem);
|
||||||
|
|
||||||
/* create device tree */
|
/* create device tree */
|
||||||
create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
|
create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
|
||||||
|
|
||||||
/* boot rom */
|
/* boot rom */
|
||||||
memory_region_init_ram(boot_rom, NULL, "riscv.sifive.u.mrom",
|
memory_region_init_rom(mask_rom, NULL, "riscv.sifive.u.mrom",
|
||||||
memmap[SIFIVE_U_MROM].base, &error_fatal);
|
memmap[SIFIVE_U_MROM].size, &error_fatal);
|
||||||
memory_region_set_readonly(boot_rom, true);
|
memory_region_add_subregion(system_memory, memmap[SIFIVE_U_MROM].base,
|
||||||
memory_region_add_subregion(sys_memory, 0x0, boot_rom);
|
mask_rom);
|
||||||
|
|
||||||
if (machine->kernel_filename) {
|
if (machine->kernel_filename) {
|
||||||
load_kernel(machine->kernel_filename);
|
load_kernel(machine->kernel_filename);
|
||||||
|
@ -275,13 +267,23 @@ static void riscv_sifive_u_init(MachineState *machine)
|
||||||
/* dtb: */
|
/* dtb: */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* copy in the reset vector */
|
/* copy in the reset vector in little_endian byte order */
|
||||||
copy_le32_to_phys(memmap[SIFIVE_U_MROM].base, reset_vec, sizeof(reset_vec));
|
for (i = 0; i < sizeof(reset_vec) >> 2; i++) {
|
||||||
|
reset_vec[i] = cpu_to_le32(reset_vec[i]);
|
||||||
|
}
|
||||||
|
rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
|
||||||
|
memmap[SIFIVE_U_MROM].base, &address_space_memory);
|
||||||
|
|
||||||
/* copy in the device tree */
|
/* copy in the device tree */
|
||||||
qemu_fdt_dumpdtb(s->fdt, s->fdt_size);
|
if (fdt_pack(s->fdt) || fdt_totalsize(s->fdt) >
|
||||||
cpu_physical_memory_write(memmap[SIFIVE_U_MROM].base +
|
memmap[SIFIVE_U_MROM].size - sizeof(reset_vec)) {
|
||||||
sizeof(reset_vec), s->fdt, s->fdt_size);
|
error_report("not enough space to store device-tree");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
qemu_fdt_dumpdtb(s->fdt, fdt_totalsize(s->fdt));
|
||||||
|
rom_add_blob_fixed_as("mrom.fdt", s->fdt, fdt_totalsize(s->fdt),
|
||||||
|
memmap[SIFIVE_U_MROM].base + sizeof(reset_vec),
|
||||||
|
&address_space_memory);
|
||||||
|
|
||||||
/* MMIO */
|
/* MMIO */
|
||||||
s->plic = sifive_plic_create(memmap[SIFIVE_U_PLIC].base,
|
s->plic = sifive_plic_create(memmap[SIFIVE_U_PLIC].base,
|
||||||
|
@ -295,40 +297,15 @@ static void riscv_sifive_u_init(MachineState *machine)
|
||||||
SIFIVE_U_PLIC_CONTEXT_BASE,
|
SIFIVE_U_PLIC_CONTEXT_BASE,
|
||||||
SIFIVE_U_PLIC_CONTEXT_STRIDE,
|
SIFIVE_U_PLIC_CONTEXT_STRIDE,
|
||||||
memmap[SIFIVE_U_PLIC].size);
|
memmap[SIFIVE_U_PLIC].size);
|
||||||
sifive_uart_create(sys_memory, memmap[SIFIVE_U_UART0].base,
|
sifive_uart_create(system_memory, memmap[SIFIVE_U_UART0].base,
|
||||||
serial_hd(0), SIFIVE_PLIC(s->plic)->irqs[SIFIVE_U_UART0_IRQ]);
|
serial_hd(0), SIFIVE_PLIC(s->plic)->irqs[SIFIVE_U_UART0_IRQ]);
|
||||||
/* sifive_uart_create(sys_memory, memmap[SIFIVE_U_UART1].base,
|
/* sifive_uart_create(system_memory, memmap[SIFIVE_U_UART1].base,
|
||||||
serial_hd(1), SIFIVE_PLIC(s->plic)->irqs[SIFIVE_U_UART1_IRQ]); */
|
serial_hd(1), SIFIVE_PLIC(s->plic)->irqs[SIFIVE_U_UART1_IRQ]); */
|
||||||
sifive_clint_create(memmap[SIFIVE_U_CLINT].base,
|
sifive_clint_create(memmap[SIFIVE_U_CLINT].base,
|
||||||
memmap[SIFIVE_U_CLINT].size, smp_cpus,
|
memmap[SIFIVE_U_CLINT].size, smp_cpus,
|
||||||
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE);
|
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv_sifive_u_sysbus_device_init(SysBusDevice *sysbusdev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void riscv_sifive_u_class_init(ObjectClass *klass, void *data)
|
|
||||||
{
|
|
||||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
|
||||||
k->init = riscv_sifive_u_sysbus_device_init;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const TypeInfo riscv_sifive_u_device = {
|
|
||||||
.name = TYPE_SIFIVE_U,
|
|
||||||
.parent = TYPE_SYS_BUS_DEVICE,
|
|
||||||
.instance_size = sizeof(SiFiveUState),
|
|
||||||
.class_init = riscv_sifive_u_class_init,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void riscv_sifive_u_register_types(void)
|
|
||||||
{
|
|
||||||
type_register_static(&riscv_sifive_u_device);
|
|
||||||
}
|
|
||||||
|
|
||||||
type_init(riscv_sifive_u_register_types);
|
|
||||||
|
|
||||||
static void riscv_sifive_u_machine_init(MachineClass *mc)
|
static void riscv_sifive_u_machine_init(MachineClass *mc)
|
||||||
{
|
{
|
||||||
mc->desc = "RISC-V Board compatible with SiFive U SDK";
|
mc->desc = "RISC-V Board compatible with SiFive U SDK";
|
||||||
|
|
104
hw/riscv/spike.c
104
hw/riscv/spike.c
|
@ -42,34 +42,23 @@
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
static const struct MemmapEntry {
|
static const struct MemmapEntry {
|
||||||
hwaddr base;
|
hwaddr base;
|
||||||
hwaddr size;
|
hwaddr size;
|
||||||
} spike_memmap[] = {
|
} spike_memmap[] = {
|
||||||
[SPIKE_MROM] = { 0x1000, 0x2000 },
|
[SPIKE_MROM] = { 0x1000, 0x11000 },
|
||||||
[SPIKE_CLINT] = { 0x2000000, 0x10000 },
|
[SPIKE_CLINT] = { 0x2000000, 0x10000 },
|
||||||
[SPIKE_DRAM] = { 0x80000000, 0x0 },
|
[SPIKE_DRAM] = { 0x80000000, 0x0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void copy_le32_to_phys(hwaddr pa, uint32_t *rom, size_t len)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < (len >> 2); i++) {
|
|
||||||
stl_phys(&address_space_memory, pa + (i << 2), rom[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t identity_translate(void *opaque, uint64_t addr)
|
|
||||||
{
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t load_kernel(const char *kernel_filename)
|
static uint64_t load_kernel(const char *kernel_filename)
|
||||||
{
|
{
|
||||||
uint64_t kernel_entry, kernel_high;
|
uint64_t kernel_entry, kernel_high;
|
||||||
|
|
||||||
if (load_elf_ram_sym(kernel_filename, identity_translate, NULL,
|
if (load_elf_ram_sym(kernel_filename, NULL, NULL,
|
||||||
&kernel_entry, NULL, &kernel_high, 0, ELF_MACHINE, 1, 0,
|
&kernel_entry, NULL, &kernel_high, 0, EM_RISCV, 1, 0,
|
||||||
NULL, true, htif_symbol_callback) < 0) {
|
NULL, true, htif_symbol_callback) < 0) {
|
||||||
error_report("qemu: could not load kernel '%s'", kernel_filename);
|
error_report("qemu: could not load kernel '%s'", kernel_filename);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -115,7 +104,8 @@ static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap,
|
||||||
g_free(nodename);
|
g_free(nodename);
|
||||||
|
|
||||||
qemu_fdt_add_subnode(fdt, "/cpus");
|
qemu_fdt_add_subnode(fdt, "/cpus");
|
||||||
qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency", 10000000);
|
qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
|
||||||
|
SIFIVE_CLINT_TIMEBASE_FREQ);
|
||||||
qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
|
qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
|
||||||
qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
|
qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
|
||||||
|
|
||||||
|
@ -124,7 +114,8 @@ static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap,
|
||||||
char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
|
char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
|
||||||
char *isa = riscv_isa_string(&s->soc.harts[cpu]);
|
char *isa = riscv_isa_string(&s->soc.harts[cpu]);
|
||||||
qemu_fdt_add_subnode(fdt, nodename);
|
qemu_fdt_add_subnode(fdt, nodename);
|
||||||
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", 1000000000);
|
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
|
||||||
|
SPIKE_CLOCK_FREQ);
|
||||||
qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48");
|
qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48");
|
||||||
qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", isa);
|
qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", isa);
|
||||||
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv");
|
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv");
|
||||||
|
@ -176,7 +167,8 @@ static void spike_v1_10_0_board_init(MachineState *machine)
|
||||||
SpikeState *s = g_new0(SpikeState, 1);
|
SpikeState *s = g_new0(SpikeState, 1);
|
||||||
MemoryRegion *system_memory = get_system_memory();
|
MemoryRegion *system_memory = get_system_memory();
|
||||||
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
|
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
|
||||||
MemoryRegion *boot_rom = g_new(MemoryRegion, 1);
|
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Initialize SOC */
|
/* Initialize SOC */
|
||||||
object_initialize(&s->soc, sizeof(s->soc), TYPE_RISCV_HART_ARRAY);
|
object_initialize(&s->soc, sizeof(s->soc), TYPE_RISCV_HART_ARRAY);
|
||||||
|
@ -199,9 +191,10 @@ static void spike_v1_10_0_board_init(MachineState *machine)
|
||||||
create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
|
create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
|
||||||
|
|
||||||
/* boot rom */
|
/* boot rom */
|
||||||
memory_region_init_ram(boot_rom, NULL, "riscv.spike.bootrom",
|
memory_region_init_rom(mask_rom, NULL, "riscv.spike.mrom",
|
||||||
s->fdt_size + 0x2000, &error_fatal);
|
memmap[SPIKE_MROM].size, &error_fatal);
|
||||||
memory_region_add_subregion(system_memory, 0x0, boot_rom);
|
memory_region_add_subregion(system_memory, memmap[SPIKE_MROM].base,
|
||||||
|
mask_rom);
|
||||||
|
|
||||||
if (machine->kernel_filename) {
|
if (machine->kernel_filename) {
|
||||||
load_kernel(machine->kernel_filename);
|
load_kernel(machine->kernel_filename);
|
||||||
|
@ -224,16 +217,26 @@ static void spike_v1_10_0_board_init(MachineState *machine)
|
||||||
/* dtb: */
|
/* dtb: */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* copy in the reset vector */
|
/* copy in the reset vector in little_endian byte order */
|
||||||
copy_le32_to_phys(memmap[SPIKE_MROM].base, reset_vec, sizeof(reset_vec));
|
for (i = 0; i < sizeof(reset_vec) >> 2; i++) {
|
||||||
|
reset_vec[i] = cpu_to_le32(reset_vec[i]);
|
||||||
|
}
|
||||||
|
rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
|
||||||
|
memmap[SPIKE_MROM].base, &address_space_memory);
|
||||||
|
|
||||||
/* copy in the device tree */
|
/* copy in the device tree */
|
||||||
qemu_fdt_dumpdtb(s->fdt, s->fdt_size);
|
if (fdt_pack(s->fdt) || fdt_totalsize(s->fdt) >
|
||||||
cpu_physical_memory_write(memmap[SPIKE_MROM].base + sizeof(reset_vec),
|
memmap[SPIKE_MROM].size - sizeof(reset_vec)) {
|
||||||
s->fdt, s->fdt_size);
|
error_report("not enough space to store device-tree");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
qemu_fdt_dumpdtb(s->fdt, fdt_totalsize(s->fdt));
|
||||||
|
rom_add_blob_fixed_as("mrom.fdt", s->fdt, fdt_totalsize(s->fdt),
|
||||||
|
memmap[SPIKE_MROM].base + sizeof(reset_vec),
|
||||||
|
&address_space_memory);
|
||||||
|
|
||||||
/* initialize HTIF using symbols found in load_kernel */
|
/* initialize HTIF using symbols found in load_kernel */
|
||||||
htif_mm_init(system_memory, boot_rom, &s->soc.harts[0].env, serial_hd(0));
|
htif_mm_init(system_memory, mask_rom, &s->soc.harts[0].env, serial_hd(0));
|
||||||
|
|
||||||
/* Core Local Interruptor (timer and IPI) */
|
/* Core Local Interruptor (timer and IPI) */
|
||||||
sifive_clint_create(memmap[SPIKE_CLINT].base, memmap[SPIKE_CLINT].size,
|
sifive_clint_create(memmap[SPIKE_CLINT].base, memmap[SPIKE_CLINT].size,
|
||||||
|
@ -247,7 +250,8 @@ static void spike_v1_09_1_board_init(MachineState *machine)
|
||||||
SpikeState *s = g_new0(SpikeState, 1);
|
SpikeState *s = g_new0(SpikeState, 1);
|
||||||
MemoryRegion *system_memory = get_system_memory();
|
MemoryRegion *system_memory = get_system_memory();
|
||||||
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
|
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
|
||||||
MemoryRegion *boot_rom = g_new(MemoryRegion, 1);
|
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Initialize SOC */
|
/* Initialize SOC */
|
||||||
object_initialize(&s->soc, sizeof(s->soc), TYPE_RISCV_HART_ARRAY);
|
object_initialize(&s->soc, sizeof(s->soc), TYPE_RISCV_HART_ARRAY);
|
||||||
|
@ -267,9 +271,10 @@ static void spike_v1_09_1_board_init(MachineState *machine)
|
||||||
main_mem);
|
main_mem);
|
||||||
|
|
||||||
/* boot rom */
|
/* boot rom */
|
||||||
memory_region_init_ram(boot_rom, NULL, "riscv.spike.bootrom",
|
memory_region_init_rom(mask_rom, NULL, "riscv.spike.mrom",
|
||||||
0x40000, &error_fatal);
|
memmap[SPIKE_MROM].size, &error_fatal);
|
||||||
memory_region_add_subregion(system_memory, 0x0, boot_rom);
|
memory_region_add_subregion(system_memory, memmap[SPIKE_MROM].base,
|
||||||
|
mask_rom);
|
||||||
|
|
||||||
if (machine->kernel_filename) {
|
if (machine->kernel_filename) {
|
||||||
load_kernel(machine->kernel_filename);
|
load_kernel(machine->kernel_filename);
|
||||||
|
@ -322,33 +327,26 @@ static void spike_v1_09_1_board_init(MachineState *machine)
|
||||||
g_free(isa);
|
g_free(isa);
|
||||||
size_t config_string_len = strlen(config_string);
|
size_t config_string_len = strlen(config_string);
|
||||||
|
|
||||||
/* copy in the reset vector */
|
/* copy in the reset vector in little_endian byte order */
|
||||||
copy_le32_to_phys(memmap[SPIKE_MROM].base, reset_vec, sizeof(reset_vec));
|
for (i = 0; i < sizeof(reset_vec) >> 2; i++) {
|
||||||
|
reset_vec[i] = cpu_to_le32(reset_vec[i]);
|
||||||
|
}
|
||||||
|
rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
|
||||||
|
memmap[SPIKE_MROM].base, &address_space_memory);
|
||||||
|
|
||||||
/* copy in the config string */
|
/* copy in the config string */
|
||||||
cpu_physical_memory_write(memmap[SPIKE_MROM].base + sizeof(reset_vec),
|
rom_add_blob_fixed_as("mrom.reset", config_string, config_string_len,
|
||||||
config_string, config_string_len);
|
memmap[SPIKE_MROM].base + sizeof(reset_vec),
|
||||||
|
&address_space_memory);
|
||||||
|
|
||||||
/* initialize HTIF using symbols found in load_kernel */
|
/* initialize HTIF using symbols found in load_kernel */
|
||||||
htif_mm_init(system_memory, boot_rom, &s->soc.harts[0].env, serial_hd(0));
|
htif_mm_init(system_memory, mask_rom, &s->soc.harts[0].env, serial_hd(0));
|
||||||
|
|
||||||
/* Core Local Interruptor (timer and IPI) */
|
/* Core Local Interruptor (timer and IPI) */
|
||||||
sifive_clint_create(memmap[SPIKE_CLINT].base, memmap[SPIKE_CLINT].size,
|
sifive_clint_create(memmap[SPIKE_CLINT].base, memmap[SPIKE_CLINT].size,
|
||||||
smp_cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE);
|
smp_cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo spike_v_1_09_1_device = {
|
|
||||||
.name = TYPE_RISCV_SPIKE_V1_09_1_BOARD,
|
|
||||||
.parent = TYPE_SYS_BUS_DEVICE,
|
|
||||||
.instance_size = sizeof(SpikeState),
|
|
||||||
};
|
|
||||||
|
|
||||||
static const TypeInfo spike_v_1_10_0_device = {
|
|
||||||
.name = TYPE_RISCV_SPIKE_V1_10_0_BOARD,
|
|
||||||
.parent = TYPE_SYS_BUS_DEVICE,
|
|
||||||
.instance_size = sizeof(SpikeState),
|
|
||||||
};
|
|
||||||
|
|
||||||
static void spike_v1_09_1_machine_init(MachineClass *mc)
|
static void spike_v1_09_1_machine_init(MachineClass *mc)
|
||||||
{
|
{
|
||||||
mc->desc = "RISC-V Spike Board (Privileged ISA v1.9.1)";
|
mc->desc = "RISC-V Spike Board (Privileged ISA v1.9.1)";
|
||||||
|
@ -366,11 +364,3 @@ static void spike_v1_10_0_machine_init(MachineClass *mc)
|
||||||
|
|
||||||
DEFINE_MACHINE("spike_v1.9.1", spike_v1_09_1_machine_init)
|
DEFINE_MACHINE("spike_v1.9.1", spike_v1_09_1_machine_init)
|
||||||
DEFINE_MACHINE("spike_v1.10", spike_v1_10_0_machine_init)
|
DEFINE_MACHINE("spike_v1.10", spike_v1_10_0_machine_init)
|
||||||
|
|
||||||
static void riscv_spike_board_register_types(void)
|
|
||||||
{
|
|
||||||
type_register_static(&spike_v_1_09_1_device);
|
|
||||||
type_register_static(&spike_v_1_10_0_device);
|
|
||||||
}
|
|
||||||
|
|
||||||
type_init(riscv_spike_board_register_types);
|
|
||||||
|
|
|
@ -40,13 +40,15 @@
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
static const struct MemmapEntry {
|
static const struct MemmapEntry {
|
||||||
hwaddr base;
|
hwaddr base;
|
||||||
hwaddr size;
|
hwaddr size;
|
||||||
} virt_memmap[] = {
|
} virt_memmap[] = {
|
||||||
[VIRT_DEBUG] = { 0x0, 0x100 },
|
[VIRT_DEBUG] = { 0x0, 0x100 },
|
||||||
[VIRT_MROM] = { 0x1000, 0x2000 },
|
[VIRT_MROM] = { 0x1000, 0x11000 },
|
||||||
[VIRT_TEST] = { 0x4000, 0x1000 },
|
[VIRT_TEST] = { 0x100000, 0x1000 },
|
||||||
[VIRT_CLINT] = { 0x2000000, 0x10000 },
|
[VIRT_CLINT] = { 0x2000000, 0x10000 },
|
||||||
[VIRT_PLIC] = { 0xc000000, 0x4000000 },
|
[VIRT_PLIC] = { 0xc000000, 0x4000000 },
|
||||||
[VIRT_UART0] = { 0x10000000, 0x100 },
|
[VIRT_UART0] = { 0x10000000, 0x100 },
|
||||||
|
@ -54,26 +56,13 @@ static const struct MemmapEntry {
|
||||||
[VIRT_DRAM] = { 0x80000000, 0x0 },
|
[VIRT_DRAM] = { 0x80000000, 0x0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void copy_le32_to_phys(hwaddr pa, uint32_t *rom, size_t len)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < (len >> 2); i++) {
|
|
||||||
stl_phys(&address_space_memory, pa + (i << 2), rom[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t identity_translate(void *opaque, uint64_t addr)
|
|
||||||
{
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t load_kernel(const char *kernel_filename)
|
static uint64_t load_kernel(const char *kernel_filename)
|
||||||
{
|
{
|
||||||
uint64_t kernel_entry, kernel_high;
|
uint64_t kernel_entry, kernel_high;
|
||||||
|
|
||||||
if (load_elf(kernel_filename, identity_translate, NULL,
|
if (load_elf(kernel_filename, NULL, NULL,
|
||||||
&kernel_entry, NULL, &kernel_high,
|
&kernel_entry, NULL, &kernel_high,
|
||||||
0, ELF_MACHINE, 1, 0) < 0) {
|
0, EM_RISCV, 1, 0) < 0) {
|
||||||
error_report("qemu: could not load kernel '%s'", kernel_filename);
|
error_report("qemu: could not load kernel '%s'", kernel_filename);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -145,7 +134,8 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
||||||
g_free(nodename);
|
g_free(nodename);
|
||||||
|
|
||||||
qemu_fdt_add_subnode(fdt, "/cpus");
|
qemu_fdt_add_subnode(fdt, "/cpus");
|
||||||
qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency", 10000000);
|
qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
|
||||||
|
SIFIVE_CLINT_TIMEBASE_FREQ);
|
||||||
qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
|
qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
|
||||||
qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
|
qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
|
||||||
|
|
||||||
|
@ -155,7 +145,8 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
||||||
char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
|
char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
|
||||||
char *isa = riscv_isa_string(&s->soc.harts[cpu]);
|
char *isa = riscv_isa_string(&s->soc.harts[cpu]);
|
||||||
qemu_fdt_add_subnode(fdt, nodename);
|
qemu_fdt_add_subnode(fdt, nodename);
|
||||||
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", 1000000000);
|
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
|
||||||
|
VIRT_CLOCK_FREQ);
|
||||||
qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48");
|
qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48");
|
||||||
qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", isa);
|
qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", isa);
|
||||||
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv");
|
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv");
|
||||||
|
@ -275,7 +266,7 @@ static void riscv_virt_board_init(MachineState *machine)
|
||||||
RISCVVirtState *s = g_new0(RISCVVirtState, 1);
|
RISCVVirtState *s = g_new0(RISCVVirtState, 1);
|
||||||
MemoryRegion *system_memory = get_system_memory();
|
MemoryRegion *system_memory = get_system_memory();
|
||||||
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
|
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
|
||||||
MemoryRegion *boot_rom = g_new(MemoryRegion, 1);
|
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
|
||||||
char *plic_hart_config;
|
char *plic_hart_config;
|
||||||
size_t plic_hart_config_len;
|
size_t plic_hart_config_len;
|
||||||
int i;
|
int i;
|
||||||
|
@ -302,9 +293,10 @@ static void riscv_virt_board_init(MachineState *machine)
|
||||||
fdt = create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
|
fdt = create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
|
||||||
|
|
||||||
/* boot rom */
|
/* boot rom */
|
||||||
memory_region_init_ram(boot_rom, NULL, "riscv_virt_board.bootrom",
|
memory_region_init_rom(mask_rom, NULL, "riscv_virt_board.mrom",
|
||||||
s->fdt_size + 0x2000, &error_fatal);
|
memmap[VIRT_MROM].size, &error_fatal);
|
||||||
memory_region_add_subregion(system_memory, 0x0, boot_rom);
|
memory_region_add_subregion(system_memory, memmap[VIRT_MROM].base,
|
||||||
|
mask_rom);
|
||||||
|
|
||||||
if (machine->kernel_filename) {
|
if (machine->kernel_filename) {
|
||||||
uint64_t kernel_entry = load_kernel(machine->kernel_filename);
|
uint64_t kernel_entry = load_kernel(machine->kernel_filename);
|
||||||
|
@ -338,13 +330,23 @@ static void riscv_virt_board_init(MachineState *machine)
|
||||||
/* dtb: */
|
/* dtb: */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* copy in the reset vector */
|
/* copy in the reset vector in little_endian byte order */
|
||||||
copy_le32_to_phys(ROM_BASE, reset_vec, sizeof(reset_vec));
|
for (i = 0; i < sizeof(reset_vec) >> 2; i++) {
|
||||||
|
reset_vec[i] = cpu_to_le32(reset_vec[i]);
|
||||||
|
}
|
||||||
|
rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
|
||||||
|
memmap[VIRT_MROM].base, &address_space_memory);
|
||||||
|
|
||||||
/* copy in the device tree */
|
/* copy in the device tree */
|
||||||
qemu_fdt_dumpdtb(s->fdt, s->fdt_size);
|
if (fdt_pack(s->fdt) || fdt_totalsize(s->fdt) >
|
||||||
cpu_physical_memory_write(ROM_BASE + sizeof(reset_vec),
|
memmap[VIRT_MROM].size - sizeof(reset_vec)) {
|
||||||
s->fdt, s->fdt_size);
|
error_report("not enough space to store device-tree");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
qemu_fdt_dumpdtb(s->fdt, fdt_totalsize(s->fdt));
|
||||||
|
rom_add_blob_fixed_as("mrom.fdt", s->fdt, fdt_totalsize(s->fdt),
|
||||||
|
memmap[VIRT_MROM].base + sizeof(reset_vec),
|
||||||
|
&address_space_memory);
|
||||||
|
|
||||||
/* create PLIC hart topology configuration string */
|
/* create PLIC hart topology configuration string */
|
||||||
plic_hart_config_len = (strlen(VIRT_PLIC_HART_CONFIG) + 1) * smp_cpus;
|
plic_hart_config_len = (strlen(VIRT_PLIC_HART_CONFIG) + 1) * smp_cpus;
|
||||||
|
@ -385,36 +387,11 @@ static void riscv_virt_board_init(MachineState *machine)
|
||||||
serial_hd(0), DEVICE_LITTLE_ENDIAN);
|
serial_hd(0), DEVICE_LITTLE_ENDIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv_virt_board_sysbus_device_init(SysBusDevice *sysbusdev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void riscv_virt_board_class_init(ObjectClass *klass, void *data)
|
|
||||||
{
|
|
||||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
|
||||||
k->init = riscv_virt_board_sysbus_device_init;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const TypeInfo riscv_virt_board_device = {
|
|
||||||
.name = TYPE_RISCV_VIRT_BOARD,
|
|
||||||
.parent = TYPE_SYS_BUS_DEVICE,
|
|
||||||
.instance_size = sizeof(RISCVVirtState),
|
|
||||||
.class_init = riscv_virt_board_class_init,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void riscv_virt_board_machine_init(MachineClass *mc)
|
static void riscv_virt_board_machine_init(MachineClass *mc)
|
||||||
{
|
{
|
||||||
mc->desc = "RISC-V VirtIO Board (Privileged spec v1.10)";
|
mc->desc = "RISC-V VirtIO Board (Privileged ISA v1.10)";
|
||||||
mc->init = riscv_virt_board_init;
|
mc->init = riscv_virt_board_init;
|
||||||
mc->max_cpus = 8; /* hardcoded limit in BBL */
|
mc->max_cpus = 8; /* hardcoded limit in BBL */
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_MACHINE("virt", riscv_virt_board_machine_init)
|
DEFINE_MACHINE("virt", riscv_virt_board_machine_init)
|
||||||
|
|
||||||
static void riscv_virt_board_register_types(void)
|
|
||||||
{
|
|
||||||
type_register_static(&riscv_virt_board_device);
|
|
||||||
}
|
|
||||||
|
|
||||||
type_init(riscv_virt_board_register_types);
|
|
||||||
|
|
|
@ -47,4 +47,8 @@ enum {
|
||||||
SIFIVE_TIME_BASE = 0xBFF8
|
SIFIVE_TIME_BASE = 0xBFF8
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SIFIVE_CLINT_TIMEBASE_FREQ = 10000000
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,11 +19,6 @@
|
||||||
#ifndef HW_SIFIVE_E_H
|
#ifndef HW_SIFIVE_E_H
|
||||||
#define HW_SIFIVE_E_H
|
#define HW_SIFIVE_E_H
|
||||||
|
|
||||||
#define TYPE_SIFIVE_E "riscv.sifive_e"
|
|
||||||
|
|
||||||
#define SIFIVE_E(obj) \
|
|
||||||
OBJECT_CHECK(SiFiveEState, (obj), TYPE_SIFIVE_E)
|
|
||||||
|
|
||||||
typedef struct SiFiveEState {
|
typedef struct SiFiveEState {
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
SysBusDevice parent_obj;
|
SysBusDevice parent_obj;
|
||||||
|
|
|
@ -19,11 +19,6 @@
|
||||||
#ifndef HW_SIFIVE_U_H
|
#ifndef HW_SIFIVE_U_H
|
||||||
#define HW_SIFIVE_U_H
|
#define HW_SIFIVE_U_H
|
||||||
|
|
||||||
#define TYPE_SIFIVE_U "riscv.sifive_u"
|
|
||||||
|
|
||||||
#define SIFIVE_U(obj) \
|
|
||||||
OBJECT_CHECK(SiFiveUState, (obj), TYPE_SIFIVE_U)
|
|
||||||
|
|
||||||
typedef struct SiFiveUState {
|
typedef struct SiFiveUState {
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
SysBusDevice parent_obj;
|
SysBusDevice parent_obj;
|
||||||
|
@ -50,6 +45,10 @@ enum {
|
||||||
SIFIVE_U_UART1_IRQ = 4
|
SIFIVE_U_UART1_IRQ = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SIFIVE_U_CLOCK_FREQ = 1000000000
|
||||||
|
};
|
||||||
|
|
||||||
#define SIFIVE_U_PLIC_HART_CONFIG "MS"
|
#define SIFIVE_U_PLIC_HART_CONFIG "MS"
|
||||||
#define SIFIVE_U_PLIC_NUM_SOURCES 127
|
#define SIFIVE_U_PLIC_NUM_SOURCES 127
|
||||||
#define SIFIVE_U_PLIC_NUM_PRIORITIES 7
|
#define SIFIVE_U_PLIC_NUM_PRIORITIES 7
|
||||||
|
|
|
@ -16,14 +16,8 @@
|
||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef HW_SPIKE_H
|
#ifndef HW_RISCV_SPIKE_H
|
||||||
#define HW_SPIKE_H
|
#define HW_RISCV_SPIKE_H
|
||||||
|
|
||||||
#define TYPE_RISCV_SPIKE_V1_09_1_BOARD "riscv.spike_v1_9_1"
|
|
||||||
#define TYPE_RISCV_SPIKE_V1_10_0_BOARD "riscv.spike_v1_10"
|
|
||||||
|
|
||||||
#define SPIKE(obj) \
|
|
||||||
OBJECT_CHECK(SpikeState, (obj), TYPE_RISCV_SPIKE_BOARD)
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
|
@ -35,13 +29,16 @@ typedef struct {
|
||||||
int fdt_size;
|
int fdt_size;
|
||||||
} SpikeState;
|
} SpikeState;
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SPIKE_MROM,
|
SPIKE_MROM,
|
||||||
SPIKE_CLINT,
|
SPIKE_CLINT,
|
||||||
SPIKE_DRAM
|
SPIKE_DRAM
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SPIKE_CLOCK_FREQ = 1000000000
|
||||||
|
};
|
||||||
|
|
||||||
#if defined(TARGET_RISCV32)
|
#if defined(TARGET_RISCV32)
|
||||||
#define SPIKE_V1_09_1_CPU TYPE_RISCV_CPU_RV32GCSU_V1_09_1
|
#define SPIKE_V1_09_1_CPU TYPE_RISCV_CPU_RV32GCSU_V1_09_1
|
||||||
#define SPIKE_V1_10_0_CPU TYPE_RISCV_CPU_RV32GCSU_V1_10_0
|
#define SPIKE_V1_10_0_CPU TYPE_RISCV_CPU_RV32GCSU_V1_10_0
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* SiFive VirtIO Board
|
* QEMU RISC-V VirtIO machine interface
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017 SiFive, Inc.
|
* Copyright (c) 2017 SiFive, Inc.
|
||||||
*
|
*
|
||||||
|
@ -16,14 +16,8 @@
|
||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef HW_VIRT_H
|
#ifndef HW_RISCV_VIRT_H
|
||||||
#define HW_VIRT_H
|
#define HW_RISCV_VIRT_H
|
||||||
|
|
||||||
#define TYPE_RISCV_VIRT_BOARD "riscv.virt"
|
|
||||||
#define VIRT(obj) \
|
|
||||||
OBJECT_CHECK(RISCVVirtState, (obj), TYPE_RISCV_VIRT_BOARD)
|
|
||||||
|
|
||||||
enum { ROM_BASE = 0x1000 };
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
|
@ -47,7 +41,6 @@ enum {
|
||||||
VIRT_DRAM
|
VIRT_DRAM
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
UART0_IRQ = 10,
|
UART0_IRQ = 10,
|
||||||
VIRTIO_IRQ = 1, /* 1 to 8 */
|
VIRTIO_IRQ = 1, /* 1 to 8 */
|
||||||
|
@ -55,6 +48,10 @@ enum {
|
||||||
VIRTIO_NDEV = 10
|
VIRTIO_NDEV = 10
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
VIRT_CLOCK_FREQ = 1000000000
|
||||||
|
};
|
||||||
|
|
||||||
#define VIRT_PLIC_HART_CONFIG "MS"
|
#define VIRT_PLIC_HART_CONFIG "MS"
|
||||||
#define VIRT_PLIC_NUM_SOURCES 127
|
#define VIRT_PLIC_NUM_SOURCES 127
|
||||||
#define VIRT_PLIC_NUM_PRIORITIES 7
|
#define VIRT_PLIC_NUM_PRIORITIES 7
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
/* RISC-V CPU definitions */
|
/* RISC-V CPU definitions */
|
||||||
|
|
||||||
static const char riscv_exts[26] = "IMAFDQECLBJTPVNSUHKORWXYZG";
|
static const char riscv_exts[26] = "IEMAFDQCLBJTPVNSUHKORWXYZG";
|
||||||
|
|
||||||
const char * const riscv_int_regnames[] = {
|
const char * const riscv_int_regnames[] = {
|
||||||
"zero", "ra ", "sp ", "gp ", "tp ", "t0 ", "t1 ", "t2 ",
|
"zero", "ra ", "sp ", "gp ", "tp ", "t0 ", "t1 ", "t2 ",
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
|
|
||||||
#define TCG_GUEST_DEFAULT_MO 0
|
#define TCG_GUEST_DEFAULT_MO 0
|
||||||
|
|
||||||
#define ELF_MACHINE EM_RISCV
|
|
||||||
#define CPUArchState struct CPURISCVState
|
#define CPUArchState struct CPURISCVState
|
||||||
|
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
|
@ -72,6 +71,7 @@
|
||||||
#define RV(x) ((target_ulong)1 << (x - 'A'))
|
#define RV(x) ((target_ulong)1 << (x - 'A'))
|
||||||
|
|
||||||
#define RVI RV('I')
|
#define RVI RV('I')
|
||||||
|
#define RVE RV('E') /* E and I are mutually exclusive */
|
||||||
#define RVM RV('M')
|
#define RVM RV('M')
|
||||||
#define RVA RV('A')
|
#define RVA RV('A')
|
||||||
#define RVF RV('F')
|
#define RVF RV('F')
|
||||||
|
@ -151,10 +151,8 @@ struct CPURISCVState {
|
||||||
target_ulong mcause;
|
target_ulong mcause;
|
||||||
target_ulong mtval; /* since: priv-1.10.0 */
|
target_ulong mtval; /* since: priv-1.10.0 */
|
||||||
|
|
||||||
uint32_t mucounteren;
|
target_ulong scounteren;
|
||||||
uint32_t mscounteren;
|
target_ulong mcounteren;
|
||||||
target_ulong scounteren; /* since: priv-1.10.0 */
|
|
||||||
target_ulong mcounteren; /* since: priv-1.10.0 */
|
|
||||||
|
|
||||||
target_ulong sscratch;
|
target_ulong sscratch;
|
||||||
target_ulong mscratch;
|
target_ulong mscratch;
|
||||||
|
|
|
@ -466,6 +466,10 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
||||||
": badaddr 0x" TARGET_FMT_lx, env->mhartid, env->badaddr);
|
": badaddr 0x" TARGET_FMT_lx, env->mhartid, env->badaddr);
|
||||||
}
|
}
|
||||||
env->sbadaddr = env->badaddr;
|
env->sbadaddr = env->badaddr;
|
||||||
|
} else {
|
||||||
|
/* otherwise we must clear sbadaddr/stval
|
||||||
|
* todo: support populating stval on illegal instructions */
|
||||||
|
env->sbadaddr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
target_ulong s = env->mstatus;
|
target_ulong s = env->mstatus;
|
||||||
|
@ -487,6 +491,10 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
||||||
": badaddr 0x" TARGET_FMT_lx, env->mhartid, env->badaddr);
|
": badaddr 0x" TARGET_FMT_lx, env->mhartid, env->badaddr);
|
||||||
}
|
}
|
||||||
env->mbadaddr = env->badaddr;
|
env->mbadaddr = env->badaddr;
|
||||||
|
} else {
|
||||||
|
/* otherwise we must clear mbadaddr/mtval
|
||||||
|
* todo: support populating mtval on illegal instructions */
|
||||||
|
env->mbadaddr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
target_ulong s = env->mstatus;
|
target_ulong s = env->mstatus;
|
||||||
|
|
|
@ -213,28 +213,41 @@ void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CSR_MINSTRET:
|
case CSR_MINSTRET:
|
||||||
qemu_log_mask(LOG_UNIMP, "CSR_MINSTRET: write not implemented");
|
/* minstret is WARL so unsupported writes are ignored */
|
||||||
goto do_illegal;
|
break;
|
||||||
case CSR_MCYCLE:
|
case CSR_MCYCLE:
|
||||||
qemu_log_mask(LOG_UNIMP, "CSR_MCYCLE: write not implemented");
|
/* mcycle is WARL so unsupported writes are ignored */
|
||||||
goto do_illegal;
|
break;
|
||||||
|
#if defined(TARGET_RISCV32)
|
||||||
case CSR_MINSTRETH:
|
case CSR_MINSTRETH:
|
||||||
qemu_log_mask(LOG_UNIMP, "CSR_MINSTRETH: write not implemented");
|
/* minstreth is WARL so unsupported writes are ignored */
|
||||||
goto do_illegal;
|
break;
|
||||||
case CSR_MCYCLEH:
|
case CSR_MCYCLEH:
|
||||||
qemu_log_mask(LOG_UNIMP, "CSR_MCYCLEH: write not implemented");
|
/* mcycleh is WARL so unsupported writes are ignored */
|
||||||
goto do_illegal;
|
break;
|
||||||
|
#endif
|
||||||
case CSR_MUCOUNTEREN:
|
case CSR_MUCOUNTEREN:
|
||||||
env->mucounteren = val_to_write;
|
if (env->priv_ver <= PRIV_VERSION_1_09_1) {
|
||||||
break;
|
env->scounteren = val_to_write;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
goto do_illegal;
|
||||||
|
}
|
||||||
case CSR_MSCOUNTEREN:
|
case CSR_MSCOUNTEREN:
|
||||||
env->mscounteren = val_to_write;
|
if (env->priv_ver <= PRIV_VERSION_1_09_1) {
|
||||||
break;
|
env->mcounteren = val_to_write;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
goto do_illegal;
|
||||||
|
}
|
||||||
case CSR_SSTATUS: {
|
case CSR_SSTATUS: {
|
||||||
target_ulong ms = env->mstatus;
|
target_ulong ms = env->mstatus;
|
||||||
target_ulong mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UIE
|
target_ulong mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UIE
|
||||||
| SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS
|
| SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS
|
||||||
| SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD;
|
| SSTATUS_SUM | SSTATUS_SD;
|
||||||
|
if (env->priv_ver >= PRIV_VERSION_1_10_0) {
|
||||||
|
mask |= SSTATUS_MXR;
|
||||||
|
}
|
||||||
ms = (ms & ~mask) | (val_to_write & mask);
|
ms = (ms & ~mask) | (val_to_write & mask);
|
||||||
csr_write_helper(env, ms, CSR_MSTATUS);
|
csr_write_helper(env, ms, CSR_MSTATUS);
|
||||||
break;
|
break;
|
||||||
|
@ -255,7 +268,7 @@ void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
|
||||||
}
|
}
|
||||||
case CSR_SATP: /* CSR_SPTBR */ {
|
case CSR_SATP: /* CSR_SPTBR */ {
|
||||||
if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
|
if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
|
||||||
goto do_illegal;
|
break;
|
||||||
}
|
}
|
||||||
if (env->priv_ver <= PRIV_VERSION_1_09_1 && (val_to_write ^ env->sptbr))
|
if (env->priv_ver <= PRIV_VERSION_1_09_1 && (val_to_write ^ env->sptbr))
|
||||||
{
|
{
|
||||||
|
@ -276,15 +289,20 @@ void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
|
||||||
env->sepc = val_to_write;
|
env->sepc = val_to_write;
|
||||||
break;
|
break;
|
||||||
case CSR_STVEC:
|
case CSR_STVEC:
|
||||||
if (val_to_write & 1) {
|
/* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */
|
||||||
|
if ((val_to_write & 3) == 0) {
|
||||||
|
env->stvec = val_to_write >> 2 << 2;
|
||||||
|
} else {
|
||||||
qemu_log_mask(LOG_UNIMP, "CSR_STVEC: vectored traps not supported");
|
qemu_log_mask(LOG_UNIMP, "CSR_STVEC: vectored traps not supported");
|
||||||
goto do_illegal;
|
|
||||||
}
|
}
|
||||||
env->stvec = val_to_write >> 2 << 2;
|
|
||||||
break;
|
break;
|
||||||
case CSR_SCOUNTEREN:
|
case CSR_SCOUNTEREN:
|
||||||
env->scounteren = val_to_write;
|
if (env->priv_ver >= PRIV_VERSION_1_10_0) {
|
||||||
break;
|
env->scounteren = val_to_write;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
goto do_illegal;
|
||||||
|
}
|
||||||
case CSR_SSCRATCH:
|
case CSR_SSCRATCH:
|
||||||
env->sscratch = val_to_write;
|
env->sscratch = val_to_write;
|
||||||
break;
|
break;
|
||||||
|
@ -298,15 +316,20 @@ void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
|
||||||
env->mepc = val_to_write;
|
env->mepc = val_to_write;
|
||||||
break;
|
break;
|
||||||
case CSR_MTVEC:
|
case CSR_MTVEC:
|
||||||
if (val_to_write & 1) {
|
/* bits [1:0] indicate mode; 0 = direct, 1 = vectored, 2 >= reserved */
|
||||||
|
if ((val_to_write & 3) == 0) {
|
||||||
|
env->mtvec = val_to_write >> 2 << 2;
|
||||||
|
} else {
|
||||||
qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: vectored traps not supported");
|
qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: vectored traps not supported");
|
||||||
goto do_illegal;
|
|
||||||
}
|
}
|
||||||
env->mtvec = val_to_write >> 2 << 2;
|
|
||||||
break;
|
break;
|
||||||
case CSR_MCOUNTEREN:
|
case CSR_MCOUNTEREN:
|
||||||
env->mcounteren = val_to_write;
|
if (env->priv_ver >= PRIV_VERSION_1_10_0) {
|
||||||
break;
|
env->mcounteren = val_to_write;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
goto do_illegal;
|
||||||
|
}
|
||||||
case CSR_MSCRATCH:
|
case CSR_MSCRATCH:
|
||||||
env->mscratch = val_to_write;
|
env->mscratch = val_to_write;
|
||||||
break;
|
break;
|
||||||
|
@ -316,10 +339,9 @@ void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
|
||||||
case CSR_MBADADDR:
|
case CSR_MBADADDR:
|
||||||
env->mbadaddr = val_to_write;
|
env->mbadaddr = val_to_write;
|
||||||
break;
|
break;
|
||||||
case CSR_MISA: {
|
case CSR_MISA:
|
||||||
qemu_log_mask(LOG_UNIMP, "CSR_MISA: misa writes not supported");
|
/* misa is WARL so unsupported writes are ignored */
|
||||||
goto do_illegal;
|
break;
|
||||||
}
|
|
||||||
case CSR_PMPCFG0:
|
case CSR_PMPCFG0:
|
||||||
case CSR_PMPCFG1:
|
case CSR_PMPCFG1:
|
||||||
case CSR_PMPCFG2:
|
case CSR_PMPCFG2:
|
||||||
|
@ -344,6 +366,8 @@ void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
|
||||||
case CSR_PMPADDR15:
|
case CSR_PMPADDR15:
|
||||||
pmpaddr_csr_write(env, csrno - CSR_PMPADDR0, val_to_write);
|
pmpaddr_csr_write(env, csrno - CSR_PMPADDR0, val_to_write);
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
do_illegal:
|
do_illegal:
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
|
@ -359,8 +383,8 @@ void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
|
||||||
target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno)
|
target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
target_ulong ctr_en = env->priv == PRV_U ? env->mucounteren :
|
target_ulong ctr_en = env->priv == PRV_U ? env->scounteren :
|
||||||
env->priv == PRV_S ? env->mscounteren : -1U;
|
env->priv == PRV_S ? env->mcounteren : -1U;
|
||||||
#else
|
#else
|
||||||
target_ulong ctr_en = -1;
|
target_ulong ctr_en = -1;
|
||||||
#endif
|
#endif
|
||||||
|
@ -413,35 +437,67 @@ target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno)
|
||||||
case CSR_INSTRET:
|
case CSR_INSTRET:
|
||||||
case CSR_CYCLE:
|
case CSR_CYCLE:
|
||||||
if (ctr_ok) {
|
if (ctr_ok) {
|
||||||
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
|
if (use_icount) {
|
||||||
|
return cpu_get_icount();
|
||||||
|
} else {
|
||||||
|
return cpu_get_host_ticks();
|
||||||
|
}
|
||||||
|
#else
|
||||||
return cpu_get_host_ticks();
|
return cpu_get_host_ticks();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#if defined(TARGET_RISCV32)
|
#if defined(TARGET_RISCV32)
|
||||||
case CSR_INSTRETH:
|
case CSR_INSTRETH:
|
||||||
case CSR_CYCLEH:
|
case CSR_CYCLEH:
|
||||||
if (ctr_ok) {
|
if (ctr_ok) {
|
||||||
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
|
if (use_icount) {
|
||||||
|
return cpu_get_icount() >> 32;
|
||||||
|
} else {
|
||||||
|
return cpu_get_host_ticks() >> 32;
|
||||||
|
}
|
||||||
|
#else
|
||||||
return cpu_get_host_ticks() >> 32;
|
return cpu_get_host_ticks() >> 32;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
case CSR_MINSTRET:
|
case CSR_MINSTRET:
|
||||||
case CSR_MCYCLE:
|
case CSR_MCYCLE:
|
||||||
return cpu_get_host_ticks();
|
if (use_icount) {
|
||||||
|
return cpu_get_icount();
|
||||||
|
} else {
|
||||||
|
return cpu_get_host_ticks();
|
||||||
|
}
|
||||||
case CSR_MINSTRETH:
|
case CSR_MINSTRETH:
|
||||||
case CSR_MCYCLEH:
|
case CSR_MCYCLEH:
|
||||||
#if defined(TARGET_RISCV32)
|
#if defined(TARGET_RISCV32)
|
||||||
return cpu_get_host_ticks() >> 32;
|
if (use_icount) {
|
||||||
|
return cpu_get_icount() >> 32;
|
||||||
|
} else {
|
||||||
|
return cpu_get_host_ticks() >> 32;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case CSR_MUCOUNTEREN:
|
case CSR_MUCOUNTEREN:
|
||||||
return env->mucounteren;
|
if (env->priv_ver <= PRIV_VERSION_1_09_1) {
|
||||||
|
return env->scounteren;
|
||||||
|
} else {
|
||||||
|
break; /* illegal instruction */
|
||||||
|
}
|
||||||
case CSR_MSCOUNTEREN:
|
case CSR_MSCOUNTEREN:
|
||||||
return env->mscounteren;
|
if (env->priv_ver <= PRIV_VERSION_1_09_1) {
|
||||||
|
return env->mcounteren;
|
||||||
|
} else {
|
||||||
|
break; /* illegal instruction */
|
||||||
|
}
|
||||||
case CSR_SSTATUS: {
|
case CSR_SSTATUS: {
|
||||||
target_ulong mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UIE
|
target_ulong mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UIE
|
||||||
| SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS
|
| SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS
|
||||||
| SSTATUS_SUM | SSTATUS_SD;
|
| SSTATUS_SUM | SSTATUS_SD;
|
||||||
if (env->priv_ver >= PRIV_VERSION_1_10_0) {
|
if (env->priv_ver >= PRIV_VERSION_1_10_0) {
|
||||||
mask |= SSTATUS_MXR;
|
mask |= SSTATUS_MXR;
|
||||||
}
|
}
|
||||||
|
@ -462,10 +518,17 @@ target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno)
|
||||||
case CSR_STVEC:
|
case CSR_STVEC:
|
||||||
return env->stvec;
|
return env->stvec;
|
||||||
case CSR_SCOUNTEREN:
|
case CSR_SCOUNTEREN:
|
||||||
return env->scounteren;
|
if (env->priv_ver >= PRIV_VERSION_1_10_0) {
|
||||||
|
return env->scounteren;
|
||||||
|
} else {
|
||||||
|
break; /* illegal instruction */
|
||||||
|
}
|
||||||
case CSR_SCAUSE:
|
case CSR_SCAUSE:
|
||||||
return env->scause;
|
return env->scause;
|
||||||
case CSR_SPTBR:
|
case CSR_SATP: /* CSR_SPTBR */
|
||||||
|
if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (env->priv_ver >= PRIV_VERSION_1_10_0) {
|
if (env->priv_ver >= PRIV_VERSION_1_10_0) {
|
||||||
return env->satp;
|
return env->satp;
|
||||||
} else {
|
} else {
|
||||||
|
@ -504,7 +567,11 @@ target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno)
|
||||||
case CSR_MTVEC:
|
case CSR_MTVEC:
|
||||||
return env->mtvec;
|
return env->mtvec;
|
||||||
case CSR_MCOUNTEREN:
|
case CSR_MCOUNTEREN:
|
||||||
return env->mcounteren;
|
if (env->priv_ver >= PRIV_VERSION_1_10_0) {
|
||||||
|
return env->mcounteren;
|
||||||
|
} else {
|
||||||
|
break; /* illegal instruction */
|
||||||
|
}
|
||||||
case CSR_MEDELEG:
|
case CSR_MEDELEG:
|
||||||
return env->medeleg;
|
return env->medeleg;
|
||||||
case CSR_MIDELEG:
|
case CSR_MIDELEG:
|
||||||
|
|
|
@ -280,7 +280,6 @@ static void gen_arith(DisasContext *ctx, uint32_t opc, int rd, int rs1,
|
||||||
tcg_gen_andi_tl(source2, source2, 0x1F);
|
tcg_gen_andi_tl(source2, source2, 0x1F);
|
||||||
tcg_gen_sar_tl(source1, source1, source2);
|
tcg_gen_sar_tl(source1, source1, source2);
|
||||||
break;
|
break;
|
||||||
/* fall through to SRA */
|
|
||||||
#endif
|
#endif
|
||||||
case OPC_RISC_SRA:
|
case OPC_RISC_SRA:
|
||||||
tcg_gen_andi_tl(source2, source2, TARGET_LONG_BITS - 1);
|
tcg_gen_andi_tl(source2, source2, TARGET_LONG_BITS - 1);
|
||||||
|
@ -1391,6 +1390,7 @@ static void gen_system(CPURISCVState *env, DisasContext *ctx, uint32_t opc,
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
tcg_gen_movi_tl(imm_rs1, rs1);
|
tcg_gen_movi_tl(imm_rs1, rs1);
|
||||||
|
gen_io_start();
|
||||||
switch (opc) {
|
switch (opc) {
|
||||||
case OPC_RISC_CSRRW:
|
case OPC_RISC_CSRRW:
|
||||||
gen_helper_csrrw(dest, cpu_env, source1, csr_store);
|
gen_helper_csrrw(dest, cpu_env, source1, csr_store);
|
||||||
|
@ -1414,6 +1414,7 @@ static void gen_system(CPURISCVState *env, DisasContext *ctx, uint32_t opc,
|
||||||
gen_exception_illegal(ctx);
|
gen_exception_illegal(ctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
gen_io_end();
|
||||||
gen_set_gpr(rd, dest);
|
gen_set_gpr(rd, dest);
|
||||||
/* end tb since we may be changing priv modes, to get mmu_index right */
|
/* end tb since we may be changing priv modes, to get mmu_index right */
|
||||||
tcg_gen_movi_tl(cpu_pc, ctx->next_pc);
|
tcg_gen_movi_tl(cpu_pc, ctx->next_pc);
|
||||||
|
|
Loading…
Reference in New Issue