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:
commit
4bade28288
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
388
hw/riscv/sifive_gpio.c
Normal 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)
|
104
hw/riscv/spike.c
104
hw/riscv/spike.c
|
@ -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
7
hw/riscv/trace-events
Normal 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
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
72
include/hw/riscv/sifive_gpio.h
Normal file
72
include/hw/riscv/sifive_gpio.h
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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) +
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
28
target/riscv/insn16-32.decode
Normal file
28
target/riscv/insn16-32.decode
Normal 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
|
36
target/riscv/insn16-64.decode
Normal file
36
target/riscv/insn16-64.decode
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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); \
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue