aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2024-12-14 08:42:15 -0500
committerStefan Hajnoczi <stefanha@redhat.com>2024-12-14 08:42:15 -0500
commit94b57605c1c084d2cb399d868a53f123aafb9f55 (patch)
tree0cc6e325cd5272c5c4d05925d9a2ca150523bac1
parent7fa7aa8114dc5f97f28446a9fe98182d4968be63 (diff)
parent48e652c4bd9570f6f24def25355cb3009a7300f8 (diff)
downloadqemu-94b57605c1c084d2cb399d868a53f123aafb9f55.zip
qemu-94b57605c1c084d2cb399d868a53f123aafb9f55.tar.gz
qemu-94b57605c1c084d2cb399d868a53f123aafb9f55.tar.bz2
Merge tag 'pull-target-arm-20241213' of https://git.linaro.org/people/pmaydell/qemu-arm into staging
target-arm queue: * Finish conversion of A64 decoder to decodetree * Use float_round_to_odd in helper_fcvtx_f64_to_f32 * Move TLBI insn emulation code out to its own source file * docs/system/arm: fix broken links, document undocumented properties * MAINTAINERS: correct an email address # -----BEGIN PGP SIGNATURE----- # # iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmdcYCcZHHBldGVyLm1h # eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3usmD/9x6yTRxIK2mi0CjY0Bii89 # hL1Z3n2bxRDu+WoMcsQKXQM5RcixILJyMsnArOxI3D1bVEkAskuaVcXL0uS7Inq6 # EkEq8Z5lfRikAP698U2tzaGhKRiE4NT/cNgOoFLddkjqvZ1tq3sSbPcCudSWkP+u # Z3c5etP8llGNhokNhKmIifE/auxiFdPh8JRXHAF3KhNu4VOX7gNWnt4YZNhnV2XN # TsD+IxU9LCfI8pIFK95zBUIQT/361lIoiY/r7RpN21HeEuS+4wXT/Vfii6rEgsg5 # pNkPoxX/Tc+67l4wXzgoV/p2I1KZbJZ/s7Ta5wLmopidwi2EP9ETVcfTzKIF+PIJ # 08nozInD+fxlyGBezTRDmuIKiC4t1lVW8TP8znyp3TcSHFs5Q/iQY0uPACzoUVuE # chMIt4dD6NlMxOanWANbsVlF+ZPc8MVBMz3zHVbvkOiogoRQYjuDqQIQAhLbQolg # uC/ql79WnUe0IX1j9rcW7+DVNq/bObLCN89uSjigHO2bo5FKKr4pnOG/SaAyER5L # T/OHy1ACcxGNVIiUwKEDxdQ5iwcl+GEJfMfrpJHlTzxeZggL2lE0mcpXaHGLTzXV # K7fSOBI15T+aRqN0/29Rtsw8ayMV5/RmnanesPmC2VN86ZCE0OKGOcLEdaI+q3iT # CMxIsCUCpMM4WjbdJ69ZgQ== # =wQ1l # -----END PGP SIGNATURE----- # gpg: Signature made Fri 13 Dec 2024 11:26:15 EST # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [full] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [full] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [full] # gpg: aka "Peter Maydell <peter@archaic.org.uk>" [unknown] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * tag 'pull-target-arm-20241213' of https://git.linaro.org/people/pmaydell/qemu-arm: (85 commits) target/arm: Simplify condition for tlbi_el2_cp_reginfo[] target/arm: Move RME TLB insns to tlb-insns.c target/arm: Move small helper functions to tlb-insns.c target/arm: Move the TLBI OS insns to tlb-insns.c. target/arm: Move TLBI range insns target/arm: Move AArch64 EL3 TLBI insns target/arm: Move the AArch64 EL2 TLBI insns target/arm: Move AArch64 TLBI insns from v8_cp_reginfo[] target/arm: Move TLBI insns for AArch32 EL2 to tlbi_insn_helper.c target/arm: Move some TLBI insns to their own source file MAINTAINERS: correct my email address docs/system/arm/virt: document missing properties docs/system/arm/xlnx-versal-virt: document ospi-flash property docs/system/arm/fby35: document execute-in-place property docs/system/arm/orangepi: update links target/arm: Use float_round_to_odd in helper_fcvtx_f64_to_f32 target/arm: Convert FCVTL to decodetree target/arm: Convert URECPE and URSQRTE to decodetree target/arm: Introduce gen_gvec_urecpe, gen_gvec_ursqrte target/arm: Convert FRECPE, FRECPX, FRSQRTE to decodetree ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
-rw-r--r--MAINTAINERS2
-rw-r--r--docs/system/arm/fby35.rst5
-rw-r--r--docs/system/arm/orangepi.rst4
-rw-r--r--docs/system/arm/virt.rst16
-rw-r--r--docs/system/arm/xlnx-versal-virt.rst3
-rw-r--r--target/arm/helper.c1208
-rw-r--r--target/arm/helper.h43
-rw-r--r--target/arm/internals.h9
-rw-r--r--target/arm/tcg-stubs.c5
-rw-r--r--target/arm/tcg/a64.decode502
-rw-r--r--target/arm/tcg/gengvec.c369
-rw-r--r--target/arm/tcg/helper-a64.c124
-rw-r--r--target/arm/tcg/helper-a64.h7
-rw-r--r--target/arm/tcg/meson.build1
-rw-r--r--target/arm/tcg/neon_helper.c106
-rw-r--r--target/arm/tcg/tlb-insns.c1266
-rw-r--r--target/arm/tcg/translate-a64.c5314
-rw-r--r--target/arm/tcg/translate-neon.c337
-rw-r--r--target/arm/tcg/translate-vfp.c6
-rw-r--r--target/arm/tcg/translate.h35
-rw-r--r--target/arm/tcg/vec_helper.c65
-rw-r--r--target/arm/vfp_helper.c16
22 files changed, 4026 insertions, 5417 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 7c1ab51..822f343 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -226,7 +226,7 @@ F: target/avr/
F: tests/functional/test_avr_mega2560.py
Hexagon TCG CPUs
-M: Brian Cain <bcain@oss.qualcomm.com>
+M: Brian Cain <brian.cain@oss.qualcomm.com>
S: Supported
F: target/hexagon/
X: target/hexagon/idef-parser/
diff --git a/docs/system/arm/fby35.rst b/docs/system/arm/fby35.rst
index bf6da6b..e19274e 100644
--- a/docs/system/arm/fby35.rst
+++ b/docs/system/arm/fby35.rst
@@ -45,3 +45,8 @@ process starts.
$ screen /dev/tty0 # In a separate TMUX pane, terminal window, etc.
$ screen /dev/tty1
$ (qemu) c # Start the boot process once screen is setup.
+
+This machine model supports emulation of the boot from the CE0 flash device by
+setting option ``execute-in-place``. When using this option, the CPU fetches
+instructions to execute by reading CE0 and not from a preloaded ROM
+initialized at machine init time. As a result, execution will be slower.
diff --git a/docs/system/arm/orangepi.rst b/docs/system/arm/orangepi.rst
index 9afa542..db87e81 100644
--- a/docs/system/arm/orangepi.rst
+++ b/docs/system/arm/orangepi.rst
@@ -119,7 +119,7 @@ Orange Pi PC images
Note that the mainline kernel does not have a root filesystem. You may provide it
with an official Orange Pi PC image from the official website:
- http://www.orangepi.org/downloadresources/
+ http://www.orangepi.org/html/serviceAndSupport/index.html
Another possibility is to run an Armbian image for Orange Pi PC which
can be downloaded from:
@@ -213,7 +213,7 @@ including the Orange Pi PC. NetBSD 9.0 is known to work best for the Orange Pi P
board and provides a fully working system with serial console, networking and storage.
For the Orange Pi PC machine, get the 'evbarm-earmv7hf' based image from:
- https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/evbarm-earmv7hf/binary/gzimg/armv7.img.gz
+ https://archive.netbsd.org/pub/NetBSD-archive/NetBSD-9.0/evbarm-earmv7hf/binary/gzimg/armv7.img.gz
The image requires manually installing U-Boot in the image. Build U-Boot with
the orangepi_pc_defconfig configuration as described in the previous section.
diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst
index e67e7f0..f87adeb 100644
--- a/docs/system/arm/virt.rst
+++ b/docs/system/arm/virt.rst
@@ -167,10 +167,18 @@ iommu
``smmuv3``
Create an SMMUv3
+default-bus-bypass-iommu
+ Set ``on``/``off`` to enable/disable `bypass_iommu
+ <https://gitlab.com/qemu-project/qemu/-/blob/master/docs/bypass-iommu.txt>`_
+ for default root bus.
+
ras
Set ``on``/``off`` to enable/disable reporting host memory errors to a guest
using ACPI and guest external abort exceptions. The default is off.
+acpi
+ Set ``on``/``off``/``auto`` to enable/disable ACPI.
+
dtb-randomness
Set ``on``/``off`` to pass random seeds via the guest DTB
rng-seed and kaslr-seed nodes (in both "/chosen" and
@@ -184,6 +192,14 @@ dtb-randomness
dtb-kaslr-seed
A deprecated synonym for dtb-randomness.
+x-oem-id
+ Set string (up to 6 bytes) to override the default value of field OEMID in ACPI
+ table header.
+
+x-oem-table-id
+ Set string (up to 8 bytes) to override the default value of field OEM Table ID
+ in ACPI table header.
+
Linux guest kernel configuration
""""""""""""""""""""""""""""""""
diff --git a/docs/system/arm/xlnx-versal-virt.rst b/docs/system/arm/xlnx-versal-virt.rst
index 0bafc76..c5f35f2 100644
--- a/docs/system/arm/xlnx-versal-virt.rst
+++ b/docs/system/arm/xlnx-versal-virt.rst
@@ -178,6 +178,9 @@ Run the following at the U-Boot prompt:
fdt set /chosen/dom0 reg <0x00000000 0x40000000 0x0 0x03100000>
booti 30000000 - 20000000
+It's possible to change the OSPI flash model emulated by using the machine model
+option ``ospi-flash``.
+
BBRAM File Backend
""""""""""""""""""
BBRAM can have an optional file backend, which must be a seekable
diff --git a/target/arm/helper.c b/target/arm/helper.c
index f38eb05..910ae62 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -365,40 +365,6 @@ static CPAccessResult access_tacr(CPUARMState *env, const ARMCPRegInfo *ri,
return CP_ACCESS_OK;
}
-/* Check for traps from EL1 due to HCR_EL2.TTLB. */
-static CPAccessResult access_ttlb(CPUARMState *env, const ARMCPRegInfo *ri,
- bool isread)
-{
- if (arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_TTLB)) {
- return CP_ACCESS_TRAP_EL2;
- }
- return CP_ACCESS_OK;
-}
-
-/* Check for traps from EL1 due to HCR_EL2.TTLB or TTLBIS. */
-static CPAccessResult access_ttlbis(CPUARMState *env, const ARMCPRegInfo *ri,
- bool isread)
-{
- if (arm_current_el(env) == 1 &&
- (arm_hcr_el2_eff(env) & (HCR_TTLB | HCR_TTLBIS))) {
- return CP_ACCESS_TRAP_EL2;
- }
- return CP_ACCESS_OK;
-}
-
-#ifdef TARGET_AARCH64
-/* Check for traps from EL1 due to HCR_EL2.TTLB or TTLBOS. */
-static CPAccessResult access_ttlbos(CPUARMState *env, const ARMCPRegInfo *ri,
- bool isread)
-{
- if (arm_current_el(env) == 1 &&
- (arm_hcr_el2_eff(env) & (HCR_TTLB | HCR_TTLBOS))) {
- return CP_ACCESS_TRAP_EL2;
- }
- return CP_ACCESS_OK;
-}
-#endif
-
static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
{
ARMCPU *cpu = env_archcpu(env);
@@ -438,7 +404,7 @@ static void contextidr_write(CPUARMState *env, const ARMCPRegInfo *ri,
raw_write(env, ri, value);
}
-static int alle1_tlbmask(CPUARMState *env)
+int alle1_tlbmask(CPUARMState *env)
{
/*
* Note that the 'ALL' scope must invalidate both stage 1 and
@@ -455,174 +421,6 @@ static int alle1_tlbmask(CPUARMState *env)
ARMMMUIdxBit_Stage2_S);
}
-
-/* IS variants of TLB operations must affect all cores */
-static void tlbiall_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
-
- tlb_flush_all_cpus_synced(cs);
-}
-
-static void tlbiasid_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
-
- tlb_flush_all_cpus_synced(cs);
-}
-
-static void tlbimva_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
-
- tlb_flush_page_all_cpus_synced(cs, value & TARGET_PAGE_MASK);
-}
-
-static void tlbimvaa_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
-
- tlb_flush_page_all_cpus_synced(cs, value & TARGET_PAGE_MASK);
-}
-
-/*
- * Non-IS variants of TLB operations are upgraded to
- * IS versions if we are at EL1 and HCR_EL2.FB is effectively set to
- * force broadcast of these operations.
- */
-static bool tlb_force_broadcast(CPUARMState *env)
-{
- return arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_FB);
-}
-
-static void tlbiall_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- /* Invalidate all (TLBIALL) */
- CPUState *cs = env_cpu(env);
-
- if (tlb_force_broadcast(env)) {
- tlb_flush_all_cpus_synced(cs);
- } else {
- tlb_flush(cs);
- }
-}
-
-static void tlbimva_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- /* Invalidate single TLB entry by MVA and ASID (TLBIMVA) */
- CPUState *cs = env_cpu(env);
-
- value &= TARGET_PAGE_MASK;
- if (tlb_force_broadcast(env)) {
- tlb_flush_page_all_cpus_synced(cs, value);
- } else {
- tlb_flush_page(cs, value);
- }
-}
-
-static void tlbiasid_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- /* Invalidate by ASID (TLBIASID) */
- CPUState *cs = env_cpu(env);
-
- if (tlb_force_broadcast(env)) {
- tlb_flush_all_cpus_synced(cs);
- } else {
- tlb_flush(cs);
- }
-}
-
-static void tlbimvaa_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- /* Invalidate single entry by MVA, all ASIDs (TLBIMVAA) */
- CPUState *cs = env_cpu(env);
-
- value &= TARGET_PAGE_MASK;
- if (tlb_force_broadcast(env)) {
- tlb_flush_page_all_cpus_synced(cs, value);
- } else {
- tlb_flush_page(cs, value);
- }
-}
-
-static void tlbiall_nsnh_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
-
- tlb_flush_by_mmuidx(cs, alle1_tlbmask(env));
-}
-
-static void tlbiall_nsnh_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
-
- tlb_flush_by_mmuidx_all_cpus_synced(cs, alle1_tlbmask(env));
-}
-
-
-static void tlbiall_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
-
- tlb_flush_by_mmuidx(cs, ARMMMUIdxBit_E2);
-}
-
-static void tlbiall_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
-
- tlb_flush_by_mmuidx_all_cpus_synced(cs, ARMMMUIdxBit_E2);
-}
-
-static void tlbimva_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
- uint64_t pageaddr = value & ~MAKE_64BIT_MASK(0, 12);
-
- tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_E2);
-}
-
-static void tlbimva_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
- uint64_t pageaddr = value & ~MAKE_64BIT_MASK(0, 12);
-
- tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr,
- ARMMMUIdxBit_E2);
-}
-
-static void tlbiipas2_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
- uint64_t pageaddr = (value & MAKE_64BIT_MASK(0, 28)) << 12;
-
- tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_Stage2);
-}
-
-static void tlbiipas2is_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
- uint64_t pageaddr = (value & MAKE_64BIT_MASK(0, 28)) << 12;
-
- tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, ARMMMUIdxBit_Stage2);
-}
-
static const ARMCPRegInfo cp_reginfo[] = {
/*
* Define the secure and non-secure FCSE identifier CP registers
@@ -732,22 +530,6 @@ static const ARMCPRegInfo not_v7_cp_reginfo[] = {
*/
{ .name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0,
.access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 },
- /*
- * MMU TLB control. Note that the wildcarding means we cover not just
- * the unified TLB ops but also the dside/iside/inner-shareable variants.
- */
- { .name = "TLBIALL", .cp = 15, .crn = 8, .crm = CP_ANY,
- .opc1 = CP_ANY, .opc2 = 0, .access = PL1_W, .writefn = tlbiall_write,
- .type = ARM_CP_NO_RAW },
- { .name = "TLBIMVA", .cp = 15, .crn = 8, .crm = CP_ANY,
- .opc1 = CP_ANY, .opc2 = 1, .access = PL1_W, .writefn = tlbimva_write,
- .type = ARM_CP_NO_RAW },
- { .name = "TLBIASID", .cp = 15, .crn = 8, .crm = CP_ANY,
- .opc1 = CP_ANY, .opc2 = 2, .access = PL1_W, .writefn = tlbiasid_write,
- .type = ARM_CP_NO_RAW },
- { .name = "TLBIMVAA", .cp = 15, .crn = 8, .crm = CP_ANY,
- .opc1 = CP_ANY, .opc2 = 3, .access = PL1_W, .writefn = tlbimvaa_write,
- .type = ARM_CP_NO_RAW },
{ .name = "PRRR", .cp = 15, .crn = 10, .crm = 2,
.opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_NOP },
{ .name = "NMRR", .cp = 15, .crn = 10, .crm = 2,
@@ -2331,55 +2113,6 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
.opc0 = 3, .opc1 = 0, .crn = 12, .crm = 1, .opc2 = 0,
.fgt = FGT_ISR_EL1,
.type = ARM_CP_NO_RAW, .access = PL1_R, .readfn = isr_read },
- /* 32 bit ITLB invalidates */
- { .name = "ITLBIALL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 0,
- .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
- .writefn = tlbiall_write },
- { .name = "ITLBIMVA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 1,
- .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
- .writefn = tlbimva_write },
- { .name = "ITLBIASID", .cp = 15, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 2,
- .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
- .writefn = tlbiasid_write },
- /* 32 bit DTLB invalidates */
- { .name = "DTLBIALL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 0,
- .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
- .writefn = tlbiall_write },
- { .name = "DTLBIMVA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 1,
- .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
- .writefn = tlbimva_write },
- { .name = "DTLBIASID", .cp = 15, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 2,
- .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
- .writefn = tlbiasid_write },
- /* 32 bit TLB invalidates */
- { .name = "TLBIALL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 0,
- .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
- .writefn = tlbiall_write },
- { .name = "TLBIMVA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 1,
- .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
- .writefn = tlbimva_write },
- { .name = "TLBIASID", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 2,
- .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
- .writefn = tlbiasid_write },
- { .name = "TLBIMVAA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 3,
- .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
- .writefn = tlbimvaa_write },
-};
-
-static const ARMCPRegInfo v7mp_cp_reginfo[] = {
- /* 32 bit TLB invalidates, Inner Shareable */
- { .name = "TLBIALLIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0,
- .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
- .writefn = tlbiall_is_write },
- { .name = "TLBIMVAIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 1,
- .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
- .writefn = tlbimva_is_write },
- { .name = "TLBIASIDIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 2,
- .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
- .writefn = tlbiasid_is_write },
- { .name = "TLBIMVAAIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 3,
- .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
- .writefn = tlbimvaa_is_write },
};
static const ARMCPRegInfo pmovsset_cp_reginfo[] = {
@@ -4903,494 +4636,6 @@ static CPAccessResult access_tocu(CPUARMState *env, const ARMCPRegInfo *ri,
return do_cacheop_pou_access(env, HCR_TOCU | HCR_TPU);
}
-/*
- * See: D4.7.2 TLB maintenance requirements and the TLB maintenance instructions
- * Page D4-1736 (DDI0487A.b)
- */
-
-static int vae1_tlbmask(CPUARMState *env)
-{
- uint64_t hcr = arm_hcr_el2_eff(env);
- uint16_t mask;
-
- assert(arm_feature(env, ARM_FEATURE_AARCH64));
-
- if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
- mask = ARMMMUIdxBit_E20_2 |
- ARMMMUIdxBit_E20_2_PAN |
- ARMMMUIdxBit_E20_0;
- } else {
- /* This is AArch64 only, so we don't need to touch the EL30_x TLBs */
- mask = ARMMMUIdxBit_E10_1 |
- ARMMMUIdxBit_E10_1_PAN |
- ARMMMUIdxBit_E10_0;
- }
- return mask;
-}
-
-static int vae2_tlbmask(CPUARMState *env)
-{
- uint64_t hcr = arm_hcr_el2_eff(env);
- uint16_t mask;
-
- if (hcr & HCR_E2H) {
- mask = ARMMMUIdxBit_E20_2 |
- ARMMMUIdxBit_E20_2_PAN |
- ARMMMUIdxBit_E20_0;
- } else {
- mask = ARMMMUIdxBit_E2;
- }
- return mask;
-}
-
-/* Return 56 if TBI is enabled, 64 otherwise. */
-static int tlbbits_for_regime(CPUARMState *env, ARMMMUIdx mmu_idx,
- uint64_t addr)
-{
- uint64_t tcr = regime_tcr(env, mmu_idx);
- int tbi = aa64_va_parameter_tbi(tcr, mmu_idx);
- int select = extract64(addr, 55, 1);
-
- return (tbi >> select) & 1 ? 56 : 64;
-}
-
-static int vae1_tlbbits(CPUARMState *env, uint64_t addr)
-{
- uint64_t hcr = arm_hcr_el2_eff(env);
- ARMMMUIdx mmu_idx;
-
- assert(arm_feature(env, ARM_FEATURE_AARCH64));
-
- /* Only the regime of the mmu_idx below is significant. */
- if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
- mmu_idx = ARMMMUIdx_E20_0;
- } else {
- mmu_idx = ARMMMUIdx_E10_0;
- }
-
- return tlbbits_for_regime(env, mmu_idx, addr);
-}
-
-static int vae2_tlbbits(CPUARMState *env, uint64_t addr)
-{
- uint64_t hcr = arm_hcr_el2_eff(env);
- ARMMMUIdx mmu_idx;
-
- /*
- * Only the regime of the mmu_idx below is significant.
- * Regime EL2&0 has two ranges with separate TBI configuration, while EL2
- * only has one.
- */
- if (hcr & HCR_E2H) {
- mmu_idx = ARMMMUIdx_E20_2;
- } else {
- mmu_idx = ARMMMUIdx_E2;
- }
-
- return tlbbits_for_regime(env, mmu_idx, addr);
-}
-
-static void tlbi_aa64_vmalle1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
- int mask = vae1_tlbmask(env);
-
- tlb_flush_by_mmuidx_all_cpus_synced(cs, mask);
-}
-
-static void tlbi_aa64_vmalle1_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
- int mask = vae1_tlbmask(env);
-
- if (tlb_force_broadcast(env)) {
- tlb_flush_by_mmuidx_all_cpus_synced(cs, mask);
- } else {
- tlb_flush_by_mmuidx(cs, mask);
- }
-}
-
-static int e2_tlbmask(CPUARMState *env)
-{
- return (ARMMMUIdxBit_E20_0 |
- ARMMMUIdxBit_E20_2 |
- ARMMMUIdxBit_E20_2_PAN |
- ARMMMUIdxBit_E2);
-}
-
-static void tlbi_aa64_alle1_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
- int mask = alle1_tlbmask(env);
-
- tlb_flush_by_mmuidx(cs, mask);
-}
-
-static void tlbi_aa64_alle2_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
- int mask = e2_tlbmask(env);
-
- tlb_flush_by_mmuidx(cs, mask);
-}
-
-static void tlbi_aa64_alle3_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- ARMCPU *cpu = env_archcpu(env);
- CPUState *cs = CPU(cpu);
-
- tlb_flush_by_mmuidx(cs, ARMMMUIdxBit_E3);
-}
-
-static void tlbi_aa64_alle1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
- int mask = alle1_tlbmask(env);
-
- tlb_flush_by_mmuidx_all_cpus_synced(cs, mask);
-}
-
-static void tlbi_aa64_alle2is_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
- int mask = e2_tlbmask(env);
-
- tlb_flush_by_mmuidx_all_cpus_synced(cs, mask);
-}
-
-static void tlbi_aa64_alle3is_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
-
- tlb_flush_by_mmuidx_all_cpus_synced(cs, ARMMMUIdxBit_E3);
-}
-
-static void tlbi_aa64_vae2_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- /*
- * Invalidate by VA, EL2
- * Currently handles both VAE2 and VALE2, since we don't support
- * flush-last-level-only.
- */
- CPUState *cs = env_cpu(env);
- int mask = vae2_tlbmask(env);
- uint64_t pageaddr = sextract64(value << 12, 0, 56);
- int bits = vae2_tlbbits(env, pageaddr);
-
- tlb_flush_page_bits_by_mmuidx(cs, pageaddr, mask, bits);
-}
-
-static void tlbi_aa64_vae3_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- /*
- * Invalidate by VA, EL3
- * Currently handles both VAE3 and VALE3, since we don't support
- * flush-last-level-only.
- */
- ARMCPU *cpu = env_archcpu(env);
- CPUState *cs = CPU(cpu);
- uint64_t pageaddr = sextract64(value << 12, 0, 56);
-
- tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_E3);
-}
-
-static void tlbi_aa64_vae1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
- int mask = vae1_tlbmask(env);
- uint64_t pageaddr = sextract64(value << 12, 0, 56);
- int bits = vae1_tlbbits(env, pageaddr);
-
- tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits);
-}
-
-static void tlbi_aa64_vae1_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- /*
- * Invalidate by VA, EL1&0 (AArch64 version).
- * Currently handles all of VAE1, VAAE1, VAALE1 and VALE1,
- * since we don't support flush-for-specific-ASID-only or
- * flush-last-level-only.
- */
- CPUState *cs = env_cpu(env);
- int mask = vae1_tlbmask(env);
- uint64_t pageaddr = sextract64(value << 12, 0, 56);
- int bits = vae1_tlbbits(env, pageaddr);
-
- if (tlb_force_broadcast(env)) {
- tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits);
- } else {
- tlb_flush_page_bits_by_mmuidx(cs, pageaddr, mask, bits);
- }
-}
-
-static void tlbi_aa64_vae2is_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
- int mask = vae2_tlbmask(env);
- uint64_t pageaddr = sextract64(value << 12, 0, 56);
- int bits = vae2_tlbbits(env, pageaddr);
-
- tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits);
-}
-
-static void tlbi_aa64_vae3is_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
- uint64_t pageaddr = sextract64(value << 12, 0, 56);
- int bits = tlbbits_for_regime(env, ARMMMUIdx_E3, pageaddr);
-
- tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr,
- ARMMMUIdxBit_E3, bits);
-}
-
-static int ipas2e1_tlbmask(CPUARMState *env, int64_t value)
-{
- /*
- * The MSB of value is the NS field, which only applies if SEL2
- * is implemented and SCR_EL3.NS is not set (i.e. in secure mode).
- */
- return (value >= 0
- && cpu_isar_feature(aa64_sel2, env_archcpu(env))
- && arm_is_secure_below_el3(env)
- ? ARMMMUIdxBit_Stage2_S
- : ARMMMUIdxBit_Stage2);
-}
-
-static void tlbi_aa64_ipas2e1_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
- int mask = ipas2e1_tlbmask(env, value);
- uint64_t pageaddr = sextract64(value << 12, 0, 56);
-
- if (tlb_force_broadcast(env)) {
- tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, mask);
- } else {
- tlb_flush_page_by_mmuidx(cs, pageaddr, mask);
- }
-}
-
-static void tlbi_aa64_ipas2e1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
- int mask = ipas2e1_tlbmask(env, value);
- uint64_t pageaddr = sextract64(value << 12, 0, 56);
-
- tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, mask);
-}
-
-#ifdef TARGET_AARCH64
-typedef struct {
- uint64_t base;
- uint64_t length;
-} TLBIRange;
-
-static ARMGranuleSize tlbi_range_tg_to_gran_size(int tg)
-{
- /*
- * Note that the TLBI range TG field encoding differs from both
- * TG0 and TG1 encodings.
- */
- switch (tg) {
- case 1:
- return Gran4K;
- case 2:
- return Gran16K;
- case 3:
- return Gran64K;
- default:
- return GranInvalid;
- }
-}
-
-static TLBIRange tlbi_aa64_get_range(CPUARMState *env, ARMMMUIdx mmuidx,
- uint64_t value)
-{
- unsigned int page_size_granule, page_shift, num, scale, exponent;
- /* Extract one bit to represent the va selector in use. */
- uint64_t select = sextract64(value, 36, 1);
- ARMVAParameters param = aa64_va_parameters(env, select, mmuidx, true, false);
- TLBIRange ret = { };
- ARMGranuleSize gran;
-
- page_size_granule = extract64(value, 46, 2);
- gran = tlbi_range_tg_to_gran_size(page_size_granule);
-
- /* The granule encoded in value must match the granule in use. */
- if (gran != param.gran) {
- qemu_log_mask(LOG_GUEST_ERROR, "Invalid tlbi page size granule %d\n",
- page_size_granule);
- return ret;
- }
-
- page_shift = arm_granule_bits(gran);
- num = extract64(value, 39, 5);
- scale = extract64(value, 44, 2);
- exponent = (5 * scale) + 1;
-
- ret.length = (num + 1) << (exponent + page_shift);
-
- if (param.select) {
- ret.base = sextract64(value, 0, 37);
- } else {
- ret.base = extract64(value, 0, 37);
- }
- if (param.ds) {
- /*
- * With DS=1, BaseADDR is always shifted 16 so that it is able
- * to address all 52 va bits. The input address is perforce
- * aligned on a 64k boundary regardless of translation granule.
- */
- page_shift = 16;
- }
- ret.base <<= page_shift;
-
- return ret;
-}
-
-static void do_rvae_write(CPUARMState *env, uint64_t value,
- int idxmap, bool synced)
-{
- ARMMMUIdx one_idx = ARM_MMU_IDX_A | ctz32(idxmap);
- TLBIRange range;
- int bits;
-
- range = tlbi_aa64_get_range(env, one_idx, value);
- bits = tlbbits_for_regime(env, one_idx, range.base);
-
- if (synced) {
- tlb_flush_range_by_mmuidx_all_cpus_synced(env_cpu(env),
- range.base,
- range.length,
- idxmap,
- bits);
- } else {
- tlb_flush_range_by_mmuidx(env_cpu(env), range.base,
- range.length, idxmap, bits);
- }
-}
-
-static void tlbi_aa64_rvae1_write(CPUARMState *env,
- const ARMCPRegInfo *ri,
- uint64_t value)
-{
- /*
- * Invalidate by VA range, EL1&0.
- * Currently handles all of RVAE1, RVAAE1, RVAALE1 and RVALE1,
- * since we don't support flush-for-specific-ASID-only or
- * flush-last-level-only.
- */
-
- do_rvae_write(env, value, vae1_tlbmask(env),
- tlb_force_broadcast(env));
-}
-
-static void tlbi_aa64_rvae1is_write(CPUARMState *env,
- const ARMCPRegInfo *ri,
- uint64_t value)
-{
- /*
- * Invalidate by VA range, Inner/Outer Shareable EL1&0.
- * Currently handles all of RVAE1IS, RVAE1OS, RVAAE1IS, RVAAE1OS,
- * RVAALE1IS, RVAALE1OS, RVALE1IS and RVALE1OS, since we don't support
- * flush-for-specific-ASID-only, flush-last-level-only or inner/outer
- * shareable specific flushes.
- */
-
- do_rvae_write(env, value, vae1_tlbmask(env), true);
-}
-
-static void tlbi_aa64_rvae2_write(CPUARMState *env,
- const ARMCPRegInfo *ri,
- uint64_t value)
-{
- /*
- * Invalidate by VA range, EL2.
- * Currently handles all of RVAE2 and RVALE2,
- * since we don't support flush-for-specific-ASID-only or
- * flush-last-level-only.
- */
-
- do_rvae_write(env, value, vae2_tlbmask(env),
- tlb_force_broadcast(env));
-
-
-}
-
-static void tlbi_aa64_rvae2is_write(CPUARMState *env,
- const ARMCPRegInfo *ri,
- uint64_t value)
-{
- /*
- * Invalidate by VA range, Inner/Outer Shareable, EL2.
- * Currently handles all of RVAE2IS, RVAE2OS, RVALE2IS and RVALE2OS,
- * since we don't support flush-for-specific-ASID-only,
- * flush-last-level-only or inner/outer shareable specific flushes.
- */
-
- do_rvae_write(env, value, vae2_tlbmask(env), true);
-
-}
-
-static void tlbi_aa64_rvae3_write(CPUARMState *env,
- const ARMCPRegInfo *ri,
- uint64_t value)
-{
- /*
- * Invalidate by VA range, EL3.
- * Currently handles all of RVAE3 and RVALE3,
- * since we don't support flush-for-specific-ASID-only or
- * flush-last-level-only.
- */
-
- do_rvae_write(env, value, ARMMMUIdxBit_E3, tlb_force_broadcast(env));
-}
-
-static void tlbi_aa64_rvae3is_write(CPUARMState *env,
- const ARMCPRegInfo *ri,
- uint64_t value)
-{
- /*
- * Invalidate by VA range, EL3, Inner/Outer Shareable.
- * Currently handles all of RVAE3IS, RVAE3OS, RVALE3IS and RVALE3OS,
- * since we don't support flush-for-specific-ASID-only,
- * flush-last-level-only or inner/outer specific flushes.
- */
-
- do_rvae_write(env, value, ARMMMUIdxBit_E3, true);
-}
-
-static void tlbi_aa64_ripas2e1_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- do_rvae_write(env, value, ipas2e1_tlbmask(env, value),
- tlb_force_broadcast(env));
-}
-
-static void tlbi_aa64_ripas2e1is_write(CPUARMState *env,
- const ARMCPRegInfo *ri,
- uint64_t value)
-{
- do_rvae_write(env, value, ipas2e1_tlbmask(env, value), true);
-}
-#endif
-
static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
@@ -5685,99 +4930,6 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 2,
.fgt = FGT_DCCISW,
.access = PL1_W, .accessfn = access_tsw, .type = ARM_CP_NOP },
- /* TLBI operations */
- { .name = "TLBI_VMALLE1IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0,
- .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIVMALLE1IS,
- .writefn = tlbi_aa64_vmalle1is_write },
- { .name = "TLBI_VAE1IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 1,
- .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIVAE1IS,
- .writefn = tlbi_aa64_vae1is_write },
- { .name = "TLBI_ASIDE1IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 2,
- .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIASIDE1IS,
- .writefn = tlbi_aa64_vmalle1is_write },
- { .name = "TLBI_VAAE1IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 3,
- .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIVAAE1IS,
- .writefn = tlbi_aa64_vae1is_write },
- { .name = "TLBI_VALE1IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 5,
- .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIVALE1IS,
- .writefn = tlbi_aa64_vae1is_write },
- { .name = "TLBI_VAALE1IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 7,
- .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIVAALE1IS,
- .writefn = tlbi_aa64_vae1is_write },
- { .name = "TLBI_VMALLE1", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 0,
- .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIVMALLE1,
- .writefn = tlbi_aa64_vmalle1_write },
- { .name = "TLBI_VAE1", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 1,
- .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIVAE1,
- .writefn = tlbi_aa64_vae1_write },
- { .name = "TLBI_ASIDE1", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 2,
- .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIASIDE1,
- .writefn = tlbi_aa64_vmalle1_write },
- { .name = "TLBI_VAAE1", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 3,
- .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIVAAE1,
- .writefn = tlbi_aa64_vae1_write },
- { .name = "TLBI_VALE1", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 5,
- .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIVALE1,
- .writefn = tlbi_aa64_vae1_write },
- { .name = "TLBI_VAALE1", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 7,
- .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIVAALE1,
- .writefn = tlbi_aa64_vae1_write },
- { .name = "TLBI_IPAS2E1IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 1,
- .access = PL2_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_ipas2e1is_write },
- { .name = "TLBI_IPAS2LE1IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 5,
- .access = PL2_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_ipas2e1is_write },
- { .name = "TLBI_ALLE1IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 4,
- .access = PL2_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_alle1is_write },
- { .name = "TLBI_VMALLS12E1IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 6,
- .access = PL2_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_alle1is_write },
- { .name = "TLBI_IPAS2E1", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 1,
- .access = PL2_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_ipas2e1_write },
- { .name = "TLBI_IPAS2LE1", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 5,
- .access = PL2_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_ipas2e1_write },
- { .name = "TLBI_ALLE1", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 4,
- .access = PL2_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_alle1_write },
- { .name = "TLBI_VMALLS12E1", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 6,
- .access = PL2_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_alle1is_write },
#ifndef CONFIG_USER_ONLY
/* 64 bit address translation operations */
{ .name = "AT_S1E1R", .state = ARM_CP_STATE_AA64,
@@ -5833,42 +4985,6 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
.fieldoffset = offsetof(CPUARMState, cp15.par_el[1]),
.writefn = par_write },
#endif
- /* TLB invalidate last level of translation table walk */
- { .name = "TLBIMVALIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 5,
- .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
- .writefn = tlbimva_is_write },
- { .name = "TLBIMVAALIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 7,
- .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
- .writefn = tlbimvaa_is_write },
- { .name = "TLBIMVAL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 5,
- .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
- .writefn = tlbimva_write },
- { .name = "TLBIMVAAL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 7,
- .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
- .writefn = tlbimvaa_write },
- { .name = "TLBIMVALH", .cp = 15, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 5,
- .type = ARM_CP_NO_RAW, .access = PL2_W,
- .writefn = tlbimva_hyp_write },
- { .name = "TLBIMVALHIS",
- .cp = 15, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 5,
- .type = ARM_CP_NO_RAW, .access = PL2_W,
- .writefn = tlbimva_hyp_is_write },
- { .name = "TLBIIPAS2",
- .cp = 15, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 1,
- .type = ARM_CP_NO_RAW, .access = PL2_W,
- .writefn = tlbiipas2_hyp_write },
- { .name = "TLBIIPAS2IS",
- .cp = 15, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 1,
- .type = ARM_CP_NO_RAW, .access = PL2_W,
- .writefn = tlbiipas2is_hyp_write },
- { .name = "TLBIIPAS2L",
- .cp = 15, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 5,
- .type = ARM_CP_NO_RAW, .access = PL2_W,
- .writefn = tlbiipas2_hyp_write },
- { .name = "TLBIIPAS2LIS",
- .cp = 15, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 5,
- .type = ARM_CP_NO_RAW, .access = PL2_W,
- .writefn = tlbiipas2is_hyp_write },
/* 32 bit cache operations */
{ .name = "ICIALLUIS", .cp = 15, .opc1 = 0, .crn = 7, .crm = 1, .opc2 = 0,
.type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_ticab },
@@ -6455,50 +5571,6 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
{ .name = "HTTBR", .cp = 15, .opc1 = 4, .crm = 2,
.access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_ALIAS,
.fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[2]) },
- { .name = "TLBIALLNSNH",
- .cp = 15, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 4,
- .type = ARM_CP_NO_RAW, .access = PL2_W,
- .writefn = tlbiall_nsnh_write },
- { .name = "TLBIALLNSNHIS",
- .cp = 15, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 4,
- .type = ARM_CP_NO_RAW, .access = PL2_W,
- .writefn = tlbiall_nsnh_is_write },
- { .name = "TLBIALLH", .cp = 15, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 0,
- .type = ARM_CP_NO_RAW, .access = PL2_W,
- .writefn = tlbiall_hyp_write },
- { .name = "TLBIALLHIS", .cp = 15, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 0,
- .type = ARM_CP_NO_RAW, .access = PL2_W,
- .writefn = tlbiall_hyp_is_write },
- { .name = "TLBIMVAH", .cp = 15, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 1,
- .type = ARM_CP_NO_RAW, .access = PL2_W,
- .writefn = tlbimva_hyp_write },
- { .name = "TLBIMVAHIS", .cp = 15, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 1,
- .type = ARM_CP_NO_RAW, .access = PL2_W,
- .writefn = tlbimva_hyp_is_write },
- { .name = "TLBI_ALLE2", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 0,
- .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
- .writefn = tlbi_aa64_alle2_write },
- { .name = "TLBI_VAE2", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 1,
- .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
- .writefn = tlbi_aa64_vae2_write },
- { .name = "TLBI_VALE2", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 5,
- .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
- .writefn = tlbi_aa64_vae2_write },
- { .name = "TLBI_ALLE2IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 0,
- .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
- .writefn = tlbi_aa64_alle2is_write },
- { .name = "TLBI_VAE2IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 1,
- .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
- .writefn = tlbi_aa64_vae2is_write },
- { .name = "TLBI_VALE2IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 5,
- .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
- .writefn = tlbi_aa64_vae2is_write },
#ifndef CONFIG_USER_ONLY
/*
* Unlike the other EL2-related AT operations, these must
@@ -6711,30 +5783,6 @@ static const ARMCPRegInfo el3_cp_reginfo[] = {
.opc0 = 3, .opc1 = 6, .crn = 5, .crm = 1, .opc2 = 1,
.access = PL3_RW, .type = ARM_CP_CONST,
.resetvalue = 0 },
- { .name = "TLBI_ALLE3IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 3, .opc2 = 0,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_alle3is_write },
- { .name = "TLBI_VAE3IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 3, .opc2 = 1,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_vae3is_write },
- { .name = "TLBI_VALE3IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 3, .opc2 = 5,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_vae3is_write },
- { .name = "TLBI_ALLE3", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 7, .opc2 = 0,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_alle3_write },
- { .name = "TLBI_VAE3", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 7, .opc2 = 1,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_vae3_write },
- { .name = "TLBI_VALE3", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 7, .opc2 = 5,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_vae3_write },
};
#ifndef CONFIG_USER_ONLY
@@ -7477,14 +6525,6 @@ static const ARMCPRegInfo sme_reginfo[] = {
.type = ARM_CP_CONST, .resetvalue = 0 },
};
-static void tlbi_aa64_paall_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
-
- tlb_flush(cs);
-}
-
static void gpccr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
@@ -7502,14 +6542,6 @@ static void gpccr_reset(CPUARMState *env, const ARMCPRegInfo *ri)
env_archcpu(env)->reset_l0gptsz);
}
-static void tlbi_aa64_paallos_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
-
- tlb_flush_all_cpus_synced(cs);
-}
-
static const ARMCPRegInfo rme_reginfo[] = {
{ .name = "GPCCR_EL3", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 6, .crn = 2, .crm = 1, .opc2 = 6,
@@ -7521,28 +6553,6 @@ static const ARMCPRegInfo rme_reginfo[] = {
{ .name = "MFAR_EL3", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 6, .crn = 6, .crm = 0, .opc2 = 5,
.access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.mfar_el3) },
- { .name = "TLBI_PAALL", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 7, .opc2 = 4,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_paall_write },
- { .name = "TLBI_PAALLOS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 1, .opc2 = 4,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_paallos_write },
- /*
- * QEMU does not have a way to invalidate by physical address, thus
- * invalidating a range of physical addresses is accomplished by
- * flushing all tlb entries in the outer shareable domain,
- * just like PAALLOS.
- */
- { .name = "TLBI_RPALOS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 4, .opc2 = 7,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_paallos_write },
- { .name = "TLBI_RPAOS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 4, .opc2 = 3,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_paallos_write },
{ .name = "DC_CIPAPA", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 6, .crn = 7, .crm = 14, .opc2 = 1,
.access = PL3_W, .type = ARM_CP_NOP },
@@ -7848,210 +6858,6 @@ static const ARMCPRegInfo pauth_reginfo[] = {
.fieldoffset = offsetof(CPUARMState, keys.apib.hi) },
};
-static const ARMCPRegInfo tlbirange_reginfo[] = {
- { .name = "TLBI_RVAE1IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 1,
- .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIRVAE1IS,
- .writefn = tlbi_aa64_rvae1is_write },
- { .name = "TLBI_RVAAE1IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 3,
- .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIRVAAE1IS,
- .writefn = tlbi_aa64_rvae1is_write },
- { .name = "TLBI_RVALE1IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 5,
- .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIRVALE1IS,
- .writefn = tlbi_aa64_rvae1is_write },
- { .name = "TLBI_RVAALE1IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 7,
- .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIRVAALE1IS,
- .writefn = tlbi_aa64_rvae1is_write },
- { .name = "TLBI_RVAE1OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 1,
- .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIRVAE1OS,
- .writefn = tlbi_aa64_rvae1is_write },
- { .name = "TLBI_RVAAE1OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 3,
- .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIRVAAE1OS,
- .writefn = tlbi_aa64_rvae1is_write },
- { .name = "TLBI_RVALE1OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 5,
- .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIRVALE1OS,
- .writefn = tlbi_aa64_rvae1is_write },
- { .name = "TLBI_RVAALE1OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 7,
- .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIRVAALE1OS,
- .writefn = tlbi_aa64_rvae1is_write },
- { .name = "TLBI_RVAE1", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 1,
- .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIRVAE1,
- .writefn = tlbi_aa64_rvae1_write },
- { .name = "TLBI_RVAAE1", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 3,
- .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIRVAAE1,
- .writefn = tlbi_aa64_rvae1_write },
- { .name = "TLBI_RVALE1", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 5,
- .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIRVALE1,
- .writefn = tlbi_aa64_rvae1_write },
- { .name = "TLBI_RVAALE1", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 7,
- .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIRVAALE1,
- .writefn = tlbi_aa64_rvae1_write },
- { .name = "TLBI_RIPAS2E1IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 2,
- .access = PL2_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_ripas2e1is_write },
- { .name = "TLBI_RIPAS2LE1IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 6,
- .access = PL2_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_ripas2e1is_write },
- { .name = "TLBI_RVAE2IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 2, .opc2 = 1,
- .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
- .writefn = tlbi_aa64_rvae2is_write },
- { .name = "TLBI_RVALE2IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 2, .opc2 = 5,
- .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
- .writefn = tlbi_aa64_rvae2is_write },
- { .name = "TLBI_RIPAS2E1", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 2,
- .access = PL2_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_ripas2e1_write },
- { .name = "TLBI_RIPAS2LE1", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 6,
- .access = PL2_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_ripas2e1_write },
- { .name = "TLBI_RVAE2OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 5, .opc2 = 1,
- .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
- .writefn = tlbi_aa64_rvae2is_write },
- { .name = "TLBI_RVALE2OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 5, .opc2 = 5,
- .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
- .writefn = tlbi_aa64_rvae2is_write },
- { .name = "TLBI_RVAE2", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 6, .opc2 = 1,
- .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
- .writefn = tlbi_aa64_rvae2_write },
- { .name = "TLBI_RVALE2", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 6, .opc2 = 5,
- .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
- .writefn = tlbi_aa64_rvae2_write },
- { .name = "TLBI_RVAE3IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 2, .opc2 = 1,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_rvae3is_write },
- { .name = "TLBI_RVALE3IS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 2, .opc2 = 5,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_rvae3is_write },
- { .name = "TLBI_RVAE3OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 5, .opc2 = 1,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_rvae3is_write },
- { .name = "TLBI_RVALE3OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 5, .opc2 = 5,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_rvae3is_write },
- { .name = "TLBI_RVAE3", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 6, .opc2 = 1,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_rvae3_write },
- { .name = "TLBI_RVALE3", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 6, .opc2 = 5,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_rvae3_write },
-};
-
-static const ARMCPRegInfo tlbios_reginfo[] = {
- { .name = "TLBI_VMALLE1OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 0,
- .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIVMALLE1OS,
- .writefn = tlbi_aa64_vmalle1is_write },
- { .name = "TLBI_VAE1OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 1,
- .fgt = FGT_TLBIVAE1OS,
- .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_vae1is_write },
- { .name = "TLBI_ASIDE1OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 2,
- .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIASIDE1OS,
- .writefn = tlbi_aa64_vmalle1is_write },
- { .name = "TLBI_VAAE1OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 3,
- .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIVAAE1OS,
- .writefn = tlbi_aa64_vae1is_write },
- { .name = "TLBI_VALE1OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 5,
- .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIVALE1OS,
- .writefn = tlbi_aa64_vae1is_write },
- { .name = "TLBI_VAALE1OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 7,
- .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
- .fgt = FGT_TLBIVAALE1OS,
- .writefn = tlbi_aa64_vae1is_write },
- { .name = "TLBI_ALLE2OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 0,
- .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
- .writefn = tlbi_aa64_alle2is_write },
- { .name = "TLBI_VAE2OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 1,
- .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
- .writefn = tlbi_aa64_vae2is_write },
- { .name = "TLBI_ALLE1OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 4,
- .access = PL2_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_alle1is_write },
- { .name = "TLBI_VALE2OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 5,
- .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
- .writefn = tlbi_aa64_vae2is_write },
- { .name = "TLBI_VMALLS12E1OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 6,
- .access = PL2_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_alle1is_write },
- { .name = "TLBI_IPAS2E1OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 0,
- .access = PL2_W, .type = ARM_CP_NOP },
- { .name = "TLBI_RIPAS2E1OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 3,
- .access = PL2_W, .type = ARM_CP_NOP },
- { .name = "TLBI_IPAS2LE1OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 4,
- .access = PL2_W, .type = ARM_CP_NOP },
- { .name = "TLBI_RIPAS2LE1OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 7,
- .access = PL2_W, .type = ARM_CP_NOP },
- { .name = "TLBI_ALLE3OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 1, .opc2 = 0,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_alle3is_write },
- { .name = "TLBI_VAE3OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 1, .opc2 = 1,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_vae3is_write },
- { .name = "TLBI_VALE3OS", .state = ARM_CP_STATE_AA64,
- .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 1, .opc2 = 5,
- .access = PL3_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_vae3is_write },
-};
-
static uint64_t rndr_readfn(CPUARMState *env, const ARMCPRegInfo *ri)
{
Error *err = NULL;
@@ -8734,6 +7540,8 @@ void register_cp_regs_for_features(ARMCPU *cpu)
define_arm_cp_regs(cpu, not_v8_cp_reginfo);
}
+ define_tlb_insn_regs(cpu);
+
if (arm_feature(env, ARM_FEATURE_V6)) {
/* The ID registers all have impdef reset values */
ARMCPRegInfo v6_idregs[] = {
@@ -8839,10 +7647,6 @@ void register_cp_regs_for_features(ARMCPU *cpu)
if (arm_feature(env, ARM_FEATURE_V6K)) {
define_arm_cp_regs(cpu, v6k_cp_reginfo);
}
- if (arm_feature(env, ARM_FEATURE_V7MP) &&
- !arm_feature(env, ARM_FEATURE_PMSA)) {
- define_arm_cp_regs(cpu, v7mp_cp_reginfo);
- }
if (arm_feature(env, ARM_FEATURE_V7VE)) {
define_arm_cp_regs(cpu, pmovsset_cp_reginfo);
}
@@ -9927,12 +8731,6 @@ void register_cp_regs_for_features(ARMCPU *cpu)
if (cpu_isar_feature(aa64_rndr, cpu)) {
define_arm_cp_regs(cpu, rndr_reginfo);
}
- if (cpu_isar_feature(aa64_tlbirange, cpu)) {
- define_arm_cp_regs(cpu, tlbirange_reginfo);
- }
- if (cpu_isar_feature(aa64_tlbios, cpu)) {
- define_arm_cp_regs(cpu, tlbios_reginfo);
- }
/* Data Cache clean instructions up to PoP */
if (cpu_isar_feature(aa64_dcpop, cpu)) {
define_one_arm_cp_reg(cpu, dcpop_reg);
diff --git a/target/arm/helper.h b/target/arm/helper.h
index 58919b6..9919b13 100644
--- a/target/arm/helper.h
+++ b/target/arm/helper.h
@@ -133,9 +133,9 @@ DEF_HELPER_3(vfp_maxnumd, f64, f64, f64, ptr)
DEF_HELPER_3(vfp_minnumh, f16, f16, f16, ptr)
DEF_HELPER_3(vfp_minnums, f32, f32, f32, ptr)
DEF_HELPER_3(vfp_minnumd, f64, f64, f64, ptr)
-DEF_HELPER_2(vfp_sqrth, f16, f16, env)
-DEF_HELPER_2(vfp_sqrts, f32, f32, env)
-DEF_HELPER_2(vfp_sqrtd, f64, f64, env)
+DEF_HELPER_2(vfp_sqrth, f16, f16, ptr)
+DEF_HELPER_2(vfp_sqrts, f32, f32, ptr)
+DEF_HELPER_2(vfp_sqrtd, f64, f64, ptr)
DEF_HELPER_3(vfp_cmph, void, f16, f16, env)
DEF_HELPER_3(vfp_cmps, void, f32, f32, env)
DEF_HELPER_3(vfp_cmpd, void, f64, f64, env)
@@ -178,8 +178,10 @@ DEF_HELPER_3(vfp_touhs_round_to_zero, i32, f32, i32, ptr)
DEF_HELPER_3(vfp_touls_round_to_zero, i32, f32, i32, ptr)
DEF_HELPER_3(vfp_toshd_round_to_zero, i64, f64, i32, ptr)
DEF_HELPER_3(vfp_tosld_round_to_zero, i64, f64, i32, ptr)
+DEF_HELPER_3(vfp_tosqd_round_to_zero, i64, f64, i32, ptr)
DEF_HELPER_3(vfp_touhd_round_to_zero, i64, f64, i32, ptr)
DEF_HELPER_3(vfp_tould_round_to_zero, i64, f64, i32, ptr)
+DEF_HELPER_3(vfp_touqd_round_to_zero, i64, f64, i32, ptr)
DEF_HELPER_3(vfp_touhh, i32, f16, i32, ptr)
DEF_HELPER_3(vfp_toshh, i32, f16, i32, ptr)
DEF_HELPER_3(vfp_toulh, i32, f16, i32, ptr)
@@ -363,8 +365,8 @@ DEF_HELPER_1(neon_clz_u16, i32, i32)
DEF_HELPER_1(neon_cls_s8, i32, i32)
DEF_HELPER_1(neon_cls_s16, i32, i32)
DEF_HELPER_1(neon_cls_s32, i32, i32)
-DEF_HELPER_1(neon_cnt_u8, i32, i32)
-DEF_HELPER_FLAGS_1(neon_rbit_u8, TCG_CALL_NO_RWG_SE, i32, i32)
+DEF_HELPER_FLAGS_3(gvec_cnt_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
+DEF_HELPER_FLAGS_3(gvec_rbit_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
DEF_HELPER_3(neon_qdmulh_s16, i32, env, i32, i32)
DEF_HELPER_3(neon_qrdmulh_s16, i32, env, i32, i32)
@@ -395,12 +397,8 @@ DEF_HELPER_1(neon_widen_s8, i64, i32)
DEF_HELPER_1(neon_widen_u16, i64, i32)
DEF_HELPER_1(neon_widen_s16, i64, i32)
-DEF_HELPER_2(neon_addl_u16, i64, i64, i64)
-DEF_HELPER_2(neon_addl_u32, i64, i64, i64)
-DEF_HELPER_2(neon_paddl_u16, i64, i64, i64)
-DEF_HELPER_2(neon_paddl_u32, i64, i64, i64)
-DEF_HELPER_2(neon_subl_u16, i64, i64, i64)
-DEF_HELPER_2(neon_subl_u32, i64, i64, i64)
+DEF_HELPER_FLAGS_1(neon_addlp_s8, TCG_CALL_NO_RWG_SE, i64, i64)
+DEF_HELPER_FLAGS_1(neon_addlp_s16, TCG_CALL_NO_RWG_SE, i64, i64)
DEF_HELPER_3(neon_addl_saturate_s32, i64, env, i64, i64)
DEF_HELPER_3(neon_addl_saturate_s64, i64, env, i64, i64)
DEF_HELPER_2(neon_abdl_u16, i64, i32, i32)
@@ -654,14 +652,21 @@ DEF_HELPER_FLAGS_4(gvec_touizs, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_vcvt_sf, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_vcvt_uf, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
-DEF_HELPER_FLAGS_4(gvec_vcvt_fs, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
-DEF_HELPER_FLAGS_4(gvec_vcvt_fu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_vcvt_rz_fs, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_vcvt_rz_fu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_vcvt_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_vcvt_uh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
-DEF_HELPER_FLAGS_4(gvec_vcvt_hs, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
-DEF_HELPER_FLAGS_4(gvec_vcvt_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_vcvt_rz_hs, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_vcvt_rz_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_vcvt_sd, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_vcvt_ud, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_vcvt_rz_ds, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_vcvt_rz_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+
+DEF_HELPER_FLAGS_4(gvec_vcvt_rm_sd, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_vcvt_rm_ud, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_vcvt_rm_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_vcvt_rm_us, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_vcvt_rm_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
@@ -683,18 +688,23 @@ DEF_HELPER_FLAGS_4(gvec_frsqrte_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_fcgt0_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_fcgt0_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_fcgt0_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_fcge0_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_fcge0_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_fcge0_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_fceq0_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_fceq0_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_fceq0_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_fcle0_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_fcle0_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_fcle0_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_fclt0_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_fclt0_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_fclt0_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_5(gvec_fadd_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_5(gvec_fadd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32)
@@ -1111,6 +1121,9 @@ DEF_HELPER_FLAGS_4(gvec_uminp_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_uminp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_uminp_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_3(gvec_urecpe_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
+DEF_HELPER_FLAGS_3(gvec_ursqrte_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
+
#ifdef TARGET_AARCH64
#include "tcg/helper-a64.h"
#include "tcg/helper-sve.h"
diff --git a/target/arm/internals.h b/target/arm/internals.h
index e37f459..c3a5b13 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1727,6 +1727,9 @@ static inline uint64_t pauth_ptr_mask(ARMVAParameters param)
/* Add the cpreg definitions for debug related system registers */
void define_debug_regs(ARMCPU *cpu);
+/* Add the cpreg definitions for TLBI instructions */
+void define_tlb_insn_regs(ARMCPU *cpu);
+
/* Effective value of MDCR_EL2 */
static inline uint64_t arm_mdcr_el2_eff(CPUARMState *env)
{
@@ -1817,4 +1820,10 @@ uint64_t gt_get_countervalue(CPUARMState *env);
* and CNTVCT_EL0 (this will be either 0 or the value of CNTVOFF_EL2).
*/
uint64_t gt_virt_cnt_offset(CPUARMState *env);
+
+/*
+ * Return mask of ARMMMUIdxBit values corresponding to an "invalidate
+ * all EL1" scope; this covers stage 1 and stage 2.
+ */
+int alle1_tlbmask(CPUARMState *env);
#endif
diff --git a/target/arm/tcg-stubs.c b/target/arm/tcg-stubs.c
index 152b172..f3f45d5 100644
--- a/target/arm/tcg-stubs.c
+++ b/target/arm/tcg-stubs.c
@@ -25,3 +25,8 @@ void raise_exception_ra(CPUARMState *env, uint32_t excp, uint32_t syndrome,
void assert_hflags_rebuild_correctly(CPUARMState *env)
{
}
+
+/* TLBI insns are only used by TCG, so we don't need to do anything for KVM */
+void define_tlb_insn_regs(ARMCPU *cpu)
+{
+}
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
index 331a8e1..7aa10f5 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -21,13 +21,18 @@
%rd 0:5
%esz_sd 22:1 !function=plus_2
+%esz_hs 22:1 !function=plus_1
%esz_hsd 22:2 !function=xor_2
%hl 11:1 21:1
%hlm 11:1 20:2
&r rn
+&rrr rd rn rm
&ri rd imm
+&rr rd rn
+&rr_sf rd rn sf
&rri_sf rd rn imm sf
+&rrr_sf rd rn rm sf
&i imm
&rr_e rd rn esz
&rri_e rd rn imm esz
@@ -41,10 +46,15 @@
&qrrrr_e q rd rn rm ra esz
@rr_h ........ ... ..... ...... rn:5 rd:5 &rr_e esz=1
+@rr_s ........ ... ..... ...... rn:5 rd:5 &rr_e esz=2
@rr_d ........ ... ..... ...... rn:5 rd:5 &rr_e esz=3
+@rr_e ........ esz:2 . ..... ...... rn:5 rd:5 &rr_e
@rr_sd ........ ... ..... ...... rn:5 rd:5 &rr_e esz=%esz_sd
+@rr_hsd ........ ... ..... ...... rn:5 rd:5 &rr_e esz=%esz_hsd
+@rrr_b ........ ... rm:5 ...... rn:5 rd:5 &rrr_e esz=0
@rrr_h ........ ... rm:5 ...... rn:5 rd:5 &rrr_e esz=1
+@rrr_s ........ ... rm:5 ...... rn:5 rd:5 &rrr_e esz=2
@rrr_d ........ ... rm:5 ...... rn:5 rd:5 &rrr_e esz=3
@rrr_sd ........ ... rm:5 ...... rn:5 rd:5 &rrr_e esz=%esz_sd
@rrr_hsd ........ ... rm:5 ...... rn:5 rd:5 &rrr_e esz=%esz_hsd
@@ -62,7 +72,12 @@
@rrr_q1e3 ........ ... rm:5 ...... rn:5 rd:5 &qrrr_e q=1 esz=3
@rrrr_q1e3 ........ ... rm:5 . ra:5 rn:5 rd:5 &qrrrr_e q=1 esz=3
+@qrr_b . q:1 ...... .. ...... ...... rn:5 rd:5 &qrr_e esz=0
@qrr_h . q:1 ...... .. ...... ...... rn:5 rd:5 &qrr_e esz=1
+@qrr_s . q:1 ...... .. ...... ...... rn:5 rd:5 &qrr_e esz=2
+@qrr_bh . q:1 ...... . esz:1 ...... ...... rn:5 rd:5 &qrr_e
+@qrr_hs . q:1 ...... .. ...... ...... rn:5 rd:5 &qrr_e esz=%esz_hs
+@qrr_sd . q:1 ...... .. ...... ...... rn:5 rd:5 &qrr_e esz=%esz_sd
@qrr_e . q:1 ...... esz:2 ...... ...... rn:5 rd:5 &qrr_e
@qrrr_b . q:1 ...... ... rm:5 ...... rn:5 rd:5 &qrrr_e esz=0
@@ -161,7 +176,7 @@ UBFM . 10 100110 . ...... ...... ..... ..... @bitfield_32
EXTR 1 00 100111 1 0 rm:5 imm:6 rn:5 rd:5 &extract sf=1
EXTR 0 00 100111 0 0 rm:5 0 imm:5 rn:5 rd:5 &extract sf=0
-# Branches
+### Branches
%imm26 0:s26 !function=times_4
@branch . ..... .......................... &i imm=%imm26
@@ -291,7 +306,7 @@ HLT 1101 0100 010 ................ 000 00 @i16
# DCPS2 1101 0100 101 ................ 000 10 @i16
# DCPS3 1101 0100 101 ................ 000 11 @i16
-# Loads and stores
+### Loads and stores
&stxr rn rt rt2 rs sz lasr
&stlr rn rt sz lasr
@@ -649,6 +664,138 @@ CPYP 00 011 1 01000 ..... .... 01 ..... ..... @cpy
CPYM 00 011 1 01010 ..... .... 01 ..... ..... @cpy
CPYE 00 011 1 01100 ..... .... 01 ..... ..... @cpy
+### Data Processing (register)
+
+# Data Processing (2-source)
+
+@rrr . .......... rm:5 ...... rn:5 rd:5 &rrr
+@rrr_sf sf:1 .......... rm:5 ...... rn:5 rd:5 &rrr_sf
+
+UDIV . 00 11010110 ..... 00001 0 ..... ..... @rrr_sf
+SDIV . 00 11010110 ..... 00001 1 ..... ..... @rrr_sf
+LSLV . 00 11010110 ..... 00100 0 ..... ..... @rrr_sf
+LSRV . 00 11010110 ..... 00100 1 ..... ..... @rrr_sf
+ASRV . 00 11010110 ..... 00101 0 ..... ..... @rrr_sf
+RORV . 00 11010110 ..... 00101 1 ..... ..... @rrr_sf
+
+CRC32 0 00 11010110 ..... 0100 00 ..... ..... @rrr_b
+CRC32 0 00 11010110 ..... 0100 01 ..... ..... @rrr_h
+CRC32 0 00 11010110 ..... 0100 10 ..... ..... @rrr_s
+CRC32 1 00 11010110 ..... 0100 11 ..... ..... @rrr_d
+
+CRC32C 0 00 11010110 ..... 0101 00 ..... ..... @rrr_b
+CRC32C 0 00 11010110 ..... 0101 01 ..... ..... @rrr_h
+CRC32C 0 00 11010110 ..... 0101 10 ..... ..... @rrr_s
+CRC32C 1 00 11010110 ..... 0101 11 ..... ..... @rrr_d
+
+SUBP 1 00 11010110 ..... 000000 ..... ..... @rrr
+SUBPS 1 01 11010110 ..... 000000 ..... ..... @rrr
+IRG 1 00 11010110 ..... 000100 ..... ..... @rrr
+GMI 1 00 11010110 ..... 000101 ..... ..... @rrr
+
+PACGA 1 00 11010110 ..... 001100 ..... ..... @rrr
+
+# Data Processing (1-source)
+
+@rr . .......... ..... ...... rn:5 rd:5 &rr
+@rr_sf sf:1 .......... ..... ...... rn:5 rd:5 &rr_sf
+
+RBIT . 10 11010110 00000 000000 ..... ..... @rr_sf
+REV16 . 10 11010110 00000 000001 ..... ..... @rr_sf
+REV32 . 10 11010110 00000 000010 ..... ..... @rr_sf
+REV64 1 10 11010110 00000 000011 ..... ..... @rr
+
+CLZ . 10 11010110 00000 000100 ..... ..... @rr_sf
+CLS . 10 11010110 00000 000101 ..... ..... @rr_sf
+
+&pacaut rd rn z
+@pacaut . .. ........ ..... .. z:1 ... rn:5 rd:5 &pacaut
+
+PACIA 1 10 11010110 00001 00.000 ..... ..... @pacaut
+PACIB 1 10 11010110 00001 00.001 ..... ..... @pacaut
+PACDA 1 10 11010110 00001 00.010 ..... ..... @pacaut
+PACDB 1 10 11010110 00001 00.011 ..... ..... @pacaut
+
+AUTIA 1 10 11010110 00001 00.100 ..... ..... @pacaut
+AUTIB 1 10 11010110 00001 00.101 ..... ..... @pacaut
+AUTDA 1 10 11010110 00001 00.110 ..... ..... @pacaut
+AUTDB 1 10 11010110 00001 00.111 ..... ..... @pacaut
+
+XPACI 1 10 11010110 00001 010000 11111 rd:5
+XPACD 1 10 11010110 00001 010001 11111 rd:5
+
+# Logical (shifted reg)
+
+&logic_shift rd rn rm sf sa st n
+@logic_shift sf:1 .. ..... st:2 n:1 rm:5 sa:6 rn:5 rd:5 &logic_shift
+
+AND_r . 00 01010 .. . ..... ...... ..... ..... @logic_shift
+ORR_r . 01 01010 .. . ..... ...... ..... ..... @logic_shift
+EOR_r . 10 01010 .. . ..... ...... ..... ..... @logic_shift
+ANDS_r . 11 01010 .. . ..... ...... ..... ..... @logic_shift
+
+# Add/subtract (shifted reg)
+
+&addsub_shift rd rn rm sf sa st
+@addsub_shift sf:1 .. ..... st:2 . rm:5 sa:6 rn:5 rd:5 &addsub_shift
+
+ADD_r . 00 01011 .. 0 ..... ...... ..... ..... @addsub_shift
+SUB_r . 10 01011 .. 0 ..... ...... ..... ..... @addsub_shift
+ADDS_r . 01 01011 .. 0 ..... ...... ..... ..... @addsub_shift
+SUBS_r . 11 01011 .. 0 ..... ...... ..... ..... @addsub_shift
+
+# Add/subtract (extended reg)
+
+&addsub_ext rd rn rm sf sa st
+@addsub_ext sf:1 .. ........ rm:5 st:3 sa:3 rn:5 rd:5 &addsub_ext
+
+ADD_ext . 00 01011001 ..... ... ... ..... ..... @addsub_ext
+SUB_ext . 10 01011001 ..... ... ... ..... ..... @addsub_ext
+ADDS_ext . 01 01011001 ..... ... ... ..... ..... @addsub_ext
+SUBS_ext . 11 01011001 ..... ... ... ..... ..... @addsub_ext
+
+# Add/subtract (carry)
+
+ADC . 00 11010000 ..... 000000 ..... ..... @rrr_sf
+ADCS . 01 11010000 ..... 000000 ..... ..... @rrr_sf
+SBC . 10 11010000 ..... 000000 ..... ..... @rrr_sf
+SBCS . 11 11010000 ..... 000000 ..... ..... @rrr_sf
+
+# Rotate right into flags
+
+RMIF 1 01 11010000 imm:6 00001 rn:5 0 mask:4
+
+# Evaluate into flags
+
+SETF8 0 01 11010000 00000 000010 rn:5 01101
+SETF16 0 01 11010000 00000 010010 rn:5 01101
+
+# Conditional compare
+
+CCMP sf:1 op:1 1 11010010 y:5 cond:4 imm:1 0 rn:5 0 nzcv:4
+
+# Conditional select
+
+CSEL sf:1 else_inv:1 011010100 rm:5 cond:4 0 else_inc:1 rn:5 rd:5
+
+# Data Processing (3-source)
+
+&rrrr rd rn rm ra
+@rrrr . .. ........ rm:5 . ra:5 rn:5 rd:5 &rrrr
+
+MADD_w 0 00 11011000 ..... 0 ..... ..... ..... @rrrr
+MSUB_w 0 00 11011000 ..... 1 ..... ..... ..... @rrrr
+MADD_x 1 00 11011000 ..... 0 ..... ..... ..... @rrrr
+MSUB_x 1 00 11011000 ..... 1 ..... ..... ..... @rrrr
+
+SMADDL 1 00 11011001 ..... 0 ..... ..... ..... @rrrr
+SMSUBL 1 00 11011001 ..... 1 ..... ..... ..... @rrrr
+UMADDL 1 00 11011101 ..... 0 ..... ..... ..... @rrrr
+UMSUBL 1 00 11011101 ..... 1 ..... ..... ..... @rrrr
+
+SMULH 1 00 11011010 ..... 0 11111 ..... ..... @rrr
+UMULH 1 00 11011110 ..... 0 11111 ..... ..... @rrr
+
### Cryptographic AES
AESE 01001110 00 10100 00100 10 ..... ..... @r2r_q1e0
@@ -1183,10 +1330,103 @@ FMAXV_s 0110 1110 00 11000 01111 10 ..... ..... @rr_q1e2
FMINV_h 0.00 1110 10 11000 01111 10 ..... ..... @qrr_h
FMINV_s 0110 1110 10 11000 01111 10 ..... ..... @rr_q1e2
+# Conversion between floating-point and fixed-point (general register)
+
+&fcvt rd rn esz sf shift
+%fcvt_shift32 10:5 !function=rsub_32
+%fcvt_shift64 10:6 !function=rsub_64
+
+@fcvt32 0 ....... .. ...... 1..... rn:5 rd:5 \
+ &fcvt sf=0 esz=%esz_hsd shift=%fcvt_shift32
+@fcvt64 1 ....... .. ...... ...... rn:5 rd:5 \
+ &fcvt sf=1 esz=%esz_hsd shift=%fcvt_shift64
+
+SCVTF_g . 0011110 .. 000010 ...... ..... ..... @fcvt32
+SCVTF_g . 0011110 .. 000010 ...... ..... ..... @fcvt64
+UCVTF_g . 0011110 .. 000011 ...... ..... ..... @fcvt32
+UCVTF_g . 0011110 .. 000011 ...... ..... ..... @fcvt64
+
+FCVTZS_g . 0011110 .. 011000 ...... ..... ..... @fcvt32
+FCVTZS_g . 0011110 .. 011000 ...... ..... ..... @fcvt64
+FCVTZU_g . 0011110 .. 011001 ...... ..... ..... @fcvt32
+FCVTZU_g . 0011110 .. 011001 ...... ..... ..... @fcvt64
+
+# Conversion between floating-point and integer (general register)
+
+@icvt sf:1 ....... .. ...... ...... rn:5 rd:5 \
+ &fcvt esz=%esz_hsd shift=0
+
+SCVTF_g . 0011110 .. 100010 000000 ..... ..... @icvt
+UCVTF_g . 0011110 .. 100011 000000 ..... ..... @icvt
+
+FCVTNS_g . 0011110 .. 100000 000000 ..... ..... @icvt
+FCVTNU_g . 0011110 .. 100001 000000 ..... ..... @icvt
+FCVTPS_g . 0011110 .. 101000 000000 ..... ..... @icvt
+FCVTPU_g . 0011110 .. 101001 000000 ..... ..... @icvt
+FCVTMS_g . 0011110 .. 110000 000000 ..... ..... @icvt
+FCVTMU_g . 0011110 .. 110001 000000 ..... ..... @icvt
+FCVTZS_g . 0011110 .. 111000 000000 ..... ..... @icvt
+FCVTZU_g . 0011110 .. 111001 000000 ..... ..... @icvt
+FCVTAS_g . 0011110 .. 100100 000000 ..... ..... @icvt
+FCVTAU_g . 0011110 .. 100101 000000 ..... ..... @icvt
+
+FJCVTZS 0 0011110 01 111110 000000 ..... ..... @rr
+
+FMOV_ws 0 0011110 00 100110 000000 ..... ..... @rr
+FMOV_sw 0 0011110 00 100111 000000 ..... ..... @rr
+
+FMOV_xd 1 0011110 01 100110 000000 ..... ..... @rr
+FMOV_dx 1 0011110 01 100111 000000 ..... ..... @rr
+
+# Move to/from upper half of 128-bit
+FMOV_xu 1 0011110 10 101110 000000 ..... ..... @rr
+FMOV_ux 1 0011110 10 101111 000000 ..... ..... @rr
+
+# Half-precision allows both sf=0 and sf=1 with identical results
+FMOV_xh - 0011110 11 100110 000000 ..... ..... @rr
+FMOV_hx - 0011110 11 100111 000000 ..... ..... @rr
+
+# Floating-point data processing (1 source)
+
+FMOV_s 00011110 .. 1 000000 10000 ..... ..... @rr_hsd
+FABS_s 00011110 .. 1 000001 10000 ..... ..... @rr_hsd
+FNEG_s 00011110 .. 1 000010 10000 ..... ..... @rr_hsd
+FSQRT_s 00011110 .. 1 000011 10000 ..... ..... @rr_hsd
+
+FRINTN_s 00011110 .. 1 001000 10000 ..... ..... @rr_hsd
+FRINTP_s 00011110 .. 1 001001 10000 ..... ..... @rr_hsd
+FRINTM_s 00011110 .. 1 001010 10000 ..... ..... @rr_hsd
+FRINTZ_s 00011110 .. 1 001011 10000 ..... ..... @rr_hsd
+FRINTA_s 00011110 .. 1 001100 10000 ..... ..... @rr_hsd
+FRINTX_s 00011110 .. 1 001110 10000 ..... ..... @rr_hsd
+FRINTI_s 00011110 .. 1 001111 10000 ..... ..... @rr_hsd
+
+BFCVT_s 00011110 01 1 000110 10000 ..... ..... @rr_s
+
+FRINT32Z_s 00011110 0. 1 010000 10000 ..... ..... @rr_sd
+FRINT32X_s 00011110 0. 1 010001 10000 ..... ..... @rr_sd
+FRINT64Z_s 00011110 0. 1 010010 10000 ..... ..... @rr_sd
+FRINT64X_s 00011110 0. 1 010011 10000 ..... ..... @rr_sd
+
+FCVT_s_ds 00011110 00 1 000101 10000 ..... ..... @rr
+FCVT_s_hs 00011110 00 1 000111 10000 ..... ..... @rr
+FCVT_s_sd 00011110 01 1 000100 10000 ..... ..... @rr
+FCVT_s_hd 00011110 01 1 000111 10000 ..... ..... @rr
+FCVT_s_sh 00011110 11 1 000100 10000 ..... ..... @rr
+FCVT_s_dh 00011110 11 1 000101 10000 ..... ..... @rr
+
# Floating-point Immediate
FMOVI_s 0001 1110 .. 1 imm:8 100 00000 rd:5 esz=%esz_hsd
+# Floating-point Compare
+
+FCMP 00011110 .. 1 rm:5 001000 rn:5 e:1 z:1 000 esz=%esz_hsd
+
+# Floating-point Conditional Compare
+
+FCCMP 00011110 .. 1 rm:5 cond:4 01 rn:5 e:1 nzcv:4 esz=%esz_hsd
+
# Advanced SIMD Modified Immediate / Shift by Immediate
%abcdefgh 16:3 5:5
@@ -1393,3 +1633,261 @@ UQRSHRN_si 0111 11110 .... ... 10011 1 ..... ..... @shri_s
SQRSHRUN_si 0111 11110 .... ... 10001 1 ..... ..... @shri_b
SQRSHRUN_si 0111 11110 .... ... 10001 1 ..... ..... @shri_h
SQRSHRUN_si 0111 11110 .... ... 10001 1 ..... ..... @shri_s
+
+# Advanced SIMD scalar two-register miscellaneous
+
+SQABS_s 0101 1110 ..1 00000 01111 0 ..... ..... @rr_e
+SQNEG_s 0111 1110 ..1 00000 01111 0 ..... ..... @rr_e
+ABS_s 0101 1110 111 00000 10111 0 ..... ..... @rr
+NEG_s 0111 1110 111 00000 10111 0 ..... ..... @rr
+CMGT0_s 0101 1110 111 00000 10001 0 ..... ..... @rr
+CMGE0_s 0111 1110 111 00000 10001 0 ..... ..... @rr
+CMEQ0_s 0101 1110 111 00000 10011 0 ..... ..... @rr
+CMLE0_s 0111 1110 111 00000 10011 0 ..... ..... @rr
+CMLT0_s 0101 1110 111 00000 10101 0 ..... ..... @rr
+
+SQXTUN_s 0111 1110 ..1 00001 00101 0 ..... ..... @rr_e
+SQXTN_s 0101 1110 ..1 00001 01001 0 ..... ..... @rr_e
+UQXTN_s 0111 1110 ..1 00001 01001 0 ..... ..... @rr_e
+
+FCVTXN_s 0111 1110 011 00001 01101 0 ..... ..... @rr_s
+
+FCMGT0_s 0101 1110 111 11000 11001 0 ..... ..... @rr_h
+FCMGT0_s 0101 1110 1.1 00000 11001 0 ..... ..... @rr_sd
+
+FCMGE0_s 0111 1110 111 11000 11001 0 ..... ..... @rr_h
+FCMGE0_s 0111 1110 1.1 00000 11001 0 ..... ..... @rr_sd
+
+FCMEQ0_s 0101 1110 111 11000 11011 0 ..... ..... @rr_h
+FCMEQ0_s 0101 1110 1.1 00000 11011 0 ..... ..... @rr_sd
+
+FCMLE0_s 0111 1110 111 11000 11011 0 ..... ..... @rr_h
+FCMLE0_s 0111 1110 1.1 00000 11011 0 ..... ..... @rr_sd
+
+FCMLT0_s 0101 1110 111 11000 11101 0 ..... ..... @rr_h
+FCMLT0_s 0101 1110 1.1 00000 11101 0 ..... ..... @rr_sd
+
+FRECPE_s 0101 1110 111 11001 11011 0 ..... ..... @rr_h
+FRECPE_s 0101 1110 1.1 00001 11011 0 ..... ..... @rr_sd
+
+FRECPX_s 0101 1110 111 11001 11111 0 ..... ..... @rr_h
+FRECPX_s 0101 1110 1.1 00001 11111 0 ..... ..... @rr_sd
+
+FRSQRTE_s 0111 1110 111 11001 11011 0 ..... ..... @rr_h
+FRSQRTE_s 0111 1110 1.1 00001 11011 0 ..... ..... @rr_sd
+
+@icvt_h . ....... .. ...... ...... rn:5 rd:5 \
+ &fcvt sf=0 esz=1 shift=0
+@icvt_sd . ....... .. ...... ...... rn:5 rd:5 \
+ &fcvt sf=0 esz=%esz_sd shift=0
+
+SCVTF_f 0101 1110 011 11001 11011 0 ..... ..... @icvt_h
+SCVTF_f 0101 1110 0.1 00001 11011 0 ..... ..... @icvt_sd
+
+UCVTF_f 0111 1110 011 11001 11011 0 ..... ..... @icvt_h
+UCVTF_f 0111 1110 0.1 00001 11011 0 ..... ..... @icvt_sd
+
+FCVTNS_f 0101 1110 011 11001 10101 0 ..... ..... @icvt_h
+FCVTNS_f 0101 1110 0.1 00001 10101 0 ..... ..... @icvt_sd
+FCVTNU_f 0111 1110 011 11001 10101 0 ..... ..... @icvt_h
+FCVTNU_f 0111 1110 0.1 00001 10101 0 ..... ..... @icvt_sd
+
+FCVTPS_f 0101 1110 111 11001 10101 0 ..... ..... @icvt_h
+FCVTPS_f 0101 1110 1.1 00001 10101 0 ..... ..... @icvt_sd
+FCVTPU_f 0111 1110 111 11001 10101 0 ..... ..... @icvt_h
+FCVTPU_f 0111 1110 1.1 00001 10101 0 ..... ..... @icvt_sd
+
+FCVTMS_f 0101 1110 011 11001 10111 0 ..... ..... @icvt_h
+FCVTMS_f 0101 1110 0.1 00001 10111 0 ..... ..... @icvt_sd
+FCVTMU_f 0111 1110 011 11001 10111 0 ..... ..... @icvt_h
+FCVTMU_f 0111 1110 0.1 00001 10111 0 ..... ..... @icvt_sd
+
+FCVTZS_f 0101 1110 111 11001 10111 0 ..... ..... @icvt_h
+FCVTZS_f 0101 1110 1.1 00001 10111 0 ..... ..... @icvt_sd
+FCVTZU_f 0111 1110 111 11001 10111 0 ..... ..... @icvt_h
+FCVTZU_f 0111 1110 1.1 00001 10111 0 ..... ..... @icvt_sd
+
+FCVTAS_f 0101 1110 011 11001 11001 0 ..... ..... @icvt_h
+FCVTAS_f 0101 1110 0.1 00001 11001 0 ..... ..... @icvt_sd
+FCVTAU_f 0111 1110 011 11001 11001 0 ..... ..... @icvt_h
+FCVTAU_f 0111 1110 0.1 00001 11001 0 ..... ..... @icvt_sd
+
+%fcvt_f_sh_h 16:4 !function=rsub_16
+%fcvt_f_sh_s 16:5 !function=rsub_32
+%fcvt_f_sh_d 16:6 !function=rsub_64
+
+@fcvt_fixed_h .... .... . 001 .... ...... rn:5 rd:5 \
+ &fcvt sf=0 esz=1 shift=%fcvt_f_sh_h
+@fcvt_fixed_s .... .... . 01 ..... ...... rn:5 rd:5 \
+ &fcvt sf=0 esz=2 shift=%fcvt_f_sh_s
+@fcvt_fixed_d .... .... . 1 ...... ...... rn:5 rd:5 \
+ &fcvt sf=0 esz=3 shift=%fcvt_f_sh_d
+
+SCVTF_f 0101 1111 0 ....... 111001 ..... ..... @fcvt_fixed_h
+SCVTF_f 0101 1111 0 ....... 111001 ..... ..... @fcvt_fixed_s
+SCVTF_f 0101 1111 0 ....... 111001 ..... ..... @fcvt_fixed_d
+
+UCVTF_f 0111 1111 0 ....... 111001 ..... ..... @fcvt_fixed_h
+UCVTF_f 0111 1111 0 ....... 111001 ..... ..... @fcvt_fixed_s
+UCVTF_f 0111 1111 0 ....... 111001 ..... ..... @fcvt_fixed_d
+
+FCVTZS_f 0101 1111 0 ....... 111111 ..... ..... @fcvt_fixed_h
+FCVTZS_f 0101 1111 0 ....... 111111 ..... ..... @fcvt_fixed_s
+FCVTZS_f 0101 1111 0 ....... 111111 ..... ..... @fcvt_fixed_d
+
+FCVTZU_f 0111 1111 0 ....... 111111 ..... ..... @fcvt_fixed_h
+FCVTZU_f 0111 1111 0 ....... 111111 ..... ..... @fcvt_fixed_s
+FCVTZU_f 0111 1111 0 ....... 111111 ..... ..... @fcvt_fixed_d
+
+# Advanced SIMD two-register miscellaneous
+
+SQABS_v 0.00 1110 ..1 00000 01111 0 ..... ..... @qrr_e
+SQNEG_v 0.10 1110 ..1 00000 01111 0 ..... ..... @qrr_e
+ABS_v 0.00 1110 ..1 00000 10111 0 ..... ..... @qrr_e
+NEG_v 0.10 1110 ..1 00000 10111 0 ..... ..... @qrr_e
+CLS_v 0.00 1110 ..1 00000 01001 0 ..... ..... @qrr_e
+CLZ_v 0.10 1110 ..1 00000 01001 0 ..... ..... @qrr_e
+CNT_v 0.00 1110 001 00000 01011 0 ..... ..... @qrr_b
+NOT_v 0.10 1110 001 00000 01011 0 ..... ..... @qrr_b
+RBIT_v 0.10 1110 011 00000 01011 0 ..... ..... @qrr_b
+CMGT0_v 0.00 1110 ..1 00000 10001 0 ..... ..... @qrr_e
+CMGE0_v 0.10 1110 ..1 00000 10001 0 ..... ..... @qrr_e
+CMEQ0_v 0.00 1110 ..1 00000 10011 0 ..... ..... @qrr_e
+CMLE0_v 0.10 1110 ..1 00000 10011 0 ..... ..... @qrr_e
+CMLT0_v 0.00 1110 ..1 00000 10101 0 ..... ..... @qrr_e
+
+REV16_v 0.00 1110 001 00000 00011 0 ..... ..... @qrr_b
+REV32_v 0.10 1110 0.1 00000 00001 0 ..... ..... @qrr_bh
+REV64_v 0.00 1110 ..1 00000 00001 0 ..... ..... @qrr_e
+
+SADDLP_v 0.00 1110 ..1 00000 00101 0 ..... ..... @qrr_e
+UADDLP_v 0.10 1110 ..1 00000 00101 0 ..... ..... @qrr_e
+SADALP_v 0.00 1110 ..1 00000 01101 0 ..... ..... @qrr_e
+UADALP_v 0.10 1110 ..1 00000 01101 0 ..... ..... @qrr_e
+
+XTN 0.00 1110 ..1 00001 00101 0 ..... ..... @qrr_e
+SQXTUN_v 0.10 1110 ..1 00001 00101 0 ..... ..... @qrr_e
+SQXTN_v 0.00 1110 ..1 00001 01001 0 ..... ..... @qrr_e
+UQXTN_v 0.10 1110 ..1 00001 01001 0 ..... ..... @qrr_e
+
+FCVTN_v 0.00 1110 0.1 00001 01101 0 ..... ..... @qrr_hs
+FCVTXN_v 0.10 1110 011 00001 01101 0 ..... ..... @qrr_s
+BFCVTN_v 0.00 1110 101 00001 01101 0 ..... ..... @qrr_h
+
+SHLL_v 0.10 1110 ..1 00001 00111 0 ..... ..... @qrr_e
+
+FABS_v 0.00 1110 111 11000 11111 0 ..... ..... @qrr_h
+FABS_v 0.00 1110 1.1 00000 11111 0 ..... ..... @qrr_sd
+
+FNEG_v 0.10 1110 111 11000 11111 0 ..... ..... @qrr_h
+FNEG_v 0.10 1110 1.1 00000 11111 0 ..... ..... @qrr_sd
+
+FSQRT_v 0.10 1110 111 11001 11111 0 ..... ..... @qrr_h
+FSQRT_v 0.10 1110 1.1 00001 11111 0 ..... ..... @qrr_sd
+
+FRINTN_v 0.00 1110 011 11001 10001 0 ..... ..... @qrr_h
+FRINTN_v 0.00 1110 0.1 00001 10001 0 ..... ..... @qrr_sd
+
+FRINTM_v 0.00 1110 011 11001 10011 0 ..... ..... @qrr_h
+FRINTM_v 0.00 1110 0.1 00001 10011 0 ..... ..... @qrr_sd
+
+FRINTP_v 0.00 1110 111 11001 10001 0 ..... ..... @qrr_h
+FRINTP_v 0.00 1110 1.1 00001 10001 0 ..... ..... @qrr_sd
+
+FRINTZ_v 0.00 1110 111 11001 10011 0 ..... ..... @qrr_h
+FRINTZ_v 0.00 1110 1.1 00001 10011 0 ..... ..... @qrr_sd
+
+FRINTA_v 0.10 1110 011 11001 10001 0 ..... ..... @qrr_h
+FRINTA_v 0.10 1110 0.1 00001 10001 0 ..... ..... @qrr_sd
+
+FRINTX_v 0.10 1110 011 11001 10011 0 ..... ..... @qrr_h
+FRINTX_v 0.10 1110 0.1 00001 10011 0 ..... ..... @qrr_sd
+
+FRINTI_v 0.10 1110 111 11001 10011 0 ..... ..... @qrr_h
+FRINTI_v 0.10 1110 1.1 00001 10011 0 ..... ..... @qrr_sd
+
+FRINT32Z_v 0.00 1110 0.1 00001 11101 0 ..... ..... @qrr_sd
+FRINT32X_v 0.10 1110 0.1 00001 11101 0 ..... ..... @qrr_sd
+FRINT64Z_v 0.00 1110 0.1 00001 11111 0 ..... ..... @qrr_sd
+FRINT64X_v 0.10 1110 0.1 00001 11111 0 ..... ..... @qrr_sd
+
+SCVTF_vi 0.00 1110 011 11001 11011 0 ..... ..... @qrr_h
+SCVTF_vi 0.00 1110 0.1 00001 11011 0 ..... ..... @qrr_sd
+
+UCVTF_vi 0.10 1110 011 11001 11011 0 ..... ..... @qrr_h
+UCVTF_vi 0.10 1110 0.1 00001 11011 0 ..... ..... @qrr_sd
+
+FCVTNS_vi 0.00 1110 011 11001 10101 0 ..... ..... @qrr_h
+FCVTNS_vi 0.00 1110 0.1 00001 10101 0 ..... ..... @qrr_sd
+FCVTNU_vi 0.10 1110 011 11001 10101 0 ..... ..... @qrr_h
+FCVTNU_vi 0.10 1110 0.1 00001 10101 0 ..... ..... @qrr_sd
+
+FCVTPS_vi 0.00 1110 111 11001 10101 0 ..... ..... @qrr_h
+FCVTPS_vi 0.00 1110 1.1 00001 10101 0 ..... ..... @qrr_sd
+FCVTPU_vi 0.10 1110 111 11001 10101 0 ..... ..... @qrr_h
+FCVTPU_vi 0.10 1110 1.1 00001 10101 0 ..... ..... @qrr_sd
+
+FCVTMS_vi 0.00 1110 011 11001 10111 0 ..... ..... @qrr_h
+FCVTMS_vi 0.00 1110 0.1 00001 10111 0 ..... ..... @qrr_sd
+FCVTMU_vi 0.10 1110 011 11001 10111 0 ..... ..... @qrr_h
+FCVTMU_vi 0.10 1110 0.1 00001 10111 0 ..... ..... @qrr_sd
+
+FCVTZS_vi 0.00 1110 111 11001 10111 0 ..... ..... @qrr_h
+FCVTZS_vi 0.00 1110 1.1 00001 10111 0 ..... ..... @qrr_sd
+FCVTZU_vi 0.10 1110 111 11001 10111 0 ..... ..... @qrr_h
+FCVTZU_vi 0.10 1110 1.1 00001 10111 0 ..... ..... @qrr_sd
+
+FCVTAS_vi 0.00 1110 011 11001 11001 0 ..... ..... @qrr_h
+FCVTAS_vi 0.00 1110 0.1 00001 11001 0 ..... ..... @qrr_sd
+FCVTAU_vi 0.10 1110 011 11001 11001 0 ..... ..... @qrr_h
+FCVTAU_vi 0.10 1110 0.1 00001 11001 0 ..... ..... @qrr_sd
+
+FCMGT0_v 0.00 1110 111 11000 11001 0 ..... ..... @qrr_h
+FCMGT0_v 0.00 1110 1.1 00000 11001 0 ..... ..... @qrr_sd
+
+FCMGE0_v 0.10 1110 111 11000 11001 0 ..... ..... @qrr_h
+FCMGE0_v 0.10 1110 1.1 00000 11001 0 ..... ..... @qrr_sd
+
+FCMEQ0_v 0.00 1110 111 11000 11011 0 ..... ..... @qrr_h
+FCMEQ0_v 0.00 1110 1.1 00000 11011 0 ..... ..... @qrr_sd
+
+FCMLE0_v 0.10 1110 111 11000 11011 0 ..... ..... @qrr_h
+FCMLE0_v 0.10 1110 1.1 00000 11011 0 ..... ..... @qrr_sd
+
+FCMLT0_v 0.00 1110 111 11000 11101 0 ..... ..... @qrr_h
+FCMLT0_v 0.00 1110 1.1 00000 11101 0 ..... ..... @qrr_sd
+
+FRECPE_v 0.00 1110 111 11001 11011 0 ..... ..... @qrr_h
+FRECPE_v 0.00 1110 1.1 00001 11011 0 ..... ..... @qrr_sd
+
+FRSQRTE_v 0.10 1110 111 11001 11011 0 ..... ..... @qrr_h
+FRSQRTE_v 0.10 1110 1.1 00001 11011 0 ..... ..... @qrr_sd
+
+URECPE_v 0.00 1110 101 00001 11001 0 ..... ..... @qrr_s
+URSQRTE_v 0.10 1110 101 00001 11001 0 ..... ..... @qrr_s
+
+FCVTL_v 0.00 1110 0.1 00001 01111 0 ..... ..... @qrr_sd
+
+&fcvt_q rd rn esz q shift
+@fcvtq_h . q:1 . ...... 001 .... ...... rn:5 rd:5 \
+ &fcvt_q esz=1 shift=%fcvt_f_sh_h
+@fcvtq_s . q:1 . ...... 01 ..... ...... rn:5 rd:5 \
+ &fcvt_q esz=2 shift=%fcvt_f_sh_s
+@fcvtq_d . q:1 . ...... 1 ...... ...... rn:5 rd:5 \
+ &fcvt_q esz=3 shift=%fcvt_f_sh_d
+
+SCVTF_vf 0.00 11110 ....... 111001 ..... ..... @fcvtq_h
+SCVTF_vf 0.00 11110 ....... 111001 ..... ..... @fcvtq_s
+SCVTF_vf 0.00 11110 ....... 111001 ..... ..... @fcvtq_d
+
+UCVTF_vf 0.10 11110 ....... 111001 ..... ..... @fcvtq_h
+UCVTF_vf 0.10 11110 ....... 111001 ..... ..... @fcvtq_s
+UCVTF_vf 0.10 11110 ....... 111001 ..... ..... @fcvtq_d
+
+FCVTZS_vf 0.00 11110 ....... 111111 ..... ..... @fcvtq_h
+FCVTZS_vf 0.00 11110 ....... 111111 ..... ..... @fcvtq_s
+FCVTZS_vf 0.00 11110 ....... 111111 ..... ..... @fcvtq_d
+
+FCVTZU_vf 0.10 11110 ....... 111111 ..... ..... @fcvtq_h
+FCVTZU_vf 0.10 11110 ....... 111111 ..... ..... @fcvtq_s
+FCVTZU_vf 0.10 11110 ....... 111111 ..... ..... @fcvtq_d
diff --git a/target/arm/tcg/gengvec.c b/target/arm/tcg/gengvec.c
index f652520..01867f8 100644
--- a/target/arm/tcg/gengvec.c
+++ b/target/arm/tcg/gengvec.c
@@ -2358,3 +2358,372 @@ void gen_gvec_urhadd(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
assert(vece <= MO_32);
tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &g[vece]);
}
+
+void gen_gvec_cls(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz)
+{
+ static const GVecGen2 g[] = {
+ { .fni4 = gen_helper_neon_cls_s8,
+ .vece = MO_8 },
+ { .fni4 = gen_helper_neon_cls_s16,
+ .vece = MO_16 },
+ { .fni4 = tcg_gen_clrsb_i32,
+ .vece = MO_32 },
+ };
+ assert(vece <= MO_32);
+ tcg_gen_gvec_2(rd_ofs, rn_ofs, opr_sz, max_sz, &g[vece]);
+}
+
+static void gen_clz32_i32(TCGv_i32 d, TCGv_i32 n)
+{
+ tcg_gen_clzi_i32(d, n, 32);
+}
+
+void gen_gvec_clz(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz)
+{
+ static const GVecGen2 g[] = {
+ { .fni4 = gen_helper_neon_clz_u8,
+ .vece = MO_8 },
+ { .fni4 = gen_helper_neon_clz_u16,
+ .vece = MO_16 },
+ { .fni4 = gen_clz32_i32,
+ .vece = MO_32 },
+ };
+ assert(vece <= MO_32);
+ tcg_gen_gvec_2(rd_ofs, rn_ofs, opr_sz, max_sz, &g[vece]);
+}
+
+void gen_gvec_cnt(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz)
+{
+ assert(vece == MO_8);
+ tcg_gen_gvec_2_ool(rd_ofs, rn_ofs, opr_sz, max_sz, 0,
+ gen_helper_gvec_cnt_b);
+}
+
+void gen_gvec_rbit(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz)
+{
+ assert(vece == MO_8);
+ tcg_gen_gvec_2_ool(rd_ofs, rn_ofs, opr_sz, max_sz, 0,
+ gen_helper_gvec_rbit_b);
+}
+
+void gen_gvec_rev16(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz)
+{
+ assert(vece == MO_8);
+ tcg_gen_gvec_rotli(MO_16, rd_ofs, rn_ofs, 8, opr_sz, max_sz);
+}
+
+static void gen_bswap32_i64(TCGv_i64 d, TCGv_i64 n)
+{
+ tcg_gen_bswap64_i64(d, n);
+ tcg_gen_rotli_i64(d, d, 32);
+}
+
+void gen_gvec_rev32(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz)
+{
+ static const GVecGen2 g = {
+ .fni8 = gen_bswap32_i64,
+ .fni4 = tcg_gen_bswap32_i32,
+ .prefer_i64 = TCG_TARGET_REG_BITS == 64,
+ .vece = MO_32
+ };
+
+ switch (vece) {
+ case MO_16:
+ tcg_gen_gvec_rotli(MO_32, rd_ofs, rn_ofs, 16, opr_sz, max_sz);
+ break;
+ case MO_8:
+ tcg_gen_gvec_2(rd_ofs, rn_ofs, opr_sz, max_sz, &g);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+void gen_gvec_rev64(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz)
+{
+ static const GVecGen2 g[] = {
+ { .fni8 = tcg_gen_bswap64_i64,
+ .vece = MO_64 },
+ { .fni8 = tcg_gen_hswap_i64,
+ .vece = MO_64 },
+ };
+
+ switch (vece) {
+ case MO_32:
+ tcg_gen_gvec_rotli(MO_64, rd_ofs, rn_ofs, 32, opr_sz, max_sz);
+ break;
+ case MO_8:
+ case MO_16:
+ tcg_gen_gvec_2(rd_ofs, rn_ofs, opr_sz, max_sz, &g[vece]);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static void gen_saddlp_vec(unsigned vece, TCGv_vec d, TCGv_vec n)
+{
+ int half = 4 << vece;
+ TCGv_vec t = tcg_temp_new_vec_matching(d);
+
+ tcg_gen_shli_vec(vece, t, n, half);
+ tcg_gen_sari_vec(vece, d, n, half);
+ tcg_gen_sari_vec(vece, t, t, half);
+ tcg_gen_add_vec(vece, d, d, t);
+}
+
+static void gen_saddlp_s_i64(TCGv_i64 d, TCGv_i64 n)
+{
+ TCGv_i64 t = tcg_temp_new_i64();
+
+ tcg_gen_ext32s_i64(t, n);
+ tcg_gen_sari_i64(d, n, 32);
+ tcg_gen_add_i64(d, d, t);
+}
+
+void gen_gvec_saddlp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz)
+{
+ static const TCGOpcode vecop_list[] = {
+ INDEX_op_sari_vec, INDEX_op_shli_vec, INDEX_op_add_vec, 0
+ };
+ static const GVecGen2 g[] = {
+ { .fniv = gen_saddlp_vec,
+ .fni8 = gen_helper_neon_addlp_s8,
+ .opt_opc = vecop_list,
+ .vece = MO_16 },
+ { .fniv = gen_saddlp_vec,
+ .fni8 = gen_helper_neon_addlp_s16,
+ .opt_opc = vecop_list,
+ .vece = MO_32 },
+ { .fniv = gen_saddlp_vec,
+ .fni8 = gen_saddlp_s_i64,
+ .opt_opc = vecop_list,
+ .vece = MO_64 },
+ };
+ assert(vece <= MO_32);
+ tcg_gen_gvec_2(rd_ofs, rn_ofs, opr_sz, max_sz, &g[vece]);
+}
+
+static void gen_sadalp_vec(unsigned vece, TCGv_vec d, TCGv_vec n)
+{
+ TCGv_vec t = tcg_temp_new_vec_matching(d);
+
+ gen_saddlp_vec(vece, t, n);
+ tcg_gen_add_vec(vece, d, d, t);
+}
+
+static void gen_sadalp_b_i64(TCGv_i64 d, TCGv_i64 n)
+{
+ TCGv_i64 t = tcg_temp_new_i64();
+
+ gen_helper_neon_addlp_s8(t, n);
+ tcg_gen_vec_add16_i64(d, d, t);
+}
+
+static void gen_sadalp_h_i64(TCGv_i64 d, TCGv_i64 n)
+{
+ TCGv_i64 t = tcg_temp_new_i64();
+
+ gen_helper_neon_addlp_s16(t, n);
+ tcg_gen_vec_add32_i64(d, d, t);
+}
+
+static void gen_sadalp_s_i64(TCGv_i64 d, TCGv_i64 n)
+{
+ TCGv_i64 t = tcg_temp_new_i64();
+
+ gen_saddlp_s_i64(t, n);
+ tcg_gen_add_i64(d, d, t);
+}
+
+void gen_gvec_sadalp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz)
+{
+ static const TCGOpcode vecop_list[] = {
+ INDEX_op_sari_vec, INDEX_op_shli_vec, INDEX_op_add_vec, 0
+ };
+ static const GVecGen2 g[] = {
+ { .fniv = gen_sadalp_vec,
+ .fni8 = gen_sadalp_b_i64,
+ .opt_opc = vecop_list,
+ .load_dest = true,
+ .vece = MO_16 },
+ { .fniv = gen_sadalp_vec,
+ .fni8 = gen_sadalp_h_i64,
+ .opt_opc = vecop_list,
+ .load_dest = true,
+ .vece = MO_32 },
+ { .fniv = gen_sadalp_vec,
+ .fni8 = gen_sadalp_s_i64,
+ .opt_opc = vecop_list,
+ .load_dest = true,
+ .vece = MO_64 },
+ };
+ assert(vece <= MO_32);
+ tcg_gen_gvec_2(rd_ofs, rn_ofs, opr_sz, max_sz, &g[vece]);
+}
+
+static void gen_uaddlp_vec(unsigned vece, TCGv_vec d, TCGv_vec n)
+{
+ int half = 4 << vece;
+ TCGv_vec t = tcg_temp_new_vec_matching(d);
+ TCGv_vec m = tcg_constant_vec_matching(d, vece, MAKE_64BIT_MASK(0, half));
+
+ tcg_gen_shri_vec(vece, t, n, half);
+ tcg_gen_and_vec(vece, d, n, m);
+ tcg_gen_add_vec(vece, d, d, t);
+}
+
+static void gen_uaddlp_b_i64(TCGv_i64 d, TCGv_i64 n)
+{
+ TCGv_i64 t = tcg_temp_new_i64();
+ TCGv_i64 m = tcg_constant_i64(dup_const(MO_16, 0xff));
+
+ tcg_gen_shri_i64(t, n, 8);
+ tcg_gen_and_i64(d, n, m);
+ tcg_gen_and_i64(t, t, m);
+ /* No carry between widened unsigned elements. */
+ tcg_gen_add_i64(d, d, t);
+}
+
+static void gen_uaddlp_h_i64(TCGv_i64 d, TCGv_i64 n)
+{
+ TCGv_i64 t = tcg_temp_new_i64();
+ TCGv_i64 m = tcg_constant_i64(dup_const(MO_32, 0xffff));
+
+ tcg_gen_shri_i64(t, n, 16);
+ tcg_gen_and_i64(d, n, m);
+ tcg_gen_and_i64(t, t, m);
+ /* No carry between widened unsigned elements. */
+ tcg_gen_add_i64(d, d, t);
+}
+
+static void gen_uaddlp_s_i64(TCGv_i64 d, TCGv_i64 n)
+{
+ TCGv_i64 t = tcg_temp_new_i64();
+
+ tcg_gen_ext32u_i64(t, n);
+ tcg_gen_shri_i64(d, n, 32);
+ tcg_gen_add_i64(d, d, t);
+}
+
+void gen_gvec_uaddlp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz)
+{
+ static const TCGOpcode vecop_list[] = {
+ INDEX_op_shri_vec, INDEX_op_add_vec, 0
+ };
+ static const GVecGen2 g[] = {
+ { .fniv = gen_uaddlp_vec,
+ .fni8 = gen_uaddlp_b_i64,
+ .opt_opc = vecop_list,
+ .vece = MO_16 },
+ { .fniv = gen_uaddlp_vec,
+ .fni8 = gen_uaddlp_h_i64,
+ .opt_opc = vecop_list,
+ .vece = MO_32 },
+ { .fniv = gen_uaddlp_vec,
+ .fni8 = gen_uaddlp_s_i64,
+ .opt_opc = vecop_list,
+ .vece = MO_64 },
+ };
+ assert(vece <= MO_32);
+ tcg_gen_gvec_2(rd_ofs, rn_ofs, opr_sz, max_sz, &g[vece]);
+}
+
+static void gen_uadalp_vec(unsigned vece, TCGv_vec d, TCGv_vec n)
+{
+ TCGv_vec t = tcg_temp_new_vec_matching(d);
+
+ gen_uaddlp_vec(vece, t, n);
+ tcg_gen_add_vec(vece, d, d, t);
+}
+
+static void gen_uadalp_b_i64(TCGv_i64 d, TCGv_i64 n)
+{
+ TCGv_i64 t = tcg_temp_new_i64();
+
+ gen_uaddlp_b_i64(t, n);
+ tcg_gen_vec_add16_i64(d, d, t);
+}
+
+static void gen_uadalp_h_i64(TCGv_i64 d, TCGv_i64 n)
+{
+ TCGv_i64 t = tcg_temp_new_i64();
+
+ gen_uaddlp_h_i64(t, n);
+ tcg_gen_vec_add32_i64(d, d, t);
+}
+
+static void gen_uadalp_s_i64(TCGv_i64 d, TCGv_i64 n)
+{
+ TCGv_i64 t = tcg_temp_new_i64();
+
+ gen_uaddlp_s_i64(t, n);
+ tcg_gen_add_i64(d, d, t);
+}
+
+void gen_gvec_uadalp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz)
+{
+ static const TCGOpcode vecop_list[] = {
+ INDEX_op_shri_vec, INDEX_op_add_vec, 0
+ };
+ static const GVecGen2 g[] = {
+ { .fniv = gen_uadalp_vec,
+ .fni8 = gen_uadalp_b_i64,
+ .load_dest = true,
+ .opt_opc = vecop_list,
+ .vece = MO_16 },
+ { .fniv = gen_uadalp_vec,
+ .fni8 = gen_uadalp_h_i64,
+ .load_dest = true,
+ .opt_opc = vecop_list,
+ .vece = MO_32 },
+ { .fniv = gen_uadalp_vec,
+ .fni8 = gen_uadalp_s_i64,
+ .load_dest = true,
+ .opt_opc = vecop_list,
+ .vece = MO_64 },
+ };
+ assert(vece <= MO_32);
+ tcg_gen_gvec_2(rd_ofs, rn_ofs, opr_sz, max_sz, &g[vece]);
+}
+
+void gen_gvec_fabs(unsigned vece, uint32_t dofs, uint32_t aofs,
+ uint32_t oprsz, uint32_t maxsz)
+{
+ uint64_t s_bit = 1ull << ((8 << vece) - 1);
+ tcg_gen_gvec_andi(vece, dofs, aofs, s_bit - 1, oprsz, maxsz);
+}
+
+void gen_gvec_fneg(unsigned vece, uint32_t dofs, uint32_t aofs,
+ uint32_t oprsz, uint32_t maxsz)
+{
+ uint64_t s_bit = 1ull << ((8 << vece) - 1);
+ tcg_gen_gvec_xori(vece, dofs, aofs, s_bit, oprsz, maxsz);
+}
+
+void gen_gvec_urecpe(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz)
+{
+ assert(vece == MO_32);
+ tcg_gen_gvec_2_ool(rd_ofs, rn_ofs, opr_sz, max_sz, 0,
+ gen_helper_gvec_urecpe_s);
+}
+
+void gen_gvec_ursqrte(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz)
+{
+ assert(vece == MO_32);
+ tcg_gen_gvec_2_ool(rd_ofs, rn_ofs, opr_sz, max_sz, 0,
+ gen_helper_gvec_ursqrte_s);
+}
diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c
index 8f42a28..fb6fe0f 100644
--- a/target/arm/tcg/helper-a64.c
+++ b/target/arm/tcg/helper-a64.c
@@ -306,67 +306,6 @@ float64 HELPER(rsqrtsf_f64)(float64 a, float64 b, void *fpstp)
return float64_muladd(a, b, float64_three, float_muladd_halve_result, fpst);
}
-/* Pairwise long add: add pairs of adjacent elements into
- * double-width elements in the result (eg _s8 is an 8x8->16 op)
- */
-uint64_t HELPER(neon_addlp_s8)(uint64_t a)
-{
- uint64_t nsignmask = 0x0080008000800080ULL;
- uint64_t wsignmask = 0x8000800080008000ULL;
- uint64_t elementmask = 0x00ff00ff00ff00ffULL;
- uint64_t tmp1, tmp2;
- uint64_t res, signres;
-
- /* Extract odd elements, sign extend each to a 16 bit field */
- tmp1 = a & elementmask;
- tmp1 ^= nsignmask;
- tmp1 |= wsignmask;
- tmp1 = (tmp1 - nsignmask) ^ wsignmask;
- /* Ditto for the even elements */
- tmp2 = (a >> 8) & elementmask;
- tmp2 ^= nsignmask;
- tmp2 |= wsignmask;
- tmp2 = (tmp2 - nsignmask) ^ wsignmask;
-
- /* calculate the result by summing bits 0..14, 16..22, etc,
- * and then adjusting the sign bits 15, 23, etc manually.
- * This ensures the addition can't overflow the 16 bit field.
- */
- signres = (tmp1 ^ tmp2) & wsignmask;
- res = (tmp1 & ~wsignmask) + (tmp2 & ~wsignmask);
- res ^= signres;
-
- return res;
-}
-
-uint64_t HELPER(neon_addlp_u8)(uint64_t a)
-{
- uint64_t tmp;
-
- tmp = a & 0x00ff00ff00ff00ffULL;
- tmp += (a >> 8) & 0x00ff00ff00ff00ffULL;
- return tmp;
-}
-
-uint64_t HELPER(neon_addlp_s16)(uint64_t a)
-{
- int32_t reslo, reshi;
-
- reslo = (int32_t)(int16_t)a + (int32_t)(int16_t)(a >> 16);
- reshi = (int32_t)(int16_t)(a >> 32) + (int32_t)(int16_t)(a >> 48);
-
- return (uint32_t)reslo | (((uint64_t)reshi) << 32);
-}
-
-uint64_t HELPER(neon_addlp_u16)(uint64_t a)
-{
- uint64_t tmp;
-
- tmp = a & 0x0000ffff0000ffffULL;
- tmp += (a >> 16) & 0x0000ffff0000ffffULL;
- return tmp;
-}
-
/* Floating-point reciprocal exponent - see FPRecpX in ARM ARM */
uint32_t HELPER(frecpx_f16)(uint32_t a, void *fpstp)
{
@@ -469,23 +408,13 @@ float64 HELPER(frecpx_f64)(float64 a, void *fpstp)
float32 HELPER(fcvtx_f64_to_f32)(float64 a, CPUARMState *env)
{
- /* Von Neumann rounding is implemented by using round-to-zero
- * and then setting the LSB of the result if Inexact was raised.
- */
float32 r;
float_status *fpst = &env->vfp.fp_status;
- float_status tstat = *fpst;
- int exflags;
-
- set_float_rounding_mode(float_round_to_zero, &tstat);
- set_float_exception_flags(0, &tstat);
- r = float64_to_float32(a, &tstat);
- exflags = get_float_exception_flags(&tstat);
- if (exflags & float_flag_inexact) {
- r = make_float32(float32_val(r) | 1);
- }
- exflags |= get_float_exception_flags(fpst);
- set_float_exception_flags(exflags, fpst);
+ int old = get_float_rounding_mode(fpst);
+
+ set_float_rounding_mode(float_round_to_odd, fpst);
+ r = float64_to_float32(a, fpst);
+ set_float_rounding_mode(old, fpst);
return r;
}
@@ -679,38 +608,6 @@ uint32_t HELPER(advsimd_rinth)(uint32_t x, void *fp_status)
return ret;
}
-/*
- * Half-precision floating point conversion functions
- *
- * There are a multitude of conversion functions with various
- * different rounding modes. This is dealt with by the calling code
- * setting the mode appropriately before calling the helper.
- */
-
-uint32_t HELPER(advsimd_f16tosinth)(uint32_t a, void *fpstp)
-{
- float_status *fpst = fpstp;
-
- /* Invalid if we are passed a NaN */
- if (float16_is_any_nan(a)) {
- float_raise(float_flag_invalid, fpst);
- return 0;
- }
- return float16_to_int16(a, fpst);
-}
-
-uint32_t HELPER(advsimd_f16touinth)(uint32_t a, void *fpstp)
-{
- float_status *fpst = fpstp;
-
- /* Invalid if we are passed a NaN */
- if (float16_is_any_nan(a)) {
- float_raise(float_flag_invalid, fpst);
- return 0;
- }
- return float16_to_uint16(a, fpst);
-}
-
static int el_from_spsr(uint32_t spsr)
{
/* Return the exception level that this SPSR is requesting a return to,
@@ -915,17 +812,6 @@ illegal_return:
"resuming execution at 0x%" PRIx64 "\n", cur_el, env->pc);
}
-/*
- * Square Root and Reciprocal square root
- */
-
-uint32_t HELPER(sqrt_f16)(uint32_t a, void *fpstp)
-{
- float_status *s = fpstp;
-
- return float16_sqrt(a, s);
-}
-
void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
{
uintptr_t ra = GETPC();
diff --git a/target/arm/tcg/helper-a64.h b/target/arm/tcg/helper-a64.h
index 481007b..3c07741 100644
--- a/target/arm/tcg/helper-a64.h
+++ b/target/arm/tcg/helper-a64.h
@@ -41,10 +41,6 @@ DEF_HELPER_FLAGS_3(recpsf_f64, TCG_CALL_NO_RWG, f64, f64, f64, ptr)
DEF_HELPER_FLAGS_3(rsqrtsf_f16, TCG_CALL_NO_RWG, f16, f16, f16, ptr)
DEF_HELPER_FLAGS_3(rsqrtsf_f32, TCG_CALL_NO_RWG, f32, f32, f32, ptr)
DEF_HELPER_FLAGS_3(rsqrtsf_f64, TCG_CALL_NO_RWG, f64, f64, f64, ptr)
-DEF_HELPER_FLAGS_1(neon_addlp_s8, TCG_CALL_NO_RWG_SE, i64, i64)
-DEF_HELPER_FLAGS_1(neon_addlp_u8, TCG_CALL_NO_RWG_SE, i64, i64)
-DEF_HELPER_FLAGS_1(neon_addlp_s16, TCG_CALL_NO_RWG_SE, i64, i64)
-DEF_HELPER_FLAGS_1(neon_addlp_u16, TCG_CALL_NO_RWG_SE, i64, i64)
DEF_HELPER_FLAGS_2(frecpx_f64, TCG_CALL_NO_RWG, f64, f64, ptr)
DEF_HELPER_FLAGS_2(frecpx_f32, TCG_CALL_NO_RWG, f32, f32, ptr)
DEF_HELPER_FLAGS_2(frecpx_f16, TCG_CALL_NO_RWG, f16, f16, ptr)
@@ -78,9 +74,6 @@ DEF_HELPER_3(advsimd_mulx2h, i32, i32, i32, ptr)
DEF_HELPER_4(advsimd_muladd2h, i32, i32, i32, i32, ptr)
DEF_HELPER_2(advsimd_rinth_exact, f16, f16, ptr)
DEF_HELPER_2(advsimd_rinth, f16, f16, ptr)
-DEF_HELPER_2(advsimd_f16tosinth, i32, f16, ptr)
-DEF_HELPER_2(advsimd_f16touinth, i32, f16, ptr)
-DEF_HELPER_2(sqrt_f16, f16, f16, ptr)
DEF_HELPER_2(exception_return, void, env, i64)
DEF_HELPER_FLAGS_2(dc_zva, TCG_CALL_NO_WG, void, env, i64)
diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build
index 508932a..0923898 100644
--- a/target/arm/tcg/meson.build
+++ b/target/arm/tcg/meson.build
@@ -39,6 +39,7 @@ arm_ss.add(files(
'op_helper.c',
'tlb_helper.c',
'vec_helper.c',
+ 'tlb-insns.c',
))
arm_ss.add(when: 'TARGET_AARCH64', if_true: files(
diff --git a/target/arm/tcg/neon_helper.c b/target/arm/tcg/neon_helper.c
index 93b2076..c687e88 100644
--- a/target/arm/tcg/neon_helper.c
+++ b/target/arm/tcg/neon_helper.c
@@ -525,27 +525,6 @@ uint32_t HELPER(neon_cls_s32)(uint32_t x)
return count - 1;
}
-/* Bit count. */
-uint32_t HELPER(neon_cnt_u8)(uint32_t x)
-{
- x = (x & 0x55555555) + ((x >> 1) & 0x55555555);
- x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
- x = (x & 0x0f0f0f0f) + ((x >> 4) & 0x0f0f0f0f);
- return x;
-}
-
-/* Reverse bits in each 8 bit word */
-uint32_t HELPER(neon_rbit_u8)(uint32_t x)
-{
- x = ((x & 0xf0f0f0f0) >> 4)
- | ((x & 0x0f0f0f0f) << 4);
- x = ((x & 0x88888888) >> 3)
- | ((x & 0x44444444) >> 1)
- | ((x & 0x22222222) << 1)
- | ((x & 0x11111111) << 3);
- return x;
-}
-
#define NEON_QDMULH16(dest, src1, src2, round) do { \
uint32_t tmp = (int32_t)(int16_t) src1 * (int16_t) src2; \
if ((tmp ^ (tmp << 1)) & SIGNBIT) { \
@@ -847,62 +826,47 @@ uint64_t HELPER(neon_widen_s16)(uint32_t x)
return ((uint32_t)(int16_t)x) | (high << 32);
}
-uint64_t HELPER(neon_addl_u16)(uint64_t a, uint64_t b)
-{
- uint64_t mask;
- mask = (a ^ b) & 0x8000800080008000ull;
- a &= ~0x8000800080008000ull;
- b &= ~0x8000800080008000ull;
- return (a + b) ^ mask;
-}
-
-uint64_t HELPER(neon_addl_u32)(uint64_t a, uint64_t b)
-{
- uint64_t mask;
- mask = (a ^ b) & 0x8000000080000000ull;
- a &= ~0x8000000080000000ull;
- b &= ~0x8000000080000000ull;
- return (a + b) ^ mask;
-}
-
-uint64_t HELPER(neon_paddl_u16)(uint64_t a, uint64_t b)
-{
- uint64_t tmp;
- uint64_t tmp2;
+/* Pairwise long add: add pairs of adjacent elements into
+ * double-width elements in the result (eg _s8 is an 8x8->16 op)
+ */
+uint64_t HELPER(neon_addlp_s8)(uint64_t a)
+{
+ uint64_t nsignmask = 0x0080008000800080ULL;
+ uint64_t wsignmask = 0x8000800080008000ULL;
+ uint64_t elementmask = 0x00ff00ff00ff00ffULL;
+ uint64_t tmp1, tmp2;
+ uint64_t res, signres;
+
+ /* Extract odd elements, sign extend each to a 16 bit field */
+ tmp1 = a & elementmask;
+ tmp1 ^= nsignmask;
+ tmp1 |= wsignmask;
+ tmp1 = (tmp1 - nsignmask) ^ wsignmask;
+ /* Ditto for the even elements */
+ tmp2 = (a >> 8) & elementmask;
+ tmp2 ^= nsignmask;
+ tmp2 |= wsignmask;
+ tmp2 = (tmp2 - nsignmask) ^ wsignmask;
+
+ /* calculate the result by summing bits 0..14, 16..22, etc,
+ * and then adjusting the sign bits 15, 23, etc manually.
+ * This ensures the addition can't overflow the 16 bit field.
+ */
+ signres = (tmp1 ^ tmp2) & wsignmask;
+ res = (tmp1 & ~wsignmask) + (tmp2 & ~wsignmask);
+ res ^= signres;
- tmp = a & 0x0000ffff0000ffffull;
- tmp += (a >> 16) & 0x0000ffff0000ffffull;
- tmp2 = b & 0xffff0000ffff0000ull;
- tmp2 += (b << 16) & 0xffff0000ffff0000ull;
- return ( tmp & 0xffff)
- | ((tmp >> 16) & 0xffff0000ull)
- | ((tmp2 << 16) & 0xffff00000000ull)
- | ( tmp2 & 0xffff000000000000ull);
+ return res;
}
-uint64_t HELPER(neon_paddl_u32)(uint64_t a, uint64_t b)
+uint64_t HELPER(neon_addlp_s16)(uint64_t a)
{
- uint32_t low = a + (a >> 32);
- uint32_t high = b + (b >> 32);
- return low + ((uint64_t)high << 32);
-}
+ int32_t reslo, reshi;
-uint64_t HELPER(neon_subl_u16)(uint64_t a, uint64_t b)
-{
- uint64_t mask;
- mask = (a ^ ~b) & 0x8000800080008000ull;
- a |= 0x8000800080008000ull;
- b &= ~0x8000800080008000ull;
- return (a - b) ^ mask;
-}
+ reslo = (int32_t)(int16_t)a + (int32_t)(int16_t)(a >> 16);
+ reshi = (int32_t)(int16_t)(a >> 32) + (int32_t)(int16_t)(a >> 48);
-uint64_t HELPER(neon_subl_u32)(uint64_t a, uint64_t b)
-{
- uint64_t mask;
- mask = (a ^ ~b) & 0x8000000080000000ull;
- a |= 0x8000000080000000ull;
- b &= ~0x8000000080000000ull;
- return (a - b) ^ mask;
+ return (uint32_t)reslo | (((uint64_t)reshi) << 32);
}
uint64_t HELPER(neon_addl_saturate_s32)(CPUARMState *env, uint64_t a, uint64_t b)
diff --git a/target/arm/tcg/tlb-insns.c b/target/arm/tcg/tlb-insns.c
new file mode 100644
index 0000000..0f67294
--- /dev/null
+++ b/target/arm/tcg/tlb-insns.c
@@ -0,0 +1,1266 @@
+/*
+ * Helpers for TLBI insns
+ *
+ * This code is licensed under the GNU GPL v2 or later.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "exec/exec-all.h"
+#include "cpu.h"
+#include "internals.h"
+#include "cpu-features.h"
+#include "cpregs.h"
+
+/* Check for traps from EL1 due to HCR_EL2.TTLB. */
+static CPAccessResult access_ttlb(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ if (arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_TTLB)) {
+ return CP_ACCESS_TRAP_EL2;
+ }
+ return CP_ACCESS_OK;
+}
+
+/* Check for traps from EL1 due to HCR_EL2.TTLB or TTLBIS. */
+static CPAccessResult access_ttlbis(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ if (arm_current_el(env) == 1 &&
+ (arm_hcr_el2_eff(env) & (HCR_TTLB | HCR_TTLBIS))) {
+ return CP_ACCESS_TRAP_EL2;
+ }
+ return CP_ACCESS_OK;
+}
+
+#ifdef TARGET_AARCH64
+/* Check for traps from EL1 due to HCR_EL2.TTLB or TTLBOS. */
+static CPAccessResult access_ttlbos(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ if (arm_current_el(env) == 1 &&
+ (arm_hcr_el2_eff(env) & (HCR_TTLB | HCR_TTLBOS))) {
+ return CP_ACCESS_TRAP_EL2;
+ }
+ return CP_ACCESS_OK;
+}
+#endif
+
+/* IS variants of TLB operations must affect all cores */
+static void tlbiall_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+
+ tlb_flush_all_cpus_synced(cs);
+}
+
+static void tlbiasid_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+
+ tlb_flush_all_cpus_synced(cs);
+}
+
+static void tlbimva_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+
+ tlb_flush_page_all_cpus_synced(cs, value & TARGET_PAGE_MASK);
+}
+
+static void tlbimvaa_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+
+ tlb_flush_page_all_cpus_synced(cs, value & TARGET_PAGE_MASK);
+}
+
+/*
+ * Non-IS variants of TLB operations are upgraded to
+ * IS versions if we are at EL1 and HCR_EL2.FB is effectively set to
+ * force broadcast of these operations.
+ */
+static bool tlb_force_broadcast(CPUARMState *env)
+{
+ return arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_FB);
+}
+
+static void tlbiall_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ /* Invalidate all (TLBIALL) */
+ CPUState *cs = env_cpu(env);
+
+ if (tlb_force_broadcast(env)) {
+ tlb_flush_all_cpus_synced(cs);
+ } else {
+ tlb_flush(cs);
+ }
+}
+
+static void tlbimva_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ /* Invalidate single TLB entry by MVA and ASID (TLBIMVA) */
+ CPUState *cs = env_cpu(env);
+
+ value &= TARGET_PAGE_MASK;
+ if (tlb_force_broadcast(env)) {
+ tlb_flush_page_all_cpus_synced(cs, value);
+ } else {
+ tlb_flush_page(cs, value);
+ }
+}
+
+static void tlbiasid_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ /* Invalidate by ASID (TLBIASID) */
+ CPUState *cs = env_cpu(env);
+
+ if (tlb_force_broadcast(env)) {
+ tlb_flush_all_cpus_synced(cs);
+ } else {
+ tlb_flush(cs);
+ }
+}
+
+static void tlbimvaa_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ /* Invalidate single entry by MVA, all ASIDs (TLBIMVAA) */
+ CPUState *cs = env_cpu(env);
+
+ value &= TARGET_PAGE_MASK;
+ if (tlb_force_broadcast(env)) {
+ tlb_flush_page_all_cpus_synced(cs, value);
+ } else {
+ tlb_flush_page(cs, value);
+ }
+}
+
+static void tlbimva_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+ uint64_t pageaddr = value & ~MAKE_64BIT_MASK(0, 12);
+
+ tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_E2);
+}
+
+static void tlbimva_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+ uint64_t pageaddr = value & ~MAKE_64BIT_MASK(0, 12);
+
+ tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr,
+ ARMMMUIdxBit_E2);
+}
+
+static void tlbiipas2_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+ uint64_t pageaddr = (value & MAKE_64BIT_MASK(0, 28)) << 12;
+
+ tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_Stage2);
+}
+
+static void tlbiipas2is_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+ uint64_t pageaddr = (value & MAKE_64BIT_MASK(0, 28)) << 12;
+
+ tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, ARMMMUIdxBit_Stage2);
+}
+
+static void tlbiall_nsnh_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+
+ tlb_flush_by_mmuidx(cs, alle1_tlbmask(env));
+}
+
+static void tlbiall_nsnh_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+
+ tlb_flush_by_mmuidx_all_cpus_synced(cs, alle1_tlbmask(env));
+}
+
+
+static void tlbiall_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+
+ tlb_flush_by_mmuidx(cs, ARMMMUIdxBit_E2);
+}
+
+static void tlbiall_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+
+ tlb_flush_by_mmuidx_all_cpus_synced(cs, ARMMMUIdxBit_E2);
+}
+
+/*
+ * See: D4.7.2 TLB maintenance requirements and the TLB maintenance instructions
+ * Page D4-1736 (DDI0487A.b)
+ */
+
+static int vae1_tlbmask(CPUARMState *env)
+{
+ uint64_t hcr = arm_hcr_el2_eff(env);
+ uint16_t mask;
+
+ assert(arm_feature(env, ARM_FEATURE_AARCH64));
+
+ if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
+ mask = ARMMMUIdxBit_E20_2 |
+ ARMMMUIdxBit_E20_2_PAN |
+ ARMMMUIdxBit_E20_0;
+ } else {
+ /* This is AArch64 only, so we don't need to touch the EL30_x TLBs */
+ mask = ARMMMUIdxBit_E10_1 |
+ ARMMMUIdxBit_E10_1_PAN |
+ ARMMMUIdxBit_E10_0;
+ }
+ return mask;
+}
+
+static int vae2_tlbmask(CPUARMState *env)
+{
+ uint64_t hcr = arm_hcr_el2_eff(env);
+ uint16_t mask;
+
+ if (hcr & HCR_E2H) {
+ mask = ARMMMUIdxBit_E20_2 |
+ ARMMMUIdxBit_E20_2_PAN |
+ ARMMMUIdxBit_E20_0;
+ } else {
+ mask = ARMMMUIdxBit_E2;
+ }
+ return mask;
+}
+
+/* Return 56 if TBI is enabled, 64 otherwise. */
+static int tlbbits_for_regime(CPUARMState *env, ARMMMUIdx mmu_idx,
+ uint64_t addr)
+{
+ uint64_t tcr = regime_tcr(env, mmu_idx);
+ int tbi = aa64_va_parameter_tbi(tcr, mmu_idx);
+ int select = extract64(addr, 55, 1);
+
+ return (tbi >> select) & 1 ? 56 : 64;
+}
+
+static int vae1_tlbbits(CPUARMState *env, uint64_t addr)
+{
+ uint64_t hcr = arm_hcr_el2_eff(env);
+ ARMMMUIdx mmu_idx;
+
+ assert(arm_feature(env, ARM_FEATURE_AARCH64));
+
+ /* Only the regime of the mmu_idx below is significant. */
+ if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
+ mmu_idx = ARMMMUIdx_E20_0;
+ } else {
+ mmu_idx = ARMMMUIdx_E10_0;
+ }
+
+ return tlbbits_for_regime(env, mmu_idx, addr);
+}
+
+static int vae2_tlbbits(CPUARMState *env, uint64_t addr)
+{
+ uint64_t hcr = arm_hcr_el2_eff(env);
+ ARMMMUIdx mmu_idx;
+
+ /*
+ * Only the regime of the mmu_idx below is significant.
+ * Regime EL2&0 has two ranges with separate TBI configuration, while EL2
+ * only has one.
+ */
+ if (hcr & HCR_E2H) {
+ mmu_idx = ARMMMUIdx_E20_2;
+ } else {
+ mmu_idx = ARMMMUIdx_E2;
+ }
+
+ return tlbbits_for_regime(env, mmu_idx, addr);
+}
+
+static void tlbi_aa64_vmalle1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+ int mask = vae1_tlbmask(env);
+
+ tlb_flush_by_mmuidx_all_cpus_synced(cs, mask);
+}
+
+static void tlbi_aa64_vmalle1_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+ int mask = vae1_tlbmask(env);
+
+ if (tlb_force_broadcast(env)) {
+ tlb_flush_by_mmuidx_all_cpus_synced(cs, mask);
+ } else {
+ tlb_flush_by_mmuidx(cs, mask);
+ }
+}
+
+static int e2_tlbmask(CPUARMState *env)
+{
+ return (ARMMMUIdxBit_E20_0 |
+ ARMMMUIdxBit_E20_2 |
+ ARMMMUIdxBit_E20_2_PAN |
+ ARMMMUIdxBit_E2);
+}
+
+static void tlbi_aa64_alle1_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+ int mask = alle1_tlbmask(env);
+
+ tlb_flush_by_mmuidx(cs, mask);
+}
+
+static void tlbi_aa64_alle2_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+ int mask = e2_tlbmask(env);
+
+ tlb_flush_by_mmuidx(cs, mask);
+}
+
+static void tlbi_aa64_alle3_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ ARMCPU *cpu = env_archcpu(env);
+ CPUState *cs = CPU(cpu);
+
+ tlb_flush_by_mmuidx(cs, ARMMMUIdxBit_E3);
+}
+
+static void tlbi_aa64_alle1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+ int mask = alle1_tlbmask(env);
+
+ tlb_flush_by_mmuidx_all_cpus_synced(cs, mask);
+}
+
+static void tlbi_aa64_alle2is_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+ int mask = e2_tlbmask(env);
+
+ tlb_flush_by_mmuidx_all_cpus_synced(cs, mask);
+}
+
+static void tlbi_aa64_alle3is_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+
+ tlb_flush_by_mmuidx_all_cpus_synced(cs, ARMMMUIdxBit_E3);
+}
+
+static void tlbi_aa64_vae2_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ /*
+ * Invalidate by VA, EL2
+ * Currently handles both VAE2 and VALE2, since we don't support
+ * flush-last-level-only.
+ */
+ CPUState *cs = env_cpu(env);
+ int mask = vae2_tlbmask(env);
+ uint64_t pageaddr = sextract64(value << 12, 0, 56);
+ int bits = vae2_tlbbits(env, pageaddr);
+
+ tlb_flush_page_bits_by_mmuidx(cs, pageaddr, mask, bits);
+}
+
+static void tlbi_aa64_vae3_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ /*
+ * Invalidate by VA, EL3
+ * Currently handles both VAE3 and VALE3, since we don't support
+ * flush-last-level-only.
+ */
+ ARMCPU *cpu = env_archcpu(env);
+ CPUState *cs = CPU(cpu);
+ uint64_t pageaddr = sextract64(value << 12, 0, 56);
+
+ tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_E3);
+}
+
+static void tlbi_aa64_vae1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+ int mask = vae1_tlbmask(env);
+ uint64_t pageaddr = sextract64(value << 12, 0, 56);
+ int bits = vae1_tlbbits(env, pageaddr);
+
+ tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits);
+}
+
+static void tlbi_aa64_vae1_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ /*
+ * Invalidate by VA, EL1&0 (AArch64 version).
+ * Currently handles all of VAE1, VAAE1, VAALE1 and VALE1,
+ * since we don't support flush-for-specific-ASID-only or
+ * flush-last-level-only.
+ */
+ CPUState *cs = env_cpu(env);
+ int mask = vae1_tlbmask(env);
+ uint64_t pageaddr = sextract64(value << 12, 0, 56);
+ int bits = vae1_tlbbits(env, pageaddr);
+
+ if (tlb_force_broadcast(env)) {
+ tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits);
+ } else {
+ tlb_flush_page_bits_by_mmuidx(cs, pageaddr, mask, bits);
+ }
+}
+
+static void tlbi_aa64_vae2is_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+ int mask = vae2_tlbmask(env);
+ uint64_t pageaddr = sextract64(value << 12, 0, 56);
+ int bits = vae2_tlbbits(env, pageaddr);
+
+ tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits);
+}
+
+static void tlbi_aa64_vae3is_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+ uint64_t pageaddr = sextract64(value << 12, 0, 56);
+ int bits = tlbbits_for_regime(env, ARMMMUIdx_E3, pageaddr);
+
+ tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr,
+ ARMMMUIdxBit_E3, bits);
+}
+
+static int ipas2e1_tlbmask(CPUARMState *env, int64_t value)
+{
+ /*
+ * The MSB of value is the NS field, which only applies if SEL2
+ * is implemented and SCR_EL3.NS is not set (i.e. in secure mode).
+ */
+ return (value >= 0
+ && cpu_isar_feature(aa64_sel2, env_archcpu(env))
+ && arm_is_secure_below_el3(env)
+ ? ARMMMUIdxBit_Stage2_S
+ : ARMMMUIdxBit_Stage2);
+}
+
+static void tlbi_aa64_ipas2e1_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+ int mask = ipas2e1_tlbmask(env, value);
+ uint64_t pageaddr = sextract64(value << 12, 0, 56);
+
+ if (tlb_force_broadcast(env)) {
+ tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, mask);
+ } else {
+ tlb_flush_page_by_mmuidx(cs, pageaddr, mask);
+ }
+}
+
+static void tlbi_aa64_ipas2e1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+ int mask = ipas2e1_tlbmask(env, value);
+ uint64_t pageaddr = sextract64(value << 12, 0, 56);
+
+ tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, mask);
+}
+
+static const ARMCPRegInfo tlbi_not_v7_cp_reginfo[] = {
+ /*
+ * MMU TLB control. Note that the wildcarding means we cover not just
+ * the unified TLB ops but also the dside/iside/inner-shareable variants.
+ */
+ { .name = "TLBIALL", .cp = 15, .crn = 8, .crm = CP_ANY,
+ .opc1 = CP_ANY, .opc2 = 0, .access = PL1_W, .writefn = tlbiall_write,
+ .type = ARM_CP_NO_RAW },
+ { .name = "TLBIMVA", .cp = 15, .crn = 8, .crm = CP_ANY,
+ .opc1 = CP_ANY, .opc2 = 1, .access = PL1_W, .writefn = tlbimva_write,
+ .type = ARM_CP_NO_RAW },
+ { .name = "TLBIASID", .cp = 15, .crn = 8, .crm = CP_ANY,
+ .opc1 = CP_ANY, .opc2 = 2, .access = PL1_W, .writefn = tlbiasid_write,
+ .type = ARM_CP_NO_RAW },
+ { .name = "TLBIMVAA", .cp = 15, .crn = 8, .crm = CP_ANY,
+ .opc1 = CP_ANY, .opc2 = 3, .access = PL1_W, .writefn = tlbimvaa_write,
+ .type = ARM_CP_NO_RAW },
+};
+
+static const ARMCPRegInfo tlbi_v7_cp_reginfo[] = {
+ /* 32 bit ITLB invalidates */
+ { .name = "ITLBIALL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 0,
+ .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
+ .writefn = tlbiall_write },
+ { .name = "ITLBIMVA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 1,
+ .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
+ .writefn = tlbimva_write },
+ { .name = "ITLBIASID", .cp = 15, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 2,
+ .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
+ .writefn = tlbiasid_write },
+ /* 32 bit DTLB invalidates */
+ { .name = "DTLBIALL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 0,
+ .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
+ .writefn = tlbiall_write },
+ { .name = "DTLBIMVA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 1,
+ .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
+ .writefn = tlbimva_write },
+ { .name = "DTLBIASID", .cp = 15, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 2,
+ .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
+ .writefn = tlbiasid_write },
+ /* 32 bit TLB invalidates */
+ { .name = "TLBIALL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 0,
+ .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
+ .writefn = tlbiall_write },
+ { .name = "TLBIMVA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 1,
+ .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
+ .writefn = tlbimva_write },
+ { .name = "TLBIASID", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 2,
+ .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
+ .writefn = tlbiasid_write },
+ { .name = "TLBIMVAA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 3,
+ .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
+ .writefn = tlbimvaa_write },
+};
+
+static const ARMCPRegInfo tlbi_v7mp_cp_reginfo[] = {
+ /* 32 bit TLB invalidates, Inner Shareable */
+ { .name = "TLBIALLIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0,
+ .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
+ .writefn = tlbiall_is_write },
+ { .name = "TLBIMVAIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 1,
+ .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
+ .writefn = tlbimva_is_write },
+ { .name = "TLBIASIDIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 2,
+ .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
+ .writefn = tlbiasid_is_write },
+ { .name = "TLBIMVAAIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 3,
+ .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
+ .writefn = tlbimvaa_is_write },
+};
+
+static const ARMCPRegInfo tlbi_v8_cp_reginfo[] = {
+ /* AArch32 TLB invalidate last level of translation table walk */
+ { .name = "TLBIMVALIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 5,
+ .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
+ .writefn = tlbimva_is_write },
+ { .name = "TLBIMVAALIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 7,
+ .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
+ .writefn = tlbimvaa_is_write },
+ { .name = "TLBIMVAL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 5,
+ .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
+ .writefn = tlbimva_write },
+ { .name = "TLBIMVAAL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 7,
+ .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
+ .writefn = tlbimvaa_write },
+ { .name = "TLBIMVALH", .cp = 15, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 5,
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
+ .writefn = tlbimva_hyp_write },
+ { .name = "TLBIMVALHIS",
+ .cp = 15, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 5,
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
+ .writefn = tlbimva_hyp_is_write },
+ { .name = "TLBIIPAS2",
+ .cp = 15, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 1,
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
+ .writefn = tlbiipas2_hyp_write },
+ { .name = "TLBIIPAS2IS",
+ .cp = 15, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 1,
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
+ .writefn = tlbiipas2is_hyp_write },
+ { .name = "TLBIIPAS2L",
+ .cp = 15, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 5,
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
+ .writefn = tlbiipas2_hyp_write },
+ { .name = "TLBIIPAS2LIS",
+ .cp = 15, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 5,
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
+ .writefn = tlbiipas2is_hyp_write },
+ /* AArch64 TLBI operations */
+ { .name = "TLBI_VMALLE1IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0,
+ .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIVMALLE1IS,
+ .writefn = tlbi_aa64_vmalle1is_write },
+ { .name = "TLBI_VAE1IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 1,
+ .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIVAE1IS,
+ .writefn = tlbi_aa64_vae1is_write },
+ { .name = "TLBI_ASIDE1IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 2,
+ .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIASIDE1IS,
+ .writefn = tlbi_aa64_vmalle1is_write },
+ { .name = "TLBI_VAAE1IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 3,
+ .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIVAAE1IS,
+ .writefn = tlbi_aa64_vae1is_write },
+ { .name = "TLBI_VALE1IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 5,
+ .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIVALE1IS,
+ .writefn = tlbi_aa64_vae1is_write },
+ { .name = "TLBI_VAALE1IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 7,
+ .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIVAALE1IS,
+ .writefn = tlbi_aa64_vae1is_write },
+ { .name = "TLBI_VMALLE1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 0,
+ .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIVMALLE1,
+ .writefn = tlbi_aa64_vmalle1_write },
+ { .name = "TLBI_VAE1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 1,
+ .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIVAE1,
+ .writefn = tlbi_aa64_vae1_write },
+ { .name = "TLBI_ASIDE1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 2,
+ .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIASIDE1,
+ .writefn = tlbi_aa64_vmalle1_write },
+ { .name = "TLBI_VAAE1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 3,
+ .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIVAAE1,
+ .writefn = tlbi_aa64_vae1_write },
+ { .name = "TLBI_VALE1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 5,
+ .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIVALE1,
+ .writefn = tlbi_aa64_vae1_write },
+ { .name = "TLBI_VAALE1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 7,
+ .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIVAALE1,
+ .writefn = tlbi_aa64_vae1_write },
+ { .name = "TLBI_IPAS2E1IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 1,
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_ipas2e1is_write },
+ { .name = "TLBI_IPAS2LE1IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 5,
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_ipas2e1is_write },
+ { .name = "TLBI_ALLE1IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 4,
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_alle1is_write },
+ { .name = "TLBI_VMALLS12E1IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 6,
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_alle1is_write },
+ { .name = "TLBI_IPAS2E1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 1,
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_ipas2e1_write },
+ { .name = "TLBI_IPAS2LE1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 5,
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_ipas2e1_write },
+ { .name = "TLBI_ALLE1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 4,
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_alle1_write },
+ { .name = "TLBI_VMALLS12E1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 6,
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_alle1is_write },
+};
+
+static const ARMCPRegInfo tlbi_el2_cp_reginfo[] = {
+ { .name = "TLBIALLNSNH",
+ .cp = 15, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 4,
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
+ .writefn = tlbiall_nsnh_write },
+ { .name = "TLBIALLNSNHIS",
+ .cp = 15, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 4,
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
+ .writefn = tlbiall_nsnh_is_write },
+ { .name = "TLBIALLH", .cp = 15, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 0,
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
+ .writefn = tlbiall_hyp_write },
+ { .name = "TLBIALLHIS", .cp = 15, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 0,
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
+ .writefn = tlbiall_hyp_is_write },
+ { .name = "TLBIMVAH", .cp = 15, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 1,
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
+ .writefn = tlbimva_hyp_write },
+ { .name = "TLBIMVAHIS", .cp = 15, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 1,
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
+ .writefn = tlbimva_hyp_is_write },
+ { .name = "TLBI_ALLE2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 0,
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
+ .writefn = tlbi_aa64_alle2_write },
+ { .name = "TLBI_VAE2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 1,
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
+ .writefn = tlbi_aa64_vae2_write },
+ { .name = "TLBI_VALE2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 5,
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
+ .writefn = tlbi_aa64_vae2_write },
+ { .name = "TLBI_ALLE2IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 0,
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
+ .writefn = tlbi_aa64_alle2is_write },
+ { .name = "TLBI_VAE2IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 1,
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
+ .writefn = tlbi_aa64_vae2is_write },
+ { .name = "TLBI_VALE2IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 5,
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
+ .writefn = tlbi_aa64_vae2is_write },
+};
+
+static const ARMCPRegInfo tlbi_el3_cp_reginfo[] = {
+ { .name = "TLBI_ALLE3IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 3, .opc2 = 0,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_alle3is_write },
+ { .name = "TLBI_VAE3IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 3, .opc2 = 1,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_vae3is_write },
+ { .name = "TLBI_VALE3IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 3, .opc2 = 5,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_vae3is_write },
+ { .name = "TLBI_ALLE3", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 7, .opc2 = 0,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_alle3_write },
+ { .name = "TLBI_VAE3", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 7, .opc2 = 1,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_vae3_write },
+ { .name = "TLBI_VALE3", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 7, .opc2 = 5,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_vae3_write },
+};
+
+#ifdef TARGET_AARCH64
+typedef struct {
+ uint64_t base;
+ uint64_t length;
+} TLBIRange;
+
+static ARMGranuleSize tlbi_range_tg_to_gran_size(int tg)
+{
+ /*
+ * Note that the TLBI range TG field encoding differs from both
+ * TG0 and TG1 encodings.
+ */
+ switch (tg) {
+ case 1:
+ return Gran4K;
+ case 2:
+ return Gran16K;
+ case 3:
+ return Gran64K;
+ default:
+ return GranInvalid;
+ }
+}
+
+static TLBIRange tlbi_aa64_get_range(CPUARMState *env, ARMMMUIdx mmuidx,
+ uint64_t value)
+{
+ unsigned int page_size_granule, page_shift, num, scale, exponent;
+ /* Extract one bit to represent the va selector in use. */
+ uint64_t select = sextract64(value, 36, 1);
+ ARMVAParameters param = aa64_va_parameters(env, select, mmuidx, true, false);
+ TLBIRange ret = { };
+ ARMGranuleSize gran;
+
+ page_size_granule = extract64(value, 46, 2);
+ gran = tlbi_range_tg_to_gran_size(page_size_granule);
+
+ /* The granule encoded in value must match the granule in use. */
+ if (gran != param.gran) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Invalid tlbi page size granule %d\n",
+ page_size_granule);
+ return ret;
+ }
+
+ page_shift = arm_granule_bits(gran);
+ num = extract64(value, 39, 5);
+ scale = extract64(value, 44, 2);
+ exponent = (5 * scale) + 1;
+
+ ret.length = (num + 1) << (exponent + page_shift);
+
+ if (param.select) {
+ ret.base = sextract64(value, 0, 37);
+ } else {
+ ret.base = extract64(value, 0, 37);
+ }
+ if (param.ds) {
+ /*
+ * With DS=1, BaseADDR is always shifted 16 so that it is able
+ * to address all 52 va bits. The input address is perforce
+ * aligned on a 64k boundary regardless of translation granule.
+ */
+ page_shift = 16;
+ }
+ ret.base <<= page_shift;
+
+ return ret;
+}
+
+static void do_rvae_write(CPUARMState *env, uint64_t value,
+ int idxmap, bool synced)
+{
+ ARMMMUIdx one_idx = ARM_MMU_IDX_A | ctz32(idxmap);
+ TLBIRange range;
+ int bits;
+
+ range = tlbi_aa64_get_range(env, one_idx, value);
+ bits = tlbbits_for_regime(env, one_idx, range.base);
+
+ if (synced) {
+ tlb_flush_range_by_mmuidx_all_cpus_synced(env_cpu(env),
+ range.base,
+ range.length,
+ idxmap,
+ bits);
+ } else {
+ tlb_flush_range_by_mmuidx(env_cpu(env), range.base,
+ range.length, idxmap, bits);
+ }
+}
+
+static void tlbi_aa64_rvae1_write(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ /*
+ * Invalidate by VA range, EL1&0.
+ * Currently handles all of RVAE1, RVAAE1, RVAALE1 and RVALE1,
+ * since we don't support flush-for-specific-ASID-only or
+ * flush-last-level-only.
+ */
+
+ do_rvae_write(env, value, vae1_tlbmask(env),
+ tlb_force_broadcast(env));
+}
+
+static void tlbi_aa64_rvae1is_write(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ /*
+ * Invalidate by VA range, Inner/Outer Shareable EL1&0.
+ * Currently handles all of RVAE1IS, RVAE1OS, RVAAE1IS, RVAAE1OS,
+ * RVAALE1IS, RVAALE1OS, RVALE1IS and RVALE1OS, since we don't support
+ * flush-for-specific-ASID-only, flush-last-level-only or inner/outer
+ * shareable specific flushes.
+ */
+
+ do_rvae_write(env, value, vae1_tlbmask(env), true);
+}
+
+static void tlbi_aa64_rvae2_write(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ /*
+ * Invalidate by VA range, EL2.
+ * Currently handles all of RVAE2 and RVALE2,
+ * since we don't support flush-for-specific-ASID-only or
+ * flush-last-level-only.
+ */
+
+ do_rvae_write(env, value, vae2_tlbmask(env),
+ tlb_force_broadcast(env));
+
+
+}
+
+static void tlbi_aa64_rvae2is_write(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ /*
+ * Invalidate by VA range, Inner/Outer Shareable, EL2.
+ * Currently handles all of RVAE2IS, RVAE2OS, RVALE2IS and RVALE2OS,
+ * since we don't support flush-for-specific-ASID-only,
+ * flush-last-level-only or inner/outer shareable specific flushes.
+ */
+
+ do_rvae_write(env, value, vae2_tlbmask(env), true);
+
+}
+
+static void tlbi_aa64_rvae3_write(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ /*
+ * Invalidate by VA range, EL3.
+ * Currently handles all of RVAE3 and RVALE3,
+ * since we don't support flush-for-specific-ASID-only or
+ * flush-last-level-only.
+ */
+
+ do_rvae_write(env, value, ARMMMUIdxBit_E3, tlb_force_broadcast(env));
+}
+
+static void tlbi_aa64_rvae3is_write(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ /*
+ * Invalidate by VA range, EL3, Inner/Outer Shareable.
+ * Currently handles all of RVAE3IS, RVAE3OS, RVALE3IS and RVALE3OS,
+ * since we don't support flush-for-specific-ASID-only,
+ * flush-last-level-only or inner/outer specific flushes.
+ */
+
+ do_rvae_write(env, value, ARMMMUIdxBit_E3, true);
+}
+
+static void tlbi_aa64_ripas2e1_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ do_rvae_write(env, value, ipas2e1_tlbmask(env, value),
+ tlb_force_broadcast(env));
+}
+
+static void tlbi_aa64_ripas2e1is_write(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ do_rvae_write(env, value, ipas2e1_tlbmask(env, value), true);
+}
+
+static const ARMCPRegInfo tlbirange_reginfo[] = {
+ { .name = "TLBI_RVAE1IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 1,
+ .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIRVAE1IS,
+ .writefn = tlbi_aa64_rvae1is_write },
+ { .name = "TLBI_RVAAE1IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 3,
+ .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIRVAAE1IS,
+ .writefn = tlbi_aa64_rvae1is_write },
+ { .name = "TLBI_RVALE1IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 5,
+ .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIRVALE1IS,
+ .writefn = tlbi_aa64_rvae1is_write },
+ { .name = "TLBI_RVAALE1IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 7,
+ .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIRVAALE1IS,
+ .writefn = tlbi_aa64_rvae1is_write },
+ { .name = "TLBI_RVAE1OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 1,
+ .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIRVAE1OS,
+ .writefn = tlbi_aa64_rvae1is_write },
+ { .name = "TLBI_RVAAE1OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 3,
+ .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIRVAAE1OS,
+ .writefn = tlbi_aa64_rvae1is_write },
+ { .name = "TLBI_RVALE1OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 5,
+ .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIRVALE1OS,
+ .writefn = tlbi_aa64_rvae1is_write },
+ { .name = "TLBI_RVAALE1OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 7,
+ .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIRVAALE1OS,
+ .writefn = tlbi_aa64_rvae1is_write },
+ { .name = "TLBI_RVAE1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 1,
+ .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIRVAE1,
+ .writefn = tlbi_aa64_rvae1_write },
+ { .name = "TLBI_RVAAE1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 3,
+ .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIRVAAE1,
+ .writefn = tlbi_aa64_rvae1_write },
+ { .name = "TLBI_RVALE1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 5,
+ .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIRVALE1,
+ .writefn = tlbi_aa64_rvae1_write },
+ { .name = "TLBI_RVAALE1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 7,
+ .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIRVAALE1,
+ .writefn = tlbi_aa64_rvae1_write },
+ { .name = "TLBI_RIPAS2E1IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 2,
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_ripas2e1is_write },
+ { .name = "TLBI_RIPAS2LE1IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 6,
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_ripas2e1is_write },
+ { .name = "TLBI_RVAE2IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 2, .opc2 = 1,
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
+ .writefn = tlbi_aa64_rvae2is_write },
+ { .name = "TLBI_RVALE2IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 2, .opc2 = 5,
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
+ .writefn = tlbi_aa64_rvae2is_write },
+ { .name = "TLBI_RIPAS2E1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 2,
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_ripas2e1_write },
+ { .name = "TLBI_RIPAS2LE1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 6,
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_ripas2e1_write },
+ { .name = "TLBI_RVAE2OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 5, .opc2 = 1,
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
+ .writefn = tlbi_aa64_rvae2is_write },
+ { .name = "TLBI_RVALE2OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 5, .opc2 = 5,
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
+ .writefn = tlbi_aa64_rvae2is_write },
+ { .name = "TLBI_RVAE2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 6, .opc2 = 1,
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
+ .writefn = tlbi_aa64_rvae2_write },
+ { .name = "TLBI_RVALE2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 6, .opc2 = 5,
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
+ .writefn = tlbi_aa64_rvae2_write },
+ { .name = "TLBI_RVAE3IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 2, .opc2 = 1,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_rvae3is_write },
+ { .name = "TLBI_RVALE3IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 2, .opc2 = 5,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_rvae3is_write },
+ { .name = "TLBI_RVAE3OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 5, .opc2 = 1,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_rvae3is_write },
+ { .name = "TLBI_RVALE3OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 5, .opc2 = 5,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_rvae3is_write },
+ { .name = "TLBI_RVAE3", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 6, .opc2 = 1,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_rvae3_write },
+ { .name = "TLBI_RVALE3", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 6, .opc2 = 5,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_rvae3_write },
+};
+
+static const ARMCPRegInfo tlbios_reginfo[] = {
+ { .name = "TLBI_VMALLE1OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 0,
+ .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIVMALLE1OS,
+ .writefn = tlbi_aa64_vmalle1is_write },
+ { .name = "TLBI_VAE1OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 1,
+ .fgt = FGT_TLBIVAE1OS,
+ .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_vae1is_write },
+ { .name = "TLBI_ASIDE1OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 2,
+ .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIASIDE1OS,
+ .writefn = tlbi_aa64_vmalle1is_write },
+ { .name = "TLBI_VAAE1OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 3,
+ .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIVAAE1OS,
+ .writefn = tlbi_aa64_vae1is_write },
+ { .name = "TLBI_VALE1OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 5,
+ .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIVALE1OS,
+ .writefn = tlbi_aa64_vae1is_write },
+ { .name = "TLBI_VAALE1OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 7,
+ .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW,
+ .fgt = FGT_TLBIVAALE1OS,
+ .writefn = tlbi_aa64_vae1is_write },
+ { .name = "TLBI_ALLE2OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 0,
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
+ .writefn = tlbi_aa64_alle2is_write },
+ { .name = "TLBI_VAE2OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 1,
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
+ .writefn = tlbi_aa64_vae2is_write },
+ { .name = "TLBI_ALLE1OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 4,
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_alle1is_write },
+ { .name = "TLBI_VALE2OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 5,
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
+ .writefn = tlbi_aa64_vae2is_write },
+ { .name = "TLBI_VMALLS12E1OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 6,
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_alle1is_write },
+ { .name = "TLBI_IPAS2E1OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 0,
+ .access = PL2_W, .type = ARM_CP_NOP },
+ { .name = "TLBI_RIPAS2E1OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 3,
+ .access = PL2_W, .type = ARM_CP_NOP },
+ { .name = "TLBI_IPAS2LE1OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 4,
+ .access = PL2_W, .type = ARM_CP_NOP },
+ { .name = "TLBI_RIPAS2LE1OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 7,
+ .access = PL2_W, .type = ARM_CP_NOP },
+ { .name = "TLBI_ALLE3OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 1, .opc2 = 0,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_alle3is_write },
+ { .name = "TLBI_VAE3OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 1, .opc2 = 1,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_vae3is_write },
+ { .name = "TLBI_VALE3OS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 1, .opc2 = 5,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_vae3is_write },
+};
+
+static void tlbi_aa64_paall_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+
+ tlb_flush(cs);
+}
+
+static void tlbi_aa64_paallos_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ CPUState *cs = env_cpu(env);
+
+ tlb_flush_all_cpus_synced(cs);
+}
+
+static const ARMCPRegInfo tlbi_rme_reginfo[] = {
+ { .name = "TLBI_PAALL", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 7, .opc2 = 4,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_paall_write },
+ { .name = "TLBI_PAALLOS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 1, .opc2 = 4,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_paallos_write },
+ /*
+ * QEMU does not have a way to invalidate by physical address, thus
+ * invalidating a range of physical addresses is accomplished by
+ * flushing all tlb entries in the outer shareable domain,
+ * just like PAALLOS.
+ */
+ { .name = "TLBI_RPALOS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 4, .opc2 = 7,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_paallos_write },
+ { .name = "TLBI_RPAOS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 4, .opc2 = 3,
+ .access = PL3_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbi_aa64_paallos_write },
+};
+
+#endif
+
+void define_tlb_insn_regs(ARMCPU *cpu)
+{
+ CPUARMState *env = &cpu->env;
+
+ if (!arm_feature(env, ARM_FEATURE_V7)) {
+ define_arm_cp_regs(cpu, tlbi_not_v7_cp_reginfo);
+ } else {
+ define_arm_cp_regs(cpu, tlbi_v7_cp_reginfo);
+ }
+ if (arm_feature(env, ARM_FEATURE_V7MP) &&
+ !arm_feature(env, ARM_FEATURE_PMSA)) {
+ define_arm_cp_regs(cpu, tlbi_v7mp_cp_reginfo);
+ }
+ if (arm_feature(env, ARM_FEATURE_V8)) {
+ define_arm_cp_regs(cpu, tlbi_v8_cp_reginfo);
+ }
+ /*
+ * We retain the existing logic for when to register these TLBI
+ * ops (i.e. matching the condition for el2_cp_reginfo[] in
+ * helper.c), but we will be able to simplify this later.
+ */
+ if (arm_feature(env, ARM_FEATURE_EL2)) {
+ define_arm_cp_regs(cpu, tlbi_el2_cp_reginfo);
+ }
+ if (arm_feature(env, ARM_FEATURE_EL3)) {
+ define_arm_cp_regs(cpu, tlbi_el3_cp_reginfo);
+ }
+#ifdef TARGET_AARCH64
+ if (cpu_isar_feature(aa64_tlbirange, cpu)) {
+ define_arm_cp_regs(cpu, tlbirange_reginfo);
+ }
+ if (cpu_isar_feature(aa64_tlbios, cpu)) {
+ define_arm_cp_regs(cpu, tlbios_reginfo);
+ }
+ if (cpu_isar_feature(aa64_rme, cpu)) {
+ define_arm_cp_regs(cpu, tlbi_rme_reginfo);
+ }
+#endif
+}
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index b2851ea..3e57b98 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -628,7 +628,16 @@ static TCGv_i32 read_fp_hreg(DisasContext *s, int reg)
return v;
}
-/* Clear the bits above an N-bit vector, for N = (is_q ? 128 : 64).
+static void clear_vec(DisasContext *s, int rd)
+{
+ unsigned ofs = fp_reg_offset(s, rd, MO_64);
+ unsigned vsz = vec_full_reg_size(s);
+
+ tcg_gen_gvec_dup_imm(MO_64, ofs, vsz, vsz, 0);
+}
+
+/*
+ * Clear the bits above an N-bit vector, for N = (is_q ? 128 : 64).
* If SVE is not enabled, then there are only 128 bits in the vector.
*/
static void clear_vec_high(DisasContext *s, bool is_q, int rd)
@@ -1240,6 +1249,49 @@ static bool fp_access_check(DisasContext *s)
}
/*
+ * Return <0 for non-supported element sizes, with MO_16 controlled by
+ * FEAT_FP16; return 0 for fp disabled; otherwise return >0 for success.
+ */
+static int fp_access_check_scalar_hsd(DisasContext *s, MemOp esz)
+{
+ switch (esz) {
+ case MO_64:
+ case MO_32:
+ break;
+ case MO_16:
+ if (!dc_isar_feature(aa64_fp16, s)) {
+ return -1;
+ }
+ break;
+ default:
+ return -1;
+ }
+ return fp_access_check(s);
+}
+
+/* Likewise, but vector MO_64 must have two elements. */
+static int fp_access_check_vector_hsd(DisasContext *s, bool is_q, MemOp esz)
+{
+ switch (esz) {
+ case MO_64:
+ if (!is_q) {
+ return -1;
+ }
+ break;
+ case MO_32:
+ break;
+ case MO_16:
+ if (!dc_isar_feature(aa64_fp16, s)) {
+ return -1;
+ }
+ break;
+ default:
+ return -1;
+ }
+ return fp_access_check(s);
+}
+
+/*
* Check that SVE access is enabled. If it is, return true.
* If not, emit code to generate an appropriate exception and return false.
* This function corresponds to CheckSVEEnabled().
@@ -1414,31 +1466,6 @@ static inline void gen_check_sp_alignment(DisasContext *s)
}
/*
- * This provides a simple table based table lookup decoder. It is
- * intended to be used when the relevant bits for decode are too
- * awkwardly placed and switch/if based logic would be confusing and
- * deeply nested. Since it's a linear search through the table, tables
- * should be kept small.
- *
- * It returns the first handler where insn & mask == pattern, or
- * NULL if there is no match.
- * The table is terminated by an empty mask (i.e. 0)
- */
-static inline AArch64DecodeFn *lookup_disas_fn(const AArch64DecodeTable *table,
- uint32_t insn)
-{
- const AArch64DecodeTable *tptr = table;
-
- while (tptr->mask) {
- if ((insn & tptr->mask) == tptr->pattern) {
- return tptr->disas_fn;
- }
- tptr++;
- }
- return NULL;
-}
-
-/*
* The instruction disassembly implemented here matches
* the instruction encoding classifications in chapter C4
* of the ARM Architecture Reference Manual (DDI0487B_a);
@@ -4808,7 +4835,6 @@ static bool trans_SM3SS1(DisasContext *s, arg_SM3SS1 *a)
TCGv_i32 tcg_op2 = tcg_temp_new_i32();
TCGv_i32 tcg_op3 = tcg_temp_new_i32();
TCGv_i32 tcg_res = tcg_temp_new_i32();
- unsigned vsz, dofs;
read_vec_element_i32(s, tcg_op1, a->rn, 3, MO_32);
read_vec_element_i32(s, tcg_op2, a->rm, 3, MO_32);
@@ -4820,9 +4846,7 @@ static bool trans_SM3SS1(DisasContext *s, arg_SM3SS1 *a)
tcg_gen_rotri_i32(tcg_res, tcg_res, 25);
/* Clear the whole register first, then store bits [127:96]. */
- vsz = vec_full_reg_size(s);
- dofs = vec_full_reg_offset(s, a->rd);
- tcg_gen_gvec_dup_imm(MO_64, dofs, vsz, vsz, 0);
+ clear_vec(s, a->rd);
write_vec_element_i32(s, tcg_res, a->rd, 3, MO_32);
}
return true;
@@ -5201,6 +5225,61 @@ static const FPScalar f_scalar_frsqrts = {
};
TRANS(FRSQRTS_s, do_fp3_scalar, a, &f_scalar_frsqrts)
+static bool do_fcmp0_s(DisasContext *s, arg_rr_e *a,
+ const FPScalar *f, bool swap)
+{
+ switch (a->esz) {
+ case MO_64:
+ if (fp_access_check(s)) {
+ TCGv_i64 t0 = read_fp_dreg(s, a->rn);
+ TCGv_i64 t1 = tcg_constant_i64(0);
+ if (swap) {
+ f->gen_d(t0, t1, t0, fpstatus_ptr(FPST_FPCR));
+ } else {
+ f->gen_d(t0, t0, t1, fpstatus_ptr(FPST_FPCR));
+ }
+ write_fp_dreg(s, a->rd, t0);
+ }
+ break;
+ case MO_32:
+ if (fp_access_check(s)) {
+ TCGv_i32 t0 = read_fp_sreg(s, a->rn);
+ TCGv_i32 t1 = tcg_constant_i32(0);
+ if (swap) {
+ f->gen_s(t0, t1, t0, fpstatus_ptr(FPST_FPCR));
+ } else {
+ f->gen_s(t0, t0, t1, fpstatus_ptr(FPST_FPCR));
+ }
+ write_fp_sreg(s, a->rd, t0);
+ }
+ break;
+ case MO_16:
+ if (!dc_isar_feature(aa64_fp16, s)) {
+ return false;
+ }
+ if (fp_access_check(s)) {
+ TCGv_i32 t0 = read_fp_hreg(s, a->rn);
+ TCGv_i32 t1 = tcg_constant_i32(0);
+ if (swap) {
+ f->gen_h(t0, t1, t0, fpstatus_ptr(FPST_FPCR_F16));
+ } else {
+ f->gen_h(t0, t0, t1, fpstatus_ptr(FPST_FPCR_F16));
+ }
+ write_fp_sreg(s, a->rd, t0);
+ }
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+TRANS(FCMEQ0_s, do_fcmp0_s, a, &f_scalar_fcmeq, false)
+TRANS(FCMGT0_s, do_fcmp0_s, a, &f_scalar_fcmgt, false)
+TRANS(FCMGE0_s, do_fcmp0_s, a, &f_scalar_fcmge, false)
+TRANS(FCMLT0_s, do_fcmp0_s, a, &f_scalar_fcmgt, true)
+TRANS(FCMLE0_s, do_fcmp0_s, a, &f_scalar_fcmge, true)
+
static bool do_satacc_s(DisasContext *s, arg_rrr_e *a,
MemOp sgn_n, MemOp sgn_m,
void (*gen_bhs)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64, MemOp),
@@ -5399,27 +5478,14 @@ static bool do_fp3_vector(DisasContext *s, arg_qrrr_e *a, int data,
gen_helper_gvec_3_ptr * const fns[3])
{
MemOp esz = a->esz;
+ int check = fp_access_check_vector_hsd(s, a->q, esz);
- switch (esz) {
- case MO_64:
- if (!a->q) {
- return false;
- }
- break;
- case MO_32:
- break;
- case MO_16:
- if (!dc_isar_feature(aa64_fp16, s)) {
- return false;
- }
- break;
- default:
- return false;
- }
- if (fp_access_check(s)) {
- gen_gvec_op3_fpst(s, a->q, a->rd, a->rn, a->rm,
- esz == MO_16, data, fns[esz - 1]);
+ if (check <= 0) {
+ return check == 0;
}
+
+ gen_gvec_op3_fpst(s, a->q, a->rd, a->rn, a->rm,
+ esz == MO_16, data, fns[esz - 1]);
return true;
}
@@ -5747,34 +5813,24 @@ TRANS_FEAT(FCADD_270, aa64_fcma, do_fp3_vector, a, 1, f_vector_fcadd)
static bool trans_FCMLA_v(DisasContext *s, arg_FCMLA_v *a)
{
- gen_helper_gvec_4_ptr *fn;
+ static gen_helper_gvec_4_ptr * const fn[] = {
+ [MO_16] = gen_helper_gvec_fcmlah,
+ [MO_32] = gen_helper_gvec_fcmlas,
+ [MO_64] = gen_helper_gvec_fcmlad,
+ };
+ int check;
if (!dc_isar_feature(aa64_fcma, s)) {
return false;
}
- switch (a->esz) {
- case MO_64:
- if (!a->q) {
- return false;
- }
- fn = gen_helper_gvec_fcmlad;
- break;
- case MO_32:
- fn = gen_helper_gvec_fcmlas;
- break;
- case MO_16:
- if (!dc_isar_feature(aa64_fp16, s)) {
- return false;
- }
- fn = gen_helper_gvec_fcmlah;
- break;
- default:
- return false;
- }
- if (fp_access_check(s)) {
- gen_gvec_op4_fpst(s, a->q, a->rd, a->rn, a->rm, a->rd,
- a->esz == MO_16, a->rot, fn);
+
+ check = fp_access_check_vector_hsd(s, a->q, a->esz);
+ if (check <= 0) {
+ return check == 0;
}
+
+ gen_gvec_op4_fpst(s, a->q, a->rd, a->rn, a->rm, a->rd,
+ a->esz == MO_16, a->rot, fn[a->esz]);
return true;
}
@@ -6287,7 +6343,6 @@ static bool do_scalar_muladd_widening_idx(DisasContext *s, arg_rrx_e *a,
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 t2 = tcg_temp_new_i64();
- unsigned vsz, dofs;
if (acc) {
read_vec_element(s, t0, a->rd, 0, a->esz + 1);
@@ -6297,9 +6352,7 @@ static bool do_scalar_muladd_widening_idx(DisasContext *s, arg_rrx_e *a,
fn(t0, t1, t2);
/* Clear the whole register first, then store scalar. */
- vsz = vec_full_reg_size(s);
- dofs = vec_full_reg_offset(s, a->rd);
- tcg_gen_gvec_dup_imm(MO_64, dofs, vsz, vsz, 0);
+ clear_vec(s, a->rd);
write_vec_element(s, t0, a->rd, 0, a->esz + 1);
}
return true;
@@ -6316,27 +6369,14 @@ static bool do_fp3_vector_idx(DisasContext *s, arg_qrrx_e *a,
gen_helper_gvec_3_ptr * const fns[3])
{
MemOp esz = a->esz;
+ int check = fp_access_check_vector_hsd(s, a->q, esz);
- switch (esz) {
- case MO_64:
- if (!a->q) {
- return false;
- }
- break;
- case MO_32:
- break;
- case MO_16:
- if (!dc_isar_feature(aa64_fp16, s)) {
- return false;
- }
- break;
- default:
- g_assert_not_reached();
- }
- if (fp_access_check(s)) {
- gen_gvec_op3_fpst(s, a->q, a->rd, a->rn, a->rm,
- esz == MO_16, a->idx, fns[esz - 1]);
+ if (check <= 0) {
+ return check == 0;
}
+
+ gen_gvec_op3_fpst(s, a->q, a->rd, a->rn, a->rm,
+ esz == MO_16, a->idx, fns[esz - 1]);
return true;
}
@@ -6362,28 +6402,15 @@ static bool do_fmla_vector_idx(DisasContext *s, arg_qrrx_e *a, bool neg)
gen_helper_gvec_fmla_idx_d,
};
MemOp esz = a->esz;
+ int check = fp_access_check_vector_hsd(s, a->q, esz);
- switch (esz) {
- case MO_64:
- if (!a->q) {
- return false;
- }
- break;
- case MO_32:
- break;
- case MO_16:
- if (!dc_isar_feature(aa64_fp16, s)) {
- return false;
- }
- break;
- default:
- g_assert_not_reached();
- }
- if (fp_access_check(s)) {
- gen_gvec_op4_fpst(s, a->q, a->rd, a->rn, a->rm, a->rd,
- esz == MO_16, (a->idx << 1) | neg,
- fns[esz - 1]);
+ if (check <= 0) {
+ return check == 0;
}
+
+ gen_gvec_op4_fpst(s, a->q, a->rd, a->rn, a->rm, a->rd,
+ esz == MO_16, (a->idx << 1) | neg,
+ fns[esz - 1]);
return true;
}
@@ -6628,22 +6655,10 @@ static bool trans_FCSEL(DisasContext *s, arg_FCSEL *a)
{
TCGv_i64 t_true, t_false;
DisasCompare64 c;
+ int check = fp_access_check_scalar_hsd(s, a->esz);
- switch (a->esz) {
- case MO_32:
- case MO_64:
- break;
- case MO_16:
- if (!dc_isar_feature(aa64_fp16, s)) {
- return false;
- }
- break;
- default:
- return false;
- }
-
- if (!fp_access_check(s)) {
- return true;
+ if (check <= 0) {
+ return check == 0;
}
/* Zero extend sreg & hreg inputs to 64 bits now. */
@@ -6894,21 +6909,114 @@ TRANS(FMINV_s, do_fp_reduction, a, gen_helper_vfp_mins)
static bool trans_FMOVI_s(DisasContext *s, arg_FMOVI_s *a)
{
- switch (a->esz) {
- case MO_32:
- case MO_64:
- break;
- case MO_16:
- if (!dc_isar_feature(aa64_fp16, s)) {
- return false;
+ int check = fp_access_check_scalar_hsd(s, a->esz);
+ uint64_t imm;
+
+ if (check <= 0) {
+ return check == 0;
+ }
+
+ imm = vfp_expand_imm(a->esz, a->imm);
+ write_fp_dreg(s, a->rd, tcg_constant_i64(imm));
+ return true;
+}
+
+/*
+ * Floating point compare, conditional compare
+ */
+
+static void handle_fp_compare(DisasContext *s, int size,
+ unsigned int rn, unsigned int rm,
+ bool cmp_with_zero, bool signal_all_nans)
+{
+ TCGv_i64 tcg_flags = tcg_temp_new_i64();
+ TCGv_ptr fpst = fpstatus_ptr(size == MO_16 ? FPST_FPCR_F16 : FPST_FPCR);
+
+ if (size == MO_64) {
+ TCGv_i64 tcg_vn, tcg_vm;
+
+ tcg_vn = read_fp_dreg(s, rn);
+ if (cmp_with_zero) {
+ tcg_vm = tcg_constant_i64(0);
+ } else {
+ tcg_vm = read_fp_dreg(s, rm);
+ }
+ if (signal_all_nans) {
+ gen_helper_vfp_cmped_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
+ } else {
+ gen_helper_vfp_cmpd_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
+ }
+ } else {
+ TCGv_i32 tcg_vn = tcg_temp_new_i32();
+ TCGv_i32 tcg_vm = tcg_temp_new_i32();
+
+ read_vec_element_i32(s, tcg_vn, rn, 0, size);
+ if (cmp_with_zero) {
+ tcg_gen_movi_i32(tcg_vm, 0);
+ } else {
+ read_vec_element_i32(s, tcg_vm, rm, 0, size);
+ }
+
+ switch (size) {
+ case MO_32:
+ if (signal_all_nans) {
+ gen_helper_vfp_cmpes_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
+ } else {
+ gen_helper_vfp_cmps_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
+ }
+ break;
+ case MO_16:
+ if (signal_all_nans) {
+ gen_helper_vfp_cmpeh_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
+ } else {
+ gen_helper_vfp_cmph_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
+ }
+ break;
+ default:
+ g_assert_not_reached();
}
- break;
- default:
- return false;
}
- if (fp_access_check(s)) {
- uint64_t imm = vfp_expand_imm(a->esz, a->imm);
- write_fp_dreg(s, a->rd, tcg_constant_i64(imm));
+
+ gen_set_nzcv(tcg_flags);
+}
+
+/* FCMP, FCMPE */
+static bool trans_FCMP(DisasContext *s, arg_FCMP *a)
+{
+ int check = fp_access_check_scalar_hsd(s, a->esz);
+
+ if (check <= 0) {
+ return check == 0;
+ }
+
+ handle_fp_compare(s, a->esz, a->rn, a->rm, a->z, a->e);
+ return true;
+}
+
+/* FCCMP, FCCMPE */
+static bool trans_FCCMP(DisasContext *s, arg_FCCMP *a)
+{
+ TCGLabel *label_continue = NULL;
+ int check = fp_access_check_scalar_hsd(s, a->esz);
+
+ if (check <= 0) {
+ return check == 0;
+ }
+
+ if (a->cond < 0x0e) { /* not always */
+ TCGLabel *label_match = gen_new_label();
+ label_continue = gen_new_label();
+ arm_gen_test_cc(a->cond, label_match);
+ /* nomatch: */
+ gen_set_nzcv(tcg_constant_i64(a->nzcv << 28));
+ tcg_gen_br(label_continue);
+ gen_set_label(label_match);
+ }
+
+ handle_fp_compare(s, a->esz, a->rn, a->rm, false, a->e);
+
+ if (label_continue) {
+ gen_set_label(label_continue);
}
return true;
}
@@ -7485,6 +7593,36 @@ TRANS(UQRSHRN_si, do_scalar_shift_imm_narrow, a, uqrshrn_fns, 0, false)
TRANS(SQSHRUN_si, do_scalar_shift_imm_narrow, a, sqshrun_fns, MO_SIGN, false)
TRANS(SQRSHRUN_si, do_scalar_shift_imm_narrow, a, sqrshrun_fns, MO_SIGN, false)
+static bool do_div(DisasContext *s, arg_rrr_sf *a, bool is_signed)
+{
+ TCGv_i64 tcg_n, tcg_m, tcg_rd;
+ tcg_rd = cpu_reg(s, a->rd);
+
+ if (!a->sf && is_signed) {
+ tcg_n = tcg_temp_new_i64();
+ tcg_m = tcg_temp_new_i64();
+ tcg_gen_ext32s_i64(tcg_n, cpu_reg(s, a->rn));
+ tcg_gen_ext32s_i64(tcg_m, cpu_reg(s, a->rm));
+ } else {
+ tcg_n = read_cpu_reg(s, a->rn, a->sf);
+ tcg_m = read_cpu_reg(s, a->rm, a->sf);
+ }
+
+ if (is_signed) {
+ gen_helper_sdiv64(tcg_rd, tcg_n, tcg_m);
+ } else {
+ gen_helper_udiv64(tcg_rd, tcg_n, tcg_m);
+ }
+
+ if (!a->sf) { /* zero extend final result */
+ tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
+ }
+ return true;
+}
+
+TRANS(SDIV, do_div, a, true)
+TRANS(UDIV, do_div, a, false)
+
/* Shift a TCGv src by TCGv shift_amount, put result in dst.
* Note that it is the caller's responsibility to ensure that the
* shift amount is in range (ie 0..31 or 0..63) and provide the ARM
@@ -7545,147 +7683,316 @@ static void shift_reg_imm(TCGv_i64 dst, TCGv_i64 src, int sf,
}
}
-/* Logical (shifted register)
- * 31 30 29 28 24 23 22 21 20 16 15 10 9 5 4 0
- * +----+-----+-----------+-------+---+------+--------+------+------+
- * | sf | opc | 0 1 0 1 0 | shift | N | Rm | imm6 | Rn | Rd |
- * +----+-----+-----------+-------+---+------+--------+------+------+
- */
-static void disas_logic_reg(DisasContext *s, uint32_t insn)
+static bool do_shift_reg(DisasContext *s, arg_rrr_sf *a,
+ enum a64_shift_type shift_type)
{
- TCGv_i64 tcg_rd, tcg_rn, tcg_rm;
- unsigned int sf, opc, shift_type, invert, rm, shift_amount, rn, rd;
-
- sf = extract32(insn, 31, 1);
- opc = extract32(insn, 29, 2);
- shift_type = extract32(insn, 22, 2);
- invert = extract32(insn, 21, 1);
- rm = extract32(insn, 16, 5);
- shift_amount = extract32(insn, 10, 6);
- rn = extract32(insn, 5, 5);
- rd = extract32(insn, 0, 5);
-
- if (!sf && (shift_amount & (1 << 5))) {
- unallocated_encoding(s);
- return;
+ TCGv_i64 tcg_shift = tcg_temp_new_i64();
+ TCGv_i64 tcg_rd = cpu_reg(s, a->rd);
+ TCGv_i64 tcg_rn = read_cpu_reg(s, a->rn, a->sf);
+
+ tcg_gen_andi_i64(tcg_shift, cpu_reg(s, a->rm), a->sf ? 63 : 31);
+ shift_reg(tcg_rd, tcg_rn, a->sf, shift_type, tcg_shift);
+ return true;
+}
+
+TRANS(LSLV, do_shift_reg, a, A64_SHIFT_TYPE_LSL)
+TRANS(LSRV, do_shift_reg, a, A64_SHIFT_TYPE_LSR)
+TRANS(ASRV, do_shift_reg, a, A64_SHIFT_TYPE_ASR)
+TRANS(RORV, do_shift_reg, a, A64_SHIFT_TYPE_ROR)
+
+static bool do_crc32(DisasContext *s, arg_rrr_e *a, bool crc32c)
+{
+ TCGv_i64 tcg_acc, tcg_val, tcg_rd;
+ TCGv_i32 tcg_bytes;
+
+ switch (a->esz) {
+ case MO_8:
+ case MO_16:
+ case MO_32:
+ tcg_val = tcg_temp_new_i64();
+ tcg_gen_extract_i64(tcg_val, cpu_reg(s, a->rm), 0, 8 << a->esz);
+ break;
+ case MO_64:
+ tcg_val = cpu_reg(s, a->rm);
+ break;
+ default:
+ g_assert_not_reached();
}
+ tcg_acc = cpu_reg(s, a->rn);
+ tcg_bytes = tcg_constant_i32(1 << a->esz);
+ tcg_rd = cpu_reg(s, a->rd);
- tcg_rd = cpu_reg(s, rd);
+ if (crc32c) {
+ gen_helper_crc32c_64(tcg_rd, tcg_acc, tcg_val, tcg_bytes);
+ } else {
+ gen_helper_crc32_64(tcg_rd, tcg_acc, tcg_val, tcg_bytes);
+ }
+ return true;
+}
- if (opc == 1 && shift_amount == 0 && shift_type == 0 && rn == 31) {
- /* Unshifted ORR and ORN with WZR/XZR is the standard encoding for
- * register-register MOV and MVN, so it is worth special casing.
- */
- tcg_rm = cpu_reg(s, rm);
- if (invert) {
- tcg_gen_not_i64(tcg_rd, tcg_rm);
- if (!sf) {
- tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
- }
+TRANS_FEAT(CRC32, aa64_crc32, do_crc32, a, false)
+TRANS_FEAT(CRC32C, aa64_crc32, do_crc32, a, true)
+
+static bool do_subp(DisasContext *s, arg_rrr *a, bool setflag)
+{
+ TCGv_i64 tcg_n = read_cpu_reg_sp(s, a->rn, true);
+ TCGv_i64 tcg_m = read_cpu_reg_sp(s, a->rm, true);
+ TCGv_i64 tcg_d = cpu_reg(s, a->rd);
+
+ tcg_gen_sextract_i64(tcg_n, tcg_n, 0, 56);
+ tcg_gen_sextract_i64(tcg_m, tcg_m, 0, 56);
+
+ if (setflag) {
+ gen_sub_CC(true, tcg_d, tcg_n, tcg_m);
+ } else {
+ tcg_gen_sub_i64(tcg_d, tcg_n, tcg_m);
+ }
+ return true;
+}
+
+TRANS_FEAT(SUBP, aa64_mte_insn_reg, do_subp, a, false)
+TRANS_FEAT(SUBPS, aa64_mte_insn_reg, do_subp, a, true)
+
+static bool trans_IRG(DisasContext *s, arg_rrr *a)
+{
+ if (dc_isar_feature(aa64_mte_insn_reg, s)) {
+ TCGv_i64 tcg_rd = cpu_reg_sp(s, a->rd);
+ TCGv_i64 tcg_rn = cpu_reg_sp(s, a->rn);
+
+ if (s->ata[0]) {
+ gen_helper_irg(tcg_rd, tcg_env, tcg_rn, cpu_reg(s, a->rm));
} else {
- if (sf) {
- tcg_gen_mov_i64(tcg_rd, tcg_rm);
- } else {
- tcg_gen_ext32u_i64(tcg_rd, tcg_rm);
- }
+ gen_address_with_allocation_tag0(tcg_rd, tcg_rn);
}
- return;
+ return true;
}
+ return false;
+}
- tcg_rm = read_cpu_reg(s, rm, sf);
+static bool trans_GMI(DisasContext *s, arg_rrr *a)
+{
+ if (dc_isar_feature(aa64_mte_insn_reg, s)) {
+ TCGv_i64 t = tcg_temp_new_i64();
- if (shift_amount) {
- shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, shift_amount);
+ tcg_gen_extract_i64(t, cpu_reg_sp(s, a->rn), 56, 4);
+ tcg_gen_shl_i64(t, tcg_constant_i64(1), t);
+ tcg_gen_or_i64(cpu_reg(s, a->rd), cpu_reg(s, a->rm), t);
+ return true;
}
+ return false;
+}
- tcg_rn = cpu_reg(s, rn);
+static bool trans_PACGA(DisasContext *s, arg_rrr *a)
+{
+ if (dc_isar_feature(aa64_pauth, s)) {
+ gen_helper_pacga(cpu_reg(s, a->rd), tcg_env,
+ cpu_reg(s, a->rn), cpu_reg_sp(s, a->rm));
+ return true;
+ }
+ return false;
+}
- switch (opc | (invert << 2)) {
- case 0: /* AND */
- case 3: /* ANDS */
- tcg_gen_and_i64(tcg_rd, tcg_rn, tcg_rm);
- break;
- case 1: /* ORR */
- tcg_gen_or_i64(tcg_rd, tcg_rn, tcg_rm);
- break;
- case 2: /* EOR */
- tcg_gen_xor_i64(tcg_rd, tcg_rn, tcg_rm);
- break;
- case 4: /* BIC */
- case 7: /* BICS */
- tcg_gen_andc_i64(tcg_rd, tcg_rn, tcg_rm);
- break;
- case 5: /* ORN */
- tcg_gen_orc_i64(tcg_rd, tcg_rn, tcg_rm);
- break;
- case 6: /* EON */
- tcg_gen_eqv_i64(tcg_rd, tcg_rn, tcg_rm);
- break;
- default:
- assert(FALSE);
- break;
+typedef void ArithOneOp(TCGv_i64, TCGv_i64);
+
+static bool gen_rr(DisasContext *s, int rd, int rn, ArithOneOp fn)
+{
+ fn(cpu_reg(s, rd), cpu_reg(s, rn));
+ return true;
+}
+
+static void gen_rbit32(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn)
+{
+ TCGv_i32 t32 = tcg_temp_new_i32();
+
+ tcg_gen_extrl_i64_i32(t32, tcg_rn);
+ gen_helper_rbit(t32, t32);
+ tcg_gen_extu_i32_i64(tcg_rd, t32);
+}
+
+static void gen_rev16_xx(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn, TCGv_i64 mask)
+{
+ TCGv_i64 tcg_tmp = tcg_temp_new_i64();
+
+ tcg_gen_shri_i64(tcg_tmp, tcg_rn, 8);
+ tcg_gen_and_i64(tcg_rd, tcg_rn, mask);
+ tcg_gen_and_i64(tcg_tmp, tcg_tmp, mask);
+ tcg_gen_shli_i64(tcg_rd, tcg_rd, 8);
+ tcg_gen_or_i64(tcg_rd, tcg_rd, tcg_tmp);
+}
+
+static void gen_rev16_32(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn)
+{
+ gen_rev16_xx(tcg_rd, tcg_rn, tcg_constant_i64(0x00ff00ff));
+}
+
+static void gen_rev16_64(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn)
+{
+ gen_rev16_xx(tcg_rd, tcg_rn, tcg_constant_i64(0x00ff00ff00ff00ffull));
+}
+
+static void gen_rev_32(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn)
+{
+ tcg_gen_bswap32_i64(tcg_rd, tcg_rn, TCG_BSWAP_OZ);
+}
+
+static void gen_rev32(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn)
+{
+ tcg_gen_bswap64_i64(tcg_rd, tcg_rn);
+ tcg_gen_rotri_i64(tcg_rd, tcg_rd, 32);
+}
+
+TRANS(RBIT, gen_rr, a->rd, a->rn, a->sf ? gen_helper_rbit64 : gen_rbit32)
+TRANS(REV16, gen_rr, a->rd, a->rn, a->sf ? gen_rev16_64 : gen_rev16_32)
+TRANS(REV32, gen_rr, a->rd, a->rn, a->sf ? gen_rev32 : gen_rev_32)
+TRANS(REV64, gen_rr, a->rd, a->rn, tcg_gen_bswap64_i64)
+
+static void gen_clz32(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn)
+{
+ TCGv_i32 t32 = tcg_temp_new_i32();
+
+ tcg_gen_extrl_i64_i32(t32, tcg_rn);
+ tcg_gen_clzi_i32(t32, t32, 32);
+ tcg_gen_extu_i32_i64(tcg_rd, t32);
+}
+
+static void gen_clz64(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn)
+{
+ tcg_gen_clzi_i64(tcg_rd, tcg_rn, 64);
+}
+
+static void gen_cls32(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn)
+{
+ TCGv_i32 t32 = tcg_temp_new_i32();
+
+ tcg_gen_extrl_i64_i32(t32, tcg_rn);
+ tcg_gen_clrsb_i32(t32, t32);
+ tcg_gen_extu_i32_i64(tcg_rd, t32);
+}
+
+TRANS(CLZ, gen_rr, a->rd, a->rn, a->sf ? gen_clz64 : gen_clz32)
+TRANS(CLS, gen_rr, a->rd, a->rn, a->sf ? tcg_gen_clrsb_i64 : gen_cls32)
+
+static bool gen_pacaut(DisasContext *s, arg_pacaut *a, NeonGenTwo64OpEnvFn fn)
+{
+ TCGv_i64 tcg_rd, tcg_rn;
+
+ if (a->z) {
+ if (a->rn != 31) {
+ return false;
+ }
+ tcg_rn = tcg_constant_i64(0);
+ } else {
+ tcg_rn = cpu_reg_sp(s, a->rn);
+ }
+ if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, a->rd);
+ fn(tcg_rd, tcg_env, tcg_rd, tcg_rn);
}
+ return true;
+}
- if (!sf) {
+TRANS_FEAT(PACIA, aa64_pauth, gen_pacaut, a, gen_helper_pacia)
+TRANS_FEAT(PACIB, aa64_pauth, gen_pacaut, a, gen_helper_pacib)
+TRANS_FEAT(PACDA, aa64_pauth, gen_pacaut, a, gen_helper_pacda)
+TRANS_FEAT(PACDB, aa64_pauth, gen_pacaut, a, gen_helper_pacdb)
+
+TRANS_FEAT(AUTIA, aa64_pauth, gen_pacaut, a, gen_helper_autia)
+TRANS_FEAT(AUTIB, aa64_pauth, gen_pacaut, a, gen_helper_autib)
+TRANS_FEAT(AUTDA, aa64_pauth, gen_pacaut, a, gen_helper_autda)
+TRANS_FEAT(AUTDB, aa64_pauth, gen_pacaut, a, gen_helper_autdb)
+
+static bool do_xpac(DisasContext *s, int rd, NeonGenOne64OpEnvFn *fn)
+{
+ if (s->pauth_active) {
+ TCGv_i64 tcg_rd = cpu_reg(s, rd);
+ fn(tcg_rd, tcg_env, tcg_rd);
+ }
+ return true;
+}
+
+TRANS_FEAT(XPACI, aa64_pauth, do_xpac, a->rd, gen_helper_xpaci)
+TRANS_FEAT(XPACD, aa64_pauth, do_xpac, a->rd, gen_helper_xpacd)
+
+static bool do_logic_reg(DisasContext *s, arg_logic_shift *a,
+ ArithTwoOp *fn, ArithTwoOp *inv_fn, bool setflags)
+{
+ TCGv_i64 tcg_rd, tcg_rn, tcg_rm;
+
+ if (!a->sf && (a->sa & (1 << 5))) {
+ return false;
+ }
+
+ tcg_rd = cpu_reg(s, a->rd);
+ tcg_rn = cpu_reg(s, a->rn);
+
+ tcg_rm = read_cpu_reg(s, a->rm, a->sf);
+ if (a->sa) {
+ shift_reg_imm(tcg_rm, tcg_rm, a->sf, a->st, a->sa);
+ }
+
+ (a->n ? inv_fn : fn)(tcg_rd, tcg_rn, tcg_rm);
+ if (!a->sf) {
tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
}
+ if (setflags) {
+ gen_logic_CC(a->sf, tcg_rd);
+ }
+ return true;
+}
- if (opc == 3) {
- gen_logic_CC(sf, tcg_rd);
+static bool trans_ORR_r(DisasContext *s, arg_logic_shift *a)
+{
+ /*
+ * Unshifted ORR and ORN with WZR/XZR is the standard encoding for
+ * register-register MOV and MVN, so it is worth special casing.
+ */
+ if (a->sa == 0 && a->st == 0 && a->rn == 31) {
+ TCGv_i64 tcg_rd = cpu_reg(s, a->rd);
+ TCGv_i64 tcg_rm = cpu_reg(s, a->rm);
+
+ if (a->n) {
+ tcg_gen_not_i64(tcg_rd, tcg_rm);
+ if (!a->sf) {
+ tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
+ }
+ } else {
+ if (a->sf) {
+ tcg_gen_mov_i64(tcg_rd, tcg_rm);
+ } else {
+ tcg_gen_ext32u_i64(tcg_rd, tcg_rm);
+ }
+ }
+ return true;
}
+
+ return do_logic_reg(s, a, tcg_gen_or_i64, tcg_gen_orc_i64, false);
}
-/*
- * Add/subtract (extended register)
- *
- * 31|30|29|28 24|23 22|21|20 16|15 13|12 10|9 5|4 0|
- * +--+--+--+-----------+-----+--+-------+------+------+----+----+
- * |sf|op| S| 0 1 0 1 1 | opt | 1| Rm |option| imm3 | Rn | Rd |
- * +--+--+--+-----------+-----+--+-------+------+------+----+----+
- *
- * sf: 0 -> 32bit, 1 -> 64bit
- * op: 0 -> add , 1 -> sub
- * S: 1 -> set flags
- * opt: 00
- * option: extension type (see DecodeRegExtend)
- * imm3: optional shift to Rm
- *
- * Rd = Rn + LSL(extend(Rm), amount)
- */
-static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn)
-{
- int rd = extract32(insn, 0, 5);
- int rn = extract32(insn, 5, 5);
- int imm3 = extract32(insn, 10, 3);
- int option = extract32(insn, 13, 3);
- int rm = extract32(insn, 16, 5);
- int opt = extract32(insn, 22, 2);
- bool setflags = extract32(insn, 29, 1);
- bool sub_op = extract32(insn, 30, 1);
- bool sf = extract32(insn, 31, 1);
-
- TCGv_i64 tcg_rm, tcg_rn; /* temps */
- TCGv_i64 tcg_rd;
- TCGv_i64 tcg_result;
-
- if (imm3 > 4 || opt != 0) {
- unallocated_encoding(s);
- return;
+TRANS(AND_r, do_logic_reg, a, tcg_gen_and_i64, tcg_gen_andc_i64, false)
+TRANS(ANDS_r, do_logic_reg, a, tcg_gen_and_i64, tcg_gen_andc_i64, true)
+TRANS(EOR_r, do_logic_reg, a, tcg_gen_xor_i64, tcg_gen_eqv_i64, false)
+
+static bool do_addsub_ext(DisasContext *s, arg_addsub_ext *a,
+ bool sub_op, bool setflags)
+{
+ TCGv_i64 tcg_rm, tcg_rn, tcg_rd, tcg_result;
+
+ if (a->sa > 4) {
+ return false;
}
/* non-flag setting ops may use SP */
if (!setflags) {
- tcg_rd = cpu_reg_sp(s, rd);
+ tcg_rd = cpu_reg_sp(s, a->rd);
} else {
- tcg_rd = cpu_reg(s, rd);
+ tcg_rd = cpu_reg(s, a->rd);
}
- tcg_rn = read_cpu_reg_sp(s, rn, sf);
+ tcg_rn = read_cpu_reg_sp(s, a->rn, a->sf);
- tcg_rm = read_cpu_reg(s, rm, sf);
- ext_and_shift_reg(tcg_rm, tcg_rm, option, imm3);
+ tcg_rm = read_cpu_reg(s, a->rm, a->sf);
+ ext_and_shift_reg(tcg_rm, tcg_rm, a->st, a->sa);
tcg_result = tcg_temp_new_i64();
-
if (!setflags) {
if (sub_op) {
tcg_gen_sub_i64(tcg_result, tcg_rn, tcg_rm);
@@ -7694,60 +8001,41 @@ static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn)
}
} else {
if (sub_op) {
- gen_sub_CC(sf, tcg_result, tcg_rn, tcg_rm);
+ gen_sub_CC(a->sf, tcg_result, tcg_rn, tcg_rm);
} else {
- gen_add_CC(sf, tcg_result, tcg_rn, tcg_rm);
+ gen_add_CC(a->sf, tcg_result, tcg_rn, tcg_rm);
}
}
- if (sf) {
+ if (a->sf) {
tcg_gen_mov_i64(tcg_rd, tcg_result);
} else {
tcg_gen_ext32u_i64(tcg_rd, tcg_result);
}
+ return true;
}
-/*
- * Add/subtract (shifted register)
- *
- * 31 30 29 28 24 23 22 21 20 16 15 10 9 5 4 0
- * +--+--+--+-----------+-----+--+-------+---------+------+------+
- * |sf|op| S| 0 1 0 1 1 |shift| 0| Rm | imm6 | Rn | Rd |
- * +--+--+--+-----------+-----+--+-------+---------+------+------+
- *
- * sf: 0 -> 32bit, 1 -> 64bit
- * op: 0 -> add , 1 -> sub
- * S: 1 -> set flags
- * shift: 00 -> LSL, 01 -> LSR, 10 -> ASR, 11 -> RESERVED
- * imm6: Shift amount to apply to Rm before the add/sub
- */
-static void disas_add_sub_reg(DisasContext *s, uint32_t insn)
-{
- int rd = extract32(insn, 0, 5);
- int rn = extract32(insn, 5, 5);
- int imm6 = extract32(insn, 10, 6);
- int rm = extract32(insn, 16, 5);
- int shift_type = extract32(insn, 22, 2);
- bool setflags = extract32(insn, 29, 1);
- bool sub_op = extract32(insn, 30, 1);
- bool sf = extract32(insn, 31, 1);
-
- TCGv_i64 tcg_rd = cpu_reg(s, rd);
- TCGv_i64 tcg_rn, tcg_rm;
- TCGv_i64 tcg_result;
-
- if ((shift_type == 3) || (!sf && (imm6 > 31))) {
- unallocated_encoding(s);
- return;
+TRANS(ADD_ext, do_addsub_ext, a, false, false)
+TRANS(SUB_ext, do_addsub_ext, a, true, false)
+TRANS(ADDS_ext, do_addsub_ext, a, false, true)
+TRANS(SUBS_ext, do_addsub_ext, a, true, true)
+
+static bool do_addsub_reg(DisasContext *s, arg_addsub_shift *a,
+ bool sub_op, bool setflags)
+{
+ TCGv_i64 tcg_rd, tcg_rn, tcg_rm, tcg_result;
+
+ if (a->st == 3 || (!a->sf && (a->sa & 32))) {
+ return false;
}
- tcg_rn = read_cpu_reg(s, rn, sf);
- tcg_rm = read_cpu_reg(s, rm, sf);
+ tcg_rd = cpu_reg(s, a->rd);
+ tcg_rn = read_cpu_reg(s, a->rn, a->sf);
+ tcg_rm = read_cpu_reg(s, a->rm, a->sf);
- shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, imm6);
+ shift_reg_imm(tcg_rm, tcg_rm, a->sf, a->st, a->sa);
tcg_result = tcg_temp_new_i64();
-
if (!setflags) {
if (sub_op) {
tcg_gen_sub_i64(tcg_result, tcg_rn, tcg_rm);
@@ -7756,171 +8044,127 @@ static void disas_add_sub_reg(DisasContext *s, uint32_t insn)
}
} else {
if (sub_op) {
- gen_sub_CC(sf, tcg_result, tcg_rn, tcg_rm);
+ gen_sub_CC(a->sf, tcg_result, tcg_rn, tcg_rm);
} else {
- gen_add_CC(sf, tcg_result, tcg_rn, tcg_rm);
+ gen_add_CC(a->sf, tcg_result, tcg_rn, tcg_rm);
}
}
- if (sf) {
+ if (a->sf) {
tcg_gen_mov_i64(tcg_rd, tcg_result);
} else {
tcg_gen_ext32u_i64(tcg_rd, tcg_result);
}
+ return true;
}
-/* Data-processing (3 source)
- *
- * 31 30 29 28 24 23 21 20 16 15 14 10 9 5 4 0
- * +--+------+-----------+------+------+----+------+------+------+
- * |sf| op54 | 1 1 0 1 1 | op31 | Rm | o0 | Ra | Rn | Rd |
- * +--+------+-----------+------+------+----+------+------+------+
- */
-static void disas_data_proc_3src(DisasContext *s, uint32_t insn)
-{
- int rd = extract32(insn, 0, 5);
- int rn = extract32(insn, 5, 5);
- int ra = extract32(insn, 10, 5);
- int rm = extract32(insn, 16, 5);
- int op_id = (extract32(insn, 29, 3) << 4) |
- (extract32(insn, 21, 3) << 1) |
- extract32(insn, 15, 1);
- bool sf = extract32(insn, 31, 1);
- bool is_sub = extract32(op_id, 0, 1);
- bool is_high = extract32(op_id, 2, 1);
- bool is_signed = false;
- TCGv_i64 tcg_op1;
- TCGv_i64 tcg_op2;
- TCGv_i64 tcg_tmp;
-
- /* Note that op_id is sf:op54:op31:o0 so it includes the 32/64 size flag */
- switch (op_id) {
- case 0x42: /* SMADDL */
- case 0x43: /* SMSUBL */
- case 0x44: /* SMULH */
- is_signed = true;
- break;
- case 0x0: /* MADD (32bit) */
- case 0x1: /* MSUB (32bit) */
- case 0x40: /* MADD (64bit) */
- case 0x41: /* MSUB (64bit) */
- case 0x4a: /* UMADDL */
- case 0x4b: /* UMSUBL */
- case 0x4c: /* UMULH */
- break;
- default:
- unallocated_encoding(s);
- return;
- }
+TRANS(ADD_r, do_addsub_reg, a, false, false)
+TRANS(SUB_r, do_addsub_reg, a, true, false)
+TRANS(ADDS_r, do_addsub_reg, a, false, true)
+TRANS(SUBS_r, do_addsub_reg, a, true, true)
- if (is_high) {
- TCGv_i64 low_bits = tcg_temp_new_i64(); /* low bits discarded */
- TCGv_i64 tcg_rd = cpu_reg(s, rd);
- TCGv_i64 tcg_rn = cpu_reg(s, rn);
- TCGv_i64 tcg_rm = cpu_reg(s, rm);
+static bool do_mulh(DisasContext *s, arg_rrr *a,
+ void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64))
+{
+ TCGv_i64 discard = tcg_temp_new_i64();
+ TCGv_i64 tcg_rd = cpu_reg(s, a->rd);
+ TCGv_i64 tcg_rn = cpu_reg(s, a->rn);
+ TCGv_i64 tcg_rm = cpu_reg(s, a->rm);
- if (is_signed) {
- tcg_gen_muls2_i64(low_bits, tcg_rd, tcg_rn, tcg_rm);
- } else {
- tcg_gen_mulu2_i64(low_bits, tcg_rd, tcg_rn, tcg_rm);
- }
- return;
- }
+ fn(discard, tcg_rd, tcg_rn, tcg_rm);
+ return true;
+}
- tcg_op1 = tcg_temp_new_i64();
- tcg_op2 = tcg_temp_new_i64();
- tcg_tmp = tcg_temp_new_i64();
+TRANS(SMULH, do_mulh, a, tcg_gen_muls2_i64)
+TRANS(UMULH, do_mulh, a, tcg_gen_mulu2_i64)
- if (op_id < 0x42) {
- tcg_gen_mov_i64(tcg_op1, cpu_reg(s, rn));
- tcg_gen_mov_i64(tcg_op2, cpu_reg(s, rm));
+static bool do_muladd(DisasContext *s, arg_rrrr *a,
+ bool sf, bool is_sub, MemOp mop)
+{
+ TCGv_i64 tcg_rd = cpu_reg(s, a->rd);
+ TCGv_i64 tcg_op1, tcg_op2;
+
+ if (mop == MO_64) {
+ tcg_op1 = cpu_reg(s, a->rn);
+ tcg_op2 = cpu_reg(s, a->rm);
} else {
- if (is_signed) {
- tcg_gen_ext32s_i64(tcg_op1, cpu_reg(s, rn));
- tcg_gen_ext32s_i64(tcg_op2, cpu_reg(s, rm));
- } else {
- tcg_gen_ext32u_i64(tcg_op1, cpu_reg(s, rn));
- tcg_gen_ext32u_i64(tcg_op2, cpu_reg(s, rm));
- }
+ tcg_op1 = tcg_temp_new_i64();
+ tcg_op2 = tcg_temp_new_i64();
+ tcg_gen_ext_i64(tcg_op1, cpu_reg(s, a->rn), mop);
+ tcg_gen_ext_i64(tcg_op2, cpu_reg(s, a->rm), mop);
}
- if (ra == 31 && !is_sub) {
+ if (a->ra == 31 && !is_sub) {
/* Special-case MADD with rA == XZR; it is the standard MUL alias */
- tcg_gen_mul_i64(cpu_reg(s, rd), tcg_op1, tcg_op2);
+ tcg_gen_mul_i64(tcg_rd, tcg_op1, tcg_op2);
} else {
+ TCGv_i64 tcg_tmp = tcg_temp_new_i64();
+ TCGv_i64 tcg_ra = cpu_reg(s, a->ra);
+
tcg_gen_mul_i64(tcg_tmp, tcg_op1, tcg_op2);
if (is_sub) {
- tcg_gen_sub_i64(cpu_reg(s, rd), cpu_reg(s, ra), tcg_tmp);
+ tcg_gen_sub_i64(tcg_rd, tcg_ra, tcg_tmp);
} else {
- tcg_gen_add_i64(cpu_reg(s, rd), cpu_reg(s, ra), tcg_tmp);
+ tcg_gen_add_i64(tcg_rd, tcg_ra, tcg_tmp);
}
}
if (!sf) {
- tcg_gen_ext32u_i64(cpu_reg(s, rd), cpu_reg(s, rd));
+ tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
}
+ return true;
}
-/* Add/subtract (with carry)
- * 31 30 29 28 27 26 25 24 23 22 21 20 16 15 10 9 5 4 0
- * +--+--+--+------------------------+------+-------------+------+-----+
- * |sf|op| S| 1 1 0 1 0 0 0 0 | rm | 0 0 0 0 0 0 | Rn | Rd |
- * +--+--+--+------------------------+------+-------------+------+-----+
- */
+TRANS(MADD_w, do_muladd, a, false, false, MO_64)
+TRANS(MSUB_w, do_muladd, a, false, true, MO_64)
+TRANS(MADD_x, do_muladd, a, true, false, MO_64)
+TRANS(MSUB_x, do_muladd, a, true, true, MO_64)
+
+TRANS(SMADDL, do_muladd, a, true, false, MO_SL)
+TRANS(SMSUBL, do_muladd, a, true, true, MO_SL)
+TRANS(UMADDL, do_muladd, a, true, false, MO_UL)
+TRANS(UMSUBL, do_muladd, a, true, true, MO_UL)
-static void disas_adc_sbc(DisasContext *s, uint32_t insn)
+static bool do_adc_sbc(DisasContext *s, arg_rrr_sf *a,
+ bool is_sub, bool setflags)
{
- unsigned int sf, op, setflags, rm, rn, rd;
TCGv_i64 tcg_y, tcg_rn, tcg_rd;
- sf = extract32(insn, 31, 1);
- op = extract32(insn, 30, 1);
- setflags = extract32(insn, 29, 1);
- rm = extract32(insn, 16, 5);
- rn = extract32(insn, 5, 5);
- rd = extract32(insn, 0, 5);
-
- tcg_rd = cpu_reg(s, rd);
- tcg_rn = cpu_reg(s, rn);
+ tcg_rd = cpu_reg(s, a->rd);
+ tcg_rn = cpu_reg(s, a->rn);
- if (op) {
+ if (is_sub) {
tcg_y = tcg_temp_new_i64();
- tcg_gen_not_i64(tcg_y, cpu_reg(s, rm));
+ tcg_gen_not_i64(tcg_y, cpu_reg(s, a->rm));
} else {
- tcg_y = cpu_reg(s, rm);
+ tcg_y = cpu_reg(s, a->rm);
}
if (setflags) {
- gen_adc_CC(sf, tcg_rd, tcg_rn, tcg_y);
+ gen_adc_CC(a->sf, tcg_rd, tcg_rn, tcg_y);
} else {
- gen_adc(sf, tcg_rd, tcg_rn, tcg_y);
+ gen_adc(a->sf, tcg_rd, tcg_rn, tcg_y);
}
+ return true;
}
-/*
- * Rotate right into flags
- * 31 30 29 21 15 10 5 4 0
- * +--+--+--+-----------------+--------+-----------+------+--+------+
- * |sf|op| S| 1 1 0 1 0 0 0 0 | imm6 | 0 0 0 0 1 | Rn |o2| mask |
- * +--+--+--+-----------------+--------+-----------+------+--+------+
- */
-static void disas_rotate_right_into_flags(DisasContext *s, uint32_t insn)
+TRANS(ADC, do_adc_sbc, a, false, false)
+TRANS(SBC, do_adc_sbc, a, true, false)
+TRANS(ADCS, do_adc_sbc, a, false, true)
+TRANS(SBCS, do_adc_sbc, a, true, true)
+
+static bool trans_RMIF(DisasContext *s, arg_RMIF *a)
{
- int mask = extract32(insn, 0, 4);
- int o2 = extract32(insn, 4, 1);
- int rn = extract32(insn, 5, 5);
- int imm6 = extract32(insn, 15, 6);
- int sf_op_s = extract32(insn, 29, 3);
+ int mask = a->mask;
TCGv_i64 tcg_rn;
TCGv_i32 nzcv;
- if (sf_op_s != 5 || o2 != 0 || !dc_isar_feature(aa64_condm_4, s)) {
- unallocated_encoding(s);
- return;
+ if (!dc_isar_feature(aa64_condm_4, s)) {
+ return false;
}
- tcg_rn = read_cpu_reg(s, rn, 1);
- tcg_gen_rotri_i64(tcg_rn, tcg_rn, imm6);
+ tcg_rn = read_cpu_reg(s, a->rn, 1);
+ tcg_gen_rotri_i64(tcg_rn, tcg_rn, a->imm);
nzcv = tcg_temp_new_i32();
tcg_gen_extrl_i64_i32(nzcv, tcg_rn);
@@ -7938,102 +8182,64 @@ static void disas_rotate_right_into_flags(DisasContext *s, uint32_t insn)
if (mask & 1) { /* V */
tcg_gen_shli_i32(cpu_VF, nzcv, 31 - 0);
}
+ return true;
}
-/*
- * Evaluate into flags
- * 31 30 29 21 15 14 10 5 4 0
- * +--+--+--+-----------------+---------+----+---------+------+--+------+
- * |sf|op| S| 1 1 0 1 0 0 0 0 | opcode2 | sz | 0 0 1 0 | Rn |o3| mask |
- * +--+--+--+-----------------+---------+----+---------+------+--+------+
- */
-static void disas_evaluate_into_flags(DisasContext *s, uint32_t insn)
+static bool do_setf(DisasContext *s, int rn, int shift)
{
- int o3_mask = extract32(insn, 0, 5);
- int rn = extract32(insn, 5, 5);
- int o2 = extract32(insn, 15, 6);
- int sz = extract32(insn, 14, 1);
- int sf_op_s = extract32(insn, 29, 3);
- TCGv_i32 tmp;
- int shift;
-
- if (sf_op_s != 1 || o2 != 0 || o3_mask != 0xd ||
- !dc_isar_feature(aa64_condm_4, s)) {
- unallocated_encoding(s);
- return;
- }
- shift = sz ? 16 : 24; /* SETF16 or SETF8 */
+ TCGv_i32 tmp = tcg_temp_new_i32();
- tmp = tcg_temp_new_i32();
tcg_gen_extrl_i64_i32(tmp, cpu_reg(s, rn));
tcg_gen_shli_i32(cpu_NF, tmp, shift);
tcg_gen_shli_i32(cpu_VF, tmp, shift - 1);
tcg_gen_mov_i32(cpu_ZF, cpu_NF);
tcg_gen_xor_i32(cpu_VF, cpu_VF, cpu_NF);
+ return true;
}
-/* Conditional compare (immediate / register)
- * 31 30 29 28 27 26 25 24 23 22 21 20 16 15 12 11 10 9 5 4 3 0
- * +--+--+--+------------------------+--------+------+----+--+------+--+-----+
- * |sf|op| S| 1 1 0 1 0 0 1 0 |imm5/rm | cond |i/r |o2| Rn |o3|nzcv |
- * +--+--+--+------------------------+--------+------+----+--+------+--+-----+
- * [1] y [0] [0]
- */
-static void disas_cc(DisasContext *s, uint32_t insn)
+TRANS_FEAT(SETF8, aa64_condm_4, do_setf, a->rn, 24)
+TRANS_FEAT(SETF16, aa64_condm_4, do_setf, a->rn, 16)
+
+/* CCMP, CCMN */
+static bool trans_CCMP(DisasContext *s, arg_CCMP *a)
{
- unsigned int sf, op, y, cond, rn, nzcv, is_imm;
- TCGv_i32 tcg_t0, tcg_t1, tcg_t2;
- TCGv_i64 tcg_tmp, tcg_y, tcg_rn;
+ TCGv_i32 tcg_t0 = tcg_temp_new_i32();
+ TCGv_i32 tcg_t1 = tcg_temp_new_i32();
+ TCGv_i32 tcg_t2 = tcg_temp_new_i32();
+ TCGv_i64 tcg_tmp = tcg_temp_new_i64();
+ TCGv_i64 tcg_rn, tcg_y;
DisasCompare c;
-
- if (!extract32(insn, 29, 1)) {
- unallocated_encoding(s);
- return;
- }
- if (insn & (1 << 10 | 1 << 4)) {
- unallocated_encoding(s);
- return;
- }
- sf = extract32(insn, 31, 1);
- op = extract32(insn, 30, 1);
- is_imm = extract32(insn, 11, 1);
- y = extract32(insn, 16, 5); /* y = rm (reg) or imm5 (imm) */
- cond = extract32(insn, 12, 4);
- rn = extract32(insn, 5, 5);
- nzcv = extract32(insn, 0, 4);
+ unsigned nzcv;
/* Set T0 = !COND. */
- tcg_t0 = tcg_temp_new_i32();
- arm_test_cc(&c, cond);
+ arm_test_cc(&c, a->cond);
tcg_gen_setcondi_i32(tcg_invert_cond(c.cond), tcg_t0, c.value, 0);
/* Load the arguments for the new comparison. */
- if (is_imm) {
- tcg_y = tcg_temp_new_i64();
- tcg_gen_movi_i64(tcg_y, y);
+ if (a->imm) {
+ tcg_y = tcg_constant_i64(a->y);
} else {
- tcg_y = cpu_reg(s, y);
+ tcg_y = cpu_reg(s, a->y);
}
- tcg_rn = cpu_reg(s, rn);
+ tcg_rn = cpu_reg(s, a->rn);
/* Set the flags for the new comparison. */
- tcg_tmp = tcg_temp_new_i64();
- if (op) {
- gen_sub_CC(sf, tcg_tmp, tcg_rn, tcg_y);
+ if (a->op) {
+ gen_sub_CC(a->sf, tcg_tmp, tcg_rn, tcg_y);
} else {
- gen_add_CC(sf, tcg_tmp, tcg_rn, tcg_y);
+ gen_add_CC(a->sf, tcg_tmp, tcg_rn, tcg_y);
}
- /* If COND was false, force the flags to #nzcv. Compute two masks
+ /*
+ * If COND was false, force the flags to #nzcv. Compute two masks
* to help with this: T1 = (COND ? 0 : -1), T2 = (COND ? -1 : 0).
* For tcg hosts that support ANDC, we can make do with just T1.
* In either case, allow the tcg optimizer to delete any unused mask.
*/
- tcg_t1 = tcg_temp_new_i32();
- tcg_t2 = tcg_temp_new_i32();
tcg_gen_neg_i32(tcg_t1, tcg_t0);
tcg_gen_subi_i32(tcg_t2, tcg_t0, 1);
+ nzcv = a->nzcv;
if (nzcv & 8) { /* N */
tcg_gen_or_i32(cpu_NF, cpu_NF, tcg_t1);
} else {
@@ -8070,41 +8276,20 @@ static void disas_cc(DisasContext *s, uint32_t insn)
tcg_gen_and_i32(cpu_VF, cpu_VF, tcg_t2);
}
}
+ return true;
}
-/* Conditional select
- * 31 30 29 28 21 20 16 15 12 11 10 9 5 4 0
- * +----+----+---+-----------------+------+------+-----+------+------+
- * | sf | op | S | 1 1 0 1 0 1 0 0 | Rm | cond | op2 | Rn | Rd |
- * +----+----+---+-----------------+------+------+-----+------+------+
- */
-static void disas_cond_select(DisasContext *s, uint32_t insn)
+static bool trans_CSEL(DisasContext *s, arg_CSEL *a)
{
- unsigned int sf, else_inv, rm, cond, else_inc, rn, rd;
- TCGv_i64 tcg_rd, zero;
+ TCGv_i64 tcg_rd = cpu_reg(s, a->rd);
+ TCGv_i64 zero = tcg_constant_i64(0);
DisasCompare64 c;
- if (extract32(insn, 29, 1) || extract32(insn, 11, 1)) {
- /* S == 1 or op2<1> == 1 */
- unallocated_encoding(s);
- return;
- }
- sf = extract32(insn, 31, 1);
- else_inv = extract32(insn, 30, 1);
- rm = extract32(insn, 16, 5);
- cond = extract32(insn, 12, 4);
- else_inc = extract32(insn, 10, 1);
- rn = extract32(insn, 5, 5);
- rd = extract32(insn, 0, 5);
-
- tcg_rd = cpu_reg(s, rd);
-
- a64_test_cc(&c, cond);
- zero = tcg_constant_i64(0);
+ a64_test_cc(&c, a->cond);
- if (rn == 31 && rm == 31 && (else_inc ^ else_inv)) {
+ if (a->rn == 31 && a->rm == 31 && (a->else_inc ^ a->else_inv)) {
/* CSET & CSETM. */
- if (else_inv) {
+ if (a->else_inv) {
tcg_gen_negsetcond_i64(tcg_invert_cond(c.cond),
tcg_rd, c.value, zero);
} else {
@@ -8112,3478 +8297,1237 @@ static void disas_cond_select(DisasContext *s, uint32_t insn)
tcg_rd, c.value, zero);
}
} else {
- TCGv_i64 t_true = cpu_reg(s, rn);
- TCGv_i64 t_false = read_cpu_reg(s, rm, 1);
- if (else_inv && else_inc) {
+ TCGv_i64 t_true = cpu_reg(s, a->rn);
+ TCGv_i64 t_false = read_cpu_reg(s, a->rm, 1);
+
+ if (a->else_inv && a->else_inc) {
tcg_gen_neg_i64(t_false, t_false);
- } else if (else_inv) {
+ } else if (a->else_inv) {
tcg_gen_not_i64(t_false, t_false);
- } else if (else_inc) {
+ } else if (a->else_inc) {
tcg_gen_addi_i64(t_false, t_false, 1);
}
tcg_gen_movcond_i64(c.cond, tcg_rd, c.value, zero, t_true, t_false);
}
- if (!sf) {
+ if (!a->sf) {
tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
}
+ return true;
}
-static void handle_clz(DisasContext *s, unsigned int sf,
- unsigned int rn, unsigned int rd)
-{
- TCGv_i64 tcg_rd, tcg_rn;
- tcg_rd = cpu_reg(s, rd);
- tcg_rn = cpu_reg(s, rn);
-
- if (sf) {
- tcg_gen_clzi_i64(tcg_rd, tcg_rn, 64);
- } else {
- TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
- tcg_gen_extrl_i64_i32(tcg_tmp32, tcg_rn);
- tcg_gen_clzi_i32(tcg_tmp32, tcg_tmp32, 32);
- tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
- }
-}
-
-static void handle_cls(DisasContext *s, unsigned int sf,
- unsigned int rn, unsigned int rd)
-{
- TCGv_i64 tcg_rd, tcg_rn;
- tcg_rd = cpu_reg(s, rd);
- tcg_rn = cpu_reg(s, rn);
-
- if (sf) {
- tcg_gen_clrsb_i64(tcg_rd, tcg_rn);
- } else {
- TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
- tcg_gen_extrl_i64_i32(tcg_tmp32, tcg_rn);
- tcg_gen_clrsb_i32(tcg_tmp32, tcg_tmp32);
- tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
- }
-}
-
-static void handle_rbit(DisasContext *s, unsigned int sf,
- unsigned int rn, unsigned int rd)
-{
- TCGv_i64 tcg_rd, tcg_rn;
- tcg_rd = cpu_reg(s, rd);
- tcg_rn = cpu_reg(s, rn);
-
- if (sf) {
- gen_helper_rbit64(tcg_rd, tcg_rn);
- } else {
- TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
- tcg_gen_extrl_i64_i32(tcg_tmp32, tcg_rn);
- gen_helper_rbit(tcg_tmp32, tcg_tmp32);
- tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
- }
-}
-
-/* REV with sf==1, opcode==3 ("REV64") */
-static void handle_rev64(DisasContext *s, unsigned int sf,
- unsigned int rn, unsigned int rd)
-{
- if (!sf) {
- unallocated_encoding(s);
- return;
- }
- tcg_gen_bswap64_i64(cpu_reg(s, rd), cpu_reg(s, rn));
-}
-
-/* REV with sf==0, opcode==2
- * REV32 (sf==1, opcode==2)
- */
-static void handle_rev32(DisasContext *s, unsigned int sf,
- unsigned int rn, unsigned int rd)
-{
- TCGv_i64 tcg_rd = cpu_reg(s, rd);
- TCGv_i64 tcg_rn = cpu_reg(s, rn);
-
- if (sf) {
- tcg_gen_bswap64_i64(tcg_rd, tcg_rn);
- tcg_gen_rotri_i64(tcg_rd, tcg_rd, 32);
- } else {
- tcg_gen_bswap32_i64(tcg_rd, tcg_rn, TCG_BSWAP_OZ);
- }
-}
+typedef struct FPScalar1Int {
+ void (*gen_h)(TCGv_i32, TCGv_i32);
+ void (*gen_s)(TCGv_i32, TCGv_i32);
+ void (*gen_d)(TCGv_i64, TCGv_i64);
+} FPScalar1Int;
-/* REV16 (opcode==1) */
-static void handle_rev16(DisasContext *s, unsigned int sf,
- unsigned int rn, unsigned int rd)
+static bool do_fp1_scalar_int(DisasContext *s, arg_rr_e *a,
+ const FPScalar1Int *f)
{
- TCGv_i64 tcg_rd = cpu_reg(s, rd);
- TCGv_i64 tcg_tmp = tcg_temp_new_i64();
- TCGv_i64 tcg_rn = read_cpu_reg(s, rn, sf);
- TCGv_i64 mask = tcg_constant_i64(sf ? 0x00ff00ff00ff00ffull : 0x00ff00ff);
-
- tcg_gen_shri_i64(tcg_tmp, tcg_rn, 8);
- tcg_gen_and_i64(tcg_rd, tcg_rn, mask);
- tcg_gen_and_i64(tcg_tmp, tcg_tmp, mask);
- tcg_gen_shli_i64(tcg_rd, tcg_rd, 8);
- tcg_gen_or_i64(tcg_rd, tcg_rd, tcg_tmp);
-}
-
-/* Data-processing (1 source)
- * 31 30 29 28 21 20 16 15 10 9 5 4 0
- * +----+---+---+-----------------+---------+--------+------+------+
- * | sf | 1 | S | 1 1 0 1 0 1 1 0 | opcode2 | opcode | Rn | Rd |
- * +----+---+---+-----------------+---------+--------+------+------+
- */
-static void disas_data_proc_1src(DisasContext *s, uint32_t insn)
-{
- unsigned int sf, opcode, opcode2, rn, rd;
- TCGv_i64 tcg_rd;
-
- if (extract32(insn, 29, 1)) {
- unallocated_encoding(s);
- return;
- }
-
- sf = extract32(insn, 31, 1);
- opcode = extract32(insn, 10, 6);
- opcode2 = extract32(insn, 16, 5);
- rn = extract32(insn, 5, 5);
- rd = extract32(insn, 0, 5);
-
-#define MAP(SF, O2, O1) ((SF) | (O1 << 1) | (O2 << 7))
-
- switch (MAP(sf, opcode2, opcode)) {
- case MAP(0, 0x00, 0x00): /* RBIT */
- case MAP(1, 0x00, 0x00):
- handle_rbit(s, sf, rn, rd);
- break;
- case MAP(0, 0x00, 0x01): /* REV16 */
- case MAP(1, 0x00, 0x01):
- handle_rev16(s, sf, rn, rd);
- break;
- case MAP(0, 0x00, 0x02): /* REV/REV32 */
- case MAP(1, 0x00, 0x02):
- handle_rev32(s, sf, rn, rd);
- break;
- case MAP(1, 0x00, 0x03): /* REV64 */
- handle_rev64(s, sf, rn, rd);
- break;
- case MAP(0, 0x00, 0x04): /* CLZ */
- case MAP(1, 0x00, 0x04):
- handle_clz(s, sf, rn, rd);
- break;
- case MAP(0, 0x00, 0x05): /* CLS */
- case MAP(1, 0x00, 0x05):
- handle_cls(s, sf, rn, rd);
- break;
- case MAP(1, 0x01, 0x00): /* PACIA */
- if (s->pauth_active) {
- tcg_rd = cpu_reg(s, rd);
- gen_helper_pacia(tcg_rd, tcg_env, tcg_rd, cpu_reg_sp(s, rn));
- } else if (!dc_isar_feature(aa64_pauth, s)) {
- goto do_unallocated;
- }
- break;
- case MAP(1, 0x01, 0x01): /* PACIB */
- if (s->pauth_active) {
- tcg_rd = cpu_reg(s, rd);
- gen_helper_pacib(tcg_rd, tcg_env, tcg_rd, cpu_reg_sp(s, rn));
- } else if (!dc_isar_feature(aa64_pauth, s)) {
- goto do_unallocated;
- }
- break;
- case MAP(1, 0x01, 0x02): /* PACDA */
- if (s->pauth_active) {
- tcg_rd = cpu_reg(s, rd);
- gen_helper_pacda(tcg_rd, tcg_env, tcg_rd, cpu_reg_sp(s, rn));
- } else if (!dc_isar_feature(aa64_pauth, s)) {
- goto do_unallocated;
- }
- break;
- case MAP(1, 0x01, 0x03): /* PACDB */
- if (s->pauth_active) {
- tcg_rd = cpu_reg(s, rd);
- gen_helper_pacdb(tcg_rd, tcg_env, tcg_rd, cpu_reg_sp(s, rn));
- } else if (!dc_isar_feature(aa64_pauth, s)) {
- goto do_unallocated;
- }
- break;
- case MAP(1, 0x01, 0x04): /* AUTIA */
- if (s->pauth_active) {
- tcg_rd = cpu_reg(s, rd);
- gen_helper_autia(tcg_rd, tcg_env, tcg_rd, cpu_reg_sp(s, rn));
- } else if (!dc_isar_feature(aa64_pauth, s)) {
- goto do_unallocated;
- }
- break;
- case MAP(1, 0x01, 0x05): /* AUTIB */
- if (s->pauth_active) {
- tcg_rd = cpu_reg(s, rd);
- gen_helper_autib(tcg_rd, tcg_env, tcg_rd, cpu_reg_sp(s, rn));
- } else if (!dc_isar_feature(aa64_pauth, s)) {
- goto do_unallocated;
- }
- break;
- case MAP(1, 0x01, 0x06): /* AUTDA */
- if (s->pauth_active) {
- tcg_rd = cpu_reg(s, rd);
- gen_helper_autda(tcg_rd, tcg_env, tcg_rd, cpu_reg_sp(s, rn));
- } else if (!dc_isar_feature(aa64_pauth, s)) {
- goto do_unallocated;
- }
- break;
- case MAP(1, 0x01, 0x07): /* AUTDB */
- if (s->pauth_active) {
- tcg_rd = cpu_reg(s, rd);
- gen_helper_autdb(tcg_rd, tcg_env, tcg_rd, cpu_reg_sp(s, rn));
- } else if (!dc_isar_feature(aa64_pauth, s)) {
- goto do_unallocated;
- }
- break;
- case MAP(1, 0x01, 0x08): /* PACIZA */
- if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
- goto do_unallocated;
- } else if (s->pauth_active) {
- tcg_rd = cpu_reg(s, rd);
- gen_helper_pacia(tcg_rd, tcg_env, tcg_rd, tcg_constant_i64(0));
- }
- break;
- case MAP(1, 0x01, 0x09): /* PACIZB */
- if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
- goto do_unallocated;
- } else if (s->pauth_active) {
- tcg_rd = cpu_reg(s, rd);
- gen_helper_pacib(tcg_rd, tcg_env, tcg_rd, tcg_constant_i64(0));
- }
- break;
- case MAP(1, 0x01, 0x0a): /* PACDZA */
- if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
- goto do_unallocated;
- } else if (s->pauth_active) {
- tcg_rd = cpu_reg(s, rd);
- gen_helper_pacda(tcg_rd, tcg_env, tcg_rd, tcg_constant_i64(0));
- }
- break;
- case MAP(1, 0x01, 0x0b): /* PACDZB */
- if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
- goto do_unallocated;
- } else if (s->pauth_active) {
- tcg_rd = cpu_reg(s, rd);
- gen_helper_pacdb(tcg_rd, tcg_env, tcg_rd, tcg_constant_i64(0));
- }
- break;
- case MAP(1, 0x01, 0x0c): /* AUTIZA */
- if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
- goto do_unallocated;
- } else if (s->pauth_active) {
- tcg_rd = cpu_reg(s, rd);
- gen_helper_autia(tcg_rd, tcg_env, tcg_rd, tcg_constant_i64(0));
- }
- break;
- case MAP(1, 0x01, 0x0d): /* AUTIZB */
- if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
- goto do_unallocated;
- } else if (s->pauth_active) {
- tcg_rd = cpu_reg(s, rd);
- gen_helper_autib(tcg_rd, tcg_env, tcg_rd, tcg_constant_i64(0));
- }
- break;
- case MAP(1, 0x01, 0x0e): /* AUTDZA */
- if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
- goto do_unallocated;
- } else if (s->pauth_active) {
- tcg_rd = cpu_reg(s, rd);
- gen_helper_autda(tcg_rd, tcg_env, tcg_rd, tcg_constant_i64(0));
+ switch (a->esz) {
+ case MO_64:
+ if (fp_access_check(s)) {
+ TCGv_i64 t = read_fp_dreg(s, a->rn);
+ f->gen_d(t, t);
+ write_fp_dreg(s, a->rd, t);
}
break;
- case MAP(1, 0x01, 0x0f): /* AUTDZB */
- if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
- goto do_unallocated;
- } else if (s->pauth_active) {
- tcg_rd = cpu_reg(s, rd);
- gen_helper_autdb(tcg_rd, tcg_env, tcg_rd, tcg_constant_i64(0));
+ case MO_32:
+ if (fp_access_check(s)) {
+ TCGv_i32 t = read_fp_sreg(s, a->rn);
+ f->gen_s(t, t);
+ write_fp_sreg(s, a->rd, t);
}
break;
- case MAP(1, 0x01, 0x10): /* XPACI */
- if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
- goto do_unallocated;
- } else if (s->pauth_active) {
- tcg_rd = cpu_reg(s, rd);
- gen_helper_xpaci(tcg_rd, tcg_env, tcg_rd);
+ case MO_16:
+ if (!dc_isar_feature(aa64_fp16, s)) {
+ return false;
}
- break;
- case MAP(1, 0x01, 0x11): /* XPACD */
- if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
- goto do_unallocated;
- } else if (s->pauth_active) {
- tcg_rd = cpu_reg(s, rd);
- gen_helper_xpacd(tcg_rd, tcg_env, tcg_rd);
+ if (fp_access_check(s)) {
+ TCGv_i32 t = read_fp_hreg(s, a->rn);
+ f->gen_h(t, t);
+ write_fp_sreg(s, a->rd, t);
}
break;
default:
- do_unallocated:
- unallocated_encoding(s);
- break;
+ return false;
}
-
-#undef MAP
+ return true;
}
-static void handle_div(DisasContext *s, bool is_signed, unsigned int sf,
- unsigned int rm, unsigned int rn, unsigned int rd)
-{
- TCGv_i64 tcg_n, tcg_m, tcg_rd;
- tcg_rd = cpu_reg(s, rd);
-
- if (!sf && is_signed) {
- tcg_n = tcg_temp_new_i64();
- tcg_m = tcg_temp_new_i64();
- tcg_gen_ext32s_i64(tcg_n, cpu_reg(s, rn));
- tcg_gen_ext32s_i64(tcg_m, cpu_reg(s, rm));
- } else {
- tcg_n = read_cpu_reg(s, rn, sf);
- tcg_m = read_cpu_reg(s, rm, sf);
- }
-
- if (is_signed) {
- gen_helper_sdiv64(tcg_rd, tcg_n, tcg_m);
- } else {
- gen_helper_udiv64(tcg_rd, tcg_n, tcg_m);
- }
+static const FPScalar1Int f_scalar_fmov = {
+ tcg_gen_mov_i32,
+ tcg_gen_mov_i32,
+ tcg_gen_mov_i64,
+};
+TRANS(FMOV_s, do_fp1_scalar_int, a, &f_scalar_fmov)
- if (!sf) { /* zero extend final result */
- tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
- }
-}
+static const FPScalar1Int f_scalar_fabs = {
+ gen_vfp_absh,
+ gen_vfp_abss,
+ gen_vfp_absd,
+};
+TRANS(FABS_s, do_fp1_scalar_int, a, &f_scalar_fabs)
-/* LSLV, LSRV, ASRV, RORV */
-static void handle_shift_reg(DisasContext *s,
- enum a64_shift_type shift_type, unsigned int sf,
- unsigned int rm, unsigned int rn, unsigned int rd)
-{
- TCGv_i64 tcg_shift = tcg_temp_new_i64();
- TCGv_i64 tcg_rd = cpu_reg(s, rd);
- TCGv_i64 tcg_rn = read_cpu_reg(s, rn, sf);
+static const FPScalar1Int f_scalar_fneg = {
+ gen_vfp_negh,
+ gen_vfp_negs,
+ gen_vfp_negd,
+};
+TRANS(FNEG_s, do_fp1_scalar_int, a, &f_scalar_fneg)
- tcg_gen_andi_i64(tcg_shift, cpu_reg(s, rm), sf ? 63 : 31);
- shift_reg(tcg_rd, tcg_rn, sf, shift_type, tcg_shift);
-}
+typedef struct FPScalar1 {
+ void (*gen_h)(TCGv_i32, TCGv_i32, TCGv_ptr);
+ void (*gen_s)(TCGv_i32, TCGv_i32, TCGv_ptr);
+ void (*gen_d)(TCGv_i64, TCGv_i64, TCGv_ptr);
+} FPScalar1;
-/* CRC32[BHWX], CRC32C[BHWX] */
-static void handle_crc32(DisasContext *s,
- unsigned int sf, unsigned int sz, bool crc32c,
- unsigned int rm, unsigned int rn, unsigned int rd)
+static bool do_fp1_scalar(DisasContext *s, arg_rr_e *a,
+ const FPScalar1 *f, int rmode)
{
- TCGv_i64 tcg_acc, tcg_val;
- TCGv_i32 tcg_bytes;
-
- if (!dc_isar_feature(aa64_crc32, s)
- || (sf == 1 && sz != 3)
- || (sf == 0 && sz == 3)) {
- unallocated_encoding(s);
- return;
- }
-
- if (sz == 3) {
- tcg_val = cpu_reg(s, rm);
- } else {
- uint64_t mask;
- switch (sz) {
- case 0:
- mask = 0xFF;
- break;
- case 1:
- mask = 0xFFFF;
- break;
- case 2:
- mask = 0xFFFFFFFF;
- break;
- default:
- g_assert_not_reached();
- }
- tcg_val = tcg_temp_new_i64();
- tcg_gen_andi_i64(tcg_val, cpu_reg(s, rm), mask);
- }
-
- tcg_acc = cpu_reg(s, rn);
- tcg_bytes = tcg_constant_i32(1 << sz);
+ TCGv_i32 tcg_rmode = NULL;
+ TCGv_ptr fpst;
+ TCGv_i64 t64;
+ TCGv_i32 t32;
+ int check = fp_access_check_scalar_hsd(s, a->esz);
- if (crc32c) {
- gen_helper_crc32c_64(cpu_reg(s, rd), tcg_acc, tcg_val, tcg_bytes);
- } else {
- gen_helper_crc32_64(cpu_reg(s, rd), tcg_acc, tcg_val, tcg_bytes);
+ if (check <= 0) {
+ return check == 0;
}
-}
-
-/* Data-processing (2 source)
- * 31 30 29 28 21 20 16 15 10 9 5 4 0
- * +----+---+---+-----------------+------+--------+------+------+
- * | sf | 0 | S | 1 1 0 1 0 1 1 0 | Rm | opcode | Rn | Rd |
- * +----+---+---+-----------------+------+--------+------+------+
- */
-static void disas_data_proc_2src(DisasContext *s, uint32_t insn)
-{
- unsigned int sf, rm, opcode, rn, rd, setflag;
- sf = extract32(insn, 31, 1);
- setflag = extract32(insn, 29, 1);
- rm = extract32(insn, 16, 5);
- opcode = extract32(insn, 10, 6);
- rn = extract32(insn, 5, 5);
- rd = extract32(insn, 0, 5);
- if (setflag && opcode != 0) {
- unallocated_encoding(s);
- return;
+ fpst = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR);
+ if (rmode >= 0) {
+ tcg_rmode = gen_set_rmode(rmode, fpst);
}
- switch (opcode) {
- case 0: /* SUBP(S) */
- if (sf == 0 || !dc_isar_feature(aa64_mte_insn_reg, s)) {
- goto do_unallocated;
- } else {
- TCGv_i64 tcg_n, tcg_m, tcg_d;
-
- tcg_n = read_cpu_reg_sp(s, rn, true);
- tcg_m = read_cpu_reg_sp(s, rm, true);
- tcg_gen_sextract_i64(tcg_n, tcg_n, 0, 56);
- tcg_gen_sextract_i64(tcg_m, tcg_m, 0, 56);
- tcg_d = cpu_reg(s, rd);
-
- if (setflag) {
- gen_sub_CC(true, tcg_d, tcg_n, tcg_m);
- } else {
- tcg_gen_sub_i64(tcg_d, tcg_n, tcg_m);
- }
- }
- break;
- case 2: /* UDIV */
- handle_div(s, false, sf, rm, rn, rd);
- break;
- case 3: /* SDIV */
- handle_div(s, true, sf, rm, rn, rd);
- break;
- case 4: /* IRG */
- if (sf == 0 || !dc_isar_feature(aa64_mte_insn_reg, s)) {
- goto do_unallocated;
- }
- if (s->ata[0]) {
- gen_helper_irg(cpu_reg_sp(s, rd), tcg_env,
- cpu_reg_sp(s, rn), cpu_reg(s, rm));
- } else {
- gen_address_with_allocation_tag0(cpu_reg_sp(s, rd),
- cpu_reg_sp(s, rn));
- }
- break;
- case 5: /* GMI */
- if (sf == 0 || !dc_isar_feature(aa64_mte_insn_reg, s)) {
- goto do_unallocated;
- } else {
- TCGv_i64 t = tcg_temp_new_i64();
-
- tcg_gen_extract_i64(t, cpu_reg_sp(s, rn), 56, 4);
- tcg_gen_shl_i64(t, tcg_constant_i64(1), t);
- tcg_gen_or_i64(cpu_reg(s, rd), cpu_reg(s, rm), t);
- }
- break;
- case 8: /* LSLV */
- handle_shift_reg(s, A64_SHIFT_TYPE_LSL, sf, rm, rn, rd);
- break;
- case 9: /* LSRV */
- handle_shift_reg(s, A64_SHIFT_TYPE_LSR, sf, rm, rn, rd);
- break;
- case 10: /* ASRV */
- handle_shift_reg(s, A64_SHIFT_TYPE_ASR, sf, rm, rn, rd);
- break;
- case 11: /* RORV */
- handle_shift_reg(s, A64_SHIFT_TYPE_ROR, sf, rm, rn, rd);
+ switch (a->esz) {
+ case MO_64:
+ t64 = read_fp_dreg(s, a->rn);
+ f->gen_d(t64, t64, fpst);
+ write_fp_dreg(s, a->rd, t64);
break;
- case 12: /* PACGA */
- if (sf == 0 || !dc_isar_feature(aa64_pauth, s)) {
- goto do_unallocated;
- }
- gen_helper_pacga(cpu_reg(s, rd), tcg_env,
- cpu_reg(s, rn), cpu_reg_sp(s, rm));
+ case MO_32:
+ t32 = read_fp_sreg(s, a->rn);
+ f->gen_s(t32, t32, fpst);
+ write_fp_sreg(s, a->rd, t32);
break;
- case 16:
- case 17:
- case 18:
- case 19:
- case 20:
- case 21:
- case 22:
- case 23: /* CRC32 */
- {
- int sz = extract32(opcode, 0, 2);
- bool crc32c = extract32(opcode, 2, 1);
- handle_crc32(s, sf, sz, crc32c, rm, rn, rd);
+ case MO_16:
+ t32 = read_fp_hreg(s, a->rn);
+ f->gen_h(t32, t32, fpst);
+ write_fp_sreg(s, a->rd, t32);
break;
- }
default:
- do_unallocated:
- unallocated_encoding(s);
- break;
+ g_assert_not_reached();
}
-}
-/*
- * Data processing - register
- * 31 30 29 28 25 21 20 16 10 0
- * +--+---+--+---+-------+-----+-------+-------+---------+
- * | |op0| |op1| 1 0 1 | op2 | | op3 | |
- * +--+---+--+---+-------+-----+-------+-------+---------+
- */
-static void disas_data_proc_reg(DisasContext *s, uint32_t insn)
-{
- int op0 = extract32(insn, 30, 1);
- int op1 = extract32(insn, 28, 1);
- int op2 = extract32(insn, 21, 4);
- int op3 = extract32(insn, 10, 6);
-
- if (!op1) {
- if (op2 & 8) {
- if (op2 & 1) {
- /* Add/sub (extended register) */
- disas_add_sub_ext_reg(s, insn);
- } else {
- /* Add/sub (shifted register) */
- disas_add_sub_reg(s, insn);
- }
- } else {
- /* Logical (shifted register) */
- disas_logic_reg(s, insn);
- }
- return;
+ if (rmode >= 0) {
+ gen_restore_rmode(tcg_rmode, fpst);
}
+ return true;
+}
- switch (op2) {
- case 0x0:
- switch (op3) {
- case 0x00: /* Add/subtract (with carry) */
- disas_adc_sbc(s, insn);
- break;
+static const FPScalar1 f_scalar_fsqrt = {
+ gen_helper_vfp_sqrth,
+ gen_helper_vfp_sqrts,
+ gen_helper_vfp_sqrtd,
+};
+TRANS(FSQRT_s, do_fp1_scalar, a, &f_scalar_fsqrt, -1)
- case 0x01: /* Rotate right into flags */
- case 0x21:
- disas_rotate_right_into_flags(s, insn);
- break;
+static const FPScalar1 f_scalar_frint = {
+ gen_helper_advsimd_rinth,
+ gen_helper_rints,
+ gen_helper_rintd,
+};
+TRANS(FRINTN_s, do_fp1_scalar, a, &f_scalar_frint, FPROUNDING_TIEEVEN)
+TRANS(FRINTP_s, do_fp1_scalar, a, &f_scalar_frint, FPROUNDING_POSINF)
+TRANS(FRINTM_s, do_fp1_scalar, a, &f_scalar_frint, FPROUNDING_NEGINF)
+TRANS(FRINTZ_s, do_fp1_scalar, a, &f_scalar_frint, FPROUNDING_ZERO)
+TRANS(FRINTA_s, do_fp1_scalar, a, &f_scalar_frint, FPROUNDING_TIEAWAY)
+TRANS(FRINTI_s, do_fp1_scalar, a, &f_scalar_frint, -1)
+
+static const FPScalar1 f_scalar_frintx = {
+ gen_helper_advsimd_rinth_exact,
+ gen_helper_rints_exact,
+ gen_helper_rintd_exact,
+};
+TRANS(FRINTX_s, do_fp1_scalar, a, &f_scalar_frintx, -1)
- case 0x02: /* Evaluate into flags */
- case 0x12:
- case 0x22:
- case 0x32:
- disas_evaluate_into_flags(s, insn);
- break;
+static const FPScalar1 f_scalar_bfcvt = {
+ .gen_s = gen_helper_bfcvt,
+};
+TRANS_FEAT(BFCVT_s, aa64_bf16, do_fp1_scalar, a, &f_scalar_bfcvt, -1)
- default:
- goto do_unallocated;
- }
- break;
+static const FPScalar1 f_scalar_frint32 = {
+ NULL,
+ gen_helper_frint32_s,
+ gen_helper_frint32_d,
+};
+TRANS_FEAT(FRINT32Z_s, aa64_frint, do_fp1_scalar, a,
+ &f_scalar_frint32, FPROUNDING_ZERO)
+TRANS_FEAT(FRINT32X_s, aa64_frint, do_fp1_scalar, a, &f_scalar_frint32, -1)
+
+static const FPScalar1 f_scalar_frint64 = {
+ NULL,
+ gen_helper_frint64_s,
+ gen_helper_frint64_d,
+};
+TRANS_FEAT(FRINT64Z_s, aa64_frint, do_fp1_scalar, a,
+ &f_scalar_frint64, FPROUNDING_ZERO)
+TRANS_FEAT(FRINT64X_s, aa64_frint, do_fp1_scalar, a, &f_scalar_frint64, -1)
+
+static const FPScalar1 f_scalar_frecpe = {
+ gen_helper_recpe_f16,
+ gen_helper_recpe_f32,
+ gen_helper_recpe_f64,
+};
+TRANS(FRECPE_s, do_fp1_scalar, a, &f_scalar_frecpe, -1)
- case 0x2: /* Conditional compare */
- disas_cc(s, insn); /* both imm and reg forms */
- break;
+static const FPScalar1 f_scalar_frecpx = {
+ gen_helper_frecpx_f16,
+ gen_helper_frecpx_f32,
+ gen_helper_frecpx_f64,
+};
+TRANS(FRECPX_s, do_fp1_scalar, a, &f_scalar_frecpx, -1)
- case 0x4: /* Conditional select */
- disas_cond_select(s, insn);
- break;
+static const FPScalar1 f_scalar_frsqrte = {
+ gen_helper_rsqrte_f16,
+ gen_helper_rsqrte_f32,
+ gen_helper_rsqrte_f64,
+};
+TRANS(FRSQRTE_s, do_fp1_scalar, a, &f_scalar_frsqrte, -1)
- case 0x6: /* Data-processing */
- if (op0) { /* (1 source) */
- disas_data_proc_1src(s, insn);
- } else { /* (2 source) */
- disas_data_proc_2src(s, insn);
- }
- break;
- case 0x8 ... 0xf: /* (3 source) */
- disas_data_proc_3src(s, insn);
- break;
+static bool trans_FCVT_s_ds(DisasContext *s, arg_rr *a)
+{
+ if (fp_access_check(s)) {
+ TCGv_i32 tcg_rn = read_fp_sreg(s, a->rn);
+ TCGv_i64 tcg_rd = tcg_temp_new_i64();
- default:
- do_unallocated:
- unallocated_encoding(s);
- break;
+ gen_helper_vfp_fcvtds(tcg_rd, tcg_rn, tcg_env);
+ write_fp_dreg(s, a->rd, tcg_rd);
}
+ return true;
}
-static void handle_fp_compare(DisasContext *s, int size,
- unsigned int rn, unsigned int rm,
- bool cmp_with_zero, bool signal_all_nans)
+static bool trans_FCVT_s_hs(DisasContext *s, arg_rr *a)
{
- TCGv_i64 tcg_flags = tcg_temp_new_i64();
- TCGv_ptr fpst = fpstatus_ptr(size == MO_16 ? FPST_FPCR_F16 : FPST_FPCR);
-
- if (size == MO_64) {
- TCGv_i64 tcg_vn, tcg_vm;
-
- tcg_vn = read_fp_dreg(s, rn);
- if (cmp_with_zero) {
- tcg_vm = tcg_constant_i64(0);
- } else {
- tcg_vm = read_fp_dreg(s, rm);
- }
- if (signal_all_nans) {
- gen_helper_vfp_cmped_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
- } else {
- gen_helper_vfp_cmpd_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
- }
- } else {
- TCGv_i32 tcg_vn = tcg_temp_new_i32();
- TCGv_i32 tcg_vm = tcg_temp_new_i32();
-
- read_vec_element_i32(s, tcg_vn, rn, 0, size);
- if (cmp_with_zero) {
- tcg_gen_movi_i32(tcg_vm, 0);
- } else {
- read_vec_element_i32(s, tcg_vm, rm, 0, size);
- }
+ if (fp_access_check(s)) {
+ TCGv_i32 tmp = read_fp_sreg(s, a->rn);
+ TCGv_i32 ahp = get_ahp_flag();
+ TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
- switch (size) {
- case MO_32:
- if (signal_all_nans) {
- gen_helper_vfp_cmpes_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
- } else {
- gen_helper_vfp_cmps_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
- }
- break;
- case MO_16:
- if (signal_all_nans) {
- gen_helper_vfp_cmpeh_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
- } else {
- gen_helper_vfp_cmph_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
- }
- break;
- default:
- g_assert_not_reached();
- }
+ gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp);
+ /* write_fp_sreg is OK here because top half of result is zero */
+ write_fp_sreg(s, a->rd, tmp);
}
-
- gen_set_nzcv(tcg_flags);
+ return true;
}
-/* Floating point compare
- * 31 30 29 28 24 23 22 21 20 16 15 14 13 10 9 5 4 0
- * +---+---+---+-----------+------+---+------+-----+---------+------+-------+
- * | M | 0 | S | 1 1 1 1 0 | type | 1 | Rm | op | 1 0 0 0 | Rn | op2 |
- * +---+---+---+-----------+------+---+------+-----+---------+------+-------+
- */
-static void disas_fp_compare(DisasContext *s, uint32_t insn)
+static bool trans_FCVT_s_sd(DisasContext *s, arg_rr *a)
{
- unsigned int mos, type, rm, op, rn, opc, op2r;
- int size;
-
- mos = extract32(insn, 29, 3);
- type = extract32(insn, 22, 2);
- rm = extract32(insn, 16, 5);
- op = extract32(insn, 14, 2);
- rn = extract32(insn, 5, 5);
- opc = extract32(insn, 3, 2);
- op2r = extract32(insn, 0, 3);
-
- if (mos || op || op2r) {
- unallocated_encoding(s);
- return;
- }
-
- switch (type) {
- case 0:
- size = MO_32;
- break;
- case 1:
- size = MO_64;
- break;
- case 3:
- size = MO_16;
- if (dc_isar_feature(aa64_fp16, s)) {
- break;
- }
- /* fallthru */
- default:
- unallocated_encoding(s);
- return;
- }
+ if (fp_access_check(s)) {
+ TCGv_i64 tcg_rn = read_fp_dreg(s, a->rn);
+ TCGv_i32 tcg_rd = tcg_temp_new_i32();
- if (!fp_access_check(s)) {
- return;
+ gen_helper_vfp_fcvtsd(tcg_rd, tcg_rn, tcg_env);
+ write_fp_sreg(s, a->rd, tcg_rd);
}
-
- handle_fp_compare(s, size, rn, rm, opc & 1, opc & 2);
+ return true;
}
-/* Floating point conditional compare
- * 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 3 0
- * +---+---+---+-----------+------+---+------+------+-----+------+----+------+
- * | M | 0 | S | 1 1 1 1 0 | type | 1 | Rm | cond | 0 1 | Rn | op | nzcv |
- * +---+---+---+-----------+------+---+------+------+-----+------+----+------+
- */
-static void disas_fp_ccomp(DisasContext *s, uint32_t insn)
+static bool trans_FCVT_s_hd(DisasContext *s, arg_rr *a)
{
- unsigned int mos, type, rm, cond, rn, op, nzcv;
- TCGLabel *label_continue = NULL;
- int size;
-
- mos = extract32(insn, 29, 3);
- type = extract32(insn, 22, 2);
- rm = extract32(insn, 16, 5);
- cond = extract32(insn, 12, 4);
- rn = extract32(insn, 5, 5);
- op = extract32(insn, 4, 1);
- nzcv = extract32(insn, 0, 4);
-
- if (mos) {
- unallocated_encoding(s);
- return;
- }
-
- switch (type) {
- case 0:
- size = MO_32;
- break;
- case 1:
- size = MO_64;
- break;
- case 3:
- size = MO_16;
- if (dc_isar_feature(aa64_fp16, s)) {
- break;
- }
- /* fallthru */
- default:
- unallocated_encoding(s);
- return;
- }
-
- if (!fp_access_check(s)) {
- return;
- }
-
- if (cond < 0x0e) { /* not always */
- TCGLabel *label_match = gen_new_label();
- label_continue = gen_new_label();
- arm_gen_test_cc(cond, label_match);
- /* nomatch: */
- gen_set_nzcv(tcg_constant_i64(nzcv << 28));
- tcg_gen_br(label_continue);
- gen_set_label(label_match);
- }
-
- handle_fp_compare(s, size, rn, rm, false, op);
+ if (fp_access_check(s)) {
+ TCGv_i64 tcg_rn = read_fp_dreg(s, a->rn);
+ TCGv_i32 tcg_rd = tcg_temp_new_i32();
+ TCGv_i32 ahp = get_ahp_flag();
+ TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
- if (cond < 0x0e) {
- gen_set_label(label_continue);
+ gen_helper_vfp_fcvt_f64_to_f16(tcg_rd, tcg_rn, fpst, ahp);
+ /* write_fp_sreg is OK here because top half of tcg_rd is zero */
+ write_fp_sreg(s, a->rd, tcg_rd);
}
+ return true;
}
-/* Floating-point data-processing (1 source) - half precision */
-static void handle_fp_1src_half(DisasContext *s, int opcode, int rd, int rn)
+static bool trans_FCVT_s_sh(DisasContext *s, arg_rr *a)
{
- TCGv_ptr fpst = NULL;
- TCGv_i32 tcg_op = read_fp_hreg(s, rn);
- TCGv_i32 tcg_res = tcg_temp_new_i32();
-
- switch (opcode) {
- case 0x0: /* FMOV */
- tcg_gen_mov_i32(tcg_res, tcg_op);
- break;
- case 0x1: /* FABS */
- gen_vfp_absh(tcg_res, tcg_op);
- break;
- case 0x2: /* FNEG */
- gen_vfp_negh(tcg_res, tcg_op);
- break;
- case 0x3: /* FSQRT */
- fpst = fpstatus_ptr(FPST_FPCR_F16);
- gen_helper_sqrt_f16(tcg_res, tcg_op, fpst);
- break;
- case 0x8: /* FRINTN */
- case 0x9: /* FRINTP */
- case 0xa: /* FRINTM */
- case 0xb: /* FRINTZ */
- case 0xc: /* FRINTA */
- {
- TCGv_i32 tcg_rmode;
+ if (fp_access_check(s)) {
+ TCGv_i32 tcg_rn = read_fp_hreg(s, a->rn);
+ TCGv_i32 tcg_rd = tcg_temp_new_i32();
+ TCGv_ptr tcg_fpst = fpstatus_ptr(FPST_FPCR);
+ TCGv_i32 tcg_ahp = get_ahp_flag();
- fpst = fpstatus_ptr(FPST_FPCR_F16);
- tcg_rmode = gen_set_rmode(opcode & 7, fpst);
- gen_helper_advsimd_rinth(tcg_res, tcg_op, fpst);
- gen_restore_rmode(tcg_rmode, fpst);
- break;
- }
- case 0xe: /* FRINTX */
- fpst = fpstatus_ptr(FPST_FPCR_F16);
- gen_helper_advsimd_rinth_exact(tcg_res, tcg_op, fpst);
- break;
- case 0xf: /* FRINTI */
- fpst = fpstatus_ptr(FPST_FPCR_F16);
- gen_helper_advsimd_rinth(tcg_res, tcg_op, fpst);
- break;
- default:
- g_assert_not_reached();
+ gen_helper_vfp_fcvt_f16_to_f32(tcg_rd, tcg_rn, tcg_fpst, tcg_ahp);
+ write_fp_sreg(s, a->rd, tcg_rd);
}
-
- write_fp_sreg(s, rd, tcg_res);
+ return true;
}
-/* Floating-point data-processing (1 source) - single precision */
-static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn)
+static bool trans_FCVT_s_dh(DisasContext *s, arg_rr *a)
{
- void (*gen_fpst)(TCGv_i32, TCGv_i32, TCGv_ptr);
- TCGv_i32 tcg_op, tcg_res;
- TCGv_ptr fpst;
- int rmode = -1;
-
- tcg_op = read_fp_sreg(s, rn);
- tcg_res = tcg_temp_new_i32();
-
- switch (opcode) {
- case 0x0: /* FMOV */
- tcg_gen_mov_i32(tcg_res, tcg_op);
- goto done;
- case 0x1: /* FABS */
- gen_vfp_abss(tcg_res, tcg_op);
- goto done;
- case 0x2: /* FNEG */
- gen_vfp_negs(tcg_res, tcg_op);
- goto done;
- case 0x3: /* FSQRT */
- gen_helper_vfp_sqrts(tcg_res, tcg_op, tcg_env);
- goto done;
- case 0x6: /* BFCVT */
- gen_fpst = gen_helper_bfcvt;
- break;
- case 0x8: /* FRINTN */
- case 0x9: /* FRINTP */
- case 0xa: /* FRINTM */
- case 0xb: /* FRINTZ */
- case 0xc: /* FRINTA */
- rmode = opcode & 7;
- gen_fpst = gen_helper_rints;
- break;
- case 0xe: /* FRINTX */
- gen_fpst = gen_helper_rints_exact;
- break;
- case 0xf: /* FRINTI */
- gen_fpst = gen_helper_rints;
- break;
- case 0x10: /* FRINT32Z */
- rmode = FPROUNDING_ZERO;
- gen_fpst = gen_helper_frint32_s;
- break;
- case 0x11: /* FRINT32X */
- gen_fpst = gen_helper_frint32_s;
- break;
- case 0x12: /* FRINT64Z */
- rmode = FPROUNDING_ZERO;
- gen_fpst = gen_helper_frint64_s;
- break;
- case 0x13: /* FRINT64X */
- gen_fpst = gen_helper_frint64_s;
- break;
- default:
- g_assert_not_reached();
- }
+ if (fp_access_check(s)) {
+ TCGv_i32 tcg_rn = read_fp_hreg(s, a->rn);
+ TCGv_i64 tcg_rd = tcg_temp_new_i64();
+ TCGv_ptr tcg_fpst = fpstatus_ptr(FPST_FPCR);
+ TCGv_i32 tcg_ahp = get_ahp_flag();
- fpst = fpstatus_ptr(FPST_FPCR);
- if (rmode >= 0) {
- TCGv_i32 tcg_rmode = gen_set_rmode(rmode, fpst);
- gen_fpst(tcg_res, tcg_op, fpst);
- gen_restore_rmode(tcg_rmode, fpst);
- } else {
- gen_fpst(tcg_res, tcg_op, fpst);
+ gen_helper_vfp_fcvt_f16_to_f64(tcg_rd, tcg_rn, tcg_fpst, tcg_ahp);
+ write_fp_dreg(s, a->rd, tcg_rd);
}
-
- done:
- write_fp_sreg(s, rd, tcg_res);
+ return true;
}
-/* Floating-point data-processing (1 source) - double precision */
-static void handle_fp_1src_double(DisasContext *s, int opcode, int rd, int rn)
+static bool do_cvtf_scalar(DisasContext *s, MemOp esz, int rd, int shift,
+ TCGv_i64 tcg_int, bool is_signed)
{
- void (*gen_fpst)(TCGv_i64, TCGv_i64, TCGv_ptr);
- TCGv_i64 tcg_op, tcg_res;
- TCGv_ptr fpst;
- int rmode = -1;
-
- switch (opcode) {
- case 0x0: /* FMOV */
- gen_gvec_fn2(s, false, rd, rn, tcg_gen_gvec_mov, 0);
- return;
- }
-
- tcg_op = read_fp_dreg(s, rn);
- tcg_res = tcg_temp_new_i64();
-
- switch (opcode) {
- case 0x1: /* FABS */
- gen_vfp_absd(tcg_res, tcg_op);
- goto done;
- case 0x2: /* FNEG */
- gen_vfp_negd(tcg_res, tcg_op);
- goto done;
- case 0x3: /* FSQRT */
- gen_helper_vfp_sqrtd(tcg_res, tcg_op, tcg_env);
- goto done;
- case 0x8: /* FRINTN */
- case 0x9: /* FRINTP */
- case 0xa: /* FRINTM */
- case 0xb: /* FRINTZ */
- case 0xc: /* FRINTA */
- rmode = opcode & 7;
- gen_fpst = gen_helper_rintd;
- break;
- case 0xe: /* FRINTX */
- gen_fpst = gen_helper_rintd_exact;
- break;
- case 0xf: /* FRINTI */
- gen_fpst = gen_helper_rintd;
- break;
- case 0x10: /* FRINT32Z */
- rmode = FPROUNDING_ZERO;
- gen_fpst = gen_helper_frint32_d;
- break;
- case 0x11: /* FRINT32X */
- gen_fpst = gen_helper_frint32_d;
- break;
- case 0x12: /* FRINT64Z */
- rmode = FPROUNDING_ZERO;
- gen_fpst = gen_helper_frint64_d;
- break;
- case 0x13: /* FRINT64X */
- gen_fpst = gen_helper_frint64_d;
- break;
- default:
- g_assert_not_reached();
- }
-
- fpst = fpstatus_ptr(FPST_FPCR);
- if (rmode >= 0) {
- TCGv_i32 tcg_rmode = gen_set_rmode(rmode, fpst);
- gen_fpst(tcg_res, tcg_op, fpst);
- gen_restore_rmode(tcg_rmode, fpst);
- } else {
- gen_fpst(tcg_res, tcg_op, fpst);
- }
+ TCGv_ptr tcg_fpstatus;
+ TCGv_i32 tcg_shift, tcg_single;
+ TCGv_i64 tcg_double;
- done:
- write_fp_dreg(s, rd, tcg_res);
-}
+ tcg_fpstatus = fpstatus_ptr(esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR);
+ tcg_shift = tcg_constant_i32(shift);
-static void handle_fp_fcvt(DisasContext *s, int opcode,
- int rd, int rn, int dtype, int ntype)
-{
- switch (ntype) {
- case 0x0:
- {
- TCGv_i32 tcg_rn = read_fp_sreg(s, rn);
- if (dtype == 1) {
- /* Single to double */
- TCGv_i64 tcg_rd = tcg_temp_new_i64();
- gen_helper_vfp_fcvtds(tcg_rd, tcg_rn, tcg_env);
- write_fp_dreg(s, rd, tcg_rd);
+ switch (esz) {
+ case MO_64:
+ tcg_double = tcg_temp_new_i64();
+ if (is_signed) {
+ gen_helper_vfp_sqtod(tcg_double, tcg_int, tcg_shift, tcg_fpstatus);
} else {
- /* Single to half */
- TCGv_i32 tcg_rd = tcg_temp_new_i32();
- TCGv_i32 ahp = get_ahp_flag();
- TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
-
- gen_helper_vfp_fcvt_f32_to_f16(tcg_rd, tcg_rn, fpst, ahp);
- /* write_fp_sreg is OK here because top half of tcg_rd is zero */
- write_fp_sreg(s, rd, tcg_rd);
+ gen_helper_vfp_uqtod(tcg_double, tcg_int, tcg_shift, tcg_fpstatus);
}
+ write_fp_dreg(s, rd, tcg_double);
break;
- }
- case 0x1:
- {
- TCGv_i64 tcg_rn = read_fp_dreg(s, rn);
- TCGv_i32 tcg_rd = tcg_temp_new_i32();
- if (dtype == 0) {
- /* Double to single */
- gen_helper_vfp_fcvtsd(tcg_rd, tcg_rn, tcg_env);
+
+ case MO_32:
+ tcg_single = tcg_temp_new_i32();
+ if (is_signed) {
+ gen_helper_vfp_sqtos(tcg_single, tcg_int, tcg_shift, tcg_fpstatus);
} else {
- TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
- TCGv_i32 ahp = get_ahp_flag();
- /* Double to half */
- gen_helper_vfp_fcvt_f64_to_f16(tcg_rd, tcg_rn, fpst, ahp);
- /* write_fp_sreg is OK here because top half of tcg_rd is zero */
+ gen_helper_vfp_uqtos(tcg_single, tcg_int, tcg_shift, tcg_fpstatus);
}
- write_fp_sreg(s, rd, tcg_rd);
+ write_fp_sreg(s, rd, tcg_single);
break;
- }
- case 0x3:
- {
- TCGv_i32 tcg_rn = read_fp_sreg(s, rn);
- TCGv_ptr tcg_fpst = fpstatus_ptr(FPST_FPCR);
- TCGv_i32 tcg_ahp = get_ahp_flag();
- tcg_gen_ext16u_i32(tcg_rn, tcg_rn);
- if (dtype == 0) {
- /* Half to single */
- TCGv_i32 tcg_rd = tcg_temp_new_i32();
- gen_helper_vfp_fcvt_f16_to_f32(tcg_rd, tcg_rn, tcg_fpst, tcg_ahp);
- write_fp_sreg(s, rd, tcg_rd);
+
+ case MO_16:
+ tcg_single = tcg_temp_new_i32();
+ if (is_signed) {
+ gen_helper_vfp_sqtoh(tcg_single, tcg_int, tcg_shift, tcg_fpstatus);
} else {
- /* Half to double */
- TCGv_i64 tcg_rd = tcg_temp_new_i64();
- gen_helper_vfp_fcvt_f16_to_f64(tcg_rd, tcg_rn, tcg_fpst, tcg_ahp);
- write_fp_dreg(s, rd, tcg_rd);
+ gen_helper_vfp_uqtoh(tcg_single, tcg_int, tcg_shift, tcg_fpstatus);
}
+ write_fp_sreg(s, rd, tcg_single);
break;
- }
+
default:
g_assert_not_reached();
}
+ return true;
}
-/* Floating point data-processing (1 source)
- * 31 30 29 28 24 23 22 21 20 15 14 10 9 5 4 0
- * +---+---+---+-----------+------+---+--------+-----------+------+------+
- * | M | 0 | S | 1 1 1 1 0 | type | 1 | opcode | 1 0 0 0 0 | Rn | Rd |
- * +---+---+---+-----------+------+---+--------+-----------+------+------+
- */
-static void disas_fp_1src(DisasContext *s, uint32_t insn)
+static bool do_cvtf_g(DisasContext *s, arg_fcvt *a, bool is_signed)
{
- int mos = extract32(insn, 29, 3);
- int type = extract32(insn, 22, 2);
- int opcode = extract32(insn, 15, 6);
- int rn = extract32(insn, 5, 5);
- int rd = extract32(insn, 0, 5);
-
- if (mos) {
- goto do_unallocated;
- }
-
- switch (opcode) {
- case 0x4: case 0x5: case 0x7:
- {
- /* FCVT between half, single and double precision */
- int dtype = extract32(opcode, 0, 2);
- if (type == 2 || dtype == type) {
- goto do_unallocated;
- }
- if (!fp_access_check(s)) {
- return;
- }
+ TCGv_i64 tcg_int;
+ int check = fp_access_check_scalar_hsd(s, a->esz);
- handle_fp_fcvt(s, opcode, rd, rn, dtype, type);
- break;
+ if (check <= 0) {
+ return check == 0;
}
- case 0x10 ... 0x13: /* FRINT{32,64}{X,Z} */
- if (type > 1 || !dc_isar_feature(aa64_frint, s)) {
- goto do_unallocated;
- }
- /* fall through */
- case 0x0 ... 0x3:
- case 0x8 ... 0xc:
- case 0xe ... 0xf:
- /* 32-to-32 and 64-to-64 ops */
- switch (type) {
- case 0:
- if (!fp_access_check(s)) {
- return;
- }
- handle_fp_1src_single(s, opcode, rd, rn);
- break;
- case 1:
- if (!fp_access_check(s)) {
- return;
- }
- handle_fp_1src_double(s, opcode, rd, rn);
- break;
- case 3:
- if (!dc_isar_feature(aa64_fp16, s)) {
- goto do_unallocated;
- }
-
- if (!fp_access_check(s)) {
- return;
- }
- handle_fp_1src_half(s, opcode, rd, rn);
- break;
- default:
- goto do_unallocated;
- }
- break;
-
- case 0x6:
- switch (type) {
- case 1: /* BFCVT */
- if (!dc_isar_feature(aa64_bf16, s)) {
- goto do_unallocated;
- }
- if (!fp_access_check(s)) {
- return;
- }
- handle_fp_1src_single(s, opcode, rd, rn);
- break;
- default:
- goto do_unallocated;
+ if (a->sf) {
+ tcg_int = cpu_reg(s, a->rn);
+ } else {
+ tcg_int = read_cpu_reg(s, a->rn, true);
+ if (is_signed) {
+ tcg_gen_ext32s_i64(tcg_int, tcg_int);
+ } else {
+ tcg_gen_ext32u_i64(tcg_int, tcg_int);
}
- break;
-
- default:
- do_unallocated:
- unallocated_encoding(s);
- break;
}
+ return do_cvtf_scalar(s, a->esz, a->rd, a->shift, tcg_int, is_signed);
}
-/* Handle floating point <=> fixed point conversions. Note that we can
- * also deal with fp <=> integer conversions as a special case (scale == 64)
- * OPTME: consider handling that special case specially or at least skipping
- * the call to scalbn in the helpers for zero shifts.
+TRANS(SCVTF_g, do_cvtf_g, a, true)
+TRANS(UCVTF_g, do_cvtf_g, a, false)
+
+/*
+ * [US]CVTF (vector), scalar version.
+ * Which sounds weird, but really just means input from fp register
+ * instead of input from general register. Input and output element
+ * size are always equal.
*/
-static void handle_fpfpcvt(DisasContext *s, int rd, int rn, int opcode,
- bool itof, int rmode, int scale, int sf, int type)
+static bool do_cvtf_f(DisasContext *s, arg_fcvt *a, bool is_signed)
{
- bool is_signed = !(opcode & 1);
- TCGv_ptr tcg_fpstatus;
- TCGv_i32 tcg_shift, tcg_single;
- TCGv_i64 tcg_double;
-
- tcg_fpstatus = fpstatus_ptr(type == 3 ? FPST_FPCR_F16 : FPST_FPCR);
-
- tcg_shift = tcg_constant_i32(64 - scale);
+ TCGv_i64 tcg_int;
+ int check = fp_access_check_scalar_hsd(s, a->esz);
- if (itof) {
- TCGv_i64 tcg_int = cpu_reg(s, rn);
- if (!sf) {
- TCGv_i64 tcg_extend = tcg_temp_new_i64();
+ if (check <= 0) {
+ return check == 0;
+ }
- if (is_signed) {
- tcg_gen_ext32s_i64(tcg_extend, tcg_int);
- } else {
- tcg_gen_ext32u_i64(tcg_extend, tcg_int);
- }
+ tcg_int = tcg_temp_new_i64();
+ read_vec_element(s, tcg_int, a->rn, 0, a->esz | (is_signed ? MO_SIGN : 0));
+ return do_cvtf_scalar(s, a->esz, a->rd, a->shift, tcg_int, is_signed);
+}
- tcg_int = tcg_extend;
- }
+TRANS(SCVTF_f, do_cvtf_f, a, true)
+TRANS(UCVTF_f, do_cvtf_f, a, false)
- switch (type) {
- case 1: /* float64 */
- tcg_double = tcg_temp_new_i64();
- if (is_signed) {
- gen_helper_vfp_sqtod(tcg_double, tcg_int,
- tcg_shift, tcg_fpstatus);
- } else {
- gen_helper_vfp_uqtod(tcg_double, tcg_int,
- tcg_shift, tcg_fpstatus);
- }
- write_fp_dreg(s, rd, tcg_double);
- break;
+static void do_fcvt_scalar(DisasContext *s, MemOp out, MemOp esz,
+ TCGv_i64 tcg_out, int shift, int rn,
+ ARMFPRounding rmode)
+{
+ TCGv_ptr tcg_fpstatus;
+ TCGv_i32 tcg_shift, tcg_rmode, tcg_single;
- case 0: /* float32 */
- tcg_single = tcg_temp_new_i32();
- if (is_signed) {
- gen_helper_vfp_sqtos(tcg_single, tcg_int,
- tcg_shift, tcg_fpstatus);
- } else {
- gen_helper_vfp_uqtos(tcg_single, tcg_int,
- tcg_shift, tcg_fpstatus);
- }
- write_fp_sreg(s, rd, tcg_single);
- break;
+ tcg_fpstatus = fpstatus_ptr(esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR);
+ tcg_shift = tcg_constant_i32(shift);
+ tcg_rmode = gen_set_rmode(rmode, tcg_fpstatus);
- case 3: /* float16 */
- tcg_single = tcg_temp_new_i32();
- if (is_signed) {
- gen_helper_vfp_sqtoh(tcg_single, tcg_int,
- tcg_shift, tcg_fpstatus);
- } else {
- gen_helper_vfp_uqtoh(tcg_single, tcg_int,
- tcg_shift, tcg_fpstatus);
- }
- write_fp_sreg(s, rd, tcg_single);
+ switch (esz) {
+ case MO_64:
+ read_vec_element(s, tcg_out, rn, 0, MO_64);
+ switch (out) {
+ case MO_64 | MO_SIGN:
+ gen_helper_vfp_tosqd(tcg_out, tcg_out, tcg_shift, tcg_fpstatus);
break;
-
- default:
- g_assert_not_reached();
- }
- } else {
- TCGv_i64 tcg_int = cpu_reg(s, rd);
- TCGv_i32 tcg_rmode;
-
- if (extract32(opcode, 2, 1)) {
- /* There are too many rounding modes to all fit into rmode,
- * so FCVTA[US] is a special case.
- */
- rmode = FPROUNDING_TIEAWAY;
- }
-
- tcg_rmode = gen_set_rmode(rmode, tcg_fpstatus);
-
- switch (type) {
- case 1: /* float64 */
- tcg_double = read_fp_dreg(s, rn);
- if (is_signed) {
- if (!sf) {
- gen_helper_vfp_tosld(tcg_int, tcg_double,
- tcg_shift, tcg_fpstatus);
- } else {
- gen_helper_vfp_tosqd(tcg_int, tcg_double,
- tcg_shift, tcg_fpstatus);
- }
- } else {
- if (!sf) {
- gen_helper_vfp_tould(tcg_int, tcg_double,
- tcg_shift, tcg_fpstatus);
- } else {
- gen_helper_vfp_touqd(tcg_int, tcg_double,
- tcg_shift, tcg_fpstatus);
- }
- }
- if (!sf) {
- tcg_gen_ext32u_i64(tcg_int, tcg_int);
- }
+ case MO_64:
+ gen_helper_vfp_touqd(tcg_out, tcg_out, tcg_shift, tcg_fpstatus);
break;
-
- case 0: /* float32 */
- tcg_single = read_fp_sreg(s, rn);
- if (sf) {
- if (is_signed) {
- gen_helper_vfp_tosqs(tcg_int, tcg_single,
- tcg_shift, tcg_fpstatus);
- } else {
- gen_helper_vfp_touqs(tcg_int, tcg_single,
- tcg_shift, tcg_fpstatus);
- }
- } else {
- TCGv_i32 tcg_dest = tcg_temp_new_i32();
- if (is_signed) {
- gen_helper_vfp_tosls(tcg_dest, tcg_single,
- tcg_shift, tcg_fpstatus);
- } else {
- gen_helper_vfp_touls(tcg_dest, tcg_single,
- tcg_shift, tcg_fpstatus);
- }
- tcg_gen_extu_i32_i64(tcg_int, tcg_dest);
- }
+ case MO_32 | MO_SIGN:
+ gen_helper_vfp_tosld(tcg_out, tcg_out, tcg_shift, tcg_fpstatus);
break;
-
- case 3: /* float16 */
- tcg_single = read_fp_sreg(s, rn);
- if (sf) {
- if (is_signed) {
- gen_helper_vfp_tosqh(tcg_int, tcg_single,
- tcg_shift, tcg_fpstatus);
- } else {
- gen_helper_vfp_touqh(tcg_int, tcg_single,
- tcg_shift, tcg_fpstatus);
- }
- } else {
- TCGv_i32 tcg_dest = tcg_temp_new_i32();
- if (is_signed) {
- gen_helper_vfp_toslh(tcg_dest, tcg_single,
- tcg_shift, tcg_fpstatus);
- } else {
- gen_helper_vfp_toulh(tcg_dest, tcg_single,
- tcg_shift, tcg_fpstatus);
- }
- tcg_gen_extu_i32_i64(tcg_int, tcg_dest);
- }
+ case MO_32:
+ gen_helper_vfp_tould(tcg_out, tcg_out, tcg_shift, tcg_fpstatus);
break;
-
default:
g_assert_not_reached();
}
-
- gen_restore_rmode(tcg_rmode, tcg_fpstatus);
- }
-}
-
-/* Floating point <-> fixed point conversions
- * 31 30 29 28 24 23 22 21 20 19 18 16 15 10 9 5 4 0
- * +----+---+---+-----------+------+---+-------+--------+-------+------+------+
- * | sf | 0 | S | 1 1 1 1 0 | type | 0 | rmode | opcode | scale | Rn | Rd |
- * +----+---+---+-----------+------+---+-------+--------+-------+------+------+
- */
-static void disas_fp_fixed_conv(DisasContext *s, uint32_t insn)
-{
- int rd = extract32(insn, 0, 5);
- int rn = extract32(insn, 5, 5);
- int scale = extract32(insn, 10, 6);
- int opcode = extract32(insn, 16, 3);
- int rmode = extract32(insn, 19, 2);
- int type = extract32(insn, 22, 2);
- bool sbit = extract32(insn, 29, 1);
- bool sf = extract32(insn, 31, 1);
- bool itof;
-
- if (sbit || (!sf && scale < 32)) {
- unallocated_encoding(s);
- return;
- }
-
- switch (type) {
- case 0: /* float32 */
- case 1: /* float64 */
break;
- case 3: /* float16 */
- if (dc_isar_feature(aa64_fp16, s)) {
- break;
- }
- /* fallthru */
- default:
- unallocated_encoding(s);
- return;
- }
- switch ((rmode << 3) | opcode) {
- case 0x2: /* SCVTF */
- case 0x3: /* UCVTF */
- itof = true;
- break;
- case 0x18: /* FCVTZS */
- case 0x19: /* FCVTZU */
- itof = false;
- break;
- default:
- unallocated_encoding(s);
- return;
- }
-
- if (!fp_access_check(s)) {
- return;
- }
-
- handle_fpfpcvt(s, rd, rn, opcode, itof, FPROUNDING_ZERO, scale, sf, type);
-}
-
-static void handle_fmov(DisasContext *s, int rd, int rn, int type, bool itof)
-{
- /* FMOV: gpr to or from float, double, or top half of quad fp reg,
- * without conversion.
- */
-
- if (itof) {
- TCGv_i64 tcg_rn = cpu_reg(s, rn);
- TCGv_i64 tmp;
-
- switch (type) {
- case 0:
- /* 32 bit */
- tmp = tcg_temp_new_i64();
- tcg_gen_ext32u_i64(tmp, tcg_rn);
- write_fp_dreg(s, rd, tmp);
+ case MO_32:
+ tcg_single = read_fp_sreg(s, rn);
+ switch (out) {
+ case MO_64 | MO_SIGN:
+ gen_helper_vfp_tosqs(tcg_out, tcg_single, tcg_shift, tcg_fpstatus);
break;
- case 1:
- /* 64 bit */
- write_fp_dreg(s, rd, tcg_rn);
+ case MO_64:
+ gen_helper_vfp_touqs(tcg_out, tcg_single, tcg_shift, tcg_fpstatus);
break;
- case 2:
- /* 64 bit to top half. */
- tcg_gen_st_i64(tcg_rn, tcg_env, fp_reg_hi_offset(s, rd));
- clear_vec_high(s, true, rd);
+ case MO_32 | MO_SIGN:
+ gen_helper_vfp_tosls(tcg_single, tcg_single,
+ tcg_shift, tcg_fpstatus);
+ tcg_gen_extu_i32_i64(tcg_out, tcg_single);
break;
- case 3:
- /* 16 bit */
- tmp = tcg_temp_new_i64();
- tcg_gen_ext16u_i64(tmp, tcg_rn);
- write_fp_dreg(s, rd, tmp);
+ case MO_32:
+ gen_helper_vfp_touls(tcg_single, tcg_single,
+ tcg_shift, tcg_fpstatus);
+ tcg_gen_extu_i32_i64(tcg_out, tcg_single);
break;
default:
g_assert_not_reached();
}
- } else {
- TCGv_i64 tcg_rd = cpu_reg(s, rd);
+ break;
- switch (type) {
- case 0:
- /* 32 bit */
- tcg_gen_ld32u_i64(tcg_rd, tcg_env, fp_reg_offset(s, rn, MO_32));
+ case MO_16:
+ tcg_single = read_fp_hreg(s, rn);
+ switch (out) {
+ case MO_64 | MO_SIGN:
+ gen_helper_vfp_tosqh(tcg_out, tcg_single, tcg_shift, tcg_fpstatus);
break;
- case 1:
- /* 64 bit */
- tcg_gen_ld_i64(tcg_rd, tcg_env, fp_reg_offset(s, rn, MO_64));
+ case MO_64:
+ gen_helper_vfp_touqh(tcg_out, tcg_single, tcg_shift, tcg_fpstatus);
break;
- case 2:
- /* 64 bits from top half */
- tcg_gen_ld_i64(tcg_rd, tcg_env, fp_reg_hi_offset(s, rn));
+ case MO_32 | MO_SIGN:
+ gen_helper_vfp_toslh(tcg_single, tcg_single,
+ tcg_shift, tcg_fpstatus);
+ tcg_gen_extu_i32_i64(tcg_out, tcg_single);
break;
- case 3:
- /* 16 bit */
- tcg_gen_ld16u_i64(tcg_rd, tcg_env, fp_reg_offset(s, rn, MO_16));
+ case MO_32:
+ gen_helper_vfp_toulh(tcg_single, tcg_single,
+ tcg_shift, tcg_fpstatus);
+ tcg_gen_extu_i32_i64(tcg_out, tcg_single);
break;
- default:
- g_assert_not_reached();
- }
- }
-}
-
-static void handle_fjcvtzs(DisasContext *s, int rd, int rn)
-{
- TCGv_i64 t = read_fp_dreg(s, rn);
- TCGv_ptr fpstatus = fpstatus_ptr(FPST_FPCR);
-
- gen_helper_fjcvtzs(t, t, fpstatus);
-
- tcg_gen_ext32u_i64(cpu_reg(s, rd), t);
- tcg_gen_extrh_i64_i32(cpu_ZF, t);
- tcg_gen_movi_i32(cpu_CF, 0);
- tcg_gen_movi_i32(cpu_NF, 0);
- tcg_gen_movi_i32(cpu_VF, 0);
-}
-
-/* Floating point <-> integer conversions
- * 31 30 29 28 24 23 22 21 20 19 18 16 15 10 9 5 4 0
- * +----+---+---+-----------+------+---+-------+-----+-------------+----+----+
- * | sf | 0 | S | 1 1 1 1 0 | type | 1 | rmode | opc | 0 0 0 0 0 0 | Rn | Rd |
- * +----+---+---+-----------+------+---+-------+-----+-------------+----+----+
- */
-static void disas_fp_int_conv(DisasContext *s, uint32_t insn)
-{
- int rd = extract32(insn, 0, 5);
- int rn = extract32(insn, 5, 5);
- int opcode = extract32(insn, 16, 3);
- int rmode = extract32(insn, 19, 2);
- int type = extract32(insn, 22, 2);
- bool sbit = extract32(insn, 29, 1);
- bool sf = extract32(insn, 31, 1);
- bool itof = false;
-
- if (sbit) {
- goto do_unallocated;
- }
-
- switch (opcode) {
- case 2: /* SCVTF */
- case 3: /* UCVTF */
- itof = true;
- /* fallthru */
- case 4: /* FCVTAS */
- case 5: /* FCVTAU */
- if (rmode != 0) {
- goto do_unallocated;
- }
- /* fallthru */
- case 0: /* FCVT[NPMZ]S */
- case 1: /* FCVT[NPMZ]U */
- switch (type) {
- case 0: /* float32 */
- case 1: /* float64 */
+ case MO_16 | MO_SIGN:
+ gen_helper_vfp_toshh(tcg_single, tcg_single,
+ tcg_shift, tcg_fpstatus);
+ tcg_gen_extu_i32_i64(tcg_out, tcg_single);
break;
- case 3: /* float16 */
- if (!dc_isar_feature(aa64_fp16, s)) {
- goto do_unallocated;
- }
+ case MO_16:
+ gen_helper_vfp_touhh(tcg_single, tcg_single,
+ tcg_shift, tcg_fpstatus);
+ tcg_gen_extu_i32_i64(tcg_out, tcg_single);
break;
default:
- goto do_unallocated;
- }
- if (!fp_access_check(s)) {
- return;
+ g_assert_not_reached();
}
- handle_fpfpcvt(s, rd, rn, opcode, itof, rmode, 64, sf, type);
break;
default:
- switch (sf << 7 | type << 5 | rmode << 3 | opcode) {
- case 0b01100110: /* FMOV half <-> 32-bit int */
- case 0b01100111:
- case 0b11100110: /* FMOV half <-> 64-bit int */
- case 0b11100111:
- if (!dc_isar_feature(aa64_fp16, s)) {
- goto do_unallocated;
- }
- /* fallthru */
- case 0b00000110: /* FMOV 32-bit */
- case 0b00000111:
- case 0b10100110: /* FMOV 64-bit */
- case 0b10100111:
- case 0b11001110: /* FMOV top half of 128-bit */
- case 0b11001111:
- if (!fp_access_check(s)) {
- return;
- }
- itof = opcode & 1;
- handle_fmov(s, rd, rn, type, itof);
- break;
-
- case 0b00111110: /* FJCVTZS */
- if (!dc_isar_feature(aa64_jscvt, s)) {
- goto do_unallocated;
- } else if (fp_access_check(s)) {
- handle_fjcvtzs(s, rd, rn);
- }
- break;
-
- default:
- do_unallocated:
- unallocated_encoding(s);
- return;
- }
- break;
+ g_assert_not_reached();
}
+
+ gen_restore_rmode(tcg_rmode, tcg_fpstatus);
}
-/* FP-specific subcases of table C3-6 (SIMD and FP data processing)
- * 31 30 29 28 25 24 0
- * +---+---+---+---------+-----------------------------+
- * | | 0 | | 1 1 1 1 | |
- * +---+---+---+---------+-----------------------------+
- */
-static void disas_data_proc_fp(DisasContext *s, uint32_t insn)
+static bool do_fcvt_g(DisasContext *s, arg_fcvt *a,
+ ARMFPRounding rmode, bool is_signed)
{
- if (extract32(insn, 24, 1)) {
- unallocated_encoding(s); /* in decodetree */
- } else if (extract32(insn, 21, 1) == 0) {
- /* Floating point to fixed point conversions */
- disas_fp_fixed_conv(s, insn);
- } else {
- switch (extract32(insn, 10, 2)) {
- case 1:
- /* Floating point conditional compare */
- disas_fp_ccomp(s, insn);
- break;
- case 2:
- /* Floating point data-processing (2 source) */
- unallocated_encoding(s); /* in decodetree */
- break;
- case 3:
- /* Floating point conditional select */
- unallocated_encoding(s); /* in decodetree */
- break;
- case 0:
- switch (ctz32(extract32(insn, 12, 4))) {
- case 0: /* [15:12] == xxx1 */
- /* Floating point immediate */
- unallocated_encoding(s); /* in decodetree */
- break;
- case 1: /* [15:12] == xx10 */
- /* Floating point compare */
- disas_fp_compare(s, insn);
- break;
- case 2: /* [15:12] == x100 */
- /* Floating point data-processing (1 source) */
- disas_fp_1src(s, insn);
- break;
- case 3: /* [15:12] == 1000 */
- unallocated_encoding(s);
- break;
- default: /* [15:12] == 0000 */
- /* Floating point <-> integer conversions */
- disas_fp_int_conv(s, insn);
- break;
- }
- break;
- }
+ TCGv_i64 tcg_int;
+ int check = fp_access_check_scalar_hsd(s, a->esz);
+
+ if (check <= 0) {
+ return check == 0;
+ }
+
+ tcg_int = cpu_reg(s, a->rd);
+ do_fcvt_scalar(s, (a->sf ? MO_64 : MO_32) | (is_signed ? MO_SIGN : 0),
+ a->esz, tcg_int, a->shift, a->rn, rmode);
+
+ if (!a->sf) {
+ tcg_gen_ext32u_i64(tcg_int, tcg_int);
}
+ return true;
}
-/* Common vector code for handling integer to FP conversion */
-static void handle_simd_intfp_conv(DisasContext *s, int rd, int rn,
- int elements, int is_signed,
- int fracbits, int size)
-{
- TCGv_ptr tcg_fpst = fpstatus_ptr(size == MO_16 ? FPST_FPCR_F16 : FPST_FPCR);
- TCGv_i32 tcg_shift = NULL;
+TRANS(FCVTNS_g, do_fcvt_g, a, FPROUNDING_TIEEVEN, true)
+TRANS(FCVTNU_g, do_fcvt_g, a, FPROUNDING_TIEEVEN, false)
+TRANS(FCVTPS_g, do_fcvt_g, a, FPROUNDING_POSINF, true)
+TRANS(FCVTPU_g, do_fcvt_g, a, FPROUNDING_POSINF, false)
+TRANS(FCVTMS_g, do_fcvt_g, a, FPROUNDING_NEGINF, true)
+TRANS(FCVTMU_g, do_fcvt_g, a, FPROUNDING_NEGINF, false)
+TRANS(FCVTZS_g, do_fcvt_g, a, FPROUNDING_ZERO, true)
+TRANS(FCVTZU_g, do_fcvt_g, a, FPROUNDING_ZERO, false)
+TRANS(FCVTAS_g, do_fcvt_g, a, FPROUNDING_TIEAWAY, true)
+TRANS(FCVTAU_g, do_fcvt_g, a, FPROUNDING_TIEAWAY, false)
- MemOp mop = size | (is_signed ? MO_SIGN : 0);
- int pass;
+/*
+ * FCVT* (vector), scalar version.
+ * Which sounds weird, but really just means output to fp register
+ * instead of output to general register. Input and output element
+ * size are always equal.
+ */
+static bool do_fcvt_f(DisasContext *s, arg_fcvt *a,
+ ARMFPRounding rmode, bool is_signed)
+{
+ TCGv_i64 tcg_int;
+ int check = fp_access_check_scalar_hsd(s, a->esz);
- if (fracbits || size == MO_64) {
- tcg_shift = tcg_constant_i32(fracbits);
+ if (check <= 0) {
+ return check == 0;
}
- if (size == MO_64) {
- TCGv_i64 tcg_int64 = tcg_temp_new_i64();
- TCGv_i64 tcg_double = tcg_temp_new_i64();
+ tcg_int = tcg_temp_new_i64();
+ do_fcvt_scalar(s, a->esz | (is_signed ? MO_SIGN : 0),
+ a->esz, tcg_int, a->shift, a->rn, rmode);
- for (pass = 0; pass < elements; pass++) {
- read_vec_element(s, tcg_int64, rn, pass, mop);
+ clear_vec(s, a->rd);
+ write_vec_element(s, tcg_int, a->rd, 0, a->esz);
+ return true;
+}
- if (is_signed) {
- gen_helper_vfp_sqtod(tcg_double, tcg_int64,
- tcg_shift, tcg_fpst);
- } else {
- gen_helper_vfp_uqtod(tcg_double, tcg_int64,
- tcg_shift, tcg_fpst);
- }
- if (elements == 1) {
- write_fp_dreg(s, rd, tcg_double);
- } else {
- write_vec_element(s, tcg_double, rd, pass, MO_64);
- }
- }
- } else {
- TCGv_i32 tcg_int32 = tcg_temp_new_i32();
- TCGv_i32 tcg_float = tcg_temp_new_i32();
-
- for (pass = 0; pass < elements; pass++) {
- read_vec_element_i32(s, tcg_int32, rn, pass, mop);
-
- switch (size) {
- case MO_32:
- if (fracbits) {
- if (is_signed) {
- gen_helper_vfp_sltos(tcg_float, tcg_int32,
- tcg_shift, tcg_fpst);
- } else {
- gen_helper_vfp_ultos(tcg_float, tcg_int32,
- tcg_shift, tcg_fpst);
- }
- } else {
- if (is_signed) {
- gen_helper_vfp_sitos(tcg_float, tcg_int32, tcg_fpst);
- } else {
- gen_helper_vfp_uitos(tcg_float, tcg_int32, tcg_fpst);
- }
- }
- break;
- case MO_16:
- if (fracbits) {
- if (is_signed) {
- gen_helper_vfp_sltoh(tcg_float, tcg_int32,
- tcg_shift, tcg_fpst);
- } else {
- gen_helper_vfp_ultoh(tcg_float, tcg_int32,
- tcg_shift, tcg_fpst);
- }
- } else {
- if (is_signed) {
- gen_helper_vfp_sitoh(tcg_float, tcg_int32, tcg_fpst);
- } else {
- gen_helper_vfp_uitoh(tcg_float, tcg_int32, tcg_fpst);
- }
- }
- break;
- default:
- g_assert_not_reached();
- }
+TRANS(FCVTNS_f, do_fcvt_f, a, FPROUNDING_TIEEVEN, true)
+TRANS(FCVTNU_f, do_fcvt_f, a, FPROUNDING_TIEEVEN, false)
+TRANS(FCVTPS_f, do_fcvt_f, a, FPROUNDING_POSINF, true)
+TRANS(FCVTPU_f, do_fcvt_f, a, FPROUNDING_POSINF, false)
+TRANS(FCVTMS_f, do_fcvt_f, a, FPROUNDING_NEGINF, true)
+TRANS(FCVTMU_f, do_fcvt_f, a, FPROUNDING_NEGINF, false)
+TRANS(FCVTZS_f, do_fcvt_f, a, FPROUNDING_ZERO, true)
+TRANS(FCVTZU_f, do_fcvt_f, a, FPROUNDING_ZERO, false)
+TRANS(FCVTAS_f, do_fcvt_f, a, FPROUNDING_TIEAWAY, true)
+TRANS(FCVTAU_f, do_fcvt_f, a, FPROUNDING_TIEAWAY, false)
- if (elements == 1) {
- write_fp_sreg(s, rd, tcg_float);
- } else {
- write_vec_element_i32(s, tcg_float, rd, pass, size);
- }
- }
+static bool trans_FJCVTZS(DisasContext *s, arg_FJCVTZS *a)
+{
+ if (!dc_isar_feature(aa64_jscvt, s)) {
+ return false;
}
+ if (fp_access_check(s)) {
+ TCGv_i64 t = read_fp_dreg(s, a->rn);
+ TCGv_ptr fpstatus = fpstatus_ptr(FPST_FPCR);
- clear_vec_high(s, elements << size == 16, rd);
+ gen_helper_fjcvtzs(t, t, fpstatus);
+
+ tcg_gen_ext32u_i64(cpu_reg(s, a->rd), t);
+ tcg_gen_extrh_i64_i32(cpu_ZF, t);
+ tcg_gen_movi_i32(cpu_CF, 0);
+ tcg_gen_movi_i32(cpu_NF, 0);
+ tcg_gen_movi_i32(cpu_VF, 0);
+ }
+ return true;
}
-/* UCVTF/SCVTF - Integer to FP conversion */
-static void handle_simd_shift_intfp_conv(DisasContext *s, bool is_scalar,
- bool is_q, bool is_u,
- int immh, int immb, int opcode,
- int rn, int rd)
+static bool trans_FMOV_hx(DisasContext *s, arg_rr *a)
{
- int size, elements, fracbits;
- int immhb = immh << 3 | immb;
-
- if (immh & 8) {
- size = MO_64;
- if (!is_scalar && !is_q) {
- unallocated_encoding(s);
- return;
- }
- } else if (immh & 4) {
- size = MO_32;
- } else if (immh & 2) {
- size = MO_16;
- if (!dc_isar_feature(aa64_fp16, s)) {
- unallocated_encoding(s);
- return;
- }
- } else {
- /* immh == 0 would be a failure of the decode logic */
- g_assert(immh == 1);
- unallocated_encoding(s);
- return;
+ if (!dc_isar_feature(aa64_fp16, s)) {
+ return false;
}
-
- if (is_scalar) {
- elements = 1;
- } else {
- elements = (8 << is_q) >> size;
+ if (fp_access_check(s)) {
+ TCGv_i64 tcg_rn = cpu_reg(s, a->rn);
+ TCGv_i64 tmp = tcg_temp_new_i64();
+ tcg_gen_ext16u_i64(tmp, tcg_rn);
+ write_fp_dreg(s, a->rd, tmp);
}
- fracbits = (16 << size) - immhb;
+ return true;
+}
- if (!fp_access_check(s)) {
- return;
+static bool trans_FMOV_sw(DisasContext *s, arg_rr *a)
+{
+ if (fp_access_check(s)) {
+ TCGv_i64 tcg_rn = cpu_reg(s, a->rn);
+ TCGv_i64 tmp = tcg_temp_new_i64();
+ tcg_gen_ext32u_i64(tmp, tcg_rn);
+ write_fp_dreg(s, a->rd, tmp);
}
-
- handle_simd_intfp_conv(s, rd, rn, elements, !is_u, fracbits, size);
+ return true;
}
-/* FCVTZS, FVCVTZU - FP to fixedpoint conversion */
-static void handle_simd_shift_fpint_conv(DisasContext *s, bool is_scalar,
- bool is_q, bool is_u,
- int immh, int immb, int rn, int rd)
+static bool trans_FMOV_dx(DisasContext *s, arg_rr *a)
{
- int immhb = immh << 3 | immb;
- int pass, size, fracbits;
- TCGv_ptr tcg_fpstatus;
- TCGv_i32 tcg_rmode, tcg_shift;
-
- if (immh & 0x8) {
- size = MO_64;
- if (!is_scalar && !is_q) {
- unallocated_encoding(s);
- return;
- }
- } else if (immh & 0x4) {
- size = MO_32;
- } else if (immh & 0x2) {
- size = MO_16;
- if (!dc_isar_feature(aa64_fp16, s)) {
- unallocated_encoding(s);
- return;
- }
- } else {
- /* Should have split out AdvSIMD modified immediate earlier. */
- assert(immh == 1);
- unallocated_encoding(s);
- return;
+ if (fp_access_check(s)) {
+ TCGv_i64 tcg_rn = cpu_reg(s, a->rn);
+ write_fp_dreg(s, a->rd, tcg_rn);
}
+ return true;
+}
- if (!fp_access_check(s)) {
- return;
+static bool trans_FMOV_ux(DisasContext *s, arg_rr *a)
+{
+ if (fp_access_check(s)) {
+ TCGv_i64 tcg_rn = cpu_reg(s, a->rn);
+ tcg_gen_st_i64(tcg_rn, tcg_env, fp_reg_hi_offset(s, a->rd));
+ clear_vec_high(s, true, a->rd);
}
+ return true;
+}
- assert(!(is_scalar && is_q));
-
- tcg_fpstatus = fpstatus_ptr(size == MO_16 ? FPST_FPCR_F16 : FPST_FPCR);
- tcg_rmode = gen_set_rmode(FPROUNDING_ZERO, tcg_fpstatus);
- fracbits = (16 << size) - immhb;
- tcg_shift = tcg_constant_i32(fracbits);
-
- if (size == MO_64) {
- int maxpass = is_scalar ? 1 : 2;
-
- for (pass = 0; pass < maxpass; pass++) {
- TCGv_i64 tcg_op = tcg_temp_new_i64();
-
- read_vec_element(s, tcg_op, rn, pass, MO_64);
- if (is_u) {
- gen_helper_vfp_touqd(tcg_op, tcg_op, tcg_shift, tcg_fpstatus);
- } else {
- gen_helper_vfp_tosqd(tcg_op, tcg_op, tcg_shift, tcg_fpstatus);
- }
- write_vec_element(s, tcg_op, rd, pass, MO_64);
- }
- clear_vec_high(s, is_q, rd);
- } else {
- void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
- int maxpass = is_scalar ? 1 : ((8 << is_q) >> size);
-
- switch (size) {
- case MO_16:
- if (is_u) {
- fn = gen_helper_vfp_touhh;
- } else {
- fn = gen_helper_vfp_toshh;
- }
- break;
- case MO_32:
- if (is_u) {
- fn = gen_helper_vfp_touls;
- } else {
- fn = gen_helper_vfp_tosls;
- }
- break;
- default:
- g_assert_not_reached();
- }
-
- for (pass = 0; pass < maxpass; pass++) {
- TCGv_i32 tcg_op = tcg_temp_new_i32();
-
- read_vec_element_i32(s, tcg_op, rn, pass, size);
- fn(tcg_op, tcg_op, tcg_shift, tcg_fpstatus);
- if (is_scalar) {
- if (size == MO_16 && !is_u) {
- tcg_gen_ext16u_i32(tcg_op, tcg_op);
- }
- write_fp_sreg(s, rd, tcg_op);
- } else {
- write_vec_element_i32(s, tcg_op, rd, pass, size);
- }
- }
- if (!is_scalar) {
- clear_vec_high(s, is_q, rd);
- }
+static bool trans_FMOV_xh(DisasContext *s, arg_rr *a)
+{
+ if (!dc_isar_feature(aa64_fp16, s)) {
+ return false;
}
-
- gen_restore_rmode(tcg_rmode, tcg_fpstatus);
+ if (fp_access_check(s)) {
+ TCGv_i64 tcg_rd = cpu_reg(s, a->rd);
+ tcg_gen_ld16u_i64(tcg_rd, tcg_env, fp_reg_offset(s, a->rn, MO_16));
+ }
+ return true;
}
-/* AdvSIMD scalar shift by immediate
- * 31 30 29 28 23 22 19 18 16 15 11 10 9 5 4 0
- * +-----+---+-------------+------+------+--------+---+------+------+
- * | 0 1 | U | 1 1 1 1 1 0 | immh | immb | opcode | 1 | Rn | Rd |
- * +-----+---+-------------+------+------+--------+---+------+------+
- *
- * This is the scalar version so it works on a fixed sized registers
- */
-static void disas_simd_scalar_shift_imm(DisasContext *s, uint32_t insn)
+static bool trans_FMOV_ws(DisasContext *s, arg_rr *a)
{
- int rd = extract32(insn, 0, 5);
- int rn = extract32(insn, 5, 5);
- int opcode = extract32(insn, 11, 5);
- int immb = extract32(insn, 16, 3);
- int immh = extract32(insn, 19, 4);
- bool is_u = extract32(insn, 29, 1);
-
- if (immh == 0) {
- unallocated_encoding(s);
- return;
+ if (fp_access_check(s)) {
+ TCGv_i64 tcg_rd = cpu_reg(s, a->rd);
+ tcg_gen_ld32u_i64(tcg_rd, tcg_env, fp_reg_offset(s, a->rn, MO_32));
}
+ return true;
+}
- switch (opcode) {
- case 0x1c: /* SCVTF, UCVTF */
- handle_simd_shift_intfp_conv(s, true, false, is_u, immh, immb,
- opcode, rn, rd);
- break;
- case 0x1f: /* FCVTZS, FCVTZU */
- handle_simd_shift_fpint_conv(s, true, false, is_u, immh, immb, rn, rd);
- break;
- default:
- case 0x00: /* SSHR / USHR */
- case 0x02: /* SSRA / USRA */
- case 0x04: /* SRSHR / URSHR */
- case 0x06: /* SRSRA / URSRA */
- case 0x08: /* SRI */
- case 0x0a: /* SHL / SLI */
- case 0x0c: /* SQSHLU */
- case 0x0e: /* SQSHL, UQSHL */
- case 0x10: /* SQSHRUN */
- case 0x11: /* SQRSHRUN */
- case 0x12: /* SQSHRN, UQSHRN */
- case 0x13: /* SQRSHRN, UQRSHRN */
- unallocated_encoding(s);
- break;
+static bool trans_FMOV_xd(DisasContext *s, arg_rr *a)
+{
+ if (fp_access_check(s)) {
+ TCGv_i64 tcg_rd = cpu_reg(s, a->rd);
+ tcg_gen_ld_i64(tcg_rd, tcg_env, fp_reg_offset(s, a->rn, MO_64));
}
+ return true;
}
-static void handle_2misc_64(DisasContext *s, int opcode, bool u,
- TCGv_i64 tcg_rd, TCGv_i64 tcg_rn,
- TCGv_i32 tcg_rmode, TCGv_ptr tcg_fpstatus)
+static bool trans_FMOV_xu(DisasContext *s, arg_rr *a)
{
- /* Handle 64->64 opcodes which are shared between the scalar and
- * vector 2-reg-misc groups. We cover every integer opcode where size == 3
- * is valid in either group and also the double-precision fp ops.
- * The caller only need provide tcg_rmode and tcg_fpstatus if the op
- * requires them.
- */
- TCGCond cond;
-
- switch (opcode) {
- case 0x4: /* CLS, CLZ */
- if (u) {
- tcg_gen_clzi_i64(tcg_rd, tcg_rn, 64);
- } else {
- tcg_gen_clrsb_i64(tcg_rd, tcg_rn);
- }
- break;
- case 0x5: /* NOT */
- /* This opcode is shared with CNT and RBIT but we have earlier
- * enforced that size == 3 if and only if this is the NOT insn.
- */
- tcg_gen_not_i64(tcg_rd, tcg_rn);
- break;
- case 0x7: /* SQABS, SQNEG */
- if (u) {
- gen_helper_neon_qneg_s64(tcg_rd, tcg_env, tcg_rn);
- } else {
- gen_helper_neon_qabs_s64(tcg_rd, tcg_env, tcg_rn);
- }
- break;
- case 0xa: /* CMLT */
- cond = TCG_COND_LT;
- do_cmop:
- /* 64 bit integer comparison against zero, result is test ? -1 : 0. */
- tcg_gen_negsetcond_i64(cond, tcg_rd, tcg_rn, tcg_constant_i64(0));
- break;
- case 0x8: /* CMGT, CMGE */
- cond = u ? TCG_COND_GE : TCG_COND_GT;
- goto do_cmop;
- case 0x9: /* CMEQ, CMLE */
- cond = u ? TCG_COND_LE : TCG_COND_EQ;
- goto do_cmop;
- case 0xb: /* ABS, NEG */
- if (u) {
- tcg_gen_neg_i64(tcg_rd, tcg_rn);
- } else {
- tcg_gen_abs_i64(tcg_rd, tcg_rn);
- }
- break;
- case 0x2f: /* FABS */
- gen_vfp_absd(tcg_rd, tcg_rn);
- break;
- case 0x6f: /* FNEG */
- gen_vfp_negd(tcg_rd, tcg_rn);
- break;
- case 0x7f: /* FSQRT */
- gen_helper_vfp_sqrtd(tcg_rd, tcg_rn, tcg_env);
- break;
- case 0x1a: /* FCVTNS */
- case 0x1b: /* FCVTMS */
- case 0x1c: /* FCVTAS */
- case 0x3a: /* FCVTPS */
- case 0x3b: /* FCVTZS */
- gen_helper_vfp_tosqd(tcg_rd, tcg_rn, tcg_constant_i32(0), tcg_fpstatus);
- break;
- case 0x5a: /* FCVTNU */
- case 0x5b: /* FCVTMU */
- case 0x5c: /* FCVTAU */
- case 0x7a: /* FCVTPU */
- case 0x7b: /* FCVTZU */
- gen_helper_vfp_touqd(tcg_rd, tcg_rn, tcg_constant_i32(0), tcg_fpstatus);
- break;
- case 0x18: /* FRINTN */
- case 0x19: /* FRINTM */
- case 0x38: /* FRINTP */
- case 0x39: /* FRINTZ */
- case 0x58: /* FRINTA */
- case 0x79: /* FRINTI */
- gen_helper_rintd(tcg_rd, tcg_rn, tcg_fpstatus);
- break;
- case 0x59: /* FRINTX */
- gen_helper_rintd_exact(tcg_rd, tcg_rn, tcg_fpstatus);
- break;
- case 0x1e: /* FRINT32Z */
- case 0x5e: /* FRINT32X */
- gen_helper_frint32_d(tcg_rd, tcg_rn, tcg_fpstatus);
- break;
- case 0x1f: /* FRINT64Z */
- case 0x5f: /* FRINT64X */
- gen_helper_frint64_d(tcg_rd, tcg_rn, tcg_fpstatus);
- break;
- default:
- g_assert_not_reached();
+ if (fp_access_check(s)) {
+ TCGv_i64 tcg_rd = cpu_reg(s, a->rd);
+ tcg_gen_ld_i64(tcg_rd, tcg_env, fp_reg_hi_offset(s, a->rn));
}
+ return true;
}
-static void handle_2misc_fcmp_zero(DisasContext *s, int opcode,
- bool is_scalar, bool is_u, bool is_q,
- int size, int rn, int rd)
-{
- bool is_double = (size == MO_64);
- TCGv_ptr fpst;
+typedef struct ENVScalar1 {
+ NeonGenOneOpEnvFn *gen_bhs[3];
+ NeonGenOne64OpEnvFn *gen_d;
+} ENVScalar1;
+static bool do_env_scalar1(DisasContext *s, arg_rr_e *a, const ENVScalar1 *f)
+{
if (!fp_access_check(s)) {
- return;
+ return true;
}
-
- fpst = fpstatus_ptr(size == MO_16 ? FPST_FPCR_F16 : FPST_FPCR);
-
- if (is_double) {
- TCGv_i64 tcg_op = tcg_temp_new_i64();
- TCGv_i64 tcg_zero = tcg_constant_i64(0);
- TCGv_i64 tcg_res = tcg_temp_new_i64();
- NeonGenTwoDoubleOpFn *genfn;
- bool swap = false;
- int pass;
-
- switch (opcode) {
- case 0x2e: /* FCMLT (zero) */
- swap = true;
- /* fallthrough */
- case 0x2c: /* FCMGT (zero) */
- genfn = gen_helper_neon_cgt_f64;
- break;
- case 0x2d: /* FCMEQ (zero) */
- genfn = gen_helper_neon_ceq_f64;
- break;
- case 0x6d: /* FCMLE (zero) */
- swap = true;
- /* fall through */
- case 0x6c: /* FCMGE (zero) */
- genfn = gen_helper_neon_cge_f64;
- break;
- default:
- g_assert_not_reached();
- }
-
- for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
- read_vec_element(s, tcg_op, rn, pass, MO_64);
- if (swap) {
- genfn(tcg_res, tcg_zero, tcg_op, fpst);
- } else {
- genfn(tcg_res, tcg_op, tcg_zero, fpst);
- }
- write_vec_element(s, tcg_res, rd, pass, MO_64);
- }
-
- clear_vec_high(s, !is_scalar, rd);
+ if (a->esz == MO_64) {
+ TCGv_i64 t = read_fp_dreg(s, a->rn);
+ f->gen_d(t, tcg_env, t);
+ write_fp_dreg(s, a->rd, t);
} else {
- TCGv_i32 tcg_op = tcg_temp_new_i32();
- TCGv_i32 tcg_zero = tcg_constant_i32(0);
- TCGv_i32 tcg_res = tcg_temp_new_i32();
- NeonGenTwoSingleOpFn *genfn;
- bool swap = false;
- int pass, maxpasses;
-
- if (size == MO_16) {
- switch (opcode) {
- case 0x2e: /* FCMLT (zero) */
- swap = true;
- /* fall through */
- case 0x2c: /* FCMGT (zero) */
- genfn = gen_helper_advsimd_cgt_f16;
- break;
- case 0x2d: /* FCMEQ (zero) */
- genfn = gen_helper_advsimd_ceq_f16;
- break;
- case 0x6d: /* FCMLE (zero) */
- swap = true;
- /* fall through */
- case 0x6c: /* FCMGE (zero) */
- genfn = gen_helper_advsimd_cge_f16;
- break;
- default:
- g_assert_not_reached();
- }
- } else {
- switch (opcode) {
- case 0x2e: /* FCMLT (zero) */
- swap = true;
- /* fall through */
- case 0x2c: /* FCMGT (zero) */
- genfn = gen_helper_neon_cgt_f32;
- break;
- case 0x2d: /* FCMEQ (zero) */
- genfn = gen_helper_neon_ceq_f32;
- break;
- case 0x6d: /* FCMLE (zero) */
- swap = true;
- /* fall through */
- case 0x6c: /* FCMGE (zero) */
- genfn = gen_helper_neon_cge_f32;
- break;
- default:
- g_assert_not_reached();
- }
- }
-
- if (is_scalar) {
- maxpasses = 1;
- } else {
- int vector_size = 8 << is_q;
- maxpasses = vector_size >> size;
- }
+ TCGv_i32 t = tcg_temp_new_i32();
- for (pass = 0; pass < maxpasses; pass++) {
- read_vec_element_i32(s, tcg_op, rn, pass, size);
- if (swap) {
- genfn(tcg_res, tcg_zero, tcg_op, fpst);
- } else {
- genfn(tcg_res, tcg_op, tcg_zero, fpst);
- }
- if (is_scalar) {
- write_fp_sreg(s, rd, tcg_res);
- } else {
- write_vec_element_i32(s, tcg_res, rd, pass, size);
- }
- }
-
- if (!is_scalar) {
- clear_vec_high(s, is_q, rd);
- }
+ read_vec_element_i32(s, t, a->rn, 0, a->esz);
+ f->gen_bhs[a->esz](t, tcg_env, t);
+ write_fp_sreg(s, a->rd, t);
}
+ return true;
}
-static void handle_2misc_reciprocal(DisasContext *s, int opcode,
- bool is_scalar, bool is_u, bool is_q,
- int size, int rn, int rd)
+static bool do_env_vector1(DisasContext *s, arg_qrr_e *a, const ENVScalar1 *f)
{
- bool is_double = (size == 3);
- TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
+ if (a->esz == MO_64 && !a->q) {
+ return false;
+ }
+ if (!fp_access_check(s)) {
+ return true;
+ }
+ if (a->esz == MO_64) {
+ TCGv_i64 t = tcg_temp_new_i64();
- if (is_double) {
- TCGv_i64 tcg_op = tcg_temp_new_i64();
- TCGv_i64 tcg_res = tcg_temp_new_i64();
- int pass;
-
- for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
- read_vec_element(s, tcg_op, rn, pass, MO_64);
- switch (opcode) {
- case 0x3d: /* FRECPE */
- gen_helper_recpe_f64(tcg_res, tcg_op, fpst);
- break;
- case 0x3f: /* FRECPX */
- gen_helper_frecpx_f64(tcg_res, tcg_op, fpst);
- break;
- case 0x7d: /* FRSQRTE */
- gen_helper_rsqrte_f64(tcg_res, tcg_op, fpst);
- break;
- default:
- g_assert_not_reached();
- }
- write_vec_element(s, tcg_res, rd, pass, MO_64);
+ for (int i = 0; i < 2; ++i) {
+ read_vec_element(s, t, a->rn, i, MO_64);
+ f->gen_d(t, tcg_env, t);
+ write_vec_element(s, t, a->rd, i, MO_64);
}
- clear_vec_high(s, !is_scalar, rd);
} else {
- TCGv_i32 tcg_op = tcg_temp_new_i32();
- TCGv_i32 tcg_res = tcg_temp_new_i32();
- int pass, maxpasses;
+ TCGv_i32 t = tcg_temp_new_i32();
+ int n = (a->q ? 16 : 8) >> a->esz;
- if (is_scalar) {
- maxpasses = 1;
- } else {
- maxpasses = is_q ? 4 : 2;
- }
-
- for (pass = 0; pass < maxpasses; pass++) {
- read_vec_element_i32(s, tcg_op, rn, pass, MO_32);
-
- switch (opcode) {
- case 0x3c: /* URECPE */
- gen_helper_recpe_u32(tcg_res, tcg_op);
- break;
- case 0x3d: /* FRECPE */
- gen_helper_recpe_f32(tcg_res, tcg_op, fpst);
- break;
- case 0x3f: /* FRECPX */
- gen_helper_frecpx_f32(tcg_res, tcg_op, fpst);
- break;
- case 0x7d: /* FRSQRTE */
- gen_helper_rsqrte_f32(tcg_res, tcg_op, fpst);
- break;
- default:
- g_assert_not_reached();
- }
-
- if (is_scalar) {
- write_fp_sreg(s, rd, tcg_res);
- } else {
- write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
- }
- }
- if (!is_scalar) {
- clear_vec_high(s, is_q, rd);
+ for (int i = 0; i < n; ++i) {
+ read_vec_element_i32(s, t, a->rn, i, a->esz);
+ f->gen_bhs[a->esz](t, tcg_env, t);
+ write_vec_element_i32(s, t, a->rd, i, a->esz);
}
}
+ clear_vec_high(s, a->q, a->rd);
+ return true;
}
-static void handle_2misc_narrow(DisasContext *s, bool scalar,
- int opcode, bool u, bool is_q,
- int size, int rn, int rd)
-{
- /* Handle 2-reg-misc ops which are narrowing (so each 2*size element
- * in the source becomes a size element in the destination).
- */
- int pass;
- TCGv_i64 tcg_res[2];
- int destelt = is_q ? 2 : 0;
- int passes = scalar ? 1 : 2;
+static const ENVScalar1 f_scalar_sqabs = {
+ { gen_helper_neon_qabs_s8,
+ gen_helper_neon_qabs_s16,
+ gen_helper_neon_qabs_s32 },
+ gen_helper_neon_qabs_s64,
+};
+TRANS(SQABS_s, do_env_scalar1, a, &f_scalar_sqabs)
+TRANS(SQABS_v, do_env_vector1, a, &f_scalar_sqabs)
+
+static const ENVScalar1 f_scalar_sqneg = {
+ { gen_helper_neon_qneg_s8,
+ gen_helper_neon_qneg_s16,
+ gen_helper_neon_qneg_s32 },
+ gen_helper_neon_qneg_s64,
+};
+TRANS(SQNEG_s, do_env_scalar1, a, &f_scalar_sqneg)
+TRANS(SQNEG_v, do_env_vector1, a, &f_scalar_sqneg)
- if (scalar) {
- tcg_res[1] = tcg_constant_i64(0);
+static bool do_scalar1_d(DisasContext *s, arg_rr *a, ArithOneOp *f)
+{
+ if (fp_access_check(s)) {
+ TCGv_i64 t = read_fp_dreg(s, a->rn);
+ f(t, t);
+ write_fp_dreg(s, a->rd, t);
}
+ return true;
+}
- for (pass = 0; pass < passes; pass++) {
- TCGv_i64 tcg_op = tcg_temp_new_i64();
- NeonGenOne64OpFn *genfn = NULL;
- NeonGenOne64OpEnvFn *genenvfn = NULL;
+TRANS(ABS_s, do_scalar1_d, a, tcg_gen_abs_i64)
+TRANS(NEG_s, do_scalar1_d, a, tcg_gen_neg_i64)
- if (scalar) {
- read_vec_element(s, tcg_op, rn, pass, size + 1);
- } else {
- read_vec_element(s, tcg_op, rn, pass, MO_64);
- }
- tcg_res[pass] = tcg_temp_new_i64();
+static bool do_cmop0_d(DisasContext *s, arg_rr *a, TCGCond cond)
+{
+ if (fp_access_check(s)) {
+ TCGv_i64 t = read_fp_dreg(s, a->rn);
+ tcg_gen_negsetcond_i64(cond, t, t, tcg_constant_i64(0));
+ write_fp_dreg(s, a->rd, t);
+ }
+ return true;
+}
- switch (opcode) {
- case 0x12: /* XTN, SQXTUN */
- {
- static NeonGenOne64OpFn * const xtnfns[3] = {
- gen_helper_neon_narrow_u8,
- gen_helper_neon_narrow_u16,
- tcg_gen_ext32u_i64,
- };
- static NeonGenOne64OpEnvFn * const sqxtunfns[3] = {
- gen_helper_neon_unarrow_sat8,
- gen_helper_neon_unarrow_sat16,
- gen_helper_neon_unarrow_sat32,
- };
- if (u) {
- genenvfn = sqxtunfns[size];
- } else {
- genfn = xtnfns[size];
- }
- break;
- }
- case 0x14: /* SQXTN, UQXTN */
- {
- static NeonGenOne64OpEnvFn * const fns[3][2] = {
- { gen_helper_neon_narrow_sat_s8,
- gen_helper_neon_narrow_sat_u8 },
- { gen_helper_neon_narrow_sat_s16,
- gen_helper_neon_narrow_sat_u16 },
- { gen_helper_neon_narrow_sat_s32,
- gen_helper_neon_narrow_sat_u32 },
- };
- genenvfn = fns[size][u];
- break;
- }
- case 0x16: /* FCVTN, FCVTN2 */
- /* 32 bit to 16 bit or 64 bit to 32 bit float conversion */
- if (size == 2) {
- TCGv_i32 tmp = tcg_temp_new_i32();
- gen_helper_vfp_fcvtsd(tmp, tcg_op, tcg_env);
- tcg_gen_extu_i32_i64(tcg_res[pass], tmp);
- } else {
- TCGv_i32 tcg_lo = tcg_temp_new_i32();
- TCGv_i32 tcg_hi = tcg_temp_new_i32();
- TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
- TCGv_i32 ahp = get_ahp_flag();
-
- tcg_gen_extr_i64_i32(tcg_lo, tcg_hi, tcg_op);
- gen_helper_vfp_fcvt_f32_to_f16(tcg_lo, tcg_lo, fpst, ahp);
- gen_helper_vfp_fcvt_f32_to_f16(tcg_hi, tcg_hi, fpst, ahp);
- tcg_gen_deposit_i32(tcg_lo, tcg_lo, tcg_hi, 16, 16);
- tcg_gen_extu_i32_i64(tcg_res[pass], tcg_lo);
- }
- break;
- case 0x36: /* BFCVTN, BFCVTN2 */
- {
- TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
- TCGv_i32 tmp = tcg_temp_new_i32();
- gen_helper_bfcvt_pair(tmp, tcg_op, fpst);
- tcg_gen_extu_i32_i64(tcg_res[pass], tmp);
- }
- break;
- case 0x56: /* FCVTXN, FCVTXN2 */
- {
- /*
- * 64 bit to 32 bit float conversion
- * with von Neumann rounding (round to odd)
- */
- TCGv_i32 tmp = tcg_temp_new_i32();
- assert(size == 2);
- gen_helper_fcvtx_f64_to_f32(tmp, tcg_op, tcg_env);
- tcg_gen_extu_i32_i64(tcg_res[pass], tmp);
- }
- break;
- default:
- g_assert_not_reached();
- }
+TRANS(CMGT0_s, do_cmop0_d, a, TCG_COND_GT)
+TRANS(CMGE0_s, do_cmop0_d, a, TCG_COND_GE)
+TRANS(CMLE0_s, do_cmop0_d, a, TCG_COND_LE)
+TRANS(CMLT0_s, do_cmop0_d, a, TCG_COND_LT)
+TRANS(CMEQ0_s, do_cmop0_d, a, TCG_COND_EQ)
- if (genfn) {
- genfn(tcg_res[pass], tcg_op);
- } else if (genenvfn) {
- genenvfn(tcg_res[pass], tcg_env, tcg_op);
- }
+static bool do_2misc_narrow_scalar(DisasContext *s, arg_rr_e *a,
+ ArithOneOp * const fn[3])
+{
+ if (a->esz == MO_64) {
+ return false;
}
+ if (fp_access_check(s)) {
+ TCGv_i64 t = tcg_temp_new_i64();
- for (pass = 0; pass < 2; pass++) {
- write_vec_element(s, tcg_res[pass], rd, destelt + pass, MO_32);
+ read_vec_element(s, t, a->rn, 0, a->esz + 1);
+ fn[a->esz](t, t);
+ clear_vec(s, a->rd);
+ write_vec_element(s, t, a->rd, 0, a->esz);
}
- clear_vec_high(s, is_q, rd);
+ return true;
}
-/* AdvSIMD scalar two reg misc
- * 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0
- * +-----+---+-----------+------+-----------+--------+-----+------+------+
- * | 0 1 | U | 1 1 1 1 0 | size | 1 0 0 0 0 | opcode | 1 0 | Rn | Rd |
- * +-----+---+-----------+------+-----------+--------+-----+------+------+
- */
-static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn)
-{
- int rd = extract32(insn, 0, 5);
- int rn = extract32(insn, 5, 5);
- int opcode = extract32(insn, 12, 5);
- int size = extract32(insn, 22, 2);
- bool u = extract32(insn, 29, 1);
- bool is_fcvt = false;
- int rmode;
- TCGv_i32 tcg_rmode;
- TCGv_ptr tcg_fpstatus;
+#define WRAP_ENV(NAME) \
+ static void gen_##NAME(TCGv_i64 d, TCGv_i64 n) \
+ { gen_helper_##NAME(d, tcg_env, n); }
- switch (opcode) {
- case 0x7: /* SQABS / SQNEG */
- break;
- case 0xa: /* CMLT */
- if (u) {
- unallocated_encoding(s);
- return;
- }
- /* fall through */
- case 0x8: /* CMGT, CMGE */
- case 0x9: /* CMEQ, CMLE */
- case 0xb: /* ABS, NEG */
- if (size != 3) {
- unallocated_encoding(s);
- return;
- }
- break;
- case 0x12: /* SQXTUN */
- if (!u) {
- unallocated_encoding(s);
- return;
- }
- /* fall through */
- case 0x14: /* SQXTN, UQXTN */
- if (size == 3) {
- unallocated_encoding(s);
- return;
- }
- if (!fp_access_check(s)) {
- return;
- }
- handle_2misc_narrow(s, true, opcode, u, false, size, rn, rd);
- return;
- case 0xc ... 0xf:
- case 0x16 ... 0x1d:
- case 0x1f:
- /* Floating point: U, size[1] and opcode indicate operation;
- * size[0] indicates single or double precision.
- */
- opcode |= (extract32(size, 1, 1) << 5) | (u << 6);
- size = extract32(size, 0, 1) ? 3 : 2;
- switch (opcode) {
- case 0x2c: /* FCMGT (zero) */
- case 0x2d: /* FCMEQ (zero) */
- case 0x2e: /* FCMLT (zero) */
- case 0x6c: /* FCMGE (zero) */
- case 0x6d: /* FCMLE (zero) */
- handle_2misc_fcmp_zero(s, opcode, true, u, true, size, rn, rd);
- return;
- case 0x1d: /* SCVTF */
- case 0x5d: /* UCVTF */
- {
- bool is_signed = (opcode == 0x1d);
- if (!fp_access_check(s)) {
- return;
- }
- handle_simd_intfp_conv(s, rd, rn, 1, is_signed, 0, size);
- return;
- }
- case 0x3d: /* FRECPE */
- case 0x3f: /* FRECPX */
- case 0x7d: /* FRSQRTE */
- if (!fp_access_check(s)) {
- return;
- }
- handle_2misc_reciprocal(s, opcode, true, u, true, size, rn, rd);
- return;
- case 0x1a: /* FCVTNS */
- case 0x1b: /* FCVTMS */
- case 0x3a: /* FCVTPS */
- case 0x3b: /* FCVTZS */
- case 0x5a: /* FCVTNU */
- case 0x5b: /* FCVTMU */
- case 0x7a: /* FCVTPU */
- case 0x7b: /* FCVTZU */
- is_fcvt = true;
- rmode = extract32(opcode, 5, 1) | (extract32(opcode, 0, 1) << 1);
- break;
- case 0x1c: /* FCVTAS */
- case 0x5c: /* FCVTAU */
- /* TIEAWAY doesn't fit in the usual rounding mode encoding */
- is_fcvt = true;
- rmode = FPROUNDING_TIEAWAY;
- break;
- case 0x56: /* FCVTXN, FCVTXN2 */
- if (size == 2) {
- unallocated_encoding(s);
- return;
- }
- if (!fp_access_check(s)) {
- return;
- }
- handle_2misc_narrow(s, true, opcode, u, false, size - 1, rn, rd);
- return;
- default:
- unallocated_encoding(s);
- return;
- }
- break;
- default:
- case 0x3: /* USQADD / SUQADD */
- unallocated_encoding(s);
- return;
- }
+WRAP_ENV(neon_unarrow_sat8)
+WRAP_ENV(neon_unarrow_sat16)
+WRAP_ENV(neon_unarrow_sat32)
- if (!fp_access_check(s)) {
- return;
- }
+static ArithOneOp * const f_scalar_sqxtun[] = {
+ gen_neon_unarrow_sat8,
+ gen_neon_unarrow_sat16,
+ gen_neon_unarrow_sat32,
+};
+TRANS(SQXTUN_s, do_2misc_narrow_scalar, a, f_scalar_sqxtun)
- if (is_fcvt) {
- tcg_fpstatus = fpstatus_ptr(FPST_FPCR);
- tcg_rmode = gen_set_rmode(rmode, tcg_fpstatus);
- } else {
- tcg_fpstatus = NULL;
- tcg_rmode = NULL;
- }
+WRAP_ENV(neon_narrow_sat_s8)
+WRAP_ENV(neon_narrow_sat_s16)
+WRAP_ENV(neon_narrow_sat_s32)
- if (size == 3) {
- TCGv_i64 tcg_rn = read_fp_dreg(s, rn);
- TCGv_i64 tcg_rd = tcg_temp_new_i64();
+static ArithOneOp * const f_scalar_sqxtn[] = {
+ gen_neon_narrow_sat_s8,
+ gen_neon_narrow_sat_s16,
+ gen_neon_narrow_sat_s32,
+};
+TRANS(SQXTN_s, do_2misc_narrow_scalar, a, f_scalar_sqxtn)
- handle_2misc_64(s, opcode, u, tcg_rd, tcg_rn, tcg_rmode, tcg_fpstatus);
- write_fp_dreg(s, rd, tcg_rd);
- } else {
- TCGv_i32 tcg_rn = tcg_temp_new_i32();
- TCGv_i32 tcg_rd = tcg_temp_new_i32();
+WRAP_ENV(neon_narrow_sat_u8)
+WRAP_ENV(neon_narrow_sat_u16)
+WRAP_ENV(neon_narrow_sat_u32)
- read_vec_element_i32(s, tcg_rn, rn, 0, size);
+static ArithOneOp * const f_scalar_uqxtn[] = {
+ gen_neon_narrow_sat_u8,
+ gen_neon_narrow_sat_u16,
+ gen_neon_narrow_sat_u32,
+};
+TRANS(UQXTN_s, do_2misc_narrow_scalar, a, f_scalar_uqxtn)
- switch (opcode) {
- case 0x7: /* SQABS, SQNEG */
- {
- NeonGenOneOpEnvFn *genfn;
- static NeonGenOneOpEnvFn * const fns[3][2] = {
- { gen_helper_neon_qabs_s8, gen_helper_neon_qneg_s8 },
- { gen_helper_neon_qabs_s16, gen_helper_neon_qneg_s16 },
- { gen_helper_neon_qabs_s32, gen_helper_neon_qneg_s32 },
- };
- genfn = fns[size][u];
- genfn(tcg_rd, tcg_env, tcg_rn);
- break;
- }
- case 0x1a: /* FCVTNS */
- case 0x1b: /* FCVTMS */
- case 0x1c: /* FCVTAS */
- case 0x3a: /* FCVTPS */
- case 0x3b: /* FCVTZS */
- gen_helper_vfp_tosls(tcg_rd, tcg_rn, tcg_constant_i32(0),
- tcg_fpstatus);
- break;
- case 0x5a: /* FCVTNU */
- case 0x5b: /* FCVTMU */
- case 0x5c: /* FCVTAU */
- case 0x7a: /* FCVTPU */
- case 0x7b: /* FCVTZU */
- gen_helper_vfp_touls(tcg_rd, tcg_rn, tcg_constant_i32(0),
- tcg_fpstatus);
- break;
- default:
- g_assert_not_reached();
- }
+static void gen_fcvtxn_sd(TCGv_i64 d, TCGv_i64 n)
+{
+ /*
+ * 64 bit to 32 bit float conversion
+ * with von Neumann rounding (round to odd)
+ */
+ TCGv_i32 tmp = tcg_temp_new_i32();
+ gen_helper_fcvtx_f64_to_f32(tmp, n, tcg_env);
+ tcg_gen_extu_i32_i64(d, tmp);
+}
- write_fp_sreg(s, rd, tcg_rd);
- }
+static ArithOneOp * const f_scalar_fcvtxn[] = {
+ NULL,
+ NULL,
+ gen_fcvtxn_sd,
+};
+TRANS(FCVTXN_s, do_2misc_narrow_scalar, a, f_scalar_fcvtxn)
- if (is_fcvt) {
- gen_restore_rmode(tcg_rmode, tcg_fpstatus);
- }
-}
+#undef WRAP_ENV
-/* AdvSIMD shift by immediate
- * 31 30 29 28 23 22 19 18 16 15 11 10 9 5 4 0
- * +---+---+---+-------------+------+------+--------+---+------+------+
- * | 0 | Q | U | 0 1 1 1 1 0 | immh | immb | opcode | 1 | Rn | Rd |
- * +---+---+---+-------------+------+------+--------+---+------+------+
- */
-static void disas_simd_shift_imm(DisasContext *s, uint32_t insn)
+static bool do_gvec_fn2(DisasContext *s, arg_qrr_e *a, GVecGen2Fn *fn)
{
- int rd = extract32(insn, 0, 5);
- int rn = extract32(insn, 5, 5);
- int opcode = extract32(insn, 11, 5);
- int immb = extract32(insn, 16, 3);
- int immh = extract32(insn, 19, 4);
- bool is_u = extract32(insn, 29, 1);
- bool is_q = extract32(insn, 30, 1);
-
- if (immh == 0) {
- unallocated_encoding(s);
- return;
+ if (!a->q && a->esz == MO_64) {
+ return false;
}
-
- switch (opcode) {
- case 0x1c: /* SCVTF / UCVTF */
- handle_simd_shift_intfp_conv(s, false, is_q, is_u, immh, immb,
- opcode, rn, rd);
- break;
- case 0x1f: /* FCVTZS/ FCVTZU */
- handle_simd_shift_fpint_conv(s, false, is_q, is_u, immh, immb, rn, rd);
- return;
- default:
- case 0x00: /* SSHR / USHR */
- case 0x02: /* SSRA / USRA (accumulate) */
- case 0x04: /* SRSHR / URSHR (rounding) */
- case 0x06: /* SRSRA / URSRA (accum + rounding) */
- case 0x08: /* SRI */
- case 0x0a: /* SHL / SLI */
- case 0x0c: /* SQSHLU */
- case 0x0e: /* SQSHL, UQSHL */
- case 0x10: /* SHRN / SQSHRUN */
- case 0x11: /* RSHRN / SQRSHRUN */
- case 0x12: /* SQSHRN / UQSHRN */
- case 0x13: /* SQRSHRN / UQRSHRN */
- case 0x14: /* SSHLL / USHLL */
- unallocated_encoding(s);
- return;
+ if (fp_access_check(s)) {
+ gen_gvec_fn2(s, a->q, a->rd, a->rn, fn, a->esz);
}
+ return true;
}
-static void handle_2misc_widening(DisasContext *s, int opcode, bool is_q,
- int size, int rn, int rd)
-{
- /* Handle 2-reg-misc ops which are widening (so each size element
- * in the source becomes a 2*size element in the destination.
- * The only instruction like this is FCVTL.
- */
- int pass;
-
- if (size == 3) {
- /* 32 -> 64 bit fp conversion */
- TCGv_i64 tcg_res[2];
- int srcelt = is_q ? 2 : 0;
+TRANS(ABS_v, do_gvec_fn2, a, tcg_gen_gvec_abs)
+TRANS(NEG_v, do_gvec_fn2, a, tcg_gen_gvec_neg)
+TRANS(NOT_v, do_gvec_fn2, a, tcg_gen_gvec_not)
+TRANS(CNT_v, do_gvec_fn2, a, gen_gvec_cnt)
+TRANS(RBIT_v, do_gvec_fn2, a, gen_gvec_rbit)
+TRANS(CMGT0_v, do_gvec_fn2, a, gen_gvec_cgt0)
+TRANS(CMGE0_v, do_gvec_fn2, a, gen_gvec_cge0)
+TRANS(CMLT0_v, do_gvec_fn2, a, gen_gvec_clt0)
+TRANS(CMLE0_v, do_gvec_fn2, a, gen_gvec_cle0)
+TRANS(CMEQ0_v, do_gvec_fn2, a, gen_gvec_ceq0)
+TRANS(REV16_v, do_gvec_fn2, a, gen_gvec_rev16)
+TRANS(REV32_v, do_gvec_fn2, a, gen_gvec_rev32)
+TRANS(URECPE_v, do_gvec_fn2, a, gen_gvec_urecpe)
+TRANS(URSQRTE_v, do_gvec_fn2, a, gen_gvec_ursqrte)
- for (pass = 0; pass < 2; pass++) {
- TCGv_i32 tcg_op = tcg_temp_new_i32();
- tcg_res[pass] = tcg_temp_new_i64();
-
- read_vec_element_i32(s, tcg_op, rn, srcelt + pass, MO_32);
- gen_helper_vfp_fcvtds(tcg_res[pass], tcg_op, tcg_env);
- }
- for (pass = 0; pass < 2; pass++) {
- write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
- }
- } else {
- /* 16 -> 32 bit fp conversion */
- int srcelt = is_q ? 4 : 0;
- TCGv_i32 tcg_res[4];
- TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
- TCGv_i32 ahp = get_ahp_flag();
-
- for (pass = 0; pass < 4; pass++) {
- tcg_res[pass] = tcg_temp_new_i32();
-
- read_vec_element_i32(s, tcg_res[pass], rn, srcelt + pass, MO_16);
- gen_helper_vfp_fcvt_f16_to_f32(tcg_res[pass], tcg_res[pass],
- fpst, ahp);
- }
- for (pass = 0; pass < 4; pass++) {
- write_vec_element_i32(s, tcg_res[pass], rd, pass, MO_32);
- }
+static bool do_gvec_fn2_bhs(DisasContext *s, arg_qrr_e *a, GVecGen2Fn *fn)
+{
+ if (a->esz == MO_64) {
+ return false;
+ }
+ if (fp_access_check(s)) {
+ gen_gvec_fn2(s, a->q, a->rd, a->rn, fn, a->esz);
}
+ return true;
}
-static void handle_rev(DisasContext *s, int opcode, bool u,
- bool is_q, int size, int rn, int rd)
-{
- int op = (opcode << 1) | u;
- int opsz = op + size;
- int grp_size = 3 - opsz;
- int dsize = is_q ? 128 : 64;
- int i;
+TRANS(CLS_v, do_gvec_fn2_bhs, a, gen_gvec_cls)
+TRANS(CLZ_v, do_gvec_fn2_bhs, a, gen_gvec_clz)
+TRANS(REV64_v, do_gvec_fn2_bhs, a, gen_gvec_rev64)
+TRANS(SADDLP_v, do_gvec_fn2_bhs, a, gen_gvec_saddlp)
+TRANS(UADDLP_v, do_gvec_fn2_bhs, a, gen_gvec_uaddlp)
+TRANS(SADALP_v, do_gvec_fn2_bhs, a, gen_gvec_sadalp)
+TRANS(UADALP_v, do_gvec_fn2_bhs, a, gen_gvec_uadalp)
- if (opsz >= 3) {
- unallocated_encoding(s);
- return;
+static bool do_2misc_narrow_vector(DisasContext *s, arg_qrr_e *a,
+ ArithOneOp * const fn[3])
+{
+ if (a->esz == MO_64) {
+ return false;
}
+ if (fp_access_check(s)) {
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ TCGv_i64 t1 = tcg_temp_new_i64();
- if (!fp_access_check(s)) {
- return;
+ read_vec_element(s, t0, a->rn, 0, MO_64);
+ read_vec_element(s, t1, a->rn, 1, MO_64);
+ fn[a->esz](t0, t0);
+ fn[a->esz](t1, t1);
+ write_vec_element(s, t0, a->rd, a->q ? 2 : 0, MO_32);
+ write_vec_element(s, t1, a->rd, a->q ? 3 : 1, MO_32);
+ clear_vec_high(s, a->q, a->rd);
}
+ return true;
+}
- if (size == 0) {
- /* Special case bytes, use bswap op on each group of elements */
- int groups = dsize / (8 << grp_size);
-
- for (i = 0; i < groups; i++) {
- TCGv_i64 tcg_tmp = tcg_temp_new_i64();
-
- read_vec_element(s, tcg_tmp, rn, i, grp_size);
- switch (grp_size) {
- case MO_16:
- tcg_gen_bswap16_i64(tcg_tmp, tcg_tmp, TCG_BSWAP_IZ);
- break;
- case MO_32:
- tcg_gen_bswap32_i64(tcg_tmp, tcg_tmp, TCG_BSWAP_IZ);
- break;
- case MO_64:
- tcg_gen_bswap64_i64(tcg_tmp, tcg_tmp);
- break;
- default:
- g_assert_not_reached();
- }
- write_vec_element(s, tcg_tmp, rd, i, grp_size);
- }
- clear_vec_high(s, is_q, rd);
- } else {
- int revmask = (1 << grp_size) - 1;
- int esize = 8 << size;
- int elements = dsize / esize;
- TCGv_i64 tcg_rn = tcg_temp_new_i64();
- TCGv_i64 tcg_rd[2];
-
- for (i = 0; i < 2; i++) {
- tcg_rd[i] = tcg_temp_new_i64();
- tcg_gen_movi_i64(tcg_rd[i], 0);
- }
-
- for (i = 0; i < elements; i++) {
- int e_rev = (i & 0xf) ^ revmask;
- int w = (e_rev * esize) / 64;
- int o = (e_rev * esize) % 64;
+static ArithOneOp * const f_scalar_xtn[] = {
+ gen_helper_neon_narrow_u8,
+ gen_helper_neon_narrow_u16,
+ tcg_gen_ext32u_i64,
+};
+TRANS(XTN, do_2misc_narrow_vector, a, f_scalar_xtn)
+TRANS(SQXTUN_v, do_2misc_narrow_vector, a, f_scalar_sqxtun)
+TRANS(SQXTN_v, do_2misc_narrow_vector, a, f_scalar_sqxtn)
+TRANS(UQXTN_v, do_2misc_narrow_vector, a, f_scalar_uqxtn)
- read_vec_element(s, tcg_rn, rn, i, size);
- tcg_gen_deposit_i64(tcg_rd[w], tcg_rd[w], tcg_rn, o, esize);
- }
+static void gen_fcvtn_hs(TCGv_i64 d, TCGv_i64 n)
+{
+ TCGv_i32 tcg_lo = tcg_temp_new_i32();
+ TCGv_i32 tcg_hi = tcg_temp_new_i32();
+ TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
+ TCGv_i32 ahp = get_ahp_flag();
- for (i = 0; i < 2; i++) {
- write_vec_element(s, tcg_rd[i], rd, i, MO_64);
- }
- clear_vec_high(s, true, rd);
- }
+ tcg_gen_extr_i64_i32(tcg_lo, tcg_hi, n);
+ gen_helper_vfp_fcvt_f32_to_f16(tcg_lo, tcg_lo, fpst, ahp);
+ gen_helper_vfp_fcvt_f32_to_f16(tcg_hi, tcg_hi, fpst, ahp);
+ tcg_gen_deposit_i32(tcg_lo, tcg_lo, tcg_hi, 16, 16);
+ tcg_gen_extu_i32_i64(d, tcg_lo);
}
-static void handle_2misc_pairwise(DisasContext *s, int opcode, bool u,
- bool is_q, int size, int rn, int rd)
+static void gen_fcvtn_sd(TCGv_i64 d, TCGv_i64 n)
{
- /* Implement the pairwise operations from 2-misc:
- * SADDLP, UADDLP, SADALP, UADALP.
- * These all add pairs of elements in the input to produce a
- * double-width result element in the output (possibly accumulating).
- */
- bool accum = (opcode == 0x6);
- int maxpass = is_q ? 2 : 1;
- int pass;
- TCGv_i64 tcg_res[2];
-
- if (size == 2) {
- /* 32 + 32 -> 64 op */
- MemOp memop = size + (u ? 0 : MO_SIGN);
-
- for (pass = 0; pass < maxpass; pass++) {
- TCGv_i64 tcg_op1 = tcg_temp_new_i64();
- TCGv_i64 tcg_op2 = tcg_temp_new_i64();
+ TCGv_i32 tmp = tcg_temp_new_i32();
+ gen_helper_vfp_fcvtsd(tmp, n, tcg_env);
+ tcg_gen_extu_i32_i64(d, tmp);
+}
- tcg_res[pass] = tcg_temp_new_i64();
+static ArithOneOp * const f_vector_fcvtn[] = {
+ NULL,
+ gen_fcvtn_hs,
+ gen_fcvtn_sd,
+};
+TRANS(FCVTN_v, do_2misc_narrow_vector, a, f_vector_fcvtn)
+TRANS(FCVTXN_v, do_2misc_narrow_vector, a, f_scalar_fcvtxn)
- read_vec_element(s, tcg_op1, rn, pass * 2, memop);
- read_vec_element(s, tcg_op2, rn, pass * 2 + 1, memop);
- tcg_gen_add_i64(tcg_res[pass], tcg_op1, tcg_op2);
- if (accum) {
- read_vec_element(s, tcg_op1, rd, pass, MO_64);
- tcg_gen_add_i64(tcg_res[pass], tcg_res[pass], tcg_op1);
- }
- }
- } else {
- for (pass = 0; pass < maxpass; pass++) {
- TCGv_i64 tcg_op = tcg_temp_new_i64();
- NeonGenOne64OpFn *genfn;
- static NeonGenOne64OpFn * const fns[2][2] = {
- { gen_helper_neon_addlp_s8, gen_helper_neon_addlp_u8 },
- { gen_helper_neon_addlp_s16, gen_helper_neon_addlp_u16 },
- };
+static void gen_bfcvtn_hs(TCGv_i64 d, TCGv_i64 n)
+{
+ TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
+ TCGv_i32 tmp = tcg_temp_new_i32();
+ gen_helper_bfcvt_pair(tmp, n, fpst);
+ tcg_gen_extu_i32_i64(d, tmp);
+}
- genfn = fns[size][u];
+static ArithOneOp * const f_vector_bfcvtn[] = {
+ NULL,
+ gen_bfcvtn_hs,
+ NULL,
+};
+TRANS_FEAT(BFCVTN_v, aa64_bf16, do_2misc_narrow_vector, a, f_vector_bfcvtn)
- tcg_res[pass] = tcg_temp_new_i64();
+static bool trans_SHLL_v(DisasContext *s, arg_qrr_e *a)
+{
+ static NeonGenWidenFn * const widenfns[3] = {
+ gen_helper_neon_widen_u8,
+ gen_helper_neon_widen_u16,
+ tcg_gen_extu_i32_i64,
+ };
+ NeonGenWidenFn *widenfn;
+ TCGv_i64 tcg_res[2];
+ TCGv_i32 tcg_op;
+ int part, pass;
- read_vec_element(s, tcg_op, rn, pass, MO_64);
- genfn(tcg_res[pass], tcg_op);
-
- if (accum) {
- read_vec_element(s, tcg_op, rd, pass, MO_64);
- if (size == 0) {
- gen_helper_neon_addl_u16(tcg_res[pass],
- tcg_res[pass], tcg_op);
- } else {
- gen_helper_neon_addl_u32(tcg_res[pass],
- tcg_res[pass], tcg_op);
- }
- }
- }
- }
- if (!is_q) {
- tcg_res[1] = tcg_constant_i64(0);
+ if (a->esz == MO_64) {
+ return false;
}
- for (pass = 0; pass < 2; pass++) {
- write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
+ if (!fp_access_check(s)) {
+ return true;
}
-}
-static void handle_shll(DisasContext *s, bool is_q, int size, int rn, int rd)
-{
- /* Implement SHLL and SHLL2 */
- int pass;
- int part = is_q ? 2 : 0;
- TCGv_i64 tcg_res[2];
+ tcg_op = tcg_temp_new_i32();
+ widenfn = widenfns[a->esz];
+ part = a->q ? 2 : 0;
for (pass = 0; pass < 2; pass++) {
- static NeonGenWidenFn * const widenfns[3] = {
- gen_helper_neon_widen_u8,
- gen_helper_neon_widen_u16,
- tcg_gen_extu_i32_i64,
- };
- NeonGenWidenFn *widenfn = widenfns[size];
- TCGv_i32 tcg_op = tcg_temp_new_i32();
-
- read_vec_element_i32(s, tcg_op, rn, part + pass, MO_32);
+ read_vec_element_i32(s, tcg_op, a->rn, part + pass, MO_32);
tcg_res[pass] = tcg_temp_new_i64();
widenfn(tcg_res[pass], tcg_op);
- tcg_gen_shli_i64(tcg_res[pass], tcg_res[pass], 8 << size);
+ tcg_gen_shli_i64(tcg_res[pass], tcg_res[pass], 8 << a->esz);
}
for (pass = 0; pass < 2; pass++) {
- write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
+ write_vec_element(s, tcg_res[pass], a->rd, pass, MO_64);
}
+ return true;
}
-/* AdvSIMD two reg misc
- * 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0
- * +---+---+---+-----------+------+-----------+--------+-----+------+------+
- * | 0 | Q | U | 0 1 1 1 0 | size | 1 0 0 0 0 | opcode | 1 0 | Rn | Rd |
- * +---+---+---+-----------+------+-----------+--------+-----+------+------+
- */
-static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
-{
- int size = extract32(insn, 22, 2);
- int opcode = extract32(insn, 12, 5);
- bool u = extract32(insn, 29, 1);
- bool is_q = extract32(insn, 30, 1);
- int rn = extract32(insn, 5, 5);
- int rd = extract32(insn, 0, 5);
- bool need_fpstatus = false;
- int rmode = -1;
- TCGv_i32 tcg_rmode;
- TCGv_ptr tcg_fpstatus;
-
- switch (opcode) {
- case 0x0: /* REV64, REV32 */
- case 0x1: /* REV16 */
- handle_rev(s, opcode, u, is_q, size, rn, rd);
- return;
- case 0x5: /* CNT, NOT, RBIT */
- if (u && size == 0) {
- /* NOT */
- break;
- } else if (u && size == 1) {
- /* RBIT */
- break;
- } else if (!u && size == 0) {
- /* CNT */
- break;
- }
- unallocated_encoding(s);
- return;
- case 0x12: /* XTN, XTN2, SQXTUN, SQXTUN2 */
- case 0x14: /* SQXTN, SQXTN2, UQXTN, UQXTN2 */
- if (size == 3) {
- unallocated_encoding(s);
- return;
- }
- if (!fp_access_check(s)) {
- return;
- }
-
- handle_2misc_narrow(s, false, opcode, u, is_q, size, rn, rd);
- return;
- case 0x4: /* CLS, CLZ */
- if (size == 3) {
- unallocated_encoding(s);
- return;
- }
- break;
- case 0x2: /* SADDLP, UADDLP */
- case 0x6: /* SADALP, UADALP */
- if (size == 3) {
- unallocated_encoding(s);
- return;
- }
- if (!fp_access_check(s)) {
- return;
- }
- handle_2misc_pairwise(s, opcode, u, is_q, size, rn, rd);
- return;
- case 0x13: /* SHLL, SHLL2 */
- if (u == 0 || size == 3) {
- unallocated_encoding(s);
- return;
- }
- if (!fp_access_check(s)) {
- return;
- }
- handle_shll(s, is_q, size, rn, rd);
- return;
- case 0xa: /* CMLT */
- if (u == 1) {
- unallocated_encoding(s);
- return;
- }
- /* fall through */
- case 0x8: /* CMGT, CMGE */
- case 0x9: /* CMEQ, CMLE */
- case 0xb: /* ABS, NEG */
- if (size == 3 && !is_q) {
- unallocated_encoding(s);
- return;
- }
- break;
- case 0x7: /* SQABS, SQNEG */
- if (size == 3 && !is_q) {
- unallocated_encoding(s);
- return;
- }
- break;
- case 0xc ... 0xf:
- case 0x16 ... 0x1f:
- {
- /* Floating point: U, size[1] and opcode indicate operation;
- * size[0] indicates single or double precision.
- */
- int is_double = extract32(size, 0, 1);
- opcode |= (extract32(size, 1, 1) << 5) | (u << 6);
- size = is_double ? 3 : 2;
- switch (opcode) {
- case 0x2f: /* FABS */
- case 0x6f: /* FNEG */
- if (size == 3 && !is_q) {
- unallocated_encoding(s);
- return;
- }
- break;
- case 0x1d: /* SCVTF */
- case 0x5d: /* UCVTF */
- {
- bool is_signed = (opcode == 0x1d) ? true : false;
- int elements = is_double ? 2 : is_q ? 4 : 2;
- if (is_double && !is_q) {
- unallocated_encoding(s);
- return;
- }
- if (!fp_access_check(s)) {
- return;
- }
- handle_simd_intfp_conv(s, rd, rn, elements, is_signed, 0, size);
- return;
- }
- case 0x2c: /* FCMGT (zero) */
- case 0x2d: /* FCMEQ (zero) */
- case 0x2e: /* FCMLT (zero) */
- case 0x6c: /* FCMGE (zero) */
- case 0x6d: /* FCMLE (zero) */
- if (size == 3 && !is_q) {
- unallocated_encoding(s);
- return;
- }
- handle_2misc_fcmp_zero(s, opcode, false, u, is_q, size, rn, rd);
- return;
- case 0x7f: /* FSQRT */
- if (size == 3 && !is_q) {
- unallocated_encoding(s);
- return;
- }
- break;
- case 0x1a: /* FCVTNS */
- case 0x1b: /* FCVTMS */
- case 0x3a: /* FCVTPS */
- case 0x3b: /* FCVTZS */
- case 0x5a: /* FCVTNU */
- case 0x5b: /* FCVTMU */
- case 0x7a: /* FCVTPU */
- case 0x7b: /* FCVTZU */
- need_fpstatus = true;
- rmode = extract32(opcode, 5, 1) | (extract32(opcode, 0, 1) << 1);
- if (size == 3 && !is_q) {
- unallocated_encoding(s);
- return;
- }
- break;
- case 0x5c: /* FCVTAU */
- case 0x1c: /* FCVTAS */
- need_fpstatus = true;
- rmode = FPROUNDING_TIEAWAY;
- if (size == 3 && !is_q) {
- unallocated_encoding(s);
- return;
- }
- break;
- case 0x3c: /* URECPE */
- if (size == 3) {
- unallocated_encoding(s);
- return;
- }
- /* fall through */
- case 0x3d: /* FRECPE */
- case 0x7d: /* FRSQRTE */
- if (size == 3 && !is_q) {
- unallocated_encoding(s);
- return;
- }
- if (!fp_access_check(s)) {
- return;
- }
- handle_2misc_reciprocal(s, opcode, false, u, is_q, size, rn, rd);
- return;
- case 0x56: /* FCVTXN, FCVTXN2 */
- if (size == 2) {
- unallocated_encoding(s);
- return;
- }
- /* fall through */
- case 0x16: /* FCVTN, FCVTN2 */
- /* handle_2misc_narrow does a 2*size -> size operation, but these
- * instructions encode the source size rather than dest size.
- */
- if (!fp_access_check(s)) {
- return;
- }
- handle_2misc_narrow(s, false, opcode, 0, is_q, size - 1, rn, rd);
- return;
- case 0x36: /* BFCVTN, BFCVTN2 */
- if (!dc_isar_feature(aa64_bf16, s) || size != 2) {
- unallocated_encoding(s);
- return;
- }
- if (!fp_access_check(s)) {
- return;
- }
- handle_2misc_narrow(s, false, opcode, 0, is_q, size - 1, rn, rd);
- return;
- case 0x17: /* FCVTL, FCVTL2 */
- if (!fp_access_check(s)) {
- return;
- }
- handle_2misc_widening(s, opcode, is_q, size, rn, rd);
- return;
- case 0x18: /* FRINTN */
- case 0x19: /* FRINTM */
- case 0x38: /* FRINTP */
- case 0x39: /* FRINTZ */
- rmode = extract32(opcode, 5, 1) | (extract32(opcode, 0, 1) << 1);
- /* fall through */
- case 0x59: /* FRINTX */
- case 0x79: /* FRINTI */
- need_fpstatus = true;
- if (size == 3 && !is_q) {
- unallocated_encoding(s);
- return;
- }
- break;
- case 0x58: /* FRINTA */
- rmode = FPROUNDING_TIEAWAY;
- need_fpstatus = true;
- if (size == 3 && !is_q) {
- unallocated_encoding(s);
- return;
- }
- break;
- case 0x7c: /* URSQRTE */
- if (size == 3) {
- unallocated_encoding(s);
- return;
- }
- break;
- case 0x1e: /* FRINT32Z */
- case 0x1f: /* FRINT64Z */
- rmode = FPROUNDING_ZERO;
- /* fall through */
- case 0x5e: /* FRINT32X */
- case 0x5f: /* FRINT64X */
- need_fpstatus = true;
- if ((size == 3 && !is_q) || !dc_isar_feature(aa64_frint, s)) {
- unallocated_encoding(s);
- return;
- }
- break;
- default:
- unallocated_encoding(s);
- return;
- }
- break;
- }
- default:
- case 0x3: /* SUQADD, USQADD */
- unallocated_encoding(s);
- return;
- }
+static bool do_fabs_fneg_v(DisasContext *s, arg_qrr_e *a, GVecGen2Fn *fn)
+{
+ int check = fp_access_check_vector_hsd(s, a->q, a->esz);
- if (!fp_access_check(s)) {
- return;
+ if (check <= 0) {
+ return check == 0;
}
- if (need_fpstatus || rmode >= 0) {
- tcg_fpstatus = fpstatus_ptr(FPST_FPCR);
- } else {
- tcg_fpstatus = NULL;
- }
- if (rmode >= 0) {
- tcg_rmode = gen_set_rmode(rmode, tcg_fpstatus);
- } else {
- tcg_rmode = NULL;
- }
+ gen_gvec_fn2(s, a->q, a->rd, a->rn, fn, a->esz);
+ return true;
+}
- switch (opcode) {
- case 0x5:
- if (u && size == 0) { /* NOT */
- gen_gvec_fn2(s, is_q, rd, rn, tcg_gen_gvec_not, 0);
- return;
- }
- break;
- case 0x8: /* CMGT, CMGE */
- if (u) {
- gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_cge0, size);
- } else {
- gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_cgt0, size);
- }
- return;
- case 0x9: /* CMEQ, CMLE */
- if (u) {
- gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_cle0, size);
- } else {
- gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_ceq0, size);
- }
- return;
- case 0xa: /* CMLT */
- gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_clt0, size);
- return;
- case 0xb:
- if (u) { /* ABS, NEG */
- gen_gvec_fn2(s, is_q, rd, rn, tcg_gen_gvec_neg, size);
- } else {
- gen_gvec_fn2(s, is_q, rd, rn, tcg_gen_gvec_abs, size);
- }
- return;
- }
+TRANS(FABS_v, do_fabs_fneg_v, a, gen_gvec_fabs)
+TRANS(FNEG_v, do_fabs_fneg_v, a, gen_gvec_fneg)
- if (size == 3) {
- /* All 64-bit element operations can be shared with scalar 2misc */
- int pass;
+static bool do_fp1_vector(DisasContext *s, arg_qrr_e *a,
+ const FPScalar1 *f, int rmode)
+{
+ TCGv_i32 tcg_rmode = NULL;
+ TCGv_ptr fpst;
+ int check = fp_access_check_vector_hsd(s, a->q, a->esz);
- /* Coverity claims (size == 3 && !is_q) has been eliminated
- * from all paths leading to here.
- */
- tcg_debug_assert(is_q);
- for (pass = 0; pass < 2; pass++) {
- TCGv_i64 tcg_op = tcg_temp_new_i64();
- TCGv_i64 tcg_res = tcg_temp_new_i64();
+ if (check <= 0) {
+ return check == 0;
+ }
- read_vec_element(s, tcg_op, rn, pass, MO_64);
+ fpst = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR);
+ if (rmode >= 0) {
+ tcg_rmode = gen_set_rmode(rmode, fpst);
+ }
- handle_2misc_64(s, opcode, u, tcg_res, tcg_op,
- tcg_rmode, tcg_fpstatus);
+ if (a->esz == MO_64) {
+ TCGv_i64 t64 = tcg_temp_new_i64();
- write_vec_element(s, tcg_res, rd, pass, MO_64);
+ for (int pass = 0; pass < 2; ++pass) {
+ read_vec_element(s, t64, a->rn, pass, MO_64);
+ f->gen_d(t64, t64, fpst);
+ write_vec_element(s, t64, a->rd, pass, MO_64);
}
} else {
- int pass;
-
- for (pass = 0; pass < (is_q ? 4 : 2); pass++) {
- TCGv_i32 tcg_op = tcg_temp_new_i32();
- TCGv_i32 tcg_res = tcg_temp_new_i32();
-
- read_vec_element_i32(s, tcg_op, rn, pass, MO_32);
-
- if (size == 2) {
- /* Special cases for 32 bit elements */
- switch (opcode) {
- case 0x4: /* CLS */
- if (u) {
- tcg_gen_clzi_i32(tcg_res, tcg_op, 32);
- } else {
- tcg_gen_clrsb_i32(tcg_res, tcg_op);
- }
- break;
- case 0x7: /* SQABS, SQNEG */
- if (u) {
- gen_helper_neon_qneg_s32(tcg_res, tcg_env, tcg_op);
- } else {
- gen_helper_neon_qabs_s32(tcg_res, tcg_env, tcg_op);
- }
- break;
- case 0x2f: /* FABS */
- gen_vfp_abss(tcg_res, tcg_op);
- break;
- case 0x6f: /* FNEG */
- gen_vfp_negs(tcg_res, tcg_op);
- break;
- case 0x7f: /* FSQRT */
- gen_helper_vfp_sqrts(tcg_res, tcg_op, tcg_env);
- break;
- case 0x1a: /* FCVTNS */
- case 0x1b: /* FCVTMS */
- case 0x1c: /* FCVTAS */
- case 0x3a: /* FCVTPS */
- case 0x3b: /* FCVTZS */
- gen_helper_vfp_tosls(tcg_res, tcg_op,
- tcg_constant_i32(0), tcg_fpstatus);
- break;
- case 0x5a: /* FCVTNU */
- case 0x5b: /* FCVTMU */
- case 0x5c: /* FCVTAU */
- case 0x7a: /* FCVTPU */
- case 0x7b: /* FCVTZU */
- gen_helper_vfp_touls(tcg_res, tcg_op,
- tcg_constant_i32(0), tcg_fpstatus);
- break;
- case 0x18: /* FRINTN */
- case 0x19: /* FRINTM */
- case 0x38: /* FRINTP */
- case 0x39: /* FRINTZ */
- case 0x58: /* FRINTA */
- case 0x79: /* FRINTI */
- gen_helper_rints(tcg_res, tcg_op, tcg_fpstatus);
- break;
- case 0x59: /* FRINTX */
- gen_helper_rints_exact(tcg_res, tcg_op, tcg_fpstatus);
- break;
- case 0x7c: /* URSQRTE */
- gen_helper_rsqrte_u32(tcg_res, tcg_op);
- break;
- case 0x1e: /* FRINT32Z */
- case 0x5e: /* FRINT32X */
- gen_helper_frint32_s(tcg_res, tcg_op, tcg_fpstatus);
- break;
- case 0x1f: /* FRINT64Z */
- case 0x5f: /* FRINT64X */
- gen_helper_frint64_s(tcg_res, tcg_op, tcg_fpstatus);
- break;
- default:
- g_assert_not_reached();
- }
- } else {
- /* Use helpers for 8 and 16 bit elements */
- switch (opcode) {
- case 0x5: /* CNT, RBIT */
- /* For these two insns size is part of the opcode specifier
- * (handled earlier); they always operate on byte elements.
- */
- if (u) {
- gen_helper_neon_rbit_u8(tcg_res, tcg_op);
- } else {
- gen_helper_neon_cnt_u8(tcg_res, tcg_op);
- }
- break;
- case 0x7: /* SQABS, SQNEG */
- {
- NeonGenOneOpEnvFn *genfn;
- static NeonGenOneOpEnvFn * const fns[2][2] = {
- { gen_helper_neon_qabs_s8, gen_helper_neon_qneg_s8 },
- { gen_helper_neon_qabs_s16, gen_helper_neon_qneg_s16 },
- };
- genfn = fns[size][u];
- genfn(tcg_res, tcg_env, tcg_op);
- break;
- }
- case 0x4: /* CLS, CLZ */
- if (u) {
- if (size == 0) {
- gen_helper_neon_clz_u8(tcg_res, tcg_op);
- } else {
- gen_helper_neon_clz_u16(tcg_res, tcg_op);
- }
- } else {
- if (size == 0) {
- gen_helper_neon_cls_s8(tcg_res, tcg_op);
- } else {
- gen_helper_neon_cls_s16(tcg_res, tcg_op);
- }
- }
- break;
- default:
- g_assert_not_reached();
- }
- }
+ TCGv_i32 t32 = tcg_temp_new_i32();
+ void (*gen)(TCGv_i32, TCGv_i32, TCGv_ptr)
+ = (a->esz == MO_16 ? f->gen_h : f->gen_s);
- write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
+ for (int pass = 0, n = (a->q ? 16 : 8) >> a->esz; pass < n; ++pass) {
+ read_vec_element_i32(s, t32, a->rn, pass, a->esz);
+ gen(t32, t32, fpst);
+ write_vec_element_i32(s, t32, a->rd, pass, a->esz);
}
}
- clear_vec_high(s, is_q, rd);
+ clear_vec_high(s, a->q, a->rd);
- if (tcg_rmode) {
- gen_restore_rmode(tcg_rmode, tcg_fpstatus);
+ if (rmode >= 0) {
+ gen_restore_rmode(tcg_rmode, fpst);
}
+ return true;
}
-/* AdvSIMD [scalar] two register miscellaneous (FP16)
- *
- * 31 30 29 28 27 24 23 22 21 17 16 12 11 10 9 5 4 0
- * +---+---+---+---+---------+---+-------------+--------+-----+------+------+
- * | 0 | Q | U | S | 1 1 1 0 | a | 1 1 1 1 0 0 | opcode | 1 0 | Rn | Rd |
- * +---+---+---+---+---------+---+-------------+--------+-----+------+------+
- * mask: 1000 1111 0111 1110 0000 1100 0000 0000 0x8f7e 0c00
- * val: 0000 1110 0111 1000 0000 1000 0000 0000 0x0e78 0800
- *
- * This actually covers two groups where scalar access is governed by
- * bit 28. A bunch of the instructions (float to integral) only exist
- * in the vector form and are un-allocated for the scalar decode. Also
- * in the scalar decode Q is always 1.
- */
-static void disas_simd_two_reg_misc_fp16(DisasContext *s, uint32_t insn)
-{
- int fpop, opcode, a, u;
- int rn, rd;
- bool is_q;
- bool is_scalar;
- bool only_in_vector = false;
+TRANS(FSQRT_v, do_fp1_vector, a, &f_scalar_fsqrt, -1)
- int pass;
- TCGv_i32 tcg_rmode = NULL;
- TCGv_ptr tcg_fpstatus = NULL;
- bool need_fpst = true;
- int rmode = -1;
-
- if (!dc_isar_feature(aa64_fp16, s)) {
- unallocated_encoding(s);
- return;
- }
-
- rd = extract32(insn, 0, 5);
- rn = extract32(insn, 5, 5);
+TRANS(FRINTN_v, do_fp1_vector, a, &f_scalar_frint, FPROUNDING_TIEEVEN)
+TRANS(FRINTP_v, do_fp1_vector, a, &f_scalar_frint, FPROUNDING_POSINF)
+TRANS(FRINTM_v, do_fp1_vector, a, &f_scalar_frint, FPROUNDING_NEGINF)
+TRANS(FRINTZ_v, do_fp1_vector, a, &f_scalar_frint, FPROUNDING_ZERO)
+TRANS(FRINTA_v, do_fp1_vector, a, &f_scalar_frint, FPROUNDING_TIEAWAY)
+TRANS(FRINTI_v, do_fp1_vector, a, &f_scalar_frint, -1)
+TRANS(FRINTX_v, do_fp1_vector, a, &f_scalar_frintx, -1)
- a = extract32(insn, 23, 1);
- u = extract32(insn, 29, 1);
- is_scalar = extract32(insn, 28, 1);
- is_q = extract32(insn, 30, 1);
+TRANS_FEAT(FRINT32Z_v, aa64_frint, do_fp1_vector, a,
+ &f_scalar_frint32, FPROUNDING_ZERO)
+TRANS_FEAT(FRINT32X_v, aa64_frint, do_fp1_vector, a, &f_scalar_frint32, -1)
+TRANS_FEAT(FRINT64Z_v, aa64_frint, do_fp1_vector, a,
+ &f_scalar_frint64, FPROUNDING_ZERO)
+TRANS_FEAT(FRINT64X_v, aa64_frint, do_fp1_vector, a, &f_scalar_frint64, -1)
- opcode = extract32(insn, 12, 5);
- fpop = deposit32(opcode, 5, 1, a);
- fpop = deposit32(fpop, 6, 1, u);
-
- switch (fpop) {
- case 0x1d: /* SCVTF */
- case 0x5d: /* UCVTF */
- {
- int elements;
-
- if (is_scalar) {
- elements = 1;
- } else {
- elements = (is_q ? 8 : 4);
- }
+static bool do_gvec_op2_fpst(DisasContext *s, MemOp esz, bool is_q,
+ int rd, int rn, int data,
+ gen_helper_gvec_2_ptr * const fns[3])
+{
+ int check = fp_access_check_vector_hsd(s, is_q, esz);
+ TCGv_ptr fpst;
- if (!fp_access_check(s)) {
- return;
- }
- handle_simd_intfp_conv(s, rd, rn, elements, !u, 0, MO_16);
- return;
- }
- break;
- case 0x2c: /* FCMGT (zero) */
- case 0x2d: /* FCMEQ (zero) */
- case 0x2e: /* FCMLT (zero) */
- case 0x6c: /* FCMGE (zero) */
- case 0x6d: /* FCMLE (zero) */
- handle_2misc_fcmp_zero(s, fpop, is_scalar, 0, is_q, MO_16, rn, rd);
- return;
- case 0x3d: /* FRECPE */
- case 0x3f: /* FRECPX */
- break;
- case 0x18: /* FRINTN */
- only_in_vector = true;
- rmode = FPROUNDING_TIEEVEN;
- break;
- case 0x19: /* FRINTM */
- only_in_vector = true;
- rmode = FPROUNDING_NEGINF;
- break;
- case 0x38: /* FRINTP */
- only_in_vector = true;
- rmode = FPROUNDING_POSINF;
- break;
- case 0x39: /* FRINTZ */
- only_in_vector = true;
- rmode = FPROUNDING_ZERO;
- break;
- case 0x58: /* FRINTA */
- only_in_vector = true;
- rmode = FPROUNDING_TIEAWAY;
- break;
- case 0x59: /* FRINTX */
- case 0x79: /* FRINTI */
- only_in_vector = true;
- /* current rounding mode */
- break;
- case 0x1a: /* FCVTNS */
- rmode = FPROUNDING_TIEEVEN;
- break;
- case 0x1b: /* FCVTMS */
- rmode = FPROUNDING_NEGINF;
- break;
- case 0x1c: /* FCVTAS */
- rmode = FPROUNDING_TIEAWAY;
- break;
- case 0x3a: /* FCVTPS */
- rmode = FPROUNDING_POSINF;
- break;
- case 0x3b: /* FCVTZS */
- rmode = FPROUNDING_ZERO;
- break;
- case 0x5a: /* FCVTNU */
- rmode = FPROUNDING_TIEEVEN;
- break;
- case 0x5b: /* FCVTMU */
- rmode = FPROUNDING_NEGINF;
- break;
- case 0x5c: /* FCVTAU */
- rmode = FPROUNDING_TIEAWAY;
- break;
- case 0x7a: /* FCVTPU */
- rmode = FPROUNDING_POSINF;
- break;
- case 0x7b: /* FCVTZU */
- rmode = FPROUNDING_ZERO;
- break;
- case 0x2f: /* FABS */
- case 0x6f: /* FNEG */
- need_fpst = false;
- break;
- case 0x7d: /* FRSQRTE */
- case 0x7f: /* FSQRT (vector) */
- break;
- default:
- unallocated_encoding(s);
- return;
+ if (check <= 0) {
+ return check == 0;
}
+ fpst = fpstatus_ptr(esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR);
+ tcg_gen_gvec_2_ptr(vec_full_reg_offset(s, rd),
+ vec_full_reg_offset(s, rn), fpst,
+ is_q ? 16 : 8, vec_full_reg_size(s),
+ data, fns[esz - 1]);
+ return true;
+}
- /* Check additional constraints for the scalar encoding */
- if (is_scalar) {
- if (!is_q) {
- unallocated_encoding(s);
- return;
- }
- /* FRINTxx is only in the vector form */
- if (only_in_vector) {
- unallocated_encoding(s);
- return;
- }
- }
+static gen_helper_gvec_2_ptr * const f_scvtf_v[] = {
+ gen_helper_gvec_vcvt_sh,
+ gen_helper_gvec_vcvt_sf,
+ gen_helper_gvec_vcvt_sd,
+};
+TRANS(SCVTF_vi, do_gvec_op2_fpst,
+ a->esz, a->q, a->rd, a->rn, 0, f_scvtf_v)
+TRANS(SCVTF_vf, do_gvec_op2_fpst,
+ a->esz, a->q, a->rd, a->rn, a->shift, f_scvtf_v)
+
+static gen_helper_gvec_2_ptr * const f_ucvtf_v[] = {
+ gen_helper_gvec_vcvt_uh,
+ gen_helper_gvec_vcvt_uf,
+ gen_helper_gvec_vcvt_ud,
+};
+TRANS(UCVTF_vi, do_gvec_op2_fpst,
+ a->esz, a->q, a->rd, a->rn, 0, f_ucvtf_v)
+TRANS(UCVTF_vf, do_gvec_op2_fpst,
+ a->esz, a->q, a->rd, a->rn, a->shift, f_ucvtf_v)
+
+static gen_helper_gvec_2_ptr * const f_fcvtzs_vf[] = {
+ gen_helper_gvec_vcvt_rz_hs,
+ gen_helper_gvec_vcvt_rz_fs,
+ gen_helper_gvec_vcvt_rz_ds,
+};
+TRANS(FCVTZS_vf, do_gvec_op2_fpst,
+ a->esz, a->q, a->rd, a->rn, a->shift, f_fcvtzs_vf)
- if (!fp_access_check(s)) {
- return;
- }
+static gen_helper_gvec_2_ptr * const f_fcvtzu_vf[] = {
+ gen_helper_gvec_vcvt_rz_hu,
+ gen_helper_gvec_vcvt_rz_fu,
+ gen_helper_gvec_vcvt_rz_du,
+};
+TRANS(FCVTZU_vf, do_gvec_op2_fpst,
+ a->esz, a->q, a->rd, a->rn, a->shift, f_fcvtzu_vf)
- if (rmode >= 0 || need_fpst) {
- tcg_fpstatus = fpstatus_ptr(FPST_FPCR_F16);
- }
+static gen_helper_gvec_2_ptr * const f_fcvt_s_vi[] = {
+ gen_helper_gvec_vcvt_rm_sh,
+ gen_helper_gvec_vcvt_rm_ss,
+ gen_helper_gvec_vcvt_rm_sd,
+};
- if (rmode >= 0) {
- tcg_rmode = gen_set_rmode(rmode, tcg_fpstatus);
- }
+static gen_helper_gvec_2_ptr * const f_fcvt_u_vi[] = {
+ gen_helper_gvec_vcvt_rm_uh,
+ gen_helper_gvec_vcvt_rm_us,
+ gen_helper_gvec_vcvt_rm_ud,
+};
- if (is_scalar) {
- TCGv_i32 tcg_op = read_fp_hreg(s, rn);
- TCGv_i32 tcg_res = tcg_temp_new_i32();
+TRANS(FCVTNS_vi, do_gvec_op2_fpst,
+ a->esz, a->q, a->rd, a->rn, float_round_nearest_even, f_fcvt_s_vi)
+TRANS(FCVTNU_vi, do_gvec_op2_fpst,
+ a->esz, a->q, a->rd, a->rn, float_round_nearest_even, f_fcvt_u_vi)
+TRANS(FCVTPS_vi, do_gvec_op2_fpst,
+ a->esz, a->q, a->rd, a->rn, float_round_up, f_fcvt_s_vi)
+TRANS(FCVTPU_vi, do_gvec_op2_fpst,
+ a->esz, a->q, a->rd, a->rn, float_round_up, f_fcvt_u_vi)
+TRANS(FCVTMS_vi, do_gvec_op2_fpst,
+ a->esz, a->q, a->rd, a->rn, float_round_down, f_fcvt_s_vi)
+TRANS(FCVTMU_vi, do_gvec_op2_fpst,
+ a->esz, a->q, a->rd, a->rn, float_round_down, f_fcvt_u_vi)
+TRANS(FCVTZS_vi, do_gvec_op2_fpst,
+ a->esz, a->q, a->rd, a->rn, float_round_to_zero, f_fcvt_s_vi)
+TRANS(FCVTZU_vi, do_gvec_op2_fpst,
+ a->esz, a->q, a->rd, a->rn, float_round_to_zero, f_fcvt_u_vi)
+TRANS(FCVTAS_vi, do_gvec_op2_fpst,
+ a->esz, a->q, a->rd, a->rn, float_round_ties_away, f_fcvt_s_vi)
+TRANS(FCVTAU_vi, do_gvec_op2_fpst,
+ a->esz, a->q, a->rd, a->rn, float_round_ties_away, f_fcvt_u_vi)
+
+static gen_helper_gvec_2_ptr * const f_fceq0[] = {
+ gen_helper_gvec_fceq0_h,
+ gen_helper_gvec_fceq0_s,
+ gen_helper_gvec_fceq0_d,
+};
+TRANS(FCMEQ0_v, do_gvec_op2_fpst, a->esz, a->q, a->rd, a->rn, 0, f_fceq0)
- switch (fpop) {
- case 0x1a: /* FCVTNS */
- case 0x1b: /* FCVTMS */
- case 0x1c: /* FCVTAS */
- case 0x3a: /* FCVTPS */
- case 0x3b: /* FCVTZS */
- gen_helper_advsimd_f16tosinth(tcg_res, tcg_op, tcg_fpstatus);
- break;
- case 0x3d: /* FRECPE */
- gen_helper_recpe_f16(tcg_res, tcg_op, tcg_fpstatus);
- break;
- case 0x3f: /* FRECPX */
- gen_helper_frecpx_f16(tcg_res, tcg_op, tcg_fpstatus);
- break;
- case 0x5a: /* FCVTNU */
- case 0x5b: /* FCVTMU */
- case 0x5c: /* FCVTAU */
- case 0x7a: /* FCVTPU */
- case 0x7b: /* FCVTZU */
- gen_helper_advsimd_f16touinth(tcg_res, tcg_op, tcg_fpstatus);
- break;
- case 0x6f: /* FNEG */
- tcg_gen_xori_i32(tcg_res, tcg_op, 0x8000);
- break;
- case 0x7d: /* FRSQRTE */
- gen_helper_rsqrte_f16(tcg_res, tcg_op, tcg_fpstatus);
- break;
- default:
- g_assert_not_reached();
- }
+static gen_helper_gvec_2_ptr * const f_fcgt0[] = {
+ gen_helper_gvec_fcgt0_h,
+ gen_helper_gvec_fcgt0_s,
+ gen_helper_gvec_fcgt0_d,
+};
+TRANS(FCMGT0_v, do_gvec_op2_fpst, a->esz, a->q, a->rd, a->rn, 0, f_fcgt0)
- /* limit any sign extension going on */
- tcg_gen_andi_i32(tcg_res, tcg_res, 0xffff);
- write_fp_sreg(s, rd, tcg_res);
- } else {
- for (pass = 0; pass < (is_q ? 8 : 4); pass++) {
- TCGv_i32 tcg_op = tcg_temp_new_i32();
- TCGv_i32 tcg_res = tcg_temp_new_i32();
-
- read_vec_element_i32(s, tcg_op, rn, pass, MO_16);
-
- switch (fpop) {
- case 0x1a: /* FCVTNS */
- case 0x1b: /* FCVTMS */
- case 0x1c: /* FCVTAS */
- case 0x3a: /* FCVTPS */
- case 0x3b: /* FCVTZS */
- gen_helper_advsimd_f16tosinth(tcg_res, tcg_op, tcg_fpstatus);
- break;
- case 0x3d: /* FRECPE */
- gen_helper_recpe_f16(tcg_res, tcg_op, tcg_fpstatus);
- break;
- case 0x5a: /* FCVTNU */
- case 0x5b: /* FCVTMU */
- case 0x5c: /* FCVTAU */
- case 0x7a: /* FCVTPU */
- case 0x7b: /* FCVTZU */
- gen_helper_advsimd_f16touinth(tcg_res, tcg_op, tcg_fpstatus);
- break;
- case 0x18: /* FRINTN */
- case 0x19: /* FRINTM */
- case 0x38: /* FRINTP */
- case 0x39: /* FRINTZ */
- case 0x58: /* FRINTA */
- case 0x79: /* FRINTI */
- gen_helper_advsimd_rinth(tcg_res, tcg_op, tcg_fpstatus);
- break;
- case 0x59: /* FRINTX */
- gen_helper_advsimd_rinth_exact(tcg_res, tcg_op, tcg_fpstatus);
- break;
- case 0x2f: /* FABS */
- tcg_gen_andi_i32(tcg_res, tcg_op, 0x7fff);
- break;
- case 0x6f: /* FNEG */
- tcg_gen_xori_i32(tcg_res, tcg_op, 0x8000);
- break;
- case 0x7d: /* FRSQRTE */
- gen_helper_rsqrte_f16(tcg_res, tcg_op, tcg_fpstatus);
- break;
- case 0x7f: /* FSQRT */
- gen_helper_sqrt_f16(tcg_res, tcg_op, tcg_fpstatus);
- break;
- default:
- g_assert_not_reached();
- }
+static gen_helper_gvec_2_ptr * const f_fcge0[] = {
+ gen_helper_gvec_fcge0_h,
+ gen_helper_gvec_fcge0_s,
+ gen_helper_gvec_fcge0_d,
+};
+TRANS(FCMGE0_v, do_gvec_op2_fpst, a->esz, a->q, a->rd, a->rn, 0, f_fcge0)
- write_vec_element_i32(s, tcg_res, rd, pass, MO_16);
- }
+static gen_helper_gvec_2_ptr * const f_fclt0[] = {
+ gen_helper_gvec_fclt0_h,
+ gen_helper_gvec_fclt0_s,
+ gen_helper_gvec_fclt0_d,
+};
+TRANS(FCMLT0_v, do_gvec_op2_fpst, a->esz, a->q, a->rd, a->rn, 0, f_fclt0)
- clear_vec_high(s, is_q, rd);
- }
+static gen_helper_gvec_2_ptr * const f_fcle0[] = {
+ gen_helper_gvec_fcle0_h,
+ gen_helper_gvec_fcle0_s,
+ gen_helper_gvec_fcle0_d,
+};
+TRANS(FCMLE0_v, do_gvec_op2_fpst, a->esz, a->q, a->rd, a->rn, 0, f_fcle0)
- if (tcg_rmode) {
- gen_restore_rmode(tcg_rmode, tcg_fpstatus);
- }
-}
+static gen_helper_gvec_2_ptr * const f_frecpe[] = {
+ gen_helper_gvec_frecpe_h,
+ gen_helper_gvec_frecpe_s,
+ gen_helper_gvec_frecpe_d,
+};
+TRANS(FRECPE_v, do_gvec_op2_fpst, a->esz, a->q, a->rd, a->rn, 0, f_frecpe)
-/* C3.6 Data processing - SIMD, inc Crypto
- *
- * As the decode gets a little complex we are using a table based
- * approach for this part of the decode.
- */
-static const AArch64DecodeTable data_proc_simd[] = {
- /* pattern , mask , fn */
- { 0x0e200800, 0x9f3e0c00, disas_simd_two_reg_misc },
- { 0x0f000400, 0x9f800400, disas_simd_shift_imm },
- { 0x5e200800, 0xdf3e0c00, disas_simd_scalar_two_reg_misc },
- { 0x5f000400, 0xdf800400, disas_simd_scalar_shift_imm },
- { 0x0e780800, 0x8f7e0c00, disas_simd_two_reg_misc_fp16 },
- { 0x00000000, 0x00000000, NULL }
+static gen_helper_gvec_2_ptr * const f_frsqrte[] = {
+ gen_helper_gvec_frsqrte_h,
+ gen_helper_gvec_frsqrte_s,
+ gen_helper_gvec_frsqrte_d,
};
+TRANS(FRSQRTE_v, do_gvec_op2_fpst, a->esz, a->q, a->rd, a->rn, 0, f_frsqrte)
-static void disas_data_proc_simd(DisasContext *s, uint32_t insn)
+static bool trans_FCVTL_v(DisasContext *s, arg_qrr_e *a)
{
- /* Note that this is called with all non-FP cases from
- * table C3-6 so it must UNDEF for entries not specifically
- * allocated to instructions in that table.
+ /* Handle 2-reg-misc ops which are widening (so each size element
+ * in the source becomes a 2*size element in the destination.
+ * The only instruction like this is FCVTL.
*/
- AArch64DecodeFn *fn = lookup_disas_fn(&data_proc_simd[0], insn);
- if (fn) {
- fn(s, insn);
- } else {
- unallocated_encoding(s);
+ int pass;
+
+ if (!fp_access_check(s)) {
+ return true;
}
-}
-/* C3.6 Data processing - SIMD and floating point */
-static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
-{
- if (extract32(insn, 28, 1) == 1 && extract32(insn, 30, 1) == 0) {
- disas_data_proc_fp(s, insn);
+ if (a->esz == MO_64) {
+ /* 32 -> 64 bit fp conversion */
+ TCGv_i64 tcg_res[2];
+ TCGv_i32 tcg_op = tcg_temp_new_i32();
+ int srcelt = a->q ? 2 : 0;
+
+ for (pass = 0; pass < 2; pass++) {
+ tcg_res[pass] = tcg_temp_new_i64();
+ read_vec_element_i32(s, tcg_op, a->rn, srcelt + pass, MO_32);
+ gen_helper_vfp_fcvtds(tcg_res[pass], tcg_op, tcg_env);
+ }
+ for (pass = 0; pass < 2; pass++) {
+ write_vec_element(s, tcg_res[pass], a->rd, pass, MO_64);
+ }
} else {
- /* SIMD, including crypto */
- disas_data_proc_simd(s, insn);
+ /* 16 -> 32 bit fp conversion */
+ int srcelt = a->q ? 4 : 0;
+ TCGv_i32 tcg_res[4];
+ TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
+ TCGv_i32 ahp = get_ahp_flag();
+
+ for (pass = 0; pass < 4; pass++) {
+ tcg_res[pass] = tcg_temp_new_i32();
+ read_vec_element_i32(s, tcg_res[pass], a->rn, srcelt + pass, MO_16);
+ gen_helper_vfp_fcvt_f16_to_f32(tcg_res[pass], tcg_res[pass],
+ fpst, ahp);
+ }
+ for (pass = 0; pass < 4; pass++) {
+ write_vec_element_i32(s, tcg_res[pass], a->rd, pass, MO_32);
+ }
}
+ clear_vec_high(s, true, a->rd);
+ return true;
}
static bool trans_OK(DisasContext *s, arg_OK *a)
@@ -11649,24 +9593,6 @@ static bool btype_destination_ok(uint32_t insn, bool bt, int btype)
return false;
}
-/* C3.1 A64 instruction index by encoding */
-static void disas_a64_legacy(DisasContext *s, uint32_t insn)
-{
- switch (extract32(insn, 25, 4)) {
- case 0x5:
- case 0xd: /* Data processing - register */
- disas_data_proc_reg(s, insn);
- break;
- case 0x7:
- case 0xf: /* Data processing - SIMD and floating point */
- disas_data_proc_simd_fp(s, insn);
- break;
- default:
- unallocated_encoding(s);
- break;
- }
-}
-
static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
CPUState *cpu)
{
@@ -11869,7 +9795,7 @@ static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
if (!disas_a64(s, insn) &&
!disas_sme(s, insn) &&
!disas_sve(s, insn)) {
- disas_a64_legacy(s, insn);
+ unallocated_encoding(s);
}
/*
diff --git a/target/arm/tcg/translate-neon.c b/target/arm/tcg/translate-neon.c
index 9c8829a..c4fecb8 100644
--- a/target/arm/tcg/translate-neon.c
+++ b/target/arm/tcg/translate-neon.c
@@ -1409,13 +1409,13 @@ static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a,
DO_FP_2SH(VCVT_SF, gen_helper_gvec_vcvt_sf)
DO_FP_2SH(VCVT_UF, gen_helper_gvec_vcvt_uf)
-DO_FP_2SH(VCVT_FS, gen_helper_gvec_vcvt_fs)
-DO_FP_2SH(VCVT_FU, gen_helper_gvec_vcvt_fu)
+DO_FP_2SH(VCVT_FS, gen_helper_gvec_vcvt_rz_fs)
+DO_FP_2SH(VCVT_FU, gen_helper_gvec_vcvt_rz_fu)
DO_FP_2SH(VCVT_SH, gen_helper_gvec_vcvt_sh)
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)
+DO_FP_2SH(VCVT_HS, gen_helper_gvec_vcvt_rz_hs)
+DO_FP_2SH(VCVT_HU, gen_helper_gvec_vcvt_rz_hu)
static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a,
GVecGen2iFn *fn)
@@ -1560,8 +1560,8 @@ static bool do_prewiden_3d(DisasContext *s, arg_3diff *a,
NULL, NULL, \
}; \
static NeonGenTwo64OpFn * const addfn[] = { \
- gen_helper_neon_##OP##l_u16, \
- gen_helper_neon_##OP##l_u32, \
+ tcg_gen_vec_##OP##16_i64, \
+ tcg_gen_vec_##OP##32_i64, \
tcg_gen_##OP##_i64, \
NULL, \
}; \
@@ -1639,8 +1639,8 @@ static bool do_narrow_3d(DisasContext *s, arg_3diff *a,
static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \
{ \
static NeonGenTwo64OpFn * const addfn[] = { \
- gen_helper_neon_##OP##l_u16, \
- gen_helper_neon_##OP##l_u32, \
+ tcg_gen_vec_##OP##16_i64, \
+ tcg_gen_vec_##OP##32_i64, \
tcg_gen_##OP##_i64, \
NULL, \
}; \
@@ -1761,8 +1761,8 @@ static bool trans_VABAL_S_3d(DisasContext *s, arg_3diff *a)
NULL,
};
static NeonGenTwo64OpFn * const addfn[] = {
- gen_helper_neon_addl_u16,
- gen_helper_neon_addl_u32,
+ tcg_gen_vec_add16_i64,
+ tcg_gen_vec_add32_i64,
tcg_gen_add_i64,
NULL,
};
@@ -1779,8 +1779,8 @@ static bool trans_VABAL_U_3d(DisasContext *s, arg_3diff *a)
NULL,
};
static NeonGenTwo64OpFn * const addfn[] = {
- gen_helper_neon_addl_u16,
- gen_helper_neon_addl_u32,
+ tcg_gen_vec_add16_i64,
+ tcg_gen_vec_add32_i64,
tcg_gen_add_i64,
NULL,
};
@@ -1840,8 +1840,8 @@ static bool trans_VMULL_U_3d(DisasContext *s, arg_3diff *a)
NULL, \
}; \
static NeonGenTwo64OpFn * const accfn[] = { \
- gen_helper_neon_##ACC##l_u16, \
- gen_helper_neon_##ACC##l_u32, \
+ tcg_gen_vec_##ACC##16_i64, \
+ tcg_gen_vec_##ACC##32_i64, \
tcg_gen_##ACC##_i64, \
NULL, \
}; \
@@ -2371,7 +2371,7 @@ static bool trans_VMULL_U_2sc(DisasContext *s, arg_2scalar *a)
}; \
static NeonGenTwo64OpFn * const accfn[] = { \
NULL, \
- gen_helper_neon_##ACC##l_u32, \
+ tcg_gen_vec_##ACC##32_i64, \
tcg_gen_##ACC##_i64, \
NULL, \
}; \
@@ -2565,204 +2565,6 @@ static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a)
return true;
}
-static bool trans_VREV64(DisasContext *s, arg_VREV64 *a)
-{
- int pass, half;
- TCGv_i32 tmp[2];
-
- if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
- return false;
- }
-
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) &&
- ((a->vd | a->vm) & 0x10)) {
- return false;
- }
-
- if ((a->vd | a->vm) & a->q) {
- return false;
- }
-
- if (a->size == 3) {
- return false;
- }
-
- if (!vfp_access_check(s)) {
- return true;
- }
-
- tmp[0] = tcg_temp_new_i32();
- tmp[1] = tcg_temp_new_i32();
-
- for (pass = 0; pass < (a->q ? 2 : 1); pass++) {
- for (half = 0; half < 2; half++) {
- read_neon_element32(tmp[half], a->vm, pass * 2 + half, MO_32);
- switch (a->size) {
- case 0:
- tcg_gen_bswap32_i32(tmp[half], tmp[half]);
- break;
- case 1:
- gen_swap_half(tmp[half], tmp[half]);
- break;
- case 2:
- break;
- default:
- g_assert_not_reached();
- }
- }
- write_neon_element32(tmp[1], a->vd, pass * 2, MO_32);
- write_neon_element32(tmp[0], a->vd, pass * 2 + 1, MO_32);
- }
- return true;
-}
-
-static bool do_2misc_pairwise(DisasContext *s, arg_2misc *a,
- NeonGenWidenFn *widenfn,
- NeonGenTwo64OpFn *opfn,
- NeonGenTwo64OpFn *accfn)
-{
- /*
- * Pairwise long operations: widen both halves of the pair,
- * combine the pairs with the opfn, and then possibly accumulate
- * into the destination with the accfn.
- */
- int pass;
-
- if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
- return false;
- }
-
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) &&
- ((a->vd | a->vm) & 0x10)) {
- return false;
- }
-
- if ((a->vd | a->vm) & a->q) {
- return false;
- }
-
- if (!widenfn) {
- return false;
- }
-
- if (!vfp_access_check(s)) {
- return true;
- }
-
- for (pass = 0; pass < a->q + 1; pass++) {
- TCGv_i32 tmp;
- TCGv_i64 rm0_64, rm1_64, rd_64;
-
- rm0_64 = tcg_temp_new_i64();
- rm1_64 = tcg_temp_new_i64();
- rd_64 = tcg_temp_new_i64();
-
- tmp = tcg_temp_new_i32();
- read_neon_element32(tmp, a->vm, pass * 2, MO_32);
- widenfn(rm0_64, tmp);
- read_neon_element32(tmp, a->vm, pass * 2 + 1, MO_32);
- widenfn(rm1_64, tmp);
-
- opfn(rd_64, rm0_64, rm1_64);
-
- if (accfn) {
- TCGv_i64 tmp64 = tcg_temp_new_i64();
- read_neon_element64(tmp64, a->vd, pass, MO_64);
- accfn(rd_64, tmp64, rd_64);
- }
- write_neon_element64(rd_64, a->vd, pass, MO_64);
- }
- return true;
-}
-
-static bool trans_VPADDL_S(DisasContext *s, arg_2misc *a)
-{
- static NeonGenWidenFn * const widenfn[] = {
- gen_helper_neon_widen_s8,
- gen_helper_neon_widen_s16,
- tcg_gen_ext_i32_i64,
- NULL,
- };
- static NeonGenTwo64OpFn * const opfn[] = {
- gen_helper_neon_paddl_u16,
- gen_helper_neon_paddl_u32,
- tcg_gen_add_i64,
- NULL,
- };
-
- return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL);
-}
-
-static bool trans_VPADDL_U(DisasContext *s, arg_2misc *a)
-{
- static NeonGenWidenFn * const widenfn[] = {
- gen_helper_neon_widen_u8,
- gen_helper_neon_widen_u16,
- tcg_gen_extu_i32_i64,
- NULL,
- };
- static NeonGenTwo64OpFn * const opfn[] = {
- gen_helper_neon_paddl_u16,
- gen_helper_neon_paddl_u32,
- tcg_gen_add_i64,
- NULL,
- };
-
- return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL);
-}
-
-static bool trans_VPADAL_S(DisasContext *s, arg_2misc *a)
-{
- static NeonGenWidenFn * const widenfn[] = {
- gen_helper_neon_widen_s8,
- gen_helper_neon_widen_s16,
- tcg_gen_ext_i32_i64,
- NULL,
- };
- static NeonGenTwo64OpFn * const opfn[] = {
- gen_helper_neon_paddl_u16,
- gen_helper_neon_paddl_u32,
- tcg_gen_add_i64,
- NULL,
- };
- static NeonGenTwo64OpFn * const accfn[] = {
- gen_helper_neon_addl_u16,
- gen_helper_neon_addl_u32,
- tcg_gen_add_i64,
- NULL,
- };
-
- return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size],
- accfn[a->size]);
-}
-
-static bool trans_VPADAL_U(DisasContext *s, arg_2misc *a)
-{
- static NeonGenWidenFn * const widenfn[] = {
- gen_helper_neon_widen_u8,
- gen_helper_neon_widen_u16,
- tcg_gen_extu_i32_i64,
- NULL,
- };
- static NeonGenTwo64OpFn * const opfn[] = {
- gen_helper_neon_paddl_u16,
- gen_helper_neon_paddl_u32,
- tcg_gen_add_i64,
- NULL,
- };
- static NeonGenTwo64OpFn * const accfn[] = {
- gen_helper_neon_addl_u16,
- gen_helper_neon_addl_u32,
- tcg_gen_add_i64,
- NULL,
- };
-
- return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size],
- accfn[a->size]);
-}
-
typedef void ZipFn(TCGv_ptr, TCGv_ptr);
static bool do_zip_uzp(DisasContext *s, arg_2misc *a,
@@ -3120,6 +2922,13 @@ DO_2MISC_VEC(VCGT0, gen_gvec_cgt0)
DO_2MISC_VEC(VCLE0, gen_gvec_cle0)
DO_2MISC_VEC(VCGE0, gen_gvec_cge0)
DO_2MISC_VEC(VCLT0, gen_gvec_clt0)
+DO_2MISC_VEC(VCLS, gen_gvec_cls)
+DO_2MISC_VEC(VCLZ, gen_gvec_clz)
+DO_2MISC_VEC(VREV64, gen_gvec_rev64)
+DO_2MISC_VEC(VPADDL_S, gen_gvec_saddlp)
+DO_2MISC_VEC(VPADDL_U, gen_gvec_uaddlp)
+DO_2MISC_VEC(VPADAL_S, gen_gvec_sadalp)
+DO_2MISC_VEC(VPADAL_U, gen_gvec_uadalp)
static bool trans_VMVN(DisasContext *s, arg_2misc *a)
{
@@ -3129,6 +2938,30 @@ static bool trans_VMVN(DisasContext *s, arg_2misc *a)
return do_2misc_vec(s, a, tcg_gen_gvec_not);
}
+static bool trans_VCNT(DisasContext *s, arg_2misc *a)
+{
+ if (a->size != 0) {
+ return false;
+ }
+ return do_2misc_vec(s, a, gen_gvec_cnt);
+}
+
+static bool trans_VREV16(DisasContext *s, arg_2misc *a)
+{
+ if (a->size != 0) {
+ return false;
+ }
+ return do_2misc_vec(s, a, gen_gvec_rev16);
+}
+
+static bool trans_VREV32(DisasContext *s, arg_2misc *a)
+{
+ if (a->size != 0 && a->size != 1) {
+ return false;
+ }
+ return do_2misc_vec(s, a, gen_gvec_rev32);
+}
+
#define WRAP_2M_3_OOL_FN(WRAPNAME, FUNC, DATA) \
static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \
uint32_t rm_ofs, uint32_t oprsz, \
@@ -3208,68 +3041,6 @@ static bool do_2misc(DisasContext *s, arg_2misc *a, NeonGenOneOpFn *fn)
return true;
}
-static bool trans_VREV32(DisasContext *s, arg_2misc *a)
-{
- static NeonGenOneOpFn * const fn[] = {
- tcg_gen_bswap32_i32,
- gen_swap_half,
- NULL,
- NULL,
- };
- return do_2misc(s, a, fn[a->size]);
-}
-
-static bool trans_VREV16(DisasContext *s, arg_2misc *a)
-{
- if (a->size != 0) {
- return false;
- }
- return do_2misc(s, a, gen_rev16);
-}
-
-static bool trans_VCLS(DisasContext *s, arg_2misc *a)
-{
- static NeonGenOneOpFn * const fn[] = {
- gen_helper_neon_cls_s8,
- gen_helper_neon_cls_s16,
- gen_helper_neon_cls_s32,
- NULL,
- };
- return do_2misc(s, a, fn[a->size]);
-}
-
-static void do_VCLZ_32(TCGv_i32 rd, TCGv_i32 rm)
-{
- tcg_gen_clzi_i32(rd, rm, 32);
-}
-
-static bool trans_VCLZ(DisasContext *s, arg_2misc *a)
-{
- static NeonGenOneOpFn * const fn[] = {
- gen_helper_neon_clz_u8,
- gen_helper_neon_clz_u16,
- do_VCLZ_32,
- NULL,
- };
- return do_2misc(s, a, fn[a->size]);
-}
-
-static bool trans_VCNT(DisasContext *s, arg_2misc *a)
-{
- if (a->size != 0) {
- return false;
- }
- return do_2misc(s, a, gen_helper_neon_cnt_u8);
-}
-
-static void gen_VABS_F(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
- uint32_t oprsz, uint32_t maxsz)
-{
- tcg_gen_gvec_andi(vece, rd_ofs, rm_ofs,
- vece == MO_16 ? 0x7fff : 0x7fffffff,
- oprsz, maxsz);
-}
-
static bool trans_VABS_F(DisasContext *s, arg_2misc *a)
{
if (a->size == MO_16) {
@@ -3279,15 +3050,7 @@ static bool trans_VABS_F(DisasContext *s, arg_2misc *a)
} else if (a->size != MO_32) {
return false;
}
- return do_2misc_vec(s, a, gen_VABS_F);
-}
-
-static void gen_VNEG_F(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
- uint32_t oprsz, uint32_t maxsz)
-{
- tcg_gen_gvec_xori(vece, rd_ofs, rm_ofs,
- vece == MO_16 ? 0x8000 : 0x80000000,
- oprsz, maxsz);
+ return do_2misc_vec(s, a, gen_gvec_fabs);
}
static bool trans_VNEG_F(DisasContext *s, arg_2misc *a)
@@ -3299,7 +3062,7 @@ static bool trans_VNEG_F(DisasContext *s, arg_2misc *a)
} else if (a->size != MO_32) {
return false;
}
- return do_2misc_vec(s, a, gen_VNEG_F);
+ return do_2misc_vec(s, a, gen_gvec_fneg);
}
static bool trans_VRECPE(DisasContext *s, arg_2misc *a)
@@ -3307,7 +3070,7 @@ static bool trans_VRECPE(DisasContext *s, arg_2misc *a)
if (a->size != 2) {
return false;
}
- return do_2misc(s, a, gen_helper_recpe_u32);
+ return do_2misc_vec(s, a, gen_gvec_urecpe);
}
static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a)
@@ -3315,7 +3078,7 @@ static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a)
if (a->size != 2) {
return false;
}
- return do_2misc(s, a, gen_helper_rsqrte_u32);
+ return do_2misc_vec(s, a, gen_gvec_ursqrte);
}
#define WRAP_1OP_ENV_FN(WRAPNAME, FUNC) \
diff --git a/target/arm/tcg/translate-vfp.c b/target/arm/tcg/translate-vfp.c
index b6fa28a..c160a86 100644
--- a/target/arm/tcg/translate-vfp.c
+++ b/target/arm/tcg/translate-vfp.c
@@ -2424,17 +2424,17 @@ DO_VFP_2OP(VNEG, dp, gen_vfp_negd, aa32_fpdp_v2)
static void gen_VSQRT_hp(TCGv_i32 vd, TCGv_i32 vm)
{
- gen_helper_vfp_sqrth(vd, vm, tcg_env);
+ gen_helper_vfp_sqrth(vd, vm, fpstatus_ptr(FPST_FPCR_F16));
}
static void gen_VSQRT_sp(TCGv_i32 vd, TCGv_i32 vm)
{
- gen_helper_vfp_sqrts(vd, vm, tcg_env);
+ gen_helper_vfp_sqrts(vd, vm, fpstatus_ptr(FPST_FPCR));
}
static void gen_VSQRT_dp(TCGv_i64 vd, TCGv_i64 vm)
{
- gen_helper_vfp_sqrtd(vd, vm, tcg_env);
+ gen_helper_vfp_sqrtd(vd, vm, fpstatus_ptr(FPST_FPCR));
}
DO_VFP_2OP(VSQRT, hp, gen_VSQRT_hp, aa32_fp16_arith)
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
index 20cd0e8..9b9abf1 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -578,6 +578,41 @@ void gen_gvec_umaxp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
void gen_gvec_uminp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz);
+void gen_gvec_cls(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz);
+void gen_gvec_clz(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz);
+void gen_gvec_cnt(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz);
+void gen_gvec_rbit(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz);
+void gen_gvec_rev16(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz);
+void gen_gvec_rev32(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz);
+void gen_gvec_rev64(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz);
+
+void gen_gvec_saddlp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz);
+void gen_gvec_sadalp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz);
+void gen_gvec_uaddlp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz);
+void gen_gvec_uadalp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz);
+
+/* These exclusively manipulate the sign bit. */
+void gen_gvec_fabs(unsigned vece, uint32_t dofs, uint32_t aofs,
+ uint32_t oprsz, uint32_t maxsz);
+void gen_gvec_fneg(unsigned vece, uint32_t dofs, uint32_t aofs,
+ uint32_t oprsz, uint32_t maxsz);
+
+void gen_gvec_urecpe(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz);
+void gen_gvec_ursqrte(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t opr_sz, uint32_t max_sz);
+
/*
* Forward to the isar_feature_* tests given a DisasContext pointer.
*/
diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c
index ad6f265..768f745 100644
--- a/target/arm/tcg/vec_helper.c
+++ b/target/arm/tcg/vec_helper.c
@@ -1253,8 +1253,10 @@ DO_2OP(gvec_touszh, vfp_touszh, float16)
#define DO_2OP_CMP0(FN, CMPOP, DIRN) \
WRAP_CMP0_##DIRN(FN, CMPOP, float16) \
WRAP_CMP0_##DIRN(FN, CMPOP, float32) \
+ WRAP_CMP0_##DIRN(FN, CMPOP, float64) \
DO_2OP(gvec_f##FN##0_h, float16_##FN##0, float16) \
- DO_2OP(gvec_f##FN##0_s, float32_##FN##0, float32)
+ DO_2OP(gvec_f##FN##0_s, float32_##FN##0, float32) \
+ DO_2OP(gvec_f##FN##0_d, float64_##FN##0, float64)
DO_2OP_CMP0(cgt, cgt, FWD)
DO_2OP_CMP0(cge, cge, FWD)
@@ -2505,14 +2507,19 @@ DO_3OP_PAIR(gvec_uminp_s, MIN, uint32_t, H4)
clear_tail(d, oprsz, simd_maxsz(desc)); \
}
+DO_VCVT_FIXED(gvec_vcvt_sd, helper_vfp_sqtod, uint64_t)
+DO_VCVT_FIXED(gvec_vcvt_ud, helper_vfp_uqtod, uint64_t)
DO_VCVT_FIXED(gvec_vcvt_sf, helper_vfp_sltos, uint32_t)
DO_VCVT_FIXED(gvec_vcvt_uf, helper_vfp_ultos, uint32_t)
-DO_VCVT_FIXED(gvec_vcvt_fs, helper_vfp_tosls_round_to_zero, uint32_t)
-DO_VCVT_FIXED(gvec_vcvt_fu, helper_vfp_touls_round_to_zero, uint32_t)
DO_VCVT_FIXED(gvec_vcvt_sh, helper_vfp_shtoh, uint16_t)
DO_VCVT_FIXED(gvec_vcvt_uh, helper_vfp_uhtoh, uint16_t)
-DO_VCVT_FIXED(gvec_vcvt_hs, helper_vfp_toshh_round_to_zero, uint16_t)
-DO_VCVT_FIXED(gvec_vcvt_hu, helper_vfp_touhh_round_to_zero, uint16_t)
+
+DO_VCVT_FIXED(gvec_vcvt_rz_ds, helper_vfp_tosqd_round_to_zero, uint64_t)
+DO_VCVT_FIXED(gvec_vcvt_rz_du, helper_vfp_touqd_round_to_zero, uint64_t)
+DO_VCVT_FIXED(gvec_vcvt_rz_fs, helper_vfp_tosls_round_to_zero, uint32_t)
+DO_VCVT_FIXED(gvec_vcvt_rz_fu, helper_vfp_touls_round_to_zero, uint32_t)
+DO_VCVT_FIXED(gvec_vcvt_rz_hs, helper_vfp_toshh_round_to_zero, uint16_t)
+DO_VCVT_FIXED(gvec_vcvt_rz_hu, helper_vfp_touhh_round_to_zero, uint16_t)
#undef DO_VCVT_FIXED
@@ -2532,6 +2539,8 @@ DO_VCVT_FIXED(gvec_vcvt_hu, helper_vfp_touhh_round_to_zero, uint16_t)
clear_tail(d, oprsz, simd_maxsz(desc)); \
}
+DO_VCVT_RMODE(gvec_vcvt_rm_sd, helper_vfp_tosqd, uint64_t)
+DO_VCVT_RMODE(gvec_vcvt_rm_ud, helper_vfp_touqd, uint64_t)
DO_VCVT_RMODE(gvec_vcvt_rm_ss, helper_vfp_tosls, uint32_t)
DO_VCVT_RMODE(gvec_vcvt_rm_us, helper_vfp_touls, uint32_t)
DO_VCVT_RMODE(gvec_vcvt_rm_sh, helper_vfp_toshh, uint16_t)
@@ -3066,3 +3075,49 @@ DO_CLAMP(gvec_uclamp_b, uint8_t)
DO_CLAMP(gvec_uclamp_h, uint16_t)
DO_CLAMP(gvec_uclamp_s, uint32_t)
DO_CLAMP(gvec_uclamp_d, uint64_t)
+
+/* Bit count in each 8-bit word. */
+void HELPER(gvec_cnt_b)(void *vd, void *vn, uint32_t desc)
+{
+ intptr_t i, opr_sz = simd_oprsz(desc);
+ uint8_t *d = vd, *n = vn;
+
+ for (i = 0; i < opr_sz; ++i) {
+ d[i] = ctpop8(n[i]);
+ }
+ clear_tail(d, opr_sz, simd_maxsz(desc));
+}
+
+/* Reverse bits in each 8 bit word */
+void HELPER(gvec_rbit_b)(void *vd, void *vn, uint32_t desc)
+{
+ intptr_t i, opr_sz = simd_oprsz(desc);
+ uint64_t *d = vd, *n = vn;
+
+ for (i = 0; i < opr_sz / 8; ++i) {
+ d[i] = revbit64(bswap64(n[i]));
+ }
+ clear_tail(d, opr_sz, simd_maxsz(desc));
+}
+
+void HELPER(gvec_urecpe_s)(void *vd, void *vn, uint32_t desc)
+{
+ intptr_t i, opr_sz = simd_oprsz(desc);
+ uint32_t *d = vd, *n = vn;
+
+ for (i = 0; i < opr_sz / 4; ++i) {
+ d[i] = helper_recpe_u32(n[i]);
+ }
+ clear_tail(d, opr_sz, simd_maxsz(desc));
+}
+
+void HELPER(gvec_ursqrte_s)(void *vd, void *vn, uint32_t desc)
+{
+ intptr_t i, opr_sz = simd_oprsz(desc);
+ uint32_t *d = vd, *n = vn;
+
+ for (i = 0; i < opr_sz / 4; ++i) {
+ d[i] = helper_rsqrte_u32(n[i]);
+ }
+ clear_tail(d, opr_sz, simd_maxsz(desc));
+}
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
index 62638d2..5a19af5 100644
--- a/target/arm/vfp_helper.c
+++ b/target/arm/vfp_helper.c
@@ -314,19 +314,19 @@ VFP_BINOP(minnum)
VFP_BINOP(maxnum)
#undef VFP_BINOP
-dh_ctype_f16 VFP_HELPER(sqrt, h)(dh_ctype_f16 a, CPUARMState *env)
+dh_ctype_f16 VFP_HELPER(sqrt, h)(dh_ctype_f16 a, void *fpstp)
{
- return float16_sqrt(a, &env->vfp.fp_status_f16);
+ return float16_sqrt(a, fpstp);
}
-float32 VFP_HELPER(sqrt, s)(float32 a, CPUARMState *env)
+float32 VFP_HELPER(sqrt, s)(float32 a, void *fpstp)
{
- return float32_sqrt(a, &env->vfp.fp_status);
+ return float32_sqrt(a, fpstp);
}
-float64 VFP_HELPER(sqrt, d)(float64 a, CPUARMState *env)
+float64 VFP_HELPER(sqrt, d)(float64 a, void *fpstp)
{
- return float64_sqrt(a, &env->vfp.fp_status);
+ return float64_sqrt(a, fpstp);
}
static void softfloat_to_vfp_compare(CPUARMState *env, FloatRelation cmp)
@@ -495,6 +495,10 @@ VFP_CONV_FIX_A64(sq, h, 16, dh_ctype_f16, 64, int64)
VFP_CONV_FIX(uh, h, 16, dh_ctype_f16, 32, uint16)
VFP_CONV_FIX(ul, h, 16, dh_ctype_f16, 32, uint32)
VFP_CONV_FIX_A64(uq, h, 16, dh_ctype_f16, 64, uint64)
+VFP_CONV_FLOAT_FIX_ROUND(sq, d, 64, float64, 64, int64,
+ float_round_to_zero, _round_to_zero)
+VFP_CONV_FLOAT_FIX_ROUND(uq, d, 64, float64, 64, uint64,
+ float_round_to_zero, _round_to_zero)
#undef VFP_CONV_FIX
#undef VFP_CONV_FIX_FLOAT