target-arm queue:
* more MVE instructions * hw/gpio/gpio_pwr: use shutdown function for reboot * target/arm: Check NaN mode before silencing NaN * tests: Boot and halt a Linux guest on the Raspberry Pi 2 machine * hw/arm: Add basic power management to raspi. * docs/system/arm: Add quanta-gbs-bmc, quanta-q7l1-bmc -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmDfDacZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3hLREACwXLyfUWdqWpbW2wAHU4n9 SlNJjaKval707CBYQL03xvQyrSGinjaLmbljjE4Y3KV+XK/cRWXe/1bimBokk9Xt 8blX2OlEkBViqyTqPcSLU0AMMzoTYCRHMlR9tVbz4h39Z/yfcxzDKvWjjpor/vtw +0G8N/Z/O3TL2gSDAb7fQcdhS4pwsTBFOkOgGv06WxWUAidHxuguJOn0DF+mr1Tl hroz8fivG2RfQL/OVE6GJgD+VIlw+Ea4Znnuue+gdoCCvY4TE79K6kGSV9RZVg4d VGtzNd5m9UGFaeU+jof/45hD4ex4x+c5ggH6fDwx6pJhKpxYwsJBMvE8U4I2TfsG Hf7EjODxvJ5I78/qCyYJ+be2ZnqMcfqPVhU3MwqBwGMIuYMJRWH2b4eD3PmRWPBf fxrlEZ9PvzaONzwFDHJ06XiMhxByVF+kK4XNtBZZMWH0Jte8e1TPnY26PfNtvnfE lQYf4qETx3A2aYIG5zjXiIhGrH5/OevIBOkVKWvdEHXbVN0dt0JcjUbZee6MG9Q1 BN0xXlRQ2btsgYTvGVg08mkMi6LWl55j0CK/sx1qZPjnbgEyPq90kk6FKyflJhR5 fUdW1qCn+xRERMH+m8xIvkGzYTlmPal86BRwxBxyGrVRHpXDgWE3sw/m6p6wMsQZ Szx8eMJEAX5GNbF7M+KmCg== =mvVV -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20210702' into staging target-arm queue: * more MVE instructions * hw/gpio/gpio_pwr: use shutdown function for reboot * target/arm: Check NaN mode before silencing NaN * tests: Boot and halt a Linux guest on the Raspberry Pi 2 machine * hw/arm: Add basic power management to raspi. * docs/system/arm: Add quanta-gbs-bmc, quanta-q7l1-bmc # gpg: Signature made Fri 02 Jul 2021 13:59:19 BST # 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-20210702: (24 commits) target/arm: Implement MVE shifts by register target/arm: Implement MVE shifts by immediate target/arm: Implement MVE long shifts by register target/arm: Implement MVE long shifts by immediate target/arm: Implement MVE VADDLV target/arm: Implement MVE VSHLC target/arm: Implement MVE saturating narrowing shifts target/arm: Implement MVE VSHRN, VRSHRN target/arm: Implement MVE VSRI, VSLI target/arm: Implement MVE VSHLL target/arm: Implement MVE vector shift right by immediate insns target/arm: Implement MVE vector shift left by immediate insns target/arm: Implement MVE logical immediate insns target/arm: Use dup_const() instead of bitfield_replicate() target/arm: Use asimd_imm_const for A64 decode target/arm: Make asimd_imm_const() public target/arm: Fix bugs in MVE VRMLALDAVH, VRMLSLDAVH target/arm: Fix MVE widening/narrowing VLDR/VSTR offset calculation hw/gpio/gpio_pwr: use shutdown function for reboot target/arm: Check NaN mode before silencing NaN ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
73c8bf4ccf
@ -13,6 +13,7 @@ etc.
|
||||
AST2400 SoC based machines :
|
||||
|
||||
- ``palmetto-bmc`` OpenPOWER Palmetto POWER8 BMC
|
||||
- ``quanta-q71l-bmc`` OpenBMC Quanta BMC
|
||||
|
||||
AST2500 SoC based machines :
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
Nuvoton iBMC boards (``npcm750-evb``, ``quanta-gsj``)
|
||||
=====================================================
|
||||
Nuvoton iBMC boards (``*-bmc``, ``npcm750-evb``, ``quanta-gsj``)
|
||||
================================================================
|
||||
|
||||
The `Nuvoton iBMC`_ chips (NPCM7xx) are a family of ARM-based SoCs that are
|
||||
designed to be used as Baseboard Management Controllers (BMCs) in various
|
||||
@ -18,6 +18,7 @@ segment. The following machines are based on this chip :
|
||||
The NPCM730 SoC has two Cortex-A9 cores and is targeted for Data Center and
|
||||
Hyperscale applications. The following machines are based on this chip :
|
||||
|
||||
- ``quanta-gbs-bmc`` Quanta GBS server BMC
|
||||
- ``quanta-gsj`` Quanta GSJ server BMC
|
||||
|
||||
There are also two more SoCs, NPCM710 and NPCM705, which are single-core
|
||||
|
@ -126,6 +126,10 @@ static void bcm2835_peripherals_init(Object *obj)
|
||||
|
||||
object_property_add_const_link(OBJECT(&s->dwc2), "dma-mr",
|
||||
OBJECT(&s->gpu_bus_mr));
|
||||
|
||||
/* Power Management */
|
||||
object_initialize_child(obj, "powermgt", &s->powermgt,
|
||||
TYPE_BCM2835_POWERMGT);
|
||||
}
|
||||
|
||||
static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
|
||||
@ -364,9 +368,16 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
|
||||
qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
|
||||
INTERRUPT_USB));
|
||||
|
||||
/* Power Management */
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->powermgt), errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_add_subregion(&s->peri_mr, PM_OFFSET,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->powermgt), 0));
|
||||
|
||||
create_unimp(s, &s->txp, "bcm2835-txp", TXP_OFFSET, 0x1000);
|
||||
create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40);
|
||||
create_unimp(s, &s->powermgt, "bcm2835-powermgt", PM_OFFSET, 0x114);
|
||||
create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_OFFSET, 0x100);
|
||||
create_unimp(s, &s->smi, "bcm2835-smi", SMI_OFFSET, 0x100);
|
||||
create_unimp(s, &s->spi[0], "bcm2835-spi0", SPI0_OFFSET, 0x20);
|
||||
|
@ -43,7 +43,7 @@ static void gpio_pwr_reset(void *opaque, int n, int level)
|
||||
static void gpio_pwr_shutdown(void *opaque, int n, int level)
|
||||
{
|
||||
if (level) {
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
|
||||
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
|
||||
}
|
||||
}
|
||||
|
||||
|
160
hw/misc/bcm2835_powermgt.c
Normal file
160
hw/misc/bcm2835_powermgt.c
Normal file
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* BCM2835 Power Management emulation
|
||||
*
|
||||
* Copyright (C) 2017 Marcin Chojnacki <marcinch7@gmail.com>
|
||||
* Copyright (C) 2021 Nolan Leake <nolan@sigbus.net>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "hw/misc/bcm2835_powermgt.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "sysemu/runstate.h"
|
||||
|
||||
#define PASSWORD 0x5a000000
|
||||
#define PASSWORD_MASK 0xff000000
|
||||
|
||||
#define R_RSTC 0x1c
|
||||
#define V_RSTC_RESET 0x20
|
||||
#define R_RSTS 0x20
|
||||
#define V_RSTS_POWEROFF 0x555 /* Linux uses partition 63 to indicate halt. */
|
||||
#define R_WDOG 0x24
|
||||
|
||||
static uint64_t bcm2835_powermgt_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
BCM2835PowerMgtState *s = (BCM2835PowerMgtState *)opaque;
|
||||
uint32_t res = 0;
|
||||
|
||||
switch (offset) {
|
||||
case R_RSTC:
|
||||
res = s->rstc;
|
||||
break;
|
||||
case R_RSTS:
|
||||
res = s->rsts;
|
||||
break;
|
||||
case R_WDOG:
|
||||
res = s->wdog;
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"bcm2835_powermgt_read: Unknown offset 0x%08"HWADDR_PRIx
|
||||
"\n", offset);
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void bcm2835_powermgt_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
BCM2835PowerMgtState *s = (BCM2835PowerMgtState *)opaque;
|
||||
|
||||
if ((value & PASSWORD_MASK) != PASSWORD) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"bcm2835_powermgt_write: Bad password 0x%"PRIx64
|
||||
" at offset 0x%08"HWADDR_PRIx"\n",
|
||||
value, offset);
|
||||
return;
|
||||
}
|
||||
|
||||
value = value & ~PASSWORD_MASK;
|
||||
|
||||
switch (offset) {
|
||||
case R_RSTC:
|
||||
s->rstc = value;
|
||||
if (value & V_RSTC_RESET) {
|
||||
if ((s->rsts & 0xfff) == V_RSTS_POWEROFF) {
|
||||
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
|
||||
} else {
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case R_RSTS:
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"bcm2835_powermgt_write: RSTS\n");
|
||||
s->rsts = value;
|
||||
break;
|
||||
case R_WDOG:
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"bcm2835_powermgt_write: WDOG\n");
|
||||
s->wdog = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"bcm2835_powermgt_write: Unknown offset 0x%08"HWADDR_PRIx
|
||||
"\n", offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps bcm2835_powermgt_ops = {
|
||||
.read = bcm2835_powermgt_read,
|
||||
.write = bcm2835_powermgt_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.impl.min_access_size = 4,
|
||||
.impl.max_access_size = 4,
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_bcm2835_powermgt = {
|
||||
.name = TYPE_BCM2835_POWERMGT,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(rstc, BCM2835PowerMgtState),
|
||||
VMSTATE_UINT32(rsts, BCM2835PowerMgtState),
|
||||
VMSTATE_UINT32(wdog, BCM2835PowerMgtState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void bcm2835_powermgt_init(Object *obj)
|
||||
{
|
||||
BCM2835PowerMgtState *s = BCM2835_POWERMGT(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &bcm2835_powermgt_ops, s,
|
||||
TYPE_BCM2835_POWERMGT, 0x200);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
|
||||
}
|
||||
|
||||
static void bcm2835_powermgt_reset(DeviceState *dev)
|
||||
{
|
||||
BCM2835PowerMgtState *s = BCM2835_POWERMGT(dev);
|
||||
|
||||
/* https://elinux.org/BCM2835_registers#PM */
|
||||
s->rstc = 0x00000102;
|
||||
s->rsts = 0x00001000;
|
||||
s->wdog = 0x00000000;
|
||||
}
|
||||
|
||||
static void bcm2835_powermgt_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->reset = bcm2835_powermgt_reset;
|
||||
dc->vmsd = &vmstate_bcm2835_powermgt;
|
||||
}
|
||||
|
||||
static TypeInfo bcm2835_powermgt_info = {
|
||||
.name = TYPE_BCM2835_POWERMGT,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(BCM2835PowerMgtState),
|
||||
.class_init = bcm2835_powermgt_class_init,
|
||||
.instance_init = bcm2835_powermgt_init,
|
||||
};
|
||||
|
||||
static void bcm2835_powermgt_register_types(void)
|
||||
{
|
||||
type_register_static(&bcm2835_powermgt_info);
|
||||
}
|
||||
|
||||
type_init(bcm2835_powermgt_register_types)
|
@ -82,6 +82,7 @@ softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files(
|
||||
'bcm2835_rng.c',
|
||||
'bcm2835_thermal.c',
|
||||
'bcm2835_cprman.c',
|
||||
'bcm2835_powermgt.c',
|
||||
))
|
||||
softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c', 'zynq-xadc.c'))
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "hw/misc/bcm2835_mphi.h"
|
||||
#include "hw/misc/bcm2835_thermal.h"
|
||||
#include "hw/misc/bcm2835_cprman.h"
|
||||
#include "hw/misc/bcm2835_powermgt.h"
|
||||
#include "hw/sd/sdhci.h"
|
||||
#include "hw/sd/bcm2835_sdhost.h"
|
||||
#include "hw/gpio/bcm2835_gpio.h"
|
||||
@ -48,7 +49,7 @@ struct BCM2835PeripheralState {
|
||||
BCM2835MphiState mphi;
|
||||
UnimplementedDeviceState txp;
|
||||
UnimplementedDeviceState armtmr;
|
||||
UnimplementedDeviceState powermgt;
|
||||
BCM2835PowerMgtState powermgt;
|
||||
BCM2835CprmanState cprman;
|
||||
PL011State uart0;
|
||||
BCM2835AuxState aux;
|
||||
|
29
include/hw/misc/bcm2835_powermgt.h
Normal file
29
include/hw/misc/bcm2835_powermgt.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* BCM2835 Power Management emulation
|
||||
*
|
||||
* Copyright (C) 2017 Marcin Chojnacki <marcinch7@gmail.com>
|
||||
* Copyright (C) 2021 Nolan Leake <nolan@sigbus.net>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef BCM2835_POWERMGT_H
|
||||
#define BCM2835_POWERMGT_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_BCM2835_POWERMGT "bcm2835-powermgt"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(BCM2835PowerMgtState, BCM2835_POWERMGT)
|
||||
|
||||
struct BCM2835PowerMgtState {
|
||||
SysBusDevice busdev;
|
||||
MemoryRegion iomem;
|
||||
|
||||
uint32_t rstc;
|
||||
uint32_t rsts;
|
||||
uint32_t wdog;
|
||||
};
|
||||
|
||||
#endif
|
@ -365,7 +365,9 @@ uint32_t HELPER(frecpx_f16)(uint32_t a, void *fpstp)
|
||||
float16 nan = a;
|
||||
if (float16_is_signaling_nan(a, fpst)) {
|
||||
float_raise(float_flag_invalid, fpst);
|
||||
nan = float16_silence_nan(a, fpst);
|
||||
if (!fpst->default_nan_mode) {
|
||||
nan = float16_silence_nan(a, fpst);
|
||||
}
|
||||
}
|
||||
if (fpst->default_nan_mode) {
|
||||
nan = float16_default_nan(fpst);
|
||||
@ -396,7 +398,9 @@ float32 HELPER(frecpx_f32)(float32 a, void *fpstp)
|
||||
float32 nan = a;
|
||||
if (float32_is_signaling_nan(a, fpst)) {
|
||||
float_raise(float_flag_invalid, fpst);
|
||||
nan = float32_silence_nan(a, fpst);
|
||||
if (!fpst->default_nan_mode) {
|
||||
nan = float32_silence_nan(a, fpst);
|
||||
}
|
||||
}
|
||||
if (fpst->default_nan_mode) {
|
||||
nan = float32_default_nan(fpst);
|
||||
@ -427,7 +431,9 @@ float64 HELPER(frecpx_f64)(float64 a, void *fpstp)
|
||||
float64 nan = a;
|
||||
if (float64_is_signaling_nan(a, fpst)) {
|
||||
float_raise(float_flag_invalid, fpst);
|
||||
nan = float64_silence_nan(a, fpst);
|
||||
if (!fpst->default_nan_mode) {
|
||||
nan = float64_silence_nan(a, fpst);
|
||||
}
|
||||
}
|
||||
if (fpst->default_nan_mode) {
|
||||
nan = float64_default_nan(fpst);
|
||||
|
@ -355,3 +355,111 @@ DEF_HELPER_FLAGS_3(mve_vaddvsh, TCG_CALL_NO_WG, i32, env, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_vaddvuh, TCG_CALL_NO_WG, i32, env, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_vaddvsw, TCG_CALL_NO_WG, i32, env, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_vaddvuw, TCG_CALL_NO_WG, i32, env, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_3(mve_vaddlv_s, TCG_CALL_NO_WG, i64, env, ptr, i64)
|
||||
DEF_HELPER_FLAGS_3(mve_vaddlv_u, TCG_CALL_NO_WG, i64, env, ptr, i64)
|
||||
|
||||
DEF_HELPER_FLAGS_3(mve_vmovi, TCG_CALL_NO_WG, void, env, ptr, i64)
|
||||
DEF_HELPER_FLAGS_3(mve_vandi, TCG_CALL_NO_WG, void, env, ptr, i64)
|
||||
DEF_HELPER_FLAGS_3(mve_vorri, TCG_CALL_NO_WG, void, env, ptr, i64)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vshli_sb, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vshli_sh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vshli_sw, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vshli_ub, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vshli_uh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vshli_uw, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vqshli_sb, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqshli_sh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqshli_sw, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vqshli_ub, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqshli_uh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqshli_uw, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vqshlui_sb, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqshlui_sh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqshlui_sw, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vrshli_sb, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vrshli_sh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vrshli_sw, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vrshli_ub, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vrshli_uh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vrshli_uw, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vshllbsb, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vshllbsh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vshllbub, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vshllbuh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vshlltsb, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vshlltsh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vshlltub, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vshlltuh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vsrib, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vsrih, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vsriw, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vslib, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vslih, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vsliw, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vshrnbb, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vshrnbh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vshrntb, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vshrnth, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vrshrnbb, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vrshrnbh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vrshrntb, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vrshrnth, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vqshrnb_sb, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqshrnb_sh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqshrnt_sb, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqshrnt_sh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vqshrnb_ub, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqshrnb_uh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqshrnt_ub, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqshrnt_uh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vqshrunbb, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqshrunbh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqshruntb, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqshrunth, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vqrshrnb_sb, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqrshrnb_sh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqrshrnt_sb, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqrshrnt_sh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vqrshrnb_ub, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqrshrnb_uh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqrshrnt_ub, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqrshrnt_uh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vqrshrunbb, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqrshrunbh, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqrshruntb, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(mve_vqrshrunth, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(mve_vshlc, TCG_CALL_NO_WG, i32, env, ptr, i32, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_3(mve_sshrl, TCG_CALL_NO_RWG, i64, env, i64, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_ushll, TCG_CALL_NO_RWG, i64, env, i64, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_sqshll, TCG_CALL_NO_RWG, i64, env, i64, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_uqshll, TCG_CALL_NO_RWG, i64, env, i64, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_sqrshrl, TCG_CALL_NO_RWG, i64, env, i64, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_uqrshll, TCG_CALL_NO_RWG, i64, env, i64, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_sqrshrl48, TCG_CALL_NO_RWG, i64, env, i64, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_uqrshll48, TCG_CALL_NO_RWG, i64, env, i64, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_3(mve_uqshl, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_sqshl, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_uqrshl, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_sqrshr, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
|
@ -26,10 +26,15 @@
|
||||
# VQDMULL has size in bit 28: 0 for 16 bit, 1 for 32 bit
|
||||
%size_28 28:1 !function=plus_1
|
||||
|
||||
# 1imm format immediate
|
||||
%imm_28_16_0 28:1 16:3 0:4
|
||||
|
||||
&vldr_vstr rn qd imm p a w size l u
|
||||
&1op qd qm size
|
||||
&2op qd qm qn size
|
||||
&2scalar qd qn rm size
|
||||
&1imm qd imm cmode op
|
||||
&2shift qd qm shift size
|
||||
|
||||
@vldr_vstr ....... . . . . l:1 rn:4 ... ...... imm:7 &vldr_vstr qd=%qd u=0
|
||||
# Note that both Rn and Qd are 3 bits only (no D bit)
|
||||
@ -41,6 +46,7 @@
|
||||
@2op_nosz .... .... .... .... .... .... .... .... &2op qd=%qd qm=%qm qn=%qn size=0
|
||||
@2op_sz28 .... .... .... .... .... .... .... .... &2op qd=%qd qm=%qm qn=%qn \
|
||||
size=%size_28
|
||||
@1imm .... .... .... .... .... cmode:4 .. op:1 . .... &1imm qd=%qd imm=%imm_28_16_0
|
||||
|
||||
# The _rev suffix indicates that Vn and Vm are reversed. This is
|
||||
# the case for shifts. In the Arm ARM these insns are documented
|
||||
@ -54,6 +60,30 @@
|
||||
@2scalar .... .... .. size:2 .... .... .... .... rm:4 &2scalar qd=%qd qn=%qn
|
||||
@2scalar_nosz .... .... .... .... .... .... .... rm:4 &2scalar qd=%qd qn=%qn
|
||||
|
||||
@2_shl_b .... .... .. 001 shift:3 .... .... .... .... &2shift qd=%qd qm=%qm size=0
|
||||
@2_shl_h .... .... .. 01 shift:4 .... .... .... .... &2shift qd=%qd qm=%qm size=1
|
||||
@2_shl_w .... .... .. 1 shift:5 .... .... .... .... &2shift qd=%qd qm=%qm size=2
|
||||
|
||||
@2_shll_b .... .... ... 01 shift:3 .... .... .... .... &2shift qd=%qd qm=%qm size=0
|
||||
@2_shll_h .... .... ... 1 shift:4 .... .... .... .... &2shift qd=%qd qm=%qm size=1
|
||||
# VSHLL encoding T2 where shift == esize
|
||||
@2_shll_esize_b .... .... .... 00 .. .... .... .... .... &2shift \
|
||||
qd=%qd qm=%qm size=0 shift=8
|
||||
@2_shll_esize_h .... .... .... 01 .. .... .... .... .... &2shift \
|
||||
qd=%qd qm=%qm size=1 shift=16
|
||||
|
||||
# Right shifts are encoded as N - shift, where N is the element size in bits.
|
||||
%rshift_i5 16:5 !function=rsub_32
|
||||
%rshift_i4 16:4 !function=rsub_16
|
||||
%rshift_i3 16:3 !function=rsub_8
|
||||
|
||||
@2_shr_b .... .... .. 001 ... .... .... .... .... &2shift qd=%qd qm=%qm \
|
||||
size=0 shift=%rshift_i3
|
||||
@2_shr_h .... .... .. 01 .... .... .... .... .... &2shift qd=%qd qm=%qm \
|
||||
size=1 shift=%rshift_i4
|
||||
@2_shr_w .... .... .. 1 ..... .... .... .... .... &2shift qd=%qd qm=%qm \
|
||||
size=2 shift=%rshift_i5
|
||||
|
||||
# Vector loads and stores
|
||||
|
||||
# Widening loads and narrowing stores:
|
||||
@ -100,11 +130,35 @@ VADD 1110 1111 0 . .. ... 0 ... 0 1000 . 1 . 0 ... 0 @2op
|
||||
VSUB 1111 1111 0 . .. ... 0 ... 0 1000 . 1 . 0 ... 0 @2op
|
||||
VMUL 1110 1111 0 . .. ... 0 ... 0 1001 . 1 . 1 ... 0 @2op
|
||||
|
||||
VMULH_S 111 0 1110 0 . .. ...1 ... 0 1110 . 0 . 0 ... 1 @2op
|
||||
VMULH_U 111 1 1110 0 . .. ...1 ... 0 1110 . 0 . 0 ... 1 @2op
|
||||
# The VSHLL T2 encoding is not a @2op pattern, but is here because it
|
||||
# overlaps what would be size=0b11 VMULH/VRMULH
|
||||
{
|
||||
VSHLL_BS 111 0 1110 0 . 11 .. 01 ... 0 1110 0 0 . 0 ... 1 @2_shll_esize_b
|
||||
VSHLL_BS 111 0 1110 0 . 11 .. 01 ... 0 1110 0 0 . 0 ... 1 @2_shll_esize_h
|
||||
|
||||
VRMULH_S 111 0 1110 0 . .. ...1 ... 1 1110 . 0 . 0 ... 1 @2op
|
||||
VRMULH_U 111 1 1110 0 . .. ...1 ... 1 1110 . 0 . 0 ... 1 @2op
|
||||
VMULH_S 111 0 1110 0 . .. ...1 ... 0 1110 . 0 . 0 ... 1 @2op
|
||||
}
|
||||
|
||||
{
|
||||
VSHLL_BU 111 1 1110 0 . 11 .. 01 ... 0 1110 0 0 . 0 ... 1 @2_shll_esize_b
|
||||
VSHLL_BU 111 1 1110 0 . 11 .. 01 ... 0 1110 0 0 . 0 ... 1 @2_shll_esize_h
|
||||
|
||||
VMULH_U 111 1 1110 0 . .. ...1 ... 0 1110 . 0 . 0 ... 1 @2op
|
||||
}
|
||||
|
||||
{
|
||||
VSHLL_TS 111 0 1110 0 . 11 .. 01 ... 1 1110 0 0 . 0 ... 1 @2_shll_esize_b
|
||||
VSHLL_TS 111 0 1110 0 . 11 .. 01 ... 1 1110 0 0 . 0 ... 1 @2_shll_esize_h
|
||||
|
||||
VRMULH_S 111 0 1110 0 . .. ...1 ... 1 1110 . 0 . 0 ... 1 @2op
|
||||
}
|
||||
|
||||
{
|
||||
VSHLL_TU 111 1 1110 0 . 11 .. 01 ... 1 1110 0 0 . 0 ... 1 @2_shll_esize_b
|
||||
VSHLL_TU 111 1 1110 0 . 11 .. 01 ... 1 1110 0 0 . 0 ... 1 @2_shll_esize_h
|
||||
|
||||
VRMULH_U 111 1 1110 0 . .. ...1 ... 1 1110 . 0 . 0 ... 1 @2op
|
||||
}
|
||||
|
||||
VMAX_S 111 0 1111 0 . .. ... 0 ... 0 0110 . 1 . 0 ... 0 @2op
|
||||
VMAX_U 111 1 1111 0 . .. ... 0 ... 0 0110 . 1 . 0 ... 0 @2op
|
||||
@ -253,8 +307,121 @@ VQDMULH_scalar 1110 1110 0 . .. ... 1 ... 0 1110 . 110 .... @2scalar
|
||||
VQRDMULH_scalar 1111 1110 0 . .. ... 1 ... 0 1110 . 110 .... @2scalar
|
||||
|
||||
# Vector add across vector
|
||||
VADDV 111 u:1 1110 1111 size:2 01 ... 0 1111 0 0 a:1 0 qm:3 0 rda=%rdalo
|
||||
{
|
||||
VADDV 111 u:1 1110 1111 size:2 01 ... 0 1111 0 0 a:1 0 qm:3 0 rda=%rdalo
|
||||
VADDLV 111 u:1 1110 1 ... 1001 ... 0 1111 00 a:1 0 qm:3 0 \
|
||||
rdahi=%rdahi rdalo=%rdalo
|
||||
}
|
||||
|
||||
# Predicate operations
|
||||
%mask_22_13 22:1 13:3
|
||||
VPST 1111 1110 0 . 11 000 1 ... 0 1111 0100 1101 mask=%mask_22_13
|
||||
|
||||
# Logical immediate operations (1 reg and modified-immediate)
|
||||
|
||||
# The cmode/op bits here decode VORR/VBIC/VMOV/VMVN, but
|
||||
# not in a way we can conveniently represent in decodetree without
|
||||
# a lot of repetition:
|
||||
# VORR: op=0, (cmode & 1) && cmode < 12
|
||||
# VBIC: op=1, (cmode & 1) && cmode < 12
|
||||
# VMOV: everything else
|
||||
# So we have a single decode line and check the cmode/op in the
|
||||
# trans function.
|
||||
Vimm_1r 111 . 1111 1 . 00 0 ... ... 0 .... 0 1 . 1 .... @1imm
|
||||
|
||||
# Shifts by immediate
|
||||
|
||||
VSHLI 111 0 1111 1 . ... ... ... 0 0101 0 1 . 1 ... 0 @2_shl_b
|
||||
VSHLI 111 0 1111 1 . ... ... ... 0 0101 0 1 . 1 ... 0 @2_shl_h
|
||||
VSHLI 111 0 1111 1 . ... ... ... 0 0101 0 1 . 1 ... 0 @2_shl_w
|
||||
|
||||
VQSHLI_S 111 0 1111 1 . ... ... ... 0 0111 0 1 . 1 ... 0 @2_shl_b
|
||||
VQSHLI_S 111 0 1111 1 . ... ... ... 0 0111 0 1 . 1 ... 0 @2_shl_h
|
||||
VQSHLI_S 111 0 1111 1 . ... ... ... 0 0111 0 1 . 1 ... 0 @2_shl_w
|
||||
|
||||
VQSHLI_U 111 1 1111 1 . ... ... ... 0 0111 0 1 . 1 ... 0 @2_shl_b
|
||||
VQSHLI_U 111 1 1111 1 . ... ... ... 0 0111 0 1 . 1 ... 0 @2_shl_h
|
||||
VQSHLI_U 111 1 1111 1 . ... ... ... 0 0111 0 1 . 1 ... 0 @2_shl_w
|
||||
|
||||
VQSHLUI 111 1 1111 1 . ... ... ... 0 0110 0 1 . 1 ... 0 @2_shl_b
|
||||
VQSHLUI 111 1 1111 1 . ... ... ... 0 0110 0 1 . 1 ... 0 @2_shl_h
|
||||
VQSHLUI 111 1 1111 1 . ... ... ... 0 0110 0 1 . 1 ... 0 @2_shl_w
|
||||
|
||||
VSHRI_S 111 0 1111 1 . ... ... ... 0 0000 0 1 . 1 ... 0 @2_shr_b
|
||||
VSHRI_S 111 0 1111 1 . ... ... ... 0 0000 0 1 . 1 ... 0 @2_shr_h
|
||||
VSHRI_S 111 0 1111 1 . ... ... ... 0 0000 0 1 . 1 ... 0 @2_shr_w
|
||||
|
||||
VSHRI_U 111 1 1111 1 . ... ... ... 0 0000 0 1 . 1 ... 0 @2_shr_b
|
||||
VSHRI_U 111 1 1111 1 . ... ... ... 0 0000 0 1 . 1 ... 0 @2_shr_h
|
||||
VSHRI_U 111 1 1111 1 . ... ... ... 0 0000 0 1 . 1 ... 0 @2_shr_w
|
||||
|
||||
VRSHRI_S 111 0 1111 1 . ... ... ... 0 0010 0 1 . 1 ... 0 @2_shr_b
|
||||
VRSHRI_S 111 0 1111 1 . ... ... ... 0 0010 0 1 . 1 ... 0 @2_shr_h
|
||||
VRSHRI_S 111 0 1111 1 . ... ... ... 0 0010 0 1 . 1 ... 0 @2_shr_w
|
||||
|
||||
VRSHRI_U 111 1 1111 1 . ... ... ... 0 0010 0 1 . 1 ... 0 @2_shr_b
|
||||
VRSHRI_U 111 1 1111 1 . ... ... ... 0 0010 0 1 . 1 ... 0 @2_shr_h
|
||||
VRSHRI_U 111 1 1111 1 . ... ... ... 0 0010 0 1 . 1 ... 0 @2_shr_w
|
||||
|
||||
# VSHLL T1 encoding; the T2 VSHLL encoding is elsewhere in this file
|
||||
VSHLL_BS 111 0 1110 1 . 1 .. ... ... 0 1111 0 1 . 0 ... 0 @2_shll_b
|
||||
VSHLL_BS 111 0 1110 1 . 1 .. ... ... 0 1111 0 1 . 0 ... 0 @2_shll_h
|
||||
|
||||
VSHLL_BU 111 1 1110 1 . 1 .. ... ... 0 1111 0 1 . 0 ... 0 @2_shll_b
|
||||
VSHLL_BU 111 1 1110 1 . 1 .. ... ... 0 1111 0 1 . 0 ... 0 @2_shll_h
|
||||
|
||||
VSHLL_TS 111 0 1110 1 . 1 .. ... ... 1 1111 0 1 . 0 ... 0 @2_shll_b
|
||||
VSHLL_TS 111 0 1110 1 . 1 .. ... ... 1 1111 0 1 . 0 ... 0 @2_shll_h
|
||||
|
||||
VSHLL_TU 111 1 1110 1 . 1 .. ... ... 1 1111 0 1 . 0 ... 0 @2_shll_b
|
||||
VSHLL_TU 111 1 1110 1 . 1 .. ... ... 1 1111 0 1 . 0 ... 0 @2_shll_h
|
||||
|
||||
# Shift-and-insert
|
||||
VSRI 111 1 1111 1 . ... ... ... 0 0100 0 1 . 1 ... 0 @2_shr_b
|
||||
VSRI 111 1 1111 1 . ... ... ... 0 0100 0 1 . 1 ... 0 @2_shr_h
|
||||
VSRI 111 1 1111 1 . ... ... ... 0 0100 0 1 . 1 ... 0 @2_shr_w
|
||||
|
||||
VSLI 111 1 1111 1 . ... ... ... 0 0101 0 1 . 1 ... 0 @2_shl_b
|
||||
VSLI 111 1 1111 1 . ... ... ... 0 0101 0 1 . 1 ... 0 @2_shl_h
|
||||
VSLI 111 1 1111 1 . ... ... ... 0 0101 0 1 . 1 ... 0 @2_shl_w
|
||||
|
||||
# Narrowing shifts (which only support b and h sizes)
|
||||
VSHRNB 111 0 1110 1 . ... ... ... 0 1111 1 1 . 0 ... 1 @2_shr_b
|
||||
VSHRNB 111 0 1110 1 . ... ... ... 0 1111 1 1 . 0 ... 1 @2_shr_h
|
||||
VSHRNT 111 0 1110 1 . ... ... ... 1 1111 1 1 . 0 ... 1 @2_shr_b
|
||||
VSHRNT 111 0 1110 1 . ... ... ... 1 1111 1 1 . 0 ... 1 @2_shr_h
|
||||
|
||||
VRSHRNB 111 1 1110 1 . ... ... ... 0 1111 1 1 . 0 ... 1 @2_shr_b
|
||||
VRSHRNB 111 1 1110 1 . ... ... ... 0 1111 1 1 . 0 ... 1 @2_shr_h
|
||||
VRSHRNT 111 1 1110 1 . ... ... ... 1 1111 1 1 . 0 ... 1 @2_shr_b
|
||||
VRSHRNT 111 1 1110 1 . ... ... ... 1 1111 1 1 . 0 ... 1 @2_shr_h
|
||||
|
||||
VQSHRNB_S 111 0 1110 1 . ... ... ... 0 1111 0 1 . 0 ... 0 @2_shr_b
|
||||
VQSHRNB_S 111 0 1110 1 . ... ... ... 0 1111 0 1 . 0 ... 0 @2_shr_h
|
||||
VQSHRNT_S 111 0 1110 1 . ... ... ... 1 1111 0 1 . 0 ... 0 @2_shr_b
|
||||
VQSHRNT_S 111 0 1110 1 . ... ... ... 1 1111 0 1 . 0 ... 0 @2_shr_h
|
||||
VQSHRNB_U 111 1 1110 1 . ... ... ... 0 1111 0 1 . 0 ... 0 @2_shr_b
|
||||
VQSHRNB_U 111 1 1110 1 . ... ... ... 0 1111 0 1 . 0 ... 0 @2_shr_h
|
||||
VQSHRNT_U 111 1 1110 1 . ... ... ... 1 1111 0 1 . 0 ... 0 @2_shr_b
|
||||
VQSHRNT_U 111 1 1110 1 . ... ... ... 1 1111 0 1 . 0 ... 0 @2_shr_h
|
||||
|
||||
VQSHRUNB 111 0 1110 1 . ... ... ... 0 1111 1 1 . 0 ... 0 @2_shr_b
|
||||
VQSHRUNB 111 0 1110 1 . ... ... ... 0 1111 1 1 . 0 ... 0 @2_shr_h
|
||||
VQSHRUNT 111 0 1110 1 . ... ... ... 1 1111 1 1 . 0 ... 0 @2_shr_b
|
||||
VQSHRUNT 111 0 1110 1 . ... ... ... 1 1111 1 1 . 0 ... 0 @2_shr_h
|
||||
|
||||
VQRSHRNB_S 111 0 1110 1 . ... ... ... 0 1111 0 1 . 0 ... 1 @2_shr_b
|
||||
VQRSHRNB_S 111 0 1110 1 . ... ... ... 0 1111 0 1 . 0 ... 1 @2_shr_h
|
||||
VQRSHRNT_S 111 0 1110 1 . ... ... ... 1 1111 0 1 . 0 ... 1 @2_shr_b
|
||||
VQRSHRNT_S 111 0 1110 1 . ... ... ... 1 1111 0 1 . 0 ... 1 @2_shr_h
|
||||
VQRSHRNB_U 111 1 1110 1 . ... ... ... 0 1111 0 1 . 0 ... 1 @2_shr_b
|
||||
VQRSHRNB_U 111 1 1110 1 . ... ... ... 0 1111 0 1 . 0 ... 1 @2_shr_h
|
||||
VQRSHRNT_U 111 1 1110 1 . ... ... ... 1 1111 0 1 . 0 ... 1 @2_shr_b
|
||||
VQRSHRNT_U 111 1 1110 1 . ... ... ... 1 1111 0 1 . 0 ... 1 @2_shr_h
|
||||
|
||||
VQRSHRUNB 111 1 1110 1 . ... ... ... 0 1111 1 1 . 0 ... 0 @2_shr_b
|
||||
VQRSHRUNB 111 1 1110 1 . ... ... ... 0 1111 1 1 . 0 ... 0 @2_shr_h
|
||||
VQRSHRUNT 111 1 1110 1 . ... ... ... 1 1111 1 1 . 0 ... 0 @2_shr_b
|
||||
VQRSHRUNT 111 1 1110 1 . ... ... ... 1 1111 1 1 . 0 ... 0 @2_shr_h
|
||||
|
||||
VSHLC 111 0 1110 1 . 1 imm:5 ... 0 1111 1100 rdm:4 qd=%qd
|
||||
|
@ -18,7 +18,6 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/int128.h"
|
||||
#include "cpu.h"
|
||||
#include "internals.h"
|
||||
#include "vec_internal.h"
|
||||
@ -324,6 +323,30 @@ DO_1OP(vnegw, 4, int32_t, DO_NEG)
|
||||
DO_1OP(vfnegh, 8, uint64_t, DO_FNEGH)
|
||||
DO_1OP(vfnegs, 8, uint64_t, DO_FNEGS)
|
||||
|
||||
/*
|
||||
* 1 operand immediates: Vda is destination and possibly also one source.
|
||||
* All these insns work at 64-bit widths.
|
||||
*/
|
||||
#define DO_1OP_IMM(OP, FN) \
|
||||
void HELPER(mve_##OP)(CPUARMState *env, void *vda, uint64_t imm) \
|
||||
{ \
|
||||
uint64_t *da = vda; \
|
||||
uint16_t mask = mve_element_mask(env); \
|
||||
unsigned e; \
|
||||
for (e = 0; e < 16 / 8; e++, mask >>= 8) { \
|
||||
mergemask(&da[H8(e)], FN(da[H8(e)], imm), mask); \
|
||||
} \
|
||||
mve_advance_vpt(env); \
|
||||
}
|
||||
|
||||
#define DO_MOVI(N, I) (I)
|
||||
#define DO_ANDI(N, I) ((N) & (I))
|
||||
#define DO_ORRI(N, I) ((N) | (I))
|
||||
|
||||
DO_1OP_IMM(vmovi, DO_MOVI)
|
||||
DO_1OP_IMM(vandi, DO_ANDI)
|
||||
DO_1OP_IMM(vorri, DO_ORRI)
|
||||
|
||||
#define DO_2OP(OP, ESIZE, TYPE, FN) \
|
||||
void HELPER(glue(mve_, OP))(CPUARMState *env, \
|
||||
void *vd, void *vn, void *vm) \
|
||||
@ -710,6 +733,8 @@ DO_2OP_SAT(vqsubsw, 4, int32_t, DO_SQSUB_W)
|
||||
WRAP_QRSHL_HELPER(do_sqrshl_bhs, N, M, true, satp)
|
||||
#define DO_UQRSHL_OP(N, M, satp) \
|
||||
WRAP_QRSHL_HELPER(do_uqrshl_bhs, N, M, true, satp)
|
||||
#define DO_SUQSHL_OP(N, M, satp) \
|
||||
WRAP_QRSHL_HELPER(do_suqrshl_bhs, N, M, false, satp)
|
||||
|
||||
DO_2OP_SAT_S(vqshls, DO_SQSHL_OP)
|
||||
DO_2OP_SAT_U(vqshlu, DO_UQSHL_OP)
|
||||
@ -1100,40 +1125,45 @@ DO_LDAV(vmlsldavsw, 4, int32_t, false, +=, -=)
|
||||
DO_LDAV(vmlsldavxsw, 4, int32_t, true, +=, -=)
|
||||
|
||||
/*
|
||||
* Rounding multiply add long dual accumulate high: we must keep
|
||||
* a 72-bit internal accumulator value and return the top 64 bits.
|
||||
* Rounding multiply add long dual accumulate high. In the pseudocode
|
||||
* this is implemented with a 72-bit internal accumulator value of which
|
||||
* the top 64 bits are returned. We optimize this to avoid having to
|
||||
* use 128-bit arithmetic -- we can do this because the 74-bit accumulator
|
||||
* is squashed back into 64-bits after each beat.
|
||||
*/
|
||||
#define DO_LDAVH(OP, ESIZE, TYPE, XCHG, EVENACC, ODDACC, TO128) \
|
||||
#define DO_LDAVH(OP, TYPE, LTYPE, XCHG, SUB) \
|
||||
uint64_t HELPER(glue(mve_, OP))(CPUARMState *env, void *vn, \
|
||||
void *vm, uint64_t a) \
|
||||
{ \
|
||||
uint16_t mask = mve_element_mask(env); \
|
||||
unsigned e; \
|
||||
TYPE *n = vn, *m = vm; \
|
||||
Int128 acc = int128_lshift(TO128(a), 8); \
|
||||
for (e = 0; e < 16 / ESIZE; e++, mask >>= ESIZE) { \
|
||||
for (e = 0; e < 16 / 4; e++, mask >>= 4) { \
|
||||
if (mask & 1) { \
|
||||
LTYPE mul; \
|
||||
if (e & 1) { \
|
||||
acc = ODDACC(acc, TO128(n[H##ESIZE(e - 1 * XCHG)] * \
|
||||
m[H##ESIZE(e)])); \
|
||||
mul = (LTYPE)n[H4(e - 1 * XCHG)] * m[H4(e)]; \
|
||||
if (SUB) { \
|
||||
mul = -mul; \
|
||||
} \
|
||||
} else { \
|
||||
acc = EVENACC(acc, TO128(n[H##ESIZE(e + 1 * XCHG)] * \
|
||||
m[H##ESIZE(e)])); \
|
||||
mul = (LTYPE)n[H4(e + 1 * XCHG)] * m[H4(e)]; \
|
||||
} \
|
||||
acc = int128_add(acc, int128_make64(1 << 7)); \
|
||||
mul = (mul >> 8) + ((mul >> 7) & 1); \
|
||||
a += mul; \
|
||||
} \
|
||||
} \
|
||||
mve_advance_vpt(env); \
|
||||
return int128_getlo(int128_rshift(acc, 8)); \
|
||||
return a; \
|
||||
}
|
||||
|
||||
DO_LDAVH(vrmlaldavhsw, 4, int32_t, false, int128_add, int128_add, int128_makes64)
|
||||
DO_LDAVH(vrmlaldavhxsw, 4, int32_t, true, int128_add, int128_add, int128_makes64)
|
||||
DO_LDAVH(vrmlaldavhsw, int32_t, int64_t, false, false)
|
||||
DO_LDAVH(vrmlaldavhxsw, int32_t, int64_t, true, false)
|
||||
|
||||
DO_LDAVH(vrmlaldavhuw, 4, uint32_t, false, int128_add, int128_add, int128_make64)
|
||||
DO_LDAVH(vrmlaldavhuw, uint32_t, uint64_t, false, false)
|
||||
|
||||
DO_LDAVH(vrmlsldavhsw, 4, int32_t, false, int128_add, int128_sub, int128_makes64)
|
||||
DO_LDAVH(vrmlsldavhxsw, 4, int32_t, true, int128_add, int128_sub, int128_makes64)
|
||||
DO_LDAVH(vrmlsldavhsw, int32_t, int64_t, false, true)
|
||||
DO_LDAVH(vrmlsldavhxsw, int32_t, int64_t, true, true)
|
||||
|
||||
/* Vector add across vector */
|
||||
#define DO_VADDV(OP, ESIZE, TYPE) \
|
||||
@ -1158,3 +1188,463 @@ DO_VADDV(vaddvsw, 4, uint32_t)
|
||||
DO_VADDV(vaddvub, 1, uint8_t)
|
||||
DO_VADDV(vaddvuh, 2, uint16_t)
|
||||
DO_VADDV(vaddvuw, 4, uint32_t)
|
||||
|
||||
#define DO_VADDLV(OP, TYPE, LTYPE) \
|
||||
uint64_t HELPER(glue(mve_, OP))(CPUARMState *env, void *vm, \
|
||||
uint64_t ra) \
|
||||
{ \
|
||||
uint16_t mask = mve_element_mask(env); \
|
||||
unsigned e; \
|
||||
TYPE *m = vm; \
|
||||
for (e = 0; e < 16 / 4; e++, mask >>= 4) { \
|
||||
if (mask & 1) { \
|
||||
ra += (LTYPE)m[H4(e)]; \
|
||||
} \
|
||||
} \
|
||||
mve_advance_vpt(env); \
|
||||
return ra; \
|
||||
} \
|
||||
|
||||
DO_VADDLV(vaddlv_s, int32_t, int64_t)
|
||||
DO_VADDLV(vaddlv_u, uint32_t, uint64_t)
|
||||
|
||||
/* Shifts by immediate */
|
||||
#define DO_2SHIFT(OP, ESIZE, TYPE, FN) \
|
||||
void HELPER(glue(mve_, OP))(CPUARMState *env, void *vd, \
|
||||
void *vm, uint32_t shift) \
|
||||
{ \
|
||||
TYPE *d = vd, *m = vm; \
|
||||
uint16_t mask = mve_element_mask(env); \
|
||||
unsigned e; \
|
||||
for (e = 0; e < 16 / ESIZE; e++, mask >>= ESIZE) { \
|
||||
mergemask(&d[H##ESIZE(e)], \
|
||||
FN(m[H##ESIZE(e)], shift), mask); \
|
||||
} \
|
||||
mve_advance_vpt(env); \
|
||||
}
|
||||
|
||||
#define DO_2SHIFT_SAT(OP, ESIZE, TYPE, FN) \
|
||||
void HELPER(glue(mve_, OP))(CPUARMState *env, void *vd, \
|
||||
void *vm, uint32_t shift) \
|
||||
{ \
|
||||
TYPE *d = vd, *m = vm; \
|
||||
uint16_t mask = mve_element_mask(env); \
|
||||
unsigned e; \
|
||||
bool qc = false; \
|
||||
for (e = 0; e < 16 / ESIZE; e++, mask >>= ESIZE) { \
|
||||
bool sat = false; \
|
||||
mergemask(&d[H##ESIZE(e)], \
|
||||
FN(m[H##ESIZE(e)], shift, &sat), mask); \
|
||||
qc |= sat & mask & 1; \
|
||||
} \
|
||||
if (qc) { \
|
||||
env->vfp.qc[0] = qc; \
|
||||
} \
|
||||
mve_advance_vpt(env); \
|
||||
}
|
||||
|
||||
/* provide unsigned 2-op shift helpers for all sizes */
|
||||
#define DO_2SHIFT_U(OP, FN) \
|
||||
DO_2SHIFT(OP##b, 1, uint8_t, FN) \
|
||||
DO_2SHIFT(OP##h, 2, uint16_t, FN) \
|
||||
DO_2SHIFT(OP##w, 4, uint32_t, FN)
|
||||
#define DO_2SHIFT_S(OP, FN) \
|
||||
DO_2SHIFT(OP##b, 1, int8_t, FN) \
|
||||
DO_2SHIFT(OP##h, 2, int16_t, FN) \
|
||||
DO_2SHIFT(OP##w, 4, int32_t, FN)
|
||||
|
||||
#define DO_2SHIFT_SAT_U(OP, FN) \
|
||||
DO_2SHIFT_SAT(OP##b, 1, uint8_t, FN) \
|
||||
DO_2SHIFT_SAT(OP##h, 2, uint16_t, FN) \
|
||||
DO_2SHIFT_SAT(OP##w, 4, uint32_t, FN)
|
||||
#define DO_2SHIFT_SAT_S(OP, FN) \
|
||||
DO_2SHIFT_SAT(OP##b, 1, int8_t, FN) \
|
||||
DO_2SHIFT_SAT(OP##h, 2, int16_t, FN) \
|
||||
DO_2SHIFT_SAT(OP##w, 4, int32_t, FN)
|
||||
|
||||
DO_2SHIFT_U(vshli_u, DO_VSHLU)
|
||||
DO_2SHIFT_S(vshli_s, DO_VSHLS)
|
||||
DO_2SHIFT_SAT_U(vqshli_u, DO_UQSHL_OP)
|
||||
DO_2SHIFT_SAT_S(vqshli_s, DO_SQSHL_OP)
|
||||
DO_2SHIFT_SAT_S(vqshlui_s, DO_SUQSHL_OP)
|
||||
DO_2SHIFT_U(vrshli_u, DO_VRSHLU)
|
||||
DO_2SHIFT_S(vrshli_s, DO_VRSHLS)
|
||||
|
||||
/* Shift-and-insert; we always work with 64 bits at a time */
|
||||
#define DO_2SHIFT_INSERT(OP, ESIZE, SHIFTFN, MASKFN) \
|
||||
void HELPER(glue(mve_, OP))(CPUARMState *env, void *vd, \
|
||||
void *vm, uint32_t shift) \
|
||||
{ \
|
||||
uint64_t *d = vd, *m = vm; \
|
||||
uint16_t mask; \
|
||||
uint64_t shiftmask; \
|
||||
unsigned e; \
|
||||
if (shift == 0 || shift == ESIZE * 8) { \
|
||||
/* \
|
||||
* Only VSLI can shift by 0; only VSRI can shift by <dt>. \
|
||||
* The generic logic would give the right answer for 0 but \
|
||||
* fails for <dt>. \
|
||||
*/ \
|
||||
goto done; \
|
||||
} \
|
||||
assert(shift < ESIZE * 8); \
|
||||
mask = mve_element_mask(env); \
|
||||
/* ESIZE / 2 gives the MO_* value if ESIZE is in [1,2,4] */ \
|
||||
shiftmask = dup_const(ESIZE / 2, MASKFN(ESIZE * 8, shift)); \
|
||||
for (e = 0; e < 16 / 8; e++, mask >>= 8) { \
|
||||
uint64_t r = (SHIFTFN(m[H8(e)], shift) & shiftmask) | \
|
||||
(d[H8(e)] & ~shiftmask); \
|
||||
mergemask(&d[H8(e)], r, mask); \
|
||||
} \
|
||||
done: \
|
||||
mve_advance_vpt(env); \
|
||||
}
|
||||
|
||||
#define DO_SHL(N, SHIFT) ((N) << (SHIFT))
|
||||
#define DO_SHR(N, SHIFT) ((N) >> (SHIFT))
|
||||
#define SHL_MASK(EBITS, SHIFT) MAKE_64BIT_MASK((SHIFT), (EBITS) - (SHIFT))
|
||||
#define SHR_MASK(EBITS, SHIFT) MAKE_64BIT_MASK(0, (EBITS) - (SHIFT))
|
||||
|
||||
DO_2SHIFT_INSERT(vsrib, 1, DO_SHR, SHR_MASK)
|
||||
DO_2SHIFT_INSERT(vsrih, 2, DO_SHR, SHR_MASK)
|
||||
DO_2SHIFT_INSERT(vsriw, 4, DO_SHR, SHR_MASK)
|
||||
DO_2SHIFT_INSERT(vslib, 1, DO_SHL, SHL_MASK)
|
||||
DO_2SHIFT_INSERT(vslih, 2, DO_SHL, SHL_MASK)
|
||||
DO_2SHIFT_INSERT(vsliw, 4, DO_SHL, SHL_MASK)
|
||||
|
||||
/*
|
||||
* Long shifts taking half-sized inputs from top or bottom of the input
|
||||
* vector and producing a double-width result. ESIZE, TYPE are for
|
||||
* the input, and LESIZE, LTYPE for the output.
|
||||
* Unlike the normal shift helpers, we do not handle negative shift counts,
|
||||
* because the long shift is strictly left-only.
|
||||
*/
|
||||
#define DO_VSHLL(OP, TOP, ESIZE, TYPE, LESIZE, LTYPE) \
|
||||
void HELPER(glue(mve_, OP))(CPUARMState *env, void *vd, \
|
||||
void *vm, uint32_t shift) \
|
||||
{ \
|
||||
LTYPE *d = vd; \
|
||||
TYPE *m = vm; \
|
||||
uint16_t mask = mve_element_mask(env); \
|
||||
unsigned le; \
|
||||
assert(shift <= 16); \
|
||||
for (le = 0; le < 16 / LESIZE; le++, mask >>= LESIZE) { \
|
||||
LTYPE r = (LTYPE)m[H##ESIZE(le * 2 + TOP)] << shift; \
|
||||
mergemask(&d[H##LESIZE(le)], r, mask); \
|
||||
} \
|
||||
mve_advance_vpt(env); \
|
||||
}
|
||||
|
||||
#define DO_VSHLL_ALL(OP, TOP) \
|
||||
DO_VSHLL(OP##sb, TOP, 1, int8_t, 2, int16_t) \
|
||||
DO_VSHLL(OP##ub, TOP, 1, uint8_t, 2, uint16_t) \
|
||||
DO_VSHLL(OP##sh, TOP, 2, int16_t, 4, int32_t) \
|
||||
DO_VSHLL(OP##uh, TOP, 2, uint16_t, 4, uint32_t) \
|
||||
|
||||
DO_VSHLL_ALL(vshllb, false)
|
||||
DO_VSHLL_ALL(vshllt, true)
|
||||
|
||||
/*
|
||||
* Narrowing right shifts, taking a double sized input, shifting it
|
||||
* and putting the result in either the top or bottom half of the output.
|
||||
* ESIZE, TYPE are the output, and LESIZE, LTYPE the input.
|
||||
*/
|
||||
#define DO_VSHRN(OP, TOP, ESIZE, TYPE, LESIZE, LTYPE, FN) \
|
||||
void HELPER(glue(mve_, OP))(CPUARMState *env, void *vd, \
|
||||
void *vm, uint32_t shift) \
|
||||
{ \
|
||||
LTYPE *m = vm; \
|
||||
TYPE *d = vd; \
|
||||
uint16_t mask = mve_element_mask(env); \
|
||||
unsigned le; \
|
||||
for (le = 0; le < 16 / LESIZE; le++, mask >>= LESIZE) { \
|
||||
TYPE r = FN(m[H##LESIZE(le)], shift); \
|
||||
mergemask(&d[H##ESIZE(le * 2 + TOP)], r, mask); \
|
||||
} \
|
||||
mve_advance_vpt(env); \
|
||||
}
|
||||
|
||||
#define DO_VSHRN_ALL(OP, FN) \
|
||||
DO_VSHRN(OP##bb, false, 1, uint8_t, 2, uint16_t, FN) \
|
||||
DO_VSHRN(OP##bh, false, 2, uint16_t, 4, uint32_t, FN) \
|
||||
DO_VSHRN(OP##tb, true, 1, uint8_t, 2, uint16_t, FN) \
|
||||
DO_VSHRN(OP##th, true, 2, uint16_t, 4, uint32_t, FN)
|
||||
|
||||
static inline uint64_t do_urshr(uint64_t x, unsigned sh)
|
||||
{
|
||||
if (likely(sh < 64)) {
|
||||
return (x >> sh) + ((x >> (sh - 1)) & 1);
|
||||
} else if (sh == 64) {
|
||||
return x >> 63;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int64_t do_srshr(int64_t x, unsigned sh)
|
||||
{
|
||||
if (likely(sh < 64)) {
|
||||
return (x >> sh) + ((x >> (sh - 1)) & 1);
|
||||
} else {
|
||||
/* Rounding the sign bit always produces 0. */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
DO_VSHRN_ALL(vshrn, DO_SHR)
|
||||
DO_VSHRN_ALL(vrshrn, do_urshr)
|
||||
|
||||
static inline int32_t do_sat_bhs(int64_t val, int64_t min, int64_t max,
|
||||
bool *satp)
|
||||
{
|
||||
if (val > max) {
|
||||
*satp = true;
|
||||
return max;
|
||||
} else if (val < min) {
|
||||
*satp = true;
|
||||
return min;
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
/* Saturating narrowing right shifts */
|
||||
#define DO_VSHRN_SAT(OP, TOP, ESIZE, TYPE, LESIZE, LTYPE, FN) \
|
||||
void HELPER(glue(mve_, OP))(CPUARMState *env, void *vd, \
|
||||
void *vm, uint32_t shift) \
|
||||
{ \
|
||||
LTYPE *m = vm; \
|
||||
TYPE *d = vd; \
|
||||
uint16_t mask = mve_element_mask(env); \
|
||||
bool qc = false; \
|
||||
unsigned le; \
|
||||
for (le = 0; le < 16 / LESIZE; le++, mask >>= LESIZE) { \
|
||||
bool sat = false; \
|
||||
TYPE r = FN(m[H##LESIZE(le)], shift, &sat); \
|
||||
mergemask(&d[H##ESIZE(le * 2 + TOP)], r, mask); \
|
||||
qc |= sat && (mask & 1 << (TOP * ESIZE)); \
|
||||
} \
|
||||
if (qc) { \
|
||||
env->vfp.qc[0] = qc; \
|
||||
} \
|
||||
mve_advance_vpt(env); \
|
||||
}
|
||||
|
||||
#define DO_VSHRN_SAT_UB(BOP, TOP, FN) \
|
||||
DO_VSHRN_SAT(BOP, false, 1, uint8_t, 2, uint16_t, FN) \
|
||||
DO_VSHRN_SAT(TOP, true, 1, uint8_t, 2, uint16_t, FN)
|
||||
|
||||
#define DO_VSHRN_SAT_UH(BOP, TOP, FN) \
|
||||
DO_VSHRN_SAT(BOP, false, 2, uint16_t, 4, uint32_t, FN) \
|
||||
DO_VSHRN_SAT(TOP, true, 2, uint16_t, 4, uint32_t, FN)
|
||||
|
||||
#define DO_VSHRN_SAT_SB(BOP, TOP, FN) \
|
||||
DO_VSHRN_SAT(BOP, false, 1, int8_t, 2, int16_t, FN) \
|
||||
DO_VSHRN_SAT(TOP, true, 1, int8_t, 2, int16_t, FN)
|
||||
|
||||
#define DO_VSHRN_SAT_SH(BOP, TOP, FN) \
|
||||
DO_VSHRN_SAT(BOP, false, 2, int16_t, 4, int32_t, FN) \
|
||||
DO_VSHRN_SAT(TOP, true, 2, int16_t, 4, int32_t, FN)
|
||||
|
||||
#define DO_SHRN_SB(N, M, SATP) \
|
||||
do_sat_bhs((int64_t)(N) >> (M), INT8_MIN, INT8_MAX, SATP)
|
||||
#define DO_SHRN_UB(N, M, SATP) \
|
||||
do_sat_bhs((uint64_t)(N) >> (M), 0, UINT8_MAX, SATP)
|
||||
#define DO_SHRUN_B(N, M, SATP) \
|
||||
do_sat_bhs((int64_t)(N) >> (M), 0, UINT8_MAX, SATP)
|
||||
|
||||
#define DO_SHRN_SH(N, M, SATP) \
|
||||
do_sat_bhs((int64_t)(N) >> (M), INT16_MIN, INT16_MAX, SATP)
|
||||
#define DO_SHRN_UH(N, M, SATP) \
|
||||
do_sat_bhs((uint64_t)(N) >> (M), 0, UINT16_MAX, SATP)
|
||||
#define DO_SHRUN_H(N, M, SATP) \
|
||||
do_sat_bhs((int64_t)(N) >> (M), 0, UINT16_MAX, SATP)
|
||||
|
||||
#define DO_RSHRN_SB(N, M, SATP) \
|
||||
do_sat_bhs(do_srshr(N, M), INT8_MIN, INT8_MAX, SATP)
|
||||
#define DO_RSHRN_UB(N, M, SATP) \
|
||||
do_sat_bhs(do_urshr(N, M), 0, UINT8_MAX, SATP)
|
||||
#define DO_RSHRUN_B(N, M, SATP) \
|
||||
do_sat_bhs(do_srshr(N, M), 0, UINT8_MAX, SATP)
|
||||
|
||||
#define DO_RSHRN_SH(N, M, SATP) \
|
||||
do_sat_bhs(do_srshr(N, M), INT16_MIN, INT16_MAX, SATP)
|
||||
#define DO_RSHRN_UH(N, M, SATP) \
|
||||
do_sat_bhs(do_urshr(N, M), 0, UINT16_MAX, SATP)
|
||||
#define DO_RSHRUN_H(N, M, SATP) \
|
||||
do_sat_bhs(do_srshr(N, M), 0, UINT16_MAX, SATP)
|
||||
|
||||
DO_VSHRN_SAT_SB(vqshrnb_sb, vqshrnt_sb, DO_SHRN_SB)
|
||||
DO_VSHRN_SAT_SH(vqshrnb_sh, vqshrnt_sh, DO_SHRN_SH)
|
||||
DO_VSHRN_SAT_UB(vqshrnb_ub, vqshrnt_ub, DO_SHRN_UB)
|
||||
DO_VSHRN_SAT_UH(vqshrnb_uh, vqshrnt_uh, DO_SHRN_UH)
|
||||
DO_VSHRN_SAT_SB(vqshrunbb, vqshruntb, DO_SHRUN_B)
|
||||
DO_VSHRN_SAT_SH(vqshrunbh, vqshrunth, DO_SHRUN_H)
|
||||
|
||||
DO_VSHRN_SAT_SB(vqrshrnb_sb, vqrshrnt_sb, DO_RSHRN_SB)
|
||||
DO_VSHRN_SAT_SH(vqrshrnb_sh, vqrshrnt_sh, DO_RSHRN_SH)
|
||||
DO_VSHRN_SAT_UB(vqrshrnb_ub, vqrshrnt_ub, DO_RSHRN_UB)
|
||||
DO_VSHRN_SAT_UH(vqrshrnb_uh, vqrshrnt_uh, DO_RSHRN_UH)
|
||||
DO_VSHRN_SAT_SB(vqrshrunbb, vqrshruntb, DO_RSHRUN_B)
|
||||
DO_VSHRN_SAT_SH(vqrshrunbh, vqrshrunth, DO_RSHRUN_H)
|
||||
|
||||
uint32_t HELPER(mve_vshlc)(CPUARMState *env, void *vd, uint32_t rdm,
|
||||
uint32_t shift)
|
||||
{
|
||||
uint32_t *d = vd;
|
||||
uint16_t mask = mve_element_mask(env);
|
||||
unsigned e;
|
||||
uint32_t r;
|
||||
|
||||
/*
|
||||
* For each 32-bit element, we shift it left, bringing in the
|
||||
* low 'shift' bits of rdm at the bottom. Bits shifted out at
|
||||
* the top become the new rdm, if the predicate mask permits.
|
||||
* The final rdm value is returned to update the register.
|
||||
* shift == 0 here means "shift by 32 bits".
|
||||
*/
|
||||
if (shift == 0) {
|
||||
for (e = 0; e < 16 / 4; e++, mask >>= 4) {
|
||||
r = rdm;
|
||||
if (mask & 1) {
|
||||
rdm = d[H4(e)];
|
||||
}
|
||||
mergemask(&d[H4(e)], r, mask);
|
||||
}
|
||||
} else {
|
||||
uint32_t shiftmask = MAKE_64BIT_MASK(0, shift);
|
||||
|
||||
for (e = 0; e < 16 / 4; e++, mask >>= 4) {
|
||||
r = (d[H4(e)] << shift) | (rdm & shiftmask);
|
||||
if (mask & 1) {
|
||||
rdm = d[H4(e)] >> (32 - shift);
|
||||
}
|
||||
mergemask(&d[H4(e)], r, mask);
|
||||
}
|
||||
}
|
||||
mve_advance_vpt(env);
|
||||
return rdm;
|
||||
}
|
||||
|
||||
uint64_t HELPER(mve_sshrl)(CPUARMState *env, uint64_t n, uint32_t shift)
|
||||
{
|
||||
return do_sqrshl_d(n, -(int8_t)shift, false, NULL);
|
||||
}
|
||||
|
||||
uint64_t HELPER(mve_ushll)(CPUARMState *env, uint64_t n, uint32_t shift)
|
||||
{
|
||||
return do_uqrshl_d(n, (int8_t)shift, false, NULL);
|
||||
}
|
||||
|
||||
uint64_t HELPER(mve_sqshll)(CPUARMState *env, uint64_t n, uint32_t shift)
|
||||
{
|
||||
return do_sqrshl_d(n, (int8_t)shift, false, &env->QF);
|
||||
}
|
||||
|
||||
uint64_t HELPER(mve_uqshll)(CPUARMState *env, uint64_t n, uint32_t shift)
|
||||
{
|
||||
return do_uqrshl_d(n, (int8_t)shift, false, &env->QF);
|
||||
}
|
||||
|
||||
uint64_t HELPER(mve_sqrshrl)(CPUARMState *env, uint64_t n, uint32_t shift)
|
||||
{
|
||||
return do_sqrshl_d(n, -(int8_t)shift, true, &env->QF);
|
||||
}
|
||||
|
||||
uint64_t HELPER(mve_uqrshll)(CPUARMState *env, uint64_t n, uint32_t shift)
|
||||
{
|
||||
return do_uqrshl_d(n, (int8_t)shift, true, &env->QF);
|
||||
}
|
||||
|
||||
/* Operate on 64-bit values, but saturate at 48 bits */
|
||||
static inline int64_t do_sqrshl48_d(int64_t src, int64_t shift,
|
||||
bool round, uint32_t *sat)
|
||||
{
|
||||
if (shift <= -48) {
|
||||
/* Rounding the sign bit always produces 0. */
|
||||
if (round) {
|
||||
return 0;
|
||||
}
|
||||
return src >> 63;
|
||||
} else if (shift < 0) {
|
||||
if (round) {
|
||||
src >>= -shift - 1;
|
||||
return (src >> 1) + (src & 1);
|
||||
}
|
||||
return src >> -shift;
|
||||
} else if (shift < 48) {
|
||||
int64_t val = src << shift;
|
||||
int64_t extval = sextract64(val, 0, 48);
|
||||
if (!sat || val == extval) {
|
||||
return extval;
|
||||
}
|
||||
} else if (!sat || src == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sat = 1;
|
||||
return (1ULL << 47) - (src >= 0);
|
||||
}
|
||||
|
||||
/* Operate on 64-bit values, but saturate at 48 bits */
|
||||
static inline uint64_t do_uqrshl48_d(uint64_t src, int64_t shift,
|
||||
bool round, uint32_t *sat)
|
||||
{
|
||||
uint64_t val, extval;
|
||||
|
||||
if (shift <= -(48 + round)) {
|
||||
return 0;
|
||||
} else if (shift < 0) {
|
||||
if (round) {
|
||||
val = src >> (-shift - 1);
|
||||
val = (val >> 1) + (val & 1);
|
||||
} else {
|
||||
val = src >> -shift;
|
||||
}
|
||||
extval = extract64(val, 0, 48);
|
||||
if (!sat || val == extval) {
|
||||
return extval;
|
||||
}
|
||||
} else if (shift < 48) {
|
||||
uint64_t val = src << shift;
|
||||
uint64_t extval = extract64(val, 0, 48);
|
||||
if (!sat || val == extval) {
|
||||
return extval;
|
||||
}
|
||||
} else if (!sat || src == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sat = 1;
|
||||
return MAKE_64BIT_MASK(0, 48);
|
||||
}
|
||||
|
||||
uint64_t HELPER(mve_sqrshrl48)(CPUARMState *env, uint64_t n, uint32_t shift)
|
||||
{
|
||||
return do_sqrshl48_d(n, -(int8_t)shift, true, &env->QF);
|
||||
}
|
||||
|
||||
uint64_t HELPER(mve_uqrshll48)(CPUARMState *env, uint64_t n, uint32_t shift)
|
||||
{
|
||||
return do_uqrshl48_d(n, (int8_t)shift, true, &env->QF);
|
||||
}
|
||||
|
||||
uint32_t HELPER(mve_uqshl)(CPUARMState *env, uint32_t n, uint32_t shift)
|
||||
{
|
||||
return do_uqrshl_bhs(n, (int8_t)shift, 32, false, &env->QF);
|
||||
}
|
||||
|
||||
uint32_t HELPER(mve_sqshl)(CPUARMState *env, uint32_t n, uint32_t shift)
|
||||
{
|
||||
return do_sqrshl_bhs(n, (int8_t)shift, 32, false, &env->QF);
|
||||
}
|
||||
|
||||
uint32_t HELPER(mve_uqrshl)(CPUARMState *env, uint32_t n, uint32_t shift)
|
||||
{
|
||||
return do_uqrshl_bhs(n, (int8_t)shift, 32, true, &env->QF);
|
||||
}
|
||||
|
||||
uint32_t HELPER(mve_sqrshr)(CPUARMState *env, uint32_t n, uint32_t shift)
|
||||
{
|
||||
return do_sqrshl_bhs(n, -(int8_t)shift, 32, true, &env->QF);
|
||||
}
|
||||
|
@ -48,6 +48,16 @@
|
||||
&mcr !extern cp opc1 crn crm opc2 rt
|
||||
&mcrr !extern cp opc1 crm rt rt2
|
||||
|
||||
&mve_shl_ri rdalo rdahi shim
|
||||
&mve_shl_rr rdalo rdahi rm
|
||||
&mve_sh_ri rda shim
|
||||
&mve_sh_rr rda rm
|
||||
|
||||
# rdahi: bits [3:1] from insn, bit 0 is 1
|
||||
# rdalo: bits [3:1] from insn, bit 0 is 0
|
||||
%rdahi_9 9:3 !function=times_2_plus_1
|
||||
%rdalo_17 17:3 !function=times_2
|
||||
|
||||
# Data-processing (register)
|
||||
|
||||
%imm5_12_6 12:3 6:2
|
||||
@ -59,14 +69,72 @@
|
||||
@S_xrr_shi ....... .... . rn:4 .... .... .. shty:2 rm:4 \
|
||||
&s_rrr_shi shim=%imm5_12_6 s=1 rd=0
|
||||
|
||||
@mve_shl_ri ....... .... . ... . . ... ... . .. .. .... \
|
||||
&mve_shl_ri shim=%imm5_12_6 rdalo=%rdalo_17 rdahi=%rdahi_9
|
||||
@mve_shl_rr ....... .... . ... . rm:4 ... . .. .. .... \
|
||||
&mve_shl_rr rdalo=%rdalo_17 rdahi=%rdahi_9
|
||||
@mve_sh_ri ....... .... . rda:4 . ... ... . .. .. .... \
|
||||
&mve_sh_ri shim=%imm5_12_6
|
||||
@mve_sh_rr ....... .... . rda:4 rm:4 .... .... .... &mve_sh_rr
|
||||
|
||||
{
|
||||
TST_xrri 1110101 0000 1 .... 0 ... 1111 .... .... @S_xrr_shi
|
||||
AND_rrri 1110101 0000 . .... 0 ... .... .... .... @s_rrr_shi
|
||||
}
|
||||
BIC_rrri 1110101 0001 . .... 0 ... .... .... .... @s_rrr_shi
|
||||
{
|
||||
# The v8.1M MVE shift insns overlap in encoding with MOVS/ORRS
|
||||
# and are distinguished by having Rm==13 or 15. Those are UNPREDICTABLE
|
||||
# cases for MOVS/ORRS. We decode the MVE cases first, ensuring that
|
||||
# they explicitly call unallocated_encoding() for cases that must UNDEF
|
||||
# (eg "using a new shift insn on a v8.1M CPU without MVE"), and letting
|
||||
# the rest fall through (where ORR_rrri and MOV_rxri will end up
|
||||
# handling them as r13 and r15 accesses with the same semantics as A32).
|
||||
[
|
||||
{
|
||||
UQSHL_ri 1110101 0010 1 .... 0 ... 1111 .. 00 1111 @mve_sh_ri
|
||||
LSLL_ri 1110101 0010 1 ... 0 0 ... ... 1 .. 00 1111 @mve_shl_ri
|
||||
UQSHLL_ri 1110101 0010 1 ... 1 0 ... ... 1 .. 00 1111 @mve_shl_ri
|
||||
}
|
||||
|
||||
{
|
||||
URSHR_ri 1110101 0010 1 .... 0 ... 1111 .. 01 1111 @mve_sh_ri
|
||||
LSRL_ri 1110101 0010 1 ... 0 0 ... ... 1 .. 01 1111 @mve_shl_ri
|
||||
URSHRL_ri 1110101 0010 1 ... 1 0 ... ... 1 .. 01 1111 @mve_shl_ri
|
||||
}
|
||||
|
||||
{
|
||||
SRSHR_ri 1110101 0010 1 .... 0 ... 1111 .. 10 1111 @mve_sh_ri
|
||||
ASRL_ri 1110101 0010 1 ... 0 0 ... ... 1 .. 10 1111 @mve_shl_ri
|
||||
SRSHRL_ri 1110101 0010 1 ... 1 0 ... ... 1 .. 10 1111 @mve_shl_ri
|
||||
}
|
||||
|
||||
{
|
||||
SQSHL_ri 1110101 0010 1 .... 0 ... 1111 .. 11 1111 @mve_sh_ri
|
||||
SQSHLL_ri 1110101 0010 1 ... 1 0 ... ... 1 .. 11 1111 @mve_shl_ri
|
||||
}
|
||||
|
||||
{
|
||||
UQRSHL_rr 1110101 0010 1 .... .... 1111 0000 1101 @mve_sh_rr
|
||||
LSLL_rr 1110101 0010 1 ... 0 .... ... 1 0000 1101 @mve_shl_rr
|
||||
UQRSHLL64_rr 1110101 0010 1 ... 1 .... ... 1 0000 1101 @mve_shl_rr
|
||||
}
|
||||
|
||||
{
|
||||
SQRSHR_rr 1110101 0010 1 .... .... 1111 0010 1101 @mve_sh_rr
|
||||
ASRL_rr 1110101 0010 1 ... 0 .... ... 1 0010 1101 @mve_shl_rr
|
||||
SQRSHRL64_rr 1110101 0010 1 ... 1 .... ... 1 0010 1101 @mve_shl_rr
|
||||
}
|
||||
|
||||
UQRSHLL48_rr 1110101 0010 1 ... 1 .... ... 1 1000 1101 @mve_shl_rr
|
||||
SQRSHRL48_rr 1110101 0010 1 ... 1 .... ... 1 1010 1101 @mve_shl_rr
|
||||
]
|
||||
|
||||
MOV_rxri 1110101 0010 . 1111 0 ... .... .... .... @s_rxr_shi
|
||||
ORR_rrri 1110101 0010 . .... 0 ... .... .... .... @s_rrr_shi
|
||||
|
||||
# v8.1M CSEL and friends
|
||||
CSEL 1110101 0010 1 rn:4 10 op:2 rd:4 fcond:4 rm:4
|
||||
}
|
||||
{
|
||||
MVN_rxri 1110101 0011 . 1111 0 ... .... .... .... @s_rxr_shi
|
||||
@ -90,9 +158,6 @@ SBC_rrri 1110101 1011 . .... 0 ... .... .... .... @s_rrr_shi
|
||||
}
|
||||
RSB_rrri 1110101 1110 . .... 0 ... .... .... .... @s_rrr_shi
|
||||
|
||||
# v8.1M CSEL and friends
|
||||
CSEL 1110101 0010 1 rn:4 10 op:2 rd:4 fcond:4 rm:4
|
||||
|
||||
# Data-processing (register-shifted register)
|
||||
|
||||
MOV_rxrr 1111 1010 0 shty:2 s:1 rm:4 1111 rd:4 0000 rs:4 \
|
||||
|
@ -8190,8 +8190,6 @@ static void disas_simd_mod_imm(DisasContext *s, uint32_t insn)
|
||||
{
|
||||
int rd = extract32(insn, 0, 5);
|
||||
int cmode = extract32(insn, 12, 4);
|
||||
int cmode_3_1 = extract32(cmode, 1, 3);
|
||||
int cmode_0 = extract32(cmode, 0, 1);
|
||||
int o2 = extract32(insn, 11, 1);
|
||||
uint64_t abcdefgh = extract32(insn, 5, 5) | (extract32(insn, 16, 3) << 5);
|
||||
bool is_neg = extract32(insn, 29, 1);
|
||||
@ -8210,83 +8208,13 @@ static void disas_simd_mod_imm(DisasContext *s, uint32_t insn)
|
||||
return;
|
||||
}
|
||||
|
||||
/* See AdvSIMDExpandImm() in ARM ARM */
|
||||
switch (cmode_3_1) {
|
||||
case 0: /* Replicate(Zeros(24):imm8, 2) */
|
||||
case 1: /* Replicate(Zeros(16):imm8:Zeros(8), 2) */
|
||||
case 2: /* Replicate(Zeros(8):imm8:Zeros(16), 2) */
|
||||
case 3: /* Replicate(imm8:Zeros(24), 2) */
|
||||
{
|
||||
int shift = cmode_3_1 * 8;
|
||||
imm = bitfield_replicate(abcdefgh << shift, 32);
|
||||
break;
|
||||
}
|
||||
case 4: /* Replicate(Zeros(8):imm8, 4) */
|
||||
case 5: /* Replicate(imm8:Zeros(8), 4) */
|
||||
{
|
||||
int shift = (cmode_3_1 & 0x1) * 8;
|
||||
imm = bitfield_replicate(abcdefgh << shift, 16);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
if (cmode_0) {
|
||||
/* Replicate(Zeros(8):imm8:Ones(16), 2) */
|
||||
imm = (abcdefgh << 16) | 0xffff;
|
||||
} else {
|
||||
/* Replicate(Zeros(16):imm8:Ones(8), 2) */
|
||||
imm = (abcdefgh << 8) | 0xff;
|
||||
}
|
||||
imm = bitfield_replicate(imm, 32);
|
||||
break;
|
||||
case 7:
|
||||
if (!cmode_0 && !is_neg) {
|
||||
imm = bitfield_replicate(abcdefgh, 8);
|
||||
} else if (!cmode_0 && is_neg) {
|
||||
int i;
|
||||
imm = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if ((abcdefgh) & (1 << i)) {
|
||||
imm |= 0xffULL << (i * 8);
|
||||
}
|
||||
}
|
||||
} else if (cmode_0) {
|
||||
if (is_neg) {
|
||||
imm = (abcdefgh & 0x3f) << 48;
|
||||
if (abcdefgh & 0x80) {
|
||||
imm |= 0x8000000000000000ULL;
|
||||
}
|
||||
if (abcdefgh & 0x40) {
|
||||
imm |= 0x3fc0000000000000ULL;
|
||||
} else {
|
||||
imm |= 0x4000000000000000ULL;
|
||||
}
|
||||
} else {
|
||||
if (o2) {
|
||||
/* FMOV (vector, immediate) - half-precision */
|
||||
imm = vfp_expand_imm(MO_16, abcdefgh);
|
||||
/* now duplicate across the lanes */
|
||||
imm = bitfield_replicate(imm, 16);
|
||||
} else {
|
||||
imm = (abcdefgh & 0x3f) << 19;
|
||||
if (abcdefgh & 0x80) {
|
||||
imm |= 0x80000000;
|
||||
}
|
||||
if (abcdefgh & 0x40) {
|
||||
imm |= 0x3e000000;
|
||||
} else {
|
||||
imm |= 0x40000000;
|
||||
}
|
||||
imm |= (imm << 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (cmode_3_1 != 7 && is_neg) {
|
||||
imm = ~imm;
|
||||
if (cmode == 15 && o2 && !is_neg) {
|
||||
/* FMOV (vector, immediate) - half-precision */
|
||||
imm = vfp_expand_imm(MO_16, abcdefgh);
|
||||
/* now duplicate across the lanes */
|
||||
imm = dup_const(MO_16, imm);
|
||||
} else {
|
||||
imm = asimd_imm_const(abcdefgh, cmode, is_neg);
|
||||
}
|
||||
|
||||
if (!((cmode & 0x9) == 0x1 || (cmode & 0xd) == 0x9)) {
|
||||
|
@ -32,8 +32,10 @@ typedef void MVEGenLdStFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
|
||||
typedef void MVEGenOneOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
|
||||
typedef void MVEGenTwoOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr);
|
||||
typedef void MVEGenTwoOpScalarFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
|
||||
typedef void MVEGenTwoOpShiftFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
|
||||
typedef void MVEGenDualAccOpFn(TCGv_i64, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i64);
|
||||
typedef void MVEGenVADDVFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_i32);
|
||||
typedef void MVEGenOneOpImmFn(TCGv_ptr, TCGv_ptr, TCGv_i64);
|
||||
|
||||
/* Return the offset of a Qn register (same semantics as aa32_vfp_qreg()) */
|
||||
static inline long mve_qreg_offset(unsigned reg)
|
||||
@ -120,7 +122,8 @@ static bool mve_skip_first_beat(DisasContext *s)
|
||||
}
|
||||
}
|
||||
|
||||
static bool do_ldst(DisasContext *s, arg_VLDR_VSTR *a, MVEGenLdStFn *fn)
|
||||
static bool do_ldst(DisasContext *s, arg_VLDR_VSTR *a, MVEGenLdStFn *fn,
|
||||
unsigned msize)
|
||||
{
|
||||
TCGv_i32 addr;
|
||||
uint32_t offset;
|
||||
@ -141,7 +144,7 @@ static bool do_ldst(DisasContext *s, arg_VLDR_VSTR *a, MVEGenLdStFn *fn)
|
||||
return true;
|
||||
}
|
||||
|
||||
offset = a->imm << a->size;
|
||||
offset = a->imm << msize;
|
||||
if (!a->a) {
|
||||
offset = -offset;
|
||||
}
|
||||
@ -178,22 +181,22 @@ static bool trans_VLDR_VSTR(DisasContext *s, arg_VLDR_VSTR *a)
|
||||
{ gen_helper_mve_vstrw, gen_helper_mve_vldrw },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
return do_ldst(s, a, ldstfns[a->size][a->l]);
|
||||
return do_ldst(s, a, ldstfns[a->size][a->l], a->size);
|
||||
}
|
||||
|
||||
#define DO_VLDST_WIDE_NARROW(OP, SLD, ULD, ST) \
|
||||
#define DO_VLDST_WIDE_NARROW(OP, SLD, ULD, ST, MSIZE) \
|
||||
static bool trans_##OP(DisasContext *s, arg_VLDR_VSTR *a) \
|
||||
{ \
|
||||
static MVEGenLdStFn * const ldstfns[2][2] = { \
|
||||
{ gen_helper_mve_##ST, gen_helper_mve_##SLD }, \
|
||||
{ NULL, gen_helper_mve_##ULD }, \
|
||||
}; \
|
||||
return do_ldst(s, a, ldstfns[a->u][a->l]); \
|
||||
return do_ldst(s, a, ldstfns[a->u][a->l], MSIZE); \
|
||||
}
|
||||
|
||||
DO_VLDST_WIDE_NARROW(VLDSTB_H, vldrb_sh, vldrb_uh, vstrb_h)
|
||||
DO_VLDST_WIDE_NARROW(VLDSTB_W, vldrb_sw, vldrb_uw, vstrb_w)
|
||||
DO_VLDST_WIDE_NARROW(VLDSTH_W, vldrh_sw, vldrh_uw, vstrh_w)
|
||||
DO_VLDST_WIDE_NARROW(VLDSTB_H, vldrb_sh, vldrb_uh, vstrb_h, MO_8)
|
||||
DO_VLDST_WIDE_NARROW(VLDSTB_W, vldrb_sw, vldrb_uw, vstrb_w, MO_8)
|
||||
DO_VLDST_WIDE_NARROW(VLDSTH_W, vldrh_sw, vldrh_uw, vstrh_w, MO_16)
|
||||
|
||||
static bool trans_VDUP(DisasContext *s, arg_VDUP *a)
|
||||
{
|
||||
@ -786,3 +789,245 @@ static bool trans_VADDV(DisasContext *s, arg_VADDV *a)
|
||||
mve_update_eci(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_VADDLV(DisasContext *s, arg_VADDLV *a)
|
||||
{
|
||||
/*
|
||||
* Vector Add Long Across Vector: accumulate the 32-bit
|
||||
* elements of the vector into a 64-bit result stored in
|
||||
* a pair of general-purpose registers.
|
||||
* No need to check Qm's bank: it is only 3 bits in decode.
|
||||
*/
|
||||
TCGv_ptr qm;
|
||||
TCGv_i64 rda;
|
||||
TCGv_i32 rdalo, rdahi;
|
||||
|
||||
if (!dc_isar_feature(aa32_mve, s)) {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
* rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related
|
||||
* encoding; rdalo always has bit 0 clear so cannot be 13 or 15.
|
||||
*/
|
||||
if (a->rdahi == 13 || a->rdahi == 15) {
|
||||
return false;
|
||||
}
|
||||
if (!mve_eci_check(s) || !vfp_access_check(s)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This insn is subject to beat-wise execution. Partial execution
|
||||
* of an A=0 (no-accumulate) insn which does not execute the first
|
||||
* beat must start with the current value of RdaHi:RdaLo, not zero.
|
||||
*/
|
||||
if (a->a || mve_skip_first_beat(s)) {
|
||||
/* Accumulate input from RdaHi:RdaLo */
|
||||
rda = tcg_temp_new_i64();
|
||||
rdalo = load_reg(s, a->rdalo);
|
||||
rdahi = load_reg(s, a->rdahi);
|
||||
tcg_gen_concat_i32_i64(rda, rdalo, rdahi);
|
||||
tcg_temp_free_i32(rdalo);
|
||||
tcg_temp_free_i32(rdahi);
|
||||
} else {
|
||||
/* Accumulate starting at zero */
|
||||
rda = tcg_const_i64(0);
|
||||
}
|
||||
|
||||
qm = mve_qreg_ptr(a->qm);
|
||||
if (a->u) {
|
||||
gen_helper_mve_vaddlv_u(rda, cpu_env, qm, rda);
|
||||
} else {
|
||||
gen_helper_mve_vaddlv_s(rda, cpu_env, qm, rda);
|
||||
}
|
||||
tcg_temp_free_ptr(qm);
|
||||
|
||||
rdalo = tcg_temp_new_i32();
|
||||
rdahi = tcg_temp_new_i32();
|
||||
tcg_gen_extrl_i64_i32(rdalo, rda);
|
||||
tcg_gen_extrh_i64_i32(rdahi, rda);
|
||||
store_reg(s, a->rdalo, rdalo);
|
||||
store_reg(s, a->rdahi, rdahi);
|
||||
tcg_temp_free_i64(rda);
|
||||
mve_update_eci(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool do_1imm(DisasContext *s, arg_1imm *a, MVEGenOneOpImmFn *fn)
|
||||
{
|
||||
TCGv_ptr qd;
|
||||
uint64_t imm;
|
||||
|
||||
if (!dc_isar_feature(aa32_mve, s) ||
|
||||
!mve_check_qreg_bank(s, a->qd) ||
|
||||
!fn) {
|
||||
return false;
|
||||
}
|
||||
if (!mve_eci_check(s) || !vfp_access_check(s)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
imm = asimd_imm_const(a->imm, a->cmode, a->op);
|
||||
|
||||
qd = mve_qreg_ptr(a->qd);
|
||||
fn(cpu_env, qd, tcg_constant_i64(imm));
|
||||
tcg_temp_free_ptr(qd);
|
||||
mve_update_eci(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_Vimm_1r(DisasContext *s, arg_1imm *a)
|
||||
{
|
||||
/* Handle decode of cmode/op here between VORR/VBIC/VMOV */
|
||||
MVEGenOneOpImmFn *fn;
|
||||
|
||||
if ((a->cmode & 1) && a->cmode < 12) {
|
||||
if (a->op) {
|
||||
/*
|
||||
* For op=1, the immediate will be inverted by asimd_imm_const(),
|
||||
* so the VBIC becomes a logical AND operation.
|
||||
*/
|
||||
fn = gen_helper_mve_vandi;
|
||||
} else {
|
||||
fn = gen_helper_mve_vorri;
|
||||
}
|
||||
} else {
|
||||
/* There is one unallocated cmode/op combination in this space */
|
||||
if (a->cmode == 15 && a->op == 1) {
|
||||
return false;
|
||||
}
|
||||
/* asimd_imm_const() sorts out VMVNI vs VMOVI for us */
|
||||
fn = gen_helper_mve_vmovi;
|
||||
}
|
||||
return do_1imm(s, a, fn);
|
||||
}
|
||||
|
||||
static bool do_2shift(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn,
|
||||
bool negateshift)
|
||||
{
|
||||
TCGv_ptr qd, qm;
|
||||
int shift = a->shift;
|
||||
|
||||
if (!dc_isar_feature(aa32_mve, s) ||
|
||||
!mve_check_qreg_bank(s, a->qd | a->qm) ||
|
||||
!fn) {
|
||||
return false;
|
||||
}
|
||||
if (!mve_eci_check(s) || !vfp_access_check(s)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* When we handle a right shift insn using a left-shift helper
|
||||
* which permits a negative shift count to indicate a right-shift,
|
||||
* we must negate the shift count.
|
||||
*/
|
||||
if (negateshift) {
|
||||
shift = -shift;
|
||||
}
|
||||
|
||||
qd = mve_qreg_ptr(a->qd);
|
||||
qm = mve_qreg_ptr(a->qm);
|
||||
fn(cpu_env, qd, qm, tcg_constant_i32(shift));
|
||||
tcg_temp_free_ptr(qd);
|
||||
tcg_temp_free_ptr(qm);
|
||||
mve_update_eci(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
#define DO_2SHIFT(INSN, FN, NEGATESHIFT) \
|
||||
static bool trans_##INSN(DisasContext *s, arg_2shift *a) \
|
||||
{ \
|
||||
static MVEGenTwoOpShiftFn * const fns[] = { \
|
||||
gen_helper_mve_##FN##b, \
|
||||
gen_helper_mve_##FN##h, \
|
||||
gen_helper_mve_##FN##w, \
|
||||
NULL, \
|
||||
}; \
|
||||
return do_2shift(s, a, fns[a->size], NEGATESHIFT); \
|
||||
}
|
||||
|
||||
DO_2SHIFT(VSHLI, vshli_u, false)
|
||||
DO_2SHIFT(VQSHLI_S, vqshli_s, false)
|
||||
DO_2SHIFT(VQSHLI_U, vqshli_u, false)
|
||||
DO_2SHIFT(VQSHLUI, vqshlui_s, false)
|
||||
/* These right shifts use a left-shift helper with negated shift count */
|
||||
DO_2SHIFT(VSHRI_S, vshli_s, true)
|
||||
DO_2SHIFT(VSHRI_U, vshli_u, true)
|
||||
DO_2SHIFT(VRSHRI_S, vrshli_s, true)
|
||||
DO_2SHIFT(VRSHRI_U, vrshli_u, true)
|
||||
|
||||
DO_2SHIFT(VSRI, vsri, false)
|
||||
DO_2SHIFT(VSLI, vsli, false)
|
||||
|
||||
#define DO_VSHLL(INSN, FN) \
|
||||
static bool trans_##INSN(DisasContext *s, arg_2shift *a) \
|
||||
{ \
|
||||
static MVEGenTwoOpShiftFn * const fns[] = { \
|
||||
gen_helper_mve_##FN##b, \
|
||||
gen_helper_mve_##FN##h, \
|
||||
}; \
|
||||
return do_2shift(s, a, fns[a->size], false); \
|
||||
}
|
||||
|
||||
DO_VSHLL(VSHLL_BS, vshllbs)
|
||||
DO_VSHLL(VSHLL_BU, vshllbu)
|
||||
DO_VSHLL(VSHLL_TS, vshllts)
|
||||
DO_VSHLL(VSHLL_TU, vshlltu)
|
||||
|
||||
#define DO_2SHIFT_N(INSN, FN) \
|
||||
static bool trans_##INSN(DisasContext *s, arg_2shift *a) \
|
||||
{ \
|
||||
static MVEGenTwoOpShiftFn * const fns[] = { \
|
||||
gen_helper_mve_##FN##b, \
|
||||
gen_helper_mve_##FN##h, \
|
||||
}; \
|
||||
return do_2shift(s, a, fns[a->size], false); \
|
||||
}
|
||||
|
||||
DO_2SHIFT_N(VSHRNB, vshrnb)
|
||||
DO_2SHIFT_N(VSHRNT, vshrnt)
|
||||
DO_2SHIFT_N(VRSHRNB, vrshrnb)
|
||||
DO_2SHIFT_N(VRSHRNT, vrshrnt)
|
||||
DO_2SHIFT_N(VQSHRNB_S, vqshrnb_s)
|
||||
DO_2SHIFT_N(VQSHRNT_S, vqshrnt_s)
|
||||
DO_2SHIFT_N(VQSHRNB_U, vqshrnb_u)
|
||||
DO_2SHIFT_N(VQSHRNT_U, vqshrnt_u)
|
||||
DO_2SHIFT_N(VQSHRUNB, vqshrunb)
|
||||
DO_2SHIFT_N(VQSHRUNT, vqshrunt)
|
||||
DO_2SHIFT_N(VQRSHRNB_S, vqrshrnb_s)
|
||||
DO_2SHIFT_N(VQRSHRNT_S, vqrshrnt_s)
|
||||
DO_2SHIFT_N(VQRSHRNB_U, vqrshrnb_u)
|
||||
DO_2SHIFT_N(VQRSHRNT_U, vqrshrnt_u)
|
||||
DO_2SHIFT_N(VQRSHRUNB, vqrshrunb)
|
||||
DO_2SHIFT_N(VQRSHRUNT, vqrshrunt)
|
||||
|
||||
static bool trans_VSHLC(DisasContext *s, arg_VSHLC *a)
|
||||
{
|
||||
/*
|
||||
* Whole Vector Left Shift with Carry. The carry is taken
|
||||
* from a general purpose register and written back there.
|
||||
* An imm of 0 means "shift by 32".
|
||||
*/
|
||||
TCGv_ptr qd;
|
||||
TCGv_i32 rdm;
|
||||
|
||||
if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) {
|
||||
return false;
|
||||
}
|
||||
if (a->rdm == 13 || a->rdm == 15) {
|
||||
/* CONSTRAINED UNPREDICTABLE: we UNDEF */
|
||||
return false;
|
||||
}
|
||||
if (!mve_eci_check(s) || !vfp_access_check(s)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
qd = mve_qreg_ptr(a->qd);
|
||||
rdm = load_reg(s, a->rdm);
|
||||
gen_helper_mve_vshlc(rdm, cpu_env, qd, rdm, tcg_constant_i32(a->imm));
|
||||
store_reg(s, a->rdm, rdm);
|
||||
tcg_temp_free_ptr(qd);
|
||||
mve_update_eci(s);
|
||||
return true;
|
||||
}
|
||||
|
@ -33,24 +33,6 @@ static inline int plus1(DisasContext *s, int x)
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
static inline int rsub_64(DisasContext *s, int x)
|
||||
{
|
||||
return 64 - x;
|
||||
}
|
||||
|
||||
static inline int rsub_32(DisasContext *s, int x)
|
||||
{
|
||||
return 32 - x;
|
||||
}
|
||||
static inline int rsub_16(DisasContext *s, int x)
|
||||
{
|
||||
return 16 - x;
|
||||
}
|
||||
static inline int rsub_8(DisasContext *s, int x)
|
||||
{
|
||||
return 8 - x;
|
||||
}
|
||||
|
||||
static inline int neon_3same_fp_size(DisasContext *s, int x)
|
||||
{
|
||||
/* Convert 0==fp32, 1==fp16 into a MO_* value */
|
||||
@ -1781,69 +1763,6 @@ DO_FP_2SH(VCVT_UH, gen_helper_gvec_vcvt_uh)
|
||||
DO_FP_2SH(VCVT_HS, gen_helper_gvec_vcvt_hs)
|
||||
DO_FP_2SH(VCVT_HU, gen_helper_gvec_vcvt_hu)
|
||||
|
||||
static uint64_t asimd_imm_const(uint32_t imm, int cmode, int op)
|
||||
{
|
||||
/*
|
||||
* Expand the encoded constant.
|
||||
* Note that cmode = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE.
|
||||
* We choose to not special-case this and will behave as if a
|
||||
* valid constant encoding of 0 had been given.
|
||||
* cmode = 15 op = 1 must UNDEF; we assume decode has handled that.
|
||||
*/
|
||||
switch (cmode) {
|
||||
case 0: case 1:
|
||||
/* no-op */
|
||||
break;
|
||||
case 2: case 3:
|
||||
imm <<= 8;
|
||||
break;
|
||||
case 4: case 5:
|
||||
imm <<= 16;
|
||||
break;
|
||||
case 6: case 7:
|
||||
imm <<= 24;
|
||||
break;
|
||||
case 8: case 9:
|
||||
imm |= imm << 16;
|
||||
break;
|
||||
case 10: case 11:
|
||||
imm = (imm << 8) | (imm << 24);
|
||||
break;
|
||||
case 12:
|
||||
imm = (imm << 8) | 0xff;
|
||||
break;
|
||||
case 13:
|
||||
imm = (imm << 16) | 0xffff;
|
||||
break;
|
||||
case 14:
|
||||
if (op) {
|
||||
/*
|
||||
* This is the only case where the top and bottom 32 bits
|
||||
* of the encoded constant differ.
|
||||
*/
|
||||
uint64_t imm64 = 0;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < 8; n++) {
|
||||
if (imm & (1 << n)) {
|
||||
imm64 |= (0xffULL << (n * 8));
|
||||
}
|
||||
}
|
||||
return imm64;
|
||||
}
|
||||
imm |= (imm << 8) | (imm << 16) | (imm << 24);
|
||||
break;
|
||||
case 15:
|
||||
imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
|
||||
| ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
|
||||
break;
|
||||
}
|
||||
if (op) {
|
||||
imm = ~imm;
|
||||
}
|
||||
return dup_const(MO_32, imm);
|
||||
}
|
||||
|
||||
static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a,
|
||||
GVecGen2iFn *fn)
|
||||
{
|
||||
|
@ -90,6 +90,76 @@ void arm_translate_init(void)
|
||||
a64_translate_init();
|
||||
}
|
||||
|
||||
uint64_t asimd_imm_const(uint32_t imm, int cmode, int op)
|
||||
{
|
||||
/* Expand the encoded constant as per AdvSIMDExpandImm pseudocode */
|
||||
switch (cmode) {
|
||||
case 0: case 1:
|
||||
/* no-op */
|
||||
break;
|
||||
case 2: case 3:
|
||||
imm <<= 8;
|
||||
break;
|
||||
case 4: case 5:
|
||||
imm <<= 16;
|
||||
break;
|
||||
case 6: case 7:
|
||||
imm <<= 24;
|
||||
break;
|
||||
case 8: case 9:
|
||||
imm |= imm << 16;
|
||||
break;
|
||||
case 10: case 11:
|
||||
imm = (imm << 8) | (imm << 24);
|
||||
break;
|
||||
case 12:
|
||||
imm = (imm << 8) | 0xff;
|
||||
break;
|
||||
case 13:
|
||||
imm = (imm << 16) | 0xffff;
|
||||
break;
|
||||
case 14:
|
||||
if (op) {
|
||||
/*
|
||||
* This and cmode == 15 op == 1 are the only cases where
|
||||
* the top and bottom 32 bits of the encoded constant differ.
|
||||
*/
|
||||
uint64_t imm64 = 0;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < 8; n++) {
|
||||
if (imm & (1 << n)) {
|
||||
imm64 |= (0xffULL << (n * 8));
|
||||
}
|
||||
}
|
||||
return imm64;
|
||||
}
|
||||
imm |= (imm << 8) | (imm << 16) | (imm << 24);
|
||||
break;
|
||||
case 15:
|
||||
if (op) {
|
||||
/* Reserved encoding for AArch32; valid for AArch64 */
|
||||
uint64_t imm64 = (uint64_t)(imm & 0x3f) << 48;
|
||||
if (imm & 0x80) {
|
||||
imm64 |= 0x8000000000000000ULL;
|
||||
}
|
||||
if (imm & 0x40) {
|
||||
imm64 |= 0x3fc0000000000000ULL;
|
||||
} else {
|
||||
imm64 |= 0x4000000000000000ULL;
|
||||
}
|
||||
return imm64;
|
||||
}
|
||||
imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
|
||||
| ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
|
||||
break;
|
||||
}
|
||||
if (op) {
|
||||
imm = ~imm;
|
||||
}
|
||||
return dup_const(MO_32, imm);
|
||||
}
|
||||
|
||||
/* Generate a label used for skipping this instruction */
|
||||
void arm_gen_condlabel(DisasContext *s)
|
||||
{
|
||||
@ -3148,8 +3218,14 @@ static void gen_srshr16_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh)
|
||||
|
||||
static void gen_srshr32_i32(TCGv_i32 d, TCGv_i32 a, int32_t sh)
|
||||
{
|
||||
TCGv_i32 t = tcg_temp_new_i32();
|
||||
TCGv_i32 t;
|
||||
|
||||
/* Handle shift by the input size for the benefit of trans_SRSHR_ri */
|
||||
if (sh == 32) {
|
||||
tcg_gen_movi_i32(d, 0);
|
||||
return;
|
||||
}
|
||||
t = tcg_temp_new_i32();
|
||||
tcg_gen_extract_i32(t, a, sh - 1, 1);
|
||||
tcg_gen_sari_i32(d, a, sh);
|
||||
tcg_gen_add_i32(d, d, t);
|
||||
@ -3349,8 +3425,14 @@ static void gen_urshr16_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh)
|
||||
|
||||
static void gen_urshr32_i32(TCGv_i32 d, TCGv_i32 a, int32_t sh)
|
||||
{
|
||||
TCGv_i32 t = tcg_temp_new_i32();
|
||||
TCGv_i32 t;
|
||||
|
||||
/* Handle shift by the input size for the benefit of trans_URSHR_ri */
|
||||
if (sh == 32) {
|
||||
tcg_gen_extract_i32(d, a, sh - 1, 1);
|
||||
return;
|
||||
}
|
||||
t = tcg_temp_new_i32();
|
||||
tcg_gen_extract_i32(t, a, sh - 1, 1);
|
||||
tcg_gen_shri_i32(d, a, sh);
|
||||
tcg_gen_add_i32(d, d, t);
|
||||
@ -5632,6 +5714,247 @@ static bool trans_MOVT(DisasContext *s, arg_MOVW *a)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* v8.1M MVE wide-shifts
|
||||
*/
|
||||
static bool do_mve_shl_ri(DisasContext *s, arg_mve_shl_ri *a,
|
||||
WideShiftImmFn *fn)
|
||||
{
|
||||
TCGv_i64 rda;
|
||||
TCGv_i32 rdalo, rdahi;
|
||||
|
||||
if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
|
||||
/* Decode falls through to ORR/MOV UNPREDICTABLE handling */
|
||||
return false;
|
||||
}
|
||||
if (a->rdahi == 15) {
|
||||
/* These are a different encoding (SQSHL/SRSHR/UQSHL/URSHR) */
|
||||
return false;
|
||||
}
|
||||
if (!dc_isar_feature(aa32_mve, s) ||
|
||||
!arm_dc_feature(s, ARM_FEATURE_M_MAIN) ||
|
||||
a->rdahi == 13) {
|
||||
/* RdaHi == 13 is UNPREDICTABLE; we choose to UNDEF */
|
||||
unallocated_encoding(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a->shim == 0) {
|
||||
a->shim = 32;
|
||||
}
|
||||
|
||||
rda = tcg_temp_new_i64();
|
||||
rdalo = load_reg(s, a->rdalo);
|
||||
rdahi = load_reg(s, a->rdahi);
|
||||
tcg_gen_concat_i32_i64(rda, rdalo, rdahi);
|
||||
|
||||
fn(rda, rda, a->shim);
|
||||
|
||||
tcg_gen_extrl_i64_i32(rdalo, rda);
|
||||
tcg_gen_extrh_i64_i32(rdahi, rda);
|
||||
store_reg(s, a->rdalo, rdalo);
|
||||
store_reg(s, a->rdahi, rdahi);
|
||||
tcg_temp_free_i64(rda);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_ASRL_ri(DisasContext *s, arg_mve_shl_ri *a)
|
||||
{
|
||||
return do_mve_shl_ri(s, a, tcg_gen_sari_i64);
|
||||
}
|
||||
|
||||
static bool trans_LSLL_ri(DisasContext *s, arg_mve_shl_ri *a)
|
||||
{
|
||||
return do_mve_shl_ri(s, a, tcg_gen_shli_i64);
|
||||
}
|
||||
|
||||
static bool trans_LSRL_ri(DisasContext *s, arg_mve_shl_ri *a)
|
||||
{
|
||||
return do_mve_shl_ri(s, a, tcg_gen_shri_i64);
|
||||
}
|
||||
|
||||
static void gen_mve_sqshll(TCGv_i64 r, TCGv_i64 n, int64_t shift)
|
||||
{
|
||||
gen_helper_mve_sqshll(r, cpu_env, n, tcg_constant_i32(shift));
|
||||
}
|
||||
|
||||
static bool trans_SQSHLL_ri(DisasContext *s, arg_mve_shl_ri *a)
|
||||
{
|
||||
return do_mve_shl_ri(s, a, gen_mve_sqshll);
|
||||
}
|
||||
|
||||
static void gen_mve_uqshll(TCGv_i64 r, TCGv_i64 n, int64_t shift)
|
||||
{
|
||||
gen_helper_mve_uqshll(r, cpu_env, n, tcg_constant_i32(shift));
|
||||
}
|
||||
|
||||
static bool trans_UQSHLL_ri(DisasContext *s, arg_mve_shl_ri *a)
|
||||
{
|
||||
return do_mve_shl_ri(s, a, gen_mve_uqshll);
|
||||
}
|
||||
|
||||
static bool trans_SRSHRL_ri(DisasContext *s, arg_mve_shl_ri *a)
|
||||
{
|
||||
return do_mve_shl_ri(s, a, gen_srshr64_i64);
|
||||
}
|
||||
|
||||
static bool trans_URSHRL_ri(DisasContext *s, arg_mve_shl_ri *a)
|
||||
{
|
||||
return do_mve_shl_ri(s, a, gen_urshr64_i64);
|
||||
}
|
||||
|
||||
static bool do_mve_shl_rr(DisasContext *s, arg_mve_shl_rr *a, WideShiftFn *fn)
|
||||
{
|
||||
TCGv_i64 rda;
|
||||
TCGv_i32 rdalo, rdahi;
|
||||
|
||||
if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
|
||||
/* Decode falls through to ORR/MOV UNPREDICTABLE handling */
|
||||
return false;
|
||||
}
|
||||
if (a->rdahi == 15) {
|
||||
/* These are a different encoding (SQSHL/SRSHR/UQSHL/URSHR) */
|
||||
return false;
|
||||
}
|
||||
if (!dc_isar_feature(aa32_mve, s) ||
|
||||
!arm_dc_feature(s, ARM_FEATURE_M_MAIN) ||
|
||||
a->rdahi == 13 || a->rm == 13 || a->rm == 15 ||
|
||||
a->rm == a->rdahi || a->rm == a->rdalo) {
|
||||
/* These rdahi/rdalo/rm cases are UNPREDICTABLE; we choose to UNDEF */
|
||||
unallocated_encoding(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
rda = tcg_temp_new_i64();
|
||||
rdalo = load_reg(s, a->rdalo);
|
||||
rdahi = load_reg(s, a->rdahi);
|
||||
tcg_gen_concat_i32_i64(rda, rdalo, rdahi);
|
||||
|
||||
/* The helper takes care of the sign-extension of the low 8 bits of Rm */
|
||||
fn(rda, cpu_env, rda, cpu_R[a->rm]);
|
||||
|
||||
tcg_gen_extrl_i64_i32(rdalo, rda);
|
||||
tcg_gen_extrh_i64_i32(rdahi, rda);
|
||||
store_reg(s, a->rdalo, rdalo);
|
||||
store_reg(s, a->rdahi, rdahi);
|
||||
tcg_temp_free_i64(rda);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_LSLL_rr(DisasContext *s, arg_mve_shl_rr *a)
|
||||
{
|
||||
return do_mve_shl_rr(s, a, gen_helper_mve_ushll);
|
||||
}
|
||||
|
||||
static bool trans_ASRL_rr(DisasContext *s, arg_mve_shl_rr *a)
|
||||
{
|
||||
return do_mve_shl_rr(s, a, gen_helper_mve_sshrl);
|
||||
}
|
||||
|
||||
static bool trans_UQRSHLL64_rr(DisasContext *s, arg_mve_shl_rr *a)
|
||||
{
|
||||
return do_mve_shl_rr(s, a, gen_helper_mve_uqrshll);
|
||||
}
|
||||
|
||||
static bool trans_SQRSHRL64_rr(DisasContext *s, arg_mve_shl_rr *a)
|
||||
{
|
||||
return do_mve_shl_rr(s, a, gen_helper_mve_sqrshrl);
|
||||
}
|
||||
|
||||
static bool trans_UQRSHLL48_rr(DisasContext *s, arg_mve_shl_rr *a)
|
||||
{
|
||||
return do_mve_shl_rr(s, a, gen_helper_mve_uqrshll48);
|
||||
}
|
||||
|
||||
static bool trans_SQRSHRL48_rr(DisasContext *s, arg_mve_shl_rr *a)
|
||||
{
|
||||
return do_mve_shl_rr(s, a, gen_helper_mve_sqrshrl48);
|
||||
}
|
||||
|
||||
static bool do_mve_sh_ri(DisasContext *s, arg_mve_sh_ri *a, ShiftImmFn *fn)
|
||||
{
|
||||
if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
|
||||
/* Decode falls through to ORR/MOV UNPREDICTABLE handling */
|
||||
return false;
|
||||
}
|
||||
if (!dc_isar_feature(aa32_mve, s) ||
|
||||
!arm_dc_feature(s, ARM_FEATURE_M_MAIN) ||
|
||||
a->rda == 13 || a->rda == 15) {
|
||||
/* These rda cases are UNPREDICTABLE; we choose to UNDEF */
|
||||
unallocated_encoding(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a->shim == 0) {
|
||||
a->shim = 32;
|
||||
}
|
||||
fn(cpu_R[a->rda], cpu_R[a->rda], a->shim);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_URSHR_ri(DisasContext *s, arg_mve_sh_ri *a)
|
||||
{
|
||||
return do_mve_sh_ri(s, a, gen_urshr32_i32);
|
||||
}
|
||||
|
||||
static bool trans_SRSHR_ri(DisasContext *s, arg_mve_sh_ri *a)
|
||||
{
|
||||
return do_mve_sh_ri(s, a, gen_srshr32_i32);
|
||||
}
|
||||
|
||||
static void gen_mve_sqshl(TCGv_i32 r, TCGv_i32 n, int32_t shift)
|
||||
{
|
||||
gen_helper_mve_sqshl(r, cpu_env, n, tcg_constant_i32(shift));
|
||||
}
|
||||
|
||||
static bool trans_SQSHL_ri(DisasContext *s, arg_mve_sh_ri *a)
|
||||
{
|
||||
return do_mve_sh_ri(s, a, gen_mve_sqshl);
|
||||
}
|
||||
|
||||
static void gen_mve_uqshl(TCGv_i32 r, TCGv_i32 n, int32_t shift)
|
||||
{
|
||||
gen_helper_mve_uqshl(r, cpu_env, n, tcg_constant_i32(shift));
|
||||
}
|
||||
|
||||
static bool trans_UQSHL_ri(DisasContext *s, arg_mve_sh_ri *a)
|
||||
{
|
||||
return do_mve_sh_ri(s, a, gen_mve_uqshl);
|
||||
}
|
||||
|
||||
static bool do_mve_sh_rr(DisasContext *s, arg_mve_sh_rr *a, ShiftFn *fn)
|
||||
{
|
||||
if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
|
||||
/* Decode falls through to ORR/MOV UNPREDICTABLE handling */
|
||||
return false;
|
||||
}
|
||||
if (!dc_isar_feature(aa32_mve, s) ||
|
||||
!arm_dc_feature(s, ARM_FEATURE_M_MAIN) ||
|
||||
a->rda == 13 || a->rda == 15 || a->rm == 13 || a->rm == 15 ||
|
||||
a->rm == a->rda) {
|
||||
/* These rda/rm cases are UNPREDICTABLE; we choose to UNDEF */
|
||||
unallocated_encoding(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* The helper takes care of the sign-extension of the low 8 bits of Rm */
|
||||
fn(cpu_R[a->rda], cpu_env, cpu_R[a->rda], cpu_R[a->rm]);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_SQRSHR_rr(DisasContext *s, arg_mve_sh_rr *a)
|
||||
{
|
||||
return do_mve_sh_rr(s, a, gen_helper_mve_sqrshr);
|
||||
}
|
||||
|
||||
static bool trans_UQRSHL_rr(DisasContext *s, arg_mve_sh_rr *a)
|
||||
{
|
||||
return do_mve_sh_rr(s, a, gen_helper_mve_uqrshl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Multiply and multiply accumulate
|
||||
*/
|
||||
|
@ -161,6 +161,26 @@ static inline int times_2_plus_1(DisasContext *s, int x)
|
||||
return x * 2 + 1;
|
||||
}
|
||||
|
||||
static inline int rsub_64(DisasContext *s, int x)
|
||||
{
|
||||
return 64 - x;
|
||||
}
|
||||
|
||||
static inline int rsub_32(DisasContext *s, int x)
|
||||
{
|
||||
return 32 - x;
|
||||
}
|
||||
|
||||
static inline int rsub_16(DisasContext *s, int x)
|
||||
{
|
||||
return 16 - x;
|
||||
}
|
||||
|
||||
static inline int rsub_8(DisasContext *s, int x)
|
||||
{
|
||||
return 8 - x;
|
||||
}
|
||||
|
||||
static inline int arm_dc_feature(DisasContext *dc, int feature)
|
||||
{
|
||||
return (dc->features & (1ULL << feature)) != 0;
|
||||
@ -444,6 +464,10 @@ typedef void CryptoTwoOpFn(TCGv_ptr, TCGv_ptr);
|
||||
typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
|
||||
typedef void CryptoThreeOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
|
||||
typedef void AtomicThreeOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGArg, MemOp);
|
||||
typedef void WideShiftImmFn(TCGv_i64, TCGv_i64, int64_t shift);
|
||||
typedef void WideShiftFn(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i32);
|
||||
typedef void ShiftImmFn(TCGv_i32, TCGv_i32, int32_t shift);
|
||||
typedef void ShiftFn(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32);
|
||||
|
||||
/**
|
||||
* arm_tbflags_from_tb:
|
||||
@ -532,4 +556,21 @@ static inline MemOp finalize_memop(DisasContext *s, MemOp opc)
|
||||
return opc | s->be_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* asimd_imm_const: Expand an encoded SIMD constant value
|
||||
*
|
||||
* Expand a SIMD constant value. This is essentially the pseudocode
|
||||
* AdvSIMDExpandImm, except that we also perform the boolean NOT needed for
|
||||
* VMVN and VBIC (when cmode < 14 && op == 1).
|
||||
*
|
||||
* The combination cmode == 15 op == 1 is a reserved encoding for AArch32;
|
||||
* callers must catch this; we return the 64-bit constant value defined
|
||||
* for AArch64.
|
||||
*
|
||||
* cmode = 2,3,4,5,6,7,10,11,12,13 imm=0 was UNPREDICTABLE in v7A but
|
||||
* is either not unpredictable or merely CONSTRAINED UNPREDICTABLE in v8A;
|
||||
* we produce an immediate constant value of 0 in these cases.
|
||||
*/
|
||||
uint64_t asimd_imm_const(uint32_t imm, int cmode, int op);
|
||||
|
||||
#endif /* TARGET_ARM_TRANSLATE_H */
|
||||
|
@ -671,7 +671,9 @@ uint32_t HELPER(recpe_f16)(uint32_t input, void *fpstp)
|
||||
float16 nan = f16;
|
||||
if (float16_is_signaling_nan(f16, fpst)) {
|
||||
float_raise(float_flag_invalid, fpst);
|
||||
nan = float16_silence_nan(f16, fpst);
|
||||
if (!fpst->default_nan_mode) {
|
||||
nan = float16_silence_nan(f16, fpst);
|
||||
}
|
||||
}
|
||||
if (fpst->default_nan_mode) {
|
||||
nan = float16_default_nan(fpst);
|
||||
@ -719,7 +721,9 @@ float32 HELPER(recpe_f32)(float32 input, void *fpstp)
|
||||
float32 nan = f32;
|
||||
if (float32_is_signaling_nan(f32, fpst)) {
|
||||
float_raise(float_flag_invalid, fpst);
|
||||
nan = float32_silence_nan(f32, fpst);
|
||||
if (!fpst->default_nan_mode) {
|
||||
nan = float32_silence_nan(f32, fpst);
|
||||
}
|
||||
}
|
||||
if (fpst->default_nan_mode) {
|
||||
nan = float32_default_nan(fpst);
|
||||
@ -767,7 +771,9 @@ float64 HELPER(recpe_f64)(float64 input, void *fpstp)
|
||||
float64 nan = f64;
|
||||
if (float64_is_signaling_nan(f64, fpst)) {
|
||||
float_raise(float_flag_invalid, fpst);
|
||||
nan = float64_silence_nan(f64, fpst);
|
||||
if (!fpst->default_nan_mode) {
|
||||
nan = float64_silence_nan(f64, fpst);
|
||||
}
|
||||
}
|
||||
if (fpst->default_nan_mode) {
|
||||
nan = float64_default_nan(fpst);
|
||||
@ -866,7 +872,9 @@ uint32_t HELPER(rsqrte_f16)(uint32_t input, void *fpstp)
|
||||
float16 nan = f16;
|
||||
if (float16_is_signaling_nan(f16, s)) {
|
||||
float_raise(float_flag_invalid, s);
|
||||
nan = float16_silence_nan(f16, s);
|
||||
if (!s->default_nan_mode) {
|
||||
nan = float16_silence_nan(f16, fpstp);
|
||||
}
|
||||
}
|
||||
if (s->default_nan_mode) {
|
||||
nan = float16_default_nan(s);
|
||||
@ -910,7 +918,9 @@ float32 HELPER(rsqrte_f32)(float32 input, void *fpstp)
|
||||
float32 nan = f32;
|
||||
if (float32_is_signaling_nan(f32, s)) {
|
||||
float_raise(float_flag_invalid, s);
|
||||
nan = float32_silence_nan(f32, s);
|
||||
if (!s->default_nan_mode) {
|
||||
nan = float32_silence_nan(f32, fpstp);
|
||||
}
|
||||
}
|
||||
if (s->default_nan_mode) {
|
||||
nan = float32_default_nan(s);
|
||||
@ -953,7 +963,9 @@ float64 HELPER(rsqrte_f64)(float64 input, void *fpstp)
|
||||
float64 nan = f64;
|
||||
if (float64_is_signaling_nan(f64, s)) {
|
||||
float_raise(float_flag_invalid, s);
|
||||
nan = float64_silence_nan(f64, s);
|
||||
if (!s->default_nan_mode) {
|
||||
nan = float64_silence_nan(f64, fpstp);
|
||||
}
|
||||
}
|
||||
if (s->default_nan_mode) {
|
||||
nan = float64_default_nan(s);
|
||||
|
@ -16,6 +16,7 @@ import shutil
|
||||
from avocado import skip
|
||||
from avocado import skipUnless
|
||||
from avocado_qemu import Test
|
||||
from avocado_qemu import exec_command
|
||||
from avocado_qemu import exec_command_and_wait_for_pattern
|
||||
from avocado_qemu import interrupt_interactive_console_until_pattern
|
||||
from avocado_qemu import wait_for_console_pattern
|
||||
@ -477,6 +478,48 @@ class BootLinuxConsole(LinuxKernelTest):
|
||||
"""
|
||||
self.do_test_arm_raspi2(0)
|
||||
|
||||
def test_arm_raspi2_initrd(self):
|
||||
"""
|
||||
:avocado: tags=arch:arm
|
||||
:avocado: tags=machine:raspi2
|
||||
"""
|
||||
deb_url = ('http://archive.raspberrypi.org/debian/'
|
||||
'pool/main/r/raspberrypi-firmware/'
|
||||
'raspberrypi-kernel_1.20190215-1_armhf.deb')
|
||||
deb_hash = 'cd284220b32128c5084037553db3c482426f3972'
|
||||
deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
|
||||
kernel_path = self.extract_from_deb(deb_path, '/boot/kernel7.img')
|
||||
dtb_path = self.extract_from_deb(deb_path, '/boot/bcm2709-rpi-2-b.dtb')
|
||||
|
||||
initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
|
||||
'2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
|
||||
'arm/rootfs-armv7a.cpio.gz')
|
||||
initrd_hash = '604b2e45cdf35045846b8bbfbf2129b1891bdc9c'
|
||||
initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
|
||||
initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
|
||||
archive.gzip_uncompress(initrd_path_gz, initrd_path)
|
||||
|
||||
self.vm.set_console()
|
||||
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
|
||||
'earlycon=pl011,0x3f201000 console=ttyAMA0 '
|
||||
'panic=-1 noreboot ' +
|
||||
'dwc_otg.fiq_fsm_enable=0')
|
||||
self.vm.add_args('-kernel', kernel_path,
|
||||
'-dtb', dtb_path,
|
||||
'-initrd', initrd_path,
|
||||
'-append', kernel_command_line,
|
||||
'-no-reboot')
|
||||
self.vm.launch()
|
||||
self.wait_for_console_pattern('Boot successful.')
|
||||
|
||||
exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
|
||||
'BCM2835')
|
||||
exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
|
||||
'/soc/cprman@7e101000')
|
||||
exec_command(self, 'halt')
|
||||
# Wait for VM to shut down gracefully
|
||||
self.vm.wait()
|
||||
|
||||
def test_arm_exynos4210_initrd(self):
|
||||
"""
|
||||
:avocado: tags=arch:arm
|
||||
|
Loading…
Reference in New Issue
Block a user