RISC-V Patches for the 4.1 Soft Freeze, Part 1

This tag contains a handful of patches that I'd like to target for 4.1:
 
 * An emulation for SiFive's GPIO device.
 * A fix to disallow sfence.vma from userspace.
 * Additional decodetree cleanups that should have no functional impact.
 * C extension emulation fidelity fixes that were noticed as part of that
   cleanup process.
 * A new "spike" target, along with the deprecation of a handful of old
   targets and CPUs.
 * Some initial infastructure related to the hypervisor extension.
 * An emulation fidelity fix that prevents prevents arbitrary bits in the
   SIP CSR from being set.
 * A small performance improvement that avoids excessive TLB flushing
   when the ASID does not change.
 
 This time I've used a new testing workflow: I've tested on both 32-bit
 and 64-bit builds of OpenEmbedded, via the default OpenSBI-based boot
 flow.
 -----BEGIN PGP SIGNATURE-----
 
 iQJHBAABCAAxFiEEAM520YNJYN/OiG3470yhUCzLq0EFAlzohuUTHHBhbG1lckBk
 YWJiZWx0LmNvbQAKCRDvTKFQLMurQfcKD/9xSyQld3g41e4qrcq/MHHQhIou0Mpj
 FdJ9jb5k8ndlhJix1RCJorXQ4ld7KPco5ywdQGebEzrSlsI0hanlWkrtBDibR9dU
 OoNjrBRqKAjTQOkIsmgQMW961n9HnfSZNlmm/L1n94TC/6W4/g+hlvDXQNJjyDKX
 u8QalbfNFlolSv11vOxSlVFTo8Cb6/++yBitvbLdNnquWcDgxid6FYWKMEmYB4jK
 pOTzlb0ZDdvS7rGLdMkTB2pTqrvEykP1uLvXpF7qOurGgoeHul2lqKiRuVcFFU46
 6IOsaiwzDtMoUHzuFZypEJfnm0uJ4FEGEK8ZQBXlQhl2c0MDLXzXhIekKZIs/BmG
 K1Anio30zgfJscA6Zv6ZPataeEbPQ/l0LeAgS/Q8n7zIN5oRi3D9kdNTlo1MoSpD
 RLXESf0uXaTxkOAiyQ2hDj/NuPqja4TFD6UKj91eoWIhcga8i4olqsvLmsTsxhCK
 aaaiLGpYnmm/yhmBjMOAeBnu03w0ApTFS2UoPoMvTnrhZI4OXhm9XABEASpzdh57
 5mJL/U8eJ098QSxBui2Sjcpn8mxfy1FHqAQl+urDCAb6/P/94+729LVzyuvEV08U
 IHYMFjO8v4e56Sf6eys6rcPYpPV/jrLnyL8uFODN1PsXY9+OyH/KLCGVb1vyAgsP
 nhE2uPKTnIrPqA==
 =7LvI
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/palmer/tags/riscv-for-master-4.1-sf0' into staging

RISC-V Patches for the 4.1 Soft Freeze, Part 1

This tag contains a handful of patches that I'd like to target for 4.1:

* An emulation for SiFive's GPIO device.
* A fix to disallow sfence.vma from userspace.
* Additional decodetree cleanups that should have no functional impact.
* C extension emulation fidelity fixes that were noticed as part of that
  cleanup process.
* A new "spike" target, along with the deprecation of a handful of old
  targets and CPUs.
* Some initial infastructure related to the hypervisor extension.
* An emulation fidelity fix that prevents prevents arbitrary bits in the
  SIP CSR from being set.
* A small performance improvement that avoids excessive TLB flushing
  when the ASID does not change.

This time I've used a new testing workflow: I've tested on both 32-bit
and 64-bit builds of OpenEmbedded, via the default OpenSBI-based boot
flow.

# gpg: Signature made Sat 25 May 2019 01:05:57 BST
# gpg:                using RSA key 00CE76D1834960DFCE886DF8EF4CA1502CCBAB41
# gpg:                issuer "palmer@dabbelt.com"
# gpg: Good signature from "Palmer Dabbelt <palmer@dabbelt.com>" [unknown]
# gpg:                 aka "Palmer Dabbelt <palmer@sifive.com>" [unknown]
# 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: 00CE 76D1 8349 60DF CE88  6DF8 EF4C A150 2CCB AB41

* remotes/palmer/tags/riscv-for-master-4.1-sf0: (29 commits)
  target/riscv: Only flush TLB if SATP.ASID changes
  target/riscv: More accurate handling of `sip` CSR
  target/riscv: Add checks for several RVC reserved operands
  target/riscv: Add the HGATP register masks
  target/riscv: Add the HSTATUS register masks
  target/riscv: Add Hypervisor CSR macros
  target/riscv: Allow setting mstatus virtulisation bits
  target/riscv: Add the MPV and MTL mstatus bits
  target/riscv: Improve the scause logic
  target/riscv: Trigger interrupt on MIP update asynchronously
  target/riscv: Mark privilege level 2 as reserved
  riscv: spike: Add a generic spike machine
  target/riscv: Deprecate the generic no MMU CPUs
  target/riscv: Add a base 32 and 64 bit CPU
  target/riscv: Create settable CPU properties
  riscv: virt: Allow specifying a CPU via commandline
  linux-user/riscv: Add the CPU type as a comment
  target/riscv: Remove unused include of riscv_htif.h for virt board riscv
  target/riscv: Remove spaces from register names
  target/riscv: Split gen_arith_imm into functional and temp
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-05-28 11:52:53 +01:00
commit 4bade28288
27 changed files with 1046 additions and 507 deletions

View file

@ -182,6 +182,7 @@ trace-events-subdirs += hw/virtio
trace-events-subdirs += hw/watchdog
trace-events-subdirs += hw/xen
trace-events-subdirs += hw/gpio
trace-events-subdirs += hw/riscv
trace-events-subdirs += migration
trace-events-subdirs += net
trace-events-subdirs += ui

View file

@ -2,6 +2,7 @@ obj-$(CONFIG_SPIKE) += riscv_htif.o
obj-$(CONFIG_HART) += riscv_hart.o
obj-$(CONFIG_SIFIVE_E) += sifive_e.o
obj-$(CONFIG_SIFIVE) += sifive_clint.o
obj-$(CONFIG_SIFIVE) += sifive_gpio.o
obj-$(CONFIG_SIFIVE) += sifive_prci.o
obj-$(CONFIG_SIFIVE) += sifive_plic.o
obj-$(CONFIG_SIFIVE) += sifive_test.o

View file

@ -146,11 +146,15 @@ static void riscv_sifive_e_soc_init(Object *obj)
&error_abort);
object_property_set_int(OBJECT(&s->cpus), smp_cpus, "num-harts",
&error_abort);
sysbus_init_child_obj(obj, "riscv.sifive.e.gpio0",
&s->gpio, sizeof(s->gpio),
TYPE_SIFIVE_GPIO);
}
static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp)
{
const struct MemmapEntry *memmap = sifive_e_memmap;
Error *err = NULL;
SiFiveESoCState *s = RISCV_E_SOC(dev);
MemoryRegion *sys_mem = get_system_memory();
@ -184,8 +188,28 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp)
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.aon",
memmap[SIFIVE_E_AON].base, memmap[SIFIVE_E_AON].size);
sifive_prci_create(memmap[SIFIVE_E_PRCI].base);
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.gpio0",
memmap[SIFIVE_E_GPIO0].base, memmap[SIFIVE_E_GPIO0].size);
/* GPIO */
object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
/* Map GPIO registers */
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, memmap[SIFIVE_E_GPIO0].base);
/* Pass all GPIOs to the SOC layer so they are available to the board */
qdev_pass_gpios(DEVICE(&s->gpio), dev, NULL);
/* Connect GPIO interrupts to the PLIC */
for (int i = 0; i < 32; i++) {
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), i,
qdev_get_gpio_in(DEVICE(s->plic),
SIFIVE_E_GPIO0_IRQ0 + i));
}
sifive_uart_create(sys_mem, memmap[SIFIVE_E_UART0].base,
serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_E_UART0_IRQ));
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.qspi0",

388
hw/riscv/sifive_gpio.c Normal file
View file

@ -0,0 +1,388 @@
/*
* 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/riscv/sifive_gpio.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 < SIFIVE_GPIO_PINS; 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 < SIFIVE_GPIO_PINS; 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;
}
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 void sifive_gpio_init(Object *obj)
{
SIFIVEGPIOState *s = SIFIVE_GPIO(obj);
memory_region_init_io(&s->mmio, obj, &gpio_ops, s,
TYPE_SIFIVE_GPIO, SIFIVE_GPIO_SIZE);
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
for (int i = 0; i < SIFIVE_GPIO_PINS; i++) {
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq[i]);
}
qdev_init_gpio_in(DEVICE(s), sifive_gpio_set, SIFIVE_GPIO_PINS);
qdev_init_gpio_out(DEVICE(s), s->output, SIFIVE_GPIO_PINS);
}
static void sifive_gpio_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_sifive_gpio;
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),
.instance_init = sifive_gpio_init,
.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)

View file

@ -39,6 +39,7 @@
#include "chardev/char.h"
#include "sysemu/arch_init.h"
#include "sysemu/device_tree.h"
#include "sysemu/qtest.h"
#include "exec/address-spaces.h"
#include "elf.h"
@ -160,7 +161,89 @@ static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap,
qemu_fdt_add_subnode(fdt, "/chosen");
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
}
}
}
static void spike_board_init(MachineState *machine)
{
const struct MemmapEntry *memmap = spike_memmap;
SpikeState *s = g_new0(SpikeState, 1);
MemoryRegion *system_memory = get_system_memory();
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
int i;
/* Initialize SOC */
object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc),
TYPE_RISCV_HART_ARRAY, &error_abort, NULL);
object_property_set_str(OBJECT(&s->soc), machine->cpu_type, "cpu-type",
&error_abort);
object_property_set_int(OBJECT(&s->soc), smp_cpus, "num-harts",
&error_abort);
object_property_set_bool(OBJECT(&s->soc), true, "realized",
&error_abort);
/* register system main memory (actual RAM) */
memory_region_init_ram(main_mem, NULL, "riscv.spike.ram",
machine->ram_size, &error_fatal);
memory_region_add_subregion(system_memory, memmap[SPIKE_DRAM].base,
main_mem);
/* create device tree */
create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
/* boot rom */
memory_region_init_rom(mask_rom, NULL, "riscv.spike.mrom",
memmap[SPIKE_MROM].size, &error_fatal);
memory_region_add_subregion(system_memory, memmap[SPIKE_MROM].base,
mask_rom);
if (machine->kernel_filename) {
load_kernel(machine->kernel_filename);
}
/* reset vector */
uint32_t reset_vec[8] = {
0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */
0x02028593, /* addi a1, t0, %pcrel_lo(1b) */
0xf1402573, /* csrr a0, mhartid */
#if defined(TARGET_RISCV32)
0x0182a283, /* lw t0, 24(t0) */
#elif defined(TARGET_RISCV64)
0x0182b283, /* ld t0, 24(t0) */
#endif
0x00028067, /* jr t0 */
0x00000000,
memmap[SPIKE_DRAM].base, /* start: .dword DRAM_BASE */
0x00000000,
/* dtb: */
};
/* copy in the reset vector in little_endian byte order */
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 */
if (fdt_pack(s->fdt) || fdt_totalsize(s->fdt) >
memmap[SPIKE_MROM].size - sizeof(reset_vec)) {
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 */
htif_mm_init(system_memory, mask_rom, &s->soc.harts[0].env, serial_hd(0));
/* Core Local Interruptor (timer and IPI) */
sifive_clint_create(memmap[SPIKE_CLINT].base, memmap[SPIKE_CLINT].size,
smp_cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE);
}
static void spike_v1_10_0_board_init(MachineState *machine)
{
@ -172,6 +255,12 @@ static void spike_v1_10_0_board_init(MachineState *machine)
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
int i;
if (!qtest_enabled()) {
info_report("The Spike v1.10.0 machine has been deprecated. "
"Please use the generic spike machine and specify the ISA "
"versions using -cpu.");
}
/* Initialize SOC */
object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc),
TYPE_RISCV_HART_ARRAY, &error_abort, NULL);
@ -254,6 +343,12 @@ static void spike_v1_09_1_board_init(MachineState *machine)
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
int i;
if (!qtest_enabled()) {
info_report("The Spike v1.09.1 machine has been deprecated. "
"Please use the generic spike machine and specify the ISA "
"versions using -cpu.");
}
/* Initialize SOC */
object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc),
TYPE_RISCV_HART_ARRAY, &error_abort, NULL);
@ -359,8 +454,17 @@ static void spike_v1_10_0_machine_init(MachineClass *mc)
mc->desc = "RISC-V Spike Board (Privileged ISA v1.10)";
mc->init = spike_v1_10_0_board_init;
mc->max_cpus = 1;
}
static void spike_machine_init(MachineClass *mc)
{
mc->desc = "RISC-V Spike Board";
mc->init = spike_board_init;
mc->max_cpus = 1;
mc->is_default = 1;
mc->default_cpu_type = SPIKE_V1_10_0_CPU;
}
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", spike_machine_init)

7
hw/riscv/trace-events Normal file
View file

@ -0,0 +1,7 @@
# See docs/devel/tracing.txt for syntax documentation.
# hw/gpio/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

View file

@ -29,7 +29,6 @@
#include "hw/sysbus.h"
#include "hw/char/serial.h"
#include "target/riscv/cpu.h"
#include "hw/riscv/riscv_htif.h"
#include "hw/riscv/riscv_hart.h"
#include "hw/riscv/sifive_plic.h"
#include "hw/riscv/sifive_clint.h"
@ -400,7 +399,7 @@ static void riscv_virt_board_init(MachineState *machine)
/* Initialize SOC */
object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc),
TYPE_RISCV_HART_ARRAY, &error_abort, NULL);
object_property_set_str(OBJECT(&s->soc), VIRT_CPU, "cpu-type",
object_property_set_str(OBJECT(&s->soc), machine->cpu_type, "cpu-type",
&error_abort);
object_property_set_int(OBJECT(&s->soc), smp_cpus, "num-harts",
&error_abort);
@ -526,6 +525,7 @@ static void riscv_virt_board_machine_init(MachineClass *mc)
mc->desc = "RISC-V VirtIO Board (Privileged ISA v1.10)";
mc->init = riscv_virt_board_init;
mc->max_cpus = 8; /* hardcoded limit in BBL */
mc->default_cpu_type = VIRT_CPU;
}
DEFINE_MACHINE("virt", riscv_virt_board_machine_init)

View file

@ -19,6 +19,8 @@
#ifndef HW_SIFIVE_E_H
#define HW_SIFIVE_E_H
#include "hw/riscv/sifive_gpio.h"
#define TYPE_RISCV_E_SOC "riscv.sifive.e.soc"
#define RISCV_E_SOC(obj) \
OBJECT_CHECK(SiFiveESoCState, (obj), TYPE_RISCV_E_SOC)
@ -30,6 +32,7 @@ typedef struct SiFiveESoCState {
/*< public >*/
RISCVHartArrayState cpus;
DeviceState *plic;
SIFIVEGPIOState gpio;
} SiFiveESoCState;
typedef struct SiFiveEState {
@ -63,8 +66,9 @@ enum {
};
enum {
SIFIVE_E_UART0_IRQ = 3,
SIFIVE_E_UART1_IRQ = 4
SIFIVE_E_UART0_IRQ = 3,
SIFIVE_E_UART1_IRQ = 4,
SIFIVE_E_GPIO0_IRQ0 = 8
};
#define SIFIVE_E_PLIC_HART_CONFIG "M"

View file

@ -0,0 +1,72 @@
/*
* 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.
*/
#ifndef SIFIVE_GPIO_H
#define SIFIVE_GPIO_H
#include "hw/sysbus.h"
#define TYPE_SIFIVE_GPIO "sifive_soc.gpio"
#define SIFIVE_GPIO(obj) OBJECT_CHECK(SIFIVEGPIOState, (obj), TYPE_SIFIVE_GPIO)
#define SIFIVE_GPIO_PINS 32
#define SIFIVE_GPIO_SIZE 0x100
#define SIFIVE_GPIO_REG_VALUE 0x000
#define SIFIVE_GPIO_REG_INPUT_EN 0x004
#define SIFIVE_GPIO_REG_OUTPUT_EN 0x008
#define SIFIVE_GPIO_REG_PORT 0x00C
#define SIFIVE_GPIO_REG_PUE 0x010
#define SIFIVE_GPIO_REG_DS 0x014
#define SIFIVE_GPIO_REG_RISE_IE 0x018
#define SIFIVE_GPIO_REG_RISE_IP 0x01C
#define SIFIVE_GPIO_REG_FALL_IE 0x020
#define SIFIVE_GPIO_REG_FALL_IP 0x024
#define SIFIVE_GPIO_REG_HIGH_IE 0x028
#define SIFIVE_GPIO_REG_HIGH_IP 0x02C
#define SIFIVE_GPIO_REG_LOW_IE 0x030
#define SIFIVE_GPIO_REG_LOW_IP 0x034
#define SIFIVE_GPIO_REG_IOF_EN 0x038
#define SIFIVE_GPIO_REG_IOF_SEL 0x03C
#define SIFIVE_GPIO_REG_OUT_XOR 0x040
typedef struct SIFIVEGPIOState {
SysBusDevice parent_obj;
MemoryRegion mmio;
qemu_irq irq[SIFIVE_GPIO_PINS];
qemu_irq output[SIFIVE_GPIO_PINS];
uint32_t value; /* Actual value of the pin */
uint32_t input_en;
uint32_t output_en;
uint32_t port; /* Pin value requested by the user */
uint32_t pue;
uint32_t ds;
uint32_t rise_ie;
uint32_t rise_ip;
uint32_t fall_ie;
uint32_t fall_ip;
uint32_t high_ie;
uint32_t high_ip;
uint32_t low_ie;
uint32_t low_ip;
uint32_t iof_en;
uint32_t iof_sel;
uint32_t out_xor;
uint32_t in;
uint32_t in_mask;
} SIFIVEGPIOState;
#endif

View file

@ -74,9 +74,9 @@ enum {
FDT_PLIC_ADDR_CELLS + FDT_PLIC_INT_CELLS)
#if defined(TARGET_RISCV32)
#define VIRT_CPU TYPE_RISCV_CPU_RV32GCSU_V1_10_0
#define VIRT_CPU TYPE_RISCV_CPU_BASE32
#elif defined(TARGET_RISCV64)
#define VIRT_CPU TYPE_RISCV_CPU_RV64GCSU_V1_10_0
#define VIRT_CPU TYPE_RISCV_CPU_BASE64
#endif
#endif

View file

@ -9,6 +9,7 @@
#define RISCV_TARGET_ELF_H
static inline const char *cpu_get_model(uint32_t eflags)
{
/* TYPE_RISCV_CPU_ANY */
return "any";
}
#endif

View file

@ -138,6 +138,21 @@ The ``acl_show'', ``acl_reset'', ``acl_policy'', ``acl_add'', and
``acl_remove'' commands are deprecated with no replacement. Authorization
for VNC should be performed using the pluggable QAuthZ objects.
@section System emulator CPUS
@subsection RISC-V ISA CPUs (since 4.1)
The RISC-V cpus with the ISA version in the CPU name have been depcreated. The
four CPUs are: ``rv32gcsu-v1.9.1``, ``rv32gcsu-v1.10.0``, ``rv64gcsu-v1.9.1`` and
``rv64gcsu-v1.10.0``. Instead the version can be specified via the CPU ``priv_spec``
option when using the ``rv32`` or ``rv64`` CPUs.
@subsection RISC-V ISA CPUs (since 4.1)
The RISC-V no MMU cpus have been depcreated. The two CPUs: ``rv32imacu-nommu`` and
``rv64imacu-nommu`` should no longer be used. Instead the MMU status can be specified
via the CPU ``mmu`` option when using the ``rv32`` or ``rv64`` CPUs.
@section System emulator devices
@subsection bluetooth (since 3.1)
@ -160,6 +175,12 @@ This machine type uses an unmaintained firmware, broken in lots of ways,
and unable to start post-2004 operating systems. 40p machine type should be
used instead.
@subsection spike_v1.9.1 and spike_v1.10 (since 4.1)
The version specific Spike machines have been deprecated in favour of the
generic ``spike`` machine. If you need to specify an older version of the RISC-V
spec you can use the ``-cpu rv64gcsu,priv_spec=v1.9.1`` command line argument.
@section Device options
@subsection Block device options

View file

@ -5,16 +5,19 @@ DECODETREE = $(SRC_PATH)/scripts/decodetree.py
decode32-y = $(SRC_PATH)/target/riscv/insn32.decode
decode32-$(TARGET_RISCV64) += $(SRC_PATH)/target/riscv/insn32-64.decode
decode16-y = $(SRC_PATH)/target/riscv/insn16.decode
decode16-$(TARGET_RISCV32) += $(SRC_PATH)/target/riscv/insn16-32.decode
decode16-$(TARGET_RISCV64) += $(SRC_PATH)/target/riscv/insn16-64.decode
target/riscv/decode_insn32.inc.c: $(decode32-y) $(DECODETREE)
$(call quiet-command, \
$(PYTHON) $(DECODETREE) -o $@ --decode decode_insn32 $(decode32-y), \
"GEN", $(TARGET_DIR)$@)
$(PYTHON) $(DECODETREE) -o $@ --static-decode decode_insn32 \
$(decode32-y), "GEN", $(TARGET_DIR)$@)
target/riscv/decode_insn16.inc.c: \
$(SRC_PATH)/target/riscv/insn16.decode $(DECODETREE)
target/riscv/decode_insn16.inc.c: $(decode16-y) $(DECODETREE)
$(call quiet-command, \
$(PYTHON) $(DECODETREE) -o $@ --decode decode_insn16 --insnwidth 16 $<, \
"GEN", $(TARGET_DIR)$@)
$(PYTHON) $(DECODETREE) -o $@ --static-decode decode_insn16 \
--insnwidth 16 $(decode16-y), "GEN", $(TARGET_DIR)$@)
target/riscv/translate.o: target/riscv/decode_insn32.inc.c \
target/riscv/decode_insn16.inc.c

View file

@ -23,6 +23,7 @@
#include "cpu.h"
#include "exec/exec-all.h"
#include "qapi/error.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
/* RISC-V CPU definitions */
@ -30,17 +31,17 @@
static const char riscv_exts[26] = "IEMAFDQCLBJTPVNSUHKORWXYZG";
const char * const riscv_int_regnames[] = {
"zero", "ra ", "sp ", "gp ", "tp ", "t0 ", "t1 ", "t2 ",
"s0 ", "s1 ", "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ",
"a6 ", "a7 ", "s2 ", "s3 ", "s4 ", "s5 ", "s6 ", "s7 ",
"s8 ", "s9 ", "s10 ", "s11 ", "t3 ", "t4 ", "t5 ", "t6 "
"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
"s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
"a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
"s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
};
const char * const riscv_fpr_regnames[] = {
"ft0 ", "ft1 ", "ft2 ", "ft3 ", "ft4 ", "ft5 ", "ft6 ", "ft7 ",
"fs0 ", "fs1 ", "fa0 ", "fa1 ", "fa2 ", "fa3 ", "fa4 ", "fa5 ",
"fa6 ", "fa7 ", "fs2 ", "fs3 ", "fs4 ", "fs5 ", "fs6 ", "fs7 ",
"fs8 ", "fs9 ", "fs10", "fs11", "ft8 ", "ft9 ", "ft10", "ft11"
"ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7",
"fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5",
"fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
"fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11"
};
const char * const riscv_excp_names[] = {
@ -114,6 +115,12 @@ static void riscv_any_cpu_init(Object *obj)
#if defined(TARGET_RISCV32)
static void riscv_base32_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
}
static void rv32gcsu_priv1_09_1_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
@ -145,6 +152,12 @@ static void rv32imacu_nommu_cpu_init(Object *obj)
#elif defined(TARGET_RISCV64)
static void riscv_base64_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
}
static void rv64gcsu_priv1_09_1_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
@ -296,7 +309,11 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info)
static void riscv_cpu_realize(DeviceState *dev, Error **errp)
{
CPUState *cs = CPU(dev);
RISCVCPU *cpu = RISCV_CPU(dev);
CPURISCVState *env = &cpu->env;
RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
int priv_version = PRIV_VERSION_1_10_0;
int user_version = USER_VERSION_2_02_0;
Error *local_err = NULL;
cpu_exec_realizefn(cs, &local_err);
@ -305,6 +322,41 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
return;
}
if (cpu->cfg.priv_spec) {
if (!g_strcmp0(cpu->cfg.priv_spec, "v1.10.0")) {
priv_version = PRIV_VERSION_1_10_0;
} else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.9.1")) {
priv_version = PRIV_VERSION_1_09_1;
} else {
error_setg(errp,
"Unsupported privilege spec version '%s'",
cpu->cfg.priv_spec);
return;
}
}
if (cpu->cfg.user_spec) {
if (!g_strcmp0(cpu->cfg.user_spec, "v2.02.0")) {
user_version = USER_VERSION_2_02_0;
} else {
error_setg(errp,
"Unsupported user spec version '%s'",
cpu->cfg.user_spec);
return;
}
}
set_versions(env, user_version, priv_version);
set_resetvec(env, DEFAULT_RSTVEC);
if (cpu->cfg.mmu) {
set_feature(env, RISCV_FEATURE_MMU);
}
if (cpu->cfg.pmp) {
set_feature(env, RISCV_FEATURE_PMP);
}
riscv_cpu_register_gdb_regs_for_features(cs);
qemu_init_vcpu(cs);
@ -326,6 +378,14 @@ static const VMStateDescription vmstate_riscv_cpu = {
.unmigratable = 1,
};
static Property riscv_cpu_properties[] = {
DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec),
DEFINE_PROP_STRING("user_spec", RISCVCPU, cfg.user_spec),
DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
DEFINE_PROP_END_OF_LIST(),
};
static void riscv_cpu_class_init(ObjectClass *c, void *data)
{
RISCVCPUClass *mcc = RISCV_CPU_CLASS(c);
@ -365,6 +425,7 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
#endif
/* For now, mark unmigratable: */
cc->vmsd = &vmstate_riscv_cpu;
dc->props = riscv_cpu_properties;
}
char *riscv_isa_string(RISCVCPU *cpu)
@ -430,12 +491,14 @@ static const TypeInfo riscv_cpu_type_infos[] = {
},
DEFINE_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init),
#if defined(TARGET_RISCV32)
DEFINE_CPU(TYPE_RISCV_CPU_BASE32, riscv_base32_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_09_1, rv32gcsu_priv1_09_1_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_10_0, rv32gcsu_priv1_10_0_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_RV32IMACU_NOMMU, rv32imacu_nommu_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32imacu_nommu_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32gcsu_priv1_10_0_cpu_init)
#elif defined(TARGET_RISCV64)
DEFINE_CPU(TYPE_RISCV_CPU_BASE64, riscv_base64_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_09_1, rv64gcsu_priv1_09_1_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_10_0, rv64gcsu_priv1_10_0_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_RV64IMACU_NOMMU, rv64imacu_nommu_cpu_init),

View file

@ -48,6 +48,8 @@
#define CPU_RESOLVING_TYPE TYPE_RISCV_CPU
#define TYPE_RISCV_CPU_ANY RISCV_CPU_TYPE_NAME("any")
#define TYPE_RISCV_CPU_BASE32 RISCV_CPU_TYPE_NAME("rv32")
#define TYPE_RISCV_CPU_BASE64 RISCV_CPU_TYPE_NAME("rv64")
#define TYPE_RISCV_CPU_RV32GCSU_V1_09_1 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.9.1")
#define TYPE_RISCV_CPU_RV32GCSU_V1_10_0 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.10.0")
#define TYPE_RISCV_CPU_RV32IMACU_NOMMU RISCV_CPU_TYPE_NAME("rv32imacu-nommu")
@ -224,6 +226,14 @@ typedef struct RISCVCPU {
CPUState parent_obj;
/*< public >*/
CPURISCVState env;
/* Configuration Settings */
struct {
char *priv_spec;
char *user_spec;
bool mmu;
bool pmp;
} cfg;
} RISCVCPU;
static inline RISCVCPU *riscv_env_get_cpu(CPURISCVState *env)

View file

@ -202,6 +202,23 @@
#define CSR_DPC 0x7b1
#define CSR_DSCRATCH 0x7b2
/* Hpervisor CSRs */
#define CSR_HSTATUS 0xa00
#define CSR_HEDELEG 0xa02
#define CSR_HIDELEG 0xa03
#define CSR_HGATP 0xa80
#if defined(TARGET_RISCV32)
#define HGATP_MODE SATP32_MODE
#define HGATP_ASID SATP32_ASID
#define HGATP_PPN SATP32_PPN
#endif
#if defined(TARGET_RISCV64)
#define HGATP_MODE SATP64_MODE
#define HGATP_ASID SATP64_ASID
#define HGATP_PPN SATP64_PPN
#endif
/* Performance Counters */
#define CSR_MHPMCOUNTER3 0xb03
#define CSR_MHPMCOUNTER4 0xb04
@ -292,9 +309,6 @@
#define CSR_MHPMCOUNTER31H 0xb9f
/* Legacy Hypervisor Trap Setup (priv v1.9.1) */
#define CSR_HSTATUS 0x200
#define CSR_HEDELEG 0x202
#define CSR_HIDELEG 0x203
#define CSR_HIE 0x204
#define CSR_HTVEC 0x205
@ -316,14 +330,11 @@
/* mstatus CSR bits */
#define MSTATUS_UIE 0x00000001
#define MSTATUS_SIE 0x00000002
#define MSTATUS_HIE 0x00000004
#define MSTATUS_MIE 0x00000008
#define MSTATUS_UPIE 0x00000010
#define MSTATUS_SPIE 0x00000020
#define MSTATUS_HPIE 0x00000040
#define MSTATUS_MPIE 0x00000080
#define MSTATUS_SPP 0x00000100
#define MSTATUS_HPP 0x00000600
#define MSTATUS_MPP 0x00001800
#define MSTATUS_FS 0x00006000
#define MSTATUS_XS 0x00018000
@ -335,6 +346,8 @@
#define MSTATUS_TVM 0x00100000 /* since: priv-1.10 */
#define MSTATUS_TW 0x20000000 /* since: priv-1.10 */
#define MSTATUS_TSR 0x40000000 /* since: priv-1.10 */
#define MSTATUS_MTL 0x4000000000ULL
#define MSTATUS_MPV 0x8000000000ULL
#define MSTATUS64_UXL 0x0000000300000000ULL
#define MSTATUS64_SXL 0x0000000C00000000ULL
@ -380,10 +393,28 @@
#define SSTATUS_SD SSTATUS64_SD
#endif
/* hstatus CSR bits */
#define HSTATUS_SPRV 0x00000001
#define HSTATUS_STL 0x00000040
#define HSTATUS_SPV 0x00000080
#define HSTATUS_SP2P 0x00000100
#define HSTATUS_SP2V 0x00000200
#define HSTATUS_VTVM 0x00100000
#define HSTATUS_VTSR 0x00400000
#define HSTATUS32_WPRI 0xFF8FF87E
#define HSTATUS64_WPRI 0xFFFFFFFFFF8FF87EULL
#if defined(TARGET_RISCV32)
#define HSTATUS_WPRI HSTATUS32_WPRI
#elif defined(TARGET_RISCV64)
#define HSTATUS_WPRI HSTATUS64_WPRI
#endif
/* Privilege modes */
#define PRV_U 0
#define PRV_S 1
#define PRV_H 2
#define PRV_H 2 /* Reserved */
#define PRV_M 3
/* RV32 satp CSR field masks */

View file

@ -82,10 +82,31 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
}
}
/* iothread_mutex must be held */
struct CpuAsyncInfo {
uint32_t new_mip;
};
static void riscv_cpu_update_mip_irqs_async(CPUState *target_cpu_state,
run_on_cpu_data data)
{
CPURISCVState *env = &RISCV_CPU(target_cpu_state)->env;
RISCVCPU *cpu = riscv_env_get_cpu(env);
struct CpuAsyncInfo *info = (struct CpuAsyncInfo *) data.host_ptr;
if (info->new_mip) {
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
} else {
cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
}
g_free(info);
}
uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
{
CPURISCVState *env = &cpu->env;
CPUState *cs = CPU(cpu);
struct CpuAsyncInfo *info;
uint32_t old, new, cmp = atomic_read(&env->mip);
do {
@ -94,11 +115,11 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
cmp = atomic_cmpxchg(&env->mip, old, new);
} while (old != cmp);
if (new) {
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
} else {
cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
}
info = g_new(struct CpuAsyncInfo, 1);
info->new_mip = new;
async_run_on_cpu(cs, riscv_cpu_update_mip_irqs_async,
RUN_ON_CPU_HOST_PTR(info));
return old;
}
@ -494,7 +515,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
s = set_field(s, MSTATUS_SPP, env->priv);
s = set_field(s, MSTATUS_SIE, 0);
env->mstatus = s;
env->scause = cause | ~(((target_ulong)-1) >> async);
env->scause = cause | ((target_ulong)async << (TARGET_LONG_BITS - 1));
env->sepc = env->pc;
env->sbadaddr = tval;
env->pc = (env->stvec >> 2 << 2) +

View file

@ -237,6 +237,7 @@ static const target_ulong sstatus_v1_9_mask = SSTATUS_SIE | SSTATUS_SPIE |
static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD;
static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
#if defined(TARGET_RISCV32)
static const char valid_vm_1_09[16] = {
@ -290,7 +291,6 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
{
target_ulong mstatus = env->mstatus;
target_ulong mask = 0;
target_ulong mpp = get_field(val, MSTATUS_MPP);
/* flush tlb on mstatus fields that affect VM */
if (env->priv_ver <= PRIV_VERSION_1_09_1) {
@ -305,7 +305,7 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
MSTATUS_VM : 0);
}
if (env->priv_ver >= PRIV_VERSION_1_10_0) {
if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP |
if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP | MSTATUS_MPV |
MSTATUS_MPRV | MSTATUS_SUM)) {
tlb_flush(CPU(riscv_env_get_cpu(env)));
}
@ -313,13 +313,13 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM |
MSTATUS_MPP | MSTATUS_MXR | MSTATUS_TVM | MSTATUS_TSR |
MSTATUS_TW;
}
/* silenty discard mstatus.mpp writes for unsupported modes */
if (mpp == PRV_H ||
(!riscv_has_ext(env, RVS) && mpp == PRV_S) ||
(!riscv_has_ext(env, RVU) && mpp == PRV_U)) {
mask &= ~MSTATUS_MPP;
#if defined(TARGET_RISCV64)
/*
* RV32: MPV and MTL are not in mstatus. The current plan is to
* add them to mstatush. For now, we just don't support it.
*/
mask |= MSTATUS_MPP | MSTATUS_MPV;
#endif
}
mstatus = (mstatus & ~mask) | (val & mask);
@ -555,9 +555,7 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
uint32_t old_mip;
if (mask) {
qemu_mutex_lock_iothread();
old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
qemu_mutex_unlock_iothread();
} else {
old_mip = atomic_read(&env->mip);
}
@ -685,8 +683,10 @@ static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val)
static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value,
target_ulong new_value, target_ulong write_mask)
{
return rmw_mip(env, CSR_MSTATUS, ret_value, new_value,
write_mask & env->mideleg);
int ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value,
write_mask & env->mideleg & sip_writable_mask);
*ret_value &= env->mideleg;
return ret;
}
/* Supervisor Protection and Translation */
@ -723,7 +723,9 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
return -1;
} else {
tlb_flush(CPU(riscv_env_get_cpu(env)));
if((val ^ env->satp) & SATP_ASID) {
tlb_flush(CPU(riscv_env_get_cpu(env)));
}
env->satp = val;
}
}

View file

@ -0,0 +1,28 @@
#
# RISC-V translation routines for the RVXI Base Integer Instruction Set.
#
# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
# Bastian Koppelmann, kbastian@mail.uni-paderborn.de
#
# This program is free software; you can redistribute it and/or modify it
# under the terms and conditions of the GNU General Public License,
# version 2 or later, as published by the Free Software Foundation.
#
# This program is distributed in the hope it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
# *** RV32C Standard Extension (Quadrant 0) ***
flw 011 ... ... .. ... 00 @cl_w
fsw 111 ... ... .. ... 00 @cs_w
# *** RV32C Standard Extension (Quadrant 1) ***
jal 001 ........... 01 @cj rd=1 # C.JAL
# *** RV32C Standard Extension (Quadrant 2) ***
flw 011 . ..... ..... 10 @c_lwsp
fsw 111 . ..... ..... 10 @c_swsp

View file

@ -0,0 +1,36 @@
#
# RISC-V translation routines for the RVXI Base Integer Instruction Set.
#
# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
# Bastian Koppelmann, kbastian@mail.uni-paderborn.de
#
# This program is free software; you can redistribute it and/or modify it
# under the terms and conditions of the GNU General Public License,
# version 2 or later, as published by the Free Software Foundation.
#
# This program is distributed in the hope it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
# *** RV64C Standard Extension (Quadrant 0) ***
ld 011 ... ... .. ... 00 @cl_d
sd 111 ... ... .. ... 00 @cs_d
# *** RV64C Standard Extension (Quadrant 1) ***
{
illegal 001 - 00000 ----- 01 # c.addiw, RES rd=0
addiw 001 . ..... ..... 01 @ci
}
subw 100 1 11 ... 00 ... 01 @cs_2
addw 100 1 11 ... 01 ... 01 @cs_2
# *** RV64C Standard Extension (Quadrant 2) ***
{
illegal 011 - 00000 ----- 10 # c.ldsp, RES rd=0
ld 011 . ..... ..... 10 @c_ldsp
}
sd 111 . ..... ..... 10 @c_sdsp

View file

@ -30,7 +30,7 @@
%imm_cb 12:s1 5:2 2:1 10:2 3:2 !function=ex_shift_1
%imm_cj 12:s1 8:1 9:2 6:1 7:1 2:1 11:1 3:3 !function=ex_shift_1
%nzuimm_6bit 12:1 2:5
%shimm_6bit 12:1 2:5 !function=ex_rvc_shifti
%uimm_6bit_ld 2:3 12:1 5:2 !function=ex_shift_3
%uimm_6bit_lw 2:2 12:1 4:3 !function=ex_shift_2
%uimm_6bit_sd 7:3 10:3 !function=ex_shift_3
@ -40,90 +40,93 @@
%imm_lui 12:s1 2:5 !function=ex_shift_12
# Argument sets imported from insn32.decode:
&empty !extern
&r rd rs1 rs2 !extern
&i imm rs1 rd !extern
&s imm rs1 rs2 !extern
&j imm rd !extern
&b imm rs2 rs1 !extern
&u imm rd !extern
&shift shamt rs1 rd !extern
# Argument sets:
&cl rs1 rd
&cl_dw uimm rs1 rd
&ci imm rd
&ciw nzuimm rd
&cs rs1 rs2
&cs_dw uimm rs1 rs2
&cb imm rs1
&cr rd rs2
&cj imm
&c_shift shamt rd
&c_ld uimm rd
&c_sd uimm rs2
&caddi16sp_lui imm_lui imm_addi16sp rd
&cflwsp_ldsp uimm_flwsp uimm_ldsp rd
&cfswsp_sdsp uimm_fswsp uimm_sdsp rs2
# Formats 16:
@cr .... ..... ..... .. &cr rs2=%rs2_5 %rd
@ci ... . ..... ..... .. &ci imm=%imm_ci %rd
@ciw ... ........ ... .. &ciw nzuimm=%nzuimm_ciw rd=%rs2_3
@cl_d ... ... ... .. ... .. &cl_dw uimm=%uimm_cl_d rs1=%rs1_3 rd=%rs2_3
@cl_w ... ... ... .. ... .. &cl_dw uimm=%uimm_cl_w rs1=%rs1_3 rd=%rs2_3
@cl ... ... ... .. ... .. &cl rs1=%rs1_3 rd=%rs2_3
@cs ... ... ... .. ... .. &cs rs1=%rs1_3 rs2=%rs2_3
@cs_2 ... ... ... .. ... .. &cr rd=%rs1_3 rs2=%rs2_3
@cs_d ... ... ... .. ... .. &cs_dw uimm=%uimm_cl_d rs1=%rs1_3 rs2=%rs2_3
@cs_w ... ... ... .. ... .. &cs_dw uimm=%uimm_cl_w rs1=%rs1_3 rs2=%rs2_3
@cb ... ... ... .. ... .. &cb imm=%imm_cb rs1=%rs1_3
@cj ... ........... .. &cj imm=%imm_cj
@cr .... ..... ..... .. &r rs2=%rs2_5 rs1=%rd %rd
@ci ... . ..... ..... .. &i imm=%imm_ci rs1=%rd %rd
@cl_d ... ... ... .. ... .. &i imm=%uimm_cl_d rs1=%rs1_3 rd=%rs2_3
@cl_w ... ... ... .. ... .. &i imm=%uimm_cl_w rs1=%rs1_3 rd=%rs2_3
@cs_2 ... ... ... .. ... .. &r rs2=%rs2_3 rs1=%rs1_3 rd=%rs1_3
@cs_d ... ... ... .. ... .. &s imm=%uimm_cl_d rs1=%rs1_3 rs2=%rs2_3
@cs_w ... ... ... .. ... .. &s imm=%uimm_cl_w rs1=%rs1_3 rs2=%rs2_3
@cj ... ........... .. &j imm=%imm_cj
@cb_z ... ... ... .. ... .. &b imm=%imm_cb rs1=%rs1_3 rs2=0
@c_ld ... . ..... ..... .. &c_ld uimm=%uimm_6bit_ld %rd
@c_lw ... . ..... ..... .. &c_ld uimm=%uimm_6bit_lw %rd
@c_sd ... . ..... ..... .. &c_sd uimm=%uimm_6bit_sd rs2=%rs2_5
@c_sw ... . ..... ..... .. &c_sd uimm=%uimm_6bit_sw rs2=%rs2_5
@c_ldsp ... . ..... ..... .. &i imm=%uimm_6bit_ld rs1=2 %rd
@c_lwsp ... . ..... ..... .. &i imm=%uimm_6bit_lw rs1=2 %rd
@c_sdsp ... . ..... ..... .. &s imm=%uimm_6bit_sd rs1=2 rs2=%rs2_5
@c_swsp ... . ..... ..... .. &s imm=%uimm_6bit_sw rs1=2 rs2=%rs2_5
@c_li ... . ..... ..... .. &i imm=%imm_ci rs1=0 %rd
@c_lui ... . ..... ..... .. &u imm=%imm_lui %rd
@c_jalr ... . ..... ..... .. &i imm=0 rs1=%rd
@c_mv ... . ..... ..... .. &i imm=0 rs1=%rs2_5 %rd
@c_addi16sp_lui ... . ..... ..... .. &caddi16sp_lui %imm_lui %imm_addi16sp %rd
@c_flwsp_ldsp ... . ..... ..... .. &cflwsp_ldsp uimm_flwsp=%uimm_6bit_lw \
uimm_ldsp=%uimm_6bit_ld %rd
@c_fswsp_sdsp ... . ..... ..... .. &cfswsp_sdsp uimm_fswsp=%uimm_6bit_sw \
uimm_sdsp=%uimm_6bit_sd rs2=%rs2_5
@c_addi4spn ... . ..... ..... .. &i imm=%nzuimm_ciw rs1=2 rd=%rs2_3
@c_addi16sp ... . ..... ..... .. &i imm=%imm_addi16sp rs1=2 rd=2
@c_shift ... . .. ... ..... .. &c_shift rd=%rs1_3 shamt=%nzuimm_6bit
@c_shift2 ... . .. ... ..... .. &c_shift rd=%rd shamt=%nzuimm_6bit
@c_shift ... . .. ... ..... .. \
&shift rd=%rs1_3 rs1=%rs1_3 shamt=%shimm_6bit
@c_shift2 ... . .. ... ..... .. \
&shift rd=%rd rs1=%rd shamt=%shimm_6bit
@c_andi ... . .. ... ..... .. &ci imm=%imm_ci rd=%rs1_3
@c_andi ... . .. ... ..... .. &i imm=%imm_ci rs1=%rs1_3 rd=%rs1_3
# *** RV64C Standard Extension (Quadrant 0) ***
c_addi4spn 000 ........ ... 00 @ciw
c_fld 001 ... ... .. ... 00 @cl_d
c_lw 010 ... ... .. ... 00 @cl_w
c_flw_ld 011 --- ... -- ... 00 @cl #Note: Must parse uimm manually
c_fsd 101 ... ... .. ... 00 @cs_d
c_sw 110 ... ... .. ... 00 @cs_w
c_fsw_sd 111 --- ... -- ... 00 @cs #Note: Must parse uimm manually
# *** RV32/64C Standard Extension (Quadrant 0) ***
{
# Opcode of all zeros is illegal; rd != 0, nzuimm == 0 is reserved.
illegal 000 000 000 00 --- 00
addi 000 ... ... .. ... 00 @c_addi4spn
}
fld 001 ... ... .. ... 00 @cl_d
lw 010 ... ... .. ... 00 @cl_w
fsd 101 ... ... .. ... 00 @cs_d
sw 110 ... ... .. ... 00 @cs_w
# *** RV64C Standard Extension (Quadrant 1) ***
c_addi 000 . ..... ..... 01 @ci
c_jal_addiw 001 . ..... ..... 01 @ci #Note: parse rd and/or imm manually
c_li 010 . ..... ..... 01 @ci
c_addi16sp_lui 011 . ..... ..... 01 @c_addi16sp_lui # shares opc with C.LUI
c_srli 100 . 00 ... ..... 01 @c_shift
c_srai 100 . 01 ... ..... 01 @c_shift
c_andi 100 . 10 ... ..... 01 @c_andi
c_sub 100 0 11 ... 00 ... 01 @cs_2
c_xor 100 0 11 ... 01 ... 01 @cs_2
c_or 100 0 11 ... 10 ... 01 @cs_2
c_and 100 0 11 ... 11 ... 01 @cs_2
c_subw 100 1 11 ... 00 ... 01 @cs_2
c_addw 100 1 11 ... 01 ... 01 @cs_2
c_j 101 ........... 01 @cj
c_beqz 110 ... ... ..... 01 @cb
c_bnez 111 ... ... ..... 01 @cb
# *** RV32/64C Standard Extension (Quadrant 1) ***
addi 000 . ..... ..... 01 @ci
addi 010 . ..... ..... 01 @c_li
{
illegal 011 0 ----- 00000 01 # c.addi16sp and c.lui, RES nzimm=0
addi 011 . 00010 ..... 01 @c_addi16sp
lui 011 . ..... ..... 01 @c_lui
}
srli 100 . 00 ... ..... 01 @c_shift
srai 100 . 01 ... ..... 01 @c_shift
andi 100 . 10 ... ..... 01 @c_andi
sub 100 0 11 ... 00 ... 01 @cs_2
xor 100 0 11 ... 01 ... 01 @cs_2
or 100 0 11 ... 10 ... 01 @cs_2
and 100 0 11 ... 11 ... 01 @cs_2
jal 101 ........... 01 @cj rd=0 # C.J
beq 110 ... ... ..... 01 @cb_z
bne 111 ... ... ..... 01 @cb_z
# *** RV64C Standard Extension (Quadrant 2) ***
c_slli 000 . ..... ..... 10 @c_shift2
c_fldsp 001 . ..... ..... 10 @c_ld
c_lwsp 010 . ..... ..... 10 @c_lw
c_flwsp_ldsp 011 . ..... ..... 10 @c_flwsp_ldsp #C.LDSP:RV64;C.FLWSP:RV32
c_jr_mv 100 0 ..... ..... 10 @cr
c_ebreak_jalr_add 100 1 ..... ..... 10 @cr
c_fsdsp 101 ...... ..... 10 @c_sd
c_swsp 110 . ..... ..... 10 @c_sw
c_fswsp_sdsp 111 . ..... ..... 10 @c_fswsp_sdsp #C.SDSP:RV64;C.FSWSP:RV32
# *** RV32/64C Standard Extension (Quadrant 2) ***
slli 000 . ..... ..... 10 @c_shift2
fld 001 . ..... ..... 10 @c_ldsp
{
illegal 010 - 00000 ----- 10 # c.lwsp, RES rd=0
lw 010 . ..... ..... 10 @c_lwsp
}
{
illegal 100 0 00000 00000 10 # c.jr, RES rs1=0
jalr 100 0 ..... 00000 10 @c_jalr rd=0 # C.JR
addi 100 0 ..... ..... 10 @c_mv
}
{
ebreak 100 1 00000 00000 10
jalr 100 1 ..... 00000 10 @c_jalr rd=1 # C.JALR
add 100 1 ..... ..... 10 @cr
}
fsd 101 ...... ..... 10 @c_sdsp
sw 110 . ..... ..... 10 @c_swsp

View file

@ -34,9 +34,13 @@
%imm_u 12:s20 !function=ex_shift_12
# Argument sets:
&empty
&b imm rs2 rs1
&i imm rs1 rd
&j imm rd
&r rd rs1 rs2
&s imm rs1 rs2
&u imm rd
&shift shamt rs1 rd
&atomic aq rl rs2 rs1 rd
@ -44,9 +48,9 @@
@r ....... ..... ..... ... ..... ....... &r %rs2 %rs1 %rd
@i ............ ..... ... ..... ....... &i imm=%imm_i %rs1 %rd
@b ....... ..... ..... ... ..... ....... &b imm=%imm_b %rs2 %rs1
@s ....... ..... ..... ... ..... ....... imm=%imm_s %rs2 %rs1
@u .................... ..... ....... imm=%imm_u %rd
@j .................... ..... ....... imm=%imm_j %rd
@s ....... ..... ..... ... ..... ....... &s imm=%imm_s %rs2 %rs1
@u .................... ..... ....... &u imm=%imm_u %rd
@j .................... ..... ....... &j imm=%imm_j %rd
@sh ...... ...... ..... ... ..... ....... &shift shamt=%sh10 %rs1 %rd
@csr ............ ..... ... ..... ....... %csr %rs1 %rd

View file

@ -22,7 +22,7 @@ static bool trans_ecall(DisasContext *ctx, arg_ecall *a)
{
/* always generates U-level ECALL, fixed in do_interrupt handler */
generate_exception(ctx, RISCV_EXCP_U_ECALL);
tcg_gen_exit_tb(NULL, 0); /* no chaining */
exit_tb(ctx); /* no chaining */
ctx->base.is_jmp = DISAS_NORETURN;
return true;
}
@ -30,7 +30,7 @@ static bool trans_ecall(DisasContext *ctx, arg_ecall *a)
static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a)
{
generate_exception(ctx, RISCV_EXCP_BREAKPOINT);
tcg_gen_exit_tb(NULL, 0); /* no chaining */
exit_tb(ctx); /* no chaining */
ctx->base.is_jmp = DISAS_NORETURN;
return true;
}
@ -47,7 +47,7 @@ static bool trans_sret(DisasContext *ctx, arg_sret *a)
if (has_ext(ctx, RVS)) {
gen_helper_sret(cpu_pc, cpu_env, cpu_pc);
tcg_gen_exit_tb(NULL, 0); /* no chaining */
exit_tb(ctx); /* no chaining */
ctx->base.is_jmp = DISAS_NORETURN;
} else {
return false;
@ -68,7 +68,7 @@ static bool trans_mret(DisasContext *ctx, arg_mret *a)
#ifndef CONFIG_USER_ONLY
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
gen_helper_mret(cpu_pc, cpu_env, cpu_pc);
tcg_gen_exit_tb(NULL, 0); /* no chaining */
exit_tb(ctx); /* no chaining */
ctx->base.is_jmp = DISAS_NORETURN;
return true;
#else

View file

@ -1,347 +0,0 @@
/*
* RISC-V translation routines for the RVC Compressed Instruction Set.
*
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
* Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
* Bastian Koppelmann, kbastian@mail.uni-paderborn.de
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
static bool trans_c_addi4spn(DisasContext *ctx, arg_c_addi4spn *a)
{
if (a->nzuimm == 0) {
/* Reserved in ISA */
return false;
}
arg_addi arg = { .rd = a->rd, .rs1 = 2, .imm = a->nzuimm };
return trans_addi(ctx, &arg);
}
static bool trans_c_fld(DisasContext *ctx, arg_c_fld *a)
{
arg_fld arg = { .rd = a->rd, .rs1 = a->rs1, .imm = a->uimm };
return trans_fld(ctx, &arg);
}
static bool trans_c_lw(DisasContext *ctx, arg_c_lw *a)
{
arg_lw arg = { .rd = a->rd, .rs1 = a->rs1, .imm = a->uimm };
return trans_lw(ctx, &arg);
}
static bool trans_c_flw_ld(DisasContext *ctx, arg_c_flw_ld *a)
{
#ifdef TARGET_RISCV32
/* C.FLW ( RV32FC-only ) */
REQUIRE_FPU;
REQUIRE_EXT(ctx, RVF);
arg_c_lw tmp;
decode_insn16_extract_cl_w(ctx, &tmp, ctx->opcode);
arg_flw arg = { .rd = tmp.rd, .rs1 = tmp.rs1, .imm = tmp.uimm };
return trans_flw(ctx, &arg);
#else
/* C.LD ( RV64C/RV128C-only ) */
arg_c_fld tmp;
decode_insn16_extract_cl_d(ctx, &tmp, ctx->opcode);
arg_ld arg = { .rd = tmp.rd, .rs1 = tmp.rs1, .imm = tmp.uimm };
return trans_ld(ctx, &arg);
#endif
}
static bool trans_c_fsd(DisasContext *ctx, arg_c_fsd *a)
{
arg_fsd arg = { .rs1 = a->rs1, .rs2 = a->rs2, .imm = a->uimm };
return trans_fsd(ctx, &arg);
}
static bool trans_c_sw(DisasContext *ctx, arg_c_sw *a)
{
arg_sw arg = { .rs1 = a->rs1, .rs2 = a->rs2, .imm = a->uimm };
return trans_sw(ctx, &arg);
}
static bool trans_c_fsw_sd(DisasContext *ctx, arg_c_fsw_sd *a)
{
#ifdef TARGET_RISCV32
/* C.FSW ( RV32FC-only ) */
REQUIRE_FPU;
REQUIRE_EXT(ctx, RVF);
arg_c_sw tmp;
decode_insn16_extract_cs_w(ctx, &tmp, ctx->opcode);
arg_fsw arg = { .rs1 = tmp.rs1, .rs2 = tmp.rs2, .imm = tmp.uimm };
return trans_fsw(ctx, &arg);
#else
/* C.SD ( RV64C/RV128C-only ) */
arg_c_fsd tmp;
decode_insn16_extract_cs_d(ctx, &tmp, ctx->opcode);
arg_sd arg = { .rs1 = tmp.rs1, .rs2 = tmp.rs2, .imm = tmp.uimm };
return trans_sd(ctx, &arg);
#endif
}
static bool trans_c_addi(DisasContext *ctx, arg_c_addi *a)
{
if (a->imm == 0) {
/* Hint: insn is valid but does not affect state */
return true;
}
arg_addi arg = { .rd = a->rd, .rs1 = a->rd, .imm = a->imm };
return trans_addi(ctx, &arg);
}
static bool trans_c_jal_addiw(DisasContext *ctx, arg_c_jal_addiw *a)
{
#ifdef TARGET_RISCV32
/* C.JAL */
arg_c_j tmp;
decode_insn16_extract_cj(ctx, &tmp, ctx->opcode);
arg_jal arg = { .rd = 1, .imm = tmp.imm };
return trans_jal(ctx, &arg);
#else
/* C.ADDIW */
arg_addiw arg = { .rd = a->rd, .rs1 = a->rd, .imm = a->imm };
return trans_addiw(ctx, &arg);
#endif
}
static bool trans_c_li(DisasContext *ctx, arg_c_li *a)
{
if (a->rd == 0) {
/* Hint: insn is valid but does not affect state */
return true;
}
arg_addi arg = { .rd = a->rd, .rs1 = 0, .imm = a->imm };
return trans_addi(ctx, &arg);
}
static bool trans_c_addi16sp_lui(DisasContext *ctx, arg_c_addi16sp_lui *a)
{
if (a->rd == 2) {
/* C.ADDI16SP */
arg_addi arg = { .rd = 2, .rs1 = 2, .imm = a->imm_addi16sp };
return trans_addi(ctx, &arg);
} else if (a->imm_lui != 0) {
/* C.LUI */
if (a->rd == 0) {
/* Hint: insn is valid but does not affect state */
return true;
}
arg_lui arg = { .rd = a->rd, .imm = a->imm_lui };
return trans_lui(ctx, &arg);
}
return false;
}
static bool trans_c_srli(DisasContext *ctx, arg_c_srli *a)
{
int shamt = a->shamt;
if (shamt == 0) {
/* For RV128 a shamt of 0 means a shift by 64 */
shamt = 64;
}
/* Ensure, that shamt[5] is zero for RV32 */
if (shamt >= TARGET_LONG_BITS) {
return false;
}
arg_srli arg = { .rd = a->rd, .rs1 = a->rd, .shamt = a->shamt };
return trans_srli(ctx, &arg);
}
static bool trans_c_srai(DisasContext *ctx, arg_c_srai *a)
{
int shamt = a->shamt;
if (shamt == 0) {
/* For RV128 a shamt of 0 means a shift by 64 */
shamt = 64;
}
/* Ensure, that shamt[5] is zero for RV32 */
if (shamt >= TARGET_LONG_BITS) {
return false;
}
arg_srai arg = { .rd = a->rd, .rs1 = a->rd, .shamt = a->shamt };
return trans_srai(ctx, &arg);
}
static bool trans_c_andi(DisasContext *ctx, arg_c_andi *a)
{
arg_andi arg = { .rd = a->rd, .rs1 = a->rd, .imm = a->imm };
return trans_andi(ctx, &arg);
}
static bool trans_c_sub(DisasContext *ctx, arg_c_sub *a)
{
arg_sub arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
return trans_sub(ctx, &arg);
}
static bool trans_c_xor(DisasContext *ctx, arg_c_xor *a)
{
arg_xor arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
return trans_xor(ctx, &arg);
}
static bool trans_c_or(DisasContext *ctx, arg_c_or *a)
{
arg_or arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
return trans_or(ctx, &arg);
}
static bool trans_c_and(DisasContext *ctx, arg_c_and *a)
{
arg_and arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
return trans_and(ctx, &arg);
}
static bool trans_c_subw(DisasContext *ctx, arg_c_subw *a)
{
#ifdef TARGET_RISCV64
arg_subw arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
return trans_subw(ctx, &arg);
#else
return false;
#endif
}
static bool trans_c_addw(DisasContext *ctx, arg_c_addw *a)
{
#ifdef TARGET_RISCV64
arg_addw arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
return trans_addw(ctx, &arg);
#else
return false;
#endif
}
static bool trans_c_j(DisasContext *ctx, arg_c_j *a)
{
arg_jal arg = { .rd = 0, .imm = a->imm };
return trans_jal(ctx, &arg);
}
static bool trans_c_beqz(DisasContext *ctx, arg_c_beqz *a)
{
arg_beq arg = { .rs1 = a->rs1, .rs2 = 0, .imm = a->imm };
return trans_beq(ctx, &arg);
}
static bool trans_c_bnez(DisasContext *ctx, arg_c_bnez *a)
{
arg_bne arg = { .rs1 = a->rs1, .rs2 = 0, .imm = a->imm };
return trans_bne(ctx, &arg);
}
static bool trans_c_slli(DisasContext *ctx, arg_c_slli *a)
{
int shamt = a->shamt;
if (shamt == 0) {
/* For RV128 a shamt of 0 means a shift by 64 */
shamt = 64;
}
/* Ensure, that shamt[5] is zero for RV32 */
if (shamt >= TARGET_LONG_BITS) {
return false;
}
arg_slli arg = { .rd = a->rd, .rs1 = a->rd, .shamt = a->shamt };
return trans_slli(ctx, &arg);
}
static bool trans_c_fldsp(DisasContext *ctx, arg_c_fldsp *a)
{
arg_fld arg = { .rd = a->rd, .rs1 = 2, .imm = a->uimm };
return trans_fld(ctx, &arg);
}
static bool trans_c_lwsp(DisasContext *ctx, arg_c_lwsp *a)
{
arg_lw arg = { .rd = a->rd, .rs1 = 2, .imm = a->uimm };
return trans_lw(ctx, &arg);
}
static bool trans_c_flwsp_ldsp(DisasContext *ctx, arg_c_flwsp_ldsp *a)
{
#ifdef TARGET_RISCV32
/* C.FLWSP */
arg_flw arg_flw = { .rd = a->rd, .rs1 = 2, .imm = a->uimm_flwsp };
return trans_flw(ctx, &arg_flw);
#else
/* C.LDSP */
arg_ld arg_ld = { .rd = a->rd, .rs1 = 2, .imm = a->uimm_ldsp };
return trans_ld(ctx, &arg_ld);
#endif
return false;
}
static bool trans_c_jr_mv(DisasContext *ctx, arg_c_jr_mv *a)
{
if (a->rd != 0 && a->rs2 == 0) {
/* C.JR */
arg_jalr arg = { .rd = 0, .rs1 = a->rd, .imm = 0 };
return trans_jalr(ctx, &arg);
} else if (a->rd != 0 && a->rs2 != 0) {
/* C.MV */
arg_add arg = { .rd = a->rd, .rs1 = 0, .rs2 = a->rs2 };
return trans_add(ctx, &arg);
}
return false;
}
static bool trans_c_ebreak_jalr_add(DisasContext *ctx, arg_c_ebreak_jalr_add *a)
{
if (a->rd == 0 && a->rs2 == 0) {
/* C.EBREAK */
arg_ebreak arg = { };
return trans_ebreak(ctx, &arg);
} else if (a->rd != 0) {
if (a->rs2 == 0) {
/* C.JALR */
arg_jalr arg = { .rd = 1, .rs1 = a->rd, .imm = 0 };
return trans_jalr(ctx, &arg);
} else {
/* C.ADD */
arg_add arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
return trans_add(ctx, &arg);
}
}
return false;
}
static bool trans_c_fsdsp(DisasContext *ctx, arg_c_fsdsp *a)
{
arg_fsd arg = { .rs1 = 2, .rs2 = a->rs2, .imm = a->uimm };
return trans_fsd(ctx, &arg);
}
static bool trans_c_swsp(DisasContext *ctx, arg_c_swsp *a)
{
arg_sw arg = { .rs1 = 2, .rs2 = a->rs2, .imm = a->uimm };
return trans_sw(ctx, &arg);
}
static bool trans_c_fswsp_sdsp(DisasContext *ctx, arg_c_fswsp_sdsp *a)
{
#ifdef TARGET_RISCV32
/* C.FSWSP */
arg_fsw a_fsw = { .rs1 = 2, .rs2 = a->rs2, .imm = a->uimm_fswsp };
return trans_fsw(ctx, &a_fsw);
#else
/* C.SDSP */
arg_sd a_sd = { .rs1 = 2, .rs2 = a->rs2, .imm = a->uimm_sdsp };
return trans_sd(ctx, &a_sd);
#endif
}

View file

@ -18,6 +18,12 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
static bool trans_illegal(DisasContext *ctx, arg_empty *a)
{
gen_exception_illegal(ctx);
return true;
}
static bool trans_lui(DisasContext *ctx, arg_lui *a)
{
if (a->rd != 0) {
@ -60,7 +66,7 @@ static bool trans_jalr(DisasContext *ctx, arg_jalr *a)
if (a->rd != 0) {
tcg_gen_movi_tl(cpu_gpr[a->rd], ctx->pc_succ_insn);
}
tcg_gen_lookup_and_goto_ptr();
lookup_and_goto_ptr(ctx);
if (misaligned) {
gen_set_label(misaligned);
@ -217,7 +223,7 @@ static bool trans_sd(DisasContext *ctx, arg_sd *a)
static bool trans_addi(DisasContext *ctx, arg_addi *a)
{
return gen_arith_imm(ctx, a, &tcg_gen_add_tl);
return gen_arith_imm_fn(ctx, a, &tcg_gen_addi_tl);
}
static void gen_slt(TCGv ret, TCGv s1, TCGv s2)
@ -233,25 +239,25 @@ static void gen_sltu(TCGv ret, TCGv s1, TCGv s2)
static bool trans_slti(DisasContext *ctx, arg_slti *a)
{
return gen_arith_imm(ctx, a, &gen_slt);
return gen_arith_imm_tl(ctx, a, &gen_slt);
}
static bool trans_sltiu(DisasContext *ctx, arg_sltiu *a)
{
return gen_arith_imm(ctx, a, &gen_sltu);
return gen_arith_imm_tl(ctx, a, &gen_sltu);
}
static bool trans_xori(DisasContext *ctx, arg_xori *a)
{
return gen_arith_imm(ctx, a, &tcg_gen_xor_tl);
return gen_arith_imm_fn(ctx, a, &tcg_gen_xori_tl);
}
static bool trans_ori(DisasContext *ctx, arg_ori *a)
{
return gen_arith_imm(ctx, a, &tcg_gen_or_tl);
return gen_arith_imm_fn(ctx, a, &tcg_gen_ori_tl);
}
static bool trans_andi(DisasContext *ctx, arg_andi *a)
{
return gen_arith_imm(ctx, a, &tcg_gen_and_tl);
return gen_arith_imm_fn(ctx, a, &tcg_gen_andi_tl);
}
static bool trans_slli(DisasContext *ctx, arg_slli *a)
{
@ -358,7 +364,7 @@ static bool trans_and(DisasContext *ctx, arg_and *a)
#ifdef TARGET_RISCV64
static bool trans_addiw(DisasContext *ctx, arg_addiw *a)
{
return gen_arith_imm(ctx, a, &gen_addw);
return gen_arith_imm_tl(ctx, a, &gen_addw);
}
static bool trans_slliw(DisasContext *ctx, arg_slliw *a)
@ -483,7 +489,7 @@ static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a)
* however we need to end the translation block
*/
tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
tcg_gen_exit_tb(NULL, 0);
exit_tb(ctx);
ctx->base.is_jmp = DISAS_NORETURN;
return true;
}
@ -504,7 +510,7 @@ static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a)
gen_io_end(); \
gen_set_gpr(a->rd, dest); \
tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); \
tcg_gen_exit_tb(NULL, 0); \
exit_tb(ctx); \
ctx->base.is_jmp = DISAS_NORETURN; \
tcg_temp_free(source1); \
tcg_temp_free(csr_store); \

View file

@ -145,9 +145,10 @@ void helper_tlb_flush(CPURISCVState *env)
{
RISCVCPU *cpu = riscv_env_get_cpu(env);
CPUState *cs = CPU(cpu);
if (env->priv == PRV_S &&
env->priv_ver >= PRIV_VERSION_1_10_0 &&
get_field(env->mstatus, MSTATUS_TVM)) {
if (!(env->priv >= PRV_S) ||
(env->priv == PRV_S &&
env->priv_ver >= PRIV_VERSION_1_10_0 &&
get_field(env->mstatus, MSTATUS_TVM))) {
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
} else {
tlb_flush(cs);

View file

@ -109,6 +109,26 @@ static void gen_exception_debug(void)
tcg_temp_free_i32(helper_tmp);
}
/* Wrapper around tcg_gen_exit_tb that handles single stepping */
static void exit_tb(DisasContext *ctx)
{
if (ctx->base.singlestep_enabled) {
gen_exception_debug();
} else {
tcg_gen_exit_tb(NULL, 0);
}
}
/* Wrapper around tcg_gen_lookup_and_goto_ptr that handles single stepping */
static void lookup_and_goto_ptr(DisasContext *ctx)
{
if (ctx->base.singlestep_enabled) {
gen_exception_debug();
} else {
tcg_gen_lookup_and_goto_ptr();
}
}
static void gen_exception_illegal(DisasContext *ctx)
{
generate_exception(ctx, RISCV_EXCP_ILLEGAL_INST);
@ -138,14 +158,14 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
/* chaining is only allowed when the jump is to the same page */
tcg_gen_goto_tb(n);
tcg_gen_movi_tl(cpu_pc, dest);
/* No need to check for single stepping here as use_goto_tb() will
* return false in case of single stepping.
*/
tcg_gen_exit_tb(ctx->base.tb, n);
} else {
tcg_gen_movi_tl(cpu_pc, dest);
if (ctx->base.singlestep_enabled) {
gen_exception_debug();
} else {
tcg_gen_lookup_and_goto_ptr();
}
lookup_and_goto_ptr(ctx);
}
}
@ -538,12 +558,32 @@ static int ex_rvc_register(DisasContext *ctx, int reg)
return 8 + reg;
}
bool decode_insn32(DisasContext *ctx, uint32_t insn);
static int ex_rvc_shifti(DisasContext *ctx, int imm)
{
/* For RV128 a shamt of 0 means a shift by 64. */
return imm ? imm : 64;
}
/* Include the auto-generated decoder for 32 bit insn */
#include "decode_insn32.inc.c"
static bool gen_arith_imm(DisasContext *ctx, arg_i *a,
void(*func)(TCGv, TCGv, TCGv))
static bool gen_arith_imm_fn(DisasContext *ctx, arg_i *a,
void (*func)(TCGv, TCGv, target_long))
{
TCGv source1;
source1 = tcg_temp_new();
gen_get_gpr(source1, a->rs1);
(*func)(source1, source1, a->imm);
gen_set_gpr(a->rd, source1);
tcg_temp_free(source1);
return true;
}
static bool gen_arith_imm_tl(DisasContext *ctx, arg_i *a,
void (*func)(TCGv, TCGv, TCGv))
{
TCGv source1, source2;
source1 = tcg_temp_new();
@ -667,10 +707,25 @@ static bool gen_shift(DisasContext *ctx, arg_r *a,
#include "insn_trans/trans_rvd.inc.c"
#include "insn_trans/trans_privileged.inc.c"
bool decode_insn16(DisasContext *ctx, uint16_t insn);
/* auto-generated decoder*/
/*
* Auto-generated decoder.
* Note that the 16-bit decoder reuses some of the trans_* functions
* initially declared by the 32-bit decoder, which results in duplicate
* declaration warnings. Suppress them.
*/
#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wredundant-decls"
# ifdef __clang__
# pragma GCC diagnostic ignored "-Wtypedef-redefinition"
# endif
#endif
#include "decode_insn16.inc.c"
#include "insn_trans/trans_rvc.inc.c"
#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
# pragma GCC diagnostic pop
#endif
static void decode_opc(DisasContext *ctx)
{