mirror of https://gitee.com/openkylin/qemu.git
target-arm queue:
* hw/arm: Use TYPE_PL011 to create serial port * target/arm: Set ID_MMFR4.HPDS for aarch64_max_initfn * hw/arm/integratorcp: Map the audio codec controller * GICv2: Correctly implement the limited number of priority bits * target/arm: refactoring of VFP related feature checks and decode * xilinx_zynq: Fix USB port instantiation * acceptance tests for n800, n810, integratorcp * Implement v8.3-RCPC, v8.4-RCPC, v8.3-CCIDX * arm_gic_kvm: Don't assume kernel can provide a GICv2 (provide better error message for user error) -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAl5ZQewZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3k8KEACTvyek0uVQ58fuj4wITjjO 9c9PautseST6o/jylY1SUYma66dm+ID77f3XqwTu4wVAI7zoM+bPUkBiDqe2rgAa gCgNn4eWo9ZWgGfvyUXE4pXAsCBoUZ+tTaaxGdMvHMJTClOZNv7X9AV1pRPcYPAO /PpbmZwYe+as/S19CqqiBl4/k2jM0bw2+vQYdK+cgmL89FrGSpqLrpSm98PVoLBX IwrlkG/QHjZbMuAas0LEueIIig0zZrObzGzwHbnLpYn4jWwpkPRGvT/zdRMcCr2u HU1nBfMh6M1Q0HkLlQ70qzRiq/IC2Tk2jR7eneWraY5yZIhh7dFwAhR5rUcEtskG loJn68N8IUHrkZ4xEYsXeAQtlerrlCrpaLzA2nwAe7b7wUsRqhjSC5yulWmecz0D V1p9fCXP7TlHlEsQcxU4Di/D57zEjHuhshHjHbt33yIevC/+oh8ObWLRKQ1tnIsC R6YEBEQ2Ti0PjNsN7C0KMLh1fgweBRpPYesmsULDqB0Fg78AM9JNmX0Z58lQ10f0 VO5RTrygRshp2PpY6imSvfdz1cDw2jyOCtKHyi7kV7qxFbnnS6aLQHwHAFhyyxK4 +2x9Ax0TTNK5wvEQCHajJS+THO1y8LTvfg9d5hiQ1ZmNww1M5g/2ToRhvsdg6MN0 2HVcAPNIktk2dsHL63y4mg== =OqHC -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20200228' into staging target-arm queue: * hw/arm: Use TYPE_PL011 to create serial port * target/arm: Set ID_MMFR4.HPDS for aarch64_max_initfn * hw/arm/integratorcp: Map the audio codec controller * GICv2: Correctly implement the limited number of priority bits * target/arm: refactoring of VFP related feature checks and decode * xilinx_zynq: Fix USB port instantiation * acceptance tests for n800, n810, integratorcp * Implement v8.3-RCPC, v8.4-RCPC, v8.3-CCIDX * arm_gic_kvm: Don't assume kernel can provide a GICv2 (provide better error message for user error) # gpg: Signature made Fri 28 Feb 2020 16:38:04 GMT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20200228: (33 commits) hw/intc/arm_gic_kvm: Don't assume kernel can provide a GICv2 target/arm: Implement ARMv8.3-CCIDX target/arm: Implement v8.4-RCPC target/arm: Implement v8.3-RCPC target/arm: Fix wrong use of FIELD_EX32 on ID_AA64DFR0 tests/acceptance/integratorcp: Verify Tux is displayed on framebuffer tests/acceptance: Extract boot_integratorcp() from test_integratorcp() tests/acceptance: Add a test for the integratorcp arm machine tests/acceptance: Add a test for the N800 and N810 arm machines hw/usb/hcd-ehci-sysbus: Remove obsolete xlnx, ps7-usb class hw/arm/xilinx_zynq: Fix USB port instantiation target/arm: Split VMINMAXNM decode target/arm: Split VFM decode target/arm: Add formats for some vfp 2 and 3-register insns target/arm: Remove ARM_FEATURE_VFP* linux-user/arm: Replace ARM_FEATURE_VFP* tests for HWCAP target/arm: Move the vfp decodetree calls next to the base isa target/arm: Move VLLDM and VLSTM to vfp.decode target/arm: Remove ARM_FEATURE_VFP check from disas_vfp_insn target/arm: Replace ARM_FEATURE_VFP4 with isar_feature_aa32_simdfmac ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
e0175b7163
|
@ -613,6 +613,7 @@ S: Maintained
|
||||||
F: hw/arm/integratorcp.c
|
F: hw/arm/integratorcp.c
|
||||||
F: hw/misc/arm_integrator_debug.c
|
F: hw/misc/arm_integrator_debug.c
|
||||||
F: include/hw/misc/arm_integrator_debug.h
|
F: include/hw/misc/arm_integrator_debug.h
|
||||||
|
F: tests/acceptance/machine_arm_integratorcp.py
|
||||||
|
|
||||||
MCIMX6UL EVK / i.MX6ul
|
MCIMX6UL EVK / i.MX6ul
|
||||||
M: Peter Maydell <peter.maydell@linaro.org>
|
M: Peter Maydell <peter.maydell@linaro.org>
|
||||||
|
@ -686,6 +687,7 @@ F: hw/rtc/twl92230.c
|
||||||
F: include/hw/display/blizzard.h
|
F: include/hw/display/blizzard.h
|
||||||
F: include/hw/input/tsc2xxx.h
|
F: include/hw/input/tsc2xxx.h
|
||||||
F: include/hw/misc/cbus.h
|
F: include/hw/misc/cbus.h
|
||||||
|
F: tests/acceptance/machine_arm_n8x0.py
|
||||||
|
|
||||||
Palm
|
Palm
|
||||||
M: Andrzej Zaborowski <balrogg@gmail.com>
|
M: Andrzej Zaborowski <balrogg@gmail.com>
|
||||||
|
|
|
@ -69,6 +69,7 @@ config INTEGRATOR
|
||||||
select INTEGRATOR_DEBUG
|
select INTEGRATOR_DEBUG
|
||||||
select PL011 # UART
|
select PL011 # UART
|
||||||
select PL031 # RTC
|
select PL031 # RTC
|
||||||
|
select PL041 # audio
|
||||||
select PL050 # keyboard/mouse
|
select PL050 # keyboard/mouse
|
||||||
select PL110 # pl111 LCD controller
|
select PL110 # pl111 LCD controller
|
||||||
select PL181 # display
|
select PL181 # display
|
||||||
|
|
|
@ -642,6 +642,7 @@ static void integratorcp_init(MachineState *machine)
|
||||||
qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_WPROT, 0));
|
qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_WPROT, 0));
|
||||||
qdev_connect_gpio_out(dev, 1,
|
qdev_connect_gpio_out(dev, 1,
|
||||||
qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_CARDIN, 0));
|
qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_CARDIN, 0));
|
||||||
|
sysbus_create_varargs("pl041", 0x1d000000, pic[25], NULL);
|
||||||
|
|
||||||
if (nd_table[0].used)
|
if (nd_table[0].used)
|
||||||
smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
|
smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "hw/pci-host/gpex.h"
|
#include "hw/pci-host/gpex.h"
|
||||||
#include "hw/qdev-properties.h"
|
#include "hw/qdev-properties.h"
|
||||||
#include "hw/usb.h"
|
#include "hw/usb.h"
|
||||||
|
#include "hw/char/pl011.h"
|
||||||
#include "net/net.h"
|
#include "net/net.h"
|
||||||
|
|
||||||
#define RAMLIMIT_GB 8192
|
#define RAMLIMIT_GB 8192
|
||||||
|
@ -409,7 +410,7 @@ static void create_uart(const SBSAMachineState *sms, int uart,
|
||||||
{
|
{
|
||||||
hwaddr base = sbsa_ref_memmap[uart].base;
|
hwaddr base = sbsa_ref_memmap[uart].base;
|
||||||
int irq = sbsa_ref_irqmap[uart];
|
int irq = sbsa_ref_irqmap[uart];
|
||||||
DeviceState *dev = qdev_create(NULL, "pl011");
|
DeviceState *dev = qdev_create(NULL, TYPE_PL011);
|
||||||
SysBusDevice *s = SYS_BUS_DEVICE(dev);
|
SysBusDevice *s = SYS_BUS_DEVICE(dev);
|
||||||
|
|
||||||
qdev_prop_set_chr(dev, "chardev", chr);
|
qdev_prop_set_chr(dev, "chardev", chr);
|
||||||
|
|
|
@ -74,6 +74,7 @@
|
||||||
#include "hw/mem/nvdimm.h"
|
#include "hw/mem/nvdimm.h"
|
||||||
#include "hw/acpi/generic_event_device.h"
|
#include "hw/acpi/generic_event_device.h"
|
||||||
#include "hw/virtio/virtio-iommu.h"
|
#include "hw/virtio/virtio-iommu.h"
|
||||||
|
#include "hw/char/pl011.h"
|
||||||
|
|
||||||
#define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \
|
#define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \
|
||||||
static void virt_##major##_##minor##_class_init(ObjectClass *oc, \
|
static void virt_##major##_##minor##_class_init(ObjectClass *oc, \
|
||||||
|
@ -727,7 +728,7 @@ static void create_uart(const VirtMachineState *vms, int uart,
|
||||||
int irq = vms->irqmap[uart];
|
int irq = vms->irqmap[uart];
|
||||||
const char compat[] = "arm,pl011\0arm,primecell";
|
const char compat[] = "arm,pl011\0arm,primecell";
|
||||||
const char clocknames[] = "uartclk\0apb_pclk";
|
const char clocknames[] = "uartclk\0apb_pclk";
|
||||||
DeviceState *dev = qdev_create(NULL, "pl011");
|
DeviceState *dev = qdev_create(NULL, TYPE_PL011);
|
||||||
SysBusDevice *s = SYS_BUS_DEVICE(dev);
|
SysBusDevice *s = SYS_BUS_DEVICE(dev);
|
||||||
|
|
||||||
qdev_prop_set_chr(dev, "chardev", chr);
|
qdev_prop_set_chr(dev, "chardev", chr);
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "hw/loader.h"
|
#include "hw/loader.h"
|
||||||
#include "hw/misc/zynq-xadc.h"
|
#include "hw/misc/zynq-xadc.h"
|
||||||
#include "hw/ssi/ssi.h"
|
#include "hw/ssi/ssi.h"
|
||||||
|
#include "hw/usb/chipidea.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "hw/sd/sdhci.h"
|
#include "hw/sd/sdhci.h"
|
||||||
#include "hw/char/cadence_uart.h"
|
#include "hw/char/cadence_uart.h"
|
||||||
|
@ -225,8 +226,8 @@ static void zynq_init(MachineState *machine)
|
||||||
zynq_init_spi_flashes(0xE0007000, pic[81-IRQ_OFFSET], false);
|
zynq_init_spi_flashes(0xE0007000, pic[81-IRQ_OFFSET], false);
|
||||||
zynq_init_spi_flashes(0xE000D000, pic[51-IRQ_OFFSET], true);
|
zynq_init_spi_flashes(0xE000D000, pic[51-IRQ_OFFSET], true);
|
||||||
|
|
||||||
sysbus_create_simple("xlnx,ps7-usb", 0xE0002000, pic[53-IRQ_OFFSET]);
|
sysbus_create_simple(TYPE_CHIPIDEA, 0xE0002000, pic[53 - IRQ_OFFSET]);
|
||||||
sysbus_create_simple("xlnx,ps7-usb", 0xE0003000, pic[76-IRQ_OFFSET]);
|
sysbus_create_simple(TYPE_CHIPIDEA, 0xE0003000, pic[76 - IRQ_OFFSET]);
|
||||||
|
|
||||||
cadence_uart_create(0xE0000000, pic[59 - IRQ_OFFSET], serial_hd(0));
|
cadence_uart_create(0xE0000000, pic[59 - IRQ_OFFSET], serial_hd(0));
|
||||||
cadence_uart_create(0xE0001000, pic[82 - IRQ_OFFSET], serial_hd(1));
|
cadence_uart_create(0xE0001000, pic[82 - IRQ_OFFSET], serial_hd(1));
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "hw/misc/unimp.h"
|
#include "hw/misc/unimp.h"
|
||||||
#include "hw/intc/arm_gicv3_common.h"
|
#include "hw/intc/arm_gicv3_common.h"
|
||||||
#include "hw/arm/xlnx-versal.h"
|
#include "hw/arm/xlnx-versal.h"
|
||||||
|
#include "hw/char/pl011.h"
|
||||||
|
|
||||||
#define XLNX_VERSAL_ACPU_TYPE ARM_CPU_TYPE_NAME("cortex-a72")
|
#define XLNX_VERSAL_ACPU_TYPE ARM_CPU_TYPE_NAME("cortex-a72")
|
||||||
#define GEM_REVISION 0x40070106
|
#define GEM_REVISION 0x40070106
|
||||||
|
@ -144,7 +145,7 @@ static void versal_create_uarts(Versal *s, qemu_irq *pic)
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
MemoryRegion *mr;
|
MemoryRegion *mr;
|
||||||
|
|
||||||
dev = qdev_create(NULL, "pl011");
|
dev = qdev_create(NULL, TYPE_PL011);
|
||||||
s->lpd.iou.uart[i] = SYS_BUS_DEVICE(dev);
|
s->lpd.iou.uart[i] = SYS_BUS_DEVICE(dev);
|
||||||
qdev_prop_set_chr(dev, "chardev", serial_hd(i));
|
qdev_prop_set_chr(dev, "chardev", serial_hd(i));
|
||||||
object_property_add_child(OBJECT(s), name, OBJECT(dev), &error_fatal);
|
object_property_add_child(OBJECT(s), name, OBJECT(dev), &error_fatal);
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
#include "hw/qdev-properties.h"
|
#include "hw/qdev-properties.h"
|
||||||
#include "hw/core/cpu.h"
|
#include "hw/core/cpu.h"
|
||||||
|
|
||||||
|
#define A9_GIC_NUM_PRIORITY_BITS 5
|
||||||
|
|
||||||
static void a9mp_priv_set_irq(void *opaque, int irq, int level)
|
static void a9mp_priv_set_irq(void *opaque, int irq, int level)
|
||||||
{
|
{
|
||||||
A9MPPrivState *s = (A9MPPrivState *)opaque;
|
A9MPPrivState *s = (A9MPPrivState *)opaque;
|
||||||
|
@ -68,6 +70,8 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp)
|
||||||
gicdev = DEVICE(&s->gic);
|
gicdev = DEVICE(&s->gic);
|
||||||
qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu);
|
qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu);
|
||||||
qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq);
|
qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq);
|
||||||
|
qdev_prop_set_uint32(gicdev, "num-priority-bits",
|
||||||
|
A9_GIC_NUM_PRIORITY_BITS);
|
||||||
|
|
||||||
/* Make the GIC's TZ support match the CPUs. We assume that
|
/* Make the GIC's TZ support match the CPUs. We assume that
|
||||||
* either all the CPUs have TZ, or none do.
|
* either all the CPUs have TZ, or none do.
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "hw/irq.h"
|
#include "hw/irq.h"
|
||||||
#include "hw/qdev-properties.h"
|
#include "hw/qdev-properties.h"
|
||||||
|
|
||||||
|
#define ARM11MPCORE_NUM_GIC_PRIORITY_BITS 4
|
||||||
|
|
||||||
static void mpcore_priv_set_irq(void *opaque, int irq, int level)
|
static void mpcore_priv_set_irq(void *opaque, int irq, int level)
|
||||||
{
|
{
|
||||||
|
@ -86,6 +87,10 @@ static void mpcore_priv_realize(DeviceState *dev, Error **errp)
|
||||||
|
|
||||||
qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu);
|
qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu);
|
||||||
qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq);
|
qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq);
|
||||||
|
qdev_prop_set_uint32(gicdev, "num-priority-bits",
|
||||||
|
ARM11MPCORE_NUM_GIC_PRIORITY_BITS);
|
||||||
|
|
||||||
|
|
||||||
object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
|
object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
|
||||||
if (err != NULL) {
|
if (err != NULL) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
|
|
|
@ -641,6 +641,23 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t gic_fullprio_mask(GICState *s, int cpu)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Return a mask word which clears the unimplemented priority
|
||||||
|
* bits from a priority value for an interrupt. (Not to be
|
||||||
|
* confused with the group priority, whose mask depends on BPR.)
|
||||||
|
*/
|
||||||
|
int priBits;
|
||||||
|
|
||||||
|
if (gic_is_vcpu(cpu)) {
|
||||||
|
priBits = GIC_VIRT_MAX_GROUP_PRIO_BITS;
|
||||||
|
} else {
|
||||||
|
priBits = s->n_prio_bits;
|
||||||
|
}
|
||||||
|
return ~0U << (8 - priBits);
|
||||||
|
}
|
||||||
|
|
||||||
void gic_dist_set_priority(GICState *s, int cpu, int irq, uint8_t val,
|
void gic_dist_set_priority(GICState *s, int cpu, int irq, uint8_t val,
|
||||||
MemTxAttrs attrs)
|
MemTxAttrs attrs)
|
||||||
{
|
{
|
||||||
|
@ -651,6 +668,8 @@ void gic_dist_set_priority(GICState *s, int cpu, int irq, uint8_t val,
|
||||||
val = 0x80 | (val >> 1); /* Non-secure view */
|
val = 0x80 | (val >> 1); /* Non-secure view */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val &= gic_fullprio_mask(s, cpu);
|
||||||
|
|
||||||
if (irq < GIC_INTERNAL) {
|
if (irq < GIC_INTERNAL) {
|
||||||
s->priority1[irq][cpu] = val;
|
s->priority1[irq][cpu] = val;
|
||||||
} else {
|
} else {
|
||||||
|
@ -669,7 +688,7 @@ static uint32_t gic_dist_get_priority(GICState *s, int cpu, int irq,
|
||||||
}
|
}
|
||||||
prio = (prio << 1) & 0xff; /* Non-secure view */
|
prio = (prio << 1) & 0xff; /* Non-secure view */
|
||||||
}
|
}
|
||||||
return prio;
|
return prio & gic_fullprio_mask(s, cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gic_set_priority_mask(GICState *s, int cpu, uint8_t pmask,
|
static void gic_set_priority_mask(GICState *s, int cpu, uint8_t pmask,
|
||||||
|
@ -684,7 +703,7 @@ static void gic_set_priority_mask(GICState *s, int cpu, uint8_t pmask,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s->priority_mask[cpu] = pmask;
|
s->priority_mask[cpu] = pmask & gic_fullprio_mask(s, cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t gic_get_priority_mask(GICState *s, int cpu, MemTxAttrs attrs)
|
static uint32_t gic_get_priority_mask(GICState *s, int cpu, MemTxAttrs attrs)
|
||||||
|
@ -2055,6 +2074,16 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (s->n_prio_bits > GIC_MAX_PRIORITY_BITS ||
|
||||||
|
(s->virt_extn ? s->n_prio_bits < GIC_VIRT_MAX_GROUP_PRIO_BITS :
|
||||||
|
s->n_prio_bits < GIC_MIN_PRIORITY_BITS)) {
|
||||||
|
error_setg(errp, "num-priority-bits cannot be greater than %d"
|
||||||
|
" or less than %d", GIC_MAX_PRIORITY_BITS,
|
||||||
|
s->virt_extn ? GIC_VIRT_MAX_GROUP_PRIO_BITS :
|
||||||
|
GIC_MIN_PRIORITY_BITS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* This creates distributor, main CPU interface (s->cpuiomem[0]) and if
|
/* This creates distributor, main CPU interface (s->cpuiomem[0]) and if
|
||||||
* enabled, virtualization extensions related interfaces (main virtual
|
* enabled, virtualization extensions related interfaces (main virtual
|
||||||
* interface (s->vifaceiomem[0]) and virtual CPU interface).
|
* interface (s->vifaceiomem[0]) and virtual CPU interface).
|
||||||
|
|
|
@ -357,6 +357,7 @@ static Property arm_gic_common_properties[] = {
|
||||||
DEFINE_PROP_BOOL("has-security-extensions", GICState, security_extn, 0),
|
DEFINE_PROP_BOOL("has-security-extensions", GICState, security_extn, 0),
|
||||||
/* True if the GIC should implement the virtualization extensions */
|
/* True if the GIC should implement the virtualization extensions */
|
||||||
DEFINE_PROP_BOOL("has-virtualization-extensions", GICState, virt_extn, 0),
|
DEFINE_PROP_BOOL("has-virtualization-extensions", GICState, virt_extn, 0),
|
||||||
|
DEFINE_PROP_UINT32("num-priority-bits", GICState, n_prio_bits, 8),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -551,7 +551,16 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
||||||
KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true,
|
KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true,
|
||||||
&error_abort);
|
&error_abort);
|
||||||
}
|
}
|
||||||
|
} else if (kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
|
||||||
|
error_setg_errno(errp, -ret, "error creating in-kernel VGIC");
|
||||||
|
error_append_hint(errp,
|
||||||
|
"Perhaps the host CPU does not support GICv2?\n");
|
||||||
} else if (ret != -ENODEV && ret != -ENOTSUP) {
|
} else if (ret != -ENODEV && ret != -ENOTSUP) {
|
||||||
|
/*
|
||||||
|
* Very ancient kernel without KVM_CAP_DEVICE_CTRL: assume that
|
||||||
|
* ENODEV or ENOTSUP mean "can't create GICv2 with KVM_CREATE_DEVICE",
|
||||||
|
* and that we will get a GICv2 via KVM_CREATE_IRQCHIP.
|
||||||
|
*/
|
||||||
error_setg_errno(errp, -ret, "error creating in-kernel VGIC");
|
error_setg_errno(errp, -ret, "error creating in-kernel VGIC");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1262,12 +1262,12 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
|
||||||
case 0xd84: /* CSSELR */
|
case 0xd84: /* CSSELR */
|
||||||
return cpu->env.v7m.csselr[attrs.secure];
|
return cpu->env.v7m.csselr[attrs.secure];
|
||||||
case 0xd88: /* CPACR */
|
case 0xd88: /* CPACR */
|
||||||
if (!arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
|
if (!cpu_isar_feature(aa32_vfp_simd, cpu)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return cpu->env.v7m.cpacr[attrs.secure];
|
return cpu->env.v7m.cpacr[attrs.secure];
|
||||||
case 0xd8c: /* NSACR */
|
case 0xd8c: /* NSACR */
|
||||||
if (!attrs.secure || !arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
|
if (!attrs.secure || !cpu_isar_feature(aa32_vfp_simd, cpu)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return cpu->env.v7m.nsacr;
|
return cpu->env.v7m.nsacr;
|
||||||
|
@ -1417,7 +1417,7 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
|
||||||
}
|
}
|
||||||
return cpu->env.v7m.sfar;
|
return cpu->env.v7m.sfar;
|
||||||
case 0xf34: /* FPCCR */
|
case 0xf34: /* FPCCR */
|
||||||
if (!arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
|
if (!cpu_isar_feature(aa32_vfp_simd, cpu)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (attrs.secure) {
|
if (attrs.secure) {
|
||||||
|
@ -1444,12 +1444,12 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
case 0xf38: /* FPCAR */
|
case 0xf38: /* FPCAR */
|
||||||
if (!arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
|
if (!cpu_isar_feature(aa32_vfp_simd, cpu)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return cpu->env.v7m.fpcar[attrs.secure];
|
return cpu->env.v7m.fpcar[attrs.secure];
|
||||||
case 0xf3c: /* FPDSCR */
|
case 0xf3c: /* FPDSCR */
|
||||||
if (!arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
|
if (!cpu_isar_feature(aa32_vfp_simd, cpu)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return cpu->env.v7m.fpdscr[attrs.secure];
|
return cpu->env.v7m.fpdscr[attrs.secure];
|
||||||
|
@ -1711,13 +1711,13 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0xd88: /* CPACR */
|
case 0xd88: /* CPACR */
|
||||||
if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
|
if (cpu_isar_feature(aa32_vfp_simd, cpu)) {
|
||||||
/* We implement only the Floating Point extension's CP10/CP11 */
|
/* We implement only the Floating Point extension's CP10/CP11 */
|
||||||
cpu->env.v7m.cpacr[attrs.secure] = value & (0xf << 20);
|
cpu->env.v7m.cpacr[attrs.secure] = value & (0xf << 20);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0xd8c: /* NSACR */
|
case 0xd8c: /* NSACR */
|
||||||
if (attrs.secure && arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
|
if (attrs.secure && cpu_isar_feature(aa32_vfp_simd, cpu)) {
|
||||||
/* We implement only the Floating Point extension's CP10/CP11 */
|
/* We implement only the Floating Point extension's CP10/CP11 */
|
||||||
cpu->env.v7m.nsacr = value & (3 << 10);
|
cpu->env.v7m.nsacr = value & (3 << 10);
|
||||||
}
|
}
|
||||||
|
@ -1951,7 +1951,7 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0xf34: /* FPCCR */
|
case 0xf34: /* FPCCR */
|
||||||
if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
|
if (cpu_isar_feature(aa32_vfp_simd, cpu)) {
|
||||||
/* Not all bits here are banked. */
|
/* Not all bits here are banked. */
|
||||||
uint32_t fpccr_s;
|
uint32_t fpccr_s;
|
||||||
|
|
||||||
|
@ -2005,13 +2005,13 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0xf38: /* FPCAR */
|
case 0xf38: /* FPCAR */
|
||||||
if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
|
if (cpu_isar_feature(aa32_vfp_simd, cpu)) {
|
||||||
value &= ~7;
|
value &= ~7;
|
||||||
cpu->env.v7m.fpcar[attrs.secure] = value;
|
cpu->env.v7m.fpcar[attrs.secure] = value;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0xf3c: /* FPDSCR */
|
case 0xf3c: /* FPDSCR */
|
||||||
if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
|
if (cpu_isar_feature(aa32_vfp_simd, cpu)) {
|
||||||
value &= 0x07c00000;
|
value &= 0x07c00000;
|
||||||
cpu->env.v7m.fpdscr[attrs.secure] = value;
|
cpu->env.v7m.fpdscr[attrs.secure] = value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,22 +115,6 @@ static const TypeInfo ehci_platform_type_info = {
|
||||||
.class_init = ehci_platform_class_init,
|
.class_init = ehci_platform_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ehci_xlnx_class_init(ObjectClass *oc, void *data)
|
|
||||||
{
|
|
||||||
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
|
|
||||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
|
||||||
|
|
||||||
set_bit(DEVICE_CATEGORY_USB, dc->categories);
|
|
||||||
sec->capsbase = 0x100;
|
|
||||||
sec->opregbase = 0x140;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const TypeInfo ehci_xlnx_type_info = {
|
|
||||||
.name = "xlnx,ps7-usb",
|
|
||||||
.parent = TYPE_SYS_BUS_EHCI,
|
|
||||||
.class_init = ehci_xlnx_class_init,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void ehci_exynos4210_class_init(ObjectClass *oc, void *data)
|
static void ehci_exynos4210_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
|
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
|
||||||
|
@ -267,7 +251,6 @@ static void ehci_sysbus_register_types(void)
|
||||||
{
|
{
|
||||||
type_register_static(&ehci_type_info);
|
type_register_static(&ehci_type_info);
|
||||||
type_register_static(&ehci_platform_type_info);
|
type_register_static(&ehci_platform_type_info);
|
||||||
type_register_static(&ehci_xlnx_type_info);
|
|
||||||
type_register_static(&ehci_exynos4210_type_info);
|
type_register_static(&ehci_exynos4210_type_info);
|
||||||
type_register_static(&ehci_tegra2_type_info);
|
type_register_static(&ehci_tegra2_type_info);
|
||||||
type_register_static(&ehci_ppc4xx_type_info);
|
type_register_static(&ehci_ppc4xx_type_info);
|
||||||
|
|
|
@ -68,6 +68,8 @@
|
||||||
|
|
||||||
/* Number of SGI target-list bits */
|
/* Number of SGI target-list bits */
|
||||||
#define GIC_TARGETLIST_BITS 8
|
#define GIC_TARGETLIST_BITS 8
|
||||||
|
#define GIC_MAX_PRIORITY_BITS 8
|
||||||
|
#define GIC_MIN_PRIORITY_BITS 4
|
||||||
|
|
||||||
#define TYPE_ARM_GIC "arm_gic"
|
#define TYPE_ARM_GIC "arm_gic"
|
||||||
#define ARM_GIC(obj) \
|
#define ARM_GIC(obj) \
|
||||||
|
|
|
@ -96,6 +96,7 @@ typedef struct GICState {
|
||||||
uint16_t priority_mask[GIC_NCPU_VCPU];
|
uint16_t priority_mask[GIC_NCPU_VCPU];
|
||||||
uint16_t running_priority[GIC_NCPU_VCPU];
|
uint16_t running_priority[GIC_NCPU_VCPU];
|
||||||
uint16_t current_pending[GIC_NCPU_VCPU];
|
uint16_t current_pending[GIC_NCPU_VCPU];
|
||||||
|
uint32_t n_prio_bits;
|
||||||
|
|
||||||
/* If we present the GICv2 without security extensions to a guest,
|
/* If we present the GICv2 without security extensions to a guest,
|
||||||
* the guest can configure the GICC_CTLR to configure group 1 binary point
|
* the guest can configure the GICC_CTLR to configure group 1 binary point
|
||||||
|
|
|
@ -346,7 +346,7 @@ static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
|
||||||
setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
|
setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
|
||||||
/* Save coprocessor signal frame. */
|
/* Save coprocessor signal frame. */
|
||||||
regspace = uc->tuc_regspace;
|
regspace = uc->tuc_regspace;
|
||||||
if (arm_feature(env, ARM_FEATURE_VFP)) {
|
if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) {
|
||||||
regspace = setup_sigframe_v2_vfp(regspace, env);
|
regspace = setup_sigframe_v2_vfp(regspace, env);
|
||||||
}
|
}
|
||||||
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
|
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
|
||||||
|
@ -671,7 +671,7 @@ static int do_sigframe_return_v2(CPUARMState *env,
|
||||||
|
|
||||||
/* Restore coprocessor signal frame */
|
/* Restore coprocessor signal frame */
|
||||||
regspace = uc->tuc_regspace;
|
regspace = uc->tuc_regspace;
|
||||||
if (arm_feature(env, ARM_FEATURE_VFP)) {
|
if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) {
|
||||||
regspace = restore_sigframe_v2_vfp(env, regspace);
|
regspace = restore_sigframe_v2_vfp(env, regspace);
|
||||||
if (!regspace) {
|
if (!regspace) {
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -468,22 +468,25 @@ static uint32_t get_elf_hwcap(void)
|
||||||
|
|
||||||
/* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */
|
/* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */
|
||||||
GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP);
|
GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP);
|
||||||
GET_FEATURE(ARM_FEATURE_VFP, ARM_HWCAP_ARM_VFP);
|
|
||||||
GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT);
|
GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT);
|
||||||
GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE);
|
GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE);
|
||||||
GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON);
|
GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON);
|
||||||
GET_FEATURE(ARM_FEATURE_VFP3, ARM_HWCAP_ARM_VFPv3);
|
|
||||||
GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS);
|
GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS);
|
||||||
GET_FEATURE(ARM_FEATURE_VFP4, ARM_HWCAP_ARM_VFPv4);
|
GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE);
|
||||||
GET_FEATURE_ID(aa32_arm_div, ARM_HWCAP_ARM_IDIVA);
|
GET_FEATURE_ID(aa32_arm_div, ARM_HWCAP_ARM_IDIVA);
|
||||||
GET_FEATURE_ID(aa32_thumb_div, ARM_HWCAP_ARM_IDIVT);
|
GET_FEATURE_ID(aa32_thumb_div, ARM_HWCAP_ARM_IDIVT);
|
||||||
/* All QEMU's VFPv3 CPUs have 32 registers, see VFP_DREG in translate.c.
|
GET_FEATURE_ID(aa32_vfp, ARM_HWCAP_ARM_VFP);
|
||||||
* Note that the ARM_HWCAP_ARM_VFPv3D16 bit is always the inverse of
|
|
||||||
* ARM_HWCAP_ARM_VFPD32 (and so always clear for QEMU); it is unrelated
|
if (cpu_isar_feature(aa32_fpsp_v3, cpu) ||
|
||||||
* to our VFP_FP16 feature bit.
|
cpu_isar_feature(aa32_fpdp_v3, cpu)) {
|
||||||
*/
|
hwcaps |= ARM_HWCAP_ARM_VFPv3;
|
||||||
GET_FEATURE(ARM_FEATURE_VFP3, ARM_HWCAP_ARM_VFPD32);
|
if (cpu_isar_feature(aa32_simd_r32, cpu)) {
|
||||||
GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE);
|
hwcaps |= ARM_HWCAP_ARM_VFPD32;
|
||||||
|
} else {
|
||||||
|
hwcaps |= ARM_HWCAP_ARM_VFPv3D16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GET_FEATURE_ID(aa32_simdfmac, ARM_HWCAP_ARM_VFPv4);
|
||||||
|
|
||||||
return hwcaps;
|
return hwcaps;
|
||||||
}
|
}
|
||||||
|
@ -658,6 +661,8 @@ static uint32_t get_elf_hwcap(void)
|
||||||
GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB);
|
GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB);
|
||||||
GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM);
|
GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM);
|
||||||
GET_FEATURE_ID(aa64_dcpop, ARM_HWCAP_A64_DCPOP);
|
GET_FEATURE_ID(aa64_dcpop, ARM_HWCAP_A64_DCPOP);
|
||||||
|
GET_FEATURE_ID(aa64_rcpc_8_3, ARM_HWCAP_A64_LRCPC);
|
||||||
|
GET_FEATURE_ID(aa64_rcpc_8_4, ARM_HWCAP_A64_ILRCPC);
|
||||||
|
|
||||||
return hwcaps;
|
return hwcaps;
|
||||||
}
|
}
|
||||||
|
|
|
@ -363,9 +363,11 @@ int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
|
||||||
int cpuid, void *opaque)
|
int cpuid, void *opaque)
|
||||||
{
|
{
|
||||||
struct arm_note note;
|
struct arm_note note;
|
||||||
CPUARMState *env = &ARM_CPU(cs)->env;
|
ARMCPU *cpu = ARM_CPU(cs);
|
||||||
|
CPUARMState *env = &cpu->env;
|
||||||
DumpState *s = opaque;
|
DumpState *s = opaque;
|
||||||
int ret, i, fpvalid = !!arm_feature(env, ARM_FEATURE_VFP);
|
int ret, i;
|
||||||
|
bool fpvalid = cpu_isar_feature(aa32_vfp_simd, cpu);
|
||||||
|
|
||||||
arm_note_init(¬e, s, "CORE", 5, NT_PRSTATUS, sizeof(note.prstatus));
|
arm_note_init(¬e, s, "CORE", 5, NT_PRSTATUS, sizeof(note.prstatus));
|
||||||
|
|
||||||
|
@ -444,7 +446,6 @@ int cpu_get_dump_info(ArchDumpInfo *info,
|
||||||
ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
|
ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = ARM_CPU(first_cpu);
|
ARMCPU *cpu = ARM_CPU(first_cpu);
|
||||||
CPUARMState *env = &cpu->env;
|
|
||||||
size_t note_size;
|
size_t note_size;
|
||||||
|
|
||||||
if (class == ELFCLASS64) {
|
if (class == ELFCLASS64) {
|
||||||
|
@ -452,12 +453,12 @@ ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
|
||||||
note_size += AARCH64_PRFPREG_NOTE_SIZE;
|
note_size += AARCH64_PRFPREG_NOTE_SIZE;
|
||||||
#ifdef TARGET_AARCH64
|
#ifdef TARGET_AARCH64
|
||||||
if (cpu_isar_feature(aa64_sve, cpu)) {
|
if (cpu_isar_feature(aa64_sve, cpu)) {
|
||||||
note_size += AARCH64_SVE_NOTE_SIZE(env);
|
note_size += AARCH64_SVE_NOTE_SIZE(&cpu->env);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
note_size = ARM_PRSTATUS_NOTE_SIZE;
|
note_size = ARM_PRSTATUS_NOTE_SIZE;
|
||||||
if (arm_feature(env, ARM_FEATURE_VFP)) {
|
if (cpu_isar_feature(aa32_vfp_simd, cpu)) {
|
||||||
note_size += ARM_VFP_NOTE_SIZE;
|
note_size += ARM_VFP_NOTE_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -293,7 +293,7 @@ static void arm_cpu_reset(CPUState *s)
|
||||||
env->v7m.ccr[M_REG_S] |= R_V7M_CCR_UNALIGN_TRP_MASK;
|
env->v7m.ccr[M_REG_S] |= R_V7M_CCR_UNALIGN_TRP_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arm_feature(env, ARM_FEATURE_VFP)) {
|
if (cpu_isar_feature(aa32_vfp_simd, cpu)) {
|
||||||
env->v7m.fpccr[M_REG_NS] = R_V7M_FPCCR_ASPEN_MASK;
|
env->v7m.fpccr[M_REG_NS] = R_V7M_FPCCR_ASPEN_MASK;
|
||||||
env->v7m.fpccr[M_REG_S] = R_V7M_FPCCR_ASPEN_MASK |
|
env->v7m.fpccr[M_REG_S] = R_V7M_FPCCR_ASPEN_MASK |
|
||||||
R_V7M_FPCCR_LSPEN_MASK | R_V7M_FPCCR_S_MASK;
|
R_V7M_FPCCR_LSPEN_MASK | R_V7M_FPCCR_S_MASK;
|
||||||
|
@ -1011,7 +1011,7 @@ static void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
||||||
int numvfpregs = 0;
|
int numvfpregs = 0;
|
||||||
if (cpu_isar_feature(aa32_simd_r32, cpu)) {
|
if (cpu_isar_feature(aa32_simd_r32, cpu)) {
|
||||||
numvfpregs = 32;
|
numvfpregs = 32;
|
||||||
} else if (arm_feature(env, ARM_FEATURE_VFP)) {
|
} else if (cpu_isar_feature(aa32_vfp_simd, cpu)) {
|
||||||
numvfpregs = 16;
|
numvfpregs = 16;
|
||||||
}
|
}
|
||||||
for (i = 0; i < numvfpregs; i++) {
|
for (i = 0; i < numvfpregs; i++) {
|
||||||
|
@ -1208,13 +1208,6 @@ void arm_cpu_post_init(Object *obj)
|
||||||
if (arm_feature(&cpu->env, ARM_FEATURE_M)) {
|
if (arm_feature(&cpu->env, ARM_FEATURE_M)) {
|
||||||
set_feature(&cpu->env, ARM_FEATURE_PMSA);
|
set_feature(&cpu->env, ARM_FEATURE_PMSA);
|
||||||
}
|
}
|
||||||
/* Similarly for the VFP feature bits */
|
|
||||||
if (arm_feature(&cpu->env, ARM_FEATURE_VFP4)) {
|
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP3);
|
|
||||||
}
|
|
||||||
if (arm_feature(&cpu->env, ARM_FEATURE_VFP3)) {
|
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arm_feature(&cpu->env, ARM_FEATURE_CBAR) ||
|
if (arm_feature(&cpu->env, ARM_FEATURE_CBAR) ||
|
||||||
arm_feature(&cpu->env, ARM_FEATURE_CBAR_RO)) {
|
arm_feature(&cpu->env, ARM_FEATURE_CBAR_RO)) {
|
||||||
|
@ -1260,7 +1253,9 @@ void arm_cpu_post_init(Object *obj)
|
||||||
* KVM does not currently allow us to lie to the guest about its
|
* KVM does not currently allow us to lie to the guest about its
|
||||||
* ID/feature registers, so the guest always sees what the host has.
|
* ID/feature registers, so the guest always sees what the host has.
|
||||||
*/
|
*/
|
||||||
if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
|
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)
|
||||||
|
? cpu_isar_feature(aa64_fp_simd, cpu)
|
||||||
|
: cpu_isar_feature(aa32_vfp, cpu)) {
|
||||||
cpu->has_vfp = true;
|
cpu->has_vfp = true;
|
||||||
if (!kvm_enabled()) {
|
if (!kvm_enabled()) {
|
||||||
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_vfp_property);
|
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_vfp_property);
|
||||||
|
@ -1440,10 +1435,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||||
uint64_t t;
|
uint64_t t;
|
||||||
uint32_t u;
|
uint32_t u;
|
||||||
|
|
||||||
unset_feature(env, ARM_FEATURE_VFP);
|
|
||||||
unset_feature(env, ARM_FEATURE_VFP3);
|
|
||||||
unset_feature(env, ARM_FEATURE_VFP4);
|
|
||||||
|
|
||||||
t = cpu->isar.id_aa64isar1;
|
t = cpu->isar.id_aa64isar1;
|
||||||
t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 0);
|
t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 0);
|
||||||
cpu->isar.id_aa64isar1 = t;
|
cpu->isar.id_aa64isar1 = t;
|
||||||
|
@ -1510,7 +1501,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||||
u = FIELD_DP32(u, MVFR1, SIMDINT, 0);
|
u = FIELD_DP32(u, MVFR1, SIMDINT, 0);
|
||||||
u = FIELD_DP32(u, MVFR1, SIMDSP, 0);
|
u = FIELD_DP32(u, MVFR1, SIMDSP, 0);
|
||||||
u = FIELD_DP32(u, MVFR1, SIMDHP, 0);
|
u = FIELD_DP32(u, MVFR1, SIMDHP, 0);
|
||||||
u = FIELD_DP32(u, MVFR1, SIMDFMAC, 0);
|
|
||||||
cpu->isar.mvfr1 = u;
|
cpu->isar.mvfr1 = u;
|
||||||
|
|
||||||
u = cpu->isar.mvfr2;
|
u = cpu->isar.mvfr2;
|
||||||
|
@ -1533,6 +1523,11 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||||
u = cpu->isar.mvfr0;
|
u = cpu->isar.mvfr0;
|
||||||
u = FIELD_DP32(u, MVFR0, SIMDREG, 0);
|
u = FIELD_DP32(u, MVFR0, SIMDREG, 0);
|
||||||
cpu->isar.mvfr0 = u;
|
cpu->isar.mvfr0 = u;
|
||||||
|
|
||||||
|
/* Despite the name, this field covers both VFP and Neon */
|
||||||
|
u = cpu->isar.mvfr1;
|
||||||
|
u = FIELD_DP32(u, MVFR1, SIMDFMAC, 0);
|
||||||
|
cpu->isar.mvfr1 = u;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arm_feature(env, ARM_FEATURE_M) && !cpu->has_dsp) {
|
if (arm_feature(env, ARM_FEATURE_M) && !cpu->has_dsp) {
|
||||||
|
@ -1636,8 +1631,9 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||||
* We rely on no XScale CPU having VFP so we can use the same bits in the
|
* We rely on no XScale CPU having VFP so we can use the same bits in the
|
||||||
* TB flags field for VECSTRIDE and XSCALE_CPAR.
|
* TB flags field for VECSTRIDE and XSCALE_CPAR.
|
||||||
*/
|
*/
|
||||||
assert(!(arm_feature(env, ARM_FEATURE_VFP) &&
|
assert(arm_feature(&cpu->env, ARM_FEATURE_AARCH64) ||
|
||||||
arm_feature(env, ARM_FEATURE_XSCALE)));
|
!cpu_isar_feature(aa32_vfp_simd, cpu) ||
|
||||||
|
!arm_feature(env, ARM_FEATURE_XSCALE));
|
||||||
|
|
||||||
if (arm_feature(env, ARM_FEATURE_V7) &&
|
if (arm_feature(env, ARM_FEATURE_V7) &&
|
||||||
!arm_feature(env, ARM_FEATURE_M) &&
|
!arm_feature(env, ARM_FEATURE_M) &&
|
||||||
|
@ -1858,7 +1854,6 @@ static void arm926_initfn(Object *obj)
|
||||||
|
|
||||||
cpu->dtb_compatible = "arm,arm926";
|
cpu->dtb_compatible = "arm,arm926";
|
||||||
set_feature(&cpu->env, ARM_FEATURE_V5);
|
set_feature(&cpu->env, ARM_FEATURE_V5);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP);
|
|
||||||
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
|
set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
|
||||||
cpu->midr = 0x41069265;
|
cpu->midr = 0x41069265;
|
||||||
|
@ -1899,7 +1894,6 @@ static void arm1026_initfn(Object *obj)
|
||||||
|
|
||||||
cpu->dtb_compatible = "arm,arm1026";
|
cpu->dtb_compatible = "arm,arm1026";
|
||||||
set_feature(&cpu->env, ARM_FEATURE_V5);
|
set_feature(&cpu->env, ARM_FEATURE_V5);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP);
|
|
||||||
set_feature(&cpu->env, ARM_FEATURE_AUXCR);
|
set_feature(&cpu->env, ARM_FEATURE_AUXCR);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
|
set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
|
||||||
|
@ -1947,7 +1941,6 @@ static void arm1136_r2_initfn(Object *obj)
|
||||||
|
|
||||||
cpu->dtb_compatible = "arm,arm1136";
|
cpu->dtb_compatible = "arm,arm1136";
|
||||||
set_feature(&cpu->env, ARM_FEATURE_V6);
|
set_feature(&cpu->env, ARM_FEATURE_V6);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP);
|
|
||||||
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG);
|
set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS);
|
set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS);
|
||||||
|
@ -1979,7 +1972,6 @@ static void arm1136_initfn(Object *obj)
|
||||||
cpu->dtb_compatible = "arm,arm1136";
|
cpu->dtb_compatible = "arm,arm1136";
|
||||||
set_feature(&cpu->env, ARM_FEATURE_V6K);
|
set_feature(&cpu->env, ARM_FEATURE_V6K);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_V6);
|
set_feature(&cpu->env, ARM_FEATURE_V6);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP);
|
|
||||||
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG);
|
set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS);
|
set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS);
|
||||||
|
@ -2010,7 +2002,6 @@ static void arm1176_initfn(Object *obj)
|
||||||
|
|
||||||
cpu->dtb_compatible = "arm,arm1176";
|
cpu->dtb_compatible = "arm,arm1176";
|
||||||
set_feature(&cpu->env, ARM_FEATURE_V6K);
|
set_feature(&cpu->env, ARM_FEATURE_V6K);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP);
|
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VAPA);
|
set_feature(&cpu->env, ARM_FEATURE_VAPA);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG);
|
set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG);
|
||||||
|
@ -2043,7 +2034,6 @@ static void arm11mpcore_initfn(Object *obj)
|
||||||
|
|
||||||
cpu->dtb_compatible = "arm,arm11mpcore";
|
cpu->dtb_compatible = "arm,arm11mpcore";
|
||||||
set_feature(&cpu->env, ARM_FEATURE_V6K);
|
set_feature(&cpu->env, ARM_FEATURE_V6K);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP);
|
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VAPA);
|
set_feature(&cpu->env, ARM_FEATURE_VAPA);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_MPIDR);
|
set_feature(&cpu->env, ARM_FEATURE_MPIDR);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
||||||
|
@ -2109,7 +2099,6 @@ static void cortex_m4_initfn(Object *obj)
|
||||||
set_feature(&cpu->env, ARM_FEATURE_M);
|
set_feature(&cpu->env, ARM_FEATURE_M);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
|
set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
|
set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP4);
|
|
||||||
cpu->midr = 0x410fc240; /* r0p0 */
|
cpu->midr = 0x410fc240; /* r0p0 */
|
||||||
cpu->pmsav7_dregion = 8;
|
cpu->pmsav7_dregion = 8;
|
||||||
cpu->isar.mvfr0 = 0x10110021;
|
cpu->isar.mvfr0 = 0x10110021;
|
||||||
|
@ -2140,7 +2129,6 @@ static void cortex_m7_initfn(Object *obj)
|
||||||
set_feature(&cpu->env, ARM_FEATURE_M);
|
set_feature(&cpu->env, ARM_FEATURE_M);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
|
set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
|
set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP4);
|
|
||||||
cpu->midr = 0x411fc272; /* r1p2 */
|
cpu->midr = 0x411fc272; /* r1p2 */
|
||||||
cpu->pmsav7_dregion = 8;
|
cpu->pmsav7_dregion = 8;
|
||||||
cpu->isar.mvfr0 = 0x10110221;
|
cpu->isar.mvfr0 = 0x10110221;
|
||||||
|
@ -2172,7 +2160,6 @@ static void cortex_m33_initfn(Object *obj)
|
||||||
set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
|
set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_M_SECURITY);
|
set_feature(&cpu->env, ARM_FEATURE_M_SECURITY);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
|
set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP4);
|
|
||||||
cpu->midr = 0x410fd213; /* r0p3 */
|
cpu->midr = 0x410fd213; /* r0p3 */
|
||||||
cpu->pmsav7_dregion = 16;
|
cpu->pmsav7_dregion = 16;
|
||||||
cpu->sau_sregion = 8;
|
cpu->sau_sregion = 8;
|
||||||
|
@ -2256,7 +2243,6 @@ static void cortex_r5f_initfn(Object *obj)
|
||||||
ARMCPU *cpu = ARM_CPU(obj);
|
ARMCPU *cpu = ARM_CPU(obj);
|
||||||
|
|
||||||
cortex_r5_initfn(obj);
|
cortex_r5_initfn(obj);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP3);
|
|
||||||
cpu->isar.mvfr0 = 0x10110221;
|
cpu->isar.mvfr0 = 0x10110221;
|
||||||
cpu->isar.mvfr1 = 0x00000011;
|
cpu->isar.mvfr1 = 0x00000011;
|
||||||
}
|
}
|
||||||
|
@ -2275,7 +2261,6 @@ static void cortex_a8_initfn(Object *obj)
|
||||||
|
|
||||||
cpu->dtb_compatible = "arm,cortex-a8";
|
cpu->dtb_compatible = "arm,cortex-a8";
|
||||||
set_feature(&cpu->env, ARM_FEATURE_V7);
|
set_feature(&cpu->env, ARM_FEATURE_V7);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP3);
|
|
||||||
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
|
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
||||||
|
@ -2343,7 +2328,6 @@ static void cortex_a9_initfn(Object *obj)
|
||||||
|
|
||||||
cpu->dtb_compatible = "arm,cortex-a9";
|
cpu->dtb_compatible = "arm,cortex-a9";
|
||||||
set_feature(&cpu->env, ARM_FEATURE_V7);
|
set_feature(&cpu->env, ARM_FEATURE_V7);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP3);
|
|
||||||
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
|
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_EL3);
|
set_feature(&cpu->env, ARM_FEATURE_EL3);
|
||||||
|
@ -2408,7 +2392,6 @@ static void cortex_a7_initfn(Object *obj)
|
||||||
|
|
||||||
cpu->dtb_compatible = "arm,cortex-a7";
|
cpu->dtb_compatible = "arm,cortex-a7";
|
||||||
set_feature(&cpu->env, ARM_FEATURE_V7VE);
|
set_feature(&cpu->env, ARM_FEATURE_V7VE);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP4);
|
|
||||||
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
|
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
|
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
|
||||||
|
@ -2454,7 +2437,6 @@ static void cortex_a15_initfn(Object *obj)
|
||||||
|
|
||||||
cpu->dtb_compatible = "arm,cortex-a15";
|
cpu->dtb_compatible = "arm,cortex-a15";
|
||||||
set_feature(&cpu->env, ARM_FEATURE_V7VE);
|
set_feature(&cpu->env, ARM_FEATURE_V7VE);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP4);
|
|
||||||
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
|
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
|
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
|
||||||
|
|
|
@ -904,7 +904,7 @@ struct ARMCPU {
|
||||||
/* The elements of this array are the CCSIDR values for each cache,
|
/* The elements of this array are the CCSIDR values for each cache,
|
||||||
* in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
|
* in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
|
||||||
*/
|
*/
|
||||||
uint32_t ccsidr[16];
|
uint64_t ccsidr[16];
|
||||||
uint64_t reset_cbar;
|
uint64_t reset_cbar;
|
||||||
uint32_t reset_auxcr;
|
uint32_t reset_auxcr;
|
||||||
bool reset_hivecs;
|
bool reset_hivecs;
|
||||||
|
@ -1880,7 +1880,6 @@ QEMU_BUILD_BUG_ON(ARRAY_SIZE(((ARMCPU *)0)->ccsidr) <= R_V7M_CSSELR_INDEX_MASK);
|
||||||
* mapping in linux-user/elfload.c:get_elf_hwcap().
|
* mapping in linux-user/elfload.c:get_elf_hwcap().
|
||||||
*/
|
*/
|
||||||
enum arm_features {
|
enum arm_features {
|
||||||
ARM_FEATURE_VFP,
|
|
||||||
ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */
|
ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */
|
||||||
ARM_FEATURE_XSCALE, /* Intel XScale extensions. */
|
ARM_FEATURE_XSCALE, /* Intel XScale extensions. */
|
||||||
ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension. */
|
ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension. */
|
||||||
|
@ -1889,7 +1888,6 @@ enum arm_features {
|
||||||
ARM_FEATURE_V7,
|
ARM_FEATURE_V7,
|
||||||
ARM_FEATURE_THUMB2,
|
ARM_FEATURE_THUMB2,
|
||||||
ARM_FEATURE_PMSA, /* no MMU; may have Memory Protection Unit */
|
ARM_FEATURE_PMSA, /* no MMU; may have Memory Protection Unit */
|
||||||
ARM_FEATURE_VFP3,
|
|
||||||
ARM_FEATURE_NEON,
|
ARM_FEATURE_NEON,
|
||||||
ARM_FEATURE_M, /* Microcontroller profile. */
|
ARM_FEATURE_M, /* Microcontroller profile. */
|
||||||
ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling. */
|
ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling. */
|
||||||
|
@ -1900,7 +1898,6 @@ enum arm_features {
|
||||||
ARM_FEATURE_V5,
|
ARM_FEATURE_V5,
|
||||||
ARM_FEATURE_STRONGARM,
|
ARM_FEATURE_STRONGARM,
|
||||||
ARM_FEATURE_VAPA, /* cp15 VA to PA lookups */
|
ARM_FEATURE_VAPA, /* cp15 VA to PA lookups */
|
||||||
ARM_FEATURE_VFP4, /* VFPv4 (implies that NEON is v2) */
|
|
||||||
ARM_FEATURE_GENERIC_TIMER,
|
ARM_FEATURE_GENERIC_TIMER,
|
||||||
ARM_FEATURE_MVFR, /* Media and VFP Feature Registers 0 and 1 */
|
ARM_FEATURE_MVFR, /* Media and VFP Feature Registers 0 and 1 */
|
||||||
ARM_FEATURE_DUMMY_C15_REGS, /* RAZ/WI all of cp15 crn=15 */
|
ARM_FEATURE_DUMMY_C15_REGS, /* RAZ/WI all of cp15 crn=15 */
|
||||||
|
@ -3450,6 +3447,15 @@ static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id)
|
||||||
return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) == 1;
|
return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool isar_feature_aa32_vfp_simd(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Return true if either VFP or SIMD is implemented.
|
||||||
|
* In this case, a minimum of VFP w/ D0-D15.
|
||||||
|
*/
|
||||||
|
return FIELD_EX32(id->mvfr0, MVFR0, SIMDREG) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool isar_feature_aa32_simd_r32(const ARMISARegisters *id)
|
static inline bool isar_feature_aa32_simd_r32(const ARMISARegisters *id)
|
||||||
{
|
{
|
||||||
/* Return true if D16-D31 are implemented */
|
/* Return true if D16-D31 are implemented */
|
||||||
|
@ -3461,12 +3467,35 @@ static inline bool isar_feature_aa32_fpshvec(const ARMISARegisters *id)
|
||||||
return FIELD_EX32(id->mvfr0, MVFR0, FPSHVEC) > 0;
|
return FIELD_EX32(id->mvfr0, MVFR0, FPSHVEC) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool isar_feature_aa32_fpdp(const ARMISARegisters *id)
|
static inline bool isar_feature_aa32_fpsp_v2(const ARMISARegisters *id)
|
||||||
{
|
{
|
||||||
/* Return true if CPU supports double precision floating point */
|
/* Return true if CPU supports single precision floating point, VFPv2 */
|
||||||
|
return FIELD_EX32(id->mvfr0, MVFR0, FPSP) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isar_feature_aa32_fpsp_v3(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
/* Return true if CPU supports single precision floating point, VFPv3 */
|
||||||
|
return FIELD_EX32(id->mvfr0, MVFR0, FPSP) >= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isar_feature_aa32_fpdp_v2(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
/* Return true if CPU supports double precision floating point, VFPv2 */
|
||||||
return FIELD_EX32(id->mvfr0, MVFR0, FPDP) > 0;
|
return FIELD_EX32(id->mvfr0, MVFR0, FPDP) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool isar_feature_aa32_fpdp_v3(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
/* Return true if CPU supports double precision floating point, VFPv3 */
|
||||||
|
return FIELD_EX32(id->mvfr0, MVFR0, FPDP) >= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isar_feature_aa32_vfp(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
return isar_feature_aa32_fpsp_v2(id) || isar_feature_aa32_fpdp_v2(id);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We always set the FP and SIMD FP16 fields to indicate identical
|
* We always set the FP and SIMD FP16 fields to indicate identical
|
||||||
* levels of support (assuming SIMD is implemented at all), so
|
* levels of support (assuming SIMD is implemented at all), so
|
||||||
|
@ -3482,6 +3511,18 @@ static inline bool isar_feature_aa32_fp16_dpconv(const ARMISARegisters *id)
|
||||||
return FIELD_EX32(id->mvfr1, MVFR1, FPHP) > 1;
|
return FIELD_EX32(id->mvfr1, MVFR1, FPHP) > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that this ID register field covers both VFP and Neon FMAC,
|
||||||
|
* so should usually be tested in combination with some other
|
||||||
|
* check that confirms the presence of whichever of VFP or Neon is
|
||||||
|
* relevant, to avoid accidentally enabling a Neon feature on
|
||||||
|
* a VFP-no-Neon core or vice-versa.
|
||||||
|
*/
|
||||||
|
static inline bool isar_feature_aa32_simdfmac(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
return FIELD_EX32(id->mvfr1, MVFR1, SIMDFMAC) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool isar_feature_aa32_vsel(const ARMISARegisters *id)
|
static inline bool isar_feature_aa32_vsel(const ARMISARegisters *id)
|
||||||
{
|
{
|
||||||
return FIELD_EX32(id->mvfr2, MVFR2, FPMISC) >= 1;
|
return FIELD_EX32(id->mvfr2, MVFR2, FPMISC) >= 1;
|
||||||
|
@ -3536,6 +3577,11 @@ static inline bool isar_feature_aa32_ac2(const ARMISARegisters *id)
|
||||||
return FIELD_EX32(id->id_mmfr4, ID_MMFR4, AC2) != 0;
|
return FIELD_EX32(id->id_mmfr4, ID_MMFR4, AC2) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool isar_feature_aa32_ccidx(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
return FIELD_EX32(id->id_mmfr4, ID_MMFR4, CCIDX) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 64-bit feature tests via id registers.
|
* 64-bit feature tests via id registers.
|
||||||
*/
|
*/
|
||||||
|
@ -3669,6 +3715,12 @@ static inline bool isar_feature_aa64_dcpodp(const ARMISARegisters *id)
|
||||||
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, DPB) >= 2;
|
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, DPB) >= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool isar_feature_aa64_fp_simd(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
/* We always set the AdvSIMD and FP fields identically. */
|
||||||
|
return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) != 0xf;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool isar_feature_aa64_fp16(const ARMISARegisters *id)
|
static inline bool isar_feature_aa64_fp16(const ARMISARegisters *id)
|
||||||
{
|
{
|
||||||
/* We always set the AdvSIMD and FP fields identically wrt FP16. */
|
/* We always set the AdvSIMD and FP fields identically wrt FP16. */
|
||||||
|
@ -3723,8 +3775,23 @@ static inline bool isar_feature_aa64_pmu_8_1(const ARMISARegisters *id)
|
||||||
|
|
||||||
static inline bool isar_feature_aa64_pmu_8_4(const ARMISARegisters *id)
|
static inline bool isar_feature_aa64_pmu_8_4(const ARMISARegisters *id)
|
||||||
{
|
{
|
||||||
return FIELD_EX32(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 5 &&
|
return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 5 &&
|
||||||
FIELD_EX32(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf;
|
FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isar_feature_aa64_rcpc_8_3(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isar_feature_aa64_rcpc_8_4(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) >= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isar_feature_aa64_ccidx(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, CCIDX) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3750,6 +3817,11 @@ static inline bool isar_feature_any_pmu_8_4(const ARMISARegisters *id)
|
||||||
return isar_feature_aa64_pmu_8_4(id) || isar_feature_aa32_pmu_8_4(id);
|
return isar_feature_aa64_pmu_8_4(id) || isar_feature_aa32_pmu_8_4(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool isar_feature_any_ccidx(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
return isar_feature_aa64_ccidx(id) || isar_feature_aa32_ccidx(id);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Forward to the above feature tests given an ARMCPU pointer.
|
* Forward to the above feature tests given an ARMCPU pointer.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -102,7 +102,6 @@ static void aarch64_a57_initfn(Object *obj)
|
||||||
|
|
||||||
cpu->dtb_compatible = "arm,cortex-a57";
|
cpu->dtb_compatible = "arm,cortex-a57";
|
||||||
set_feature(&cpu->env, ARM_FEATURE_V8);
|
set_feature(&cpu->env, ARM_FEATURE_V8);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP4);
|
|
||||||
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
|
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_AARCH64);
|
set_feature(&cpu->env, ARM_FEATURE_AARCH64);
|
||||||
|
@ -156,7 +155,6 @@ static void aarch64_a53_initfn(Object *obj)
|
||||||
|
|
||||||
cpu->dtb_compatible = "arm,cortex-a53";
|
cpu->dtb_compatible = "arm,cortex-a53";
|
||||||
set_feature(&cpu->env, ARM_FEATURE_V8);
|
set_feature(&cpu->env, ARM_FEATURE_V8);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP4);
|
|
||||||
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
|
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_AARCH64);
|
set_feature(&cpu->env, ARM_FEATURE_AARCH64);
|
||||||
|
@ -210,7 +208,6 @@ static void aarch64_a72_initfn(Object *obj)
|
||||||
|
|
||||||
cpu->dtb_compatible = "arm,cortex-a72";
|
cpu->dtb_compatible = "arm,cortex-a72";
|
||||||
set_feature(&cpu->env, ARM_FEATURE_V8);
|
set_feature(&cpu->env, ARM_FEATURE_V8);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_VFP4);
|
|
||||||
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
|
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_AARCH64);
|
set_feature(&cpu->env, ARM_FEATURE_AARCH64);
|
||||||
|
@ -657,6 +654,7 @@ static void aarch64_max_initfn(Object *obj)
|
||||||
t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1);
|
t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1);
|
||||||
t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1);
|
t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1);
|
||||||
t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1);
|
t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1);
|
||||||
|
t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 2); /* ARMv8.4-RCPC */
|
||||||
cpu->isar.id_aa64isar1 = t;
|
cpu->isar.id_aa64isar1 = t;
|
||||||
|
|
||||||
t = cpu->isar.id_aa64pfr0;
|
t = cpu->isar.id_aa64pfr0;
|
||||||
|
@ -704,6 +702,7 @@ static void aarch64_max_initfn(Object *obj)
|
||||||
cpu->isar.id_mmfr3 = u;
|
cpu->isar.id_mmfr3 = u;
|
||||||
|
|
||||||
u = cpu->isar.id_mmfr4;
|
u = cpu->isar.id_mmfr4;
|
||||||
|
u = FIELD_DP32(u, ID_MMFR4, HPDS, 1); /* AA32HPD */
|
||||||
u = FIELD_DP32(u, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */
|
u = FIELD_DP32(u, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */
|
||||||
cpu->isar.id_mmfr4 = u;
|
cpu->isar.id_mmfr4 = u;
|
||||||
|
|
||||||
|
|
|
@ -894,7 +894,7 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
* ASEDIS [31] and D32DIS [30] are both UNK/SBZP without VFP.
|
* ASEDIS [31] and D32DIS [30] are both UNK/SBZP without VFP.
|
||||||
* TRCDIS [28] is RAZ/WI since we do not implement a trace macrocell.
|
* TRCDIS [28] is RAZ/WI since we do not implement a trace macrocell.
|
||||||
*/
|
*/
|
||||||
if (arm_feature(env, ARM_FEATURE_VFP)) {
|
if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) {
|
||||||
/* VFP coprocessor: cp10 & cp11 [23:20] */
|
/* VFP coprocessor: cp10 & cp11 [23:20] */
|
||||||
mask |= (1 << 31) | (1 << 30) | (0xf << 20);
|
mask |= (1 << 31) | (1 << 30) | (0xf << 20);
|
||||||
|
|
||||||
|
@ -6726,6 +6726,21 @@ static const ARMCPRegInfo predinv_reginfo[] = {
|
||||||
REGINFO_SENTINEL
|
REGINFO_SENTINEL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static uint64_t ccsidr2_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
|
{
|
||||||
|
/* Read the high 32 bits of the current CCSIDR */
|
||||||
|
return extract64(ccsidr_read(env, ri), 32, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const ARMCPRegInfo ccsidr2_reginfo[] = {
|
||||||
|
{ .name = "CCSIDR2", .state = ARM_CP_STATE_BOTH,
|
||||||
|
.opc0 = 3, .opc1 = 1, .crn = 0, .crm = 0, .opc2 = 2,
|
||||||
|
.access = PL1_R,
|
||||||
|
.accessfn = access_aa64_tid2,
|
||||||
|
.readfn = ccsidr2_read, .type = ARM_CP_NO_RAW },
|
||||||
|
REGINFO_SENTINEL
|
||||||
|
};
|
||||||
|
|
||||||
static CPAccessResult access_aa64_tid3(CPUARMState *env, const ARMCPRegInfo *ri,
|
static CPAccessResult access_aa64_tid3(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
bool isread)
|
bool isread)
|
||||||
{
|
{
|
||||||
|
@ -7788,6 +7803,10 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||||
define_arm_cp_regs(cpu, predinv_reginfo);
|
define_arm_cp_regs(cpu, predinv_reginfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cpu_isar_feature(any_ccidx, cpu)) {
|
||||||
|
define_arm_cp_regs(cpu, ccsidr2_reginfo);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
/*
|
/*
|
||||||
* Register redirections and aliases must be done last,
|
* Register redirections and aliases must be done last,
|
||||||
|
@ -7814,7 +7833,7 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
|
||||||
} else if (cpu_isar_feature(aa32_simd_r32, cpu)) {
|
} else if (cpu_isar_feature(aa32_simd_r32, cpu)) {
|
||||||
gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
|
gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
|
||||||
35, "arm-vfp3.xml", 0);
|
35, "arm-vfp3.xml", 0);
|
||||||
} else if (arm_feature(env, ARM_FEATURE_VFP)) {
|
} else if (cpu_isar_feature(aa32_vfp_simd, cpu)) {
|
||||||
gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
|
gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
|
||||||
19, "arm-vfp.xml", 0);
|
19, "arm-vfp.xml", 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,7 +147,6 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
|
||||||
* bits, but a few must be tested.
|
* bits, but a few must be tested.
|
||||||
*/
|
*/
|
||||||
set_feature(&features, ARM_FEATURE_V7VE);
|
set_feature(&features, ARM_FEATURE_V7VE);
|
||||||
set_feature(&features, ARM_FEATURE_VFP3);
|
|
||||||
set_feature(&features, ARM_FEATURE_GENERIC_TIMER);
|
set_feature(&features, ARM_FEATURE_GENERIC_TIMER);
|
||||||
|
|
||||||
if (extract32(id_pfr0, 12, 4) == 1) {
|
if (extract32(id_pfr0, 12, 4) == 1) {
|
||||||
|
@ -156,10 +155,6 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
|
||||||
if (extract32(ahcf->isar.mvfr1, 12, 4) == 1) {
|
if (extract32(ahcf->isar.mvfr1, 12, 4) == 1) {
|
||||||
set_feature(&features, ARM_FEATURE_NEON);
|
set_feature(&features, ARM_FEATURE_NEON);
|
||||||
}
|
}
|
||||||
if (extract32(ahcf->isar.mvfr1, 28, 4) == 1) {
|
|
||||||
/* FMAC support implies VFPv4 */
|
|
||||||
set_feature(&features, ARM_FEATURE_VFP4);
|
|
||||||
}
|
|
||||||
|
|
||||||
ahcf->features = features;
|
ahcf->features = features;
|
||||||
|
|
||||||
|
|
|
@ -649,7 +649,6 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
|
||||||
* feature bits.
|
* feature bits.
|
||||||
*/
|
*/
|
||||||
set_feature(&features, ARM_FEATURE_V8);
|
set_feature(&features, ARM_FEATURE_V8);
|
||||||
set_feature(&features, ARM_FEATURE_VFP4);
|
|
||||||
set_feature(&features, ARM_FEATURE_NEON);
|
set_feature(&features, ARM_FEATURE_NEON);
|
||||||
set_feature(&features, ARM_FEATURE_AARCH64);
|
set_feature(&features, ARM_FEATURE_AARCH64);
|
||||||
set_feature(&features, ARM_FEATURE_PMU);
|
set_feature(&features, ARM_FEATURE_PMU);
|
||||||
|
|
|
@ -738,7 +738,8 @@ static uint32_t v7m_integrity_sig(CPUARMState *env, uint32_t lr)
|
||||||
*/
|
*/
|
||||||
uint32_t sig = 0xfefa125a;
|
uint32_t sig = 0xfefa125a;
|
||||||
|
|
||||||
if (!arm_feature(env, ARM_FEATURE_VFP) || (lr & R_V7M_EXCRET_FTYPE_MASK)) {
|
if (!cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))
|
||||||
|
|| (lr & R_V7M_EXCRET_FTYPE_MASK)) {
|
||||||
sig |= 1;
|
sig |= 1;
|
||||||
}
|
}
|
||||||
return sig;
|
return sig;
|
||||||
|
@ -841,7 +842,7 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
|
||||||
|
|
||||||
if (dotailchain) {
|
if (dotailchain) {
|
||||||
/* Sanitize LR FType and PREFIX bits */
|
/* Sanitize LR FType and PREFIX bits */
|
||||||
if (!arm_feature(env, ARM_FEATURE_VFP)) {
|
if (!cpu_isar_feature(aa32_vfp_simd, cpu)) {
|
||||||
lr |= R_V7M_EXCRET_FTYPE_MASK;
|
lr |= R_V7M_EXCRET_FTYPE_MASK;
|
||||||
}
|
}
|
||||||
lr = deposit32(lr, 24, 8, 0xff);
|
lr = deposit32(lr, 24, 8, 0xff);
|
||||||
|
@ -1373,7 +1374,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
||||||
|
|
||||||
ftype = excret & R_V7M_EXCRET_FTYPE_MASK;
|
ftype = excret & R_V7M_EXCRET_FTYPE_MASK;
|
||||||
|
|
||||||
if (!arm_feature(env, ARM_FEATURE_VFP) && !ftype) {
|
if (!ftype && !cpu_isar_feature(aa32_vfp_simd, cpu)) {
|
||||||
qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero FTYPE in exception "
|
qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero FTYPE in exception "
|
||||||
"exit PC value 0x%" PRIx32 " is UNPREDICTABLE "
|
"exit PC value 0x%" PRIx32 " is UNPREDICTABLE "
|
||||||
"if FPU not present\n",
|
"if FPU not present\n",
|
||||||
|
@ -2450,7 +2451,7 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
|
||||||
* SFPA is RAZ/WI from NS. FPCA is RO if NSACR.CP10 == 0,
|
* SFPA is RAZ/WI from NS. FPCA is RO if NSACR.CP10 == 0,
|
||||||
* RES0 if the FPU is not present, and is stored in the S bank
|
* RES0 if the FPU is not present, and is stored in the S bank
|
||||||
*/
|
*/
|
||||||
if (arm_feature(env, ARM_FEATURE_VFP) &&
|
if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env)) &&
|
||||||
extract32(env->v7m.nsacr, 10, 1)) {
|
extract32(env->v7m.nsacr, 10, 1)) {
|
||||||
env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
|
env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
|
||||||
env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
|
env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
|
||||||
|
@ -2565,7 +2566,7 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
|
||||||
env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
|
env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
|
||||||
env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK;
|
env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK;
|
||||||
}
|
}
|
||||||
if (arm_feature(env, ARM_FEATURE_VFP)) {
|
if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) {
|
||||||
/*
|
/*
|
||||||
* SFPA is RAZ/WI from NS or if no FPU.
|
* SFPA is RAZ/WI from NS or if no FPU.
|
||||||
* FPCA is RO if NSACR.CP10 == 0, RES0 if the FPU is not present.
|
* FPCA is RO if NSACR.CP10 == 0, RES0 if the FPU is not present.
|
||||||
|
|
|
@ -9,9 +9,10 @@
|
||||||
static bool vfp_needed(void *opaque)
|
static bool vfp_needed(void *opaque)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = opaque;
|
ARMCPU *cpu = opaque;
|
||||||
CPUARMState *env = &cpu->env;
|
|
||||||
|
|
||||||
return arm_feature(env, ARM_FEATURE_VFP);
|
return (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)
|
||||||
|
? cpu_isar_feature(aa64_fp_simd, cpu)
|
||||||
|
: cpu_isar_feature(aa32_vfp_simd, cpu));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_fpscr(QEMUFile *f, void *opaque, size_t size,
|
static int get_fpscr(QEMUFile *f, void *opaque, size_t size,
|
||||||
|
|
|
@ -3142,6 +3142,8 @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
|
||||||
int rs = extract32(insn, 16, 5);
|
int rs = extract32(insn, 16, 5);
|
||||||
int rn = extract32(insn, 5, 5);
|
int rn = extract32(insn, 5, 5);
|
||||||
int o3_opc = extract32(insn, 12, 4);
|
int o3_opc = extract32(insn, 12, 4);
|
||||||
|
bool r = extract32(insn, 22, 1);
|
||||||
|
bool a = extract32(insn, 23, 1);
|
||||||
TCGv_i64 tcg_rs, clean_addr;
|
TCGv_i64 tcg_rs, clean_addr;
|
||||||
AtomicThreeOpFn *fn;
|
AtomicThreeOpFn *fn;
|
||||||
|
|
||||||
|
@ -3177,6 +3179,13 @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
|
||||||
case 010: /* SWP */
|
case 010: /* SWP */
|
||||||
fn = tcg_gen_atomic_xchg_i64;
|
fn = tcg_gen_atomic_xchg_i64;
|
||||||
break;
|
break;
|
||||||
|
case 014: /* LDAPR, LDAPRH, LDAPRB */
|
||||||
|
if (!dc_isar_feature(aa64_rcpc_8_3, s) ||
|
||||||
|
rs != 31 || a != 1 || r != 0) {
|
||||||
|
unallocated_encoding(s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
unallocated_encoding(s);
|
unallocated_encoding(s);
|
||||||
return;
|
return;
|
||||||
|
@ -3186,6 +3195,21 @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
|
||||||
gen_check_sp_alignment(s);
|
gen_check_sp_alignment(s);
|
||||||
}
|
}
|
||||||
clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn));
|
clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn));
|
||||||
|
|
||||||
|
if (o3_opc == 014) {
|
||||||
|
/*
|
||||||
|
* LDAPR* are a special case because they are a simple load, not a
|
||||||
|
* fetch-and-do-something op.
|
||||||
|
* The architectural consistency requirements here are weaker than
|
||||||
|
* full load-acquire (we only need "load-acquire processor consistent"),
|
||||||
|
* but we choose to implement them as full LDAQ.
|
||||||
|
*/
|
||||||
|
do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size, false, false,
|
||||||
|
true, rt, disas_ldst_compute_iss_sf(size, false, 0), true);
|
||||||
|
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
tcg_rs = read_cpu_reg(s, rs, true);
|
tcg_rs = read_cpu_reg(s, rs, true);
|
||||||
|
|
||||||
if (o3_opc == 1) { /* LDCLR */
|
if (o3_opc == 1) { /* LDCLR */
|
||||||
|
@ -3259,6 +3283,88 @@ static void disas_ldst_pac(DisasContext *s, uint32_t insn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LDAPR/STLR (unscaled immediate)
|
||||||
|
*
|
||||||
|
* 31 30 24 22 21 12 10 5 0
|
||||||
|
* +------+-------------+-----+---+--------+-----+----+-----+
|
||||||
|
* | size | 0 1 1 0 0 1 | opc | 0 | imm9 | 0 0 | Rn | Rt |
|
||||||
|
* +------+-------------+-----+---+--------+-----+----+-----+
|
||||||
|
*
|
||||||
|
* Rt: source or destination register
|
||||||
|
* Rn: base register
|
||||||
|
* imm9: unscaled immediate offset
|
||||||
|
* opc: 00: STLUR*, 01/10/11: various LDAPUR*
|
||||||
|
* size: size of load/store
|
||||||
|
*/
|
||||||
|
static void disas_ldst_ldapr_stlr(DisasContext *s, uint32_t insn)
|
||||||
|
{
|
||||||
|
int rt = extract32(insn, 0, 5);
|
||||||
|
int rn = extract32(insn, 5, 5);
|
||||||
|
int offset = sextract32(insn, 12, 9);
|
||||||
|
int opc = extract32(insn, 22, 2);
|
||||||
|
int size = extract32(insn, 30, 2);
|
||||||
|
TCGv_i64 clean_addr, dirty_addr;
|
||||||
|
bool is_store = false;
|
||||||
|
bool is_signed = false;
|
||||||
|
bool extend = false;
|
||||||
|
bool iss_sf;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa64_rcpc_8_4, s)) {
|
||||||
|
unallocated_encoding(s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (opc) {
|
||||||
|
case 0: /* STLURB */
|
||||||
|
is_store = true;
|
||||||
|
break;
|
||||||
|
case 1: /* LDAPUR* */
|
||||||
|
break;
|
||||||
|
case 2: /* LDAPURS* 64-bit variant */
|
||||||
|
if (size == 3) {
|
||||||
|
unallocated_encoding(s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
is_signed = true;
|
||||||
|
break;
|
||||||
|
case 3: /* LDAPURS* 32-bit variant */
|
||||||
|
if (size > 1) {
|
||||||
|
unallocated_encoding(s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
is_signed = true;
|
||||||
|
extend = true; /* zero-extend 32->64 after signed load */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc);
|
||||||
|
|
||||||
|
if (rn == 31) {
|
||||||
|
gen_check_sp_alignment(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
dirty_addr = read_cpu_reg_sp(s, rn, 1);
|
||||||
|
tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
|
||||||
|
clean_addr = clean_data_tbi(s, dirty_addr);
|
||||||
|
|
||||||
|
if (is_store) {
|
||||||
|
/* Store-Release semantics */
|
||||||
|
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
|
||||||
|
do_gpr_st(s, cpu_reg(s, rt), clean_addr, size, true, rt, iss_sf, true);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Load-AcquirePC semantics; we implement as the slightly more
|
||||||
|
* restrictive Load-Acquire.
|
||||||
|
*/
|
||||||
|
do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size, is_signed, extend,
|
||||||
|
true, rt, iss_sf, true);
|
||||||
|
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Load/store register (all forms) */
|
/* Load/store register (all forms) */
|
||||||
static void disas_ldst_reg(DisasContext *s, uint32_t insn)
|
static void disas_ldst_reg(DisasContext *s, uint32_t insn)
|
||||||
{
|
{
|
||||||
|
@ -3610,6 +3716,14 @@ static void disas_ldst(DisasContext *s, uint32_t insn)
|
||||||
case 0x0d: /* AdvSIMD load/store single structure */
|
case 0x0d: /* AdvSIMD load/store single structure */
|
||||||
disas_ldst_single_struct(s, insn);
|
disas_ldst_single_struct(s, insn);
|
||||||
break;
|
break;
|
||||||
|
case 0x19: /* LDAPR/STLR (unscaled immediate) */
|
||||||
|
if (extract32(insn, 10, 2) != 0 ||
|
||||||
|
extract32(insn, 21, 1) != 0) {
|
||||||
|
unallocated_encoding(s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
disas_ldst_ldapr_stlr(s, insn);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
unallocated_encoding(s);
|
unallocated_encoding(s);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -200,13 +200,13 @@ static bool trans_VSEL(DisasContext *s, arg_VSEL *a)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* UNDEF accesses to D16-D31 if they don't exist */
|
if (dp && !dc_isar_feature(aa32_fpdp_v2, s)) {
|
||||||
if (dp && !dc_isar_feature(aa32_simd_r32, s) &&
|
|
||||||
((a->vm | a->vn | a->vd) & 0x10)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dp && !dc_isar_feature(aa32_fpdp, s)) {
|
/* UNDEF accesses to D16-D31 if they don't exist */
|
||||||
|
if (dp && !dc_isar_feature(aa32_simd_r32, s) &&
|
||||||
|
((a->vm | a->vn | a->vd) & 0x10)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,79 +322,6 @@ static bool trans_VSEL(DisasContext *s, arg_VSEL *a)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool trans_VMINMAXNM(DisasContext *s, arg_VMINMAXNM *a)
|
|
||||||
{
|
|
||||||
uint32_t rd, rn, rm;
|
|
||||||
bool dp = a->dp;
|
|
||||||
bool vmin = a->op;
|
|
||||||
TCGv_ptr fpst;
|
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_vminmaxnm, s)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* UNDEF accesses to D16-D31 if they don't exist */
|
|
||||||
if (dp && !dc_isar_feature(aa32_simd_r32, s) &&
|
|
||||||
((a->vm | a->vn | a->vd) & 0x10)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dp && !dc_isar_feature(aa32_fpdp, s)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
rd = a->vd;
|
|
||||||
rn = a->vn;
|
|
||||||
rm = a->vm;
|
|
||||||
|
|
||||||
if (!vfp_access_check(s)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
fpst = get_fpstatus_ptr(0);
|
|
||||||
|
|
||||||
if (dp) {
|
|
||||||
TCGv_i64 frn, frm, dest;
|
|
||||||
|
|
||||||
frn = tcg_temp_new_i64();
|
|
||||||
frm = tcg_temp_new_i64();
|
|
||||||
dest = tcg_temp_new_i64();
|
|
||||||
|
|
||||||
neon_load_reg64(frn, rn);
|
|
||||||
neon_load_reg64(frm, rm);
|
|
||||||
if (vmin) {
|
|
||||||
gen_helper_vfp_minnumd(dest, frn, frm, fpst);
|
|
||||||
} else {
|
|
||||||
gen_helper_vfp_maxnumd(dest, frn, frm, fpst);
|
|
||||||
}
|
|
||||||
neon_store_reg64(dest, rd);
|
|
||||||
tcg_temp_free_i64(frn);
|
|
||||||
tcg_temp_free_i64(frm);
|
|
||||||
tcg_temp_free_i64(dest);
|
|
||||||
} else {
|
|
||||||
TCGv_i32 frn, frm, dest;
|
|
||||||
|
|
||||||
frn = tcg_temp_new_i32();
|
|
||||||
frm = tcg_temp_new_i32();
|
|
||||||
dest = tcg_temp_new_i32();
|
|
||||||
|
|
||||||
neon_load_reg32(frn, rn);
|
|
||||||
neon_load_reg32(frm, rm);
|
|
||||||
if (vmin) {
|
|
||||||
gen_helper_vfp_minnums(dest, frn, frm, fpst);
|
|
||||||
} else {
|
|
||||||
gen_helper_vfp_maxnums(dest, frn, frm, fpst);
|
|
||||||
}
|
|
||||||
neon_store_reg32(dest, rd);
|
|
||||||
tcg_temp_free_i32(frn);
|
|
||||||
tcg_temp_free_i32(frm);
|
|
||||||
tcg_temp_free_i32(dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
tcg_temp_free_ptr(fpst);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Table for converting the most common AArch32 encoding of
|
* Table for converting the most common AArch32 encoding of
|
||||||
* rounding mode to arm_fprounding order (which matches the
|
* rounding mode to arm_fprounding order (which matches the
|
||||||
|
@ -419,13 +346,13 @@ static bool trans_VRINT(DisasContext *s, arg_VRINT *a)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* UNDEF accesses to D16-D31 if they don't exist */
|
if (dp && !dc_isar_feature(aa32_fpdp_v2, s)) {
|
||||||
if (dp && !dc_isar_feature(aa32_simd_r32, s) &&
|
|
||||||
((a->vm | a->vd) & 0x10)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dp && !dc_isar_feature(aa32_fpdp, s)) {
|
/* UNDEF accesses to D16-D31 if they don't exist */
|
||||||
|
if (dp && !dc_isar_feature(aa32_simd_r32, s) &&
|
||||||
|
((a->vm | a->vd) & 0x10)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,12 +410,12 @@ static bool trans_VCVT(DisasContext *s, arg_VCVT *a)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* UNDEF accesses to D16-D31 if they don't exist */
|
if (dp && !dc_isar_feature(aa32_fpdp_v2, s)) {
|
||||||
if (dp && !dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dp && !dc_isar_feature(aa32_fpdp, s)) {
|
/* UNDEF accesses to D16-D31 if they don't exist */
|
||||||
|
if (dp && !dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -555,6 +482,13 @@ static bool trans_VMOV_to_gp(DisasContext *s, arg_VMOV_to_gp *a)
|
||||||
int pass;
|
int pass;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
|
|
||||||
|
/* SIZE == 2 is a VFP instruction; otherwise NEON. */
|
||||||
|
if (a->size == 2
|
||||||
|
? !dc_isar_feature(aa32_fpsp_v2, s)
|
||||||
|
: !arm_dc_feature(s, ARM_FEATURE_NEON)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* UNDEF accesses to D16-D31 if they don't exist */
|
/* UNDEF accesses to D16-D31 if they don't exist */
|
||||||
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) {
|
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -564,10 +498,6 @@ static bool trans_VMOV_to_gp(DisasContext *s, arg_VMOV_to_gp *a)
|
||||||
pass = extract32(offset, 2, 1);
|
pass = extract32(offset, 2, 1);
|
||||||
offset = extract32(offset, 0, 2) * 8;
|
offset = extract32(offset, 0, 2) * 8;
|
||||||
|
|
||||||
if (a->size != 2 && !arm_dc_feature(s, ARM_FEATURE_NEON)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vfp_access_check(s)) {
|
if (!vfp_access_check(s)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -614,6 +544,13 @@ static bool trans_VMOV_from_gp(DisasContext *s, arg_VMOV_from_gp *a)
|
||||||
int pass;
|
int pass;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
|
|
||||||
|
/* SIZE == 2 is a VFP instruction; otherwise NEON. */
|
||||||
|
if (a->size == 2
|
||||||
|
? !dc_isar_feature(aa32_fpsp_v2, s)
|
||||||
|
: !arm_dc_feature(s, ARM_FEATURE_NEON)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* UNDEF accesses to D16-D31 if they don't exist */
|
/* UNDEF accesses to D16-D31 if they don't exist */
|
||||||
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) {
|
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -623,10 +560,6 @@ static bool trans_VMOV_from_gp(DisasContext *s, arg_VMOV_from_gp *a)
|
||||||
pass = extract32(offset, 2, 1);
|
pass = extract32(offset, 2, 1);
|
||||||
offset = extract32(offset, 0, 2) * 8;
|
offset = extract32(offset, 0, 2) * 8;
|
||||||
|
|
||||||
if (a->size != 2 && !arm_dc_feature(s, ARM_FEATURE_NEON)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vfp_access_check(s)) {
|
if (!vfp_access_check(s)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -700,6 +633,10 @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a)
|
||||||
TCGv_i32 tmp;
|
TCGv_i32 tmp;
|
||||||
bool ignore_vfp_enabled = false;
|
bool ignore_vfp_enabled = false;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fpsp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (arm_dc_feature(s, ARM_FEATURE_M)) {
|
if (arm_dc_feature(s, ARM_FEATURE_M)) {
|
||||||
/*
|
/*
|
||||||
* The only M-profile VFP vmrs/vmsr sysreg is FPSCR.
|
* The only M-profile VFP vmrs/vmsr sysreg is FPSCR.
|
||||||
|
@ -717,7 +654,7 @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a)
|
||||||
* VFPv2 allows access to FPSID from userspace; VFPv3 restricts
|
* VFPv2 allows access to FPSID from userspace; VFPv3 restricts
|
||||||
* all ID registers to privileged access only.
|
* all ID registers to privileged access only.
|
||||||
*/
|
*/
|
||||||
if (IS_USER(s) && arm_dc_feature(s, ARM_FEATURE_VFP3)) {
|
if (IS_USER(s) && dc_isar_feature(aa32_fpsp_v3, s)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ignore_vfp_enabled = true;
|
ignore_vfp_enabled = true;
|
||||||
|
@ -746,7 +683,7 @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a)
|
||||||
case ARM_VFP_FPINST:
|
case ARM_VFP_FPINST:
|
||||||
case ARM_VFP_FPINST2:
|
case ARM_VFP_FPINST2:
|
||||||
/* Not present in VFPv3 */
|
/* Not present in VFPv3 */
|
||||||
if (IS_USER(s) || arm_dc_feature(s, ARM_FEATURE_VFP3)) {
|
if (IS_USER(s) || dc_isar_feature(aa32_fpsp_v3, s)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -844,6 +781,10 @@ static bool trans_VMOV_single(DisasContext *s, arg_VMOV_single *a)
|
||||||
{
|
{
|
||||||
TCGv_i32 tmp;
|
TCGv_i32 tmp;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fpsp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!vfp_access_check(s)) {
|
if (!vfp_access_check(s)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -873,6 +814,10 @@ static bool trans_VMOV_64_sp(DisasContext *s, arg_VMOV_64_sp *a)
|
||||||
{
|
{
|
||||||
TCGv_i32 tmp;
|
TCGv_i32 tmp;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fpsp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* VMOV between two general-purpose registers and two single precision
|
* VMOV between two general-purpose registers and two single precision
|
||||||
* floating point registers
|
* floating point registers
|
||||||
|
@ -908,8 +853,12 @@ static bool trans_VMOV_64_dp(DisasContext *s, arg_VMOV_64_dp *a)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* VMOV between two general-purpose registers and one double precision
|
* VMOV between two general-purpose registers and one double precision
|
||||||
* floating point register
|
* floating point register. Note that this does not require support
|
||||||
|
* for double precision arithmetic.
|
||||||
*/
|
*/
|
||||||
|
if (!dc_isar_feature(aa32_fpsp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* UNDEF accesses to D16-D31 if they don't exist */
|
/* UNDEF accesses to D16-D31 if they don't exist */
|
||||||
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
|
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
|
||||||
|
@ -946,6 +895,10 @@ static bool trans_VLDR_VSTR_sp(DisasContext *s, arg_VLDR_VSTR_sp *a)
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
TCGv_i32 addr, tmp;
|
TCGv_i32 addr, tmp;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fpsp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!vfp_access_check(s)) {
|
if (!vfp_access_check(s)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -977,6 +930,11 @@ static bool trans_VLDR_VSTR_dp(DisasContext *s, arg_VLDR_VSTR_dp *a)
|
||||||
TCGv_i32 addr;
|
TCGv_i32 addr;
|
||||||
TCGv_i64 tmp;
|
TCGv_i64 tmp;
|
||||||
|
|
||||||
|
/* Note that this does not require support for double arithmetic. */
|
||||||
|
if (!dc_isar_feature(aa32_fpsp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* UNDEF accesses to D16-D31 if they don't exist */
|
/* UNDEF accesses to D16-D31 if they don't exist */
|
||||||
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
|
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1013,6 +971,10 @@ static bool trans_VLDM_VSTM_sp(DisasContext *s, arg_VLDM_VSTM_sp *a)
|
||||||
TCGv_i32 addr, tmp;
|
TCGv_i32 addr, tmp;
|
||||||
int i, n;
|
int i, n;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fpsp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
n = a->imm;
|
n = a->imm;
|
||||||
|
|
||||||
if (n == 0 || (a->vd + n) > 32) {
|
if (n == 0 || (a->vd + n) > 32) {
|
||||||
|
@ -1086,6 +1048,11 @@ static bool trans_VLDM_VSTM_dp(DisasContext *s, arg_VLDM_VSTM_dp *a)
|
||||||
TCGv_i64 tmp;
|
TCGv_i64 tmp;
|
||||||
int i, n;
|
int i, n;
|
||||||
|
|
||||||
|
/* Note that this does not require support for double arithmetic. */
|
||||||
|
if (!dc_isar_feature(aa32_fpsp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
n = a->imm >> 1;
|
n = a->imm >> 1;
|
||||||
|
|
||||||
if (n == 0 || (a->vd + n) > 32 || n > 16) {
|
if (n == 0 || (a->vd + n) > 32 || n > 16) {
|
||||||
|
@ -1234,6 +1201,10 @@ static bool do_vfp_3op_sp(DisasContext *s, VFPGen3OpSPFn *fn,
|
||||||
TCGv_i32 f0, f1, fd;
|
TCGv_i32 f0, f1, fd;
|
||||||
TCGv_ptr fpst;
|
TCGv_ptr fpst;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fpsp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpshvec, s) &&
|
if (!dc_isar_feature(aa32_fpshvec, s) &&
|
||||||
(veclen != 0 || s->vec_stride != 0)) {
|
(veclen != 0 || s->vec_stride != 0)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1308,12 +1279,12 @@ static bool do_vfp_3op_dp(DisasContext *s, VFPGen3OpDPFn *fn,
|
||||||
TCGv_i64 f0, f1, fd;
|
TCGv_i64 f0, f1, fd;
|
||||||
TCGv_ptr fpst;
|
TCGv_ptr fpst;
|
||||||
|
|
||||||
/* UNDEF accesses to D16-D31 if they don't exist */
|
if (!dc_isar_feature(aa32_fpdp_v2, s)) {
|
||||||
if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vn | vm) & 0x10)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpdp, s)) {
|
/* UNDEF accesses to D16-D31 if they don't exist */
|
||||||
|
if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vn | vm) & 0x10)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1388,6 +1359,10 @@ static bool do_vfp_2op_sp(DisasContext *s, VFPGen2OpSPFn *fn, int vd, int vm)
|
||||||
int veclen = s->vec_len;
|
int veclen = s->vec_len;
|
||||||
TCGv_i32 f0, fd;
|
TCGv_i32 f0, fd;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fpsp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpshvec, s) &&
|
if (!dc_isar_feature(aa32_fpshvec, s) &&
|
||||||
(veclen != 0 || s->vec_stride != 0)) {
|
(veclen != 0 || s->vec_stride != 0)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1457,12 +1432,12 @@ static bool do_vfp_2op_dp(DisasContext *s, VFPGen2OpDPFn *fn, int vd, int vm)
|
||||||
int veclen = s->vec_len;
|
int veclen = s->vec_len;
|
||||||
TCGv_i64 f0, fd;
|
TCGv_i64 f0, fd;
|
||||||
|
|
||||||
/* UNDEF accesses to D16-D31 if they don't exist */
|
if (!dc_isar_feature(aa32_fpdp_v2, s)) {
|
||||||
if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vm) & 0x10)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpdp, s)) {
|
/* UNDEF accesses to D16-D31 if they don't exist */
|
||||||
|
if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vm) & 0x10)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1736,7 +1711,43 @@ static bool trans_VDIV_dp(DisasContext *s, arg_VDIV_dp *a)
|
||||||
return do_vfp_3op_dp(s, gen_helper_vfp_divd, a->vd, a->vn, a->vm, false);
|
return do_vfp_3op_dp(s, gen_helper_vfp_divd, a->vd, a->vn, a->vm, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool trans_VFM_sp(DisasContext *s, arg_VFM_sp *a)
|
static bool trans_VMINNM_sp(DisasContext *s, arg_VMINNM_sp *a)
|
||||||
|
{
|
||||||
|
if (!dc_isar_feature(aa32_vminmaxnm, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return do_vfp_3op_sp(s, gen_helper_vfp_minnums,
|
||||||
|
a->vd, a->vn, a->vm, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool trans_VMAXNM_sp(DisasContext *s, arg_VMAXNM_sp *a)
|
||||||
|
{
|
||||||
|
if (!dc_isar_feature(aa32_vminmaxnm, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return do_vfp_3op_sp(s, gen_helper_vfp_maxnums,
|
||||||
|
a->vd, a->vn, a->vm, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool trans_VMINNM_dp(DisasContext *s, arg_VMINNM_dp *a)
|
||||||
|
{
|
||||||
|
if (!dc_isar_feature(aa32_vminmaxnm, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return do_vfp_3op_dp(s, gen_helper_vfp_minnumd,
|
||||||
|
a->vd, a->vn, a->vm, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool trans_VMAXNM_dp(DisasContext *s, arg_VMAXNM_dp *a)
|
||||||
|
{
|
||||||
|
if (!dc_isar_feature(aa32_vminmaxnm, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return do_vfp_3op_dp(s, gen_helper_vfp_maxnumd,
|
||||||
|
a->vd, a->vn, a->vm, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool do_vfm_sp(DisasContext *s, arg_VFMA_sp *a, bool neg_n, bool neg_d)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* VFNMA : fd = muladd(-fd, fn, fm)
|
* VFNMA : fd = muladd(-fd, fn, fm)
|
||||||
|
@ -1755,11 +1766,18 @@ static bool trans_VFM_sp(DisasContext *s, arg_VFM_sp *a)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Present in VFPv4 only.
|
* Present in VFPv4 only.
|
||||||
|
* Note that we can't rely on the SIMDFMAC check alone, because
|
||||||
|
* in a Neon-no-VFP core that ID register field will be non-zero.
|
||||||
|
*/
|
||||||
|
if (!dc_isar_feature(aa32_simdfmac, s) ||
|
||||||
|
!dc_isar_feature(aa32_fpsp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/*
|
||||||
* In v7A, UNPREDICTABLE with non-zero vector length/stride; from
|
* In v7A, UNPREDICTABLE with non-zero vector length/stride; from
|
||||||
* v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
|
* v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
|
||||||
*/
|
*/
|
||||||
if (!arm_dc_feature(s, ARM_FEATURE_VFP4) ||
|
if (s->vec_len != 0 || s->vec_stride != 0) {
|
||||||
(s->vec_len != 0 || s->vec_stride != 0)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1773,12 +1791,12 @@ static bool trans_VFM_sp(DisasContext *s, arg_VFM_sp *a)
|
||||||
|
|
||||||
neon_load_reg32(vn, a->vn);
|
neon_load_reg32(vn, a->vn);
|
||||||
neon_load_reg32(vm, a->vm);
|
neon_load_reg32(vm, a->vm);
|
||||||
if (a->o2) {
|
if (neg_n) {
|
||||||
/* VFNMS, VFMS */
|
/* VFNMS, VFMS */
|
||||||
gen_helper_vfp_negs(vn, vn);
|
gen_helper_vfp_negs(vn, vn);
|
||||||
}
|
}
|
||||||
neon_load_reg32(vd, a->vd);
|
neon_load_reg32(vd, a->vd);
|
||||||
if (a->o1 & 1) {
|
if (neg_d) {
|
||||||
/* VFNMA, VFNMS */
|
/* VFNMA, VFNMS */
|
||||||
gen_helper_vfp_negs(vd, vd);
|
gen_helper_vfp_negs(vd, vd);
|
||||||
}
|
}
|
||||||
|
@ -1794,7 +1812,27 @@ static bool trans_VFM_sp(DisasContext *s, arg_VFM_sp *a)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool trans_VFM_dp(DisasContext *s, arg_VFM_dp *a)
|
static bool trans_VFMA_sp(DisasContext *s, arg_VFMA_sp *a)
|
||||||
|
{
|
||||||
|
return do_vfm_sp(s, a, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool trans_VFMS_sp(DisasContext *s, arg_VFMS_sp *a)
|
||||||
|
{
|
||||||
|
return do_vfm_sp(s, a, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool trans_VFNMA_sp(DisasContext *s, arg_VFNMA_sp *a)
|
||||||
|
{
|
||||||
|
return do_vfm_sp(s, a, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool trans_VFNMS_sp(DisasContext *s, arg_VFNMS_sp *a)
|
||||||
|
{
|
||||||
|
return do_vfm_sp(s, a, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool do_vfm_dp(DisasContext *s, arg_VFMA_dp *a, bool neg_n, bool neg_d)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* VFNMA : fd = muladd(-fd, fn, fm)
|
* VFNMA : fd = muladd(-fd, fn, fm)
|
||||||
|
@ -1813,11 +1851,18 @@ static bool trans_VFM_dp(DisasContext *s, arg_VFM_dp *a)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Present in VFPv4 only.
|
* Present in VFPv4 only.
|
||||||
|
* Note that we can't rely on the SIMDFMAC check alone, because
|
||||||
|
* in a Neon-no-VFP core that ID register field will be non-zero.
|
||||||
|
*/
|
||||||
|
if (!dc_isar_feature(aa32_simdfmac, s) ||
|
||||||
|
!dc_isar_feature(aa32_fpdp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/*
|
||||||
* In v7A, UNPREDICTABLE with non-zero vector length/stride; from
|
* In v7A, UNPREDICTABLE with non-zero vector length/stride; from
|
||||||
* v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
|
* v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
|
||||||
*/
|
*/
|
||||||
if (!arm_dc_feature(s, ARM_FEATURE_VFP4) ||
|
if (s->vec_len != 0 || s->vec_stride != 0) {
|
||||||
(s->vec_len != 0 || s->vec_stride != 0)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1827,7 +1872,9 @@ static bool trans_VFM_dp(DisasContext *s, arg_VFM_dp *a)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpdp, s)) {
|
/* UNDEF accesses to D16-D31 if they don't exist. */
|
||||||
|
if (!dc_isar_feature(aa32_simd_r32, s) &&
|
||||||
|
((a->vd | a->vn | a->vm) & 0x10)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1841,12 +1888,12 @@ static bool trans_VFM_dp(DisasContext *s, arg_VFM_dp *a)
|
||||||
|
|
||||||
neon_load_reg64(vn, a->vn);
|
neon_load_reg64(vn, a->vn);
|
||||||
neon_load_reg64(vm, a->vm);
|
neon_load_reg64(vm, a->vm);
|
||||||
if (a->o2) {
|
if (neg_n) {
|
||||||
/* VFNMS, VFMS */
|
/* VFNMS, VFMS */
|
||||||
gen_helper_vfp_negd(vn, vn);
|
gen_helper_vfp_negd(vn, vn);
|
||||||
}
|
}
|
||||||
neon_load_reg64(vd, a->vd);
|
neon_load_reg64(vd, a->vd);
|
||||||
if (a->o1 & 1) {
|
if (neg_d) {
|
||||||
/* VFNMA, VFNMS */
|
/* VFNMA, VFNMS */
|
||||||
gen_helper_vfp_negd(vd, vd);
|
gen_helper_vfp_negd(vd, vd);
|
||||||
}
|
}
|
||||||
|
@ -1862,6 +1909,26 @@ static bool trans_VFM_dp(DisasContext *s, arg_VFM_dp *a)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool trans_VFMA_dp(DisasContext *s, arg_VFMA_dp *a)
|
||||||
|
{
|
||||||
|
return do_vfm_dp(s, a, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool trans_VFMS_dp(DisasContext *s, arg_VFMS_dp *a)
|
||||||
|
{
|
||||||
|
return do_vfm_dp(s, a, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool trans_VFNMA_dp(DisasContext *s, arg_VFNMA_dp *a)
|
||||||
|
{
|
||||||
|
return do_vfm_dp(s, a, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool trans_VFNMS_dp(DisasContext *s, arg_VFNMS_dp *a)
|
||||||
|
{
|
||||||
|
return do_vfm_dp(s, a, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
static bool trans_VMOV_imm_sp(DisasContext *s, arg_VMOV_imm_sp *a)
|
static bool trans_VMOV_imm_sp(DisasContext *s, arg_VMOV_imm_sp *a)
|
||||||
{
|
{
|
||||||
uint32_t delta_d = 0;
|
uint32_t delta_d = 0;
|
||||||
|
@ -1871,12 +1938,12 @@ static bool trans_VMOV_imm_sp(DisasContext *s, arg_VMOV_imm_sp *a)
|
||||||
|
|
||||||
vd = a->vd;
|
vd = a->vd;
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpshvec, s) &&
|
if (!dc_isar_feature(aa32_fpsp_v3, s)) {
|
||||||
(veclen != 0 || s->vec_stride != 0)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
|
if (!dc_isar_feature(aa32_fpshvec, s) &&
|
||||||
|
(veclen != 0 || s->vec_stride != 0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1921,24 +1988,20 @@ static bool trans_VMOV_imm_dp(DisasContext *s, arg_VMOV_imm_dp *a)
|
||||||
|
|
||||||
vd = a->vd;
|
vd = a->vd;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fpdp_v3, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* UNDEF accesses to D16-D31 if they don't exist. */
|
/* UNDEF accesses to D16-D31 if they don't exist. */
|
||||||
if (!dc_isar_feature(aa32_simd_r32, s) && (vd & 0x10)) {
|
if (!dc_isar_feature(aa32_simd_r32, s) && (vd & 0x10)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpdp, s)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpshvec, s) &&
|
if (!dc_isar_feature(aa32_fpshvec, s) &&
|
||||||
(veclen != 0 || s->vec_stride != 0)) {
|
(veclen != 0 || s->vec_stride != 0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vfp_access_check(s)) {
|
if (!vfp_access_check(s)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2025,6 +2088,10 @@ static bool trans_VCMP_sp(DisasContext *s, arg_VCMP_sp *a)
|
||||||
{
|
{
|
||||||
TCGv_i32 vd, vm;
|
TCGv_i32 vd, vm;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fpsp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Vm/M bits must be zero for the Z variant */
|
/* Vm/M bits must be zero for the Z variant */
|
||||||
if (a->z && a->vm != 0) {
|
if (a->z && a->vm != 0) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -2060,6 +2127,10 @@ static bool trans_VCMP_dp(DisasContext *s, arg_VCMP_dp *a)
|
||||||
{
|
{
|
||||||
TCGv_i64 vd, vm;
|
TCGv_i64 vd, vm;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fpdp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Vm/M bits must be zero for the Z variant */
|
/* Vm/M bits must be zero for the Z variant */
|
||||||
if (a->z && a->vm != 0) {
|
if (a->z && a->vm != 0) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -2070,10 +2141,6 @@ static bool trans_VCMP_dp(DisasContext *s, arg_VCMP_dp *a)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpdp, s)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vfp_access_check(s)) {
|
if (!vfp_access_check(s)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2134,6 +2201,10 @@ static bool trans_VCVT_f64_f16(DisasContext *s, arg_VCVT_f64_f16 *a)
|
||||||
TCGv_i32 tmp;
|
TCGv_i32 tmp;
|
||||||
TCGv_i64 vd;
|
TCGv_i64 vd;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fpdp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fp16_dpconv, s)) {
|
if (!dc_isar_feature(aa32_fp16_dpconv, s)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2143,10 +2214,6 @@ static bool trans_VCVT_f64_f16(DisasContext *s, arg_VCVT_f64_f16 *a)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpdp, s)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vfp_access_check(s)) {
|
if (!vfp_access_check(s)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2200,6 +2267,10 @@ static bool trans_VCVT_f16_f64(DisasContext *s, arg_VCVT_f16_f64 *a)
|
||||||
TCGv_i32 tmp;
|
TCGv_i32 tmp;
|
||||||
TCGv_i64 vm;
|
TCGv_i64 vm;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fpdp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fp16_dpconv, s)) {
|
if (!dc_isar_feature(aa32_fp16_dpconv, s)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2209,10 +2280,6 @@ static bool trans_VCVT_f16_f64(DisasContext *s, arg_VCVT_f16_f64 *a)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpdp, s)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vfp_access_check(s)) {
|
if (!vfp_access_check(s)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2260,6 +2327,10 @@ static bool trans_VRINTR_dp(DisasContext *s, arg_VRINTR_dp *a)
|
||||||
TCGv_ptr fpst;
|
TCGv_ptr fpst;
|
||||||
TCGv_i64 tmp;
|
TCGv_i64 tmp;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fpdp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_vrint, s)) {
|
if (!dc_isar_feature(aa32_vrint, s)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2269,10 +2340,6 @@ static bool trans_VRINTR_dp(DisasContext *s, arg_VRINTR_dp *a)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpdp, s)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vfp_access_check(s)) {
|
if (!vfp_access_check(s)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2321,6 +2388,10 @@ static bool trans_VRINTZ_dp(DisasContext *s, arg_VRINTZ_dp *a)
|
||||||
TCGv_i64 tmp;
|
TCGv_i64 tmp;
|
||||||
TCGv_i32 tcg_rmode;
|
TCGv_i32 tcg_rmode;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fpdp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_vrint, s)) {
|
if (!dc_isar_feature(aa32_vrint, s)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2330,10 +2401,6 @@ static bool trans_VRINTZ_dp(DisasContext *s, arg_VRINTZ_dp *a)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpdp, s)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vfp_access_check(s)) {
|
if (!vfp_access_check(s)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2380,6 +2447,10 @@ static bool trans_VRINTX_dp(DisasContext *s, arg_VRINTX_dp *a)
|
||||||
TCGv_ptr fpst;
|
TCGv_ptr fpst;
|
||||||
TCGv_i64 tmp;
|
TCGv_i64 tmp;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fpdp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_vrint, s)) {
|
if (!dc_isar_feature(aa32_vrint, s)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2389,10 +2460,6 @@ static bool trans_VRINTX_dp(DisasContext *s, arg_VRINTX_dp *a)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpdp, s)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vfp_access_check(s)) {
|
if (!vfp_access_check(s)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2412,12 +2479,12 @@ static bool trans_VCVT_sp(DisasContext *s, arg_VCVT_sp *a)
|
||||||
TCGv_i64 vd;
|
TCGv_i64 vd;
|
||||||
TCGv_i32 vm;
|
TCGv_i32 vm;
|
||||||
|
|
||||||
/* UNDEF accesses to D16-D31 if they don't exist. */
|
if (!dc_isar_feature(aa32_fpdp_v2, s)) {
|
||||||
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpdp, s)) {
|
/* UNDEF accesses to D16-D31 if they don't exist. */
|
||||||
|
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2440,12 +2507,12 @@ static bool trans_VCVT_dp(DisasContext *s, arg_VCVT_dp *a)
|
||||||
TCGv_i64 vm;
|
TCGv_i64 vm;
|
||||||
TCGv_i32 vd;
|
TCGv_i32 vd;
|
||||||
|
|
||||||
/* UNDEF accesses to D16-D31 if they don't exist. */
|
if (!dc_isar_feature(aa32_fpdp_v2, s)) {
|
||||||
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpdp, s)) {
|
/* UNDEF accesses to D16-D31 if they don't exist. */
|
||||||
|
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2468,6 +2535,10 @@ static bool trans_VCVT_int_sp(DisasContext *s, arg_VCVT_int_sp *a)
|
||||||
TCGv_i32 vm;
|
TCGv_i32 vm;
|
||||||
TCGv_ptr fpst;
|
TCGv_ptr fpst;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fpsp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!vfp_access_check(s)) {
|
if (!vfp_access_check(s)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2494,12 +2565,12 @@ static bool trans_VCVT_int_dp(DisasContext *s, arg_VCVT_int_dp *a)
|
||||||
TCGv_i64 vd;
|
TCGv_i64 vd;
|
||||||
TCGv_ptr fpst;
|
TCGv_ptr fpst;
|
||||||
|
|
||||||
/* UNDEF accesses to D16-D31 if they don't exist. */
|
if (!dc_isar_feature(aa32_fpdp_v2, s)) {
|
||||||
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpdp, s)) {
|
/* UNDEF accesses to D16-D31 if they don't exist. */
|
||||||
|
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2530,6 +2601,10 @@ static bool trans_VJCVT(DisasContext *s, arg_VJCVT *a)
|
||||||
TCGv_i32 vd;
|
TCGv_i32 vd;
|
||||||
TCGv_i64 vm;
|
TCGv_i64 vm;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fpdp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_jscvt, s)) {
|
if (!dc_isar_feature(aa32_jscvt, s)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2539,10 +2614,6 @@ static bool trans_VJCVT(DisasContext *s, arg_VJCVT *a)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpdp, s)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vfp_access_check(s)) {
|
if (!vfp_access_check(s)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2563,7 +2634,7 @@ static bool trans_VCVT_fix_sp(DisasContext *s, arg_VCVT_fix_sp *a)
|
||||||
TCGv_ptr fpst;
|
TCGv_ptr fpst;
|
||||||
int frac_bits;
|
int frac_bits;
|
||||||
|
|
||||||
if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
|
if (!dc_isar_feature(aa32_fpsp_v3, s)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2623,7 +2694,7 @@ static bool trans_VCVT_fix_dp(DisasContext *s, arg_VCVT_fix_dp *a)
|
||||||
TCGv_ptr fpst;
|
TCGv_ptr fpst;
|
||||||
int frac_bits;
|
int frac_bits;
|
||||||
|
|
||||||
if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
|
if (!dc_isar_feature(aa32_fpdp_v3, s)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2632,10 +2703,6 @@ static bool trans_VCVT_fix_dp(DisasContext *s, arg_VCVT_fix_dp *a)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpdp, s)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vfp_access_check(s)) {
|
if (!vfp_access_check(s)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2690,6 +2757,10 @@ static bool trans_VCVT_sp_int(DisasContext *s, arg_VCVT_sp_int *a)
|
||||||
TCGv_i32 vm;
|
TCGv_i32 vm;
|
||||||
TCGv_ptr fpst;
|
TCGv_ptr fpst;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fpsp_v2, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!vfp_access_check(s)) {
|
if (!vfp_access_check(s)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2723,12 +2794,12 @@ static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a)
|
||||||
TCGv_i64 vm;
|
TCGv_i64 vm;
|
||||||
TCGv_ptr fpst;
|
TCGv_ptr fpst;
|
||||||
|
|
||||||
/* UNDEF accesses to D16-D31 if they don't exist. */
|
if (!dc_isar_feature(aa32_fpdp_v2, s)) {
|
||||||
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_fpdp, s)) {
|
/* UNDEF accesses to D16-D31 if they don't exist. */
|
||||||
|
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2760,3 +2831,42 @@ static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a)
|
||||||
tcg_temp_free_ptr(fpst);
|
tcg_temp_free_ptr(fpst);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decode VLLDM and VLSTM are nonstandard because:
|
||||||
|
* * if there is no FPU then these insns must NOP in
|
||||||
|
* Secure state and UNDEF in Nonsecure state
|
||||||
|
* * if there is an FPU then these insns do not have
|
||||||
|
* the usual behaviour that vfp_access_check() provides of
|
||||||
|
* being controlled by CPACR/NSACR enable bits or the
|
||||||
|
* lazy-stacking logic.
|
||||||
|
*/
|
||||||
|
static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
|
||||||
|
{
|
||||||
|
TCGv_i32 fptr;
|
||||||
|
|
||||||
|
if (!arm_dc_feature(s, ARM_FEATURE_M) ||
|
||||||
|
!arm_dc_feature(s, ARM_FEATURE_V8)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* If not secure, UNDEF. */
|
||||||
|
if (!s->v8m_secure) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* If no fpu, NOP. */
|
||||||
|
if (!dc_isar_feature(aa32_vfp, s)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fptr = load_reg(s, a->rn);
|
||||||
|
if (a->l) {
|
||||||
|
gen_helper_v7m_vlldm(cpu_env, fptr);
|
||||||
|
} else {
|
||||||
|
gen_helper_v7m_vlstm(cpu_env, fptr);
|
||||||
|
}
|
||||||
|
tcg_temp_free_i32(fptr);
|
||||||
|
|
||||||
|
/* End the TB, because we have updated FP control bits */
|
||||||
|
s->base.is_jmp = DISAS_UPDATE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -2646,35 +2646,6 @@ static void gen_neon_dup_high16(TCGv_i32 var)
|
||||||
tcg_temp_free_i32(tmp);
|
tcg_temp_free_i32(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Disassemble a VFP instruction. Returns nonzero if an error occurred
|
|
||||||
* (ie. an undefined instruction).
|
|
||||||
*/
|
|
||||||
static int disas_vfp_insn(DisasContext *s, uint32_t insn)
|
|
||||||
{
|
|
||||||
if (!arm_dc_feature(s, ARM_FEATURE_VFP)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the decodetree decoder handles this insn it will always
|
|
||||||
* emit code to either execute the insn or generate an appropriate
|
|
||||||
* exception; so we don't need to ever return non-zero to tell
|
|
||||||
* the calling code to emit an UNDEF exception.
|
|
||||||
*/
|
|
||||||
if (extract32(insn, 28, 4) == 0xf) {
|
|
||||||
if (disas_vfp_uncond(s, insn)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (disas_vfp(s, insn)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* If the decodetree decoder didn't handle this insn, it must be UNDEF */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool use_goto_tb(DisasContext *s, target_ulong dest)
|
static inline bool use_goto_tb(DisasContext *s, target_ulong dest)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
@ -5150,7 +5121,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NEON_3R_VFM_VQRDMLSH:
|
case NEON_3R_VFM_VQRDMLSH:
|
||||||
if (!arm_dc_feature(s, ARM_FEATURE_VFP4)) {
|
if (!dc_isar_feature(aa32_simdfmac, s)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -10782,7 +10753,9 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||||
ARCH(5);
|
ARCH(5);
|
||||||
|
|
||||||
/* Unconditional instructions. */
|
/* Unconditional instructions. */
|
||||||
if (disas_a32_uncond(s, insn)) {
|
/* TODO: Perhaps merge these into one decodetree output file. */
|
||||||
|
if (disas_a32_uncond(s, insn) ||
|
||||||
|
disas_vfp_uncond(s, insn)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* fall back to legacy decoder */
|
/* fall back to legacy decoder */
|
||||||
|
@ -10809,13 +10782,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((insn & 0x0f000e10) == 0x0e000a00) {
|
|
||||||
/* VFP. */
|
|
||||||
if (disas_vfp_insn(s, insn)) {
|
|
||||||
goto illegal_op;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((insn & 0x0e000f00) == 0x0c000100) {
|
if ((insn & 0x0e000f00) == 0x0c000100) {
|
||||||
if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) {
|
if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) {
|
||||||
/* iWMMXt register transfer. */
|
/* iWMMXt register transfer. */
|
||||||
|
@ -10846,7 +10812,9 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||||
arm_skip_unless(s, cond);
|
arm_skip_unless(s, cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (disas_a32(s, insn)) {
|
/* TODO: Perhaps merge these into one decodetree output file. */
|
||||||
|
if (disas_a32(s, insn) ||
|
||||||
|
disas_vfp(s, insn)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* fall back to legacy decoder */
|
/* fall back to legacy decoder */
|
||||||
|
@ -10856,11 +10824,10 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||||
case 0xd:
|
case 0xd:
|
||||||
case 0xe:
|
case 0xe:
|
||||||
if (((insn >> 8) & 0xe) == 10) {
|
if (((insn >> 8) & 0xe) == 10) {
|
||||||
/* VFP. */
|
/* VFP, but failed disas_vfp. */
|
||||||
if (disas_vfp_insn(s, insn)) {
|
goto illegal_op;
|
||||||
goto illegal_op;
|
}
|
||||||
}
|
if (disas_coproc_insn(s, insn)) {
|
||||||
} else if (disas_coproc_insn(s, insn)) {
|
|
||||||
/* Coprocessor. */
|
/* Coprocessor. */
|
||||||
goto illegal_op;
|
goto illegal_op;
|
||||||
}
|
}
|
||||||
|
@ -10949,7 +10916,14 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
|
||||||
ARCH(6T2);
|
ARCH(6T2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (disas_t32(s, insn)) {
|
/*
|
||||||
|
* TODO: Perhaps merge these into one decodetree output file.
|
||||||
|
* Note disas_vfp is written for a32 with cond field in the
|
||||||
|
* top nibble. The t32 encoding requires 0xe in the top nibble.
|
||||||
|
*/
|
||||||
|
if (disas_t32(s, insn) ||
|
||||||
|
disas_vfp_uncond(s, insn) ||
|
||||||
|
((insn >> 28) == 0xe && disas_vfp(s, insn))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* fall back to legacy decoder */
|
/* fall back to legacy decoder */
|
||||||
|
@ -10966,53 +10940,16 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
|
||||||
goto illegal_op; /* op0 = 0b11 : unallocated */
|
goto illegal_op; /* op0 = 0b11 : unallocated */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (((insn >> 8) & 0xe) == 10 &&
|
||||||
* Decode VLLDM and VLSTM first: these are nonstandard because:
|
dc_isar_feature(aa32_fpsp_v2, s)) {
|
||||||
* * if there is no FPU then these insns must NOP in
|
|
||||||
* Secure state and UNDEF in Nonsecure state
|
|
||||||
* * if there is an FPU then these insns do not have
|
|
||||||
* the usual behaviour that disas_vfp_insn() provides of
|
|
||||||
* being controlled by CPACR/NSACR enable bits or the
|
|
||||||
* lazy-stacking logic.
|
|
||||||
*/
|
|
||||||
if (arm_dc_feature(s, ARM_FEATURE_V8) &&
|
|
||||||
(insn & 0xffa00f00) == 0xec200a00) {
|
|
||||||
/* 0b1110_1100_0x1x_xxxx_xxxx_1010_xxxx_xxxx
|
|
||||||
* - VLLDM, VLSTM
|
|
||||||
* We choose to UNDEF if the RAZ bits are non-zero.
|
|
||||||
*/
|
|
||||||
if (!s->v8m_secure || (insn & 0x0040f0ff)) {
|
|
||||||
goto illegal_op;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arm_dc_feature(s, ARM_FEATURE_VFP)) {
|
|
||||||
uint32_t rn = (insn >> 16) & 0xf;
|
|
||||||
TCGv_i32 fptr = load_reg(s, rn);
|
|
||||||
|
|
||||||
if (extract32(insn, 20, 1)) {
|
|
||||||
gen_helper_v7m_vlldm(cpu_env, fptr);
|
|
||||||
} else {
|
|
||||||
gen_helper_v7m_vlstm(cpu_env, fptr);
|
|
||||||
}
|
|
||||||
tcg_temp_free_i32(fptr);
|
|
||||||
|
|
||||||
/* End the TB, because we have updated FP control bits */
|
|
||||||
s->base.is_jmp = DISAS_UPDATE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (arm_dc_feature(s, ARM_FEATURE_VFP) &&
|
|
||||||
((insn >> 8) & 0xe) == 10) {
|
|
||||||
/* FP, and the CPU supports it */
|
/* FP, and the CPU supports it */
|
||||||
if (disas_vfp_insn(s, insn)) {
|
goto illegal_op;
|
||||||
goto illegal_op;
|
} else {
|
||||||
}
|
/* All other insns: NOCP */
|
||||||
break;
|
gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
|
||||||
|
syn_uncategorized(),
|
||||||
|
default_exception_el(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* All other insns: NOCP */
|
|
||||||
gen_exception_insn(s, s->pc_curr, EXCP_NOCP, syn_uncategorized(),
|
|
||||||
default_exception_el(s));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ((insn & 0xfe000a00) == 0xfc000800
|
if ((insn & 0xfe000a00) == 0xfc000800
|
||||||
|
@ -11034,9 +10971,8 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
|
||||||
goto illegal_op;
|
goto illegal_op;
|
||||||
}
|
}
|
||||||
} else if (((insn >> 8) & 0xe) == 10) {
|
} else if (((insn >> 8) & 0xe) == 10) {
|
||||||
if (disas_vfp_insn(s, insn)) {
|
/* VFP, but failed disas_vfp. */
|
||||||
goto illegal_op;
|
goto illegal_op;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (insn & (1 << 28))
|
if (insn & (1 << 28))
|
||||||
goto illegal_op;
|
goto illegal_op;
|
||||||
|
|
|
@ -41,15 +41,19 @@
|
||||||
%vd_dp 22:1 12:4
|
%vd_dp 22:1 12:4
|
||||||
%vd_sp 12:4 22:1
|
%vd_sp 12:4 22:1
|
||||||
|
|
||||||
|
@vfp_dnm_s ................................ vm=%vm_sp vn=%vn_sp vd=%vd_sp
|
||||||
|
@vfp_dnm_d ................................ vm=%vm_dp vn=%vn_dp vd=%vd_dp
|
||||||
|
|
||||||
VSEL 1111 1110 0. cc:2 .... .... 1010 .0.0 .... \
|
VSEL 1111 1110 0. cc:2 .... .... 1010 .0.0 .... \
|
||||||
vm=%vm_sp vn=%vn_sp vd=%vd_sp dp=0
|
vm=%vm_sp vn=%vn_sp vd=%vd_sp dp=0
|
||||||
VSEL 1111 1110 0. cc:2 .... .... 1011 .0.0 .... \
|
VSEL 1111 1110 0. cc:2 .... .... 1011 .0.0 .... \
|
||||||
vm=%vm_dp vn=%vn_dp vd=%vd_dp dp=1
|
vm=%vm_dp vn=%vn_dp vd=%vd_dp dp=1
|
||||||
|
|
||||||
VMINMAXNM 1111 1110 1.00 .... .... 1010 . op:1 .0 .... \
|
VMAXNM_sp 1111 1110 1.00 .... .... 1010 .0.0 .... @vfp_dnm_s
|
||||||
vm=%vm_sp vn=%vn_sp vd=%vd_sp dp=0
|
VMINNM_sp 1111 1110 1.00 .... .... 1010 .1.0 .... @vfp_dnm_s
|
||||||
VMINMAXNM 1111 1110 1.00 .... .... 1011 . op:1 .0 .... \
|
|
||||||
vm=%vm_dp vn=%vn_dp vd=%vd_dp dp=1
|
VMAXNM_dp 1111 1110 1.00 .... .... 1011 .0.0 .... @vfp_dnm_d
|
||||||
|
VMINNM_dp 1111 1110 1.00 .... .... 1011 .1.0 .... @vfp_dnm_d
|
||||||
|
|
||||||
VRINT 1111 1110 1.11 10 rm:2 .... 1010 01.0 .... \
|
VRINT 1111 1110 1.11 10 rm:2 .... 1010 01.0 .... \
|
||||||
vm=%vm_sp vd=%vd_sp dp=0
|
vm=%vm_sp vd=%vd_sp dp=0
|
||||||
|
|
|
@ -46,6 +46,14 @@
|
||||||
|
|
||||||
%vmov_imm 16:4 0:4
|
%vmov_imm 16:4 0:4
|
||||||
|
|
||||||
|
@vfp_dnm_s ................................ vm=%vm_sp vn=%vn_sp vd=%vd_sp
|
||||||
|
@vfp_dnm_d ................................ vm=%vm_dp vn=%vn_dp vd=%vd_dp
|
||||||
|
|
||||||
|
@vfp_dm_ss ................................ vm=%vm_sp vd=%vd_sp
|
||||||
|
@vfp_dm_dd ................................ vm=%vm_dp vd=%vd_dp
|
||||||
|
@vfp_dm_ds ................................ vm=%vm_sp vd=%vd_dp
|
||||||
|
@vfp_dm_sd ................................ vm=%vm_dp vd=%vd_sp
|
||||||
|
|
||||||
# VMOV scalar to general-purpose register; note that this does
|
# VMOV scalar to general-purpose register; note that this does
|
||||||
# include some Neon cases.
|
# include some Neon cases.
|
||||||
VMOV_to_gp ---- 1110 u:1 1. 1 .... rt:4 1011 ... 1 0000 \
|
VMOV_to_gp ---- 1110 u:1 1. 1 .... rt:4 1011 ... 1 0000 \
|
||||||
|
@ -66,20 +74,15 @@ VDUP ---- 1110 1 b:1 q:1 0 .... rt:4 1011 . 0 e:1 1 0000 \
|
||||||
vn=%vn_dp
|
vn=%vn_dp
|
||||||
|
|
||||||
VMSR_VMRS ---- 1110 111 l:1 reg:4 rt:4 1010 0001 0000
|
VMSR_VMRS ---- 1110 111 l:1 reg:4 rt:4 1010 0001 0000
|
||||||
VMOV_single ---- 1110 000 l:1 .... rt:4 1010 . 001 0000 \
|
VMOV_single ---- 1110 000 l:1 .... rt:4 1010 . 001 0000 vn=%vn_sp
|
||||||
vn=%vn_sp
|
|
||||||
|
|
||||||
VMOV_64_sp ---- 1100 010 op:1 rt2:4 rt:4 1010 00.1 .... \
|
VMOV_64_sp ---- 1100 010 op:1 rt2:4 rt:4 1010 00.1 .... vm=%vm_sp
|
||||||
vm=%vm_sp
|
VMOV_64_dp ---- 1100 010 op:1 rt2:4 rt:4 1011 00.1 .... vm=%vm_dp
|
||||||
VMOV_64_dp ---- 1100 010 op:1 rt2:4 rt:4 1011 00.1 .... \
|
|
||||||
vm=%vm_dp
|
|
||||||
|
|
||||||
# Note that the half-precision variants of VLDR and VSTR are
|
# Note that the half-precision variants of VLDR and VSTR are
|
||||||
# not part of this decodetree at all because they have bits [9:8] == 0b01
|
# not part of this decodetree at all because they have bits [9:8] == 0b01
|
||||||
VLDR_VSTR_sp ---- 1101 u:1 .0 l:1 rn:4 .... 1010 imm:8 \
|
VLDR_VSTR_sp ---- 1101 u:1 .0 l:1 rn:4 .... 1010 imm:8 vd=%vd_sp
|
||||||
vd=%vd_sp
|
VLDR_VSTR_dp ---- 1101 u:1 .0 l:1 rn:4 .... 1011 imm:8 vd=%vd_dp
|
||||||
VLDR_VSTR_dp ---- 1101 u:1 .0 l:1 rn:4 .... 1011 imm:8 \
|
|
||||||
vd=%vd_dp
|
|
||||||
|
|
||||||
# We split the load/store multiple up into two patterns to avoid
|
# We split the load/store multiple up into two patterns to avoid
|
||||||
# overlap with other insns in the "Advanced SIMD load/store and 64-bit move"
|
# overlap with other insns in the "Advanced SIMD load/store and 64-bit move"
|
||||||
|
@ -100,84 +103,59 @@ VLDM_VSTM_dp ---- 1101 0.1 l:1 rn:4 .... 1011 imm:8 \
|
||||||
vd=%vd_dp p=1 u=0 w=1
|
vd=%vd_dp p=1 u=0 w=1
|
||||||
|
|
||||||
# 3-register VFP data-processing; bits [23,21:20,6] identify the operation.
|
# 3-register VFP data-processing; bits [23,21:20,6] identify the operation.
|
||||||
VMLA_sp ---- 1110 0.00 .... .... 1010 .0.0 .... \
|
VMLA_sp ---- 1110 0.00 .... .... 1010 .0.0 .... @vfp_dnm_s
|
||||||
vm=%vm_sp vn=%vn_sp vd=%vd_sp
|
VMLA_dp ---- 1110 0.00 .... .... 1011 .0.0 .... @vfp_dnm_d
|
||||||
VMLA_dp ---- 1110 0.00 .... .... 1011 .0.0 .... \
|
|
||||||
vm=%vm_dp vn=%vn_dp vd=%vd_dp
|
|
||||||
|
|
||||||
VMLS_sp ---- 1110 0.00 .... .... 1010 .1.0 .... \
|
VMLS_sp ---- 1110 0.00 .... .... 1010 .1.0 .... @vfp_dnm_s
|
||||||
vm=%vm_sp vn=%vn_sp vd=%vd_sp
|
VMLS_dp ---- 1110 0.00 .... .... 1011 .1.0 .... @vfp_dnm_d
|
||||||
VMLS_dp ---- 1110 0.00 .... .... 1011 .1.0 .... \
|
|
||||||
vm=%vm_dp vn=%vn_dp vd=%vd_dp
|
|
||||||
|
|
||||||
VNMLS_sp ---- 1110 0.01 .... .... 1010 .0.0 .... \
|
VNMLS_sp ---- 1110 0.01 .... .... 1010 .0.0 .... @vfp_dnm_s
|
||||||
vm=%vm_sp vn=%vn_sp vd=%vd_sp
|
VNMLS_dp ---- 1110 0.01 .... .... 1011 .0.0 .... @vfp_dnm_d
|
||||||
VNMLS_dp ---- 1110 0.01 .... .... 1011 .0.0 .... \
|
|
||||||
vm=%vm_dp vn=%vn_dp vd=%vd_dp
|
|
||||||
|
|
||||||
VNMLA_sp ---- 1110 0.01 .... .... 1010 .1.0 .... \
|
VNMLA_sp ---- 1110 0.01 .... .... 1010 .1.0 .... @vfp_dnm_s
|
||||||
vm=%vm_sp vn=%vn_sp vd=%vd_sp
|
VNMLA_dp ---- 1110 0.01 .... .... 1011 .1.0 .... @vfp_dnm_d
|
||||||
VNMLA_dp ---- 1110 0.01 .... .... 1011 .1.0 .... \
|
|
||||||
vm=%vm_dp vn=%vn_dp vd=%vd_dp
|
|
||||||
|
|
||||||
VMUL_sp ---- 1110 0.10 .... .... 1010 .0.0 .... \
|
VMUL_sp ---- 1110 0.10 .... .... 1010 .0.0 .... @vfp_dnm_s
|
||||||
vm=%vm_sp vn=%vn_sp vd=%vd_sp
|
VMUL_dp ---- 1110 0.10 .... .... 1011 .0.0 .... @vfp_dnm_d
|
||||||
VMUL_dp ---- 1110 0.10 .... .... 1011 .0.0 .... \
|
|
||||||
vm=%vm_dp vn=%vn_dp vd=%vd_dp
|
|
||||||
|
|
||||||
VNMUL_sp ---- 1110 0.10 .... .... 1010 .1.0 .... \
|
VNMUL_sp ---- 1110 0.10 .... .... 1010 .1.0 .... @vfp_dnm_s
|
||||||
vm=%vm_sp vn=%vn_sp vd=%vd_sp
|
VNMUL_dp ---- 1110 0.10 .... .... 1011 .1.0 .... @vfp_dnm_d
|
||||||
VNMUL_dp ---- 1110 0.10 .... .... 1011 .1.0 .... \
|
|
||||||
vm=%vm_dp vn=%vn_dp vd=%vd_dp
|
|
||||||
|
|
||||||
VADD_sp ---- 1110 0.11 .... .... 1010 .0.0 .... \
|
VADD_sp ---- 1110 0.11 .... .... 1010 .0.0 .... @vfp_dnm_s
|
||||||
vm=%vm_sp vn=%vn_sp vd=%vd_sp
|
VADD_dp ---- 1110 0.11 .... .... 1011 .0.0 .... @vfp_dnm_d
|
||||||
VADD_dp ---- 1110 0.11 .... .... 1011 .0.0 .... \
|
|
||||||
vm=%vm_dp vn=%vn_dp vd=%vd_dp
|
|
||||||
|
|
||||||
VSUB_sp ---- 1110 0.11 .... .... 1010 .1.0 .... \
|
VSUB_sp ---- 1110 0.11 .... .... 1010 .1.0 .... @vfp_dnm_s
|
||||||
vm=%vm_sp vn=%vn_sp vd=%vd_sp
|
VSUB_dp ---- 1110 0.11 .... .... 1011 .1.0 .... @vfp_dnm_d
|
||||||
VSUB_dp ---- 1110 0.11 .... .... 1011 .1.0 .... \
|
|
||||||
vm=%vm_dp vn=%vn_dp vd=%vd_dp
|
|
||||||
|
|
||||||
VDIV_sp ---- 1110 1.00 .... .... 1010 .0.0 .... \
|
VDIV_sp ---- 1110 1.00 .... .... 1010 .0.0 .... @vfp_dnm_s
|
||||||
vm=%vm_sp vn=%vn_sp vd=%vd_sp
|
VDIV_dp ---- 1110 1.00 .... .... 1011 .0.0 .... @vfp_dnm_d
|
||||||
VDIV_dp ---- 1110 1.00 .... .... 1011 .0.0 .... \
|
|
||||||
vm=%vm_dp vn=%vn_dp vd=%vd_dp
|
|
||||||
|
|
||||||
VFM_sp ---- 1110 1.01 .... .... 1010 . o2:1 . 0 .... \
|
VFMA_sp ---- 1110 1.10 .... .... 1010 .0. 0 .... @vfp_dnm_s
|
||||||
vm=%vm_sp vn=%vn_sp vd=%vd_sp o1=1
|
VFMS_sp ---- 1110 1.10 .... .... 1010 .1. 0 .... @vfp_dnm_s
|
||||||
VFM_dp ---- 1110 1.01 .... .... 1011 . o2:1 . 0 .... \
|
VFNMA_sp ---- 1110 1.01 .... .... 1010 .0. 0 .... @vfp_dnm_s
|
||||||
vm=%vm_dp vn=%vn_dp vd=%vd_dp o1=1
|
VFNMS_sp ---- 1110 1.01 .... .... 1010 .1. 0 .... @vfp_dnm_s
|
||||||
VFM_sp ---- 1110 1.10 .... .... 1010 . o2:1 . 0 .... \
|
|
||||||
vm=%vm_sp vn=%vn_sp vd=%vd_sp o1=2
|
VFMA_dp ---- 1110 1.10 .... .... 1011 .0.0 .... @vfp_dnm_d
|
||||||
VFM_dp ---- 1110 1.10 .... .... 1011 . o2:1 . 0 .... \
|
VFMS_dp ---- 1110 1.10 .... .... 1011 .1.0 .... @vfp_dnm_d
|
||||||
vm=%vm_dp vn=%vn_dp vd=%vd_dp o1=2
|
VFNMA_dp ---- 1110 1.01 .... .... 1011 .0.0 .... @vfp_dnm_d
|
||||||
|
VFNMS_dp ---- 1110 1.01 .... .... 1011 .1.0 .... @vfp_dnm_d
|
||||||
|
|
||||||
VMOV_imm_sp ---- 1110 1.11 .... .... 1010 0000 .... \
|
VMOV_imm_sp ---- 1110 1.11 .... .... 1010 0000 .... \
|
||||||
vd=%vd_sp imm=%vmov_imm
|
vd=%vd_sp imm=%vmov_imm
|
||||||
VMOV_imm_dp ---- 1110 1.11 .... .... 1011 0000 .... \
|
VMOV_imm_dp ---- 1110 1.11 .... .... 1011 0000 .... \
|
||||||
vd=%vd_dp imm=%vmov_imm
|
vd=%vd_dp imm=%vmov_imm
|
||||||
|
|
||||||
VMOV_reg_sp ---- 1110 1.11 0000 .... 1010 01.0 .... \
|
VMOV_reg_sp ---- 1110 1.11 0000 .... 1010 01.0 .... @vfp_dm_ss
|
||||||
vd=%vd_sp vm=%vm_sp
|
VMOV_reg_dp ---- 1110 1.11 0000 .... 1011 01.0 .... @vfp_dm_dd
|
||||||
VMOV_reg_dp ---- 1110 1.11 0000 .... 1011 01.0 .... \
|
|
||||||
vd=%vd_dp vm=%vm_dp
|
|
||||||
|
|
||||||
VABS_sp ---- 1110 1.11 0000 .... 1010 11.0 .... \
|
VABS_sp ---- 1110 1.11 0000 .... 1010 11.0 .... @vfp_dm_ss
|
||||||
vd=%vd_sp vm=%vm_sp
|
VABS_dp ---- 1110 1.11 0000 .... 1011 11.0 .... @vfp_dm_dd
|
||||||
VABS_dp ---- 1110 1.11 0000 .... 1011 11.0 .... \
|
|
||||||
vd=%vd_dp vm=%vm_dp
|
|
||||||
|
|
||||||
VNEG_sp ---- 1110 1.11 0001 .... 1010 01.0 .... \
|
VNEG_sp ---- 1110 1.11 0001 .... 1010 01.0 .... @vfp_dm_ss
|
||||||
vd=%vd_sp vm=%vm_sp
|
VNEG_dp ---- 1110 1.11 0001 .... 1011 01.0 .... @vfp_dm_dd
|
||||||
VNEG_dp ---- 1110 1.11 0001 .... 1011 01.0 .... \
|
|
||||||
vd=%vd_dp vm=%vm_dp
|
|
||||||
|
|
||||||
VSQRT_sp ---- 1110 1.11 0001 .... 1010 11.0 .... \
|
VSQRT_sp ---- 1110 1.11 0001 .... 1010 11.0 .... @vfp_dm_ss
|
||||||
vd=%vd_sp vm=%vm_sp
|
VSQRT_dp ---- 1110 1.11 0001 .... 1011 11.0 .... @vfp_dm_dd
|
||||||
VSQRT_dp ---- 1110 1.11 0001 .... 1011 11.0 .... \
|
|
||||||
vd=%vd_dp vm=%vm_dp
|
|
||||||
|
|
||||||
VCMP_sp ---- 1110 1.11 010 z:1 .... 1010 e:1 1.0 .... \
|
VCMP_sp ---- 1110 1.11 010 z:1 .... 1010 e:1 1.0 .... \
|
||||||
vd=%vd_sp vm=%vm_sp
|
vd=%vd_sp vm=%vm_sp
|
||||||
|
@ -190,32 +168,26 @@ VCVT_f32_f16 ---- 1110 1.11 0010 .... 1010 t:1 1.0 .... \
|
||||||
VCVT_f64_f16 ---- 1110 1.11 0010 .... 1011 t:1 1.0 .... \
|
VCVT_f64_f16 ---- 1110 1.11 0010 .... 1011 t:1 1.0 .... \
|
||||||
vd=%vd_dp vm=%vm_sp
|
vd=%vd_dp vm=%vm_sp
|
||||||
|
|
||||||
# VCVTB and VCVTT to f16: Vd format is always vd_sp; Vm format depends on size bit
|
# VCVTB and VCVTT to f16: Vd format is always vd_sp;
|
||||||
|
# Vm format depends on size bit
|
||||||
VCVT_f16_f32 ---- 1110 1.11 0011 .... 1010 t:1 1.0 .... \
|
VCVT_f16_f32 ---- 1110 1.11 0011 .... 1010 t:1 1.0 .... \
|
||||||
vd=%vd_sp vm=%vm_sp
|
vd=%vd_sp vm=%vm_sp
|
||||||
VCVT_f16_f64 ---- 1110 1.11 0011 .... 1011 t:1 1.0 .... \
|
VCVT_f16_f64 ---- 1110 1.11 0011 .... 1011 t:1 1.0 .... \
|
||||||
vd=%vd_sp vm=%vm_dp
|
vd=%vd_sp vm=%vm_dp
|
||||||
|
|
||||||
VRINTR_sp ---- 1110 1.11 0110 .... 1010 01.0 .... \
|
VRINTR_sp ---- 1110 1.11 0110 .... 1010 01.0 .... @vfp_dm_ss
|
||||||
vd=%vd_sp vm=%vm_sp
|
VRINTR_dp ---- 1110 1.11 0110 .... 1011 01.0 .... @vfp_dm_dd
|
||||||
VRINTR_dp ---- 1110 1.11 0110 .... 1011 01.0 .... \
|
|
||||||
vd=%vd_dp vm=%vm_dp
|
|
||||||
|
|
||||||
VRINTZ_sp ---- 1110 1.11 0110 .... 1010 11.0 .... \
|
VRINTZ_sp ---- 1110 1.11 0110 .... 1010 11.0 .... @vfp_dm_ss
|
||||||
vd=%vd_sp vm=%vm_sp
|
VRINTZ_dp ---- 1110 1.11 0110 .... 1011 11.0 .... @vfp_dm_dd
|
||||||
VRINTZ_dp ---- 1110 1.11 0110 .... 1011 11.0 .... \
|
|
||||||
vd=%vd_dp vm=%vm_dp
|
|
||||||
|
|
||||||
VRINTX_sp ---- 1110 1.11 0111 .... 1010 01.0 .... \
|
VRINTX_sp ---- 1110 1.11 0111 .... 1010 01.0 .... @vfp_dm_ss
|
||||||
vd=%vd_sp vm=%vm_sp
|
VRINTX_dp ---- 1110 1.11 0111 .... 1011 01.0 .... @vfp_dm_dd
|
||||||
VRINTX_dp ---- 1110 1.11 0111 .... 1011 01.0 .... \
|
|
||||||
vd=%vd_dp vm=%vm_dp
|
|
||||||
|
|
||||||
# VCVT between single and double: Vm precision depends on size; Vd is its reverse
|
# VCVT between single and double:
|
||||||
VCVT_sp ---- 1110 1.11 0111 .... 1010 11.0 .... \
|
# Vm precision depends on size; Vd is its reverse
|
||||||
vd=%vd_dp vm=%vm_sp
|
VCVT_sp ---- 1110 1.11 0111 .... 1010 11.0 .... @vfp_dm_ds
|
||||||
VCVT_dp ---- 1110 1.11 0111 .... 1011 11.0 .... \
|
VCVT_dp ---- 1110 1.11 0111 .... 1011 11.0 .... @vfp_dm_sd
|
||||||
vd=%vd_sp vm=%vm_dp
|
|
||||||
|
|
||||||
# VCVT from integer to floating point: Vm always single; Vd depends on size
|
# VCVT from integer to floating point: Vm always single; Vd depends on size
|
||||||
VCVT_int_sp ---- 1110 1.11 1000 .... 1010 s:1 1.0 .... \
|
VCVT_int_sp ---- 1110 1.11 1000 .... 1010 s:1 1.0 .... \
|
||||||
|
@ -224,8 +196,7 @@ VCVT_int_dp ---- 1110 1.11 1000 .... 1011 s:1 1.0 .... \
|
||||||
vd=%vd_dp vm=%vm_sp
|
vd=%vd_dp vm=%vm_sp
|
||||||
|
|
||||||
# VJCVT is always dp to sp
|
# VJCVT is always dp to sp
|
||||||
VJCVT ---- 1110 1.11 1001 .... 1011 11.0 .... \
|
VJCVT ---- 1110 1.11 1001 .... 1011 11.0 .... @vfp_dm_sd
|
||||||
vd=%vd_sp vm=%vm_dp
|
|
||||||
|
|
||||||
# VCVT between floating-point and fixed-point. The immediate value
|
# VCVT between floating-point and fixed-point. The immediate value
|
||||||
# is in the same format as a Vm single-precision register number.
|
# is in the same format as a Vm single-precision register number.
|
||||||
|
@ -242,3 +213,5 @@ VCVT_sp_int ---- 1110 1.11 110 s:1 .... 1010 rz:1 1.0 .... \
|
||||||
vd=%vd_sp vm=%vm_sp
|
vd=%vd_sp vm=%vm_sp
|
||||||
VCVT_dp_int ---- 1110 1.11 110 s:1 .... 1011 rz:1 1.0 .... \
|
VCVT_dp_int ---- 1110 1.11 110 s:1 .... 1011 rz:1 1.0 .... \
|
||||||
vd=%vd_sp vm=%vm_dp
|
vd=%vd_sp vm=%vm_dp
|
||||||
|
|
||||||
|
VLLDM_VLSTM 1110 1100 001 l:1 rn:4 0000 1010 0000 0000
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
# Functional test that boots a Linux kernel and checks the console
|
||||||
|
#
|
||||||
|
# Copyright (c) 2020 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# Author:
|
||||||
|
# Thomas Huth <thuth@redhat.com>
|
||||||
|
#
|
||||||
|
# This work is licensed under the terms of the GNU GPL, version 2 or
|
||||||
|
# later. See the COPYING file in the top-level directory.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from avocado import skipUnless
|
||||||
|
from avocado_qemu import Test
|
||||||
|
from avocado_qemu import wait_for_console_pattern
|
||||||
|
|
||||||
|
|
||||||
|
NUMPY_AVAILABLE = True
|
||||||
|
try:
|
||||||
|
import numpy as np
|
||||||
|
except ImportError:
|
||||||
|
NUMPY_AVAILABLE = False
|
||||||
|
|
||||||
|
CV2_AVAILABLE = True
|
||||||
|
try:
|
||||||
|
import cv2
|
||||||
|
except ImportError:
|
||||||
|
CV2_AVAILABLE = False
|
||||||
|
|
||||||
|
|
||||||
|
class IntegratorMachine(Test):
|
||||||
|
|
||||||
|
timeout = 90
|
||||||
|
|
||||||
|
def boot_integratorcp(self):
|
||||||
|
kernel_url = ('https://github.com/zayac/qemu-arm/raw/master/'
|
||||||
|
'arm-test/kernel/zImage.integrator')
|
||||||
|
kernel_hash = '0d7adba893c503267c946a3cbdc63b4b54f25468'
|
||||||
|
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
|
||||||
|
|
||||||
|
initrd_url = ('https://github.com/zayac/qemu-arm/raw/master/'
|
||||||
|
'arm-test/kernel/arm_root.img')
|
||||||
|
initrd_hash = 'b51e4154285bf784e017a37586428332d8c7bd8b'
|
||||||
|
initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
|
||||||
|
|
||||||
|
self.vm.set_console()
|
||||||
|
self.vm.add_args('-kernel', kernel_path,
|
||||||
|
'-initrd', initrd_path,
|
||||||
|
'-append', 'printk.time=0 console=ttyAMA0')
|
||||||
|
self.vm.launch()
|
||||||
|
|
||||||
|
@skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
|
||||||
|
def test_integratorcp_console(self):
|
||||||
|
"""
|
||||||
|
Boots the Linux kernel and checks that the console is operational
|
||||||
|
:avocado: tags=arch:arm
|
||||||
|
:avocado: tags=machine:integratorcp
|
||||||
|
:avocado: tags=device:pl011
|
||||||
|
"""
|
||||||
|
self.boot_integratorcp()
|
||||||
|
wait_for_console_pattern(self, 'Log in as root')
|
||||||
|
|
||||||
|
@skipUnless(NUMPY_AVAILABLE, 'Python NumPy not installed')
|
||||||
|
@skipUnless(CV2_AVAILABLE, 'Python OpenCV not installed')
|
||||||
|
@skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
|
||||||
|
def test_framebuffer_tux_logo(self):
|
||||||
|
"""
|
||||||
|
Boot Linux and verify the Tux logo is displayed on the framebuffer.
|
||||||
|
:avocado: tags=arch:arm
|
||||||
|
:avocado: tags=machine:integratorcp
|
||||||
|
:avocado: tags=device:pl110
|
||||||
|
:avocado: tags=device:framebuffer
|
||||||
|
"""
|
||||||
|
screendump_path = os.path.join(self.workdir, "screendump.pbm")
|
||||||
|
tuxlogo_url = ('https://github.com/torvalds/linux/raw/v2.6.12/'
|
||||||
|
'drivers/video/logo/logo_linux_vga16.ppm')
|
||||||
|
tuxlogo_hash = '3991c2ddbd1ddaecda7601f8aafbcf5b02dc86af'
|
||||||
|
tuxlogo_path = self.fetch_asset(tuxlogo_url, asset_hash=tuxlogo_hash)
|
||||||
|
|
||||||
|
self.boot_integratorcp()
|
||||||
|
framebuffer_ready = 'Console: switching to colour frame buffer device'
|
||||||
|
wait_for_console_pattern(self, framebuffer_ready)
|
||||||
|
self.vm.command('human-monitor-command', command_line='stop')
|
||||||
|
self.vm.command('human-monitor-command',
|
||||||
|
command_line='screendump %s' % screendump_path)
|
||||||
|
logger = logging.getLogger('framebuffer')
|
||||||
|
|
||||||
|
cpu_count = 1
|
||||||
|
match_threshold = 0.92
|
||||||
|
screendump_bgr = cv2.imread(screendump_path)
|
||||||
|
screendump_gray = cv2.cvtColor(screendump_bgr, cv2.COLOR_BGR2GRAY)
|
||||||
|
result = cv2.matchTemplate(screendump_gray, cv2.imread(tuxlogo_path, 0),
|
||||||
|
cv2.TM_CCOEFF_NORMED)
|
||||||
|
loc = np.where(result >= match_threshold)
|
||||||
|
tux_count = 0
|
||||||
|
for tux_count, pt in enumerate(zip(*loc[::-1]), start=1):
|
||||||
|
logger.debug('found Tux at position [x, y] = %s', pt)
|
||||||
|
self.assertGreaterEqual(tux_count, cpu_count)
|
|
@ -0,0 +1,49 @@
|
||||||
|
# Functional test that boots a Linux kernel and checks the console
|
||||||
|
#
|
||||||
|
# Copyright (c) 2020 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# Author:
|
||||||
|
# Thomas Huth <thuth@redhat.com>
|
||||||
|
#
|
||||||
|
# This work is licensed under the terms of the GNU GPL, version 2 or
|
||||||
|
# later. See the COPYING file in the top-level directory.
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from avocado import skipUnless
|
||||||
|
from avocado_qemu import Test
|
||||||
|
from avocado_qemu import wait_for_console_pattern
|
||||||
|
|
||||||
|
class N8x0Machine(Test):
|
||||||
|
"""Boots the Linux kernel and checks that the console is operational"""
|
||||||
|
|
||||||
|
timeout = 90
|
||||||
|
|
||||||
|
def __do_test_n8x0(self):
|
||||||
|
kernel_url = ('http://stskeeps.subnetmask.net/meego-n8x0/'
|
||||||
|
'meego-arm-n8x0-1.0.80.20100712.1431-'
|
||||||
|
'vmlinuz-2.6.35~rc4-129.1-n8x0')
|
||||||
|
kernel_hash = 'e9d5ab8d7548923a0061b6fbf601465e479ed269'
|
||||||
|
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
|
||||||
|
|
||||||
|
self.vm.set_console(console_index=1)
|
||||||
|
self.vm.add_args('-kernel', kernel_path,
|
||||||
|
'-append', 'printk.time=0 console=ttyS1')
|
||||||
|
self.vm.launch()
|
||||||
|
wait_for_console_pattern(self, 'TSC2005 driver initializing')
|
||||||
|
|
||||||
|
@skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
|
||||||
|
def test_n800(self):
|
||||||
|
"""
|
||||||
|
:avocado: tags=arch:arm
|
||||||
|
:avocado: tags=machine:n800
|
||||||
|
"""
|
||||||
|
self.__do_test_n8x0()
|
||||||
|
|
||||||
|
@skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
|
||||||
|
def test_n810(self):
|
||||||
|
"""
|
||||||
|
:avocado: tags=arch:arm
|
||||||
|
:avocado: tags=machine:n810
|
||||||
|
"""
|
||||||
|
self.__do_test_n8x0()
|
Loading…
Reference in New Issue