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"
@ -162,6 +163,88 @@ static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap,
}
}
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)
{
const struct MemmapEntry *memmap = spike_memmap;
@ -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 {
@ -64,7 +67,8 @@ enum {
enum {
SIFIVE_E_UART0_IRQ = 3,
SIFIVE_E_UART1_IRQ = 4
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 */
@ -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 {
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 &&
if (!(env->priv >= PRV_S) ||
(env->priv == PRV_S &&
env->priv_ver >= PRIV_VERSION_1_10_0 &&
get_field(env->mstatus, MSTATUS_TVM)) {
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,11 +558,31 @@ 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,
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;
@ -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)
{